ftrace: add ftrace_graph_stop()
authorSteven Rostedt <srostedt@redhat.com>
Wed, 3 Dec 2008 04:50:02 +0000 (23:50 -0500)
committerIngo Molnar <mingo@elte.hu>
Wed, 3 Dec 2008 07:56:23 +0000 (08:56 +0100)
Impact: new ftrace_graph_stop function

While developing more features of function graph, I hit a bug that
caused the WARN_ON to trigger in the prepare_ftrace_return function.
Well, it was hard for me to find out that was happening because the
bug would not print, it would just cause a hard lockup or reboot.
The reason is that it is not safe to call printk from this function.

Looking further, I also found that it calls unregister_ftrace_graph,
which grabs a mutex and calls kstop machine. This would definitely
lock the box up if it were to trigger.

This patch adds a fast and safe ftrace_graph_stop() which will
stop the function tracer. Then it is safe to call the WARN ON.

Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/ftrace.c
include/linux/ftrace.h
kernel/trace/ftrace.c

index 1a5b8f8cb3cc556b9953c83d80276d7dcf590a55..adba8e9a427c7beea213013a9fdf0502847418ac 100644 (file)
@@ -484,14 +484,16 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
                : "memory"
        );
 
-       if (WARN_ON(faulted)) {
-               unregister_ftrace_graph();
+       if (unlikely(faulted)) {
+               ftrace_graph_stop();
+               WARN_ON(1);
                return;
        }
 
-       if (WARN_ON(!__kernel_text_address(old))) {
-               unregister_ftrace_graph();
+       if (unlikely(!__kernel_text_address(old))) {
+               ftrace_graph_stop();
                *parent = old;
+               WARN_ON(1);
                return;
        }
 
index afba918c623c5a2ab86e4ac8363e1b24e9c95c3f..58ca1c3a3f4d4b6402a3b8cc816fa565a59db99f 100644 (file)
@@ -376,6 +376,8 @@ typedef void (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); /* entry */
 extern int register_ftrace_graph(trace_func_graph_ret_t retfunc,
                                trace_func_graph_ent_t entryfunc);
 
+extern void ftrace_graph_stop(void);
+
 /* The current handlers in use */
 extern trace_func_graph_ret_t ftrace_graph_return;
 extern trace_func_graph_ent_t ftrace_graph_entry;
index 2e78628443e8509311200484b8ddff4644044e99..a44af05ae2d00c63b7c3633f1fa43841894d620a 100644 (file)
@@ -1769,5 +1769,10 @@ void ftrace_graph_exit_task(struct task_struct *t)
 
        kfree(ret_stack);
 }
+
+void ftrace_graph_stop(void)
+{
+       ftrace_stop();
+}
 #endif