Skip to content
/ linux Public

Commit c2bbdee

Browse files
haryvengregkh
authored andcommitted
tracing: Fix syscall events activation by ensuring refcount hits zero
commit 0a663b7 upstream. When multiple syscall events are specified in the kernel command line (e.g., trace_event=syscalls:sys_enter_openat,syscalls:sys_enter_close), they are often not captured after boot, even though they appear enabled in the tracing/set_event file. The issue stems from how syscall events are initialized. Syscall tracepoints require the global reference count (sys_tracepoint_refcount) to transition from 0 to 1 to trigger the registration of the syscall work (TIF_SYSCALL_TRACEPOINT) for tasks, including the init process (pid 1). The current implementation of early_enable_events() with disable_first=true used an interleaved sequence of "Disable A -> Enable A -> Disable B -> Enable B". If multiple syscalls are enabled, the refcount never drops to zero, preventing the 0->1 transition that triggers actual registration. Fix this by splitting early_enable_events() into two distinct phases: 1. Disable all events specified in the buffer. 2. Enable all events specified in the buffer. This ensures the refcount hits zero before re-enabling, allowing syscall events to be properly activated during early boot. The code is also refactored to use a helper function to avoid logic duplication between the disable and enable phases. Cc: stable@vger.kernel.org Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Link: https://patch.msgid.link/20260224023544.1250787-1-hehuiwen@kylinos.cn Fixes: ce1039b ("tracing: Fix enabling of syscall events on the command line") Signed-off-by: Huiwen He <hehuiwen@kylinos.cn> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent efd9598 commit c2bbdee

File tree

1 file changed

+37
-15
lines changed

1 file changed

+37
-15
lines changed

kernel/trace/trace_events.c

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4173,26 +4173,22 @@ static __init int event_trace_memsetup(void)
41734173
return 0;
41744174
}
41754175

4176-
__init void
4177-
early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
4176+
/*
4177+
* Helper function to enable or disable a comma-separated list of events
4178+
* from the bootup buffer.
4179+
*/
4180+
static __init void __early_set_events(struct trace_array *tr, char *buf, bool enable)
41784181
{
41794182
char *token;
4180-
int ret;
4181-
4182-
while (true) {
4183-
token = strsep(&buf, ",");
4184-
4185-
if (!token)
4186-
break;
41874183

4184+
while ((token = strsep(&buf, ","))) {
41884185
if (*token) {
4189-
/* Restarting syscalls requires that we stop them first */
4190-
if (disable_first)
4186+
if (enable) {
4187+
if (ftrace_set_clr_event(tr, token, 1))
4188+
pr_warn("Failed to enable trace event: %s\n", token);
4189+
} else {
41914190
ftrace_set_clr_event(tr, token, 0);
4192-
4193-
ret = ftrace_set_clr_event(tr, token, 1);
4194-
if (ret)
4195-
pr_warn("Failed to enable trace event: %s\n", token);
4191+
}
41964192
}
41974193

41984194
/* Put back the comma to allow this to be called again */
@@ -4201,6 +4197,32 @@ early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
42014197
}
42024198
}
42034199

4200+
/**
4201+
* early_enable_events - enable events from the bootup buffer
4202+
* @tr: The trace array to enable the events in
4203+
* @buf: The buffer containing the comma separated list of events
4204+
* @disable_first: If true, disable all events in @buf before enabling them
4205+
*
4206+
* This function enables events from the bootup buffer. If @disable_first
4207+
* is true, it will first disable all events in the buffer before enabling
4208+
* them.
4209+
*
4210+
* For syscall events, which rely on a global refcount to register the
4211+
* SYSCALL_WORK_SYSCALL_TRACEPOINT flag (especially for pid 1), we must
4212+
* ensure the refcount hits zero before re-enabling them. A simple
4213+
* "disable then enable" per-event is not enough if multiple syscalls are
4214+
* used, as the refcount will stay above zero. Thus, we need a two-phase
4215+
* approach: disable all, then enable all.
4216+
*/
4217+
__init void
4218+
early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
4219+
{
4220+
if (disable_first)
4221+
__early_set_events(tr, buf, false);
4222+
4223+
__early_set_events(tr, buf, true);
4224+
}
4225+
42044226
static __init int event_trace_enable(void)
42054227
{
42064228
struct trace_array *tr = top_trace_array();

0 commit comments

Comments
 (0)