Commit d39cdd20 authored by Chunyu Hu's avatar Chunyu Hu Committed by Steven Rostedt

tracing: Make tracer_flags use the right set_flag callback

When I was updating the ftrace_stress test of ltp. I encountered
a strange phenomemon, excute following steps:

echo nop > /sys/kernel/debug/tracing/current_tracer
echo 0 > /sys/kernel/debug/tracing/options/funcgraph-cpu
bash: echo: write error: Invalid argument

check dmesg:
[ 1024.903855] nop_test_refuse flag set to 0: we refuse.Now cat trace_options to see the result

The reason is that the trace option test will randomly setup trace
option under tracing/options no matter what the current_tracer is.
but the set_tracer_option is always using the set_flag callback
from the current_tracer. This patch adds a pointer to tracer_flags
and make it point to the tracer it belongs to. When the option is
setup, the set_flag of the right tracer will be used no matter
what the the current_tracer is.

And the old dummy_tracer_flags is used for all the tracers which
doesn't have a tracer_flags, having issue to use it to save the
pointer of a tracer. So remove it and use dynamic dummy tracer_flags
for tracers needing a dummy tracer_flags, as a result, there are no
tracers sharing tracer_flags, so remove the check code.

And save the current tracer to trace_option_dentry seems not good as
it may waste mem space when mount the debug/trace fs more than one time.

Link: http://lkml.kernel.org/r/1457444222-8654-1-git-send-email-chuhu@redhat.comSigned-off-by: default avatarChunyu Hu <chuhu@redhat.com>
[ Fixed up function tracer options to work with the change ]
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent f6cede5b
...@@ -74,11 +74,6 @@ static struct tracer_opt dummy_tracer_opt[] = { ...@@ -74,11 +74,6 @@ static struct tracer_opt dummy_tracer_opt[] = {
{ } { }
}; };
static struct tracer_flags dummy_tracer_flags = {
.val = 0,
.opts = dummy_tracer_opt
};
static int static int
dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
{ {
...@@ -1258,12 +1253,20 @@ int __init register_tracer(struct tracer *type) ...@@ -1258,12 +1253,20 @@ int __init register_tracer(struct tracer *type)
if (!type->set_flag) if (!type->set_flag)
type->set_flag = &dummy_set_flag; type->set_flag = &dummy_set_flag;
if (!type->flags) if (!type->flags) {
type->flags = &dummy_tracer_flags; /*allocate a dummy tracer_flags*/
else type->flags = kmalloc(sizeof(*type->flags), GFP_KERNEL);
if (!type->flags)
return -ENOMEM;
type->flags->val = 0;
type->flags->opts = dummy_tracer_opt;
} else
if (!type->flags->opts) if (!type->flags->opts)
type->flags->opts = dummy_tracer_opt; type->flags->opts = dummy_tracer_opt;
/* store the tracer for __set_tracer_option */
type->flags->trace = type;
ret = run_tracer_selftest(type); ret = run_tracer_selftest(type);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -3505,7 +3508,7 @@ static int __set_tracer_option(struct trace_array *tr, ...@@ -3505,7 +3508,7 @@ static int __set_tracer_option(struct trace_array *tr,
struct tracer_flags *tracer_flags, struct tracer_flags *tracer_flags,
struct tracer_opt *opts, int neg) struct tracer_opt *opts, int neg)
{ {
struct tracer *trace = tr->current_trace; struct tracer *trace = tracer_flags->trace;
int ret; int ret;
ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg); ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg);
...@@ -6391,11 +6394,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer) ...@@ -6391,11 +6394,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
return; return;
for (i = 0; i < tr->nr_topts; i++) { for (i = 0; i < tr->nr_topts; i++) {
/* /* Make sure there's no duplicate flags. */
* Check if these flags have already been added. if (WARN_ON_ONCE(tr->topts[i].tracer->flags == tracer->flags))
* Some tracers share flags.
*/
if (tr->topts[i].tracer->flags == tracer->flags)
return; return;
} }
......
...@@ -345,6 +345,7 @@ struct tracer_opt { ...@@ -345,6 +345,7 @@ struct tracer_opt {
struct tracer_flags { struct tracer_flags {
u32 val; u32 val;
struct tracer_opt *opts; struct tracer_opt *opts;
struct tracer *trace;
}; };
/* Makes more easy to define a tracer opt */ /* Makes more easy to define a tracer opt */
......
...@@ -219,6 +219,8 @@ static void tracing_stop_function_trace(struct trace_array *tr) ...@@ -219,6 +219,8 @@ static void tracing_stop_function_trace(struct trace_array *tr)
unregister_ftrace_function(tr->ops); unregister_ftrace_function(tr->ops);
} }
static struct tracer function_trace;
static int static int
func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
{ {
...@@ -228,6 +230,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) ...@@ -228,6 +230,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK)) if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
break; break;
/* We can change this flag when not running. */
if (tr->current_trace != &function_trace)
break;
unregister_ftrace_function(tr->ops); unregister_ftrace_function(tr->ops);
if (set) { if (set) {
......
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