powerpc/ftrace: Have PPC skip updating with stop_machine()
authorSteven Rostedt <srostedt@redhat.com>
Thu, 26 Apr 2012 08:31:17 +0000 (08:31 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 3 Jul 2012 04:14:38 +0000 (14:14 +1000)
PowerPC does not have the synchronization issues that x86 has with
modifying code on one CPU while another CPU is executing it.
The other CPU will either see the old or new code without any
issues, unlike x86 which may issue a GPF.

Instead of calling the heavy stop_machine, just update the code.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/ftrace.c

index bf99cfa6bbfe3a29240094eb5fe2db695ed78e66..d56848afd2cfdbf2aeae3307af29245f26a865a6 100644 (file)
@@ -484,6 +484,58 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        return ret;
 }
 
+static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+{
+       unsigned long ftrace_addr = (unsigned long)FTRACE_ADDR;
+       int ret;
+
+       ret = ftrace_update_record(rec, enable);
+
+       switch (ret) {
+       case FTRACE_UPDATE_IGNORE:
+               return 0;
+       case FTRACE_UPDATE_MAKE_CALL:
+               return ftrace_make_call(rec, ftrace_addr);
+       case FTRACE_UPDATE_MAKE_NOP:
+               return ftrace_make_nop(NULL, rec, ftrace_addr);
+       }
+
+       return 0;
+}
+
+void ftrace_replace_code(int enable)
+{
+       struct ftrace_rec_iter *iter;
+       struct dyn_ftrace *rec;
+       int ret;
+
+       for (iter = ftrace_rec_iter_start(); iter;
+            iter = ftrace_rec_iter_next(iter)) {
+               rec = ftrace_rec_iter_record(iter);
+               ret = __ftrace_replace_code(rec, enable);
+               if (ret) {
+                       ftrace_bug(ret, rec->ip);
+                       return;
+               }
+       }
+}
+
+void arch_ftrace_update_code(int command)
+{
+       if (command & FTRACE_UPDATE_CALLS)
+               ftrace_replace_code(1);
+       else if (command & FTRACE_DISABLE_CALLS)
+               ftrace_replace_code(0);
+
+       if (command & FTRACE_UPDATE_TRACE_FUNC)
+               ftrace_update_ftrace_func(ftrace_trace_function);
+
+       if (command & FTRACE_START_FUNC_RET)
+               ftrace_enable_ftrace_graph_caller();
+       else if (command & FTRACE_STOP_FUNC_RET)
+               ftrace_disable_ftrace_graph_caller();
+}
+
 int __init ftrace_dyn_arch_init(void *data)
 {
        /* caller expects data to be zero */