|
@@ -243,11 +243,11 @@ find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file)
|
|
|
static int
|
|
|
disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
|
|
|
{
|
|
|
+ struct event_file_link *link = NULL;
|
|
|
+ int wait = 0;
|
|
|
int ret = 0;
|
|
|
|
|
|
if (file) {
|
|
|
- struct event_file_link *link;
|
|
|
-
|
|
|
link = find_event_file_link(tp, file);
|
|
|
if (!link) {
|
|
|
ret = -EINVAL;
|
|
@@ -255,10 +255,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
|
|
|
}
|
|
|
|
|
|
list_del_rcu(&link->list);
|
|
|
- /* synchronize with kprobe_trace_func/kretprobe_trace_func */
|
|
|
- synchronize_sched();
|
|
|
- kfree(link);
|
|
|
-
|
|
|
+ wait = 1;
|
|
|
if (!list_empty(&tp->files))
|
|
|
goto out;
|
|
|
|
|
@@ -271,8 +268,22 @@ 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:
|
|
|
+ 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(link); /* Ignored if link == NULL */
|
|
|
+ }
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|