* [PATCH v4 0/2] tracing: Preserve repeated boot-time parameters and drain deferred trigger frees @ 2026-03-24 22:13 Wesley Atwell 2026-03-24 22:13 ` [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters Wesley Atwell 2026-03-24 22:13 ` [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails Wesley Atwell 0 siblings, 2 replies; 9+ messages in thread From: Wesley Atwell @ 2026-03-24 22:13 UTC (permalink / raw) To: linux-trace-kernel Cc: linux-kernel, rostedt, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi, Wesley Atwell Patch 1 preserves repeated boot-time tracing parameters by appending to the existing parser buffers instead of overwriting earlier values, so repeated command-line entries and Bootconfig array expansions work with the delimited formats the parsers already consume. Patch 2 fixes the deferred event-trigger free path so queued frees are still drained if the cleanup kthread never comes up after boot. v4: - drop the kernel-parameters.txt update from patch 1 - move trace_append_boot_param() into trace.c and keep only the prototype in trace.h - capitalize the tracing patch subjects - rename trigger_start_kthread_locked() to trigger_create_kthread_locked() - change the failure comment to say "creation failed" Wesley Atwell (2): tracing: Preserve repeated boot-time tracing parameters tracing: Drain deferred trigger frees if kthread creation fails kernel/trace/ftrace.c | 12 +++-- kernel/trace/trace.c | 31 ++++++++++- kernel/trace/trace.h | 2 + kernel/trace/trace_events.c | 26 ++++++++-- kernel/trace/trace_events_trigger.c | 79 ++++++++++++++++++++++++----- kernel/trace/trace_kprobe.c | 3 +- 6 files changed, 131 insertions(+), 22 deletions(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters 2026-03-24 22:13 [PATCH v4 0/2] tracing: Preserve repeated boot-time parameters and drain deferred trigger frees Wesley Atwell @ 2026-03-24 22:13 ` Wesley Atwell 2026-03-28 17:53 ` Steven Rostedt 2026-03-28 20:18 ` [PATCH v5] " Wesley Atwell 2026-03-24 22:13 ` [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails Wesley Atwell 1 sibling, 2 replies; 9+ messages in thread From: Wesley Atwell @ 2026-03-24 22:13 UTC (permalink / raw) To: linux-trace-kernel Cc: linux-kernel, rostedt, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi, Wesley Atwell Some tracing boot parameters already accept delimited value lists, but their __setup() handlers keep only the last instance seen at boot. Make repeated instances append to the same boot-time buffer in the format each parser already consumes. Use a shared trace_append_boot_param() helper for the ftrace filters, trace_options, and kprobe_event boot parameters. trace_trigger= tokenizes its backing storage in place, so keep a running offset and only parse the newly appended chunk into bootup_triggers[]. This also lets Bootconfig array values work naturally when they expand to repeated param=value entries. Signed-off-by: Wesley Atwell <atwellwea@gmail.com> --- kernel/trace/ftrace.c | 12 ++++++++---- kernel/trace/trace.c | 31 ++++++++++++++++++++++++++++++- kernel/trace/trace.h | 2 ++ kernel/trace/trace_events.c | 26 +++++++++++++++++++++++--- kernel/trace/trace_kprobe.c | 3 ++- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 413310912609..8bd3dd1d549c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -6841,7 +6841,8 @@ bool ftrace_filter_param __initdata; static int __init set_ftrace_notrace(char *str) { ftrace_filter_param = true; - strscpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_notrace_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_notrace=", set_ftrace_notrace); @@ -6849,7 +6850,8 @@ __setup("ftrace_notrace=", set_ftrace_notrace); static int __init set_ftrace_filter(char *str) { ftrace_filter_param = true; - strscpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_filter_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_filter=", set_ftrace_filter); @@ -6861,14 +6863,16 @@ static int ftrace_graph_set_hash(struct ftrace_hash *hash, char *buffer); static int __init set_graph_function(char *str) { - strscpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_graph_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_filter=", set_graph_function); static int __init set_graph_notrace_function(char *str) { - strscpy(ftrace_graph_notrace_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_graph_notrace_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_notrace=", set_graph_notrace_function); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a626211ceb9a..1b1f6f9035c6 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -228,6 +228,34 @@ static int boot_instance_index; static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata; static int boot_snapshot_index; +/* + * Repeated boot parameters, including Bootconfig array expansions, need + * to stay in the delimiter form that the existing parser consumes. + */ +void __init trace_append_boot_param(char *buf, const char *str, char sep, + size_t size) +{ + size_t len, str_len; + + if (!buf[0]) { + strscpy(buf, str, size); + return; + } + + str_len = strlen(str); + if (!str_len) + return; + + len = strlen(buf); + if (len >= size - 1) + return; + if (str_len >= size - len - 1) + return; + + buf[len] = sep; + strscpy(buf + len + 1, str, size - len - 1); +} + static int __init set_cmdline_ftrace(char *str) { strscpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); @@ -329,7 +357,8 @@ static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; static int __init set_trace_boot_options(char *str) { - strscpy(trace_boot_options_buf, str, MAX_TRACER_SIZE); + trace_append_boot_param(trace_boot_options_buf, str, ',', + MAX_TRACER_SIZE); return 1; } __setup("trace_options=", set_trace_boot_options); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index b8f3804586a0..64ce179d12dd 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -863,6 +863,8 @@ extern int DYN_FTRACE_TEST_NAME(void); extern int DYN_FTRACE_TEST_NAME2(void); extern void trace_set_ring_buffer_expanded(struct trace_array *tr); +void __init trace_append_boot_param(char *buf, const char *str, + char sep, size_t size); extern bool tracing_selftest_disabled; #ifdef CONFIG_FTRACE_STARTUP_TEST diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 249d1cba72c0..5f72be33f2d1 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -3679,20 +3679,40 @@ static struct boot_triggers { } bootup_triggers[MAX_BOOT_TRIGGERS]; static char bootup_trigger_buf[COMMAND_LINE_SIZE]; +static size_t bootup_trigger_buf_len; static int nr_boot_triggers; static __init int setup_trace_triggers(char *str) { char *trigger; char *buf; + size_t start, str_len; int i; - strscpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); + if (bootup_trigger_buf_len >= COMMAND_LINE_SIZE) + return 1; + + start = bootup_trigger_buf_len; + if (start && !*str) + return 1; + + str_len = strlen(str); + if (start && str_len >= COMMAND_LINE_SIZE - start) + return 1; + + /* + * trace_trigger= parsing tokenizes the backing storage in place. + * Copy each repeated parameter into fresh space and only parse that + * newly copied chunk here. + */ + trace_append_boot_param(bootup_trigger_buf + start, str, '\0', + COMMAND_LINE_SIZE - start); + bootup_trigger_buf_len += strlen(bootup_trigger_buf + start) + 1; trace_set_ring_buffer_expanded(NULL); disable_tracing_selftest("running event triggers"); - buf = bootup_trigger_buf; - for (i = 0; i < MAX_BOOT_TRIGGERS; i++) { + buf = bootup_trigger_buf + start; + for (i = nr_boot_triggers; i < MAX_BOOT_TRIGGERS; i++) { trigger = strsep(&buf, ","); if (!trigger) break; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a5dbb72528e0..e9f1c55aea64 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -31,7 +31,8 @@ static char kprobe_boot_events_buf[COMMAND_LINE_SIZE] __initdata; static int __init set_kprobe_boot_events(char *str) { - strscpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); + trace_append_boot_param(kprobe_boot_events_buf, str, ';', + COMMAND_LINE_SIZE); disable_tracing_selftest("running kprobe events"); return 1; -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters 2026-03-24 22:13 ` [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters Wesley Atwell @ 2026-03-28 17:53 ` Steven Rostedt 2026-03-28 20:18 ` [PATCH v5] " Wesley Atwell 1 sibling, 0 replies; 9+ messages in thread From: Steven Rostedt @ 2026-03-28 17:53 UTC (permalink / raw) To: Wesley Atwell Cc: linux-trace-kernel, linux-kernel, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi On Tue, 24 Mar 2026 16:13:25 -0600 Wesley Atwell <atwellwea@gmail.com> wrote: > +++ b/kernel/trace/trace.c > @@ -228,6 +228,34 @@ static int boot_instance_index; > static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata; > static int boot_snapshot_index; > > +/* > + * Repeated boot parameters, including Bootconfig array expansions, need > + * to stay in the delimiter form that the existing parser consumes. > + */ > +void __init trace_append_boot_param(char *buf, const char *str, char sep, > + size_t size) > +{ > + size_t len, str_len; Why use the "size_t" type? Just use int. Then you don't need to play games about unsigned types in the if statements below. The boot cmdline will never come close to being 2GB in size. > + > + if (!buf[0]) { Should we check for size here? Perhaps just remove this part (see below) > + strscpy(buf, str, size); > + return; > + } > + > + str_len = strlen(str); > + if (!str_len) > + return; > + > + len = strlen(buf); > + if (len >= size - 1) > + return; > + if (str_len >= size - len - 1) > + return; Instead of the above, have: /* Plus 2 for ",\0" */ if (str_len + len + 2 > size) return; > + > + buf[len] = sep; If we remove the first check, here we can have: if (len) buf[len++] = sep; By adding one to length, it makes the strscpy() a bit more readable. strscpy(buf + len, str, size - len); > + strscpy(buf + len + 1, str, size - len - 1); > +} > + -- Steve ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v5] tracing: Preserve repeated boot-time tracing parameters 2026-03-24 22:13 ` [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters Wesley Atwell 2026-03-28 17:53 ` Steven Rostedt @ 2026-03-28 20:18 ` Wesley Atwell 1 sibling, 0 replies; 9+ messages in thread From: Wesley Atwell @ 2026-03-28 20:18 UTC (permalink / raw) To: Steven Rostedt, Masami Hiramatsu Cc: Mark Rutland, Mathieu Desnoyers, linux-kernel, linux-trace-kernel, Wesley Atwell Some tracing boot parameters already accept delimited value lists, but their __setup() handlers keep only the last instance seen at boot. Make repeated instances append to the same boot-time buffer in the format each parser already consumes. Use a shared trace_append_boot_param() helper for the ftrace filters, trace_options, and kprobe_event boot parameters. trace_trigger= tokenizes its backing storage in place, so keep a running offset and only parse the newly appended chunk into bootup_triggers[]. This also lets Bootconfig array values work naturally when they expand to repeated param=value entries. Validated by booting with repeated ftrace_filter=, ftrace_notrace=, ftrace_graph_filter=, ftrace_graph_notrace=, trace_options=, kprobe_event=, and trace_trigger= parameters and confirming that the resulting tracefs state preserved every requested entry. Before this change, only the last instance from each repeated parameter survived boot. Signed-off-by: Wesley Atwell <atwellwea@gmail.com> --- v5: - use int sizes in the shared append helper and trace_trigger bookkeeping - keep a single bounded append path that only inserts the separator after the first entry - only advance the trace_trigger buffer offset after a successful append kernel/trace/ftrace.c | 12 ++++++++---- kernel/trace/trace.c | 29 ++++++++++++++++++++++++++++- kernel/trace/trace.h | 2 ++ kernel/trace/trace_events.c | 23 ++++++++++++++++++++--- kernel/trace/trace_kprobe.c | 3 ++- 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 413310912609..8bd3dd1d549c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -6841,7 +6841,8 @@ bool ftrace_filter_param __initdata; static int __init set_ftrace_notrace(char *str) { ftrace_filter_param = true; - strscpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_notrace_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_notrace=", set_ftrace_notrace); @@ -6849,7 +6850,8 @@ __setup("ftrace_notrace=", set_ftrace_notrace); static int __init set_ftrace_filter(char *str) { ftrace_filter_param = true; - strscpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_filter_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_filter=", set_ftrace_filter); @@ -6861,14 +6863,16 @@ static int ftrace_graph_set_hash(struct ftrace_hash *hash, char *buffer); static int __init set_graph_function(char *str) { - strscpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_graph_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_filter=", set_graph_function); static int __init set_graph_notrace_function(char *str) { - strscpy(ftrace_graph_notrace_buf, str, FTRACE_FILTER_SIZE); + trace_append_boot_param(ftrace_graph_notrace_buf, str, ',', + FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_notrace=", set_graph_notrace_function); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a626211ceb9a..c8cf45dc4152 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -228,6 +228,32 @@ static int boot_instance_index; static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata; static int boot_snapshot_index; +/* + * Repeated boot parameters, including Bootconfig array expansions, need + * to stay in the delimiter form that the existing parser consumes. + */ +void __init trace_append_boot_param(char *buf, const char *str, char sep, + int size) +{ + int len, needed, str_len; + + if (!*str) + return; + + len = strlen(buf); + str_len = strlen(str); + needed = len + str_len + 1; + if (len) + needed++; + if (needed > size) + return; + + if (len) + buf[len++] = sep; + + strscpy(buf + len, str, size - len); +} + static int __init set_cmdline_ftrace(char *str) { strscpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); @@ -329,7 +355,8 @@ static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; static int __init set_trace_boot_options(char *str) { - strscpy(trace_boot_options_buf, str, MAX_TRACER_SIZE); + trace_append_boot_param(trace_boot_options_buf, str, ',', + MAX_TRACER_SIZE); return 1; } __setup("trace_options=", set_trace_boot_options); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index b8f3804586a0..237a0417de1c 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -863,6 +863,8 @@ extern int DYN_FTRACE_TEST_NAME(void); extern int DYN_FTRACE_TEST_NAME2(void); extern void trace_set_ring_buffer_expanded(struct trace_array *tr); +void __init trace_append_boot_param(char *buf, const char *str, + char sep, int size); extern bool tracing_selftest_disabled; #ifdef CONFIG_FTRACE_STARTUP_TEST diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 249d1cba72c0..7f0bec4622f6 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -3679,20 +3679,37 @@ static struct boot_triggers { } bootup_triggers[MAX_BOOT_TRIGGERS]; static char bootup_trigger_buf[COMMAND_LINE_SIZE]; +static int bootup_trigger_buf_len; static int nr_boot_triggers; static __init int setup_trace_triggers(char *str) { + char *slot; char *trigger; char *buf; int i; - strscpy(bootup_trigger_buf, str, COMMAND_LINE_SIZE); + if (bootup_trigger_buf_len >= COMMAND_LINE_SIZE) + return 1; + + slot = bootup_trigger_buf + bootup_trigger_buf_len; + + /* + * trace_trigger= parsing tokenizes the backing storage in place. + * Copy each repeated parameter into fresh space and only parse that + * newly copied chunk here. + */ + trace_append_boot_param(slot, str, '\0', + COMMAND_LINE_SIZE - bootup_trigger_buf_len); + if (!*slot) + return 1; + + bootup_trigger_buf_len += strlen(slot) + 1; trace_set_ring_buffer_expanded(NULL); disable_tracing_selftest("running event triggers"); - buf = bootup_trigger_buf; - for (i = 0; i < MAX_BOOT_TRIGGERS; i++) { + buf = slot; + for (i = nr_boot_triggers; i < MAX_BOOT_TRIGGERS; i++) { trigger = strsep(&buf, ","); if (!trigger) break; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a5dbb72528e0..e9f1c55aea64 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -31,7 +31,8 @@ static char kprobe_boot_events_buf[COMMAND_LINE_SIZE] __initdata; static int __init set_kprobe_boot_events(char *str) { - strscpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); + trace_append_boot_param(kprobe_boot_events_buf, str, ';', + COMMAND_LINE_SIZE); disable_tracing_selftest("running kprobe events"); return 1; -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails 2026-03-24 22:13 [PATCH v4 0/2] tracing: Preserve repeated boot-time parameters and drain deferred trigger frees Wesley Atwell 2026-03-24 22:13 ` [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters Wesley Atwell @ 2026-03-24 22:13 ` Wesley Atwell 2026-03-27 19:06 ` Steven Rostedt 1 sibling, 1 reply; 9+ messages in thread From: Wesley Atwell @ 2026-03-24 22:13 UTC (permalink / raw) To: linux-trace-kernel Cc: linux-kernel, rostedt, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi, Wesley Atwell Boot-time trigger registration can fail before the trigger-data cleanup kthread exists. Deferring those frees until late init is fine, but the post-boot fallback must still drain the deferred list if kthread creation never succeeds. Otherwise, boot-deferred nodes can accumulate on trigger_data_free_list, later frees fall back to synchronously freeing only the current object, and the older queued entries are leaked forever. Keep the deferred boot-time behavior, but when kthread creation fails, drain the whole queued list synchronously. Do the same in the late-init drain path so queued entries are not stranded there either. Fixes: 61d445af0a7c ("tracing: Add bulk garbage collection of freeing event_trigger_data") Signed-off-by: Wesley Atwell <atwellwea@gmail.com> --- kernel/trace/trace_events_trigger.c | 79 ++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index d5230b759a2d..655db2e82513 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -22,6 +22,39 @@ static struct task_struct *trigger_kthread; static struct llist_head trigger_data_free_list; static DEFINE_MUTEX(trigger_data_kthread_mutex); +static int trigger_kthread_fn(void *ignore); + +static void trigger_create_kthread_locked(void) +{ + lockdep_assert_held(&trigger_data_kthread_mutex); + + if (!trigger_kthread) { + struct task_struct *kthread; + + kthread = kthread_create(trigger_kthread_fn, NULL, + "trigger_data_free"); + if (!IS_ERR(kthread)) + WRITE_ONCE(trigger_kthread, kthread); + } +} + +static void trigger_data_free_queued_locked(void) +{ + struct event_trigger_data *data, *tmp; + struct llist_node *llnodes; + + lockdep_assert_held(&trigger_data_kthread_mutex); + + llnodes = llist_del_all(&trigger_data_free_list); + if (!llnodes) + return; + + tracepoint_synchronize_unregister(); + + llist_for_each_entry_safe(data, tmp, llnodes, llist) + kfree(data); +} + /* Bulk garbage collection of event_trigger_data elements */ static int trigger_kthread_fn(void *ignore) { @@ -56,30 +89,50 @@ void trigger_data_free(struct event_trigger_data *data) if (data->cmd_ops->set_filter) data->cmd_ops->set_filter(NULL, data, NULL); + /* + * Boot-time trigger registration can fail before kthread creation + * works. Keep the deferred-free semantics during boot and let late + * init start the kthread to drain the list. + */ + if (system_state == SYSTEM_BOOTING && !trigger_kthread) { + llist_add(&data->llist, &trigger_data_free_list); + return; + } + if (unlikely(!trigger_kthread)) { guard(mutex)(&trigger_data_kthread_mutex); + + trigger_create_kthread_locked(); /* Check again after taking mutex */ if (!trigger_kthread) { - struct task_struct *kthread; - - kthread = kthread_create(trigger_kthread_fn, NULL, - "trigger_data_free"); - if (!IS_ERR(kthread)) - WRITE_ONCE(trigger_kthread, kthread); + llist_add(&data->llist, &trigger_data_free_list); + /* Drain the queued frees synchronously if creation failed. */ + trigger_data_free_queued_locked(); + return; } } - if (!trigger_kthread) { - /* Do it the slow way */ - tracepoint_synchronize_unregister(); - kfree(data); - return; - } - llist_add(&data->llist, &trigger_data_free_list); wake_up_process(trigger_kthread); } +static int __init trigger_data_free_init(void) +{ + guard(mutex)(&trigger_data_kthread_mutex); + + if (llist_empty(&trigger_data_free_list)) + return 0; + + trigger_create_kthread_locked(); + if (trigger_kthread) + wake_up_process(trigger_kthread); + else + trigger_data_free_queued_locked(); + + return 0; +} +late_initcall(trigger_data_free_init); + static inline void data_ops_trigger(struct event_trigger_data *data, struct trace_buffer *buffer, void *rec, struct ring_buffer_event *event) -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails 2026-03-24 22:13 ` [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails Wesley Atwell @ 2026-03-27 19:06 ` Steven Rostedt 2026-03-27 22:41 ` Wesley Atwell 0 siblings, 1 reply; 9+ messages in thread From: Steven Rostedt @ 2026-03-27 19:06 UTC (permalink / raw) To: Wesley Atwell Cc: linux-trace-kernel, linux-kernel, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi On Tue, 24 Mar 2026 16:13:26 -0600 Wesley Atwell <atwellwea@gmail.com> wrote: > Boot-time trigger registration can fail before the trigger-data cleanup > kthread exists. Deferring those frees until late init is fine, but the > post-boot fallback must still drain the deferred list if kthread > creation never succeeds. > > Otherwise, boot-deferred nodes can accumulate on > trigger_data_free_list, later frees fall back to synchronously freeing > only the current object, and the older queued entries are leaked > forever. > > Keep the deferred boot-time behavior, but when kthread creation fails, > drain the whole queued list synchronously. Do the same in the late-init > drain path so queued entries are not stranded there either. > > Fixes: 61d445af0a7c ("tracing: Add bulk garbage collection of freeing event_trigger_data") > Signed-off-by: Wesley Atwell <atwellwea@gmail.com> > --- Do you have a test case (kernel command line) that will make trigger_data_free() get called at boot up? -- Steve ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails 2026-03-27 19:06 ` Steven Rostedt @ 2026-03-27 22:41 ` Wesley Atwell 2026-03-28 2:30 ` Steven Rostedt 0 siblings, 1 reply; 9+ messages in thread From: Wesley Atwell @ 2026-03-27 22:41 UTC (permalink / raw) To: Steven Rostedt Cc: linux-trace-kernel, linux-kernel, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi Yes, This kernel command line reliably reaches trigger_data_free() during boot: trace_event=sched:sched_switch trace_trigger=sched_switch.traceon,sched_switch.traceon On an unpatched tree, that crashes during early boot before userspace. The call trace goes through: trigger_data_free() __kthread_create_on_node() try_to_wake_up() The stack also shows the boot-time trigger registration path: event_trigger_parse() trigger_process_regex() __trace_early_add_events() With v4 applied, the same command line boots successfully. The guest log shows: Failed to register trigger 'traceon' on event sched_switch And /sys/kernel/tracing/events/sched/sched_switch/trigger contains: traceon:unlimited I also verified patch 1 with repeated trace_trigger= parameters: before the patch, only the last parameter was preserved; after the patch, both triggers were installed. Thanks, Wesley Atwell ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails 2026-03-27 22:41 ` Wesley Atwell @ 2026-03-28 2:30 ` Steven Rostedt 2026-03-28 4:56 ` Wesley Atwell 0 siblings, 1 reply; 9+ messages in thread From: Steven Rostedt @ 2026-03-28 2:30 UTC (permalink / raw) To: Wesley Atwell Cc: linux-trace-kernel, linux-kernel, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi On Fri, 27 Mar 2026 16:41:52 -0600 Wesley Atwell <atwellwea@gmail.com> wrote: > Yes, > > This kernel command line reliably reaches trigger_data_free() during boot: > > trace_event=sched:sched_switch > trace_trigger=sched_switch.traceon,sched_switch.traceon > > On an unpatched tree, that crashes during early boot before userspace. > The call trace goes through: > > trigger_data_free() > __kthread_create_on_node() > try_to_wake_up() > > The stack also shows the boot-time trigger registration path: > > event_trigger_parse() > trigger_process_regex() > __trace_early_add_events() Thanks for this. I can reproduce the crash. I'm also going to add this to the change log as it is useful (I'll even add it to one of my regression tests). I'll take this patch separately (this didn't need to be a patch series, as the two patches do not depend on each other). -- Steve ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails 2026-03-28 2:30 ` Steven Rostedt @ 2026-03-28 4:56 ` Wesley Atwell 0 siblings, 0 replies; 9+ messages in thread From: Wesley Atwell @ 2026-03-28 4:56 UTC (permalink / raw) To: Steven Rostedt Cc: linux-trace-kernel, linux-kernel, mhiramat, mark.rutland, mathieu.desnoyers, tom.zanussi Hi Steve, I'm glad the test case was helpful. I'll include similar testing details in future commit messages and avoid grouping unrelated patches. Thanks, Wesley Atwell ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-03-28 20:18 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-24 22:13 [PATCH v4 0/2] tracing: Preserve repeated boot-time parameters and drain deferred trigger frees Wesley Atwell 2026-03-24 22:13 ` [PATCH v4 1/2] tracing: Preserve repeated boot-time tracing parameters Wesley Atwell 2026-03-28 17:53 ` Steven Rostedt 2026-03-28 20:18 ` [PATCH v5] " Wesley Atwell 2026-03-24 22:13 ` [PATCH v4 2/2] tracing: Drain deferred trigger frees if kthread creation fails Wesley Atwell 2026-03-27 19:06 ` Steven Rostedt 2026-03-27 22:41 ` Wesley Atwell 2026-03-28 2:30 ` Steven Rostedt 2026-03-28 4:56 ` Wesley Atwell
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox