Re: [PATCH 0/2] sched: Remove sched_class::balance()

From: Peter Zijlstra

Date: Wed Aug 19 2026 - 03:59:58 EST


On Thu, Jul 02, 2026 at 07:49:19PM +0800, Aaron Lu wrote:

> Assume cpuX and cpuY are siblings, it appears the following happened:
>
> cpuX cpuY
>
> pick_next_task()
> goto restart_multi
>
> rqX->core_pick = pick_task(rqX)
>
> pick_task(rqY)
> pick_task_fair(rqY)
> sched_balance_newidle(rqY)
> raw_spin_rq_unlock(rqY) // drops core lock
>
> pick_next_task()
> goto restart_multi
> rqY->core_pick = pick_task(rqY)
> rqX->core_pick = pick_task(rqX)
>
> if (rqX->curr == rqX->core_pick)
> rqX->core_pick = NULL
>
> UNLOCK rq_lockp(rqY)
>
> raw_spin_rq_lock(rqY)
>
> rqY->core_pick = pick_task(rqY)
>
> p = rqX->core_pick // NULL
> cookie_equals(p, cookie) // NULL deref

Well, damn :/ That's a nice race. So while we did a lock-break, it does
not trigger RETRY_TASK and continues.

The 'easy' fix is taking a local copy of core_task_seq when we increase
it for the pick, and double checking that is still valid at the end and
then restarting if not.

Except that is susceptible to live-locks. It doesn't have forward
progress guarantees. For that we need to limit the amount of
lock-breaks/newidle invocations.

Bah, let me go poke at this for a bit.