@@ -578,17 +578,67 @@ void trace_set_ring_buffer_expanded(struct trace_array *tr)
578578 tr -> ring_buffer_expanded = true;
579579}
580580
581+ static void trace_array_autoremove (struct work_struct * work )
582+ {
583+ struct trace_array * tr = container_of (work , struct trace_array , autoremove_work );
584+
585+ trace_array_destroy (tr );
586+ }
587+
588+ static struct workqueue_struct * autoremove_wq ;
589+
590+ static void trace_array_kick_autoremove (struct trace_array * tr )
591+ {
592+ if (autoremove_wq )
593+ queue_work (autoremove_wq , & tr -> autoremove_work );
594+ }
595+
596+ static void trace_array_cancel_autoremove (struct trace_array * tr )
597+ {
598+ /*
599+ * Since this can be called inside trace_array_autoremove(),
600+ * it has to avoid deadlock of the workqueue.
601+ */
602+ if (work_pending (& tr -> autoremove_work ))
603+ cancel_work_sync (& tr -> autoremove_work );
604+ }
605+
606+ static void trace_array_init_autoremove (struct trace_array * tr )
607+ {
608+ INIT_WORK (& tr -> autoremove_work , trace_array_autoremove );
609+ }
610+
611+ static void trace_array_start_autoremove (void )
612+ {
613+ if (autoremove_wq )
614+ return ;
615+
616+ autoremove_wq = alloc_workqueue ("tr_autoremove_wq" ,
617+ WQ_UNBOUND | WQ_HIGHPRI , 0 );
618+ if (!autoremove_wq )
619+ pr_warn ("Unable to allocate tr_autoremove_wq. autoremove disabled.\n" );
620+ }
621+
581622LIST_HEAD (ftrace_trace_arrays );
582623
624+ static int __trace_array_get (struct trace_array * this_tr )
625+ {
626+ /* When free_on_close is set, this is not available anymore. */
627+ if (autoremove_wq && this_tr -> free_on_close )
628+ return - ENODEV ;
629+
630+ this_tr -> ref ++ ;
631+ return 0 ;
632+ }
633+
583634int trace_array_get (struct trace_array * this_tr )
584635{
585636 struct trace_array * tr ;
586637
587638 guard (mutex )(& trace_types_lock );
588639 list_for_each_entry (tr , & ftrace_trace_arrays , list ) {
589640 if (tr == this_tr ) {
590- tr -> ref ++ ;
591- return 0 ;
641+ return __trace_array_get (tr );
592642 }
593643 }
594644
@@ -599,6 +649,12 @@ static void __trace_array_put(struct trace_array *this_tr)
599649{
600650 WARN_ON (!this_tr -> ref );
601651 this_tr -> ref -- ;
652+ /*
653+ * When free_on_close is set, prepare removing the array
654+ * when the last reference is released.
655+ */
656+ if (this_tr -> ref == 1 && this_tr -> free_on_close )
657+ trace_array_kick_autoremove (this_tr );
602658}
603659
604660/**
@@ -5467,6 +5523,10 @@ static void update_last_data(struct trace_array *tr)
54675523 /* Only if the buffer has previous boot data clear and update it. */
54685524 tr -> flags &= ~TRACE_ARRAY_FL_LAST_BOOT ;
54695525
5526+ /* If this is a backup instance, mark it for autoremove. */
5527+ if (tr -> flags & TRACE_ARRAY_FL_VMALLOC )
5528+ tr -> free_on_close = true;
5529+
54705530 /* Reset the module list and reload them */
54715531 if (tr -> scratch ) {
54725532 struct trace_scratch * tscratch = tr -> scratch ;
@@ -9537,8 +9597,8 @@ struct trace_array *trace_array_find_get(const char *instance)
95379597
95389598 guard (mutex )(& trace_types_lock );
95399599 tr = trace_array_find (instance );
9540- if (tr )
9541- tr -> ref ++ ;
9600+ if (tr && __trace_array_get ( tr ) < 0 )
9601+ tr = NULL ;
95429602
95439603 return tr ;
95449604}
@@ -9635,6 +9695,8 @@ trace_array_create_systems(const char *name, const char *systems,
96359695 if (ftrace_allocate_ftrace_ops (tr ) < 0 )
96369696 goto out_free_tr ;
96379697
9698+ trace_array_init_autoremove (tr );
9699+
96389700 ftrace_init_trace_array (tr );
96399701
96409702 init_trace_flags_index (tr );
@@ -9745,7 +9807,9 @@ struct trace_array *trace_array_get_by_name(const char *name, const char *system
97459807
97469808 list_for_each_entry (tr , & ftrace_trace_arrays , list ) {
97479809 if (tr -> name && strcmp (tr -> name , name ) == 0 ) {
9748- tr -> ref ++ ;
9810+ /* if this fails, @tr is going to be removed. */
9811+ if (__trace_array_get (tr ) < 0 )
9812+ tr = NULL ;
97499813 return tr ;
97509814 }
97519815 }
@@ -9784,6 +9848,7 @@ static int __remove_instance(struct trace_array *tr)
97849848 set_tracer_flag (tr , 1ULL << i , 0 );
97859849 }
97869850
9851+ trace_array_cancel_autoremove (tr );
97879852 tracing_set_nop (tr );
97889853 clear_ftrace_function_probes (tr );
97899854 event_trace_del_tracer (tr );
@@ -10790,8 +10855,10 @@ __init static void enable_instances(void)
1079010855 /*
1079110856 * Backup buffers can be freed but need vfree().
1079210857 */
10793- if (backup )
10858+ if (backup ) {
1079410859 tr -> flags |= TRACE_ARRAY_FL_VMALLOC | TRACE_ARRAY_FL_RDONLY ;
10860+ trace_array_start_autoremove ();
10861+ }
1079510862
1079610863 if (start || backup ) {
1079710864 tr -> flags |= TRACE_ARRAY_FL_BOOT | TRACE_ARRAY_FL_LAST_BOOT ;
0 commit comments