[PATCH v3 1/2] futex: Add missing rt_mutex_.*_schedule() around rt_mutex_wait_proxy_lock()

From: Sebastian Andrzej Siewior

Date: Mon Aug 24 2026 - 08:56:36 EST


From: Yao Kai <yaokai34@xxxxxxxxxx>

A waiter requeued onto a PI futex can reach rt_mutex_wait_proxy_lock()
without rtmutex schedule preparation, triggering the lockdep_assert() in
rt_mutex_schedule().
The lack of it, can be seen with requeue PI, multiple waiters and
requeing multiple tasks, the subsequent requeued task can be requeued in
the state Q_REQUEUE_PI_DONE:

waiter requeue task
------ ------------
futex_wait_requeue_pi()
futex_wait_setup()
futex_queue(&q)
futex_requeue()
futex_proxy_trylock_atomic()
futex_requeue_pi_prepare()
Q_REQUEUE_PI_NONE->Q_REQUEUE_PI_IN_PROGRESS

rt_mutex_start_proxy_lock() (ret = 0)
requeue_futex()
futex_do_wait()
futex_requeue_pi_complete()
Q_REQUEUE_PI_IN_PROGRESS -> Q_REQUEUE_PI_DONE
futex_requeue_pi_wakeup_sync()
rt_mutex_wait_proxy_lock()
rt_mutex_schedule() (on contention)

In the Q_REQUEUE_PI_DONE case the waiter will acquire the pi_mutex.
Should the lock be contended, the waiter will invoke rt_mutex_schedule()
without invoking rt_mutex_.*_schedule() before/ after scheduling.

Invoke rt_mutex_pre_schedule() and rt_mutex_post_schedule() directly around
rt_mutex_wait_proxy_lock().

[bigeasy: Redid parts of the changelog, dropped the comment misleading]

Fixes: d14f9e930b90 ("locking/rtmutex: Use rt_mutex specific scheduler helpers")
Suggested-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
Signed-off-by: Yao Kai <yaokai34@xxxxxxxxxx>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
---
kernel/futex/requeue.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
index 79823ad136830..d8c9e7d218695 100644
--- a/kernel/futex/requeue.c
+++ b/kernel/futex/requeue.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include <linux/plist.h>
+#include <linux/sched/rt.h>
#include <linux/sched/signal.h>

#include "futex.h"
@@ -865,7 +866,10 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
case Q_REQUEUE_PI_DONE:
/* Requeue completed. Current is 'pi_blocked_on' the rtmutex */
pi_mutex = &q.pi_state->pi_mutex;
+
+ rt_mutex_pre_schedule();
ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter);
+ rt_mutex_post_schedule();

/*
* See futex_unlock_pi()'s cleanup: comment.
--
2.55.0