mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: K Prateek Nayak <kprateek.nayak@amd.com>
To: Peter Zijlstra <peterz@infradead.org>, John Stultz <jstultz@google.com>
Cc: LKML <linux-kernel@vger.kernel.org>,
	Juri Lelli <juri.lelli@redhat.com>,
	Valentin Schneider <valentin.schneider@arm.com>,
	Connor O'Brien <connoro@google.com>,
	Joel Fernandes <joelagnelf@nvidia.com>,
	Qais Yousef <qyousef@layalina.io>, Ingo Molnar <mingo@redhat.com>,
	Vincent Guittot <vincent.guittot@linaro.org>,
	Dietmar Eggemann <dietmar.eggemann@arm.com>,
	Valentin Schneider <vschneid@redhat.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Ben Segall <bsegall@google.com>,
	Zimuzo Ezeozue <zezeozue@google.com>,
	Will Deacon <will@kernel.org>, Waiman Long <longman@redhat.com>,
	Boqun Feng <boqun.feng@gmail.com>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	Metin Kaya <Metin.Kaya@arm.com>,
	Xuewen Yan <xuewen.yan94@gmail.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	"Daniel Lezcano" <daniel.lezcano@linaro.org>,
	Suleiman Souhlal <suleiman@google.com>,
	kuyo chang <kuyo.chang@mediatek.com>, hupu <hupu.gm@gmail.com>,
	<kernel-team@android.com>
Subject: Re: [PATCH v29 7/9] sched: Add blocked_donor link to task for smarter mutex handoffs
Date: Tue, 19 May 2026 21:16:58 +0530	[thread overview]
Message-ID: <d77aba2e-d9e5-469b-ae50-9984ad07d503@amd.com> (raw)
In-Reply-To: <20260519143238.GB2934902@noisy.programming.kicks-ass.net>

Hello Peter,

On 5/19/2026 8:02 PM, Peter Zijlstra wrote:
> This then brings us to the consumer side of things:
> 
>> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
>> index 09534628dc01a..0064b724ccda3 100644
>> --- a/kernel/locking/mutex.c
>> +++ b/kernel/locking/mutex.c
>> @@ -980,7 +980,7 @@ EXPORT_SYMBOL_GPL(ww_mutex_lock_interruptible);
>>  static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigned long ip)
>>  	__releases(lock)
>>  {
>> -	struct task_struct *next = NULL;
>> +	struct task_struct *donor, *next = NULL;
>>  	struct mutex_waiter *waiter;
>>  	DEFINE_WAKE_Q(wake_q);
>>  	unsigned long owner;
>> @@ -1001,6 +1001,12 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne
>>  		MUTEX_WARN_ON(__owner_task(owner) != current);
>>  		MUTEX_WARN_ON(owner & MUTEX_FLAG_PICKUP);
>>  
>> +		if (sched_proxy_exec() && current->blocked_donor) {
>> +			/* force handoff if we have a blocked_donor */
>> +			owner = MUTEX_FLAG_HANDOFF;
>> +			break;
>> +		}
>> +
>>  		if (owner & MUTEX_FLAG_HANDOFF)
>>  			break;
>>  
> 
> AFAICT this is racy since we don't have preemption disabled.
> 
> So we can observe ->blocked_donor (A) set, or (B) unset.
> If (A) we can schedule() right after this (and before taking
> ->wait_lock) and it can be unset when we resume running this task. Or
> (B), the exact opposite.
> 
> Now, (A) is harmless, because if ->blocked_donor becomes NULL, the
> hand off code falls back to picking the first on the wait list and
> things just get on.
> 
> *However*, (B) might be a problem, because then we will not have the
> HANDOFF bit set even though there is in fact a donor we need to hand off
> to.

I don't think it is that big of a problem: __mutex_unlock_slowpath()
sees current->blocked_donor as NULL but just before it can do:

    atomic_long_try_cmpxchg_release(&lock->owner, &owner, __owner_flags(owner))

it is preempted and comes back with a ->blocked_donor.

Once we grab the wait_lock, we realize there is a ->blocked_donor link
and we wake it up instead of first waiter which goes and grabs the
lock once it hits mutex_trylock() for !owner case.

If a concurrent mutex_lock() races with this sequence, the
->blocked_donor that was woken up sees the new owner and goes to proxy
that.

With guard(preempt)(), we see a stable ->blocked_donor as NULL, and we
wake up the first waiter after clearing the "owner" from lock->owner.

If a concurrent mutex_lock() races, it still grabs the mutex and now
it is just the first waiter that realizes it has to go proxy the task
that stole the lock.

One wasted wakeup is incurred in both cases but it seems like no
biggie. Maybe I don't understand the subtleties but stabilizing it
against preemption is definitely a good move since it saves this
debate :-)

> That is, we need this on top, no?
> 
> ---
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1242,8 +1242,14 @@ struct task_struct {
>  #endif
>  
>  	struct mutex			*blocked_on;	/* lock we're blocked on */
> -	struct task_struct		*blocked_donor;	/* task that is boosting this task */
>  	raw_spinlock_t			blocked_lock;
> +	
> +	/*
> +	 * The task that is boosting this task; a back link for the current
> +	 * donor stack. Set in schedule() -> find_proxy_task() and only stable
> +	 * under preempt_disable().
> +	 */
> +	struct task_struct		*blocked_donor;
>  
>  #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
>  	/*
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -990,6 +990,14 @@ static noinline void __sched __mutex_unl
>  	__release(lock);
>  
>  	/*
> +	 * Ensures the proxy donor stack is stable across unlock and handoff.
> +	 * Specifically, it avoids the case where current->blocked_donor is
> +	 * NULL when it is inspected while doing the unlock, but a preemption
> +	 * before taking the wake_lock would make it set and a hand-off is
> +	 * missed.
> +	 */
> +	guard(preempt)();
> +	/*
>  	 * Release the lock before (potentially) taking the spinlock such that
>  	 * other contenders can get on with things ASAP.
>  	 *
> @@ -1063,7 +1071,8 @@ static noinline void __sched __mutex_unl
>  		__mutex_handoff(lock, next);
>  
>  	raw_spin_unlock(&current->blocked_lock);
> -	raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
> +	raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
> +	wake_up_q(&wake_q);

In that case, can't we simplify this to:

    if (next)
        wake_up_process(next);

and save on the wake_q enqueue dequeue overheads?

>  }
>  
>  #ifndef CONFIG_DEBUG_LOCK_ALLOC

-- 
Thanks and Regards,
Prateek


  parent reply	other threads:[~2026-05-19 15:47 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-12  2:56 [PATCH v29 0/9] Optimized Donor Migration for Proxy Execution John Stultz
2026-05-12  2:56 ` [PATCH v29 1/9] sched: Rework pick_next_task() and prev_balance() to avoid stale prev references John Stultz
2026-05-19 10:32   ` Peter Zijlstra
2026-05-20  2:45     ` John Stultz
2026-05-20  9:43       ` Peter Zijlstra
2026-06-04 18:45   ` [tip: sched/core] sched: Rework " tip-bot2 for John Stultz
2026-05-12  2:56 ` [PATCH v29 2/9] sched: deadline: Add some helper variables to cleanup deadline logic John Stultz
2026-06-04 18:45   ` [tip: sched/core] " tip-bot2 for John Stultz
2026-05-12  2:56 ` [PATCH v29 3/9] sched: deadline: Add dl_rq->curr pointer to address issues with Proxy Exec John Stultz
2026-06-04 18:45   ` [tip: sched/core] " tip-bot2 for John Stultz
2026-05-12  2:56 ` [PATCH v29 4/9] sched: Rework block_task so it can be directly called John Stultz
2026-06-04 18:45   ` [tip: sched/core] " tip-bot2 for John Stultz
2026-05-12  2:56 ` [PATCH v29 5/9] sched: Have try_to_wake_up() handle return-migration for PROXY_WAKING case John Stultz
2026-05-22 11:30   ` Peter Zijlstra
2026-05-22 11:35     ` Peter Zijlstra
2026-06-04 18:45   ` [tip: sched/core] " tip-bot2 for John Stultz
2026-05-12  2:56 ` [PATCH v29 6/9] sched: Add is_blocked task flag John Stultz
2026-06-04 18:45   ` [tip: sched/core] " tip-bot2 for John Stultz
2026-05-12  2:56 ` [PATCH v29 7/9] sched: Add blocked_donor link to task for smarter mutex handoffs John Stultz
2026-05-19 14:32   ` Peter Zijlstra
2026-05-19 14:46     ` Peter Zijlstra
2026-05-19 15:46     ` K Prateek Nayak [this message]
2026-05-20 18:10       ` John Stultz
2026-05-22  9:50       ` Peter Zijlstra
2026-05-20 18:09     ` John Stultz
2026-06-04 18:45   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-05-12  2:56 ` [PATCH v29 8/9] sched: Break out core of attach_tasks() helper into sched.h John Stultz
2026-05-12  2:56 ` [PATCH v29 9/9] sched: Migrate whole chain in proxy_migrate_task() John Stultz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d77aba2e-d9e5-469b-ae50-9984ad07d503@amd.com \
    --to=kprateek.nayak@amd.com \
    --cc=Metin.Kaya@arm.com \
    --cc=boqun.feng@gmail.com \
    --cc=bsegall@google.com \
    --cc=connoro@google.com \
    --cc=daniel.lezcano@linaro.org \
    --cc=dietmar.eggemann@arm.com \
    --cc=hupu.gm@gmail.com \
    --cc=joelagnelf@nvidia.com \
    --cc=jstultz@google.com \
    --cc=juri.lelli@redhat.com \
    --cc=kernel-team@android.com \
    --cc=kuyo.chang@mediatek.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=mingo@redhat.com \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=qyousef@layalina.io \
    --cc=rostedt@goodmis.org \
    --cc=suleiman@google.com \
    --cc=tglx@linutronix.de \
    --cc=valentin.schneider@arm.com \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    --cc=will@kernel.org \
    --cc=xuewen.yan94@gmail.com \
    --cc=zezeozue@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome