在local_bh_disable()/ local_bh_enable()中使用rcu_dereference()是否安全?

时间:2018-07-08 23:25:07

标签: c linux-kernel lock-free preemption rcu

local_bh_disable函数的每CPU更改量(在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()rcu_read_lock_bh()所取代,这最终变得比仅调用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调度是唯一适合您的选择。

这告诉我们在这种情况下使用 RCU Sched API ,因此rcu_dereference_sched()应该会有所帮助。通过this comprehensive table,我们可以认识到rcu_dereference()仅应在rcu_read_lock / rcu_read_unlock标记内使用。

但是,它还不够清楚。我可以在rcu_dereference() / local_bh_disable标记内使用local_bh_enable(在现代内核的情况下)而不会误会什么吗?

P.S。就我而言,我无法将调用local_bh_disable的代码更改为例如rcu_read_lock_bh,因此我的代码在bh已禁用的情况下运行。还使用常规的RCU API。因此,它充满了rcu_read_lock嵌套在local_bh_disable中。

1 个答案:

答案 0 :(得分:3)

您不应该混合使用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);进行对比。

RCU here的内核文档(在“ rcu_dereference()”部分中搜索)给出了正确用法的明确示例;只有在相应的rcu_dereference*函数完成后才能正确调用rcu_read_lock*