[RFC PATCH 2/4] ftrace: Centralize task filter state updates
From: hu.shengming
Date: Sun Aug 30 2026 - 07:10:49 EST
From: Shengming Hu <hu.shengming@xxxxxxxxxx>
A later change will add task comm filtering alongside the existing PID
filters. Both filters need to share the sched_switch probe and the
per-CPU cached task decision.
Move the probe registration and cache refresh logic into
ftrace_task_filters_changed(). This gives PID and future task filters
a single place to update the shared state when a filter changes.
The helper also refreshes the cached result for currently running tasks
when one PID filter is cleared while the other remains active, instead
of leaving the result unchanged until the next schedule-in.
Signed-off-by: Shengming Hu <hu.shengming@xxxxxxxxxx>
---
kernel/trace/ftrace.c | 58 +++++++++++++++++++++++++++----------------
1 file changed, 37 insertions(+), 21 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 479ea004adc3..0c73abb8fec8 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -8637,6 +8637,16 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops)
return ops->func;
}
+static bool ftrace_task_filters_active(struct trace_array *tr)
+{
+ return rcu_dereference_protected(tr->function_pids,
+ lockdep_is_held(&ftrace_lock)) ||
+ rcu_dereference_protected(tr->function_no_pids,
+ lockdep_is_held(&ftrace_lock));
+}
+
+static void ignore_task_cpu(void *data);
+
static void
ftrace_filter_task_sched_switch_probe(void *data, bool preempt,
struct task_struct *prev,
@@ -8703,11 +8713,31 @@ void ftrace_pid_follow_fork(struct trace_array *tr, bool enable)
}
}
+static void ftrace_task_filters_changed(struct trace_array *tr,
+ bool was_enabled)
+{
+ bool enabled = ftrace_task_filters_active(tr);
+ int cpu;
+
+ if (!was_enabled && enabled)
+ register_trace_sched_switch(ftrace_filter_task_sched_switch_probe, tr);
+ else if (was_enabled && !enabled) {
+ unregister_trace_sched_switch(ftrace_filter_task_sched_switch_probe, tr);
+ for_each_possible_cpu(cpu)
+ per_cpu_ptr(tr->array_buffer.data, cpu)->ftrace_ignore_pid =
+ FTRACE_PID_TRACE;
+ return;
+ }
+
+ if (enabled)
+ on_each_cpu(ignore_task_cpu, tr, 1);
+}
+
static void clear_ftrace_pids(struct trace_array *tr, int type)
{
struct trace_pid_list *pid_list;
struct trace_pid_list *no_pid_list;
- int cpu;
+ bool task_filters_enabled;
pid_list = rcu_dereference_protected(tr->function_pids,
lockdep_is_held(&ftrace_lock));
@@ -8718,12 +8748,7 @@ static void clear_ftrace_pids(struct trace_array *tr, int type)
if (!pid_type_enabled(type, pid_list, no_pid_list))
return;
- /* See if the pids still need to be checked after this */
- if (!still_need_pid_events(type, pid_list, no_pid_list)) {
- unregister_trace_sched_switch(ftrace_filter_task_sched_switch_probe, tr);
- for_each_possible_cpu(cpu)
- per_cpu_ptr(tr->array_buffer.data, cpu)->ftrace_ignore_pid = FTRACE_PID_TRACE;
- }
+ task_filters_enabled = ftrace_task_filters_active(tr);
if (type & TRACE_PIDS)
rcu_assign_pointer(tr->function_pids, NULL);
@@ -8731,6 +8756,8 @@ static void clear_ftrace_pids(struct trace_array *tr, int type)
if (type & TRACE_NO_PIDS)
rcu_assign_pointer(tr->function_no_pids, NULL);
+ ftrace_task_filters_changed(tr, task_filters_enabled);
+
/* Wait till all users are no longer using pid filtering */
synchronize_rcu();
@@ -8935,27 +8962,24 @@ pid_write(struct file *filp, const char __user *ubuf,
struct seq_file *m = filp->private_data;
struct trace_array *tr = m->private;
struct trace_pid_list *filtered_pids;
- struct trace_pid_list *other_pids;
struct trace_pid_list *pid_list;
+ bool task_filters_enabled;
ssize_t ret;
if (!cnt)
return 0;
guard(mutex)(&ftrace_lock);
+ task_filters_enabled = ftrace_task_filters_active(tr);
switch (type) {
case TRACE_PIDS:
filtered_pids = rcu_dereference_protected(tr->function_pids,
lockdep_is_held(&ftrace_lock));
- other_pids = rcu_dereference_protected(tr->function_no_pids,
- lockdep_is_held(&ftrace_lock));
break;
case TRACE_NO_PIDS:
filtered_pids = rcu_dereference_protected(tr->function_no_pids,
lockdep_is_held(&ftrace_lock));
- other_pids = rcu_dereference_protected(tr->function_pids,
- lockdep_is_held(&ftrace_lock));
break;
default:
WARN_ON_ONCE(1);
@@ -8979,17 +9003,9 @@ pid_write(struct file *filp, const char __user *ubuf,
if (filtered_pids) {
synchronize_rcu();
trace_pid_list_free(filtered_pids);
- } else if (pid_list && !other_pids) {
- /* Register a probe to set whether to ignore the tracing of a task */
- register_trace_sched_switch(ftrace_filter_task_sched_switch_probe, tr);
}
- /*
- * Ignoring of pids is done at task switch. But we have to
- * check for those tasks that are currently running.
- * Always do this in case a pid was appended or removed.
- */
- on_each_cpu(ignore_task_cpu, tr, 1);
+ ftrace_task_filters_changed(tr, task_filters_enabled);
ftrace_update_pid_func();
ftrace_startup_all(0);
--
2.25.1