用户空间 Verbs 访问¶
通过启用 CONFIG_INFINIBAND_USER_VERBS 构建的 ib_uverbs 模块,允许用户空间通过 “verbs” 直接访问 IB 硬件,如 InfiniBand 架构规范的第 11 章所述。
要使用 verbs,需要 libibverbs 库,可从 https://github.com/linux-rdma/rdma-core 获取。 libibverbs 包含一个设备无关的 API,用于使用 ib_uverbs 接口。 libibverbs 还需要适用于你的 InfiniBand 硬件的相应设备相关内核和用户空间驱动程序。例如,要使用 Mellanox HCA,你需要安装 ib_mthca 内核模块和 libmthca 用户空间驱动程序。
用户-内核通信¶
用户空间通过 /dev/infiniband/uverbsN 字符设备与内核进行慢速路径、资源管理操作的通信。快速路径操作通常通过直接写入映射到用户空间的硬件寄存器来执行,无需系统调用或上下文切换到内核。
命令通过对这些设备文件执行 write() 操作发送到内核。ABI 在 drivers/infiniband/include/ib_user_verbs.h 中定义。需要内核响应的命令的结构体包含一个 64 位字段,用于传递指向输出缓冲区的指针。状态作为 write() 系统调用的返回值返回到用户空间。
资源管理¶
由于所有 IB 资源的创建和销毁都是通过文件描述符传递的命令来完成的,因此内核可以跟踪哪些资源附加到给定的用户空间上下文。 ib_uverbs 模块维护 idr 表,用于在内核指针和不透明的用户空间句柄之间进行转换,从而使内核指针永远不会暴露给用户空间,并且用户空间无法欺骗内核跟随虚假指针。
这也允许内核在进程退出时进行清理,并防止一个进程触及另一个进程的资源。
内存锁定¶
直接用户空间 I/O 要求潜在 I/O 目标的内存区域保持在相同的物理地址。 ib_uverbs 模块通过 get_user_pages() 和 put_page() 调用来管理内存区域的锁定和解锁。它还会计算进程的 pinned_vm 中锁定的内存量,并检查非特权进程是否超过其 RLIMIT_MEMLOCK 限制。
多次锁定的页面在每次锁定时都会被计数,因此 pinned_vm 的值可能高估了进程锁定的页面数。
/dev 文件¶
要使用 udev 自动创建相应的字符设备文件,可以使用如下规则:
KERNEL=="uverbs*", NAME="infiniband/%k"这将创建名为
/dev/infiniband/uverbs0等等的设备节点。由于 InfiniBand 用户空间 verbs 对非特权进程来说应该是安全的,因此在 udev 规则中添加适当的 MODE 或 GROUP 可能很有用。