|
@@ -1186,22 +1186,6 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
|
|
|
|
-{
|
|
|
|
- u32 uninitialized_var(oldval);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * There is no waiter, so we unlock the futex. The owner died
|
|
|
|
- * bit has not to be preserved here. We are the owner:
|
|
|
|
- */
|
|
|
|
- if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
|
|
|
|
- return -EFAULT;
|
|
|
|
- if (oldval != uval)
|
|
|
|
- return -EAGAIN;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Express the locking dependencies for lockdep:
|
|
* Express the locking dependencies for lockdep:
|
|
*/
|
|
*/
|
|
@@ -2401,10 +2385,10 @@ uaddr_faulted:
|
|
*/
|
|
*/
|
|
static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
|
|
static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
|
|
{
|
|
{
|
|
- struct futex_hash_bucket *hb;
|
|
|
|
- struct futex_q *this, *next;
|
|
|
|
|
|
+ u32 uninitialized_var(curval), uval, vpid = task_pid_vnr(current);
|
|
union futex_key key = FUTEX_KEY_INIT;
|
|
union futex_key key = FUTEX_KEY_INIT;
|
|
- u32 uval, vpid = task_pid_vnr(current);
|
|
|
|
|
|
+ struct futex_hash_bucket *hb;
|
|
|
|
+ struct futex_q *match;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
retry:
|
|
retry:
|
|
@@ -2417,57 +2401,47 @@ retry:
|
|
return -EPERM;
|
|
return -EPERM;
|
|
|
|
|
|
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE);
|
|
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE);
|
|
- if (unlikely(ret != 0))
|
|
|
|
- goto out;
|
|
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
|
|
hb = hash_futex(&key);
|
|
hb = hash_futex(&key);
|
|
spin_lock(&hb->lock);
|
|
spin_lock(&hb->lock);
|
|
|
|
|
|
/*
|
|
/*
|
|
- * To avoid races, try to do the TID -> 0 atomic transition
|
|
|
|
- * again. If it succeeds then we can return without waking
|
|
|
|
- * anyone else up. We only try this if neither the waiters nor
|
|
|
|
- * the owner died bit are set.
|
|
|
|
|
|
+ * Check waiters first. We do not trust user space values at
|
|
|
|
+ * all and we at least want to know if user space fiddled
|
|
|
|
+ * with the futex value instead of blindly unlocking.
|
|
*/
|
|
*/
|
|
- if (!(uval & ~FUTEX_TID_MASK) &&
|
|
|
|
- cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
|
|
|
|
- goto pi_faulted;
|
|
|
|
- /*
|
|
|
|
- * Rare case: we managed to release the lock atomically,
|
|
|
|
- * no need to wake anyone else up:
|
|
|
|
- */
|
|
|
|
- if (unlikely(uval == vpid))
|
|
|
|
- goto out_unlock;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Ok, other tasks may need to be woken up - check waiters
|
|
|
|
- * and do the wakeup if necessary:
|
|
|
|
- */
|
|
|
|
- plist_for_each_entry_safe(this, next, &hb->chain, list) {
|
|
|
|
- if (!match_futex (&this->key, &key))
|
|
|
|
- continue;
|
|
|
|
- ret = wake_futex_pi(uaddr, uval, this);
|
|
|
|
|
|
+ match = futex_top_waiter(hb, &key);
|
|
|
|
+ if (match) {
|
|
|
|
+ ret = wake_futex_pi(uaddr, uval, match);
|
|
/*
|
|
/*
|
|
- * The atomic access to the futex value
|
|
|
|
- * generated a pagefault, so retry the
|
|
|
|
- * user-access and the wakeup:
|
|
|
|
|
|
+ * The atomic access to the futex value generated a
|
|
|
|
+ * pagefault, so retry the user-access and the wakeup:
|
|
*/
|
|
*/
|
|
if (ret == -EFAULT)
|
|
if (ret == -EFAULT)
|
|
goto pi_faulted;
|
|
goto pi_faulted;
|
|
goto out_unlock;
|
|
goto out_unlock;
|
|
}
|
|
}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
- * No waiters - kernel unlocks the futex:
|
|
|
|
|
|
+ * We have no kernel internal state, i.e. no waiters in the
|
|
|
|
+ * kernel. Waiters which are about to queue themselves are stuck
|
|
|
|
+ * on hb->lock. So we can safely ignore them. We do neither
|
|
|
|
+ * preserve the WAITERS bit not the OWNER_DIED one. We are the
|
|
|
|
+ * owner.
|
|
*/
|
|
*/
|
|
- ret = unlock_futex_pi(uaddr, uval);
|
|
|
|
- if (ret == -EFAULT)
|
|
|
|
|
|
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, 0))
|
|
goto pi_faulted;
|
|
goto pi_faulted;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If uval has changed, let user space handle it.
|
|
|
|
+ */
|
|
|
|
+ ret = (curval == uval) ? 0 : -EAGAIN;
|
|
|
|
+
|
|
out_unlock:
|
|
out_unlock:
|
|
spin_unlock(&hb->lock);
|
|
spin_unlock(&hb->lock);
|
|
put_futex_key(&key);
|
|
put_futex_key(&key);
|
|
-
|
|
|
|
-out:
|
|
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
pi_faulted:
|
|
pi_faulted:
|