Skip to content

Commit 613f04a

Browse files
committed
tracing: Prevent buffer overwrite disabled for latency tracers
The latency tracers require the buffers to be in overwrite mode, otherwise they get screwed up. Force the buffers to stay in overwrite mode when latency tracers are enabled. Added a flag_changed() method to the tracer structure to allow the tracers to see what flags are being changed, and also be able to prevent the change from happing. Cc: [email protected] Signed-off-by: Steven Rostedt <[email protected]>
1 parent 8090282 commit 613f04a

File tree

4 files changed

+65
-16
lines changed

4 files changed

+65
-16
lines changed

kernel/trace/trace.c

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,11 +2881,25 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
28812881
return -EINVAL;
28822882
}
28832883

2884-
static void set_tracer_flags(unsigned int mask, int enabled)
2884+
/* Some tracers require overwrite to stay enabled */
2885+
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
2886+
{
2887+
if (tracer->enabled && (mask & TRACE_ITER_OVERWRITE) && !set)
2888+
return -1;
2889+
2890+
return 0;
2891+
}
2892+
2893+
int set_tracer_flag(unsigned int mask, int enabled)
28852894
{
28862895
/* do nothing if flag is already set */
28872896
if (!!(trace_flags & mask) == !!enabled)
2888-
return;
2897+
return 0;
2898+
2899+
/* Give the tracer a chance to approve the change */
2900+
if (current_trace->flag_changed)
2901+
if (current_trace->flag_changed(current_trace, mask, !!enabled))
2902+
return -EINVAL;
28892903

28902904
if (enabled)
28912905
trace_flags |= mask;
@@ -2904,13 +2918,15 @@ static void set_tracer_flags(unsigned int mask, int enabled)
29042918

29052919
if (mask == TRACE_ITER_PRINTK)
29062920
trace_printk_start_stop_comm(enabled);
2921+
2922+
return 0;
29072923
}
29082924

29092925
static int trace_set_options(char *option)
29102926
{
29112927
char *cmp;
29122928
int neg = 0;
2913-
int ret = 0;
2929+
int ret = -ENODEV;
29142930
int i;
29152931

29162932
cmp = strstrip(option);
@@ -2924,7 +2940,7 @@ static int trace_set_options(char *option)
29242940

29252941
for (i = 0; trace_options[i]; i++) {
29262942
if (strcmp(cmp, trace_options[i]) == 0) {
2927-
set_tracer_flags(1 << i, !neg);
2943+
ret = set_tracer_flag(1 << i, !neg);
29282944
break;
29292945
}
29302946
}
@@ -2943,6 +2959,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
29432959
size_t cnt, loff_t *ppos)
29442960
{
29452961
char buf[64];
2962+
int ret;
29462963

29472964
if (cnt >= sizeof(buf))
29482965
return -EINVAL;
@@ -2952,7 +2969,9 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
29522969

29532970
buf[cnt] = 0;
29542971

2955-
trace_set_options(buf);
2972+
ret = trace_set_options(buf);
2973+
if (ret < 0)
2974+
return ret;
29562975

29572976
*ppos += cnt;
29582977

@@ -3256,6 +3275,9 @@ static int tracing_set_tracer(const char *buf)
32563275
goto out;
32573276

32583277
trace_branch_disable();
3278+
3279+
current_trace->enabled = false;
3280+
32593281
if (current_trace->reset)
32603282
current_trace->reset(tr);
32613283

@@ -3300,6 +3322,7 @@ static int tracing_set_tracer(const char *buf)
33003322
}
33013323

33023324
current_trace = t;
3325+
current_trace->enabled = true;
33033326
trace_branch_enable(tr);
33043327
out:
33053328
mutex_unlock(&trace_types_lock);
@@ -4788,9 +4811,12 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
47884811
return -EINVAL;
47894812

47904813
mutex_lock(&trace_types_lock);
4791-
set_tracer_flags(1 << index, val);
4814+
ret = set_tracer_flag(1 << index, val);
47924815
mutex_unlock(&trace_types_lock);
47934816

4817+
if (ret < 0)
4818+
return ret;
4819+
47944820
*ppos += cnt;
47954821

47964822
return cnt;

kernel/trace/trace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,15 @@ struct tracer {
283283
enum print_line_t (*print_line)(struct trace_iterator *iter);
284284
/* If you handled the flag setting, return 0 */
285285
int (*set_flag)(u32 old_flags, u32 bit, int set);
286+
/* Return 0 if OK with change, else return non-zero */
287+
int (*flag_changed)(struct tracer *tracer,
288+
u32 mask, int set);
286289
struct tracer *next;
287290
struct tracer_flags *flags;
288291
bool print_max;
289292
bool use_max_tr;
290293
bool allocated_snapshot;
294+
bool enabled;
291295
};
292296

293297

@@ -943,6 +947,8 @@ extern const char *__stop___trace_bprintk_fmt[];
943947

944948
void trace_printk_init_buffers(void);
945949
void trace_printk_start_comm(void);
950+
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
951+
int set_tracer_flag(unsigned int mask, int enabled);
946952

947953
#undef FTRACE_ENTRY
948954
#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \

kernel/trace/trace_irqsoff.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ enum {
3232

3333
static int trace_type __read_mostly;
3434

35-
static int save_lat_flag;
35+
static int save_flags;
3636

3737
static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
3838
static int start_irqsoff_tracer(struct trace_array *tr, int graph);
@@ -558,8 +558,11 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
558558

559559
static void __irqsoff_tracer_init(struct trace_array *tr)
560560
{
561-
save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
562-
trace_flags |= TRACE_ITER_LATENCY_FMT;
561+
save_flags = trace_flags;
562+
563+
/* non overwrite screws up the latency tracers */
564+
set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
565+
set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
563566

564567
tracing_max_latency = 0;
565568
irqsoff_trace = tr;
@@ -573,10 +576,13 @@ static void __irqsoff_tracer_init(struct trace_array *tr)
573576

574577
static void irqsoff_tracer_reset(struct trace_array *tr)
575578
{
579+
int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
580+
int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
581+
576582
stop_irqsoff_tracer(tr, is_graph());
577583

578-
if (!save_lat_flag)
579-
trace_flags &= ~TRACE_ITER_LATENCY_FMT;
584+
set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
585+
set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
580586
}
581587

582588
static void irqsoff_tracer_start(struct trace_array *tr)
@@ -609,6 +615,7 @@ static struct tracer irqsoff_tracer __read_mostly =
609615
.print_line = irqsoff_print_line,
610616
.flags = &tracer_flags,
611617
.set_flag = irqsoff_set_flag,
618+
.flag_changed = trace_keep_overwrite,
612619
#ifdef CONFIG_FTRACE_SELFTEST
613620
.selftest = trace_selftest_startup_irqsoff,
614621
#endif
@@ -642,6 +649,7 @@ static struct tracer preemptoff_tracer __read_mostly =
642649
.print_line = irqsoff_print_line,
643650
.flags = &tracer_flags,
644651
.set_flag = irqsoff_set_flag,
652+
.flag_changed = trace_keep_overwrite,
645653
#ifdef CONFIG_FTRACE_SELFTEST
646654
.selftest = trace_selftest_startup_preemptoff,
647655
#endif
@@ -677,6 +685,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
677685
.print_line = irqsoff_print_line,
678686
.flags = &tracer_flags,
679687
.set_flag = irqsoff_set_flag,
688+
.flag_changed = trace_keep_overwrite,
680689
#ifdef CONFIG_FTRACE_SELFTEST
681690
.selftest = trace_selftest_startup_preemptirqsoff,
682691
#endif

kernel/trace/trace_sched_wakeup.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static void __wakeup_reset(struct trace_array *tr);
3636
static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
3737
static void wakeup_graph_return(struct ftrace_graph_ret *trace);
3838

39-
static int save_lat_flag;
39+
static int save_flags;
4040

4141
#define TRACE_DISPLAY_GRAPH 1
4242

@@ -540,8 +540,11 @@ static void stop_wakeup_tracer(struct trace_array *tr)
540540

541541
static int __wakeup_tracer_init(struct trace_array *tr)
542542
{
543-
save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
544-
trace_flags |= TRACE_ITER_LATENCY_FMT;
543+
save_flags = trace_flags;
544+
545+
/* non overwrite screws up the latency tracers */
546+
set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
547+
set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
545548

546549
tracing_max_latency = 0;
547550
wakeup_trace = tr;
@@ -563,12 +566,15 @@ static int wakeup_rt_tracer_init(struct trace_array *tr)
563566

564567
static void wakeup_tracer_reset(struct trace_array *tr)
565568
{
569+
int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
570+
int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
571+
566572
stop_wakeup_tracer(tr);
567573
/* make sure we put back any tasks we are tracing */
568574
wakeup_reset(tr);
569575

570-
if (!save_lat_flag)
571-
trace_flags &= ~TRACE_ITER_LATENCY_FMT;
576+
set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
577+
set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
572578
}
573579

574580
static void wakeup_tracer_start(struct trace_array *tr)
@@ -594,6 +600,7 @@ static struct tracer wakeup_tracer __read_mostly =
594600
.print_line = wakeup_print_line,
595601
.flags = &tracer_flags,
596602
.set_flag = wakeup_set_flag,
603+
.flag_changed = trace_keep_overwrite,
597604
#ifdef CONFIG_FTRACE_SELFTEST
598605
.selftest = trace_selftest_startup_wakeup,
599606
#endif
@@ -615,6 +622,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
615622
.print_line = wakeup_print_line,
616623
.flags = &tracer_flags,
617624
.set_flag = wakeup_set_flag,
625+
.flag_changed = trace_keep_overwrite,
618626
#ifdef CONFIG_FTRACE_SELFTEST
619627
.selftest = trace_selftest_startup_wakeup,
620628
#endif

0 commit comments

Comments
 (0)