diff options
author | Peter Zijlstra <peterz@infradead.org> | 2025-04-16 18:29:06 +0200 |
---|---|---|
committer | Peter Zijlstra <peterz@infradead.org> | 2025-05-03 12:02:06 +0200 |
commit | 6c67f8d880c0950215b8e6f8539562ad1971a05a (patch) | |
tree | 0ecfbe1e5ae3666c84d6fd684d149fc4837d200e /kernel/futex | |
parent | 8486d12f558ff9e4e90331e8ef841d84bf3a8c24 (diff) |
futex: Create futex_hash() get/put class
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
Diffstat (limited to 'kernel/futex')
-rw-r--r-- | kernel/futex/core.c | 6 | ||||
-rw-r--r-- | kernel/futex/futex.h | 7 | ||||
-rw-r--r-- | kernel/futex/pi.c | 16 | ||||
-rw-r--r-- | kernel/futex/requeue.c | 10 | ||||
-rw-r--r-- | kernel/futex/waitwake.c | 15 |
5 files changed, 30 insertions, 24 deletions
diff --git a/kernel/futex/core.c b/kernel/futex/core.c index e4cb5ce9785b..56a5653e450c 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -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 diff --git a/kernel/futex/futex.h b/kernel/futex/futex.h index a219903e5208..77d9b3509f75 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> @@ -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 diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c index a56f28fda58d..e52f540e81b6 100644 --- a/kernel/futex/pi.c +++ b/kernel/futex/pi.c @@ -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, @@ -995,6 +994,16 @@ retry_private: } /* + * 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: diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c index 209794cad6f2..992e3ce005c6 100644 --- a/kernel/futex/requeue.c +++ b/kernel/futex/requeue.c @@ -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); diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c index 7dc35be09e43..d52541bcc07e 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 @@ 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); |