Add a generic method to remove event from dynamic event list. This is same as other system under ftrace. You just need to pass the event name with '!' prefix, e.g.
# echo p:new_grp/new_event _do_fork > dynamic_events This creates an event, and # echo '!new_grp/new_event' > dynamic_events Or, # echo '!new_event' > dynamic_events will remove new_grp/new_event event. Signed-off-by: Masami Hiramatsu <mhira...@kernel.org> --- kernel/trace/trace_dynevent.c | 36 +++++++++++++++++++++++++++++++++++- kernel/trace/trace_dynevent.h | 2 ++ kernel/trace/trace_kprobe.c | 12 ++++++++++++ kernel/trace/trace_uprobe.c | 12 ++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c index c829742cfe5d..c33551ad0b15 100644 --- a/kernel/trace/trace_dynevent.c +++ b/kernel/trace/trace_dynevent.c @@ -19,7 +19,8 @@ static LIST_HEAD(dyn_event_ops_list); int dyn_event_register(struct dyn_event_operations *ops) { - if (!ops || !ops->create || !ops->show || !ops->is_busy || !ops->free) + if (!ops || !ops->create || !ops->show || !ops->is_busy || + !ops->free || !ops->match) return -EINVAL; INIT_LIST_HEAD(&ops->list); @@ -29,11 +30,19 @@ int dyn_event_register(struct dyn_event_operations *ops) return 0; } +static int delete_dyn_event(int argc, char **argv); + static int create_dyn_event(int argc, char **argv) { struct dyn_event_operations *ops; int ret; + if (argc == 0) + return 0; + + if (argv[0][0] == '!') + return delete_dyn_event(argc, argv); + mutex_lock(&dyn_event_ops_mutex); list_for_each_entry(ops, &dyn_event_ops_list, list) { ret = ops->create(argc, argv); @@ -80,6 +89,31 @@ static const struct seq_operations dyn_event_seq_op = { .show = dyn_event_seq_show }; +static int delete_dyn_event(int argc, char **argv) +{ + struct dyn_event *pos, *n; + char *system = NULL, *event, *p; + int ret = -ENOENT; + + event = &argv[0][1]; + p = strchr(event, '/'); + if (p) { + system = event; + event = p + 1; + *p = '\0'; + } + mutex_lock(&dyn_event_mutex); + for_each_dyn_event_safe(pos, n) { + if (pos->ops->match(system, event, pos)) { + ret = pos->ops->free(pos); + break; + } + } + mutex_unlock(&dyn_event_mutex); + + return ret; +} + static int release_all_dyn_events(void) { struct dyn_event *ev, *tmp; diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h index 96cf9ca7adb9..705c95b435a3 100644 --- a/kernel/trace/trace_dynevent.h +++ b/kernel/trace/trace_dynevent.h @@ -20,6 +20,8 @@ struct dyn_event_operations { int (*show)(struct seq_file *m, struct dyn_event *ev); bool (*is_busy)(struct dyn_event *ev); int (*free)(struct dyn_event *ev); + bool (*match)(const char *system, const char *event, + struct dyn_event *ev); }; /* Register new dyn_event type -- must be called at first */ diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 421b9d71fedf..b1602f3584d5 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -23,12 +23,15 @@ static int trace_kprobe_create(int argc, char **argv); static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev); static int trace_kprobe_release(struct dyn_event *ev); static bool trace_kprobe_is_busy(struct dyn_event *ev); +static bool trace_kprobe_match(const char *system, const char *event, + struct dyn_event *ev); static struct dyn_event_operations trace_kprobe_ops = { .create = trace_kprobe_create, .show = trace_kprobe_show, .is_busy = trace_kprobe_is_busy, .free = trace_kprobe_release, + .match = trace_kprobe_match, }; /** @@ -115,6 +118,15 @@ static bool trace_kprobe_is_busy(struct dyn_event *ev) return trace_probe_is_enabled(&tk->tp); } +static bool trace_kprobe_match(const char *system, const char *event, + struct dyn_event *ev) +{ + struct trace_kprobe *tk = to_trace_kprobe(ev); + + return strcmp(trace_event_name(&tk->tp.call), event) == 0 && + (!system || strcmp(tk->tp.call.class->system, system) == 0); +} + static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk) { unsigned long nhit = 0; diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 90d10ef02f6b..7c15e22098af 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -41,12 +41,15 @@ static int trace_uprobe_create(int argc, char **argv); static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev); static int trace_uprobe_release(struct dyn_event *ev); static bool trace_uprobe_is_busy(struct dyn_event *ev); +static bool trace_uprobe_match(const char *system, const char *event, + struct dyn_event *ev); static struct dyn_event_operations trace_uprobe_ops = { .create = trace_uprobe_create, .show = trace_uprobe_show, .is_busy = trace_uprobe_is_busy, .free = trace_uprobe_release, + .match = trace_uprobe_match, }; /* @@ -276,6 +279,15 @@ static bool trace_uprobe_is_busy(struct dyn_event *ev) return trace_probe_is_enabled(&tu->tp); } +static bool trace_uprobe_match(const char *system, const char *event, + struct dyn_event *ev) +{ + struct trace_uprobe *tu = to_trace_uprobe(ev); + + return strcmp(trace_event_name(&tu->tp.call), event) == 0 && + (!system || strcmp(tu->tp.call.class->system, system) == 0); +} + /* * Allocate new trace_uprobe and initialize it (including uprobes). */