diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-03-12 19:48:41 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-01 19:01:17 -0400 |
commit | 70e27dedd11fdbb3a9dec79af59d8ba61a19365b (patch) | |
tree | ceeebb9871a93301e09b1c829b87bcea58e69338 /kernel | |
parent | fe030f50c598ffd9476da37d35a7dd7301487795 (diff) |
tracing: Use same local variable when resetting the ring buffer
commit 283740c619d211e34572cc93c8cdba92ccbdb9cc upstream.
In the ftrace code that resets the ring buffer it references the
buffer with a local variable, but then uses the tr->buffer as the
parameter to reset. If the wakeup tracer is running, which can
switch the tr->buffer with the max saved buffer, this can break
the requirement of disabling the buffer before the reset.
buffer = tr->buffer;
ring_buffer_record_disable(buffer);
synchronize_sched();
__tracing_reset(tr->buffer, cpu);
If the tr->buffer is swapped, then the reset is not happening to the
buffer that was disabled. This will cause the ring buffer to fail.
Found with Li Zefan's ftrace_stress_test.
Reported-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 1069dcb935e3..95c944a0b1e1 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -747,10 +747,10 @@ out: | |||
747 | mutex_unlock(&trace_types_lock); | 747 | mutex_unlock(&trace_types_lock); |
748 | } | 748 | } |
749 | 749 | ||
750 | static void __tracing_reset(struct trace_array *tr, int cpu) | 750 | static void __tracing_reset(struct ring_buffer *buffer, int cpu) |
751 | { | 751 | { |
752 | ftrace_disable_cpu(); | 752 | ftrace_disable_cpu(); |
753 | ring_buffer_reset_cpu(tr->buffer, cpu); | 753 | ring_buffer_reset_cpu(buffer, cpu); |
754 | ftrace_enable_cpu(); | 754 | ftrace_enable_cpu(); |
755 | } | 755 | } |
756 | 756 | ||
@@ -762,7 +762,7 @@ void tracing_reset(struct trace_array *tr, int cpu) | |||
762 | 762 | ||
763 | /* Make sure all commits have finished */ | 763 | /* Make sure all commits have finished */ |
764 | synchronize_sched(); | 764 | synchronize_sched(); |
765 | __tracing_reset(tr, cpu); | 765 | __tracing_reset(buffer, cpu); |
766 | 766 | ||
767 | ring_buffer_record_enable(buffer); | 767 | ring_buffer_record_enable(buffer); |
768 | } | 768 | } |
@@ -780,7 +780,7 @@ void tracing_reset_online_cpus(struct trace_array *tr) | |||
780 | tr->time_start = ftrace_now(tr->cpu); | 780 | tr->time_start = ftrace_now(tr->cpu); |
781 | 781 | ||
782 | for_each_online_cpu(cpu) | 782 | for_each_online_cpu(cpu) |
783 | __tracing_reset(tr, cpu); | 783 | __tracing_reset(buffer, cpu); |
784 | 784 | ||
785 | ring_buffer_record_enable(buffer); | 785 | ring_buffer_record_enable(buffer); |
786 | } | 786 | } |