每个CPU的local_bh_disable-函数都会改变(对于x86和最新内核)__preempt_countcurrent_thread_info()->preempt_count否则。
无论如何,这给了我们一个宽限期,所以我们可以假设在rcu_read_lock()内部执行local_bh_disable()是多余的。实际上:in earlier kernels we can see这个local_bh_disable()用于rcu,随后在函数内部调用。后来rcu_dereference()dev_queue_xmit取代,这最终变得比仅仅调用local_bh_disable()复杂一些。现在看起来是这样的:

static inline void rcu_read_lock_bh(void)
{
   local_bh_disable();
   __acquire(RCU_BH);
   rcu_lock_acquire(&rcu_bh_lock_map);
   RCU_LOCKDEP_WARN(!rcu_is_watching(),"rcu_read_lock_bh() used illegally while idle");
}

还有足够多的文章描述了rcu api。Here我们可以看到:
你需要治疗NMI处理者,Hardirq处理者,
和禁用抢占的代码段(无论
通过preempt_disable()、local_irq_save()、local_bh_disable(),
或者其他一些机制)好像它们是显式的RCU读取器?
如果是的话,RCU SCHED是你唯一的选择。
这告诉我们在这种情况下使用rcu sched api,所以rcu_read_lock_bh()应该会有帮助。从this comprehensive table我们可以意识到local_bh_disable()应该只在rcu_dereference_sched()/rcu_dereference()-标记中使用。
然而,这还不够清楚。我能在不怀疑任何错误的情况下使用(在现代内核的情况下)内部的标记吗?
P.S.在我的例子中,我不能将代码调用rcu_read_lock改为调用例如rcu_read_unlock,因此我的代码在bh已禁用的情况下运行。还使用了常用的rcu api。因此,它充满了嵌套在rcu_dereference()中的local_bh_disable

最佳答案

您不应该混合和匹配api。如果需要使用rcu bh api,则需要使用rcu_dereference_bh
您可以看到,如果在rcu_dereference_check之后调用rcu_read_lock_bh,它将正确地推测它是not called in a RCU read-side critical section;将上面片段中对lock_is_held(&rcu_lock_map)的调用与rcu_lock_acquire(&rcu_bh_lock_map);进行对比。
rcuhere的内核文档(搜索“rcu dereference()”一节)给出了正确用法的一个明确示例;只有在相应的rcu_dereference*函数完成后才能正确调用rcu_read_lock*

09-05 22:58