InfiniBand 中间层锁定¶
本指南试图明确 InfiniBand 中间层所做的锁定假设。它描述了对中间层之下的底层驱动程序和使用中间层的上层协议的要求。
睡眠和中断上下文¶
除了以下例外情况外,所有 struct ib_device 中的方法的底层驱动程序实现都可以睡眠。例外情况是来自列表中的任何方法
create_ah
modify_ah
query_ah
destroy_ah
post_send
post_recv
poll_cq
req_notify_cq
这些方法不得睡眠,必须可以从任何上下文调用。
导出到上层协议使用者的相应函数
rdma_create_ah
rdma_modify_ah
rdma_query_ah
rdma_destroy_ah
ib_post_send
ib_post_recv
ib_req_notify_cq
因此可以安全地从任何上下文调用。
此外,函数
ib_dispatch_event
由底层驱动程序用于通过中间层分派异步事件的函数,也可以安全地从任何上下文调用。
可重入性¶
底层驱动程序导出的 struct ib_device 中的所有方法都必须完全可重入。即使同时运行使用同一对象的多个函数调用,底层驱动程序也必须执行所有必要的同步以保持一致性。
IB 中间层不执行任何函数调用的序列化。
因为底层驱动程序是可重入的,所以上层协议使用者不需要执行任何序列化。但是,可能需要一些序列化才能获得合理的结果。例如,使用者可以安全地在多个 CPU 上同时调用 ib_poll_cq()。但是,在 ib_poll_cq() 的不同调用之间,工作完成信息的排序未定义。
回调¶
底层驱动程序不得从与 ib_device 方法调用相同的调用链中直接执行回调。例如,不允许底层驱动程序直接从其 post_send 方法调用使用者的完成事件处理程序。相反,底层驱动程序应该推迟此回调,例如,调度一个 tasklet 来执行回调。
底层驱动程序负责确保不会同时调用同一 CQ 的多个完成事件处理程序。驱动程序必须保证给定 CQ 的只有一个 CQ 事件处理程序在同时运行。换句话说,不允许出现以下情况
CPU1 CPU2 low-level driver -> consumer CQ event callback: /* ... */ ib_req_notify_cq(cq, ...); low-level driver -> /* ... */ consumer CQ event callback: /* ... */ return from CQ event handler运行完成事件和异步事件回调的上下文未定义。根据底层驱动程序,它可能是进程上下文、softirq 上下文或中断上下文。上层协议使用者不得在回调中睡眠。
热插拔¶
当底层驱动程序调用
ib_register_device()
时,它会通知设备已准备好供使用者使用,所有初始化必须在此调用之前完成。设备必须保持可用,直到驱动程序对ib_unregister_device()
的调用返回。底层驱动程序必须从进程上下文中调用
ib_register_device()
和ib_unregister_device()
。如果使用者在这些调用之间回调到驱动程序,它不得持有任何可能导致死锁的信号量。一旦为该设备调用其 struct ib_client 的 add 方法,上层协议使用者就可以开始使用 IB 设备。使用者必须完成所有清理工作,并在从 remove 方法返回之前释放与设备相关的所有资源。
允许使用者在其 add 和 remove 方法中睡眠。