Re: [PATCH 1/2] futex/requeue: Fix rtmutex schedule preparation for requeue PI

From: Yao Kai

Date: Mon Jul 20 2026 - 21:52:18 EST




On 7/20/2026 10:58 PM, Sebastian Andrzej Siewior wrote:
On 2026-07-20 10:40:03 [+0800], Yao Kai wrote:
I have a test but it only triggers the warning. The concern about calling
rt_mutex_pre_schedule() after the proxy waiter has been enqueued came from
audit. A generic PREEMPT_RT path could be:

rt_mutex_pre_schedule()
sched_submit_work()
blk_flush_plug()
__blk_flush_plug()
flush_plug_callbacks()
drbd_unplug()
spin_lock_irq()
rtlock_slowlock()
task_blocks_on_rt_mutex()
current->pi_blocked_on = waiter

However, I could not find a path for FUTEX_WAIT_REQUEUE_PI to enter with a
live current->plug or worker flags, so this recursion is not reachable from
this syscall.

So the suggestion is okay then?



Yes.

what about the following? This might compile but lacks all kind of testing.

diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
index 79823ad136830..42a04e6e774c4 100644
--- a/kernel/futex/requeue.c
+++ b/kernel/futex/requeue.c
@@ -865,7 +865,9 @@ 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.

This also fixes the warning in my test. I would keep rt_mutex_post_schedule()
after the proxy waiter cleanup, as futex_lock_pi() does:

But why?


Just to be consistent with the code in futex_lock_pi():

ret = rt_mutex_wait_proxy_lock(&q.pi_state->pi_mutex, to, &rt_waiter);
cleanup:
/*
* If we failed to acquire the lock (deadlock/signal/timeout), we must
* unwind the above, however we canont lock hb->lock because
* rt_mutex already has a waiter enqueued and hb->lock can itself try
* and enqueue an rt_waiter through rtlock.
*
* Doing the cleanup without holding hb->lock can cause inconsistent
* state between hb and pi_state, but only in the direction of not
* seeing a waiter that is leaving.
*
* See futex_unlock_pi(), it deals with this inconsistency.
*
* There be dragons here, since we must deal with the inconsistency on
* the way out (here), it is impossible to detect/warn about the race
* the other way around (missing an incoming waiter).
*
* What could possibly go wrong...
*/
if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter))
ret = 0;
/*
* Now that the rt_waiter has been dequeued, it is safe to use
* spinlock/rtlock (which might enqueue its own rt_waiter) and fix up
* the
*/
futex_q_lockptr_lock(&q);
/*
* Waiter is unqueued.
*/
rt_mutex_post_schedule();


diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
index 79823ad13683..41ffc795d12c 100644
--- a/kernel/futex/requeue.c
+++ b/kernel/futex/requeue.c
@@ -865,6 +865,7 @@ 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);
/*
@@ -875,6 +876,7 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
futex_q_lockptr_lock(&q);
debug_rt_mutex_free_waiter(&rt_waiter);
+ rt_mutex_post_schedule();

But there is futex_q_lockptr_lock() from what I see in the context. This
one should trigger the warning if it is done as you suggest.


I don't think it would trigger the warning. At this point rt_mutex_wait_proxy_lock()
or rt_mutex_cleanup_proxy_lock() has cleared current->pi_blocked_on.

/*
* Fixup the pi_state owner and possibly acquire the lock if we
* haven't already.

Thanks,
Yao

Sebastian