aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-12-23 11:32:24 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-23 12:45:25 -0500
commita8ccf1d6f60e3e6ae63122e02378cd4d40dd4aac (patch)
tree98a55b2caf4315617fbb9187e5a15c7f53740ff8 /kernel/trace
parent30cd324e9787ccc9a5ede59742d5409857550692 (diff)
ring-buffer: fix dangling commit race
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> Cc: <stable@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace')
-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 bb6922a931b1..d03f4f44a823 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -838,6 +838,7 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
838 * back to us). This allows us to do a simple loop to 838 * back to us). This allows us to do a simple loop to
839 * assign the commit to the tail. 839 * assign the commit to the tail.
840 */ 840 */
841 again:
841 while (cpu_buffer->commit_page != cpu_buffer->tail_page) { 842 while (cpu_buffer->commit_page != cpu_buffer->tail_page) {
842 cpu_buffer->commit_page->page->commit = 843 cpu_buffer->commit_page->page->commit =
843 cpu_buffer->commit_page->write; 844 cpu_buffer->commit_page->write;
@@ -853,6 +854,17 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
853 cpu_buffer->commit_page->write; 854 cpu_buffer->commit_page->write;
854 barrier(); 855 barrier();
855 } 856 }
857
858 /* again, keep gcc from optimizing */
859 barrier();
860
861 /*
862 * If an interrupt came in just after the first while loop
863 * and pushed the tail page forward, we will be left with
864 * a dangling commit that will never go forward.
865 */
866 if (unlikely(cpu_buffer->commit_page != cpu_buffer->tail_page))
867 goto again;
856} 868}
857 869
858static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer) 870static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer)