资讯动态

RDMA-Verbs-内核 RDMA Core(六)

发布时间:2026/10/22 2:27:49 来源:尧图企业网站定制
1. 概述Linux RDMA Core 位于 uverbs、内核消费者与硬件驱动之间。其用struct ib_device表示一个 RDMA 设备以struct ib_device_ops连接 mlx5_ib 驱动并为 PD、MR、CQ、QP 等资源提供通用对象、依赖计数和资源跟踪。用户态命令和内核 Verbs 最终都可以到达同一组驱动回调但两条路径的对象入口、用户数据和清理规则不同。RDMA 驱动创建设备对象mlx5_ib 的mlx5r_probe()调用ib_alloc_device_with_net()由 RDMA Core 的_ib_alloc_device()分配包含内嵌ib_device的完整mlx5_ib_dev对象。Device设备管理负责ib_device的注册、端口和设备引用Verbs 通过显式设备参数或 PD、QP、CQ 等对象的device成员取得该设备再使用内嵌的ib_device.ops分发到驱动。例如ib_create_qp_kernel()从pd-device取得设备通用create_qp()再调用dev-ops.create_qp()。mlx5_ib 在初始化时通过ib_set_device_ops()安装操作表并通过ib_register_device()发布设备。RDMA Core 的关键作用可以归纳为四点设备抽象为不同厂商驱动提供统一的ib_device、端口、属性和注册状态。操作分发通过ib_device_ops把通用 Verbs 请求分发到具体驱动。对象管理建立ib_ucontext、PD、MR、CQ、QP 等通用对象及其依赖关系。生命周期使用设备引用、对象usecnt、uverbs 对象引用和 restrack 引用维护生命周期。2. 设备注册与注销2.1 设备对象分配mlx5_ib 的设备探测入口mlx5r_probe()使用ib_alloc_device_with_net(mlx5_ib_dev, ib_dev, net)分配struct mlx5_ib_dev。宏通过成员类型和偏移检查保证ib_dev位于驱动对象起始位置再调用_ib_alloc_device()分配完整的驱动对象。这样同一块内存既能以struct ib_device *交给 RDMA Core也能在 mlx5_ib 内部还原为struct mlx5_ib_dev *。_ib_alloc_device()此时只建立尚未发布的设备对象主要完成以下工作按驱动对象大小分配并清零内存。调用rdma_restrack_init()为各类可跟踪资源建立 XArray 根。初始化内嵌的 Linuxstruct device、网络命名空间和端口链表。初始化事件、Client 数据、注销、CQ pool、cache 和子设备相关的锁、XArray、链表与 completion。设置 legacy uverbs 命令能力掩码。struct ib_device中与本文主线有关的成员如下。设备操作表、注册引用和 restrack 根分别承担分发、注销同步和资源可观察性。structib_device{/* 执行 DMA 的底层 Linux 设备 */structdevice*dma_device;/* 由硬件驱动安装的操作回调和对象大小 */structib_device_opsops;/* RDMA 设备名称 */charname[IB_DEVICE_NAME_MAX];/* 端口属性、cache 与端口状态 */structib_port_data*port_data;/* Linux 设备模型与 RDMA Core 设备视图 */union{structdevicedev;structib_core_devicecoredev;};/* 全局设备 XArray 使用的设备索引 */u32 index;/* 按资源类型划分的 restrack 根数组 */structrdma_restrack_root*res;/* 非零表示设备仍处于可获取的注册状态 */refcount_trefcount;/* refcount 归零时唤醒注销流程 */structcompletionunreg_completion;/* 串行化并发注销与注册竞争 */structmutexunregistration_lock;};2.2 注册流程mlx5_ib 在设备对象和操作表准备好后调用ib_register_device()注册设备。确定身份与能力。分配唯一名称和索引取得设备及端口属性为缓存和资源操作提供依据。准备端口缓存。建立 GID、P_Key 和端口状态的初始视图RoCE GID 随网络设备扫描及事件更新为后续查询提供统一数据。建立设备视图。接入 Linux 设备模型准备 sysfs、统计和 cgroup 状态。暂缓 ADD 事件避免用户空间收到通知时设备还未准备好。发布并保护注册状态。设置DEVICE_REGISTERED建立基础引用和注册线程临时引用用锁保护接入阶段防止并发注销提前 remove 设备。接入消费者。执行可选项、关联 Client并按需建立网络命名空间兼容视图。Client 机制见 RDMA-Verbs-内核 uverbs 接口五。通知就绪。发送设备 ADD 和 RDMA 注册等通知。2.3 注销流程mlx5_ib 注销流程和初始化流程相反先注销设备清理完全部资源后再调用ib_dealloc_device()。保护清理过程。临时持有 Linux device 内存引用并串行化设备注销过程避免对象提前释放或被重复清理。撤销注册资格。清除注册标记解除 Client 关联并清理共用 CQ pool。等待使用者退出。返还注册引用等待所有注册引用归零再移除兼容视图。停止外部与后台活动。remove 设备、端口和 cgroup 视图禁止 GID 更新并等待异步任务结束缓存停止工作但内存暂不释放。交还分配引用。驱动清理完成后dealloc 移除全局索引、检查资源是否遗留并释放分配阶段持有的 Linux device 引用。最终回收内存。最后一个内存引用触发ib_device_release()释放缓存等内部状态再通过 RCU 延迟回收设备对象。因此注销完成不等于内存立即释放。3. 操作接口与分发3.1ib_device_opsstruct ib_device_ops是 RDMA Core 与硬件驱动之间的主要接口。它既包含控制路径回调也包含内核消费者使用的数据路径回调。操作类别代表回调RDMA Core 的主要工作设备与端口query_device、query_port、get_port_immutable建立统一设备属性、端口属性和 link layer 视图用户上下文alloc_ucontext、dealloc_ucontext、mmap、disassociate_ucontext关联 uverbs file、映射对象和设备移除状态资源创建alloc_pd、create_cq、create_qp、reg_user_mr分配或接收通用对象传递ib_udata建立依赖并加入 restrack资源销毁dealloc_pd、destroy_cq、destroy_qp、dereg_mr检查依赖、调用驱动、解除引用并移除 restrack内核数据路径post_send、post_recv、poll_cq、req_notify_cq提供统一内核 Verbs 入口并分发到驱动实现对象布局size_ib_pd、size_ib_cq、size_ib_qp、size_ib_ucontext决定 Core 分配的通用对象与驱动私有对象总大小操作表中的重点声明如下。这里保留实际参数类型用户态附加请求通过ib_udata或uverbs_attr_bundle进入驱动。structib_device_ops{/* 查询设备和端口能力 */int(*query_device)(structib_device*device,structib_device_attr*device_attr,structib_udata*udata);int(*query_port)(structib_device*device,u32 port_num,structib_port_attr*port_attr);/* 建立和释放用户上下文 */int(*alloc_ucontext)(structib_ucontext*context,structib_udata*udata);void(*dealloc_ucontext)(structib_ucontext*context);void(*disassociate_ucontext)(structib_ucontext*ibcontext);/* 创建和释放 PD */int(*alloc_pd)(structib_pd*pd,structib_udata*udata);int(*dealloc_pd)(structib_pd*pd,structib_udata*udata);/* 创建、修改和销毁 QP */int(*create_qp)(structib_qp*qp,structib_qp_init_attr*qp_init_attr,structib_udata*udata);int(*modify_qp)(structib_qp*qp,structib_qp_attr*qp_attr,intqp_attr_mask,structib_udata*udata);int(*destroy_qp)(structib_qp*qp,structib_udata*udata);/* 创建和销毁 CQ */int(*create_cq)(structib_cq*cq,conststructib_cq_init_attr*attr,structuverbs_attr_bundle*attrs);int(*destroy_cq)(structib_cq*cq,structib_udata*udata);/* 注册和注销用户 MR */structib_mr*(*reg_user_mr)(structib_pd*pd,u64 start,u64 length,u64 virt_addr,intmr_access_flags,structib_dmah*dmah,structib_udata*udata);int(*dereg_mr)(structib_mr*mr,structib_udata*udata);/* 内核态请求提交和完成处理 */int(*post_send)(structib_qp*qp,conststructib_send_wr*send_wr,conststructib_send_wr**bad_send_wr);int(*post_recv)(structib_qp*qp,conststructib_recv_wr*recv_wr,conststructib_recv_wr**bad_recv_wr);int(*poll_cq)(structib_cq*cq,intnum_entries,structib_wc*wc);};3.2 操作表安装与对象大小ib_device_ops不是由 mlx5_ib 一次性整体赋值而是通过多张操作表逐步拼装。ib_set_device_ops()遍历传入操作表非空回调只在目标槽位尚为空时写入因此先安装的回调优先后续操作表只能补齐空槽位不能覆盖已有实现。owner、driver_id、uverbs_abi_ver和 uverbs 能力标志单独处理。mlx5_ib 在设备注册前按以下顺序安装操作表mlx5_ib_stage_caps_init()根据硬件能力安装 SR-IOV、MW、XRC、DM 等可选操作表再安装mlx5_ib_dev_ops由主操作表补齐通用 Verbs 回调。MLX5_IB_STAGE_NON_DEFAULT_CB安装端口操作。普通设备使用mlx5_ib_dev_port_opsraw Ethernet representor 使用mlx5_ib_dev_port_rep_ops。RoCE 初始化按需安装 WQ 和 RWQ indirection table 操作。之后ib_register_device()才检查必选回调并发布设备。3.3 内核 Verbs 调用路径内核消费者通过rdma/ib_verbs.h提供的 Kernel Verbs 调用 RDMA Core不经过 uverbs。对外入口通常是宏或static inline函数宏把KBUILD_MODNAME一并传给 Core用于标记资源所属的内核模块对象型接口则从 PD、QP、CQ 等对象的device成员找到ib_device再访问其中的操作表。资源管理接口会进入verbs.c的通用实现。以 QP 创建为例ib_create_qp()调用ib_create_qp_kernel()后者从pd-device取得设备并进入create_qp()。RDMA Core 按驱动登记的对象大小分配 QP初始化通用成员和 restrack再调用dev-ops.create_qp()mlx5_ib 安装在该槽位的mlx5_ib_create_qp()最终创建驱动私有资源和硬件 QP。驱动成功后Core 再建立安全状态和 PD、CQ、SRQ 等父对象的usecnt依赖。PD 和 CQ 采用相同结构ib_alloc_pd()、ib_create_cq()分别进入__ib_alloc_pd()、__ib_create_cq()完成通用对象初始化后调用device-ops.alloc_pd()、device-ops.create_cq()。基础收发接口更短。ib_post_send()、ib_post_recv()和ib_poll_cq()在ib_verbs.h中以内联函数实现直接从 QP 或 CQ 找到device-ops并调用驱动回调不再进入verbs.c的对象生命周期流程。这样仍保留统一的 Kernel Verbs 和ib_device_ops抽象同时减少数据路径上的额外调用层次。4. 核心对象模型4.1 device 与 ucontextib_device是所有资源的根。每次用户进程打开 uverbs 设备并执行 GET_CONTEXTCore 通过ib_alloc_ucontext()按size_ib_ucontext分配通用/私有上下文设置设备和 uverbs file再由ib_init_ucontext()调用ops.alloc_ucontext()。成功后context 加入 restrack并以 release store 发布到file-ucontext。structib_ucontext{/* context 所属 RDMA 设备 */structib_device*device;/* 拥有该 context 的 uverbs 文件 */structib_uverbs_file*ufile;/* 用户 mmap 对象索引 */structxarraymmap_xa;/* CTX 类型的资源跟踪项 */structrdma_restrack_entryres;};内核消费者不创建ib_ucontext而是直接持有ib_device及其资源对象。ib_ucontext因此表示用户文件与驱动用户上下文之间的关系不是所有内核 RDMA 资源的共同父对象。4.2 PD、MR、CQ 与 QPPD 建立访问保护域。MR 和 QP 引用 PDQP 还引用 send CQ、recv CQ以及可选的 SRQ 和 RWQ indirection table。CQ 可以被多个 QP 共享因此对象关系是带共享边的有向图不是单一所有权树。structib_pd{/* PD 所属设备 */structib_device*device;/* 用户 PD 对应的 uverbs 对象内核 PD 为空 */structib_uobject*uobject;/* MR、QP、AH 等子资源使用计数 */atomic_tusecnt;/* PD 类型的资源跟踪项 */structrdma_restrack_entryres;};structib_cq{/* CQ 所属设备 */structib_device*device;/* 用户 CQ 的 uverbs 包装内核 CQ 为空 */structib_ucq_object*uobject;/* 引用该 CQ 的工作队列数量 */atomic_tusecnt;/* CQ 类型的资源跟踪项 */structrdma_restrack_entryres;};structib_qp{/* QP 所属设备和保护域 */structib_device*device;structib_pd*pd;/* 发送和接收完成队列可以指向同一 CQ */structib_cq*send_cq;structib_cq*recv_cq;/* 可选共享接收队列 */structib_srq*srq;/* QP 自身被 open、multicast 或 flow 使用的计数 */atomic_tusecnt;/* 用户 QP 的 uverbs 包装内核 QP 为空 */structib_uqp_object*uobject;/* 驱动创建后给出的 QP number */u32 qp_num;/* QP 类型的资源跟踪项 */structrdma_restrack_entryres;};structib_mr{/* MR 所属设备和保护域 */structib_device*device;structib_pd*pd;/* WQE 使用的本地和远端 key */u32 lkey;u32 rkey;/* RDMA 地址范围 */u64 iova;u64 length;/* 用户 MR 对应的 uverbs 对象 */union{structib_uobject*uobject;structlist_headqp_entry;};/* MR 类型的资源跟踪项 */structrdma_restrack_entryres;};4.3 用户对象与驱动对象用户句柄指向通用对象驱动私有对象内嵌通用对象句柄事务细节见uverbs 接口五ib_uobject保存用户 handle、uverbs file、context、通用对象指针及句柄访问引用。ib_pd、ib_cq、ib_qp、ib_mr保存跨驱动统一的语义和对象关系。mlx5_ib_pd、mlx5_ib_cq、mlx5_ib_qp、mlx5_ib_mr保存 mlx5 私有状态并以内嵌的通用对象作为 Core 入口。PDN、CQN、QPN 和 MKey 等设备标识由 mlx5_ib 回调建立不能与用户 handle 或内核指针互换。下图汇总对象之间的关系。实线表示 Core 保存的直接引用虚线表示包装或索引关系usecnt沿子对象到父对象增加销毁时按相反方向解除。4.4 对象依赖关系Core 在对象成功创建后建立依赖计数。普通 QP 调用ib_qp_usecnt_inc()时分别增加 PD、send CQ、recv CQ、SRQ 和 RWQ indirection table 的usecnt成功销毁后由ib_qp_usecnt_dec()减少引用计数。send CQ 与 recv CQ 相同时会分别增加两次也会在销毁时分别减少两次。MR 注册成功后增加所属 PD 的usecnt注销成功后减少。PD 销毁入口要求所有子资源已经同步销毁用户对象路径中的uverbs_free_pd()检查pd-usecnt非零时返回-EBUSY。CQ 销毁由ib_destroy_cq_user()检查cq-usecnt。QP 的usecnt则保护 open QP、multicast attachment、flow 等直接依赖父对象依赖由单独的ib_qp_usecnt_inc()/ib_qp_usecnt_dec()维护。这些计数只表达对象之间的使用关系不代替设备注册引用或 restrack 引用前者保护设备的注册可用状态后者保证资源观察期间的元数据访问。5. 总结RDMA Kernel Core 以ib_device作为设备与资源的根以ib_device_ops作为通用语义和硬件实现之间的分发边界。mlx5_ib 分配包含ib_device的驱动对象根据硬件能力分批安装操作表并发起注册Core 负责建立设备名称、端口、cache、Linux 设备模型和可见状态。注销沿相反方向撤销这些状态先阻止新的使用再等待已有访问退出。内核消费者通过 Kernel Verbs 使用 RDMA Core。PD、CQ、QP 等资源管理接口进入verbs.c完成通用对象分配、成员初始化和依赖建立再通过ib_device_ops调用 mlx5_ibib_post_send()、ib_post_recv()和ib_poll_cq()等基础收发接口则从对象定位设备并直接分发驱动回调。PD、CQ、MR 和 QP 构成带共享关系的依赖图用户对象由ib_ucontext和ib_uobject包装mlx5_ib 私有对象以内嵌通用对象接入 Core。用户 handle、内核对象指针与 QPN、CQN、MKey 等硬件标识分别属于不同管理层次。6. 参考资料6.1 源码地图功能源码位置重点内容设备分配、注册与注销linux/drivers/infiniband/core/device.c_ib_alloc_device()、ib_register_device()、enable_device_and_get()、disable_device()、ib_unregister_device()、ib_set_device_ops()设备缓存与 sysfs 属性linux/drivers/infiniband/core/cache.c、linux/drivers/infiniband/core/sysfs.cGID/P_Key 缓存初始化与清理、设备统计属性、端口与 GID 属性发布通用 Verbs 对象linux/drivers/infiniband/core/verbs.cPD、AH、SRQ、QP、CQ、MR 的创建、依赖计数、销毁和回滚uverbs 对象生命周期linux/drivers/infiniband/core/rdma_core.cib_uobject的分配、查找、commit、abort、destroy 与文件清理用户上下文入口linux/drivers/infiniband/core/uverbs_cmd.cib_alloc_ucontext()、ib_init_ucontext()与 GET_CONTEXT标准对象 handlerlinux/drivers/infiniband/core/uverbs_std_types.c、uverbs_std_types_qp.c、uverbs_std_types_cq.c用户对象创建后的 Core 调用、usecnt检查和销毁入口资源跟踪linux/drivers/infiniband/core/restrack.c、linux/include/rdma/restrack.hrestrack 类型、XArray、kref、添加、查找、同步与删除通用对象与操作表定义linux/include/rdma/ib_verbs.hib_device、ib_device_ops、ib_ucontext、PD、MR、CQ、QP 及对象大小宏mlx5_ib 操作表与注册入口linux/drivers/infiniband/hw/mlx5/main.cmlx5_ib_dev_ops、能力操作表拼接、mlx5_ib_stage_ib_reg_init()与清理 stage6.2 相关文档《RDMA-Verbs-软件架构二》RDMA Core 在整体软件栈中的位置及四类路径。《RDMA-Verbs-API 和数据结构三》公开 Verbs API、用户态对象及 libibverbs 分发。《RDMA-Verbs-MLX5 用户态库四》mlx5 provider 私有对象、队列内存和用户态数据路径。《RDMA-Verbs-内核 uverbs 接口五》Client 接入、ABI、命令属性、用户句柄和文件关闭处理。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑