Re: [patch 58/63] futex: Prevent requeue_pi() lock nesting issue on RT
From: Peter Zijlstra
Date: Tue Aug 03 2021 - 07:22:31 EST
On Fri, Jul 30, 2021 at 03:51:05PM +0200, Thomas Gleixner wrote:
> @@ -3082,27 +3302,22 @@ static int futex_unlock_pi(u32 __user *u
> }
>
> /**
> - * handle_early_requeue_pi_wakeup() - Detect early wakeup on the initial futex
> + * handle_early_requeue_pi_wakeup() - Handle early wakeup on the initial futex
> * @hb: the hash_bucket futex_q was original enqueued on
> * @q: the futex_q woken while waiting to be requeued
> - * @key2: the futex_key of the requeue target futex
> * @timeout: the timeout associated with the wait (NULL if none)
> *
> - * Detect if the task was woken on the initial futex as opposed to the requeue
> - * target futex. If so, determine if it was a timeout or a signal that caused
> - * the wakeup and return the appropriate error code to the caller. Must be
> - * called with the hb lock held.
> + * Determine the cause for the early wakeup.
> *
> * Return:
> - * - 0 = no early wakeup detected;
> - * - <0 = -ETIMEDOUT or -ERESTARTNOINTR
> + * -EWOULDBLOCK or -ETIMEDOUT or -ERESTARTNOINTR
> */
> static inline
> int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
> - struct futex_q *q, union futex_key *key2,
> + struct futex_q *q,
> struct hrtimer_sleeper *timeout)
> {
> - int ret = 0;
> + int ret;
>
> /*
> * With the hb lock held, we avoid races while we process the wakeup.
> @@ -3111,22 +3326,21 @@ int handle_early_requeue_pi_wakeup(struc
> * It can't be requeued from uaddr2 to something else since we don't
> * support a PI aware source futex for requeue.
> */
> - if (!match_futex(&q->key, key2)) {
> - WARN_ON(q->lock_ptr && (&hb->lock != q->lock_ptr));
> - /*
> - * We were woken prior to requeue by a timeout or a signal.
> - * Unqueue the futex_q and determine which it was.
> - */
> - plist_del(&q->list, &hb->chain);
> - hb_waiters_dec(hb);
> + WARN_ON_ONCE(&hb->lock != q->lock_ptr);
>
> - /* Handle spurious wakeups gracefully */
> - ret = -EWOULDBLOCK;
> - if (timeout && !timeout->task)
> - ret = -ETIMEDOUT;
> - else if (signal_pending(current))
> - ret = -ERESTARTNOINTR;
> - }
> + /*
> + * We were woken prior to requeue by a timeout or a signal.
> + * Unqueue the futex_q and determine which it was.
> + */
> + plist_del(&q->list, &hb->chain);
> + hb_waiters_dec(hb);
> +
> + /* Handle spurious wakeups gracefully */
> + ret = -EWOULDBLOCK;
> + if (timeout && !timeout->task)
> + ret = -ETIMEDOUT;
> + else if (signal_pending(current))
> + ret = -ERESTARTNOINTR;
> return ret;
> }
AFAICT this change is a separate cleanup, possible because the only
callsite already does that match_futex() test before calling this.
I think it might be worth splitting out, just to reduce the complexity
of this patch.