ring-buffer: Do not die if rb_iter_peek() fails more than thrice
authorSteven Rostedt (VMware) <rostedt@goodmis.org>
Tue, 17 Mar 2020 21:32:28 +0000 (17:32 -0400)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Thu, 19 Mar 2020 23:11:19 +0000 (19:11 -0400)
As the iterator will be reading a live buffer, and if the event being read
is on a page that a writer crosses, it will fail and try again, the
condition in rb_iter_peek() that only allows a retry to happen three times
is no longer valid. Allow rb_iter_peek() to retry more than three times
without killing the ring buffer, but only if rb_iter_head_event() had failed
at least once.

Link: http://lkml.kernel.org/r/20200317213416.452888193@goodmis.org
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
kernel/trace/ring_buffer.c

index 3d718add73c1e4a28be270429bb70e4f156d34ca..475338fda969baf876da03ebf891ec0105c5d004 100644 (file)
@@ -4012,6 +4012,7 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
        struct ring_buffer_per_cpu *cpu_buffer;
        struct ring_buffer_event *event;
        int nr_loops = 0;
+       bool failed = false;
 
        if (ts)
                *ts = 0;
@@ -4038,10 +4039,14 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
         * to a data event, we should never loop more than three times.
         * Once for going to next page, once on time extend, and
         * finally once to get the event.
-        * (We never hit the following condition more than thrice).
+        * We should never hit the following condition more than thrice,
+        * unless the buffer is very small, and there's a writer
+        * that is causing the reader to fail getting an event.
         */
-       if (RB_WARN_ON(cpu_buffer, ++nr_loops > 3))
+       if (++nr_loops > 3) {
+               RB_WARN_ON(cpu_buffer, !failed);
                return NULL;
+       }
 
        if (rb_per_cpu_empty(cpu_buffer))
                return NULL;
@@ -4052,8 +4057,10 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
        }
 
        event = rb_iter_head_event(iter);
-       if (!event)
+       if (!event) {
+               failed = true;
                goto again;
+       }
 
        switch (event->type_len) {
        case RINGBUF_TYPE_PADDING: