ring-buffer: Make wake once of ring_buffer_wait() more robust
authorSteven Rostedt (Google) <rostedt@goodmis.org>
Fri, 15 Mar 2024 10:31:15 +0000 (06:31 -0400)
committerSteven Rostedt (Google) <rostedt@goodmis.org>
Mon, 18 Mar 2024 14:11:43 +0000 (10:11 -0400)
commitb70f2938242a028f8e9473781ede175486a59dc8
treea4f78c0671cabf157515672710c7affc72f6b058
parentf1e30cb6369251c03f63c564006f96a54197dcc4
ring-buffer: Make wake once of ring_buffer_wait() more robust

The default behavior of ring_buffer_wait() when passed a NULL "cond"
parameter is to exit the function the first time it is woken up. The
current implementation uses a counter that starts at zero and when it is
greater than one it exits the wait_event_interruptible().

But this relies on the internal working of wait_event_interruptible() as
that code basically has:

  if (cond)
    return;
  prepare_to_wait();
  if (!cond)
    schedule();
  finish_wait();

That is, cond is called twice before it sleeps. The default cond of
ring_buffer_wait() needs to account for that and wait for its counter to
increment twice before exiting.

Instead, use the seq/atomic_inc logic that is used by the tracing code
that calls this function. Add an atomic_t seq to rb_irq_work and when cond
is NULL, have the default callback take a descriptor as its data that
holds the rbwork and the value of the seq when it started.

The wakeups will now increment the rbwork->seq and the cond callback will
simply check if that number is different, and no longer have to rely on
the implementation of wait_event_interruptible().

Link: https://lore.kernel.org/linux-trace-kernel/20240315063115.6cb5d205@gandalf.local.home
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fixes: 7af9ded0c2ca ("ring-buffer: Use wait_event_interruptible() in ring_buffer_wait()")
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
kernel/trace/ring_buffer.c