Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
[linux-drm-fsl-dcu.git] / kernel / rtmutex.c
index 3e13a1e5856fecf8a06eab48372d12a01efb428b..a6fbb41305210c9d3d45c56a670f3fe96af6ce64 100644 (file)
@@ -56,7 +56,7 @@
  * state.
  */
 
-static void
+void
 rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
                   unsigned long mask)
 {
@@ -80,29 +80,6 @@ static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
                clear_rt_mutex_waiters(lock);
 }
 
-/*
- * We can speed up the acquire/release, if the architecture
- * supports cmpxchg and if there's no debugging state to be set up
- */
-#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
-# define rt_mutex_cmpxchg(l,c,n)       (cmpxchg(&l->owner, c, n) == c)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
-       unsigned long owner, *p = (unsigned long *) &lock->owner;
-
-       do {
-               owner = *p;
-       } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
-}
-#else
-# define rt_mutex_cmpxchg(l,c,n)       (0)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
-       lock->owner = (struct task_struct *)
-                       ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
-}
-#endif
-
 /*
  * Calculate task priority from the waiter list priority
  *
@@ -123,7 +100,7 @@ int rt_mutex_getprio(struct task_struct *task)
  *
  * This can be both boosting and unboosting. task->pi_lock must be held.
  */
-static void __rt_mutex_adjust_prio(struct task_struct *task)
+void __rt_mutex_adjust_prio(struct task_struct *task)
 {
        int prio = rt_mutex_getprio(task);
 
@@ -159,11 +136,11 @@ int max_lock_depth = 1024;
  * Decreases task's usage by one - may thus free the task.
  * Returns 0 or -EDEADLK.
  */
-static int rt_mutex_adjust_prio_chain(struct task_struct *task,
-                                     int deadlock_detect,
-                                     struct rt_mutex *orig_lock,
-                                     struct rt_mutex_waiter *orig_waiter,
-                                     struct task_struct *top_task)
+int rt_mutex_adjust_prio_chain(struct task_struct *task,
+                              int deadlock_detect,
+                              struct rt_mutex *orig_lock,
+                              struct rt_mutex_waiter *orig_waiter,
+                              struct task_struct *top_task)
 {
        struct rt_mutex *lock;
        struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter;
@@ -212,6 +189,19 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
        if (!waiter || !waiter->task)
                goto out_unlock_pi;
 
+       /*
+        * Check the orig_waiter state. After we dropped the locks,
+        * the previous owner of the lock might have released the lock
+        * and made us the pending owner:
+        */
+       if (orig_waiter && !orig_waiter->task)
+               goto out_unlock_pi;
+
+       /*
+        * Drop out, when the task has no waiters. Note,
+        * top_waiter can be NULL, when we are in the deboosting
+        * mode!
+        */
        if (top_waiter && (!task_has_pi_waiters(task) ||
                           top_waiter != task_top_pi_waiter(task)))
                goto out_unlock_pi;
@@ -251,6 +241,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
 
        /* Grab the next task */
        task = rt_mutex_owner(lock);
+       get_task_struct(task);
        spin_lock_irqsave(&task->pi_lock, flags);
 
        if (waiter == rt_mutex_top_waiter(lock)) {
@@ -269,7 +260,6 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
                __rt_mutex_adjust_prio(task);
        }
 
-       get_task_struct(task);
        spin_unlock_irqrestore(&task->pi_lock, flags);
 
        top_waiter = rt_mutex_top_waiter(lock);
@@ -409,7 +399,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
        struct task_struct *owner = rt_mutex_owner(lock);
        struct rt_mutex_waiter *top_waiter = waiter;
        unsigned long flags;
-       int boost = 0, res;
+       int chain_walk = 0, res;
 
        spin_lock_irqsave(&current->pi_lock, flags);
        __rt_mutex_adjust_prio(current);
@@ -433,25 +423,23 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
                plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
 
                __rt_mutex_adjust_prio(owner);
-               if (owner->pi_blocked_on) {
-                       boost = 1;
-                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
-                       get_task_struct(owner);
-               }
-               spin_unlock_irqrestore(&owner->pi_lock, flags);
-       }
-       else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
-               spin_lock_irqsave(&owner->pi_lock, flags);
-               if (owner->pi_blocked_on) {
-                       boost = 1;
-                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
-                       get_task_struct(owner);
-               }
+               if (owner->pi_blocked_on)
+                       chain_walk = 1;
                spin_unlock_irqrestore(&owner->pi_lock, flags);
        }
-       if (!boost)
+       else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock))
+               chain_walk = 1;
+
+       if (!chain_walk)
                return 0;
 
+       /*
+        * The owner can't disappear while holding a lock,
+        * so the owner struct is protected by wait_lock.
+        * Gets dropped in rt_mutex_adjust_prio_chain()!
+        */
+       get_task_struct(owner);
+
        spin_unlock(&lock->wait_lock);
 
        res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
@@ -526,13 +514,13 @@ static void wakeup_next_waiter(struct rt_mutex *lock)
  *
  * Must be called with lock->wait_lock held
  */
-static void remove_waiter(struct rt_mutex *lock,
-                         struct rt_mutex_waiter *waiter)
+void remove_waiter(struct rt_mutex *lock,
+                  struct rt_mutex_waiter *waiter)
 {
        int first = (waiter == rt_mutex_top_waiter(lock));
        struct task_struct *owner = rt_mutex_owner(lock);
        unsigned long flags;
-       int boost = 0;
+       int chain_walk = 0;
 
        spin_lock_irqsave(&current->pi_lock, flags);
        plist_del(&waiter->list_entry, &lock->wait_list);
@@ -554,19 +542,20 @@ static void remove_waiter(struct rt_mutex *lock,
                }
                __rt_mutex_adjust_prio(owner);
 
-               if (owner->pi_blocked_on) {
-                       boost = 1;
-                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
-                       get_task_struct(owner);
-               }
+               if (owner->pi_blocked_on)
+                       chain_walk = 1;
+
                spin_unlock_irqrestore(&owner->pi_lock, flags);
        }
 
        WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
 
-       if (!boost)
+       if (!chain_walk)
                return;
 
+       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+       get_task_struct(owner);
+
        spin_unlock(&lock->wait_lock);
 
        rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current);
@@ -592,10 +581,10 @@ void rt_mutex_adjust_pi(struct task_struct *task)
                return;
        }
 
-       /* gets dropped in rt_mutex_adjust_prio_chain()! */
-       get_task_struct(task);
        spin_unlock_irqrestore(&task->pi_lock, flags);
 
+       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+       get_task_struct(task);
        rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task);
 }
 
@@ -626,7 +615,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
        /* Setup the timer, when timeout != NULL */
        if (unlikely(timeout))
                hrtimer_start(&timeout->timer, timeout->timer.expires,
-                             HRTIMER_ABS);
+                             HRTIMER_MODE_ABS);
 
        for (;;) {
                /* Try to acquire the lock: */
@@ -660,9 +649,16 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                         * all over without going into schedule to try
                         * to get the lock now:
                         */
-                       if (unlikely(!waiter.task))
+                       if (unlikely(!waiter.task)) {
+                               /*
+                                * Reset the return value. We might
+                                * have returned with -EDEADLK and the
+                                * owner released the lock while we
+                                * were walking the pi chain.
+                                */
+                               ret = 0;
                                continue;
-
+                       }
                        if (unlikely(ret))
                                break;
                }