Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.31-git11 /kernel/futex.c

Filename:/kernel/futex.c
Lines Added:30
Lines Deleted:17
Also changed in: (Previous) 2.6.31-git10  2.6.31-git9  2.6.31-git8  2.6.31-git7  2.6.31-git6  2.6.31-git5 
(Following) 2.6.31-git12  2.6.31-git13  2.6.31-git14  2.6.31-git15  2.6.31-git16  2.6.31-git17 

Location
[  2.6.31-git11
  [  kernel
     o  futex.c

Patch

diff --git a/kernel/futex.c b/kernel/futex.c
index e18cfbd..248dd11 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -115,6 +115,9 @@ struct futex_q {
    /* rt_waiter storage for requeue_pi: */
    struct rt_mutex_waiter *rt_waiter;
 
+   /* The expected requeue pi target futex key: */
+   union futex_key *requeue_pi_key;
+
    /* Bitset for the optional bitmasked wakeup */
    u32 bitset;
 };
@@ -1089,6 +1092,10 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
    if (!top_waiter)
       return 0;
 
+   /* Ensure we requeue to the expected futex. */
+   if (!match_futex(top_waiter->requeue_pi_key, key2))
+      return -EINVAL;
+
    /*
     * Try to take the lock for top_waiter.  Set the FUTEX_WAITERS bit in
     * the contended case or if set_waiters is 1.  The pi_state is returned
@@ -1276,6 +1283,12 @@ retry_private:
          continue;
       }
 
+      /* Ensure we requeue to the expected futex for requeue_pi. */
+      if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) {
+         ret = -EINVAL;
+         break;
+      }
+
       /*
        * Requeue nr_requeue waiters and possibly one more in the case
        * of requeue_pi if we couldn't acquire the lock atomically.
@@ -1751,6 +1764,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
    q.pi_state = NULL;
    q.bitset = bitset;
    q.rt_waiter = NULL;
+   q.requeue_pi_key = NULL;
 
    if (abs_time) {
       to = &timeout;
@@ -1858,6 +1872,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
 
    q.pi_state = NULL;
    q.rt_waiter = NULL;
+   q.requeue_pi_key = NULL;
 retry:
    q.key = FUTEX_KEY_INIT;
    ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
@@ -2118,11 +2133,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
  * We call schedule in futex_wait_queue_me() when we enqueue and return there
  * via the following:
  * 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
- * 2) wakeup on uaddr2 after a requeue and subsequent unlock
- * 3) signal (before or after requeue)
- * 4) timeout (before or after requeue)
+ * 2) wakeup on uaddr2 after a requeue
+ * 3) signal
+ * 4) timeout
  *
- * If 3, we setup a restart_block with futex_wait_requeue_pi() as the function.
+ * If 3, cleanup and return -ERESTARTNOINTR.
  *
  * If 2, we may then block on trying to take the rt_mutex and return via:
  * 5) successful lock
@@ -2130,7 +2145,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
  * 7) timeout
  * 8) other lock acquisition failure
  *
- * If 6, we setup a restart_block with futex_lock_pi() as the function.
+ * If 6, return -EWOULDBLOCK (restarting the syscall would do the same).
  *
  * If 4 or 7, we cleanup and return with -ETIMEDOUT.
  *
@@ -2169,15 +2184,16 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
    debug_rt_mutex_init_waiter(&rt_waiter);
    rt_waiter.task = NULL;
 
-   q.pi_state = NULL;
-   q.bitset = bitset;
-   q.rt_waiter = &rt_waiter;
-
    key2 = FUTEX_KEY_INIT;
    ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
    if (unlikely(ret != 0))
       goto out;
 
+   q.pi_state = NULL;
+   q.bitset = bitset;
+   q.rt_waiter = &rt_waiter;
+   q.requeue_pi_key = &key2;
+
    /* Prepare to wait on uaddr. */
    ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
    if (ret)
@@ -2248,14 +2264,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
          rt_mutex_unlock(pi_mutex);
    } else if (ret == -EINTR) {
       /*
-       * 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().
+       * We've already been requeued, but cannot restart by calling
+       * futex_lock_pi() directly. We could restart this syscall, but
+       * it would detect that the user space "val" changed and return
+       * -EWOULDBLOCK.  Save the overhead of the restart and return
+       * -EWOULDBLOCK directly.
        */
       ret = -EWOULDBLOCK;
    }


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.