]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - kernel/futex.c
Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mv-sheeva.git] / kernel / futex.c
index 720fa3dd629de25cbfdac3ec9b270464e2787388..4949d336d88d21edf82e51fceaa6b3960fad8790 100644 (file)
@@ -89,36 +89,36 @@ struct futex_pi_state {
        union futex_key key;
 };
 
-/*
- * We use this hashed waitqueue instead of a normal wait_queue_t, so
+/**
+ * struct futex_q - The hashed futex queue entry, one per waiting task
+ * @task:              the task waiting on the futex
+ * @lock_ptr:          the hash bucket lock
+ * @key:               the key the futex is hashed on
+ * @pi_state:          optional priority inheritance state
+ * @rt_waiter:         rt_waiter storage for use with requeue_pi
+ * @requeue_pi_key:    the requeue_pi target futex key
+ * @bitset:            bitset for the optional bitmasked wakeup
+ *
+ * We use this hashed waitqueue, instead of a normal wait_queue_t, so
  * we can wake only the relevant ones (hashed queues may be shared).
  *
  * A futex_q has a woken state, just like tasks have TASK_RUNNING.
  * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
  * The order of wakup is always to make the first condition true, then
- * wake up q->waiter, then make the second condition true.
+ * the second.
+ *
+ * PI futexes are typically woken before they are removed from the hash list via
+ * the rt_mutex code. See unqueue_me_pi().
  */
 struct futex_q {
        struct plist_node list;
-       /* Waiter reference */
-       struct task_struct *task;
 
-       /* Which hash list lock to use: */
+       struct task_struct *task;
        spinlock_t *lock_ptr;
-
-       /* Key which the futex is hashed on: */
        union futex_key key;
-
-       /* Optional priority inheritance state: */
        struct futex_pi_state *pi_state;
-
-       /* 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;
 };
 
@@ -916,8 +916,8 @@ retry:
        hb1 = hash_futex(&key1);
        hb2 = hash_futex(&key2);
 
-       double_lock_hb(hb1, hb2);
 retry_private:
+       double_lock_hb(hb1, hb2);
        op_ret = futex_atomic_op_inuser(op, uaddr2);
        if (unlikely(op_ret < 0)) {
 
@@ -1656,17 +1656,14 @@ out:
 static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
                                struct hrtimer_sleeper *timeout)
 {
-       queue_me(q, hb);
-
        /*
-        * There might have been scheduling since the queue_me(), as we
-        * cannot hold a spinlock across the get_user() in case it
-        * faults, and we cannot just set TASK_INTERRUPTIBLE state when
-        * queueing ourselves into the futex hash. This code thus has to
-        * rely on the futex_wake() code removing us from hash when it
-        * wakes us up.
+        * The task state is guaranteed to be set before another task can
+        * wake it. set_current_state() is implemented using set_mb() and
+        * queue_me() calls spin_unlock() upon completion, both serializing
+        * access to the hash list and forcing another memory barrier.
         */
        set_current_state(TASK_INTERRUPTIBLE);
+       queue_me(q, hb);
 
        /* Arm the timer */
        if (timeout) {
@@ -1676,8 +1673,8 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
        }
 
        /*
-        * !plist_node_empty() is safe here without any lock.
-        * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
+        * If we have been removed from the hash list, then another task
+        * has tried to wake us, and we can skip the call to schedule().
         */
        if (likely(!plist_node_empty(&q->list))) {
                /*
@@ -2120,7 +2117,6 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
                 * Unqueue the futex_q and determine which it was.
                 */
                plist_del(&q->list, &q->list.plist);
-               drop_futex_key_refs(&q->key);
 
                if (timeout && !timeout->task)
                        ret = -ETIMEDOUT;