tracing/kprobe: Wait for disabling all running kprobe handlers
Masami Hiramatsu [Tue, 9 Jul 2013 09:35:26 +0000 (18:35 +0900)]
commit a232e270dcb55a70ad3241bc6fc160fd9b5c9e6c upstream.

Wait for disabling all running kprobe handlers when a kprobe
event is disabled, since the caller, trace_remove_event_call()
supposes that a removing event is disabled completely by
disabling the event.
With this change, ftrace can ensure that there is no running
event handlers after disabling it.

Link: http://lkml.kernel.org/r/20130709093526.20138.93100.stgit@mhiramat-M0-7522

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

kernel/trace/trace_kprobe.c

index 9f46e98..c209c6e 100644 (file)
@@ -281,6 +281,8 @@ trace_probe_file_index(struct trace_probe *tp, struct ftrace_event_file *file)
 static int
 disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
 {
+       struct ftrace_event_file **old = NULL;
+       int wait = 0;
        int ret = 0;
 
        mutex_lock(&probe_enable_lock);
@@ -314,10 +316,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
                }
 
                rcu_assign_pointer(tp->files, new);
-
-               /* Make sure the probe is done with old files */
-               synchronize_sched();
-               kfree(old);
+               wait = 1;
        } else
                tp->flags &= ~TP_FLAG_PROFILE;
 
@@ -326,11 +325,25 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
                        disable_kretprobe(&tp->rp);
                else
                        disable_kprobe(&tp->rp.kp);
+               wait = 1;
        }
 
  out_unlock:
        mutex_unlock(&probe_enable_lock);
 
+       if (wait) {
+               /*
+                * Synchronize with kprobe_trace_func/kretprobe_trace_func
+                * to ensure disabled (all running handlers are finished).
+                * This is not only for kfree(), but also the caller,
+                * trace_remove_event_call() supposes it for releasing
+                * event_call related objects, which will be accessed in
+                * the kprobe_trace_func/kretprobe_trace_func.
+                */
+               synchronize_sched();
+               kfree(old);     /* Ignored if link == NULL */
+       }
+
        return ret;
 }