Skip to content

Commit

Permalink
tracing: Prevent buffer overwrite disabled for latency tracers
Browse files Browse the repository at this point in the history
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: stable@vger.kernel.org
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (Red Hat) committed Mar 15, 2013
1 parent 8090282 commit 613f04a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 16 deletions.
38 changes: 32 additions & 6 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2881,11 +2881,25 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
return -EINVAL;
}

static void set_tracer_flags(unsigned int mask, int enabled)
/* Some tracers require overwrite to stay enabled */
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
{
if (tracer->enabled && (mask & TRACE_ITER_OVERWRITE) && !set)
return -1;

return 0;
}

int set_tracer_flag(unsigned int mask, int enabled)
{
/* do nothing if flag is already set */
if (!!(trace_flags & mask) == !!enabled)
return;
return 0;

/* Give the tracer a chance to approve the change */
if (current_trace->flag_changed)
if (current_trace->flag_changed(current_trace, mask, !!enabled))
return -EINVAL;

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

if (mask == TRACE_ITER_PRINTK)
trace_printk_start_stop_comm(enabled);

return 0;
}

static int trace_set_options(char *option)
{
char *cmp;
int neg = 0;
int ret = 0;
int ret = -ENODEV;
int i;

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

for (i = 0; trace_options[i]; i++) {
if (strcmp(cmp, trace_options[i]) == 0) {
set_tracer_flags(1 << i, !neg);
ret = set_tracer_flag(1 << i, !neg);
break;
}
}
Expand All @@ -2943,6 +2959,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char buf[64];
int ret;

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

buf[cnt] = 0;

trace_set_options(buf);
ret = trace_set_options(buf);
if (ret < 0)
return ret;

*ppos += cnt;

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

trace_branch_disable();

current_trace->enabled = false;

if (current_trace->reset)
current_trace->reset(tr);

Expand Down Expand Up @@ -3300,6 +3322,7 @@ static int tracing_set_tracer(const char *buf)
}

current_trace = t;
current_trace->enabled = true;
trace_branch_enable(tr);
out:
mutex_unlock(&trace_types_lock);
Expand Down Expand Up @@ -4788,9 +4811,12 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
return -EINVAL;

mutex_lock(&trace_types_lock);
set_tracer_flags(1 << index, val);
ret = set_tracer_flag(1 << index, val);
mutex_unlock(&trace_types_lock);

if (ret < 0)
return ret;

*ppos += cnt;

return cnt;
Expand Down
6 changes: 6 additions & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,15 @@ struct tracer {
enum print_line_t (*print_line)(struct trace_iterator *iter);
/* If you handled the flag setting, return 0 */
int (*set_flag)(u32 old_flags, u32 bit, int set);
/* Return 0 if OK with change, else return non-zero */
int (*flag_changed)(struct tracer *tracer,
u32 mask, int set);
struct tracer *next;
struct tracer_flags *flags;
bool print_max;
bool use_max_tr;
bool allocated_snapshot;
bool enabled;
};


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

void trace_printk_init_buffers(void);
void trace_printk_start_comm(void);
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
int set_tracer_flag(unsigned int mask, int enabled);

#undef FTRACE_ENTRY
#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \
Expand Down
19 changes: 14 additions & 5 deletions kernel/trace/trace_irqsoff.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ enum {

static int trace_type __read_mostly;

static int save_lat_flag;
static int save_flags;

static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
static int start_irqsoff_tracer(struct trace_array *tr, int graph);
Expand Down Expand Up @@ -558,8 +558,11 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)

static void __irqsoff_tracer_init(struct trace_array *tr)
{
save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
trace_flags |= TRACE_ITER_LATENCY_FMT;
save_flags = trace_flags;

/* non overwrite screws up the latency tracers */
set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);

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

static void irqsoff_tracer_reset(struct trace_array *tr)
{
int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;

stop_irqsoff_tracer(tr, is_graph());

if (!save_lat_flag)
trace_flags &= ~TRACE_ITER_LATENCY_FMT;
set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
}

static void irqsoff_tracer_start(struct trace_array *tr)
Expand Down Expand Up @@ -609,6 +615,7 @@ static struct tracer irqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_irqsoff,
#endif
Expand Down Expand Up @@ -642,6 +649,7 @@ static struct tracer preemptoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptoff,
#endif
Expand Down Expand Up @@ -677,6 +685,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptirqsoff,
#endif
Expand Down
18 changes: 13 additions & 5 deletions kernel/trace/trace_sched_wakeup.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static void __wakeup_reset(struct trace_array *tr);
static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
static void wakeup_graph_return(struct ftrace_graph_ret *trace);

static int save_lat_flag;
static int save_flags;

#define TRACE_DISPLAY_GRAPH 1

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

static int __wakeup_tracer_init(struct trace_array *tr)
{
save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
trace_flags |= TRACE_ITER_LATENCY_FMT;
save_flags = trace_flags;

/* non overwrite screws up the latency tracers */
set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);

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

static void wakeup_tracer_reset(struct trace_array *tr)
{
int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;

stop_wakeup_tracer(tr);
/* make sure we put back any tasks we are tracing */
wakeup_reset(tr);

if (!save_lat_flag)
trace_flags &= ~TRACE_ITER_LATENCY_FMT;
set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
}

static void wakeup_tracer_start(struct trace_array *tr)
Expand All @@ -594,6 +600,7 @@ static struct tracer wakeup_tracer __read_mostly =
.print_line = wakeup_print_line,
.flags = &tracer_flags,
.set_flag = wakeup_set_flag,
.flag_changed = trace_keep_overwrite,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
Expand All @@ -615,6 +622,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
.print_line = wakeup_print_line,
.flags = &tracer_flags,
.set_flag = wakeup_set_flag,
.flag_changed = trace_keep_overwrite,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
Expand Down

0 comments on commit 613f04a

Please sign in to comment.