[PATCH v10 05/21] futex: Create futex_hash() get/put class

From: Sebastian Andrzej Siewior
Date: Wed Mar 12 2025 - 11:18:01 EST


From: Peter Zijlstra <peterz@xxxxxxxxxxxxx>

Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
---
kernel/futex/core.c | 7 +++----
kernel/futex/futex.h | 8 +++++++-
kernel/futex/pi.c | 10 ++++++----
kernel/futex/requeue.c | 10 +++-------
kernel/futex/waitwake.c | 15 +++++----------
5 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index e4cb5ce9785b1..08cf54567aeb6 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -114,7 +114,7 @@ late_initcall(fail_futex_debugfs);
* We hash on the keys returned from get_futex_key (see below) and return the
* corresponding hash bucket in the global hash.
*/
-struct futex_hash_bucket *futex_hash(union futex_key *key)
+struct futex_hash_bucket *__futex_hash(union futex_key *key)
{
u32 hash = jhash2((u32 *)key, offsetof(typeof(*key), both.offset) / 4,
key->both.offset);
@@ -122,6 +122,7 @@ struct futex_hash_bucket *futex_hash(union futex_key *key)
return &futex_queues[hash & futex_hashmask];
}

+void futex_hash_put(struct futex_hash_bucket *hb) { }

/**
* futex_setup_timer - set up the sleeping hrtimer.
@@ -957,9 +958,7 @@ static void exit_pi_state_list(struct task_struct *curr)
pi_state = list_entry(next, struct futex_pi_state, list);
key = pi_state->key;
if (1) {
- struct futex_hash_bucket *hb;
-
- hb = futex_hash(&key);
+ CLASS(hb, hb)(&key);

/*
* We can race against put_pi_state() removing itself from the
diff --git a/kernel/futex/futex.h b/kernel/futex/futex.h
index a219903e52084..eac6de6ed563a 100644
--- a/kernel/futex/futex.h
+++ b/kernel/futex/futex.h
@@ -7,6 +7,7 @@
#include <linux/sched/wake_q.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
+#include <linux/cleanup.h>

#ifdef CONFIG_PREEMPT_RT
#include <linux/rcuwait.h>
@@ -201,7 +202,12 @@ extern struct hrtimer_sleeper *
futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout,
int flags, u64 range_ns);

-extern struct futex_hash_bucket *futex_hash(union futex_key *key);
+extern struct futex_hash_bucket *__futex_hash(union futex_key *key);
+extern void futex_hash_put(struct futex_hash_bucket *hb);
+
+DEFINE_CLASS(hb, struct futex_hash_bucket *,
+ if (_T) futex_hash_put(_T),
+ __futex_hash(key), union futex_key *key);

/**
* futex_match - Check whether two futex keys are equal
diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c
index 62ce5ecaeddd6..4cee9ec5d97d6 100644
--- a/kernel/futex/pi.c
+++ b/kernel/futex/pi.c
@@ -939,9 +939,8 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl

retry_private:
if (1) {
- struct futex_hash_bucket *hb;
+ CLASS(hb, hb)(&q.key);

- hb = futex_hash(&q.key);
futex_q_lock(&q, hb);

ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current,
@@ -1017,6 +1016,10 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
*/
raw_spin_lock_irq(&q.pi_state->pi_mutex.wait_lock);
spin_unlock(q.lock_ptr);
+ /*
+ * Caution; releasing @hb in-scope.
+ */
+ futex_hash_put(no_free_ptr(hb));
/*
* __rt_mutex_start_proxy_lock() unconditionally enqueues the @rt_waiter
* such that futex_unlock_pi() is guaranteed to observe the waiter when
@@ -1119,7 +1122,6 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
{
u32 curval, uval, vpid = task_pid_vnr(current);
union futex_key key = FUTEX_KEY_INIT;
- struct futex_hash_bucket *hb;
struct futex_q *top_waiter;
int ret;

@@ -1139,7 +1141,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
if (ret)
return ret;

- hb = futex_hash(&key);
+ CLASS(hb, hb)(&key);
spin_lock(&hb->lock);
retry_hb:

diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
index 209794cad6f2f..992e3ce005c6f 100644
--- a/kernel/futex/requeue.c
+++ b/kernel/futex/requeue.c
@@ -444,10 +444,8 @@ int futex_requeue(u32 __user *uaddr1, unsigned int flags1,

retry_private:
if (1) {
- struct futex_hash_bucket *hb1, *hb2;
-
- hb1 = futex_hash(&key1);
- hb2 = futex_hash(&key2);
+ CLASS(hb, hb1)(&key1);
+ CLASS(hb, hb2)(&key2);

futex_hb_waiters_inc(hb2);
double_lock_hb(hb1, hb2);
@@ -817,9 +815,7 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
switch (futex_requeue_pi_wakeup_sync(&q)) {
case Q_REQUEUE_PI_IGNORE:
{
- struct futex_hash_bucket *hb;
-
- hb = futex_hash(&q.key);
+ CLASS(hb, hb)(&q.key);
/* The waiter is still on uaddr1 */
spin_lock(&hb->lock);
ret = handle_early_requeue_pi_wakeup(hb, &q, to);
diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c
index 4bf839c85b66c..44034dee7a48c 100644
--- a/kernel/futex/waitwake.c
+++ b/kernel/futex/waitwake.c
@@ -154,7 +154,6 @@ void futex_wake_mark(struct wake_q_head *wake_q, struct futex_q *q)
*/
int futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
{
- struct futex_hash_bucket *hb;
struct futex_q *this, *next;
union futex_key key = FUTEX_KEY_INIT;
DEFINE_WAKE_Q(wake_q);
@@ -170,7 +169,7 @@ int futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
if ((flags & FLAGS_STRICT) && !nr_wake)
return 0;

- hb = futex_hash(&key);
+ CLASS(hb, hb)(&key);

/* Make sure we really have tasks to wakeup */
if (!futex_hb_waiters_pending(hb))
@@ -267,10 +266,8 @@ int futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,

retry_private:
if (1) {
- struct futex_hash_bucket *hb1, *hb2;
-
- hb1 = futex_hash(&key1);
- hb2 = futex_hash(&key2);
+ CLASS(hb, hb1)(&key1);
+ CLASS(hb, hb2)(&key2);

double_lock_hb(hb1, hb2);
op_ret = futex_atomic_op_inuser(op, uaddr2);
@@ -444,9 +441,8 @@ int futex_wait_multiple_setup(struct futex_vector *vs, int count, int *woken)
u32 val = vs[i].w.val;

if (1) {
- struct futex_hash_bucket *hb;
+ CLASS(hb, hb)(&q->key);

- hb = futex_hash(&q->key);
futex_q_lock(q, hb);
ret = futex_get_value_locked(&uval, uaddr);

@@ -618,9 +614,8 @@ int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,

retry_private:
if (1) {
- struct futex_hash_bucket *hb;
+ CLASS(hb, hb)(&q->key);

- hb = futex_hash(&q->key);
futex_q_lock(q, hb);

ret = futex_get_value_locked(&uval, uaddr);
--
2.47.2