Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing: Fix syscall events activation by ensuring refcount hits zero

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: ce1039bd3a89 ("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>

authored by

Huiwen He and committed by
Steven Rostedt (Google)
0a663b76 b96d0c59

+37 -15
+37 -15
kernel/trace/trace_events.c
··· 4668 4668 return 0; 4669 4669 } 4670 4670 4671 - __init void 4672 - early_enable_events(struct trace_array *tr, char *buf, bool disable_first) 4671 + /* 4672 + * Helper function to enable or disable a comma-separated list of events 4673 + * from the bootup buffer. 4674 + */ 4675 + static __init void __early_set_events(struct trace_array *tr, char *buf, bool enable) 4673 4676 { 4674 4677 char *token; 4675 - int ret; 4676 4678 4677 - while (true) { 4678 - token = strsep(&buf, ","); 4679 - 4680 - if (!token) 4681 - break; 4682 - 4679 + while ((token = strsep(&buf, ","))) { 4683 4680 if (*token) { 4684 - /* Restarting syscalls requires that we stop them first */ 4685 - if (disable_first) 4681 + if (enable) { 4682 + if (ftrace_set_clr_event(tr, token, 1)) 4683 + pr_warn("Failed to enable trace event: %s\n", token); 4684 + } else { 4686 4685 ftrace_set_clr_event(tr, token, 0); 4687 - 4688 - ret = ftrace_set_clr_event(tr, token, 1); 4689 - if (ret) 4690 - pr_warn("Failed to enable trace event: %s\n", token); 4686 + } 4691 4687 } 4692 4688 4693 4689 /* Put back the comma to allow this to be called again */ 4694 4690 if (buf) 4695 4691 *(buf - 1) = ','; 4696 4692 } 4693 + } 4694 + 4695 + /** 4696 + * early_enable_events - enable events from the bootup buffer 4697 + * @tr: The trace array to enable the events in 4698 + * @buf: The buffer containing the comma separated list of events 4699 + * @disable_first: If true, disable all events in @buf before enabling them 4700 + * 4701 + * This function enables events from the bootup buffer. If @disable_first 4702 + * is true, it will first disable all events in the buffer before enabling 4703 + * them. 4704 + * 4705 + * For syscall events, which rely on a global refcount to register the 4706 + * SYSCALL_WORK_SYSCALL_TRACEPOINT flag (especially for pid 1), we must 4707 + * ensure the refcount hits zero before re-enabling them. A simple 4708 + * "disable then enable" per-event is not enough if multiple syscalls are 4709 + * used, as the refcount will stay above zero. Thus, we need a two-phase 4710 + * approach: disable all, then enable all. 4711 + */ 4712 + __init void 4713 + early_enable_events(struct trace_array *tr, char *buf, bool disable_first) 4714 + { 4715 + if (disable_first) 4716 + __early_set_events(tr, buf, false); 4717 + 4718 + __early_set_events(tr, buf, true); 4697 4719 } 4698 4720 4699 4721 static __init int event_trace_enable(void)