summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-12-23 11:32:24 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-18 10:43:44 -0800
commit0f6645286f4c0b568d83a240a73f55ce618dd8aa (patch)
tree5bb54e95e9ff93931855b1047ba37912e0a9c03d /kernel
parent6870fdf3a70ea33f544cb1474916bee1c366ce9d (diff)
ring-buffer: fix dangling commit race
commit a8ccf1d6f60e3e6ae63122e02378cd4d40dd4aac upstream. Impact: fix stuck trace-buffers If an interrupt comes in during the rb_set_commit_to_write and pushes the tail page forward just at the right time, the commit updates will miss the adding of the interrupt data. This will cause the commit pointer to cease from moving forward. Thanks to Jiaying Zhang for finding this race. Reported-by: Jiaying Zhang <jiayingz@google.com> Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/ring_buffer.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 2b75a581ea3f..71202acea51c 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -769,6 +769,7 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
* back to us). This allows us to do a simple loop to
* assign the commit to the tail.
*/
+ again:
while (cpu_buffer->commit_page != cpu_buffer->tail_page) {
cpu_buffer->commit_page->commit =
cpu_buffer->commit_page->write;
@@ -783,6 +784,17 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
cpu_buffer->commit_page->write;
barrier();
}
+
+ /* again, keep gcc from optimizing */
+ barrier();
+
+ /*
+ * If an interrupt came in just after the first while loop
+ * and pushed the tail page forward, we will be left with
+ * a dangling commit that will never go forward.
+ */
+ if (unlikely(cpu_buffer->commit_page != cpu_buffer->tail_page))
+ goto again;
}
static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer)