Merge branch 'work.sock_recvmsg' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / kernel / futex.c
index 57d0b3657e16b90268fa3396668bb62e6e54d287..7f719d11090810622ff010c0b8adc3fe954c478d 100644 (file)
@@ -1878,6 +1878,9 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
        struct futex_q *this, *next;
        DEFINE_WAKE_Q(wake_q);
 
+       if (nr_wake < 0 || nr_requeue < 0)
+               return -EINVAL;
+
        /*
         * When PI not supported: return -ENOSYS if requeue_pi is true,
         * consequently the compiler knows requeue_pi is always false past
@@ -2294,34 +2297,33 @@ static void unqueue_me_pi(struct futex_q *q)
        spin_unlock(q->lock_ptr);
 }
 
-/*
- * Fixup the pi_state owner with the new owner.
- *
- * Must be called with hash bucket lock held and mm->sem held for non
- * private futexes.
- */
 static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-                               struct task_struct *newowner)
+                               struct task_struct *argowner)
 {
-       u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
        struct futex_pi_state *pi_state = q->pi_state;
        u32 uval, uninitialized_var(curval), newval;
-       struct task_struct *oldowner;
+       struct task_struct *oldowner, *newowner;
+       u32 newtid;
        int ret;
 
+       lockdep_assert_held(q->lock_ptr);
+
        raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
 
        oldowner = pi_state->owner;
-       /* Owner died? */
-       if (!pi_state->owner)
-               newtid |= FUTEX_OWNER_DIED;
 
        /*
-        * We are here either because we stole the rtmutex from the
-        * previous highest priority waiter or we are the highest priority
-        * waiter but have failed to get the rtmutex the first time.
+        * We are here because either:
+        *
+        *  - we stole the lock and pi_state->owner needs updating to reflect
+        *    that (@argowner == current),
+        *
+        * or:
         *
-        * We have to replace the newowner TID in the user space variable.
+        *  - someone stole our lock and we need to fix things to point to the
+        *    new owner (@argowner == NULL).
+        *
+        * Either way, we have to replace the TID in the user space variable.
         * This must be atomic as we have to preserve the owner died bit here.
         *
         * Note: We write the user space value _before_ changing the pi_state
@@ -2334,6 +2336,45 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
         * in the PID check in lookup_pi_state.
         */
 retry:
+       if (!argowner) {
+               if (oldowner != current) {
+                       /*
+                        * We raced against a concurrent self; things are
+                        * already fixed up. Nothing to do.
+                        */
+                       ret = 0;
+                       goto out_unlock;
+               }
+
+               if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) {
+                       /* We got the lock after all, nothing to fix. */
+                       ret = 0;
+                       goto out_unlock;
+               }
+
+               /*
+                * Since we just failed the trylock; there must be an owner.
+                */
+               newowner = rt_mutex_owner(&pi_state->pi_mutex);
+               BUG_ON(!newowner);
+       } else {
+               WARN_ON_ONCE(argowner != current);
+               if (oldowner == current) {
+                       /*
+                        * We raced against a concurrent self; things are
+                        * already fixed up. Nothing to do.
+                        */
+                       ret = 0;
+                       goto out_unlock;
+               }
+               newowner = argowner;
+       }
+
+       newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
+       /* Owner died? */
+       if (!pi_state->owner)
+               newtid |= FUTEX_OWNER_DIED;
+
        if (get_futex_value_locked(&uval, uaddr))
                goto handle_fault;
 
@@ -2434,15 +2475,28 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
                 * Got the lock. We might not be the anticipated owner if we
                 * did a lock-steal - fix up the PI-state in that case:
                 *
-                * We can safely read pi_state->owner without holding wait_lock
-                * because we now own the rt_mutex, only the owner will attempt
-                * to change it.
+                * Speculative pi_state->owner read (we don't hold wait_lock);
+                * since we own the lock pi_state->owner == current is the
+                * stable state, anything else needs more attention.
                 */
                if (q->pi_state->owner != current)
                        ret = fixup_pi_state_owner(uaddr, q, current);
                goto out;
        }
 
+       /*
+        * If we didn't get the lock; check if anybody stole it from us. In
+        * that case, we need to fix up the uval to point to them instead of
+        * us, otherwise bad things happen. [10]
+        *
+        * Another speculative read; pi_state->owner == current is unstable
+        * but needs our attention.
+        */
+       if (q->pi_state->owner == current) {
+               ret = fixup_pi_state_owner(uaddr, q, NULL);
+               goto out;
+       }
+
        /*
         * Paranoia check. If we did not take the lock, then we should not be
         * the owner of the rt_mutex.