Commit 328df475 authored by Steven Rostedt (Red Hat)'s avatar Steven Rostedt (Red Hat) Committed by Steven Rostedt

tracing: Add function-trace option to disable function tracing of latency tracers

Currently, the only way to stop the latency tracers from doing function
tracing is to fully disable the function tracer from the proc file
system:

  echo 0 > /proc/sys/kernel/ftrace_enabled

This is a big hammer approach as it disables function tracing for
all users. This includes kprobes, perf, stack tracer, etc.

Instead, create a function-trace option that the latency tracers can
check to determine if it should enable function tracing or not.
This option can be set or cleared even while the tracer is active
and the tracers will disable or enable function tracing depending
on how the option was set.

Instead of using the proc file, disable latency function tracing with

  echo 0 > /debug/tracing/options/function-trace

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Clark Williams <williams@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 4df29712
...@@ -328,7 +328,7 @@ static inline void trace_access_lock_init(void) ...@@ -328,7 +328,7 @@ static inline void trace_access_lock_init(void)
unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME | TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE | TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS; TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION;
/** /**
* tracing_on - enable tracing buffers * tracing_on - enable tracing buffers
...@@ -635,6 +635,7 @@ static const char *trace_options[] = { ...@@ -635,6 +635,7 @@ static const char *trace_options[] = {
"disable_on_free", "disable_on_free",
"irq-info", "irq-info",
"markers", "markers",
"function-trace",
NULL NULL
}; };
......
...@@ -867,6 +867,7 @@ enum trace_iterator_flags { ...@@ -867,6 +867,7 @@ enum trace_iterator_flags {
TRACE_ITER_STOP_ON_FREE = 0x400000, TRACE_ITER_STOP_ON_FREE = 0x400000,
TRACE_ITER_IRQ_INFO = 0x800000, TRACE_ITER_IRQ_INFO = 0x800000,
TRACE_ITER_MARKERS = 0x1000000, TRACE_ITER_MARKERS = 0x1000000,
TRACE_ITER_FUNCTION = 0x2000000,
}; };
/* /*
......
...@@ -33,6 +33,7 @@ enum { ...@@ -33,6 +33,7 @@ enum {
static int trace_type __read_mostly; static int trace_type __read_mostly;
static int save_flags; static int save_flags;
static bool function_enabled;
static void stop_irqsoff_tracer(struct trace_array *tr, int graph); static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
static int start_irqsoff_tracer(struct trace_array *tr, int graph); static int start_irqsoff_tracer(struct trace_array *tr, int graph);
...@@ -528,15 +529,60 @@ void trace_preempt_off(unsigned long a0, unsigned long a1) ...@@ -528,15 +529,60 @@ void trace_preempt_off(unsigned long a0, unsigned long a1)
} }
#endif /* CONFIG_PREEMPT_TRACER */ #endif /* CONFIG_PREEMPT_TRACER */
static int start_irqsoff_tracer(struct trace_array *tr, int graph) static int register_irqsoff_function(int graph, int set)
{ {
int ret = 0; int ret;
if (!graph) /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
ret = register_ftrace_function(&trace_ops); if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
else return 0;
if (graph)
ret = register_ftrace_graph(&irqsoff_graph_return, ret = register_ftrace_graph(&irqsoff_graph_return,
&irqsoff_graph_entry); &irqsoff_graph_entry);
else
ret = register_ftrace_function(&trace_ops);
if (!ret)
function_enabled = true;
return ret;
}
static void unregister_irqsoff_function(int graph)
{
if (!function_enabled)
return;
if (graph)
unregister_ftrace_graph();
else
unregister_ftrace_function(&trace_ops);
function_enabled = false;
}
static void irqsoff_function_set(int set)
{
if (set)
register_irqsoff_function(is_graph(), 1);
else
unregister_irqsoff_function(is_graph());
}
static int irqsoff_flag_changed(struct tracer *tracer, u32 mask, int set)
{
if (mask & TRACE_ITER_FUNCTION)
irqsoff_function_set(set);
return trace_keep_overwrite(tracer, mask, set);
}
static int start_irqsoff_tracer(struct trace_array *tr, int graph)
{
int ret;
ret = register_irqsoff_function(graph, 0);
if (!ret && tracing_is_enabled()) if (!ret && tracing_is_enabled())
tracer_enabled = 1; tracer_enabled = 1;
...@@ -550,10 +596,7 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph) ...@@ -550,10 +596,7 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
{ {
tracer_enabled = 0; tracer_enabled = 0;
if (!graph) unregister_irqsoff_function(graph);
unregister_ftrace_function(&trace_ops);
else
unregister_ftrace_graph();
} }
static void __irqsoff_tracer_init(struct trace_array *tr) static void __irqsoff_tracer_init(struct trace_array *tr)
...@@ -615,7 +658,7 @@ static struct tracer irqsoff_tracer __read_mostly = ...@@ -615,7 +658,7 @@ static struct tracer irqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line, .print_line = irqsoff_print_line,
.flags = &tracer_flags, .flags = &tracer_flags,
.set_flag = irqsoff_set_flag, .set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite, .flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST #ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_irqsoff, .selftest = trace_selftest_startup_irqsoff,
#endif #endif
...@@ -649,7 +692,7 @@ static struct tracer preemptoff_tracer __read_mostly = ...@@ -649,7 +692,7 @@ static struct tracer preemptoff_tracer __read_mostly =
.print_line = irqsoff_print_line, .print_line = irqsoff_print_line,
.flags = &tracer_flags, .flags = &tracer_flags,
.set_flag = irqsoff_set_flag, .set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite, .flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST #ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptoff, .selftest = trace_selftest_startup_preemptoff,
#endif #endif
...@@ -685,7 +728,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly = ...@@ -685,7 +728,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line, .print_line = irqsoff_print_line,
.flags = &tracer_flags, .flags = &tracer_flags,
.set_flag = irqsoff_set_flag, .set_flag = irqsoff_set_flag,
.flag_changed = trace_keep_overwrite, .flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST #ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptirqsoff, .selftest = trace_selftest_startup_preemptirqsoff,
#endif #endif
......
...@@ -37,6 +37,7 @@ static int wakeup_graph_entry(struct ftrace_graph_ent *trace); ...@@ -37,6 +37,7 @@ static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
static void wakeup_graph_return(struct ftrace_graph_ret *trace); static void wakeup_graph_return(struct ftrace_graph_ret *trace);
static int save_flags; static int save_flags;
static bool function_enabled;
#define TRACE_DISPLAY_GRAPH 1 #define TRACE_DISPLAY_GRAPH 1
...@@ -134,15 +135,60 @@ static struct ftrace_ops trace_ops __read_mostly = ...@@ -134,15 +135,60 @@ static struct ftrace_ops trace_ops __read_mostly =
}; };
#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_TRACER */
static int start_func_tracer(int graph) static int register_wakeup_function(int graph, int set)
{ {
int ret; int ret;
if (!graph) /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
ret = register_ftrace_function(&trace_ops); if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
else return 0;
if (graph)
ret = register_ftrace_graph(&wakeup_graph_return, ret = register_ftrace_graph(&wakeup_graph_return,
&wakeup_graph_entry); &wakeup_graph_entry);
else
ret = register_ftrace_function(&trace_ops);
if (!ret)
function_enabled = true;
return ret;
}
static void unregister_wakeup_function(int graph)
{
if (!function_enabled)
return;
if (graph)
unregister_ftrace_graph();
else
unregister_ftrace_function(&trace_ops);
function_enabled = false;
}
static void wakeup_function_set(int set)
{
if (set)
register_wakeup_function(is_graph(), 1);
else
unregister_wakeup_function(is_graph());
}
static int wakeup_flag_changed(struct tracer *tracer, u32 mask, int set)
{
if (mask & TRACE_ITER_FUNCTION)
wakeup_function_set(set);
return trace_keep_overwrite(tracer, mask, set);
}
static int start_func_tracer(int graph)
{
int ret;
ret = register_wakeup_function(graph, 0);
if (!ret && tracing_is_enabled()) if (!ret && tracing_is_enabled())
tracer_enabled = 1; tracer_enabled = 1;
...@@ -156,10 +202,7 @@ static void stop_func_tracer(int graph) ...@@ -156,10 +202,7 @@ static void stop_func_tracer(int graph)
{ {
tracer_enabled = 0; tracer_enabled = 0;
if (!graph) unregister_wakeup_function(graph);
unregister_ftrace_function(&trace_ops);
else
unregister_ftrace_graph();
} }
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
...@@ -600,7 +643,7 @@ static struct tracer wakeup_tracer __read_mostly = ...@@ -600,7 +643,7 @@ static struct tracer wakeup_tracer __read_mostly =
.print_line = wakeup_print_line, .print_line = wakeup_print_line,
.flags = &tracer_flags, .flags = &tracer_flags,
.set_flag = wakeup_set_flag, .set_flag = wakeup_set_flag,
.flag_changed = trace_keep_overwrite, .flag_changed = wakeup_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST #ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup, .selftest = trace_selftest_startup_wakeup,
#endif #endif
...@@ -622,7 +665,7 @@ static struct tracer wakeup_rt_tracer __read_mostly = ...@@ -622,7 +665,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
.print_line = wakeup_print_line, .print_line = wakeup_print_line,
.flags = &tracer_flags, .flags = &tracer_flags,
.set_flag = wakeup_set_flag, .set_flag = wakeup_set_flag,
.flag_changed = trace_keep_overwrite, .flag_changed = wakeup_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST #ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup, .selftest = trace_selftest_startup_wakeup,
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment