|
@@ -343,9 +343,16 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
|
|
* 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;
|
|
|
+ if (top_waiter) {
|
|
|
+ if (!task_has_pi_waiters(task))
|
|
|
+ goto out_unlock_pi;
|
|
|
+ /*
|
|
|
+ * If deadlock detection is off, we stop here if we
|
|
|
+ * are not the top pi waiter of the task.
|
|
|
+ */
|
|
|
+ if (!detect_deadlock && top_waiter != task_top_pi_waiter(task))
|
|
|
+ goto out_unlock_pi;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* When deadlock detection is off then we check, if further
|
|
@@ -361,7 +368,12 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
|
|
|
goto retry;
|
|
|
}
|
|
|
|
|
|
- /* Deadlock detection */
|
|
|
+ /*
|
|
|
+ * Deadlock detection. If the lock is the same as the original
|
|
|
+ * lock which caused us to walk the lock chain or if the
|
|
|
+ * current lock is owned by the task which initiated the chain
|
|
|
+ * walk, we detected a deadlock.
|
|
|
+ */
|
|
|
if (lock == orig_lock || rt_mutex_owner(lock) == top_task) {
|
|
|
debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock);
|
|
|
raw_spin_unlock(&lock->wait_lock);
|
|
@@ -527,6 +539,18 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
|
|
|
unsigned long flags;
|
|
|
int chain_walk = 0, res;
|
|
|
|
|
|
+ /*
|
|
|
+ * Early deadlock detection. We really don't want the task to
|
|
|
+ * enqueue on itself just to untangle the mess later. It's not
|
|
|
+ * only an optimization. We drop the locks, so another waiter
|
|
|
+ * can come in before the chain walk detects the deadlock. So
|
|
|
+ * the other will detect the deadlock and return -EDEADLOCK,
|
|
|
+ * which is wrong, as the other waiter is not in a deadlock
|
|
|
+ * situation.
|
|
|
+ */
|
|
|
+ if (detect_deadlock && owner == task)
|
|
|
+ return -EDEADLK;
|
|
|
+
|
|
|
raw_spin_lock_irqsave(&task->pi_lock, flags);
|
|
|
__rt_mutex_adjust_prio(task);
|
|
|
waiter->task = task;
|