Skip to content

Commit 93f1b6d

Browse files
author
Peter Zijlstra
committed
futex: Move futex_queue() into futex_wait_setup()
futex_wait_setup() has a weird calling convention in order to return hb to use as an argument to futex_queue(). Mostly such that requeue can have an extra test in between. Reorder code a little to get rid of this and keep the hb usage inside futex_wait_setup(). [bigeasy: fixes] Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 55284f7 commit 93f1b6d

File tree

4 files changed

+42
-43
lines changed

4 files changed

+42
-43
lines changed

io_uring/futex.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
273273
struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
274274
struct io_ring_ctx *ctx = req->ctx;
275275
struct io_futex_data *ifd = NULL;
276-
struct futex_hash_bucket *hb;
277276
int ret;
278277

279278
if (!iof->futex_mask) {
@@ -295,12 +294,11 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
295294
ifd->req = req;
296295

297296
ret = futex_wait_setup(iof->uaddr, iof->futex_val, iof->futex_flags,
298-
&ifd->q, &hb);
297+
&ifd->q, NULL, NULL);
299298
if (!ret) {
300299
hlist_add_head(&req->hash_node, &ctx->futex_list);
301300
io_ring_submit_unlock(ctx, issue_flags);
302301

303-
futex_queue(&ifd->q, hb, NULL);
304302
return IOU_ISSUE_SKIP_COMPLETE;
305303
}
306304

kernel/futex/futex.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,9 @@ static inline int futex_match(union futex_key *key1, union futex_key *key2)
219219
}
220220

221221
extern int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
222-
struct futex_q *q, struct futex_hash_bucket **hb);
223-
extern void futex_wait_queue(struct futex_hash_bucket *hb, struct futex_q *q,
224-
struct hrtimer_sleeper *timeout);
222+
struct futex_q *q, union futex_key *key2,
223+
struct task_struct *task);
224+
extern void futex_do_wait(struct futex_q *q, struct hrtimer_sleeper *timeout);
225225
extern bool __futex_wake_mark(struct futex_q *q);
226226
extern void futex_wake_mark(struct wake_q_head *wake_q, struct futex_q *q);
227227

kernel/futex/requeue.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,6 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
769769
{
770770
struct hrtimer_sleeper timeout, *to;
771771
struct rt_mutex_waiter rt_waiter;
772-
struct futex_hash_bucket *hb;
773772
union futex_key key2 = FUTEX_KEY_INIT;
774773
struct futex_q q = futex_q_init;
775774
struct rt_mutex_base *pi_mutex;
@@ -805,29 +804,24 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
805804
* Prepare to wait on uaddr. On success, it holds hb->lock and q
806805
* is initialized.
807806
*/
808-
ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
807+
ret = futex_wait_setup(uaddr, val, flags, &q, &key2, current);
809808
if (ret)
810809
goto out;
811810

812-
/*
813-
* The check above which compares uaddrs is not sufficient for
814-
* shared futexes. We need to compare the keys:
815-
*/
816-
if (futex_match(&q.key, &key2)) {
817-
futex_q_unlock(hb);
818-
ret = -EINVAL;
819-
goto out;
820-
}
821-
822811
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
823-
futex_wait_queue(hb, &q, to);
812+
futex_do_wait(&q, to);
824813

825814
switch (futex_requeue_pi_wakeup_sync(&q)) {
826815
case Q_REQUEUE_PI_IGNORE:
827-
/* The waiter is still on uaddr1 */
828-
spin_lock(&hb->lock);
829-
ret = handle_early_requeue_pi_wakeup(hb, &q, to);
830-
spin_unlock(&hb->lock);
816+
{
817+
struct futex_hash_bucket *hb;
818+
819+
hb = futex_hash(&q.key);
820+
/* The waiter is still on uaddr1 */
821+
spin_lock(&hb->lock);
822+
ret = handle_early_requeue_pi_wakeup(hb, &q, to);
823+
spin_unlock(&hb->lock);
824+
}
831825
break;
832826

833827
case Q_REQUEUE_PI_LOCKED:

kernel/futex/waitwake.c

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -339,18 +339,8 @@ static long futex_wait_restart(struct restart_block *restart);
339339
* @q: the futex_q to queue up on
340340
* @timeout: the prepared hrtimer_sleeper, or null for no timeout
341341
*/
342-
void futex_wait_queue(struct futex_hash_bucket *hb, struct futex_q *q,
343-
struct hrtimer_sleeper *timeout)
342+
void futex_do_wait(struct futex_q *q, struct hrtimer_sleeper *timeout)
344343
{
345-
/*
346-
* The task state is guaranteed to be set before another task can
347-
* wake it. set_current_state() is implemented using smp_store_mb() and
348-
* futex_queue() calls spin_unlock() upon completion, both serializing
349-
* access to the hash list and forcing another memory barrier.
350-
*/
351-
set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
352-
futex_queue(q, hb, current);
353-
354344
/* Arm the timer */
355345
if (timeout)
356346
hrtimer_sleeper_start_expires(timeout, HRTIMER_MODE_ABS);
@@ -578,7 +568,8 @@ int futex_wait_multiple(struct futex_vector *vs, unsigned int count,
578568
* @val: the expected value
579569
* @flags: futex flags (FLAGS_SHARED, etc.)
580570
* @q: the associated futex_q
581-
* @hb: storage for hash_bucket pointer to be returned to caller
571+
* @key2: the second futex_key if used for requeue PI
572+
* task: Task queueing this futex
582573
*
583574
* Setup the futex_q and locate the hash_bucket. Get the futex value and
584575
* compare it with the expected value. Handle atomic faults internally.
@@ -589,8 +580,10 @@ int futex_wait_multiple(struct futex_vector *vs, unsigned int count,
589580
* - <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlocked
590581
*/
591582
int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
592-
struct futex_q *q, struct futex_hash_bucket **hb)
583+
struct futex_q *q, union futex_key *key2,
584+
struct task_struct *task)
593585
{
586+
struct futex_hash_bucket *hb;
594587
u32 uval;
595588
int ret;
596589

@@ -618,12 +611,12 @@ int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
618611
return ret;
619612

620613
retry_private:
621-
*hb = futex_q_lock(q);
614+
hb = futex_q_lock(q);
622615

623616
ret = futex_get_value_locked(&uval, uaddr);
624617

625618
if (ret) {
626-
futex_q_unlock(*hb);
619+
futex_q_unlock(hb);
627620

628621
ret = get_user(uval, uaddr);
629622
if (ret)
@@ -636,18 +629,32 @@ int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
636629
}
637630

638631
if (uval != val) {
639-
futex_q_unlock(*hb);
640-
ret = -EWOULDBLOCK;
632+
futex_q_unlock(hb);
633+
return -EWOULDBLOCK;
641634
}
642635

636+
if (key2 && futex_match(&q->key, key2)) {
637+
futex_q_unlock(hb);
638+
return -EINVAL;
639+
}
640+
641+
/*
642+
* The task state is guaranteed to be set before another task can
643+
* wake it. set_current_state() is implemented using smp_store_mb() and
644+
* futex_queue() calls spin_unlock() upon completion, both serializing
645+
* access to the hash list and forcing another memory barrier.
646+
*/
647+
if (task == current)
648+
set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
649+
futex_queue(q, hb, task);
650+
643651
return ret;
644652
}
645653

646654
int __futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
647655
struct hrtimer_sleeper *to, u32 bitset)
648656
{
649657
struct futex_q q = futex_q_init;
650-
struct futex_hash_bucket *hb;
651658
int ret;
652659

653660
if (!bitset)
@@ -660,12 +667,12 @@ int __futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
660667
* Prepare to wait on uaddr. On success, it holds hb->lock and q
661668
* is initialized.
662669
*/
663-
ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
670+
ret = futex_wait_setup(uaddr, val, flags, &q, NULL, current);
664671
if (ret)
665672
return ret;
666673

667674
/* futex_queue and wait for wakeup, timeout, or a signal. */
668-
futex_wait_queue(hb, &q, to);
675+
futex_do_wait(&q, to);
669676

670677
/* If we were woken (and unqueued), we succeeded, whatever. */
671678
if (!futex_unqueue(&q))

0 commit comments

Comments
 (0)