diff options
| author | Chunyu Hu <chuhu@redhat.com> | 2016-03-08 08:37:01 -0500 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2016-03-08 11:19:08 -0500 |
| commit | d39cdd2036a63eef17a14efbd969405ca5612886 (patch) | |
| tree | 547098658fa6d9e6dba8ffe73ccd756ba5638668 /kernel | |
| parent | f6cede5b49e822ebc41a099fe41ab4989f64e2cb (diff) | |
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.com
Signed-off-by: Chunyu Hu <chuhu@redhat.com>
[ Fixed up function tracer options to work with the change ]
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace.c | 28 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_functions.c | 6 |
3 files changed, 21 insertions, 14 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d9293402ee68..b401a1892dc6 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -74,11 +74,6 @@ static struct tracer_opt dummy_tracer_opt[] = { | |||
| 74 | { } | 74 | { } |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | static struct tracer_flags dummy_tracer_flags = { | ||
| 78 | .val = 0, | ||
| 79 | .opts = dummy_tracer_opt | ||
| 80 | }; | ||
| 81 | |||
| 82 | static int | 77 | static int |
| 83 | dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) | 78 | dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) |
| 84 | { | 79 | { |
| @@ -1258,12 +1253,20 @@ int __init register_tracer(struct tracer *type) | |||
| 1258 | 1253 | ||
| 1259 | if (!type->set_flag) | 1254 | if (!type->set_flag) |
| 1260 | type->set_flag = &dummy_set_flag; | 1255 | type->set_flag = &dummy_set_flag; |
| 1261 | if (!type->flags) | 1256 | if (!type->flags) { |
| 1262 | type->flags = &dummy_tracer_flags; | 1257 | /*allocate a dummy tracer_flags*/ |
| 1263 | else | 1258 | type->flags = kmalloc(sizeof(*type->flags), GFP_KERNEL); |
| 1259 | if (!type->flags) | ||
| 1260 | return -ENOMEM; | ||
| 1261 | type->flags->val = 0; | ||
| 1262 | type->flags->opts = dummy_tracer_opt; | ||
| 1263 | } else | ||
| 1264 | if (!type->flags->opts) | 1264 | if (!type->flags->opts) |
| 1265 | type->flags->opts = dummy_tracer_opt; | 1265 | type->flags->opts = dummy_tracer_opt; |
| 1266 | 1266 | ||
| 1267 | /* store the tracer for __set_tracer_option */ | ||
| 1268 | type->flags->trace = type; | ||
| 1269 | |||
| 1267 | ret = run_tracer_selftest(type); | 1270 | ret = run_tracer_selftest(type); |
| 1268 | if (ret < 0) | 1271 | if (ret < 0) |
| 1269 | goto out; | 1272 | goto out; |
| @@ -3505,7 +3508,7 @@ static int __set_tracer_option(struct trace_array *tr, | |||
| 3505 | struct tracer_flags *tracer_flags, | 3508 | struct tracer_flags *tracer_flags, |
| 3506 | struct tracer_opt *opts, int neg) | 3509 | struct tracer_opt *opts, int neg) |
| 3507 | { | 3510 | { |
| 3508 | struct tracer *trace = tr->current_trace; | 3511 | struct tracer *trace = tracer_flags->trace; |
| 3509 | int ret; | 3512 | int ret; |
| 3510 | 3513 | ||
| 3511 | ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg); | 3514 | 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 | return; | 6394 | return; |
| 6392 | 6395 | ||
| 6393 | for (i = 0; i < tr->nr_topts; i++) { | 6396 | for (i = 0; i < tr->nr_topts; i++) { |
| 6394 | /* | 6397 | /* Make sure there's no duplicate flags. */ |
| 6395 | * Check if these flags have already been added. | 6398 | if (WARN_ON_ONCE(tr->topts[i].tracer->flags == tracer->flags)) |
| 6396 | * Some tracers share flags. | ||
| 6397 | */ | ||
| 6398 | if (tr->topts[i].tracer->flags == tracer->flags) | ||
| 6399 | return; | 6399 | return; |
| 6400 | } | 6400 | } |
| 6401 | 6401 | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 8414fa40bf27..b4cae47f283e 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -345,6 +345,7 @@ struct tracer_opt { | |||
| 345 | struct tracer_flags { | 345 | struct tracer_flags { |
| 346 | u32 val; | 346 | u32 val; |
| 347 | struct tracer_opt *opts; | 347 | struct tracer_opt *opts; |
| 348 | struct tracer *trace; | ||
| 348 | }; | 349 | }; |
| 349 | 350 | ||
| 350 | /* Makes more easy to define a tracer opt */ | 351 | /* Makes more easy to define a tracer opt */ |
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index fcd41a166405..5a095c2e4b69 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
| @@ -219,6 +219,8 @@ static void tracing_stop_function_trace(struct trace_array *tr) | |||
| 219 | unregister_ftrace_function(tr->ops); | 219 | unregister_ftrace_function(tr->ops); |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | static struct tracer function_trace; | ||
| 223 | |||
| 222 | static int | 224 | static int |
| 223 | func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) | 225 | func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) |
| 224 | { | 226 | { |
| @@ -228,6 +230,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) | |||
| 228 | if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK)) | 230 | if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK)) |
| 229 | break; | 231 | break; |
| 230 | 232 | ||
| 233 | /* We can change this flag when not running. */ | ||
| 234 | if (tr->current_trace != &function_trace) | ||
| 235 | break; | ||
| 236 | |||
| 231 | unregister_ftrace_function(tr->ops); | 237 | unregister_ftrace_function(tr->ops); |
| 232 | 238 | ||
| 233 | if (set) { | 239 | if (set) { |
