Re: [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop
From: Rik van Riel
Date: Thu Jul 16 2026 - 22:05:43 EST
On Wed, 2026-07-15 at 21:53 -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().
>
OK, this is more interesting than it looked at first,
and this patch does not look like the right approach,
but I'm also not sure what other approach would work :(
The actual error being thrown is a hung task:
The syzkaller kernel failure is a tragedy in 3 parts.
First, we have perf_event_open() waiting on the event_mutex:
syz.7.35551 (pid 31354, state D): perf_event_open
-> perf_tp_event_init
-> perf_trace_init
-> __mutex_lock
-> blocked on event_mutex.
Second, we have perf_trace_destroy() indirectly
waiting in synchronize_rcu_tasks(), with the
event_mutex held.
syz.5.35491 (state:I) do_exit
-> task_work_run
-> __fput
-> perf_release
-> perf_event_release_kernel
-> __free_event
-> perf_trace_destroy
-> perf_trace_event_close
-> reg(TRACE_REG_PERF_CLOSE)
-> perf_ftrace_event_register
-> perf_ftrace_function_unregister
-> unregister_ftrace_function
-> ftrace_shutdown
-> synchronize_rcu_tasks() <-- BLOCKS HERE, forever,
holding event_mutex
Tasks RCU waits for every task to have gone through
a voluntary reschedule, before the grace period can
be advanced. A preemption does not count.
Third, we have a kworker looping for a very long time:
kworker/0:0 (pid 9, TASK_RUNNING, on CPU0): process_one_work
-> prog_array_map_clear_deferred
-> bpf_fd_array_map_clear
-> __fd_array_map_delete_elem. Looping over a huge PROG_ARRAY
max_entries.
With CONFIG_PREEMPT_LAZY=y this gets preempted,
but since involuntary preemptions do not count
for tasks RCU, that does nothnig to help
ftrace_shutdown() get unstuck.
How do we solve this?
Do we actually need to have cond_resched() points
quiesce the task RCU state when running with lazy
preempt, since those are points where we could
preempt voluntarily?
Do we need to prohibit calling synchronize_rcu_tasks()
while holding a mutex?
Do we need to do something else?
What is the best way forward here?
--
All Rights Reversed.