From: Masami Hiramatsu (Google) <[email protected]> Record an invalid buffer event on the invalidated sub buffer so that user can notice how much data is skipped.
Signed-off-by: Masami Hiramatsu (Google) <[email protected]> --- kernel/trace/ring_buffer.c | 43 ++++++++++++++++++++++++++++++++++++------ kernel/trace/trace.h | 1 + kernel/trace/trace_entries.h | 15 +++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 0ae2a5ad8c3e..98df5a67de26 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1911,6 +1911,38 @@ static int rb_validate_buffer(struct buffer_data_page *dpage, int cpu) return rb_read_data_buffer(dpage, tail, cpu, &ts, &delta); } +/* Inject invalid_buffer event */ +static void rb_record_invalid_buffer(struct buffer_page *buffer, + long commit_bytes, long entries, + int buffer_index) +{ + struct buffer_data_page *dpage = buffer->page; + struct invalid_subbuf_entry *entry; + struct ring_buffer_event *event; + long length; + + length = DIV_ROUND_UP(sizeof(*entry), RB_ALIGNMENT); + + /* + * Instead of ring_buffer_lock_reserve(), directly allocate it on + * the first entry of specific buffer_page. + */ + event = (struct ring_buffer_event *)&dpage->data[0]; + event->type_len = length; + event->time_delta = 0; + + trace_event_setup(event, TRACE_INVALID_BUF, 0); + + entry = ring_buffer_event_data(event); + entry->lost_bytes = commit_bytes; + entry->lost_entries = entries; + entry->buffer_index = buffer_index; + + /* This buffer_page has only one event. */ + local_set(&buffer->entries, 1); + local_set(&buffer->page->commit, rb_event_data_length(event)); +} + /* If the meta data has been validated, now validate the events */ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer) { @@ -2043,12 +2075,11 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer) ret = rb_validate_buffer(head_page->page, cpu_buffer->cpu); if (ret < 0) { - pr_info("Ring buffer meta [%d] invalid buffer page\n", - cpu_buffer->cpu); - /* Instead of invalidate whole ring buffer, just clear this subbuffer. */ - local_set(&head_page->entries, 0); - local_set(&head_page->page->commit, 0); - /* TODO: commit an event to mark this is broken. */ + /* Discard invalid buffer and record it. */ + rb_record_invalid_buffer(head_page, + local_read(&head_page->page->commit), + local_read(&head_page->entries), + rb_meta_subbuf_idx(meta, head_page->page)); } else { /* If the buffer has content, update pages_touched */ if (ret) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 7894bf55743c..667834edb5b9 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -57,6 +57,7 @@ enum trace_type { TRACE_TIMERLAT, TRACE_RAW_DATA, TRACE_FUNC_REPEATS, + TRACE_INVALID_BUF, __TRACE_LAST_TYPE, }; diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index f6a8d29c0d76..df39fc245ab4 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -457,3 +457,18 @@ FTRACE_ENTRY(timerlat, timerlat_entry, __entry->context, __entry->timer_latency) ); + +FTRACE_ENTRY(invalid_subbuf, invalid_subbuf_entry, + TRACE_INVALID_BUF, + + F_STRUCT( + __field( long, lost_bytes ) + __field( long, lost_entries ) + __field( int, buffer_index ) + ), + + F_printk("lost_bytes:%ld\tlost_entries:%ld\tbuffer_index:%d\n", + __entry->lost_bytes, + __entry->lost_entries, + __entry->buffer_index) +);
