Skip to content

Commit 3aceaa5

Browse files
committed
tracing: Use queue_rcu_work() to free filters
Freeing of filters requires to wait for both an RCU grace period as well as a RCU task trace wait period after they have been detached from their lists. The trace task period can be quite large so the freeing of the filters was moved to use the call_rcu*() routines. The problem with that is that the callback functions of call_rcu*() is done from a soft irq and can cause latencies if the callback takes a bit of time. The filters are freed per event in a system and the syscalls system contains an event per system call, which can be over 700 events. Freeing 700 filters in a bottom half is undesirable. Instead, move the freeing to use queue_rcu_work() which is done in task context. Link: https://lore.kernel.org/all/9a2f0cd0-1561-4206-8966-f93ccd25927f@paulmck-laptop/ Cc: Masami Hiramatsu <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Link: https://lore.kernel.org/[email protected] Fixes: a9d0aab ("tracing: Fix regression of filter waiting a long time on RCU synchronization") Suggested-by: "Paul E. McKenney" <[email protected]> Reviewed-by: Paul E. McKenney <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 88c79ec commit 3aceaa5

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

kernel/trace/trace_events_filter.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,13 +1344,14 @@ struct filter_list {
13441344

13451345
struct filter_head {
13461346
struct list_head list;
1347-
struct rcu_head rcu;
1347+
union {
1348+
struct rcu_head rcu;
1349+
struct rcu_work rwork;
1350+
};
13481351
};
13491352

1350-
1351-
static void free_filter_list(struct rcu_head *rhp)
1353+
static void free_filter_list(struct filter_head *filter_list)
13521354
{
1353-
struct filter_head *filter_list = container_of(rhp, struct filter_head, rcu);
13541355
struct filter_list *filter_item, *tmp;
13551356

13561357
list_for_each_entry_safe(filter_item, tmp, &filter_list->list, list) {
@@ -1361,9 +1362,20 @@ static void free_filter_list(struct rcu_head *rhp)
13611362
kfree(filter_list);
13621363
}
13631364

1365+
static void free_filter_list_work(struct work_struct *work)
1366+
{
1367+
struct filter_head *filter_list;
1368+
1369+
filter_list = container_of(to_rcu_work(work), struct filter_head, rwork);
1370+
free_filter_list(filter_list);
1371+
}
1372+
13641373
static void free_filter_list_tasks(struct rcu_head *rhp)
13651374
{
1366-
call_rcu(rhp, free_filter_list);
1375+
struct filter_head *filter_list = container_of(rhp, struct filter_head, rcu);
1376+
1377+
INIT_RCU_WORK(&filter_list->rwork, free_filter_list_work);
1378+
queue_rcu_work(system_wq, &filter_list->rwork);
13671379
}
13681380

13691381
/*
@@ -1460,7 +1472,7 @@ static void filter_free_subsystem_filters(struct trace_subsystem_dir *dir,
14601472
tracepoint_synchronize_unregister();
14611473

14621474
if (head)
1463-
free_filter_list(&head->rcu);
1475+
free_filter_list(head);
14641476

14651477
list_for_each_entry(file, &tr->events, list) {
14661478
if (file->system != dir || !file->filter)
@@ -2305,7 +2317,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
23052317
return 0;
23062318
fail:
23072319
/* No call succeeded */
2308-
free_filter_list(&filter_list->rcu);
2320+
free_filter_list(filter_list);
23092321
parse_error(pe, FILT_ERR_BAD_SUBSYS_FILTER, 0);
23102322
return -EINVAL;
23112323
fail_mem:
@@ -2315,7 +2327,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
23152327
if (!fail)
23162328
delay_free_filter(filter_list);
23172329
else
2318-
free_filter_list(&filter_list->rcu);
2330+
free_filter_list(filter_list);
23192331

23202332
return -ENOMEM;
23212333
}

0 commit comments

Comments
 (0)