我写的代码很少创建/删除对象(多达数千个),但经常在软IRQ上下文中修改它们。这些对象也很少从任务上下文中读取(可能也很少修改)(通过procfs:file-per-object)。目前,我的代码包含全局每个CPU的数据块,每个数据块都有一个spinlock保护。这样的块包含用于对象存储的固定大小的哈希表。
显然,当前的设计并不是最优的,尤其是在对象更新负载非常高的情况下:从procfs读取对象会在更新软IRQ时导致数据丢失。我需要重写同步方案以摆脱全局锁定。最明显的选择是为每个哈希表bucket设置一个spinlock,它应该可以很好地扩展。问题是,我可能需要使用自己的哈希表实现,或者至少需要重新实现几个顶级宏(在linux/hashtable.h中找不到用于spinlock保护的bucket的宏)。我是否也应该关注启用RCU的哈希表(但我对这种同步方法还没有完全理解)?
具有锁保护的Buckets在头linux/list_bl.h中声明。它们使用头指针的最低位作为锁位。
RCU保护的对bucket的访问是用头文件linux/hashtable.h中的其他哈希表函数定义的(它们有_rcu
后缀)。
在锁和RCU之间进行选择取决于您。请注意,RCU本身无法解决-modify-modify冲突。而且它对频繁读取的数据有很大帮助,而你的情况似乎并非如此。
由于struct hlist_bl_head
只声明了一个锁定函数hlist_bl_lock
,而该函数不知道irq,因此当哈希表可以用于irq或下半部分时,应执行其他操作:
-
spin_lock_irqsave:
local_irq_save(flags); hlist_bl_lock(...);
-
spin_unlock_irqrestore:
hlist_bl_unlock(...); local_irq_restore(flags);
-
spin_lock_bh:
local_bh_disable(); hlist_bl_lock(...);
-
spin_unlock_bh:
hlist_bl_unlock(...); local_bh_enable();