On Mon, 3 Jun 2024 15:50:55 -0400 Mathieu Desnoyers <mathieu.desnoy...@efficios.com> wrote:
> On 2024-06-01 04:22, Masami Hiramatsu (Google) wrote: > > From: Masami Hiramatsu (Google) <mhira...@kernel.org> > > > > Support raw tracepoint event on module by fprobe events. > > Since it only uses for_each_kernel_tracepoint() to find a tracepoint, > > the tracepoints on modules are not handled. Thus if user specified a > > tracepoint on a module, it shows an error. > > This adds new for_each_module_tracepoint() API to tracepoint subsystem, > > and uses it to find tracepoints on modules. > > Hi Masami, > > Why prevent module unload when a fprobe tracepoint is attached to a > module ? This changes the kernel's behavior significantly just for the > sake of instrumentation. I don't prevent module unloading all the time, just before registering tracepoint handler (something like booking a ticket :-) ). See the last hunk of this patch, it puts the module before exiting __trace_fprobe_create(). > > As an alternative, LTTng-modules attach/detach to/from modules with the > coming/going notifiers, so the instrumentation gets removed when a > module is unloaded rather than preventing its unload by holding a module > reference count. I would recommend a similar approach for fprobe. Yes, since tracepoint subsystem provides a notifier API to notify the tracepoint is gone, fprobe already uses it to find unloading and unregister the target function. (see __tracepoint_probe_module_cb) Thank you! > > Thanks, > > Mathieu > > > > > > Reported-by: don <zds...@gmail.com> > > Closes: > > https://lore.kernel.org/all/20240530215718.aeec973a1d0bf058d39cb...@kernel.org/ > > Signed-off-by: Masami Hiramatsu (Google) <mhira...@kernel.org> > > --- > > Changes in v2: > > - Fix build errors with CONFIG_MODULES=y. > > --- > > kernel/trace/trace_fprobe.c | 46 > > ++++++++++++++++++++++++++++++++++++------- > > 1 file changed, 38 insertions(+), 8 deletions(-) > > > > diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c > > index 62e6a8f4aae9..1d8a983e1edc 100644 > > --- a/kernel/trace/trace_fprobe.c > > +++ b/kernel/trace/trace_fprobe.c > > @@ -385,6 +385,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const > > char *group, > > const char *event, > > const char *symbol, > > struct tracepoint *tpoint, > > + struct module *mod, > > int maxactive, > > int nargs, bool is_return) > > { > > @@ -405,6 +406,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const > > char *group, > > tf->fp.entry_handler = fentry_dispatcher; > > > > tf->tpoint = tpoint; > > + tf->mod = mod; > > tf->fp.nr_maxactive = maxactive; > > > > ret = trace_probe_init(&tf->tp, event, group, false, nargs); > > @@ -895,8 +897,23 @@ static struct notifier_block tracepoint_module_nb = { > > struct __find_tracepoint_cb_data { > > const char *tp_name; > > struct tracepoint *tpoint; > > + struct module *mod; > > }; > > > > +static void __find_tracepoint_module_cb(struct tracepoint *tp, void *priv) > > +{ > > + struct __find_tracepoint_cb_data *data = priv; > > + > > + if (!data->tpoint && !strcmp(data->tp_name, tp->name)) { > > + data->tpoint = tp; > > + data->mod = __module_text_address((unsigned long)tp->probestub); > > + if (!try_module_get(data->mod)) { > > + data->tpoint = NULL; > > + data->mod = NULL; > > + } > > + } > > +} > > + > > static void __find_tracepoint_cb(struct tracepoint *tp, void *priv) > > { > > struct __find_tracepoint_cb_data *data = priv; > > @@ -905,14 +922,28 @@ static void __find_tracepoint_cb(struct tracepoint > > *tp, void *priv) > > data->tpoint = tp; > > } > > > > -static struct tracepoint *find_tracepoint(const char *tp_name) > > +/* > > + * Find a tracepoint from kernel and module. If the tracepoint is in a > > module, > > + * this increments the module refcount to prevent unloading until the > > + * trace_fprobe is registered to the list. After registering the > > trace_fprobe > > + * on the trace_fprobe list, the module refcount is decremented because > > + * tracepoint_probe_module_cb will handle it. > > + */ > > +static struct tracepoint *find_tracepoint(const char *tp_name, > > + struct module **tp_mod) > > { > > struct __find_tracepoint_cb_data data = { > > .tp_name = tp_name, > > + .mod = NULL, > > }; > > > > for_each_kernel_tracepoint(__find_tracepoint_cb, &data); > > > > + if (!data.tpoint && IS_ENABLED(CONFIG_MODULES)) { > > + for_each_module_tracepoint(__find_tracepoint_module_cb, &data); > > + *tp_mod = data.mod; > > + } > > + > > return data.tpoint; > > } > > > > @@ -996,6 +1027,7 @@ static int __trace_fprobe_create(int argc, const char > > *argv[]) > > char abuf[MAX_BTF_ARGS_LEN]; > > char *dbuf = NULL; > > bool is_tracepoint = false; > > + struct module *tp_mod = NULL; > > struct tracepoint *tpoint = NULL; > > struct traceprobe_parse_context ctx = { > > .flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE, > > @@ -1080,7 +1112,7 @@ static int __trace_fprobe_create(int argc, const char > > *argv[]) > > > > if (is_tracepoint) { > > ctx.flags |= TPARG_FL_TPOINT; > > - tpoint = find_tracepoint(symbol); > > + tpoint = find_tracepoint(symbol, &tp_mod); > > if (!tpoint) { > > trace_probe_log_set_index(1); > > trace_probe_log_err(0, NO_TRACEPOINT); > > @@ -1110,8 +1142,8 @@ static int __trace_fprobe_create(int argc, const char > > *argv[]) > > goto out; > > > > /* setup a probe */ > > - tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive, > > - argc, is_return); > > + tf = alloc_trace_fprobe(group, event, symbol, tpoint, tp_mod, > > + maxactive, argc, is_return); > > if (IS_ERR(tf)) { > > ret = PTR_ERR(tf); > > /* This must return -ENOMEM, else there is a bug */ > > @@ -1119,10 +1151,6 @@ static int __trace_fprobe_create(int argc, const > > char *argv[]) > > goto out; /* We know tf is not allocated */ > > } > > > > - if (is_tracepoint) > > - tf->mod = __module_text_address( > > - (unsigned long)tf->tpoint->probestub); > > - > > /* parse arguments */ > > for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { > > trace_probe_log_set_index(i + 2); > > @@ -1155,6 +1183,8 @@ static int __trace_fprobe_create(int argc, const char > > *argv[]) > > } > > > > out: > > + if (tp_mod) > > + module_put(tp_mod); > > traceprobe_finish_parse(&ctx); > > trace_probe_log_clear(); > > kfree(new_argv); > > > > -- > Mathieu Desnoyers > EfficiOS Inc. > https://www.efficios.com > -- Masami Hiramatsu (Google) <mhira...@kernel.org>