Skip to content

Commit 61d445a

Browse files
committed
tracing: Add bulk garbage collection of freeing event_trigger_data
The event trigger data requires a full tracepoint_synchronize_unregister() call before freeing. That call can take 100s of milliseconds to complete. In order to allow for bulk freeing of the trigger data, it can not call the tracepoint_synchronize_unregister() for every individual trigger data being free. Create a kthread that gets created the first time a trigger data is freed, and have it use the lockless llist to get the list of data to free, run the tracepoint_synchronize_unregister() then free everything in the list. By freeing hundreds of event_trigger_data elements together, it only requires two runs of the synchronization function, and not hundreds of runs. This speeds up the operation by orders of magnitude (milliseconds instead of several seconds). Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Tom Zanussi <zanussi@kernel.org> Link: https://patch.msgid.link/20251125214032.151674992@kernel.org Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 78c7051 commit 61d445a

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/ctype.h>
2323
#include <linux/once_lite.h>
2424
#include <linux/ftrace_regs.h>
25+
#include <linux/llist.h>
2526

2627
#include "pid_list.h"
2728

@@ -1808,6 +1809,7 @@ struct event_trigger_data {
18081809
char *name;
18091810
struct list_head named_list;
18101811
struct event_trigger_data *named_data;
1812+
struct llist_node llist;
18111813
};
18121814

18131815
/* Avoid typos */

kernel/trace/trace_events_trigger.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include <linux/security.h>
9+
#include <linux/kthread.h>
910
#include <linux/module.h>
1011
#include <linux/ctype.h>
1112
#include <linux/mutex.h>
@@ -17,15 +18,63 @@
1718
static LIST_HEAD(trigger_commands);
1819
static DEFINE_MUTEX(trigger_cmd_mutex);
1920

21+
static struct task_struct *trigger_kthread;
22+
static struct llist_head trigger_data_free_list;
23+
static DEFINE_MUTEX(trigger_data_kthread_mutex);
24+
25+
/* Bulk garbage collection of event_trigger_data elements */
26+
static int trigger_kthread_fn(void *ignore)
27+
{
28+
struct event_trigger_data *data, *tmp;
29+
struct llist_node *llnodes;
30+
31+
/* Once this task starts, it lives forever */
32+
for (;;) {
33+
set_current_state(TASK_INTERRUPTIBLE);
34+
if (llist_empty(&trigger_data_free_list))
35+
schedule();
36+
37+
__set_current_state(TASK_RUNNING);
38+
39+
llnodes = llist_del_all(&trigger_data_free_list);
40+
41+
/* make sure current triggers exit before free */
42+
tracepoint_synchronize_unregister();
43+
44+
llist_for_each_entry_safe(data, tmp, llnodes, llist)
45+
kfree(data);
46+
}
47+
48+
return 0;
49+
}
50+
2051
void trigger_data_free(struct event_trigger_data *data)
2152
{
2253
if (data->cmd_ops->set_filter)
2354
data->cmd_ops->set_filter(NULL, data, NULL);
2455

25-
/* make sure current triggers exit before free */
26-
tracepoint_synchronize_unregister();
56+
if (unlikely(!trigger_kthread)) {
57+
guard(mutex)(&trigger_data_kthread_mutex);
58+
/* Check again after taking mutex */
59+
if (!trigger_kthread) {
60+
struct task_struct *kthread;
61+
62+
kthread = kthread_create(trigger_kthread_fn, NULL,
63+
"trigger_data_free");
64+
if (!IS_ERR(kthread))
65+
WRITE_ONCE(trigger_kthread, kthread);
66+
}
67+
}
68+
69+
if (!trigger_kthread) {
70+
/* Do it the slow way */
71+
tracepoint_synchronize_unregister();
72+
kfree(data);
73+
return;
74+
}
2775

28-
kfree(data);
76+
llist_add(&data->llist, &trigger_data_free_list);
77+
wake_up_process(trigger_kthread);
2978
}
3079

3180
static inline void data_ops_trigger(struct event_trigger_data *data,

0 commit comments

Comments
 (0)