[PATCH 2/2] tracing/uprobes: disallow unregister trace_uprobe whentrace_uprobe is in use

From: zhangwei(Jovi)
Date: Tue Jun 25 2013 - 04:16:48 EST


We cannot unregister trace_uprobe when trace_uprobe is in use,
otherwise resource will leak.

Just return -EBUSY if user want to unregister a trace_uprobe
which in use.

Signed-off-by: zhangwei(Jovi) <jovi.zhangwei@xxxxxxxxxx>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@xxxxxxxxxxx>
Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Oleg Nesterov <oleg@xxxxxxxxxx>
Cc: Srikar Dronamraju <srikar@xxxxxxxxxxxxxxxxxx>
---
kernel/trace/trace_uprobe.c | 51 ++++++++++++++++++++++++++++++++-----------
1 file changed, 38 insertions(+), 13 deletions(-)

diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index d2da3ea..248757b 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -102,6 +102,11 @@ static inline bool is_ret_probe(struct trace_uprobe *tu)
return tu->consumer.ret_handler != NULL;
}

+static inline bool is_trace_uprobe_enabled(struct trace_uprobe *tu)
+{
+ return tu->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE);
+}
+
/*
* Allocate new trace_uprobe and initialize it (including uprobes).
*/
@@ -171,11 +176,17 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
}

/* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */
-static void unregister_trace_uprobe(struct trace_uprobe *tu)
+static int unregister_trace_uprobe(struct trace_uprobe *tu)
{
+ /* Enabled event can not be unregistered */
+ if (is_trace_uprobe_enabled(tu))
+ return -EBUSY;
+
list_del(&tu->list);
unregister_uprobe_event(tu);
free_trace_uprobe(tu);
+
+ return 0;
}

/* Register a trace_uprobe and probe_event */
@@ -188,9 +199,12 @@ static int register_trace_uprobe(struct trace_uprobe *tu)

/* register as an event */
old_tp = find_probe_event(tu->call.name, tu->call.class->system);
- if (old_tp)
+ if (old_tp) {
/* delete old event */
- unregister_trace_uprobe(old_tp);
+ ret = unregister_trace_uprobe(old_tp);
+ if (ret < 0)
+ goto end;
+ }

ret = register_uprobe_event(tu);
if (ret) {
@@ -276,9 +290,9 @@ static int create_trace_uprobe(int argc, char **argv)
return -ENOENT;
}
/* delete an event */
- unregister_trace_uprobe(tu);
+ ret = unregister_trace_uprobe(tu);
mutex_unlock(&uprobe_lock);
- return 0;
+ return ret;
}

if (argc < 2) {
@@ -413,16 +427,27 @@ fail_address_parse:
return ret;
}

-static void cleanup_all_probes(void)
+static int cleanup_all_probes(void)
{
struct trace_uprobe *tu;
+ int ret = 0;

mutex_lock(&uprobe_lock);
+
+ /* Ensure no probe is in use. */
+ list_for_each_entry(tu, &uprobe_list, list)
+ if (is_trace_uprobe_enabled(tu)) {
+ ret = -EBUSY;
+ goto end;
+ }
+
while (!list_empty(&uprobe_list)) {
tu = list_entry(uprobe_list.next, struct trace_uprobe, list);
unregister_trace_uprobe(tu);
}
+ end:
mutex_unlock(&uprobe_lock);
+ return ret;
}

/* Probes listing interfaces */
@@ -467,8 +492,13 @@ static const struct seq_operations probes_seq_op = {

static int probes_open(struct inode *inode, struct file *file)
{
- if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
- cleanup_all_probes();
+ int ret;
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
+ ret = cleanup_all_probes();
+ if (ret < 0)
+ return ret;
+ }

return seq_open(file, &probes_seq_op);
}
@@ -622,11 +652,6 @@ partial:
return TRACE_TYPE_PARTIAL_LINE;
}

-static inline bool is_trace_uprobe_enabled(struct trace_uprobe *tu)
-{
- return tu->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE);
-}
-
typedef bool (*filter_func_t)(struct uprobe_consumer *self,
enum uprobe_filter_ctx ctx,
struct mm_struct *mm);
--
1.7.9.7


--
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/