[RFC PATCH 09/12] futex: Wake up donor in PING futex unlock.
From: Suleiman Souhlal
Date: Thu Sep 17 2026 - 00:36:20 EST
Now that PING blockers can act as donors, it makes sense to wake up
the donor instead of the top_waiter when unlocking.
Signed-off-by: Suleiman Souhlal <suleiman@xxxxxxxxxx>
---
kernel/futex/ping.c | 56 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 10 deletions(-)
diff --git a/kernel/futex/ping.c b/kernel/futex/ping.c
index 5bf2293bf582..df701b437f16 100644
--- a/kernel/futex/ping.c
+++ b/kernel/futex/ping.c
@@ -478,10 +478,46 @@ int futex_lock_ping(u32 __user *uaddr, unsigned int flags, ktime_t *time,
return ret;
}
+#ifdef CONFIG_SCHED_PROXY_EXEC
+static inline
+struct task_struct *ping_current_proxy_donor(struct futex_pi_state *ping_state)
+{
+ struct task_struct *ret = NULL;
+
+ if (sched_proxy_exec()) {
+ struct task_struct *donor;
+
+ raw_spin_lock(¤t->blocked_lock);
+ donor = current->blocked_donor;
+ if (donor) {
+ void *ping_lock = (void *)&ping_state->ping_mutex;
+
+ raw_spin_lock_nested(&donor->blocked_lock,
+ SINGLE_DEPTH_NESTING);
+ if (__get_task_blocked_on(donor) == ping_lock) {
+ ret = get_task_struct(donor);
+ __clear_task_blocked_on(donor, ping_lock);
+ current->blocked_donor = NULL;
+ }
+ raw_spin_unlock(&donor->blocked_lock);
+ }
+ raw_spin_unlock(¤t->blocked_lock);
+ }
+ return ret;
+}
+#else
+static inline
+struct task_struct *ping_current_proxy_donor(struct futex_pi_state *ping_state)
+{
+ return NULL;
+}
+#endif
+
int futex_unlock_ping(u32 __user *uaddr, unsigned int flags)
{
struct futex_pi_state *ping_state;
u32 new, uval, vpid = task_pid_vnr(current);
+ struct task_struct *next;
union futex_key key = FUTEX_KEY_INIT;
struct futex_q *top_waiter;
DEFINE_WAKE_Q(wake_q);
@@ -528,15 +564,15 @@ int futex_unlock_ping(u32 __user *uaddr, unsigned int flags)
if (!ping_state)
goto out_unlock;
raw_spin_lock_irq(&ping_state->ping_mutex.wait_lock);
- if (ping_state->owner != current) {
- raw_spin_unlock_irq(&ping_state->ping_mutex.wait_lock);
- goto out_unlock;
- }
+
+ next = ping_current_proxy_donor(ping_state);
get_ping_state(ping_state);
/* Leave it queued, it gets unqueued on the lock side */
- get_task_struct(top_waiter->task);
- wake_q_add_safe(&wake_q, top_waiter->task);
- clear_task_blocked_on(top_waiter->task, &ping_state->ping_mutex);
+ if (next == NULL) {
+ next = get_task_struct(top_waiter->task);
+ clear_task_blocked_on(next, &ping_state->ping_mutex);
+ }
+ wake_q_add_safe(&wake_q, next);
spin_unlock(&hb->lock);
/*
@@ -546,10 +582,10 @@ int futex_unlock_ping(u32 __user *uaddr, unsigned int flags)
*/
new = FUTEX_WAITERS;
if (ping_state->handoff) {
- new |= task_pid_vnr(top_waiter->task);
+ new |= task_pid_vnr(next);
ping_state->handoff = 0;
ping_state->pickup = 1;
- WRITE_ONCE(ping_state->ping_mutex.owner, top_waiter->task);
+ WRITE_ONCE(ping_state->ping_mutex.owner, next);
} else
WRITE_ONCE(ping_state->ping_mutex.owner, NULL);
ret = lock_pi_update_atomic(uaddr, uval, new);
@@ -568,7 +604,7 @@ int futex_unlock_ping(u32 __user *uaddr, unsigned int flags)
}
}
- ping_state_update_owner(ping_state, top_waiter->task);
+ ping_state_update_owner(ping_state, next);
raw_spin_unlock_irq_wake(&ping_state->ping_mutex.wait_lock, &wake_q);
put_ping_state(ping_state);
return 0;
--
2.55.0.1082.g2b9226bbc0-goog