On Wed, 28 Jan 2026 09:10:04 +0900 "Masami Hiramatsu (Google)" <[email protected]> wrote:
> From: Masami Hiramatsu (Google) <[email protected]> > > Since the backup instance is readonly, after reading all data > via pipe, no data is left on the instance. Thus it can be > removed safely after closing all files. > This also removes it if user resets the ring buffer manually > via 'trace' file. > > Signed-off-by: Masami Hiramatsu (Google) <[email protected]> > --- > Changes in v4: > - Update description. > --- > kernel/trace/trace.c | 64 > +++++++++++++++++++++++++++++++++++++++++++++++++- > kernel/trace/trace.h | 6 +++++ > 2 files changed, 69 insertions(+), 1 deletion(-) > > diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c > index d39f6509c12a..7d615a74f915 100644 > --- a/kernel/trace/trace.c > +++ b/kernel/trace/trace.c > @@ -590,6 +590,55 @@ void trace_set_ring_buffer_expanded(struct trace_array > *tr) > tr->ring_buffer_expanded = true; > } > > +static int __remove_instance(struct trace_array *tr); > + > +static void trace_array_autoremove(struct work_struct *work) > +{ > + struct trace_array *tr = container_of(work, struct trace_array, > autoremove_work); > + > + guard(mutex)(&event_mutex); > + guard(mutex)(&trace_types_lock); > + > + /* > + * This can be fail if someone gets @tr before starting this > + * function, but in that case, this will be kicked again when > + * putting it. So we don't care the result. "So we don't care about the result." > + */ > + __remove_instance(tr); > +} > + > +static struct workqueue_struct *autoremove_wq; > + > +static void trace_array_init_autoremove(struct trace_array *tr) > +{ > + INIT_WORK(&tr->autoremove_work, trace_array_autoremove); > +} > + > +static void trace_array_kick_autoremove(struct trace_array *tr) > +{ > + if (!work_pending(&tr->autoremove_work) && autoremove_wq) > + queue_work(autoremove_wq, &tr->autoremove_work); > +} > + > +static void trace_array_cancel_autoremove(struct trace_array *tr) > +{ > + if (work_pending(&tr->autoremove_work)) > + cancel_work(&tr->autoremove_work); > +} > + > +__init static int trace_array_init_autoremove_wq(void) > +{ This isn't needed if there's no backup trace_array right? Instead of creating a work queue when its not needed, just exit out if there's no backup trace_array. Oh, and the above functions should always test autoremove_wq for NULL. > + autoremove_wq = alloc_workqueue("tr_autoremove_wq", > + WQ_UNBOUND | WQ_HIGHPRI, 0); > + if (!autoremove_wq) { > + pr_err("Unable to allocate tr_autoremove_wq\n"); > + return -ENOMEM; > + } > + return 0; > +} > + > +late_initcall_sync(trace_array_init_autoremove_wq); > + > LIST_HEAD(ftrace_trace_arrays); > > int trace_array_get(struct trace_array *this_tr) > @@ -598,7 +647,7 @@ int trace_array_get(struct trace_array *this_tr) > > guard(mutex)(&trace_types_lock); > list_for_each_entry(tr, &ftrace_trace_arrays, list) { > - if (tr == this_tr) { > + if (tr == this_tr && !tr->free_on_close) { > tr->ref++; > return 0; > } Break the above into: if (tr == this_tr) { if (tr->free_on_close) break; tr->ref++; return 0; } Why continue the loop if we found the trace_array but it's in the process of closing? -- Steve
