|
@@ -53,6 +53,11 @@ unsigned long __read_mostly tracing_thresh;
|
|
*/
|
|
*/
|
|
static bool __read_mostly tracing_selftest_running;
|
|
static bool __read_mostly tracing_selftest_running;
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * If a tracer is running, we do not want to run SELFTEST.
|
|
|
|
+ */
|
|
|
|
+static bool __read_mostly tracing_selftest_disabled;
|
|
|
|
+
|
|
/* For tracers that don't implement custom flags */
|
|
/* For tracers that don't implement custom flags */
|
|
static struct tracer_opt dummy_tracer_opt[] = {
|
|
static struct tracer_opt dummy_tracer_opt[] = {
|
|
{ }
|
|
{ }
|
|
@@ -110,14 +115,19 @@ static cpumask_var_t __read_mostly tracing_buffer_mask;
|
|
*/
|
|
*/
|
|
int ftrace_dump_on_oops;
|
|
int ftrace_dump_on_oops;
|
|
|
|
|
|
-static int tracing_set_tracer(char *buf);
|
|
|
|
|
|
+static int tracing_set_tracer(const char *buf);
|
|
|
|
+
|
|
|
|
+#define BOOTUP_TRACER_SIZE 100
|
|
|
|
+static char bootup_tracer_buf[BOOTUP_TRACER_SIZE] __initdata;
|
|
|
|
+static char *default_bootup_tracer;
|
|
|
|
|
|
static int __init set_ftrace(char *str)
|
|
static int __init set_ftrace(char *str)
|
|
{
|
|
{
|
|
- tracing_set_tracer(str);
|
|
|
|
|
|
+ strncpy(bootup_tracer_buf, str, BOOTUP_TRACER_SIZE);
|
|
|
|
+ default_bootup_tracer = bootup_tracer_buf;
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
-__setup("ftrace", set_ftrace);
|
|
|
|
|
|
+__setup("ftrace=", set_ftrace);
|
|
|
|
|
|
static int __init set_ftrace_dump_on_oops(char *str)
|
|
static int __init set_ftrace_dump_on_oops(char *str)
|
|
{
|
|
{
|
|
@@ -469,7 +479,7 @@ int register_tracer(struct tracer *type)
|
|
type->flags->opts = dummy_tracer_opt;
|
|
type->flags->opts = dummy_tracer_opt;
|
|
|
|
|
|
#ifdef CONFIG_FTRACE_STARTUP_TEST
|
|
#ifdef CONFIG_FTRACE_STARTUP_TEST
|
|
- if (type->selftest) {
|
|
|
|
|
|
+ if (type->selftest && !tracing_selftest_disabled) {
|
|
struct tracer *saved_tracer = current_trace;
|
|
struct tracer *saved_tracer = current_trace;
|
|
struct trace_array *tr = &global_trace;
|
|
struct trace_array *tr = &global_trace;
|
|
int i;
|
|
int i;
|
|
@@ -511,8 +521,25 @@ int register_tracer(struct tracer *type)
|
|
out:
|
|
out:
|
|
tracing_selftest_running = false;
|
|
tracing_selftest_running = false;
|
|
mutex_unlock(&trace_types_lock);
|
|
mutex_unlock(&trace_types_lock);
|
|
- lock_kernel();
|
|
|
|
|
|
|
|
|
|
+ if (!ret && default_bootup_tracer) {
|
|
|
|
+ if (!strncmp(default_bootup_tracer, type->name,
|
|
|
|
+ BOOTUP_TRACER_SIZE)) {
|
|
|
|
+ printk(KERN_INFO "Starting tracer '%s'\n",
|
|
|
|
+ type->name);
|
|
|
|
+ /* Do we want this tracer to start on bootup? */
|
|
|
|
+ tracing_set_tracer(type->name);
|
|
|
|
+ default_bootup_tracer = NULL;
|
|
|
|
+ /* disable other selftests, since this will break it. */
|
|
|
|
+ tracing_selftest_disabled = 1;
|
|
|
|
+#ifdef CONFIG_FTRACE_STARTUP_TEST
|
|
|
|
+ printk(KERN_INFO "Disabling FTRACE selftests due"
|
|
|
|
+ " to running tracer '%s'\n", type->name);
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ lock_kernel();
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2166,7 +2193,7 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
|
|
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
|
|
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
|
|
}
|
|
}
|
|
|
|
|
|
-static int tracing_set_tracer(char *buf)
|
|
|
|
|
|
+static int tracing_set_tracer(const char *buf)
|
|
{
|
|
{
|
|
struct trace_array *tr = &global_trace;
|
|
struct trace_array *tr = &global_trace;
|
|
struct tracer *t;
|
|
struct tracer *t;
|
|
@@ -3061,12 +3088,9 @@ __init static int tracer_alloc_buffers(void)
|
|
trace_init_cmdlines();
|
|
trace_init_cmdlines();
|
|
|
|
|
|
register_tracer(&nop_trace);
|
|
register_tracer(&nop_trace);
|
|
|
|
+ current_trace = &nop_trace;
|
|
#ifdef CONFIG_BOOT_TRACER
|
|
#ifdef CONFIG_BOOT_TRACER
|
|
register_tracer(&boot_tracer);
|
|
register_tracer(&boot_tracer);
|
|
- current_trace = &boot_tracer;
|
|
|
|
- current_trace->init(&global_trace);
|
|
|
|
-#else
|
|
|
|
- current_trace = &nop_trace;
|
|
|
|
#endif
|
|
#endif
|
|
/* All seems OK, enable tracing */
|
|
/* All seems OK, enable tracing */
|
|
tracing_disabled = 0;
|
|
tracing_disabled = 0;
|
|
@@ -3084,5 +3108,26 @@ out_free_buffer_mask:
|
|
out:
|
|
out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+__init static int clear_boot_tracer(void)
|
|
|
|
+{
|
|
|
|
+ /*
|
|
|
|
+ * The default tracer at boot buffer is an init section.
|
|
|
|
+ * This function is called in lateinit. If we did not
|
|
|
|
+ * find the boot tracer, then clear it out, to prevent
|
|
|
|
+ * later registration from accessing the buffer that is
|
|
|
|
+ * about to be freed.
|
|
|
|
+ */
|
|
|
|
+ if (!default_bootup_tracer)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ printk(KERN_INFO "ftrace bootup tracer '%s' not registered.\n",
|
|
|
|
+ default_bootup_tracer);
|
|
|
|
+ default_bootup_tracer = NULL;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
early_initcall(tracer_alloc_buffers);
|
|
early_initcall(tracer_alloc_buffers);
|
|
fs_initcall(tracer_init_debugfs);
|
|
fs_initcall(tracer_init_debugfs);
|
|
|
|
+late_initcall(clear_boot_tracer);
|