Skip to content

Commit

Permalink
tracing: Use .flush() call to wake up readers
Browse files Browse the repository at this point in the history
The .release() function does not get called until all readers of a file
descriptor are finished.

If a thread is blocked on reading a file descriptor in ring_buffer_wait(),
and another thread closes the file descriptor, it will not wake up the
other thread as ring_buffer_wake_waiters() is called by .release(), and
that will not get called until the .read() is finished.

The issue originally showed up in trace-cmd, but the readers are actually
other processes with their own file descriptors. So calling close() would wake
up the other tasks because they are blocked on another descriptor then the
one that was closed(). But there's other wake ups that solve that issue.

When a thread is blocked on a read, it can still hang even when another
thread closed its descriptor.

This is what the .flush() callback is for. Have the .flush() wake up the
readers.

Link: https://lore.kernel.org/linux-trace-kernel/[email protected]

Cc: [email protected]
Cc: Masami Hiramatsu <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Mathieu Desnoyers <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: linke li <[email protected]>
Cc: Rabin Vincent <[email protected]>
Fixes: f3ddb74 ("tracing: Wake up ring buffer waiters on closing of the file")
Signed-off-by: Steven Rostedt (Google) <[email protected]>
  • Loading branch information
rostedt committed Mar 10, 2024
1 parent 68282dd commit e5d7c19
Showing 1 changed file with 15 additions and 6 deletions.
21 changes: 15 additions & 6 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -8393,6 +8393,20 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
return size;
}

static int tracing_buffers_flush(struct file *file, fl_owner_t id)
{
struct ftrace_buffer_info *info = file->private_data;
struct trace_iterator *iter = &info->iter;

iter->wait_index++;
/* Make sure the waiters see the new wait_index */
smp_wmb();

ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);

return 0;
}

static int tracing_buffers_release(struct inode *inode, struct file *file)
{
struct ftrace_buffer_info *info = file->private_data;
Expand All @@ -8404,12 +8418,6 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)

__trace_array_put(iter->tr);

iter->wait_index++;
/* Make sure the waiters see the new wait_index */
smp_wmb();

ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);

if (info->spare)
ring_buffer_free_read_page(iter->array_buffer->buffer,
info->spare_cpu, info->spare);
Expand Down Expand Up @@ -8625,6 +8633,7 @@ static const struct file_operations tracing_buffers_fops = {
.read = tracing_buffers_read,
.poll = tracing_buffers_poll,
.release = tracing_buffers_release,
.flush = tracing_buffers_flush,
.splice_read = tracing_buffers_splice_read,
.unlocked_ioctl = tracing_buffers_ioctl,
.llseek = no_llseek,
Expand Down

0 comments on commit e5d7c19

Please sign in to comment.