[PATCH] ring-buffer: Mark concurrent accesses to waiter flags
From: Zhu Jun
Date: Wed Nov 11 2026 - 03:48:10 EST
Poll and wait paths set the pending waiter flags while ring buffer
writers test and clear them without a common lock. The irq_work callback
also accesses the full-buffer wakeup flags concurrently. These plain
accesses cause KCSAN reports.
Use READ_ONCE() and WRITE_ONCE() for the shared waiter and wakeup flags.
Keep the existing barriers and irq_work wakeup protocol unchanged.
Fixes: 15693458c4bc ("tracing/ring-buffer: Move poll wake ups into ring buffer code")
Fixes: 1e0d6714aceb ("ring-buffer: Do not wake up a splice waiter when page is not full")
Signed-off-by: Zhu Jun <zhujun2@xxxxxxxxxxxxxxxxxxxx>
---
kernel/trace/ring_buffer.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 75cd8df23c1b..18f023cf1d6f 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -904,14 +904,14 @@ static void rb_wake_up_waiters(struct irq_work *work)
(void)atomic_fetch_inc_release(&rbwork->seq);
wake_up_all(&rbwork->waiters);
- if (rbwork->full_waiters_pending || rbwork->wakeup_full) {
+ if (READ_ONCE(rbwork->full_waiters_pending) || READ_ONCE(rbwork->wakeup_full)) {
/* Only cpu_buffer sets the above flags */
struct ring_buffer_per_cpu *cpu_buffer =
container_of(rbwork, struct ring_buffer_per_cpu, irq_work);
scoped_guard(raw_spinlock_irqsave, &cpu_buffer->reader_lock) {
- rbwork->wakeup_full = false;
- rbwork->full_waiters_pending = false;
+ WRITE_ONCE(rbwork->wakeup_full, false);
+ WRITE_ONCE(rbwork->full_waiters_pending, false);
/* Waking up all waiters, they will reset the shortest full */
cpu_buffer->shortest_full = 0;
@@ -1023,9 +1023,9 @@ rb_wait_cond(struct rb_irq_work *rbwork, struct trace_buffer *buffer,
* a task has been queued. It's OK for spurious wake ups.
*/
if (full)
- rbwork->full_waiters_pending = true;
+ WRITE_ONCE(rbwork->full_waiters_pending, true);
else
- rbwork->waiters_pending = true;
+ WRITE_ONCE(rbwork->waiters_pending, true);
return false;
}
@@ -1153,12 +1153,12 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
* full_waiters_pending doesn't leak up into the above.
*/
smp_mb();
- rbwork->full_waiters_pending = true;
+ WRITE_ONCE(rbwork->full_waiters_pending, true);
return 0;
}
poll_wait(filp, &rbwork->waiters, poll_table);
- rbwork->waiters_pending = true;
+ WRITE_ONCE(rbwork->waiters_pending, true);
/*
* There's a tight race between setting the waiters_pending and
@@ -4378,14 +4378,14 @@ rb_irq_work_queue(struct rb_irq_work *irq_work)
static __always_inline void
rb_wakeups(struct trace_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
{
- if (buffer->irq_work.waiters_pending) {
- buffer->irq_work.waiters_pending = false;
+ if (READ_ONCE(buffer->irq_work.waiters_pending)) {
+ WRITE_ONCE(buffer->irq_work.waiters_pending, false);
/* irq_work_queue() supplies it's own memory barriers */
rb_irq_work_queue(&buffer->irq_work);
}
- if (cpu_buffer->irq_work.waiters_pending) {
- cpu_buffer->irq_work.waiters_pending = false;
+ if (READ_ONCE(cpu_buffer->irq_work.waiters_pending)) {
+ WRITE_ONCE(cpu_buffer->irq_work.waiters_pending, false);
/* irq_work_queue() supplies it's own memory barriers */
rb_irq_work_queue(&cpu_buffer->irq_work);
}
@@ -4396,7 +4396,7 @@ rb_wakeups(struct trace_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
if (cpu_buffer->reader_page == cpu_buffer->commit_page)
return;
- if (!cpu_buffer->irq_work.full_waiters_pending)
+ if (!READ_ONCE(cpu_buffer->irq_work.full_waiters_pending))
return;
cpu_buffer->last_pages_touch = local_read(&cpu_buffer->pages_touched);
@@ -4404,8 +4404,8 @@ rb_wakeups(struct trace_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
if (!full_hit(buffer, cpu_buffer->cpu, cpu_buffer->shortest_full))
return;
- cpu_buffer->irq_work.wakeup_full = true;
- cpu_buffer->irq_work.full_waiters_pending = false;
+ WRITE_ONCE(cpu_buffer->irq_work.wakeup_full, true);
+ WRITE_ONCE(cpu_buffer->irq_work.full_waiters_pending, false);
/* irq_work_queue() supplies it's own memory barriers */
rb_irq_work_queue(&cpu_buffer->irq_work);
}
--
2.51.0