Re: [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop

From: Paul E. McKenney

Date: Wed Jul 15 2026 - 23:17:29 EST


On Wed, Jul 15, 2026 at 09:53:13PM -0400, Rik van Riel wrote:
> syzkaller creates a PROG_ARRAY with huge max_entries and triggers perf
> tracepoint open close in parallel. The hung task detector reports
> "INFO: task hung in perf_tp_event_init" with event_mutex held waiting
> for synchronize_rcu_tasks().
>
> bpf_fd_array_map_clear walks max_entries under RCU read lock on a
> workqueue kworker. Commit 4406942e65ca added cond_resched for classic
> RCU, but under PREEMPT it is a no-op and a preempted kworker never
> reports RCU-tasks QS. The loop then blocks the grace period while
> event_mutex is held in ftrace_shutdown, stalling perf_event_open().
>
> Use cond_resched_tasks_rcu_qs to report RCU-tasks QS independent of
> preemption model. The grace period completes and event_mutex is
> released normally.
>
> Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps")
> Fixes: 4406942e65ca ("bpf: Fix RCU stall in bpf_fd_array_map_clear()")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Rik van Riel <riel@xxxxxxxxxxx>
> Assisted-by: Claude:claude-opus-4-8
> ---
> QUESTION: should we change cond_resched() instead, so it unblocks RCU
> in any preempt configuration where cond_resched() is a noop?
>
> That would take care of every bug of this shape with one change,
> and rcu_tasks_qs() looks cheap enough?

Just confirming that rcu_tasks_qs() is quite cheap: Check a constant,
check a flag in the task_struct structure, and, if set, set another flag
in this same structure. If there is no RCU Tasks grace period in effect,
the first flag will always be zero.

Thanx, Paul

> kernel/bpf/arraymap.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
> index 248b4818178c..55fd97375130 100644
> --- a/kernel/bpf/arraymap.c
> +++ b/kernel/bpf/arraymap.c
> @@ -1015,7 +1015,8 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer)
>
> for (i = 0; i < array->map.max_entries; i++) {
> __fd_array_map_delete_elem(map, &i, need_defer);
> - cond_resched();
> + /* cond_resched() is a noop with preempt; unblock RCU */
> + cond_resched_tasks_rcu_qs();
> }
> }
>
> --
> 2.53.0-Meta
>
>