]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
function-graph: enable the stack after initialization of other variables
authorSteven Rostedt <srostedt@redhat.com>
Tue, 2 Jun 2009 16:26:07 +0000 (12:26 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Tue, 2 Jun 2009 18:41:50 +0000 (14:41 -0400)
The function graph tracer checks if the task_struct has ret_stack defined
to know if it is OK or not to use it. The initialization is done for
all tasks by one process, but the idle tasks use the same initialization
used by new tasks.

If an interrupt happens on an idle task that just had the ret_stack
created, but before the rest of the initialization took place, then
we can corrupt the return address of the functions.

This patch moves the setting of the task_struct's ret_stack to after
the other variables have been initialized.

[ Impact: prevent kernel panic on idle task when starting function graph ]

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/trace/ftrace.c
kernel/trace/trace_functions_graph.c

index ebff62ef40be7fdb44064768a317fff71bb3b0dd..20e066065eb3934fd497ecc93d92cebc152a972d 100644 (file)
@@ -2739,15 +2739,20 @@ void unregister_ftrace_graph(void)
 void ftrace_graph_init_task(struct task_struct *t)
 {
        if (atomic_read(&ftrace_graph_active)) {
-               t->ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
+               struct ftrace_ret_stack *ret_stack;
+
+               ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
                                * sizeof(struct ftrace_ret_stack),
                                GFP_KERNEL);
-               if (!t->ret_stack)
+               if (!ret_stack)
                        return;
                t->curr_ret_stack = -1;
                atomic_set(&t->tracing_graph_pause, 0);
                atomic_set(&t->trace_overrun, 0);
                t->ftrace_timestamp = 0;
+               /* make curr_ret_stack visable before we add the ret_stack */
+               smp_wmb();
+               t->ret_stack = ret_stack;
        } else
                t->ret_stack = NULL;
 }
index d28687e7b3a7b36859f1ac48fa1ac62d5e52f456..baeb5fe36108c66ac213ea6dd877d6ed51c45c00 100644 (file)
@@ -65,6 +65,12 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth)
        if (!current->ret_stack)
                return -EBUSY;
 
+       /*
+        * We must make sure the ret_stack is tested before we read
+        * anything else.
+        */
+       smp_rmb();
+
        /* The return trace stack is full */
        if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
                atomic_inc(&current->trace_overrun);