History

tracing: Use .flush() call to wake up readers

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/20240308202432.107909457@goodmis.org

Steven Rostedt (Google) committed 2 years ago

Commit e5d7c191 parent 68282dd1 file · +15 −6Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/trace/trace.c+15−6
@@ -8393,6 +8393,20 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, · 8392 unmodified lines
8393 return size;8393 return size;
8394}8394}
8395 8395
8396static int tracing_buffers_flush(struct file *file, fl_owner_t id)
8397{
8398 struct ftrace_buffer_info *info = file->private_data;
8399 struct trace_iterator *iter = &info->iter;
8400
8401 iter->wait_index++;
8402 /* Make sure the waiters see the new wait_index */
8403 smp_wmb();
8404
8405 ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);
8406
8407 return 0;
8408}
8409
8396static int tracing_buffers_release(struct inode *inode, struct file *file)8410static int tracing_buffers_release(struct inode *inode, struct file *file)
8397{8411{
8398 struct ftrace_buffer_info *info = file->private_data;8412 struct ftrace_buffer_info *info = file->private_data;
@@ -8404,12 +8418,6 @@ static int tracing_buffers_release(struct inode *inode, struct file *file) · 5 unmodified lines
8404 8418
8405 __trace_array_put(iter->tr);8419 __trace_array_put(iter->tr);
8406 8420
8407 iter->wait_index++;
8408 /* Make sure the waiters see the new wait_index */
8409 smp_wmb();
8410
8411 ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);
8412
8413 if (info->spare)8421 if (info->spare)
8414 ring_buffer_free_read_page(iter->array_buffer->buffer,8422 ring_buffer_free_read_page(iter->array_buffer->buffer,
8415 info->spare_cpu, info->spare);8423 info->spare_cpu, info->spare);
@@ -8625,6 +8633,7 @@ static const struct file_operations tracing_buffers_fops = { · 209 unmodified lines
8625 .read = tracing_buffers_read,8633 .read = tracing_buffers_read,
8626 .poll = tracing_buffers_poll,8634 .poll = tracing_buffers_poll,
8627 .release = tracing_buffers_release,8635 .release = tracing_buffers_release,
8636 .flush = tracing_buffers_flush,
8628 .splice_read = tracing_buffers_splice_read,8637 .splice_read = tracing_buffers_splice_read,
8629 .unlocked_ioctl = tracing_buffers_ioctl,8638 .unlocked_ioctl = tracing_buffers_ioctl,
8630 .llseek = no_llseek,8639 .llseek = no_llseek,