[PATCH] futex/requeue: Fix non-top waiter cleanup on self-deadlock
From: Yao Kai
Date: Mon Jun 29 2026 - 07:22:51 EST
FUTEX_CMP_REQUEUE_PI can hit the explicit non-top waiter
self-deadlock check after the waiter has been prepared for requeue:
INFO: task repro:325 blocked for more than 122 seconds.
Not tainted 7.2.0-rc1 #1
task:repro state:D stack:14432 pid:325 tgid:324 ppid:320 task_flags:0x400040 flags:0x00080800
Call Trace:
<TASK>
__schedule+0x550/0xf10
schedule+0x22/0xa0
futex_wait_requeue_pi+0x37a/0x440
do_futex+0x18d/0x220
__x64_sys_futex+0x8c/0x1d0
do_syscall_64+0xf9/0x530
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Kernel panic - not syncing: hung_task: blocked tasks
The self-deadlock check runs after futex_requeue_pi_prepare() stores the PI
state in the waiter and changes its requeue state to IN_PROGRESS. If the
waiter wakes concurrently, futex_requeue_pi_wakeup_sync() changes the state
to WAIT and waits for the requeue operation to finish. The self-deadlock
path, however, breaks out without dropping the PI state reference or
completing the requeue, so no path can release the waiter.
Handle the early self-deadlock exactly like the later proxy-lock failure:
clear this->pi_state, drop the pi_state reference taken for this waiter and
complete the waiter's requeue state with the error.
Fixes: 74e144274af3 ("futex/requeue: Prevent NULL pointer dereference in remove_waiter() on self-deadlock")
Signed-off-by: Yao Kai <yaokai34@xxxxxxxxxx>
---
kernel/futex/requeue.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
index 7384672916fb..73ca06ec3245 100644
--- a/kernel/futex/requeue.c
+++ b/kernel/futex/requeue.c
@@ -648,6 +648,9 @@ int futex_requeue(u32 __user *uaddr1, unsigned int flags1,
/* Self-deadlock: non-top waiter already owns the PI futex. */
if (rt_mutex_owner(&pi_state->pi_mutex) == this->task) {
ret = -EDEADLK;
+ this->pi_state = NULL;
+ put_pi_state(pi_state);
+ futex_requeue_pi_complete(this, ret);
break;
}
--
2.43.0