Skip to content

Commit fe832be

Browse files
committed
ring-buffer: Have mmapped ring buffer keep track of missed events
While testing libtracefs on the mmapped ring buffer, the test that checks if missed events are accounted for failed when using the mapped buffer. This is because the mapped page does not update the missed events that were dropped because the writer filled up the ring buffer before the reader could catch it. Add the missed events to the reader page/sub-buffer when the IOCTL is done and a new reader page is acquired. Note that all accesses to the reader_page via rb_page_commit() had to be switched to rb_page_size(), and rb_page_size() which was just a copy of rb_page_commit() but now it masks out the RB_MISSED bits. This is needed as the mapped reader page is still active in the ring buffer code and where it reads the commit field of the bpage for the size, it now must mask it otherwise the missed bits that are now set will corrupt the size returned. Link: https://lore.kernel.org/linux-trace-kernel/[email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Vincent Donnefort <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 75961e5 commit fe832be

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

kernel/trace/ring_buffer.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ static u64 rb_event_time_stamp(struct ring_buffer_event *event)
314314
/* Missed count stored at end */
315315
#define RB_MISSED_STORED (1 << 30)
316316

317+
#define RB_MISSED_MASK (3 << 30)
318+
317319
struct buffer_data_page {
318320
u64 time_stamp; /* page time stamp */
319321
local_t commit; /* write committed index */
@@ -2326,7 +2328,7 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
23262328
/* Size is determined by what has been committed */
23272329
static __always_inline unsigned rb_page_size(struct buffer_page *bpage)
23282330
{
2329-
return rb_page_commit(bpage);
2331+
return rb_page_commit(bpage) & ~RB_MISSED_MASK;
23302332
}
23312333

23322334
static __always_inline unsigned
@@ -3953,7 +3955,7 @@ static bool rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer)
39533955
return true;
39543956

39553957
/* Reader should exhaust content in reader page */
3956-
if (reader->read != rb_page_commit(reader))
3958+
if (reader->read != rb_page_size(reader))
39573959
return false;
39583960

39593961
/*
@@ -4424,7 +4426,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
44244426
return ((iter->head_page == commit_page && iter->head >= commit) ||
44254427
(iter->head_page == reader && commit_page == head_page &&
44264428
head_page->read == commit &&
4427-
iter->head == rb_page_commit(cpu_buffer->reader_page)));
4429+
iter->head == rb_page_size(cpu_buffer->reader_page)));
44284430
}
44294431
EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
44304432

@@ -5753,7 +5755,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
57535755
event = rb_reader_event(cpu_buffer);
57545756

57555757
read = reader->read;
5756-
commit = rb_page_commit(reader);
5758+
commit = rb_page_size(reader);
57575759

57585760
/* Check if any events were dropped */
57595761
missed_events = cpu_buffer->lost_events;
@@ -5830,7 +5832,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
58305832
} else {
58315833
/* update the entry counter */
58325834
cpu_buffer->read += rb_page_entries(reader);
5833-
cpu_buffer->read_bytes += rb_page_commit(reader);
5835+
cpu_buffer->read_bytes += rb_page_size(reader);
58345836

58355837
/* swap the pages */
58365838
rb_init_page(bpage);
@@ -6422,6 +6424,8 @@ int ring_buffer_unmap(struct trace_buffer *buffer, int cpu)
64226424
int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu)
64236425
{
64246426
struct ring_buffer_per_cpu *cpu_buffer;
6427+
struct buffer_page *reader;
6428+
unsigned long missed_events;
64256429
unsigned long reader_size;
64266430
unsigned long flags;
64276431

@@ -6448,9 +6452,46 @@ int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu)
64486452
goto out;
64496453
}
64506454

6451-
if (WARN_ON(!rb_get_reader_page(cpu_buffer)))
6455+
reader = rb_get_reader_page(cpu_buffer);
6456+
if (WARN_ON(!reader))
64526457
goto out;
64536458

6459+
/* Check if any events were dropped */
6460+
missed_events = cpu_buffer->lost_events;
6461+
6462+
if (cpu_buffer->reader_page != cpu_buffer->commit_page) {
6463+
if (missed_events) {
6464+
struct buffer_data_page *bpage = reader->page;
6465+
unsigned int commit;
6466+
/*
6467+
* Use the real_end for the data size,
6468+
* This gives us a chance to store the lost events
6469+
* on the page.
6470+
*/
6471+
if (reader->real_end)
6472+
local_set(&bpage->commit, reader->real_end);
6473+
/*
6474+
* If there is room at the end of the page to save the
6475+
* missed events, then record it there.
6476+
*/
6477+
commit = rb_page_size(reader);
6478+
if (buffer->subbuf_size - commit >= sizeof(missed_events)) {
6479+
memcpy(&bpage->data[commit], &missed_events,
6480+
sizeof(missed_events));
6481+
local_add(RB_MISSED_STORED, &bpage->commit);
6482+
}
6483+
local_add(RB_MISSED_EVENTS, &bpage->commit);
6484+
}
6485+
} else {
6486+
/*
6487+
* There really shouldn't be any missed events if the commit
6488+
* is on the reader page.
6489+
*/
6490+
WARN_ON_ONCE(missed_events);
6491+
}
6492+
6493+
cpu_buffer->lost_events = 0;
6494+
64546495
goto consume;
64556496

64566497
out:

0 commit comments

Comments
 (0)