Linux Trace Kernel
 help / color / mirror / Atom feed
* [PATCH] ring-buffer: Mark concurrent accesses to waiter flags
@ 2026-11-11  8:41 Zhu Jun
  2026-11-12 10:45 ` Steven Rostedt
  0 siblings, 1 reply; 2+ messages in thread
From: Zhu Jun @ 2026-11-11  8:41 UTC (permalink / raw)
  To: rostedt
  Cc: vdonnefort, mhiramat, mathieu.desnoyers, linux-trace-kernel,
	linux-kernel, syzbot+53ab168fdda7fba508ba, Zhu Jun

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@cmss.chinamobile.com>
---
 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




^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-12 10:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-11  8:41 [PATCH] ring-buffer: Mark concurrent accesses to waiter flags Zhu Jun
2026-11-12 10:45 ` Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox