[PATCH v2 2/5] locking/rtmutex: Initialize the ww_mutex context of a waiter
From: Mathieu Desnoyers
Date: Sun Nov 08 2026 - 09:14:23 EST
With PREEMPT_RT and CONFIG_DEBUG_RT_MUTEXES, FUTEX_LOCK_PI reports no
deadlock. Two threads that each block on a PI futex the other holds
sleep forever. Without PREEMPT_RT, the second one gets EDEADLK. A chain
deeper than max_lock_depth is also admitted.
With PREEMPT_RT, ww_mutexes are built on rtmutexes. They can create a
cycle in the lock graph legitimately, and the wound/die logic resolves
it. So the PREEMPT_RT chain walk turns deadlock detection off when it
finds a waiter with a ww_mutex context, waiter->ww_ctx. It also drops
the -EDEADLK of a walk that started from such a waiter.
But rt_mutex_init_waiter() does not set waiter->ww_ctx. Only
__rt_mutex_slowlock_locked() sets it. So the waiters of PI futexes and
rtlocks keep the 0x11 poison of CONFIG_DEBUG_RT_MUTEXES. Without that
option, they keep what was on the stack, unless the compiler zeroes it.
The chain walk then takes them for ww_mutex waiters.
The ww_mutex build of the chain walk can also requeue such waiters. On
two of them with equal priority, __waiter_less() would dereference the
poison.
Fix this by clearing waiter->ww_ctx in rt_mutex_init_waiter().
With this patch, the ABBA and the deep chain both get EDEADLK. The
futex_lock_pi_inherit selftest added later in this series found this.
Its deadlock and max_lock_depth cases cover it.
Fixes: 6467822b8cc9 ("locking/rtmutex: Prevent spurious EDEADLK return caused by ww_mutexes")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
---
kernel/locking/rtmutex_common.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/locking/rtmutex_common.h b/kernel/locking/rtmutex_common.h
index c38b7bdea7b3..1f56d40c3e66 100644
--- a/kernel/locking/rtmutex_common.h
+++ b/kernel/locking/rtmutex_common.h
@@ -218,6 +218,7 @@ static inline void rt_mutex_init_waiter(struct rt_mutex_waiter *waiter)
RB_CLEAR_NODE(&waiter->tree.entry);
waiter->wake_state = TASK_NORMAL;
waiter->task = NULL;
+ waiter->ww_ctx = NULL;
}
static inline void rt_mutex_init_rtlock_waiter(struct rt_mutex_waiter *waiter)
--
2.47.3