| From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org> |
| Date: Tue, 12 Mar 2013 11:32:32 -0400 |
| Subject: tracing: Fix race in snapshot swapping |
| |
| commit 2721e72dd10f71a3ba90f59781becf02638aa0d9 upstream. |
| |
| Although the swap is wrapped with a spin_lock, the assignment |
| of the temp buffer used to swap is not within that lock. |
| It needs to be moved into that lock, otherwise two swaps |
| happening on two different CPUs, can end up using the wrong |
| temp buffer to assign in the swap. |
| |
| Luckily, all current callers of the swap function appear to have |
| their own locks. But in case something is added that allows two |
| different callers to call the swap, then there's a chance that |
| this race can trigger and corrupt the buffers. |
| |
| New code is coming soon that will allow for this race to trigger. |
| |
| I've Cc'd stable, so this bug will not show up if someone backports |
| one of the changes that can trigger this bug. |
| |
| Signed-off-by: Steven Rostedt <rostedt@goodmis.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| kernel/trace/trace.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| --- a/kernel/trace/trace.c |
| +++ b/kernel/trace/trace.c |
| @@ -652,7 +652,7 @@ __update_max_tr(struct trace_array *tr, |
| void |
| update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) |
| { |
| - struct ring_buffer *buf = tr->buffer; |
| + struct ring_buffer *buf; |
| |
| if (trace_stop_count) |
| return; |
| @@ -664,6 +664,7 @@ update_max_tr(struct trace_array *tr, st |
| } |
| arch_spin_lock(&ftrace_max_lock); |
| |
| + buf = tr->buffer; |
| tr->buffer = max_tr.buffer; |
| max_tr.buffer = buf; |
| |