Skip to content

Commit a948c69

Browse files
committed
ring-buffer: Add verifier for using ring_buffer_event_time_stamp()
The ring_buffer_event_time_stamp() must be only called by an event that has not been committed yet, and is on the buffer that is passed in. This was used to help debug converting the histogram logic over to using the new time stamp code, and was proven to be very useful. Add a verifier that can check that this is the case, and extra WARN_ONs to catch unexpected use cases. Link: https://lkml.kernel.org/r/[email protected] Reviewed-by: Tom Zanussi <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent b94bc80 commit a948c69

File tree

1 file changed

+52
-4
lines changed

1 file changed

+52
-4
lines changed

kernel/trace/ring_buffer.c

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,48 @@ static bool rb_time_cmpxchg(rb_time_t *t, u64 expect, u64 set)
742742
}
743743
#endif
744744

745+
/*
746+
* Enable this to make sure that the event passed to
747+
* ring_buffer_event_time_stamp() is not committed and also
748+
* is on the buffer that it passed in.
749+
*/
750+
//#define RB_VERIFY_EVENT
751+
#ifdef RB_VERIFY_EVENT
752+
static struct list_head *rb_list_head(struct list_head *list);
753+
static void verify_event(struct ring_buffer_per_cpu *cpu_buffer,
754+
void *event)
755+
{
756+
struct buffer_page *page = cpu_buffer->commit_page;
757+
struct buffer_page *tail_page = READ_ONCE(cpu_buffer->tail_page);
758+
struct list_head *next;
759+
long commit, write;
760+
unsigned long addr = (unsigned long)event;
761+
bool done = false;
762+
int stop = 0;
763+
764+
/* Make sure the event exists and is not committed yet */
765+
do {
766+
if (page == tail_page || WARN_ON_ONCE(stop++ > 100))
767+
done = true;
768+
commit = local_read(&page->page->commit);
769+
write = local_read(&page->write);
770+
if (addr >= (unsigned long)&page->page->data[commit] &&
771+
addr < (unsigned long)&page->page->data[write])
772+
return;
773+
774+
next = rb_list_head(page->list.next);
775+
page = list_entry(next, struct buffer_page, list);
776+
} while (!done);
777+
WARN_ON_ONCE(1);
778+
}
779+
#else
780+
static inline void verify_event(struct ring_buffer_per_cpu *cpu_buffer,
781+
void *event)
782+
{
783+
}
784+
#endif
785+
786+
745787
static inline u64 rb_time_stamp(struct trace_buffer *buffer);
746788

747789
/**
@@ -772,13 +814,19 @@ u64 ring_buffer_event_time_stamp(struct trace_buffer *buffer,
772814
if (event->type_len == RINGBUF_TYPE_TIME_STAMP)
773815
return rb_event_time_stamp(event);
774816

817+
nest = local_read(&cpu_buffer->committing);
818+
verify_event(cpu_buffer, event);
819+
if (WARN_ON_ONCE(!nest))
820+
goto fail;
821+
775822
/* Read the current saved nesting level time stamp */
776-
nest = local_read(&cpu_buffer->committing) - 1;
777-
if (likely(nest < MAX_NEST))
823+
if (likely(--nest < MAX_NEST))
778824
return cpu_buffer->event_stamp[nest];
779825

780-
WARN_ON_ONCE(1);
826+
/* Shouldn't happen, warn if it does */
827+
WARN_ONCE(1, "nest (%d) greater than max", nest);
781828

829+
fail:
782830
/* Can only fail on 32 bit */
783831
if (!rb_time_read(&cpu_buffer->write_stamp, &ts))
784832
/* Screw it, just read the current time */
@@ -2750,7 +2798,7 @@ rb_update_event(struct ring_buffer_per_cpu *cpu_buffer,
27502798
u64 delta = info->delta;
27512799
unsigned int nest = local_read(&cpu_buffer->committing) - 1;
27522800

2753-
if (nest < MAX_NEST)
2801+
if (!WARN_ON_ONCE(nest >= MAX_NEST))
27542802
cpu_buffer->event_stamp[nest] = info->ts;
27552803

27562804
/*

0 commit comments

Comments
 (0)