* [PATCH] rcu: Mark accesses to ->rcu_urgent_qs and ->rcu_need_heavy_qs
@ 2026-07-23 7:41 Itai Handler
2026-07-23 15:44 ` Paul E. McKenney
0 siblings, 1 reply; 2+ messages in thread
From: Itai Handler @ 2026-07-23 7:41 UTC (permalink / raw)
To: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Boqun Feng, Uladzislau Rezki
Cc: Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu,
linux-kernel, Itai Handler
rcu_all_qs() and rcu_note_context_switch() read/clear the per-CPU
->rcu_urgent_qs and ->rcu_need_heavy_qs flags with plain raw_cpu_read()
and this_cpu_write(), while the RCU core clears them with WRITE_ONCE() in
rcu_disable_urgency_upon_qs(). KCSAN flags the resulting same-CPU race:
BUG: KCSAN: data-race in rcu_all_qs / rcu_disable_urgency_upon_qs
It is benign -- the flags are advisory and rcu_all_qs() re-reads
->rcu_urgent_qs with smp_load_acquire() before acting on it -- but these
are the last unmarked accesses to the two flags; every other access
already uses READ_ONCE()/WRITE_ONCE()/smp_*. Mark them to match. No
functional change.
Reproduced on a PREEMPT_NONE, CONFIG_KCSAN_INTERRUPT_WATCHER=y kernel with
a pthreads program whose threads (two per CPU) loop reading a large file:
for (;;) {
int fd = open("/proc/kallsyms", O_RDONLY);
while (read(fd, buf, sizeof(buf)) > 0)
;
close(fd);
}
The read()s drive cond_resched() -> rcu_all_qs() while the busy CPUs keep
the grace period urgent, so the RCU core clears the flags concurrently.
Fixes: 2dba13f0b6c2 ("rcu: Switch urgent quiescent-state requests to rcu_data structure")
Signed-off-by: Itai Handler <itai.handler@gmail.com>
---
kernel/rcu/tree_plugin.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 95ad967adcf3..608f73286647 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -970,7 +970,7 @@ void rcu_all_qs(void)
{
unsigned long flags;
- if (!raw_cpu_read(rcu_data.rcu_urgent_qs))
+ if (!READ_ONCE(*raw_cpu_ptr(&rcu_data.rcu_urgent_qs)))
return;
preempt_disable(); // For CONFIG_PREEMPT_COUNT=y kernels
/* Load rcu_urgent_qs before other flags. */
@@ -978,8 +978,8 @@ void rcu_all_qs(void)
preempt_enable();
return;
}
- this_cpu_write(rcu_data.rcu_urgent_qs, false);
- if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs))) {
+ WRITE_ONCE(*this_cpu_ptr(&rcu_data.rcu_urgent_qs), false);
+ if (unlikely(READ_ONCE(*this_cpu_ptr(&rcu_data.rcu_need_heavy_qs)))) {
local_irq_save(flags);
rcu_momentary_eqs();
local_irq_restore(flags);
@@ -999,8 +999,8 @@ void rcu_note_context_switch(bool preempt)
/* Load rcu_urgent_qs before other flags. */
if (!smp_load_acquire(this_cpu_ptr(&rcu_data.rcu_urgent_qs)))
goto out;
- this_cpu_write(rcu_data.rcu_urgent_qs, false);
- if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs)))
+ WRITE_ONCE(*this_cpu_ptr(&rcu_data.rcu_urgent_qs), false);
+ if (unlikely(READ_ONCE(*this_cpu_ptr(&rcu_data.rcu_need_heavy_qs))))
rcu_momentary_eqs();
out:
rcu_tasks_qs(current, preempt);
--
2.34.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] rcu: Mark accesses to ->rcu_urgent_qs and ->rcu_need_heavy_qs
2026-07-23 7:41 [PATCH] rcu: Mark accesses to ->rcu_urgent_qs and ->rcu_need_heavy_qs Itai Handler
@ 2026-07-23 15:44 ` Paul E. McKenney
0 siblings, 0 replies; 2+ messages in thread
From: Paul E. McKenney @ 2026-07-23 15:44 UTC (permalink / raw)
To: Itai Handler
Cc: Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu, linux-kernel
On Thu, Jul 23, 2026 at 10:41:38AM +0300, Itai Handler wrote:
> rcu_all_qs() and rcu_note_context_switch() read/clear the per-CPU
> ->rcu_urgent_qs and ->rcu_need_heavy_qs flags with plain raw_cpu_read()
> and this_cpu_write(), while the RCU core clears them with WRITE_ONCE() in
> rcu_disable_urgency_upon_qs(). KCSAN flags the resulting same-CPU race:
>
> BUG: KCSAN: data-race in rcu_all_qs / rcu_disable_urgency_upon_qs
>
> It is benign -- the flags are advisory and rcu_all_qs() re-reads
> ->rcu_urgent_qs with smp_load_acquire() before acting on it -- but these
> are the last unmarked accesses to the two flags; every other access
> already uses READ_ONCE()/WRITE_ONCE()/smp_*. Mark them to match. No
> functional change.
>
> Reproduced on a PREEMPT_NONE, CONFIG_KCSAN_INTERRUPT_WATCHER=y kernel with
> a pthreads program whose threads (two per CPU) loop reading a large file:
>
> for (;;) {
> int fd = open("/proc/kallsyms", O_RDONLY);
> while (read(fd, buf, sizeof(buf)) > 0)
> ;
> close(fd);
> }
>
> The read()s drive cond_resched() -> rcu_all_qs() while the busy CPUs keep
> the grace period urgent, so the RCU core clears the flags concurrently.
>
> Fixes: 2dba13f0b6c2 ("rcu: Switch urgent quiescent-state requests to rcu_data structure")
> Signed-off-by: Itai Handler <itai.handler@gmail.com>
Nice!!! Queued for further review and testing, thank you!
Thanx, Paul
> ---
> kernel/rcu/tree_plugin.h | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index 95ad967adcf3..608f73286647 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -970,7 +970,7 @@ void rcu_all_qs(void)
> {
> unsigned long flags;
>
> - if (!raw_cpu_read(rcu_data.rcu_urgent_qs))
> + if (!READ_ONCE(*raw_cpu_ptr(&rcu_data.rcu_urgent_qs)))
> return;
> preempt_disable(); // For CONFIG_PREEMPT_COUNT=y kernels
> /* Load rcu_urgent_qs before other flags. */
> @@ -978,8 +978,8 @@ void rcu_all_qs(void)
> preempt_enable();
> return;
> }
> - this_cpu_write(rcu_data.rcu_urgent_qs, false);
> - if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs))) {
> + WRITE_ONCE(*this_cpu_ptr(&rcu_data.rcu_urgent_qs), false);
> + if (unlikely(READ_ONCE(*this_cpu_ptr(&rcu_data.rcu_need_heavy_qs)))) {
> local_irq_save(flags);
> rcu_momentary_eqs();
> local_irq_restore(flags);
> @@ -999,8 +999,8 @@ void rcu_note_context_switch(bool preempt)
> /* Load rcu_urgent_qs before other flags. */
> if (!smp_load_acquire(this_cpu_ptr(&rcu_data.rcu_urgent_qs)))
> goto out;
> - this_cpu_write(rcu_data.rcu_urgent_qs, false);
> - if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs)))
> + WRITE_ONCE(*this_cpu_ptr(&rcu_data.rcu_urgent_qs), false);
> + if (unlikely(READ_ONCE(*this_cpu_ptr(&rcu_data.rcu_need_heavy_qs))))
> rcu_momentary_eqs();
> out:
> rcu_tasks_qs(current, preempt);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-23 15:44 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 7:41 [PATCH] rcu: Mark accesses to ->rcu_urgent_qs and ->rcu_need_heavy_qs Itai Handler
2026-07-23 15:44 ` Paul E. McKenney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox