From 294b3066364fe56bb10b1d306488002306d73b42 Mon Sep 17 00:00:00 2001 From: Jonathan Goyvaerts Date: Tue, 3 Nov 2026 20:19:40 -0300 Subject: [PATCH] sched/fair: Never pick the misfit task as its own rotation partner misfit_rotate_work() checks that p is still on src_cpu, then scans the bigger CPUs' rq->curr without locks. Load balancing can pull the misfit task p onto an idle bigger CPU in between, so the scan can return p itself. migrate_swap(p, p) then runs migrate_swap_stop() on dst_cpu, which takes double_raw_spinlock(&p->pi_lock, &p->pi_lock) with IRQs off and spins forever, while src_cpu spins in multi_cpu_stop(). Seen on m4.120: CPU 5 stopped answering IPIs and the NMI backtrace, RCU stalled, the misfit_rotate_mutex owner sat in stop_two_cpus(), and the desktop froze until a hard reboot. Skip p when scanning for a partner. Fixes: 2d24fbce39a3 ("sched/fair: Rotate misfit tasks with tasks on busy bigger CPUs") Signed-off-by: Jonathan Goyvaerts Assisted-by: LLM --- kernel/sched/fair.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 3b38f35c65413..5c8f84186e2cc 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -15104,7 +15104,11 @@ static void misfit_rotate_work(struct work_struct *work) continue; c = rcu_dereference_all(rq->curr); - if (!misfit_rotate_candidate(c) || + /* + * Balancing may have pulled p here since the check above; + * migrate_swap(p, p) takes p->pi_lock twice in the stopper. + */ + if (c == p || !misfit_rotate_candidate(c) || !cpumask_test_cpu(src_cpu, c->cpus_ptr)) continue;