]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
futex: Create futex_hash() get/put class
authorPeter Zijlstra <peterz@infradead.org>
Wed, 16 Apr 2025 16:29:06 +0000 (18:29 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Sat, 3 May 2025 10:02:06 +0000 (12:02 +0200)
This gets us:

  hb = futex_hash(key) /* gets hb and inc users */
  futex_hash_get(hb)   /* inc users */
  futex_hash_put(hb)   /* dec users */

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250416162921.513656-7-bigeasy@linutronix.de
kernel/futex/core.c
kernel/futex/futex.h
kernel/futex/pi.c
kernel/futex/requeue.c
kernel/futex/waitwake.c

index e4cb5ce9785b10fcebdb2fc3f1b5b8be60fbdeea..56a5653e450cba5a1764a0d81d02ddb3d0cf65b2 100644 (file)
@@ -122,6 +122,8 @@ struct futex_hash_bucket *futex_hash(union futex_key *key)
        return &futex_queues[hash & futex_hashmask];
 }
 
+void futex_hash_get(struct futex_hash_bucket *hb) { }
+void futex_hash_put(struct futex_hash_bucket *hb) { }
 
 /**
  * futex_setup_timer - set up the sleeping hrtimer.
@@ -957,9 +959,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
index a219903e520848427c33d93a1c925ae12bfbb346..77d9b3509f75ce5c659a86858492a9f9dd0ea489 100644 (file)
@@ -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>
@@ -202,6 +203,12 @@ 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 void futex_hash_get(struct futex_hash_bucket *hb);
+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
index a56f28fda58dd85be27955a61935da941d022e4e..e52f540e81b6ac8589dd40c49ecb40c58dd04056 100644 (file)
@@ -939,9 +939,8 @@ retry:
 
 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,
@@ -994,6 +993,16 @@ retry_private:
                        goto no_block;
                }
 
+               /*
+                * Caution; releasing @hb in-scope. The hb->lock is still locked
+                * while the reference is dropped. The reference can not be dropped
+                * after the unlock because if a user initiated resize is in progress
+                * then we might need to wake him. This can not be done after the
+                * rt_mutex_pre_schedule() invocation. The hb will remain valid because
+                * the thread, performing resize, will block on hb->lock during
+                * the requeue.
+                */
+               futex_hash_put(no_free_ptr(hb));
                /*
                 * Must be done before we enqueue the waiter, here is unfortunately
                 * under the hb lock, but that *should* work because it does nothing.
@@ -1119,7 +1128,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 +1147,7 @@ retry:
        if (ret)
                return ret;
 
-       hb = futex_hash(&key);
+       CLASS(hb, hb)(&key);
        spin_lock(&hb->lock);
 retry_hb:
 
index 209794cad6f2f88c4c1763b9c238b14d7738eb3f..992e3ce005c6f012eeac077457fcd5c05d17b8ac 100644 (file)
@@ -444,10 +444,8 @@ retry:
 
 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);
index 7dc35be09e43638dd4268bb64f0251008b96c2be..d52541bcc07e9498bd04ba6254af3e78a966a75c 100644 (file)
@@ -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 @@ retry:
 
 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 @@ retry:
                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 @@ retry:
 
 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);