]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
futex: Split out the waiter check from lookup_pi_state()
authorThomas Gleixner <tglx@linutronix.de>
Wed, 11 Jun 2014 20:45:39 +0000 (20:45 +0000)
committerThomas Gleixner <tglx@linutronix.de>
Sat, 21 Jun 2014 20:26:23 +0000 (22:26 +0200)
We want to be a bit more clever in futex_lock_pi_atomic() and separate
the possible states. Split out the waiter verification into a separate
function. No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Darren Hart <darren@dvhart.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Davidlohr Bueso <davidlohr@hp.com>
Cc: Kees Cook <kees@outflux.net>
Cc: wad@chromium.org
Link: http://lkml.kernel.org/r/20140611204237.180458410@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
kernel/futex.c

index fff1ed9b1c4375089399a9acaaf95e048d022252..db0c6863e8a35b1d781bb67b2c0adf2b3b4fdfd0 100644 (file)
@@ -792,91 +792,95 @@ void exit_pi_state_list(struct task_struct *curr)
  * [10] There is no transient state which leaves owner and user space
  *     TID out of sync.
  */
-static int
-lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
-               union futex_key *key, struct futex_pi_state **ps)
+
+/*
+ * Validate that the existing waiter has a pi_state and sanity check
+ * the pi_state against the user space value. If correct, attach to
+ * it.
+ */
+static int attach_to_pi_state(u32 uval, struct futex_pi_state *pi_state,
+                             struct futex_pi_state **ps)
 {
-       struct futex_q *match = futex_top_waiter(hb, key);
-       struct futex_pi_state *pi_state = NULL;
-       struct task_struct *p;
        pid_t pid = uval & FUTEX_TID_MASK;
 
-       if (match) {
-               /*
-                * Sanity check the waiter before increasing the
-                * refcount and attaching to it.
-                */
-               pi_state = match->pi_state;
-               /*
-                * Userspace might have messed up non-PI and PI
-                * futexes [3]
-                */
-               if (unlikely(!pi_state))
-                       return -EINVAL;
+       /*
+        * Userspace might have messed up non-PI and PI futexes [3]
+        */
+       if (unlikely(!pi_state))
+               return -EINVAL;
 
-               WARN_ON(!atomic_read(&pi_state->refcount));
+       WARN_ON(!atomic_read(&pi_state->refcount));
 
+       /*
+        * Handle the owner died case:
+        */
+       if (uval & FUTEX_OWNER_DIED) {
                /*
-                * Handle the owner died case:
+                * exit_pi_state_list sets owner to NULL and wakes the
+                * topmost waiter. The task which acquires the
+                * pi_state->rt_mutex will fixup owner.
                 */
-               if (uval & FUTEX_OWNER_DIED) {
+               if (!pi_state->owner) {
                        /*
-                        * exit_pi_state_list sets owner to NULL and
-                        * wakes the topmost waiter. The task which
-                        * acquires the pi_state->rt_mutex will fixup
-                        * owner.
+                        * No pi state owner, but the user space TID
+                        * is not 0. Inconsistent state. [5]
                         */
-                       if (!pi_state->owner) {
-                               /*
-                                * No pi state owner, but the user
-                                * space TID is not 0. Inconsistent
-                                * state. [5]
-                                */
-                               if (pid)
-                                       return -EINVAL;
-                               /*
-                                * Take a ref on the state and
-                                * return. [4]
-                                */
-                               goto out_state;
-                       }
-
-                       /*
-                        * If TID is 0, then either the dying owner
-                        * has not yet executed exit_pi_state_list()
-                        * or some waiter acquired the rtmutex in the
-                        * pi state, but did not yet fixup the TID in
-                        * user space.
-                        *
-                        * Take a ref on the state and return. [6]
-                        */
-                       if (!pid)
-                               goto out_state;
-               } else {
+                       if (pid)
+                               return -EINVAL;
                        /*
-                        * If the owner died bit is not set,
-                        * then the pi_state must have an
-                        * owner. [7]
+                        * Take a ref on the state and return success. [4]
                         */
-                       if (!pi_state->owner)
-                               return -EINVAL;
+                       goto out_state;
                }
 
                /*
-                * Bail out if user space manipulated the
-                * futex value. If pi state exists then the
-                * owner TID must be the same as the user
-                * space TID. [9/10]
+                * If TID is 0, then either the dying owner has not
+                * yet executed exit_pi_state_list() or some waiter
+                * acquired the rtmutex in the pi state, but did not
+                * yet fixup the TID in user space.
+                *
+                * Take a ref on the state and return success. [6]
                 */
-               if (pid != task_pid_vnr(pi_state->owner))
+               if (!pid)
+                       goto out_state;
+       } else {
+               /*
+                * If the owner died bit is not set, then the pi_state
+                * must have an owner. [7]
+                */
+               if (!pi_state->owner)
                        return -EINVAL;
-
-       out_state:
-               atomic_inc(&pi_state->refcount);
-               *ps = pi_state;
-               return 0;
        }
 
+       /*
+        * Bail out if user space manipulated the futex value. If pi
+        * state exists then the owner TID must be the same as the
+        * user space TID. [9/10]
+        */
+       if (pid != task_pid_vnr(pi_state->owner))
+               return -EINVAL;
+out_state:
+       atomic_inc(&pi_state->refcount);
+       *ps = pi_state;
+       return 0;
+}
+
+static int
+lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
+               union futex_key *key, struct futex_pi_state **ps)
+{
+       struct futex_q *match = futex_top_waiter(hb, key);
+       struct futex_pi_state *pi_state = NULL;
+       struct task_struct *p;
+       pid_t pid = uval & FUTEX_TID_MASK;
+
+       /*
+        * If there is a waiter on that futex, validate it and
+        * attach to the pi_state when the validation succeeds.
+        */
+       if (match)
+               return attach_to_pi_state(uval, match->pi_state, ps);
+
        /*
         * We are the first waiter - try to look up the real owner and attach
         * the new pi_state to it, but bail out when TID = 0 [1]