jbd: clean up journal_try_to_free_buffers()
[safe/jmp/linux-2.6] / kernel / futex.c
index 157bfcd..80b5ce7 100644 (file)
@@ -199,6 +199,7 @@ static void drop_futex_key_refs(union futex_key *key)
  * @uaddr: virtual address of the futex
  * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
  * @key: address where result is stored.
+ * @rw: mapping needs to be read/write (values: VERIFY_READ, VERIFY_WRITE)
  *
  * Returns a negative error code or 0
  * The key words are stored in *key on success.
@@ -209,7 +210,8 @@ static void drop_futex_key_refs(union futex_key *key)
  *
  * lock_page() might sleep, the caller should not hold a spinlock.
  */
-static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
+static int
+get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
 {
        unsigned long address = (unsigned long)uaddr;
        struct mm_struct *mm = current->mm;
@@ -232,7 +234,7 @@ static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
         *        but access_ok() should be faster than find_vma()
         */
        if (!fshared) {
-               if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
+               if (unlikely(!access_ok(rw, uaddr, sizeof(u32))))
                        return -EFAULT;
                key->private.mm = mm;
                key->private.address = address;
@@ -241,7 +243,7 @@ static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
        }
 
 again:
-       err = get_user_pages_fast(address, 1, 0, &page);
+       err = get_user_pages_fast(address, 1, rw == VERIFY_WRITE, &page);
        if (err < 0)
                return err;
 
@@ -834,7 +836,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
        if (!bitset)
                return -EINVAL;
 
-       ret = get_futex_key(uaddr, fshared, &key);
+       ret = get_futex_key(uaddr, fshared, &key, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
 
@@ -880,10 +882,10 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
        int ret, op_ret;
 
 retry:
-       ret = get_futex_key(uaddr1, fshared, &key1);
+       ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, fshared, &key2);
+       ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out_put_key1;
 
@@ -1131,10 +1133,11 @@ retry:
                pi_state = NULL;
        }
 
-       ret = get_futex_key(uaddr1, fshared, &key1);
+       ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, fshared, &key2);
+       ret = get_futex_key(uaddr2, fshared, &key2,
+                           requeue_pi ? VERIFY_WRITE : VERIFY_READ);
        if (unlikely(ret != 0))
                goto out_put_key1;
 
@@ -1267,7 +1270,12 @@ retry_private:
 out_unlock:
        double_unlock_hb(hb1, hb2);
 
-       /* drop_futex_key_refs() must be called outside the spinlocks. */
+       /*
+        * drop_futex_key_refs() must be called outside the spinlocks. During
+        * the requeue we moved futex_q's from the hash bucket at key1 to the
+        * one at key2 and updated their key pointer.  We no longer need to
+        * hold the references to key1.
+        */
        while (--drop_count >= 0)
                drop_futex_key_refs(&key1);
 
@@ -1499,7 +1507,6 @@ handle_fault:
 #define FLAGS_HAS_TIMEOUT      0x04
 
 static long futex_wait_restart(struct restart_block *restart);
-static long futex_lock_pi_restart(struct restart_block *restart);
 
 /**
  * fixup_owner() - Post lock pi_state and corner case management
@@ -1660,7 +1667,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared,
         */
 retry:
        q->key = FUTEX_KEY_INIT;
-       ret = get_futex_key(uaddr, fshared, &q->key);
+       ret = get_futex_key(uaddr, fshared, &q->key, VERIFY_READ);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1819,7 +1826,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
        q.rt_waiter = NULL;
 retry:
        q.key = FUTEX_KEY_INIT;
-       ret = get_futex_key(uaddr, fshared, &q.key);
+       ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
@@ -1922,21 +1929,6 @@ uaddr_faulted:
        goto retry;
 }
 
-static long futex_lock_pi_restart(struct restart_block *restart)
-{
-       u32 __user *uaddr = (u32 __user *)restart->futex.uaddr;
-       ktime_t t, *tp = NULL;
-       int fshared = restart->futex.flags & FLAGS_SHARED;
-
-       if (restart->futex.flags & FLAGS_HAS_TIMEOUT) {
-               t.tv64 = restart->futex.time;
-               tp = &t;
-       }
-       restart->fn = do_no_restart_syscall;
-
-       return (long)futex_lock_pi(uaddr, fshared, restart->futex.val, tp, 0);
-}
-
 /*
  * Userspace attempted a TID -> 0 atomic transition, and failed.
  * This is the in-kernel slowpath: we look up the PI state (if any),
@@ -1960,7 +1952,7 @@ retry:
        if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current))
                return -EPERM;
 
-       ret = get_futex_key(uaddr, fshared, &key);
+       ret = get_futex_key(uaddr, fshared, &key, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
@@ -2052,7 +2044,7 @@ pi_faulted:
  *
  * Returns
  *  0 - no early wakeup detected
- * <0 - -ETIMEDOUT or -ERESTARTSYS (FIXME: or ERESTARTNOINTR?)
+ * <0 - -ETIMEDOUT or -ERESTARTNOINTR
  */
 static inline
 int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
@@ -2079,15 +2071,8 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
 
                if (timeout && !timeout->task)
                        ret = -ETIMEDOUT;
-               else {
-                       /*
-                        * We expect signal_pending(current), but another
-                        * thread may have handled it for us already.
-                        */
-                       /* FIXME: ERESTARTSYS or ERESTARTNOINTR?  Do we care if
-                        * the user specified SA_RESTART or not? */
-                       ret = -ERESTARTSYS;
-               }
+               else
+                       ret = -ERESTARTNOINTR;
        }
        return ret;
 }
@@ -2140,12 +2125,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
        struct hrtimer_sleeper timeout, *to = NULL;
        struct rt_mutex_waiter rt_waiter;
        struct rt_mutex *pi_mutex = NULL;
-       struct restart_block *restart;
        struct futex_hash_bucket *hb;
        union futex_key key2;
        struct futex_q q;
        int res, ret;
-       u32 uval;
 
        if (!bitset)
                return -EINVAL;
@@ -2171,16 +2154,14 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
        q.rt_waiter = &rt_waiter;
 
        key2 = FUTEX_KEY_INIT;
-       ret = get_futex_key(uaddr2, fshared, &key2);
+       ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
        if (unlikely(ret != 0))
                goto out;
 
        /* Prepare to wait on uaddr. */
        ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
-       if (ret) {
-               put_futex_key(fshared, &key2);
-               goto out;
-       }
+       if (ret)
+               goto out_key2;
 
        /* Queue the futex_q, drop the hb lock, wait for wakeup. */
        futex_wait_queue_me(hb, &q, to);
@@ -2246,34 +2227,22 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
                if (rt_mutex_owner(pi_mutex) == current)
                        rt_mutex_unlock(pi_mutex);
        } else if (ret == -EINTR) {
-               ret = -EFAULT;
-               if (get_user(uval, uaddr2))
-                       goto out_put_keys;
-
                /*
-                * We've already been requeued, so restart by calling
-                * futex_lock_pi() directly, rather then returning to this
-                * function.
+                * We've already been requeued, but we have no way to
+                * restart by calling futex_lock_pi() directly. We
+                * could restart the syscall, but that will look at
+                * the user space value and return right away. So we
+                * drop back with EWOULDBLOCK to tell user space that
+                * "val" has been changed. That's the same what the
+                * restart of the syscall would do in
+                * futex_wait_setup().
                 */
-               ret = -ERESTART_RESTARTBLOCK;
-               restart = &current_thread_info()->restart_block;
-               restart->fn = futex_lock_pi_restart;
-               restart->futex.uaddr = (u32 *)uaddr2;
-               restart->futex.val = uval;
-               restart->futex.flags = 0;
-               if (abs_time) {
-                       restart->futex.flags |= FLAGS_HAS_TIMEOUT;
-                       restart->futex.time = abs_time->tv64;
-               }
-
-               if (fshared)
-                       restart->futex.flags |= FLAGS_SHARED;
-               if (clockrt)
-                       restart->futex.flags |= FLAGS_CLOCKRT;
+               ret = -EWOULDBLOCK;
        }
 
 out_put_keys:
        put_futex_key(fshared, &q.key);
+out_key2:
        put_futex_key(fshared, &key2);
 
 out: