Skip to content

Commit dd93942

Browse files
committed
ring-buffer: Do not try to put back write_stamp
If an update to an event is interrupted by another event between the time the initial event allocated its buffer and where it wrote to the write_stamp, the code try to reset the write stamp back to the what it had just overwritten. It knows that it was overwritten via checking the before_stamp, and if it didn't match what it wrote to the before_stamp before it allocated its space, it knows it was overwritten. To put back the write_stamp, it uses the before_stamp it read. The problem here is that by writing the before_stamp to the write_stamp it makes the two equal again, which means that the write_stamp can be considered valid as the last timestamp written to the ring buffer. But this is not necessarily true. The event that interrupted the event could have been interrupted in a way that it was interrupted as well, and can end up leaving with an invalid write_stamp. But if this happens and returns to this context that uses the before_stamp to update the write_stamp again, it can possibly incorrectly make it valid, causing later events to have in correct time stamps. As it is OK to leave this function with an invalid write_stamp (one that doesn't match the before_stamp), there's no reason to try to make it valid again in this case. If this race happens, then just leave with the invalid write_stamp and the next event to come along will just add a absolute timestamp and validate everything again. Bonus points: This gets rid of another cmpxchg64! Link: https://lore.kernel.org/linux-trace-kernel/[email protected] Cc: [email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Joel Fernandes <[email protected]> Cc: Vincent Donnefort <[email protected]> Fixes: a389d86 ("ring-buffer: Have nested events still record running time stamp") Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 1cc111b commit dd93942

File tree

1 file changed

+6
-23
lines changed

1 file changed

+6
-23
lines changed

kernel/trace/ring_buffer.c

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,39 +3612,22 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
36123612
}
36133613

36143614
if (likely(tail == w)) {
3615-
u64 save_before;
3616-
bool s_ok;
3617-
36183615
/* Nothing interrupted us between A and C */
36193616
/*D*/ rb_time_set(&cpu_buffer->write_stamp, info->ts);
3620-
barrier();
3621-
/*E*/ s_ok = rb_time_read(&cpu_buffer->before_stamp, &save_before);
3622-
RB_WARN_ON(cpu_buffer, !s_ok);
3617+
/*
3618+
* If something came in between C and D, the write stamp
3619+
* may now not be in sync. But that's fine as the before_stamp
3620+
* will be different and then next event will just be forced
3621+
* to use an absolute timestamp.
3622+
*/
36233623
if (likely(!(info->add_timestamp &
36243624
(RB_ADD_STAMP_FORCE | RB_ADD_STAMP_ABSOLUTE))))
36253625
/* This did not interrupt any time update */
36263626
info->delta = info->ts - info->after;
36273627
else
36283628
/* Just use full timestamp for interrupting event */
36293629
info->delta = info->ts;
3630-
barrier();
36313630
check_buffer(cpu_buffer, info, tail);
3632-
if (unlikely(info->ts != save_before)) {
3633-
/* SLOW PATH - Interrupted between C and E */
3634-
3635-
a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
3636-
RB_WARN_ON(cpu_buffer, !a_ok);
3637-
3638-
/* Write stamp must only go forward */
3639-
if (save_before > info->after) {
3640-
/*
3641-
* We do not care about the result, only that
3642-
* it gets updated atomically.
3643-
*/
3644-
(void)rb_time_cmpxchg(&cpu_buffer->write_stamp,
3645-
info->after, save_before);
3646-
}
3647-
}
36483631
} else {
36493632
u64 ts;
36503633
/* SLOW PATH - Interrupted between A and C */

0 commit comments

Comments
 (0)