Commit 41af3cf5 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Steven Rostedt (VMware)

tracing/uprobe: Add multi-probe per uprobe event support

Allow user to define several probes on one uprobe event.
Note that this only support appending method. So deleting
event will delete all probes on the event.

Link: http://lkml.kernel.org/r/156095687876.28024.13840331032234992863.stgit@devnote2Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent ca89bc07
...@@ -4823,7 +4823,7 @@ static const char readme_msg[] = ...@@ -4823,7 +4823,7 @@ static const char readme_msg[] =
"\t\t\t Write into this file to define/undefine new trace events.\n" "\t\t\t Write into this file to define/undefine new trace events.\n"
#endif #endif
#ifdef CONFIG_UPROBE_EVENTS #ifdef CONFIG_UPROBE_EVENTS
" uprobe_events\t\t- Add/remove/show the userspace dynamic events\n" " uprobe_events\t\t- Create/append/remove/show the userspace dynamic events\n"
"\t\t\t Write into this file to define/undefine new trace events.\n" "\t\t\t Write into this file to define/undefine new trace events.\n"
#endif #endif
#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS) #if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
......
...@@ -364,15 +364,32 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu) ...@@ -364,15 +364,32 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
{ {
int ret; int ret;
if (trace_probe_has_sibling(&tu->tp))
goto unreg;
ret = unregister_uprobe_event(tu); ret = unregister_uprobe_event(tu);
if (ret) if (ret)
return ret; return ret;
unreg:
dyn_event_remove(&tu->devent); dyn_event_remove(&tu->devent);
trace_probe_unlink(&tu->tp);
free_trace_uprobe(tu); free_trace_uprobe(tu);
return 0; return 0;
} }
static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
{
int ret;
/* Append to existing event */
ret = trace_probe_append(&tu->tp, &to->tp);
if (!ret)
dyn_event_add(&tu->devent);
return ret;
}
/* /*
* Uprobe with multiple reference counter is not allowed. i.e. * Uprobe with multiple reference counter is not allowed. i.e.
* If inode and offset matches, reference counter offset *must* * If inode and offset matches, reference counter offset *must*
...@@ -382,25 +399,21 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu) ...@@ -382,25 +399,21 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
* as the new one does not conflict with any other existing * as the new one does not conflict with any other existing
* ones. * ones.
*/ */
static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new) static int validate_ref_ctr_offset(struct trace_uprobe *new)
{ {
struct dyn_event *pos; struct dyn_event *pos;
struct trace_uprobe *tmp, *old = NULL; struct trace_uprobe *tmp;
struct inode *new_inode = d_real_inode(new->path.dentry); struct inode *new_inode = d_real_inode(new->path.dentry);
old = find_probe_event(trace_probe_name(&new->tp),
trace_probe_group_name(&new->tp));
for_each_trace_uprobe(tmp, pos) { for_each_trace_uprobe(tmp, pos) {
if ((old ? old != tmp : true) && if (new_inode == d_real_inode(tmp->path.dentry) &&
new_inode == d_real_inode(tmp->path.dentry) &&
new->offset == tmp->offset && new->offset == tmp->offset &&
new->ref_ctr_offset != tmp->ref_ctr_offset) { new->ref_ctr_offset != tmp->ref_ctr_offset) {
pr_warn("Reference counter offset mismatch."); pr_warn("Reference counter offset mismatch.");
return ERR_PTR(-EINVAL); return -EINVAL;
} }
} }
return old; return 0;
} }
/* Register a trace_uprobe and probe_event */ /* Register a trace_uprobe and probe_event */
...@@ -411,17 +424,28 @@ static int register_trace_uprobe(struct trace_uprobe *tu) ...@@ -411,17 +424,28 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
mutex_lock(&event_mutex); mutex_lock(&event_mutex);
/* register as an event */ ret = validate_ref_ctr_offset(tu);
old_tu = find_old_trace_uprobe(tu); if (ret)
if (IS_ERR(old_tu)) {
ret = PTR_ERR(old_tu);
goto end; goto end;
}
/* register as an event */
old_tu = find_probe_event(trace_probe_name(&tu->tp),
trace_probe_group_name(&tu->tp));
if (old_tu) { if (old_tu) {
/* delete old event */ if (is_ret_probe(tu) != is_ret_probe(old_tu)) {
ret = unregister_trace_uprobe(old_tu); trace_probe_log_set_index(0);
if (ret) trace_probe_log_err(0, DIFF_PROBE_TYPE);
ret = -EEXIST;
} else {
ret = trace_probe_compare_arg_type(&tu->tp, &old_tu->tp);
if (ret) {
/* Note that argument starts index = 2 */
trace_probe_log_set_index(ret + 1);
trace_probe_log_err(0, DIFF_ARG_TYPE);
ret = -EEXIST;
} else
ret = append_trace_uprobe(tu, old_tu);
}
goto end; goto end;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment