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未定义完成事件和异步事件回调运行的上下文。 根据底层驱动程序的不同,它可能是进程上下文、软中断上下文或中断上下文。 高层协议使用者不得在回调中休眠。
热插拔¶
当底层驱动程序调用
ib_register_device()
时,它会宣布设备已准备好供使用者使用,所有初始化都必须在此调用之前完成。 在驱动程序调用ib_unregister_device()
返回之前,设备必须保持可用。底层驱动程序必须从进程上下文中调用
ib_register_device()
和ib_unregister_device()
。 它不得持有任何可能导致死锁的信号量,如果使用者在这些调用中回调到驱动程序中。高层协议使用者可以在为其调用 struct ib_client 的 add 方法后立即开始使用 IB 设备。 在从 remove 方法返回之前,使用者必须完成所有清理并释放与设备相关的所有资源。
允许使用者在其 add 和 remove 方法中睡眠。