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

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

Advertisement

Kernel v2.6.24-rc7-git6 /kernel/futex.c

Filename:/kernel/futex.c
Lines Added:41
Lines Deleted:10
Also changed in: (Previous) 2.6.24-rc7-git5  2.6.24-rc7-git4  2.6.24-rc7-git3  2.6.24-rc7-git2  2.6.24-rc7-git1  2.6.24-rc7 
(Following) 2.6.24-rc7-git7  2.6.24-rc7-git8  2.6.24-rc8  2.6.24  2.6.24-git12  2.6.24-git13 

Location
[  2.6.24-rc7-git6
  [  kernel
     o  futex.c

Patch

diff --git a/kernel/futex.c b/kernel/futex.c
index 172a1ae..db9824d 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1097,15 +1097,15 @@ static void unqueue_me_pi(struct futex_q *q)
 }
 
 /*
- * Fixup the pi_state owner with current.
+ * 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 *curr)
+            struct task_struct *newowner)
 {
-   u32 newtid = task_pid_vnr(curr) | FUTEX_WAITERS;
+   u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
    struct futex_pi_state *pi_state = q->pi_state;
    u32 uval, curval, newval;
    int ret;
@@ -1119,12 +1119,12 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
    } else
       newtid |= FUTEX_OWNER_DIED;
 
-   pi_state->owner = curr;
+   pi_state->owner = newowner;
 
-   spin_lock_irq(&curr->pi_lock);
+   spin_lock_irq(&newowner->pi_lock);
    WARN_ON(!list_empty(&pi_state->list));
-   list_add(&pi_state->list, &curr->pi_state_list);
-   spin_unlock_irq(&curr->pi_lock);
+   list_add(&pi_state->list, &newowner->pi_state_list);
+   spin_unlock_irq(&newowner->pi_lock);
 
    /*
     * We own it, so we have to replace the pending owner
@@ -1508,9 +1508,40 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        * when we were on the way back before we locked the
        * hash bucket.
        */
-      if (q.pi_state->owner == curr &&
-          rt_mutex_trylock(&q.pi_state->pi_mutex)) {
-         ret = 0;
+      if (q.pi_state->owner == curr) {
+         /*
+          * Try to get the rt_mutex now. This might
+          * fail as some other task acquired the
+          * rt_mutex after we removed ourself from the
+          * rt_mutex waiters list.
+          */
+         if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+            ret = 0;
+         else {
+            /*
+             * pi_state is incorrect, some other
+             * task did a lock steal and we
+             * returned due to timeout or signal
+             * without taking the rt_mutex. Too
+             * late. We can access the
+             * rt_mutex_owner without locking, as
+             * the other task is now blocked on
+             * the hash bucket lock. Fix the state
+             * up.
+             */
+            struct task_struct *owner;
+            int res;
+
+            owner = rt_mutex_owner(&q.pi_state->pi_mutex);
+            res = fixup_pi_state_owner(uaddr, &q, owner);
+
+            WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
+               owner);
+
+            /* propagate -EFAULT, if the fixup failed */
+            if (res)
+               ret = res;
+         }
       } else {
          /*
           * Paranoia check. If we did not take the lock


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