Skip to content

Commit 6c536d7

Browse files
committed
tracing: Disable preemption when using the filter buffer
In case trace_event_buffer_lock_reserve() is called with preemption enabled, the algorithm that defines the usage of the per cpu filter buffer may fail if the task schedules to another CPU after determining which buffer it will use. Disable preemption when using the filter buffer. And because that same buffer must be used throughout the call, keep preemption disabled until the filter buffer is released. This will also keep the semantics between the use case of when the filter buffer is used, and when the ring buffer itself is used, as that case also disables preemption until the ring buffer is released. Link: https://lkml.kernel.org/r/[email protected] [ Fixed warning of assignment in if statement Reported-by: kernel test robot <[email protected]> ] Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent e07a1d5 commit 6c536d7

File tree

2 files changed

+36
-27
lines changed

2 files changed

+36
-27
lines changed

kernel/trace/trace.c

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,8 @@ __buffer_unlock_commit(struct trace_buffer *buffer, struct ring_buffer_event *ev
980980
ring_buffer_write(buffer, event->array[0], &event->array[1]);
981981
/* Release the temp buffer */
982982
this_cpu_dec(trace_buffered_event_cnt);
983+
/* ring_buffer_unlock_commit() enables preemption */
984+
preempt_enable_notrace();
983985
} else
984986
ring_buffer_unlock_commit(buffer, event);
985987
}
@@ -2745,8 +2747,8 @@ trace_event_buffer_lock_reserve(struct trace_buffer **current_rb,
27452747
*current_rb = tr->array_buffer.buffer;
27462748

27472749
if (!tr->no_filter_buffering_ref &&
2748-
(trace_file->flags & (EVENT_FILE_FL_SOFT_DISABLED | EVENT_FILE_FL_FILTERED)) &&
2749-
(entry = __this_cpu_read(trace_buffered_event))) {
2750+
(trace_file->flags & (EVENT_FILE_FL_SOFT_DISABLED | EVENT_FILE_FL_FILTERED))) {
2751+
preempt_disable_notrace();
27502752
/*
27512753
* Filtering is on, so try to use the per cpu buffer first.
27522754
* This buffer will simulate a ring_buffer_event,
@@ -2764,33 +2766,38 @@ trace_event_buffer_lock_reserve(struct trace_buffer **current_rb,
27642766
* is still quicker than no copy on match, but having
27652767
* to discard out of the ring buffer on a failed match.
27662768
*/
2767-
int max_len = PAGE_SIZE - struct_size(entry, array, 1);
2769+
if ((entry = __this_cpu_read(trace_buffered_event))) {
2770+
int max_len = PAGE_SIZE - struct_size(entry, array, 1);
27682771

2769-
val = this_cpu_inc_return(trace_buffered_event_cnt);
2772+
val = this_cpu_inc_return(trace_buffered_event_cnt);
27702773

2771-
/*
2772-
* Preemption is disabled, but interrupts and NMIs
2773-
* can still come in now. If that happens after
2774-
* the above increment, then it will have to go
2775-
* back to the old method of allocating the event
2776-
* on the ring buffer, and if the filter fails, it
2777-
* will have to call ring_buffer_discard_commit()
2778-
* to remove it.
2779-
*
2780-
* Need to also check the unlikely case that the
2781-
* length is bigger than the temp buffer size.
2782-
* If that happens, then the reserve is pretty much
2783-
* guaranteed to fail, as the ring buffer currently
2784-
* only allows events less than a page. But that may
2785-
* change in the future, so let the ring buffer reserve
2786-
* handle the failure in that case.
2787-
*/
2788-
if (val == 1 && likely(len <= max_len)) {
2789-
trace_event_setup(entry, type, trace_ctx);
2790-
entry->array[0] = len;
2791-
return entry;
2774+
/*
2775+
* Preemption is disabled, but interrupts and NMIs
2776+
* can still come in now. If that happens after
2777+
* the above increment, then it will have to go
2778+
* back to the old method of allocating the event
2779+
* on the ring buffer, and if the filter fails, it
2780+
* will have to call ring_buffer_discard_commit()
2781+
* to remove it.
2782+
*
2783+
* Need to also check the unlikely case that the
2784+
* length is bigger than the temp buffer size.
2785+
* If that happens, then the reserve is pretty much
2786+
* guaranteed to fail, as the ring buffer currently
2787+
* only allows events less than a page. But that may
2788+
* change in the future, so let the ring buffer reserve
2789+
* handle the failure in that case.
2790+
*/
2791+
if (val == 1 && likely(len <= max_len)) {
2792+
trace_event_setup(entry, type, trace_ctx);
2793+
entry->array[0] = len;
2794+
/* Return with preemption disabled */
2795+
return entry;
2796+
}
2797+
this_cpu_dec(trace_buffered_event_cnt);
27922798
}
2793-
this_cpu_dec(trace_buffered_event_cnt);
2799+
/* __trace_buffer_lock_reserve() disables preemption */
2800+
preempt_enable_notrace();
27942801
}
27952802

27962803
entry = __trace_buffer_lock_reserve(*current_rb, type, len,

kernel/trace/trace.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1337,10 +1337,12 @@ __trace_event_discard_commit(struct trace_buffer *buffer,
13371337
struct ring_buffer_event *event)
13381338
{
13391339
if (this_cpu_read(trace_buffered_event) == event) {
1340-
/* Simply release the temp buffer */
1340+
/* Simply release the temp buffer and enable preemption */
13411341
this_cpu_dec(trace_buffered_event_cnt);
1342+
preempt_enable_notrace();
13421343
return;
13431344
}
1345+
/* ring_buffer_discard_commit() enables preemption */
13441346
ring_buffer_discard_commit(buffer, event);
13451347
}
13461348

0 commit comments

Comments
 (0)