summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Raillard <douglas.raillard@arm.com>2025-03-18 18:09:05 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-04-10 14:31:02 +0200
commit72848b81b3ddee4858d3d0e09dcea30cae6e84e1 (patch)
tree3496df403b4d448a297ada5f7e2c2ee1b9f98e00
parentde7b309139f862a44379ecd96e93c9133c69f813 (diff)
downloadlinux-72848b81b3ddee4858d3d0e09dcea30cae6e84e1.tar.gz
linux-72848b81b3ddee4858d3d0e09dcea30cae6e84e1.tar.bz2
linux-72848b81b3ddee4858d3d0e09dcea30cae6e84e1.zip
tracing: Ensure module defining synth event cannot be unloaded while tracing
commit 21581dd4e7ff6c07d0ab577e3c32b13a74b31522 upstream. Currently, using synth_event_delete() will fail if the event is being used (tracing in progress), but that is normally done in the module exit function. At that stage, failing is problematic as returning a non-zero status means the module will become locked (impossible to unload or reload again). Instead, ensure the module exit function does not get called in the first place by increasing the module refcnt when the event is enabled. Cc: stable@vger.kernel.org Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Fixes: 35ca5207c2d11 ("tracing: Add synthetic event command generation functions") Link: https://lore.kernel.org/20250318180906.226841-1-douglas.raillard@arm.com Signed-off-by: Douglas Raillard <douglas.raillard@arm.com> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/trace/trace_events_synth.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index ee174de0b8f6..1f488a6c14ec 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -749,6 +749,34 @@ static struct trace_event_fields synth_event_fields_array[] = {
{}
};
+static int synth_event_reg(struct trace_event_call *call,
+ enum trace_reg type, void *data)
+{
+ struct synth_event *event = container_of(call, struct synth_event, call);
+
+ switch (type) {
+ case TRACE_REG_REGISTER:
+ case TRACE_REG_PERF_REGISTER:
+ if (!try_module_get(event->mod))
+ return -EBUSY;
+ break;
+ default:
+ break;
+ }
+
+ int ret = trace_event_reg(call, type, data);
+
+ switch (type) {
+ case TRACE_REG_UNREGISTER:
+ case TRACE_REG_PERF_UNREGISTER:
+ module_put(event->mod);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
static int register_synth_event(struct synth_event *event)
{
struct trace_event_call *call = &event->call;
@@ -778,7 +806,7 @@ static int register_synth_event(struct synth_event *event)
goto out;
}
call->flags = TRACE_EVENT_FL_TRACEPOINT;
- call->class->reg = trace_event_reg;
+ call->class->reg = synth_event_reg;
call->class->probe = trace_event_raw_event_synth;
call->data = event;
call->tp = event->tp;