Skip to content

Commit c4a80c0

Browse files
committed
tracing: Use atomic_inc_return() for updating "disabled" counter in irqsoff tracer
The irqsoff tracer uses the per CPU "disabled" field to prevent corruption of the accounting when it starts to trace interrupts disabled, but there's a slight race that could happen if for some reason it was called twice. Use atomic_inc_return() instead. Cc: Masami Hiramatsu <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Andrew Morton <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 90633c3 commit c4a80c0

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

kernel/trace/trace_irqsoff.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip)
397397
int cpu;
398398
struct trace_array *tr = irqsoff_trace;
399399
struct trace_array_cpu *data;
400+
long disabled;
400401

401402
if (!tracer_enabled || !tracing_is_enabled())
402403
return;
@@ -411,15 +412,17 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip)
411412
if (unlikely(!data) || local_read(&data->disabled))
412413
return;
413414

414-
local_inc(&data->disabled);
415+
disabled = local_inc_return(&data->disabled);
415416

416-
data->critical_sequence = max_sequence;
417-
data->preempt_timestamp = ftrace_now(cpu);
418-
data->critical_start = parent_ip ? : ip;
417+
if (disabled == 1) {
418+
data->critical_sequence = max_sequence;
419+
data->preempt_timestamp = ftrace_now(cpu);
420+
data->critical_start = parent_ip ? : ip;
419421

420-
__trace_function(tr, ip, parent_ip, tracing_gen_ctx());
422+
__trace_function(tr, ip, parent_ip, tracing_gen_ctx());
421423

422-
per_cpu(tracing_cpu, cpu) = 1;
424+
per_cpu(tracing_cpu, cpu) = 1;
425+
}
423426

424427
local_dec(&data->disabled);
425428
}
@@ -431,6 +434,7 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip)
431434
struct trace_array *tr = irqsoff_trace;
432435
struct trace_array_cpu *data;
433436
unsigned int trace_ctx;
437+
long disabled;
434438

435439
cpu = raw_smp_processor_id();
436440
/* Always clear the tracing cpu on stopping the trace */
@@ -448,12 +452,15 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip)
448452
!data->critical_start || local_read(&data->disabled))
449453
return;
450454

451-
local_inc(&data->disabled);
455+
disabled = local_inc_return(&data->disabled);
456+
457+
if (disabled == 1) {
458+
trace_ctx = tracing_gen_ctx();
459+
__trace_function(tr, ip, parent_ip, trace_ctx);
460+
check_critical_timing(tr, data, parent_ip ? : ip, cpu);
461+
data->critical_start = 0;
462+
}
452463

453-
trace_ctx = tracing_gen_ctx();
454-
__trace_function(tr, ip, parent_ip, trace_ctx);
455-
check_critical_timing(tr, data, parent_ip ? : ip, cpu);
456-
data->critical_start = 0;
457464
local_dec(&data->disabled);
458465
}
459466

0 commit comments

Comments
 (0)