Skip to content

Commit

Permalink
tracing/uprobe: Add multi-probe per uprobe event support
Browse files Browse the repository at this point in the history
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@devnote2

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  • Loading branch information
Masami Hiramatsu authored and Steven Rostedt (VMware) committed Aug 31, 2019
1 parent ca89bc0 commit 41af3cf
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 19 deletions.
2 changes: 1 addition & 1 deletion kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -4823,7 +4823,7 @@ static const char readme_msg[] =
"\t\t\t Write into this file to define/undefine new trace events.\n"
#endif
#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"
#endif
#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
Expand Down
60 changes: 42 additions & 18 deletions kernel/trace/trace_uprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,32 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
{
int ret;

if (trace_probe_has_sibling(&tu->tp))
goto unreg;

ret = unregister_uprobe_event(tu);
if (ret)
return ret;

unreg:
dyn_event_remove(&tu->devent);
trace_probe_unlink(&tu->tp);
free_trace_uprobe(tu);
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.
* If inode and offset matches, reference counter offset *must*
Expand All @@ -382,25 +399,21 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
* as the new one does not conflict with any other existing
* 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 trace_uprobe *tmp, *old = NULL;
struct trace_uprobe *tmp;
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) {
if ((old ? old != tmp : true) &&
new_inode == d_real_inode(tmp->path.dentry) &&
if (new_inode == d_real_inode(tmp->path.dentry) &&
new->offset == tmp->offset &&
new->ref_ctr_offset != tmp->ref_ctr_offset) {
pr_warn("Reference counter offset mismatch.");
return ERR_PTR(-EINVAL);
return -EINVAL;
}
}
return old;
return 0;
}

/* Register a trace_uprobe and probe_event */
Expand All @@ -411,18 +424,29 @@ static int register_trace_uprobe(struct trace_uprobe *tu)

mutex_lock(&event_mutex);

/* register as an event */
old_tu = find_old_trace_uprobe(tu);
if (IS_ERR(old_tu)) {
ret = PTR_ERR(old_tu);
ret = validate_ref_ctr_offset(tu);
if (ret)
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) {
/* delete old event */
ret = unregister_trace_uprobe(old_tu);
if (ret)
goto end;
if (is_ret_probe(tu) != is_ret_probe(old_tu)) {
trace_probe_log_set_index(0);
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;
}

ret = register_uprobe_event(tu);
Expand Down

0 comments on commit 41af3cf

Please sign in to comment.