[PATCH] tracing/kprobe: Recover old array if fails to enable kprobe

From: Masami Hiramatsu
Date: Fri Jun 28 2013 - 09:07:50 EST


Make enable_trace_probe to recover (writeback) the old file array
and free new one if we fail to enable the kprobe.
However, this MUST NOT happen at this time except for unknown
bug or changing the implementation of enable_kprobe(), because
usual failure cases (not registered or gone) are already filtered.
Thus I just add a WARN_ON() on the error path.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@xxxxxxxxxxx>
Reported-by: Oleg Nesterov <oleg@xxxxxxxxxx>
Reported-by: Srikar Dronamraju <srikar@xxxxxxxxxxxxxxxxxx>
Cc: "zhangwei(Jovi)" <jovi.zhangwei@xxxxxxxxxx>
Cc: Steven Rostedt <rostedt@xxxxxxxxxxx>
Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
---
kernel/trace/trace_kprobe.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f237417..d29773e 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -202,6 +202,20 @@ static int trace_probe_nr_files(struct trace_probe *tp)

static DEFINE_MUTEX(probe_enable_lock);

+static int __enable_trace_probe(struct trace_probe *tp)
+{
+ int ret = 0;
+
+ if (trace_probe_is_registered(tp) && !trace_probe_has_gone(tp)) {
+ if (trace_probe_is_return(tp))
+ ret = enable_kretprobe(&tp->rp);
+ else
+ ret = enable_kprobe(&tp->rp.kp);
+ WARN_ON(ret);/* This must succeed. */
+ }
+ return ret;
+}
+
/*
* Enable trace_probe
* if the file is NULL, enable "perf" handler, or enable "trace" handler.
@@ -232,19 +246,21 @@ enable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
rcu_assign_pointer(tp->files, new);
tp->flags |= TP_FLAG_TRACE;

+ ret = __enable_trace_probe(tp);
+ if (ret < 0) {
+ /* Write back the old list */
+ rcu_assign_pointer(tp->files, old);
+ old = new; /* "new" must be freed */
+ }
+
if (old) {
/* Make sure the probe is done with old files */
synchronize_sched();
kfree(old);
}
- } else
+ } else {
tp->flags |= TP_FLAG_PROFILE;
-
- if (trace_probe_is_registered(tp) && !trace_probe_has_gone(tp)) {
- if (trace_probe_is_return(tp))
- ret = enable_kretprobe(&tp->rp);
- else
- ret = enable_kprobe(&tp->rp.kp);
+ ret = __enable_trace_probe(tp);
}

out_unlock:

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/