diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2f8ac1f008f5..2c720c79bc60 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -53,6 +53,11 @@ unsigned long __read_mostly tracing_thresh; | |||
53 | */ | 53 | */ |
54 | static bool __read_mostly tracing_selftest_running; | 54 | static bool __read_mostly tracing_selftest_running; |
55 | 55 | ||
56 | /* | ||
57 | * If a tracer is running, we do not want to run SELFTEST. | ||
58 | */ | ||
59 | static bool __read_mostly tracing_selftest_disabled; | ||
60 | |||
56 | /* For tracers that don't implement custom flags */ | 61 | /* For tracers that don't implement custom flags */ |
57 | static struct tracer_opt dummy_tracer_opt[] = { | 62 | static struct tracer_opt dummy_tracer_opt[] = { |
58 | { } | 63 | { } |
@@ -110,14 +115,19 @@ static cpumask_var_t __read_mostly tracing_buffer_mask; | |||
110 | */ | 115 | */ |
111 | int ftrace_dump_on_oops; | 116 | int ftrace_dump_on_oops; |
112 | 117 | ||
113 | static int tracing_set_tracer(char *buf); | 118 | static int tracing_set_tracer(const char *buf); |
119 | |||
120 | #define BOOTUP_TRACER_SIZE 100 | ||
121 | static char bootup_tracer_buf[BOOTUP_TRACER_SIZE] __initdata; | ||
122 | static char *default_bootup_tracer; | ||
114 | 123 | ||
115 | static int __init set_ftrace(char *str) | 124 | static int __init set_ftrace(char *str) |
116 | { | 125 | { |
117 | tracing_set_tracer(str); | 126 | strncpy(bootup_tracer_buf, str, BOOTUP_TRACER_SIZE); |
127 | default_bootup_tracer = bootup_tracer_buf; | ||
118 | return 1; | 128 | return 1; |
119 | } | 129 | } |
120 | __setup("ftrace", set_ftrace); | 130 | __setup("ftrace=", set_ftrace); |
121 | 131 | ||
122 | static int __init set_ftrace_dump_on_oops(char *str) | 132 | static int __init set_ftrace_dump_on_oops(char *str) |
123 | { | 133 | { |
@@ -468,7 +478,7 @@ int register_tracer(struct tracer *type) | |||
468 | type->flags->opts = dummy_tracer_opt; | 478 | type->flags->opts = dummy_tracer_opt; |
469 | 479 | ||
470 | #ifdef CONFIG_FTRACE_STARTUP_TEST | 480 | #ifdef CONFIG_FTRACE_STARTUP_TEST |
471 | if (type->selftest) { | 481 | if (type->selftest && !tracing_selftest_disabled) { |
472 | struct tracer *saved_tracer = current_trace; | 482 | struct tracer *saved_tracer = current_trace; |
473 | struct trace_array *tr = &global_trace; | 483 | struct trace_array *tr = &global_trace; |
474 | int i; | 484 | int i; |
@@ -510,8 +520,25 @@ int register_tracer(struct tracer *type) | |||
510 | out: | 520 | out: |
511 | tracing_selftest_running = false; | 521 | tracing_selftest_running = false; |
512 | mutex_unlock(&trace_types_lock); | 522 | mutex_unlock(&trace_types_lock); |
513 | lock_kernel(); | ||
514 | 523 | ||
524 | if (!ret && default_bootup_tracer) { | ||
525 | if (!strncmp(default_bootup_tracer, type->name, | ||
526 | BOOTUP_TRACER_SIZE)) { | ||
527 | printk(KERN_INFO "Starting tracer '%s'\n", | ||
528 | type->name); | ||
529 | /* Do we want this tracer to start on bootup? */ | ||
530 | tracing_set_tracer(type->name); | ||
531 | default_bootup_tracer = NULL; | ||
532 | /* disable other selftests, since this will break it. */ | ||
533 | tracing_selftest_disabled = 1; | ||
534 | #ifdef CONFIG_FTRACE_STARTUP_TEST | ||
535 | printk(KERN_INFO "Disabling FTRACE selftests due" | ||
536 | " to running tracer '%s'\n", type->name); | ||
537 | #endif | ||
538 | } | ||
539 | } | ||
540 | |||
541 | lock_kernel(); | ||
515 | return ret; | 542 | return ret; |
516 | } | 543 | } |
517 | 544 | ||
@@ -2245,7 +2272,7 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf, | |||
2245 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | 2272 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
2246 | } | 2273 | } |
2247 | 2274 | ||
2248 | static int tracing_set_tracer(char *buf) | 2275 | static int tracing_set_tracer(const char *buf) |
2249 | { | 2276 | { |
2250 | struct trace_array *tr = &global_trace; | 2277 | struct trace_array *tr = &global_trace; |
2251 | struct tracer *t; | 2278 | struct tracer *t; |
@@ -3163,5 +3190,26 @@ out_free_buffer_mask: | |||
3163 | out: | 3190 | out: |
3164 | return ret; | 3191 | return ret; |
3165 | } | 3192 | } |
3193 | |||
3194 | __init static int clear_boot_tracer(void) | ||
3195 | { | ||
3196 | /* | ||
3197 | * The default tracer at boot buffer is an init section. | ||
3198 | * This function is called in lateinit. If we did not | ||
3199 | * find the boot tracer, then clear it out, to prevent | ||
3200 | * later registration from accessing the buffer that is | ||
3201 | * about to be freed. | ||
3202 | */ | ||
3203 | if (!default_bootup_tracer) | ||
3204 | return 0; | ||
3205 | |||
3206 | printk(KERN_INFO "ftrace bootup tracer '%s' not registered.\n", | ||
3207 | default_bootup_tracer); | ||
3208 | default_bootup_tracer = NULL; | ||
3209 | |||
3210 | return 0; | ||
3211 | } | ||
3212 | |||
3166 | early_initcall(tracer_alloc_buffers); | 3213 | early_initcall(tracer_alloc_buffers); |
3167 | fs_initcall(tracer_init_debugfs); | 3214 | fs_initcall(tracer_init_debugfs); |
3215 | late_initcall(clear_boot_tracer); | ||