| From 436fc280261dcfce5af38f08b89287750dc91cd2 Mon Sep 17 00:00:00 2001 |
| From: Steven Rostedt <srostedt@redhat.com> |
| Date: Fri, 14 Oct 2011 10:44:25 -0400 |
| Subject: tracing: Fix returning of duplicate data after EOF in trace_pipe_raw |
| |
| From: Steven Rostedt <srostedt@redhat.com> |
| |
| commit 436fc280261dcfce5af38f08b89287750dc91cd2 upstream. |
| |
| The trace_pipe_raw handler holds a cached page from the time the file |
| is opened to the time it is closed. The cached page is used to handle |
| the case of the user space buffer being smaller than what was read from |
| the ring buffer. The left over buffer is held in the cache so that the |
| next read will continue where the data left off. |
| |
| After EOF is returned (no more data in the buffer), the index of |
| the cached page is set to zero. If a user app reads the page again |
| after EOF, the check in the buffer will see that the cached page |
| is less than page size and will return the cached page again. This |
| will cause reading the trace_pipe_raw again after EOF to return |
| duplicate data, making the output look like the time went backwards |
| but instead data is just repeated. |
| |
| The fix is to not reset the index right after all data is read |
| from the cache, but to reset it after all data is read and more |
| data exists in the ring buffer. |
| |
| Reported-by: Jeremy Eder <jeder@redhat.com> |
| Signed-off-by: Steven Rostedt <rostedt@goodmis.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| kernel/trace/trace.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/kernel/trace/trace.c |
| +++ b/kernel/trace/trace.c |
| @@ -3624,8 +3624,6 @@ tracing_buffers_read(struct file *filp, |
| if (info->read < PAGE_SIZE) |
| goto read; |
| |
| - info->read = 0; |
| - |
| trace_access_lock(info->cpu); |
| ret = ring_buffer_read_page(info->tr->buffer, |
| &info->spare, |
| @@ -3640,6 +3638,8 @@ tracing_buffers_read(struct file *filp, |
| if (pos < PAGE_SIZE) |
| memset(info->spare + pos, 0, PAGE_SIZE - pos); |
| |
| + info->read = 0; |
| + |
| read: |
| size = PAGE_SIZE - info->read; |
| if (size > count) |