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: 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>

authored by

Masami Hiramatsu (Google) and committed by
Steven Rostedt (Google)
eca33fda 2c79da09

+79 -6
+73 -6
kernel/trace/trace.c
··· 578 578 tr->ring_buffer_expanded = true; 579 579 } 580 580 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 + 581 622 LIST_HEAD(ftrace_trace_arrays); 623 + 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 + } 582 633 583 634 int trace_array_get(struct trace_array *this_tr) 584 635 { ··· 638 587 guard(mutex)(&trace_types_lock); 639 588 list_for_each_entry(tr, &ftrace_trace_arrays, list) { 640 589 if (tr == this_tr) { 641 - tr->ref++; 642 - return 0; 590 + return __trace_array_get(tr); 643 591 } 644 592 } 645 593 ··· 649 599 { 650 600 WARN_ON(!this_tr->ref); 651 601 this_tr->ref--; 602 + /* 603 + * When free_on_close is set, prepare removing the array 604 + * when the last reference is released. 605 + */ 606 + if (this_tr->ref == 1 && this_tr->free_on_close) 607 + trace_array_kick_autoremove(this_tr); 652 608 } 653 609 654 610 /** ··· 5523 5467 /* Only if the buffer has previous boot data clear and update it. */ 5524 5468 tr->flags &= ~TRACE_ARRAY_FL_LAST_BOOT; 5525 5469 5470 + /* If this is a backup instance, mark it for autoremove. */ 5471 + if (tr->flags & TRACE_ARRAY_FL_VMALLOC) 5472 + tr->free_on_close = true; 5473 + 5526 5474 /* Reset the module list and reload them */ 5527 5475 if (tr->scratch) { 5528 5476 struct trace_scratch *tscratch = tr->scratch; ··· 9597 9537 9598 9538 guard(mutex)(&trace_types_lock); 9599 9539 tr = trace_array_find(instance); 9600 - if (tr) 9601 - tr->ref++; 9540 + if (tr && __trace_array_get(tr) < 0) 9541 + tr = NULL; 9602 9542 9603 9543 return tr; 9604 9544 } ··· 9694 9634 9695 9635 if (ftrace_allocate_ftrace_ops(tr) < 0) 9696 9636 goto out_free_tr; 9637 + 9638 + trace_array_init_autoremove(tr); 9697 9639 9698 9640 ftrace_init_trace_array(tr); 9699 9641 ··· 9807 9745 9808 9746 list_for_each_entry(tr, &ftrace_trace_arrays, list) { 9809 9747 if (tr->name && strcmp(tr->name, name) == 0) { 9810 - tr->ref++; 9748 + /* if this fails, @tr is going to be removed. */ 9749 + if (__trace_array_get(tr) < 0) 9750 + tr = NULL; 9811 9751 return tr; 9812 9752 } 9813 9753 } ··· 9848 9784 set_tracer_flag(tr, 1ULL << i, 0); 9849 9785 } 9850 9786 9787 + trace_array_cancel_autoremove(tr); 9851 9788 tracing_set_nop(tr); 9852 9789 clear_ftrace_function_probes(tr); 9853 9790 event_trace_del_tracer(tr); ··· 10855 10790 /* 10856 10791 * Backup buffers can be freed but need vfree(). 10857 10792 */ 10858 - if (backup) 10793 + if (backup) { 10859 10794 tr->flags |= TRACE_ARRAY_FL_VMALLOC | TRACE_ARRAY_FL_RDONLY; 10795 + trace_array_start_autoremove(); 10796 + } 10860 10797 10861 10798 if (start || backup) { 10862 10799 tr->flags |= TRACE_ARRAY_FL_BOOT | TRACE_ARRAY_FL_LAST_BOOT;
+6
kernel/trace/trace.h
··· 453 453 * we do not waste memory on systems that are not using tracing. 454 454 */ 455 455 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; 456 462 }; 457 463 458 464 enum {