FAILED: patch "[PATCH] locking/rtmutex: Skip remove_waiter() when waiter is not" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 40a25d59e85b3c8709ac2424d44f65610467871e
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026061513-dating-gaining-4f76@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 40a25d59e85b3c8709ac2424d44f65610467871e Mon Sep 17 00:00:00 2001
From: Davidlohr Bueso <[email protected]>
Date: Thu, 7 May 2026 04:29:13 -0700
Subject: [PATCH] locking/rtmutex: Skip remove_waiter() when waiter is not
enqueued
syzbot triggered the following splat in remove_waiter() via FUTEX_CMP_REQUEUE_PI:
KASAN: null-ptr-deref in range [0x0000000000000a88-0x0000000000000a8f] class_raw_spinlock_constructor remove_waiter+0x159/0x1200 kernel/locking/rtmutex.c:1561 rt_mutex_start_proxy_lock+0x103/0x120 futex_requeue+0x10e4/0x20d0 __x64_sys_futex+0x34f/0x4d0
task_blocks_on_rt_mutex() does not arm the waiter upon deadlock detection, leaving waiter->task nil, where 3bfdc63936dd ("rtmutex: Use waiter::task instead of current in remove_waiter()") made this fatal.
Furthermore, rt_mutex_start_proxy_lock() should not be calling into remove_waiter() upon a successfully grabbing the rtmutex. 1a1fb985f2e2 ("futex: Handle early deadlock return correctly"), moved the remove_waiter() out of __rt_mutex_start_proxy_lock() (where 'ret' was only ever 0 or < 0) into the wrapper. Tighten this check to account for try_to_take_rt_mutex().
kernel/locking/rtmutex.c +3 -0
@@ -1558,6 +1558,9 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,lockdep_assert_held (&lock->wait_lock); +if (!waiter_task)/* never enqueued */ +return ; + scoped_guard(raw_spinlock, &waiter_task->pi_lock) {rt_mutex_dequeue (lock, waiter); waiter_task->pi_blocked_on =NULL ;
kernel/locking/rtmutex_api.c +1 -1
@@ -365,7 +365,7 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,raw_spin_lock_irq (&lock->wait_lock); ret =__rt_mutex_start_proxy_lock (lock, waiter, task, &wake_q); -if (unlikely (ret)) +if (unlikely (ret <0 ))remove_waiter (lock, waiter);preempt_disable ();raw_spin_unlock_irq (&lock->wait_lock);
Sasha Levin
maintainerPATCH 1/2 locking/mutex: Remove wakeups from under mutex::wait_lock
From: Peter Zijlstra <[email protected]>
[ Upstream commit 894d1b3db41cf7e6ae0304429a1747b3c3f390bc ]
In preparation to nest mutex::wait_lock under rq::lock we need to remove wakeups from under it.
Do this by utilizing wake_qs to defer the wakeup until after the lock is dropped.
[Heavily changed after 55f036ca7e74 ("locking: WW mutex cleanup") and 08295b3b5bee ("locking: Implement an algorithm choice for Wound-Wait mutexes")]
[jstultz: rebased to mainline, added extra wake_up_q & init
to avoid hangs, similar to Connor's rework of this patch]
Stable-dep-of: 40a25d59e85b ("locking/rtmutex: Skip remove_waiter() when waiter is not enqueued")
--- kernel/futex/pi.c | 6 +++- kernel/locking/mutex.c | 16 ++++++++--- kernel/locking/rtmutex.c | 51 ++++++++++++++++++++++++--------- kernel/locking/rtmutex_api.c | 12 ++++++-- kernel/locking/rtmutex_common.h | 3 +- kernel/locking/rwbase_rt.c | 8 +++++- kernel/locking/rwsem.c | 4 +-- kernel/locking/spinlock_rt.c | 5 ++-- kernel/locking/ww_mutex.h | 30 ++++++++++++------- 9 files changed, 96 insertions(+), 39 deletions(-)
kernel/futex/pi.c +5 -1
@@ -922,6 +922,7 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylstruct rt_mutex_waiter rt_waiter;struct futex_hash_bucket *hb;struct futex_q q = futex_q_init; +DEFINE_WAKE_Q (wake_q);int res, ret;if (!IS_ENABLED (CONFIG_FUTEX_PI ))
@@ -1019,8 +1020,11 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl* such that futex_unlock_pi() is guaranteed to observe the waiter when * it sees the futex_q::pi_state. */ - ret =__rt_mutex_start_proxy_lock (&q.pi_state->pi_mutex, &rt_waiter, current); + ret =__rt_mutex_start_proxy_lock (&q.pi_state->pi_mutex, &rt_waiter, current, &wake_q); +preempt_disable ();raw_spin_unlock_irq (&q.pi_state->pi_mutex.wait_lock); +wake_up_q (&wake_q); +preempt_enable ();if (ret) {if (ret ==1 )
kernel/locking/mutex.c +12 -4
@@ -575,6 +575,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas struct lockdep_map *nest_lock, unsigned long ip, struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) { +DEFINE_WAKE_Q (wake_q );struct mutex_waiter waiter;struct ww_mutex *ww;int ret;
@@ -625,7 +626,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas*/ if (__mutex_trylock (lock)) {if (ww_ctx) -__ww_mutex_check_waiters (lock, ww_ctx); +__ww_mutex_check_waiters (lock, ww_ctx, &wake_q); goto skip_wait; }
@@ -645,7 +646,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas* Add in stamp order, waking up waiters that must kill * themselves. */ - ret =__ww_mutex_add_waiter (&waiter, lock, ww_ctx); + ret =__ww_mutex_add_waiter (&waiter, lock, ww_ctx, &wake_q);if (ret) goto err_early_kill; }
@@ -681,6 +682,10 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas }raw_spin_unlock (&lock->wait_lock); +/* Make sure we do wakeups before calling schedule */ +wake_up_q (&wake_q); +wake_q_init (&wake_q); +schedule_preempt_disabled (); first =__mutex_waiter_is_first (lock, &waiter);
@@ -714,7 +719,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas*/ if (!ww_ctx->is_wait_die && !__mutex_waiter_is_first (lock, &waiter)) -__ww_mutex_check_waiters (lock, ww_ctx); +__ww_mutex_check_waiters (lock, ww_ctx, &wake_q); }__mutex_remove_waiter (lock, &waiter);
@@ -730,6 +735,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasww_mutex_lock_acquired (ww, ww_ctx);raw_spin_unlock (&lock->wait_lock); +wake_up_q (&wake_q);preempt_enable ();return 0 ;
@@ -741,6 +747,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasraw_spin_unlock (&lock->wait_lock);debug_mutex_free_waiter (&waiter);mutex_release (&lock->dep_map, ip); +wake_up_q (&wake_q);preempt_enable ();return ret; }
@@ -951,9 +958,10 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigneif (owner &MUTEX_FLAG_HANDOFF )__mutex_handoff (lock, next); +preempt_disable ();raw_spin_unlock (&lock->wait_lock); -wake_up_q (&wake_q); +preempt_enable (); }#ifndef CONFIG_DEBUG_LOCK_ALLOC
kernel/locking/rtmutex.c +37 -14
157 lines not on this page · raw message
kernel/locking/rtmutex_api.c +9 -3
@@ -275,6 +275,7 @@ void __sched rt_mutex_proxy_unlock(struct rt_mutex_base *lock)* @lock: the rt_mutex to take * @waiter: the pre-initialized rt_mutex_waiter * @task: the task to prepare +* @wake_q: the wake_q to wake tasks after we release the wait_lock * * Starts the rt_mutex acquire; it enqueues the @waiter and does deadlock * detection. It does not wait, see rt_mutex_wait_proxy_lock() for that.
@@ -291,7 +292,8 @@ void __sched rt_mutex_proxy_unlock(struct rt_mutex_base *lock)*/ int __sched __rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,struct rt_mutex_waiter *waiter, -struct task_struct *task) +struct task_struct *task, +struct wake_q_head *wake_q) {int ret;
@@ -302,7 +304,7 @@ int __sched __rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,/* We enforce deadlock detection for futexes */ ret =task_blocks_on_rt_mutex (lock, waiter, task,NULL , -RT_MUTEX_FULL_CHAINWALK ); +RT_MUTEX_FULL_CHAINWALK , wake_q);if (ret && !rt_mutex_owner (lock)) {/*
@@ -341,12 +343,16 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock, struct task_struct *task) {int ret; +DEFINE_WAKE_Q (wake_q);raw_spin_lock_irq (&lock->wait_lock); - ret =__rt_mutex_start_proxy_lock (lock, waiter, task); + ret =__rt_mutex_start_proxy_lock (lock, waiter, task, &wake_q);if (unlikely (ret))remove_waiter (lock, waiter); +preempt_disable ();raw_spin_unlock_irq (&lock->wait_lock); +wake_up_q (&wake_q); +preempt_enable ();return ret; }
kernel/locking/rtmutex_common.h +2 -1
@@ -83,7 +83,8 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex_base *lock,extern void rt_mutex_proxy_unlock (struct rt_mutex_base *lock);extern int __rt_mutex_start_proxy_lock (struct rt_mutex_base *lock,struct rt_mutex_waiter *waiter, -struct task_struct *task); +struct task_struct *task, +struct wake_q_head *);extern int rt_mutex_start_proxy_lock (struct rt_mutex_base *lock,struct rt_mutex_waiter *waiter,struct task_struct *task);
kernel/locking/rwbase_rt.c +7 -1
@@ -69,6 +69,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, unsigned int state) {struct rt_mutex_base *rtm = &rwb->rtmutex; +DEFINE_WAKE_Q (wake_q);int ret;rwbase_pre_schedule ();
@@ -110,7 +111,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,* For rwlocks this returns 0 unconditionally, so the below * !ret conditionals are optimized out. */ - ret =rwbase_rtmutex_slowlock_locked (rtm, state); + ret =rwbase_rtmutex_slowlock_locked (rtm, state, &wake_q);/* * On success the rtmutex is held, so there can't be a writer
@@ -121,7 +122,12 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,*/ if (!ret)atomic_inc (&rwb->readers); + +preempt_disable ();raw_spin_unlock_irq (&rtm->wait_lock); +wake_up_q (&wake_q); +preempt_enable (); +if (!ret)rwbase_rtmutex_unlock (rtm);
kernel/locking/rwsem.c +2 -2
@@ -1413,8 +1413,8 @@ static inline void __downgrade_write(struct rw_semaphore *sem)#define rwbase_rtmutex_lock_state (rtm, state) \ __rt_mutex_lock(rtm, state) -#define rwbase_rtmutex_slowlock_locked (rtm, state) \ - __rt_mutex_slowlock_locked(rtm, NULL, state) +#define rwbase_rtmutex_slowlock_locked (rtm, state, wq) \ + __rt_mutex_slowlock_locked(rtm, NULL, state, wq)#define rwbase_rtmutex_unlock (rtm) \ __rt_mutex_unlock(rtm)
kernel/locking/spinlock_rt.c +3 -2
@@ -162,9 +162,10 @@ rwbase_rtmutex_lock_state(struct rt_mutex_base *rtm, unsigned int state) } static __always_inline int -rwbase_rtmutex_slowlock_locked (struct rt_mutex_base *rtm,unsigned int state) +rwbase_rtmutex_slowlock_locked (struct rt_mutex_base *rtm,unsigned int state, +struct wake_q_head *wake_q) { -rtlock_slowlock_locked (rtm); +rtlock_slowlock_locked (rtm, wake_q);return 0 ; }
kernel/locking/ww_mutex.h +19 -11
@@ -275,7 +275,7 @@ __ww_ctx_less(struct ww_acquire_ctx *a, struct ww_acquire_ctx *b)*/ static bool __ww_mutex_die (struct MUTEX *lock,struct MUTEX_WAITER *waiter, -struct ww_acquire_ctx *ww_ctx) +struct ww_acquire_ctx *ww_ctx,struct wake_q_head *wake_q) {if (!ww_ctx->is_wait_die)return false;
@@ -284,7 +284,7 @@ __ww_mutex_die(struct MUTEX *lock, struct MUTEX_WAITER *waiter,#ifndef WW_RT debug_mutex_wake_waiter (lock, waiter);#endif -wake_up_process (waiter->task); +wake_q_add (wake_q, waiter->task); }return true;
@@ -299,7 +299,8 @@ __ww_mutex_die(struct MUTEX *lock, struct MUTEX_WAITER *waiter,*/ static bool __ww_mutex_wound (struct MUTEX *lock,struct ww_acquire_ctx *ww_ctx, -struct ww_acquire_ctx *hold_ctx) +struct ww_acquire_ctx *hold_ctx, +struct wake_q_head *wake_q) {struct task_struct *owner =__ww_mutex_owner (lock);
@@ -331,7 +332,7 @@ static bool __ww_mutex_wound(struct MUTEX *lock,* wakeup pending to re-read the wounded state. */ if (owner != current) -wake_up_process (owner); +wake_q_add (wake_q, owner);return true; }
@@ -352,7 +353,8 @@ static bool __ww_mutex_wound(struct MUTEX *lock,* The current task must not be on the wait list. */ static void -__ww_mutex_check_waiters (struct MUTEX *lock,struct ww_acquire_ctx *ww_ctx) +__ww_mutex_check_waiters (struct MUTEX *lock,struct ww_acquire_ctx *ww_ctx, +struct wake_q_head *wake_q) {struct MUTEX_WAITER *cur;
@@ -364,8 +366,8 @@ __ww_mutex_check_waiters(struct MUTEX *lock, struct ww_acquire_ctx *ww_ctx)if (!cur->ww_ctx)continue ; -if (__ww_mutex_die (lock, cur, ww_ctx) || -__ww_mutex_wound (lock, cur->ww_ctx, ww_ctx)) +if (__ww_mutex_die (lock, cur, ww_ctx, wake_q) || +__ww_mutex_wound (lock, cur->ww_ctx, ww_ctx, wake_q))break ; } }
@@ -377,6 +379,8 @@ __ww_mutex_check_waiters(struct MUTEX *lock, struct ww_acquire_ctx *ww_ctx) static __always_inline voidww_mutex_set_context_fastpath (struct ww_mutex *lock,struct ww_acquire_ctx *ctx) { +DEFINE_WAKE_Q (wake_q); +ww_mutex_lock_acquired (lock, ctx);/*
@@ -405,8 +409,11 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)* die or wound us. */ lock_wait_lock (&lock->base); -__ww_mutex_check_waiters (&lock->base, ctx); +__ww_mutex_check_waiters (&lock->base, ctx, &wake_q); +preempt_disable ();unlock_wait_lock (&lock->base); +wake_up_q (&wake_q); +preempt_enable (); }static __always_inline int
@@ -488,7 +495,8 @@ __ww_mutex_check_kill(struct MUTEX *lock, struct MUTEX_WAITER *waiter,static inline int __ww_mutex_add_waiter (struct MUTEX_WAITER *waiter,struct MUTEX *lock, -struct ww_acquire_ctx *ww_ctx) +struct ww_acquire_ctx *ww_ctx, +struct wake_q_head *wake_q) {struct MUTEX_WAITER *cur, *pos =NULL ;bool is_wait_die;
@@ -532,7 +540,7 @@ __ww_mutex_add_waiter(struct MUTEX_WAITER *waiter, pos = cur;/* Wait-Die: ensure younger waiters die. */ -__ww_mutex_die (lock, cur, ww_ctx); +__ww_mutex_die (lock, cur, ww_ctx, wake_q); }__ww_waiter_add (lock, waiter, pos);
@@ -550,7 +558,7 @@ __ww_mutex_add_waiter(struct MUTEX_WAITER *waiter,* such that either we or the fastpath will wound @ww->ctx. */ smp_mb (); -__ww_mutex_wound (lock, ww_ctx, ww->ctx); +__ww_mutex_wound (lock, ww_ctx, ww->ctx, wake_q); }return 0 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 locking/rtmutex: Skip remove_waiter() when waiter is not enqueued
From: Davidlohr Bueso <[email protected]>
[ Upstream commit 40a25d59e85b3c8709ac2424d44f65610467871e ]
syzbot triggered the following splat in remove_waiter() via FUTEX_CMP_REQUEUE_PI:
KASAN: null-ptr-deref in range [0x0000000000000a88-0x0000000000000a8f] class_raw_spinlock_constructor remove_waiter+0x159/0x1200 kernel/locking/rtmutex.c:1561 rt_mutex_start_proxy_lock+0x103/0x120 futex_requeue+0x10e4/0x20d0 __x64_sys_futex+0x34f/0x4d0
task_blocks_on_rt_mutex() does not arm the waiter upon deadlock detection, leaving waiter->task nil, where 3bfdc63936dd ("rtmutex: Use waiter::task instead of current in remove_waiter()") made this fatal.
Furthermore, rt_mutex_start_proxy_lock() should not be calling into remove_waiter() upon a successfully grabbing the rtmutex. 1a1fb985f2e2 ("futex: Handle early deadlock return correctly"), moved the remove_waiter() out of __rt_mutex_start_proxy_lock() (where 'ret' was only ever 0 or < 0) into the wrapper. Tighten this check to account for try_to_take_rt_mutex().
--- kernel/locking/rtmutex.c | 3 +++ kernel/locking/rtmutex_api.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-)
kernel/locking/rtmutex.c +3 -0
@@ -1550,6 +1550,9 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,lockdep_assert_held (&lock->wait_lock); +if (!waiter_task)/* never enqueued */ +return ; + scoped_guard(raw_spinlock, &waiter_task->pi_lock) {rt_mutex_dequeue (lock, waiter); waiter_task->pi_blocked_on =NULL ;
kernel/locking/rtmutex_api.c +1 -1
@@ -347,7 +347,7 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,raw_spin_lock_irq (&lock->wait_lock); ret =__rt_mutex_start_proxy_lock (lock, waiter, task, &wake_q); -if (unlikely (ret)) +if (unlikely (ret <0 ))remove_waiter (lock, waiter);preempt_disable ();raw_spin_unlock_irq (&lock->wait_lock);
Signature · 1 line
2.53.0