Skip to content

Commit eca33fd

Browse files
mhiramatrostedt
authored andcommitted
tracing: Remove the backup instance automatically after read
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. Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Link: https://patch.msgid.link/177502547711.1311542.12572973358010839400.stgit@mhiramat.tok.corp.google.com Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 2c79da0 commit eca33fd

2 files changed

Lines changed: 79 additions & 6 deletions

File tree

kernel/trace/trace.c

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
581622
LIST_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+
583634
int 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;

kernel/trace/trace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,12 @@ struct trace_array {
453453
* we do not waste memory on systems that are not using tracing.
454454
*/
455455
bool ring_buffer_expanded;
456+
/*
457+
* If the ring buffer is a read only backup instance, it will be
458+
* removed after dumping all data via pipe, because no readable data.
459+
*/
460+
bool free_on_close;
461+
struct work_struct autoremove_work;
456462
};
457463

458464
enum {

0 commit comments

Comments
 (0)