Skip to content

Commit

Permalink
tracing: Postpone tracer start-up tests till the system is more robust
Browse files Browse the repository at this point in the history
As tracing can now be enabled very early in boot up, even before some
critical system services (like scheduling), do not run the tracer selftests
until after early_initcall() is performed. If a tracer is registered before
such time, it is saved off in a list and the test is run when the system is
able to handle more diverse functions.

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (VMware) committed Mar 25, 2017
1 parent f631718 commit 9afecfb
Showing 1 changed file with 71 additions and 0 deletions.
71 changes: 71 additions & 0 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,28 @@ static int wait_on_pipe(struct trace_iterator *iter, bool full)
}

#ifdef CONFIG_FTRACE_STARTUP_TEST
static bool selftests_can_run;

struct trace_selftests {
struct list_head list;
struct tracer *type;
};

static LIST_HEAD(postponed_selftests);

static int save_selftest(struct tracer *type)
{
struct trace_selftests *selftest;

selftest = kmalloc(sizeof(*selftest), GFP_KERNEL);
if (!selftest)
return -ENOMEM;

selftest->type = type;
list_add(&selftest->list, &postponed_selftests);
return 0;
}

static int run_tracer_selftest(struct tracer *type)
{
struct trace_array *tr = &global_trace;
Expand All @@ -1433,6 +1455,14 @@ static int run_tracer_selftest(struct tracer *type)
if (!type->selftest || tracing_selftest_disabled)
return 0;

/*
* If a tracer registers early in boot up (before scheduling is
* initialized and such), then do not run its selftests yet.
* Instead, run it a little later in the boot process.
*/
if (!selftests_can_run)
return save_selftest(type);

/*
* Run a selftest on this tracer.
* Here we reset the trace buffer, and set the current
Expand Down Expand Up @@ -1482,6 +1512,47 @@ static int run_tracer_selftest(struct tracer *type)
printk(KERN_CONT "PASSED\n");
return 0;
}

static __init int init_trace_selftests(void)
{
struct trace_selftests *p, *n;
struct tracer *t, **last;
int ret;

selftests_can_run = true;

mutex_lock(&trace_types_lock);

if (list_empty(&postponed_selftests))
goto out;

pr_info("Running postponed tracer tests:\n");

list_for_each_entry_safe(p, n, &postponed_selftests, list) {
ret = run_tracer_selftest(p->type);
/* If the test fails, then warn and remove from available_tracers */
if (ret < 0) {
WARN(1, "tracer: %s failed selftest, disabling\n",
p->type->name);
last = &trace_types;
for (t = trace_types; t; t = t->next) {
if (t == p->type) {
*last = t->next;
break;
}
last = &t->next;
}
}
list_del(&p->list);
kfree(p);
}

out:
mutex_unlock(&trace_types_lock);

return 0;
}
early_initcall(init_trace_selftests);
#else
static inline int run_tracer_selftest(struct tracer *type)
{
Expand Down

0 comments on commit 9afecfb

Please sign in to comment.