Re: [PATCH v33 3/7] sched/core: Activate blocked donor when no owner is found

From: Andrea Righi

Date: Sat Oct 24 2026 - 04:33:53 EST


Hi John and Prateek,

On Fri, Oct 23, 2026 at 10:04:14PM +0000, John Stultz wrote:
> From: K Prateek Nayak <kprateek.nayak@xxxxxxx>
>
> mutex_unlock_slowpath() follows:
>
> if (owner & MUTEX_FLAG_HANDOFF)
> break /* ... and do __mutex_handoff() */
>
> if (atomic_long_try_cmpxchg_release(&lock->owner, &owner, __owner_flags(owner))) {
> if (owner & MUTEX_FLAG_WAITERS)
> break; /* ... and wake up the forst waiter. */
>
> MUTEX_FLAG_HANDOFF is only set by first-waiter after it has been woken
> up and in absence of MUTEX_FLAG_HANDOFF, the owner clears itself from
> the lock_word and wakes up the first waiter to try a
> __mutex_trylock_or_handoff().
>
> MUTEX_FLAG_HANDOFF exists to prevent new optimistic spinners from
> trying to hijack the lock from waiter all the time and potentially
> starving them but it is not necessary for MUTEX_FLAG_HANDOFF to be
> always set in presence of a waiter.
>
> If a blocked donor is deactivated when no owner is observed, it may not
> be woken up until it becomes the first waiter and is naturally woken up
> which breaks proxy in the interim.
>
> Wake up the blocked donor and allow it to grab the lock when no owner is
> observed. If the task manages to grab the lock, the block chain will
> follow at the next proxy migration. If the task fails to grab the lock,
> same situation is restored and everyone migrated to the CPU of new
> owner.
>
> Similarly, do the same for the NULL blocked_on/mutex pointer for
> consistency.
>
> Fixes: f13beb010e4a ("sched: Have try_to_wake_up() handle return-migration for PROXY_WAKING case")
> Signed-off-by: K Prateek Nayak <kprateek.nayak@xxxxxxx>
> Signed-off-by: John Stultz <jstultz@xxxxxxxxxx>
> ---

...

> @@ -7013,11 +7026,11 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf)
> struct mutex *mutex = p->blocked_on;
> if (!mutex) {
> clear_task_blocked_on(p, mutex);
> - if (task_current(rq, p)) {
> + if (task_current(rq, p) || p->wake_cpu == task_cpu(p)) {
> p->is_blocked = 0;
> return p;
> }
> - goto deactivate;
> + goto activate;
> }

IIUC, p here isn't necessarily the donor, after the first iteration it
can be an intermediate owner that is queued on this rq and blocked
itself. If its blocked_on was cleared by a handoff (or its mutex has no
owner, below), we now return it when p->wake_cpu == task_cpu(p),
skipping the sched_cpu_cookie_match() check at the end of the function.

So with CONFIG_SCHED_CORE enabled, are we running a task that was never
cookie-checked by the core-wide pick?

>
> /*
> @@ -7046,14 +7059,15 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf)
> /*
> * If there is no owner, either clear blocked_on
> * and return p (if it is current and safe to
> - * just run on this rq), or return-migrate the task.
> + * just run on this rq), or wake the task to try
> + * and grab the lock it is blocked on.
> */
> __clear_task_blocked_on(p, NULL);
> - if (task_current(rq, p)) {
> + if (task_current(rq, p) || p->wake_cpu == task_cpu(p)) {
> p->is_blocked = 0;
> return p;
> }
> - goto deactivate;
> + goto activate;
> }

Same here.

Thanks,
-Andrea