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

标签 c linux-kernel lock-free preemption rcu

local_bh_disable-函数改变每个 cpu(在 x86 和最新内核的情况下)__preempt_countcurrent_thread_info()->preempt_count 否则.

无论如何,这给了我们一个宽限期,所以我们可以假设在 local_bh_disable() 中执行 rcu_read_lock() 是多余的。确实: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我们可以看到:

Do you need to treat NMI handlers, hardirq handlers, and code segments with preemption disabled (whether via preempt_disable(), local_irq_save(), local_bh_disable(), or some other mechanism) as if they were explicit RCU readers? If so, RCU-sched is the only choice that will work for you.

这告诉我们在这种情况下使用 RCU Sched API,因此 rcu_dereference_sched() 应该有所帮助。来自 this comprehensive table我们可以意识到 rcu_dereference() 应该只在 rcu_read_lock/rcu_read_unlock 标记中使用。

但是,还不够清楚。我可以在 local_bh_disable/local_bh_enable 中使用(在现代内核的情况下)rcu_dereference() 标记而不担心出现任何问题吗?

附言就我而言,我无法更改调用 local_bh_disable 的代码来调用例如rcu_read_lock_bh,所以我的代码运行时 bh 已经被禁用。还使用了通常的 RCU API。因此,它充满了嵌套在 local_bh_disable 中的 rcu_read_lock

最佳答案

您不应该混合搭配 API。如果需要使用RCU-bh API,需要使用rcu_dereference_bh .

您可以看到,如果您在 rcu_read_lock_bh 之后调用 rcu_dereference_check,它会正确地推测它是 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*函数完成后才能正确调用。

关于c - 在 local_bh_disable()/local_bh_enable() 中使用 rcu_dereference() 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51236711/

相关文章:

c - Windbg 堆栈跟踪显示宏扩展之前或之后的行号

linux - vm.dirty_ratio 和 vm.dirty_background_ratio 之间的区别?

delphi - Delphi 是否存在无锁队列 "multiple producers-single consumer"?

c - Ncurses curs_set(0) tty

C 语言的 MySQL 批量更新

linux-kernel - 什么是内核启动安静模式参数?

c# - 无锁并发队列

c# - 如何在 .NET 中编写写时复制列表

c - `configure.ac` 文件给出错误

Linux gretap - net/ipv4/ip_gre.c - 如何设置 key->tun_flags 的值