summaryrefslogtreecommitdiff
path: root/kernel/rtmutex.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-06-10 09:04:15 (GMT)
committerScott Wood <scottwood@freescale.com>2015-02-13 22:20:41 (GMT)
commitc810b6e562630d3ecab6d11777e1b5c227ca8357 (patch)
tree319cd9587c1664d48864c40cf5a4edddbcfa5374 /kernel/rtmutex.c
parent7ea336a7833a210873feaa9375dab0836e4064e6 (diff)
downloadlinux-fsl-qoriq-c810b6e562630d3ecab6d11777e1b5c227ca8357.tar.xz
rtmutex-futex-prepare-rt.patch
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/rtmutex.c')
-rw-r--r--kernel/rtmutex.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
index 911829b..c9d8a2a 100644
--- a/kernel/rtmutex.c
+++ b/kernel/rtmutex.c
@@ -68,6 +68,11 @@ static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
clear_rt_mutex_waiters(lock);
}
+static int rt_mutex_real_waiter(struct rt_mutex_waiter *waiter)
+{
+ return waiter && waiter != PI_WAKEUP_INPROGRESS;
+}
+
/*
* We can speed up the acquire/release, if the architecture
* supports cmpxchg and if there's no debugging state to be set up
@@ -208,7 +213,8 @@ int max_lock_depth = 1024;
static inline struct rt_mutex *task_blocked_on_lock(struct task_struct *p)
{
- return p->pi_blocked_on ? p->pi_blocked_on->lock : NULL;
+ struct rt_mutex_waiter *waiter = p->pi_blocked_on;
+ return rt_mutex_real_waiter(waiter) ? waiter->lock : NULL;
}
/*
@@ -283,7 +289,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
* reached or the state of the chain has changed while we
* dropped the locks.
*/
- if (!waiter)
+ if (!rt_mutex_real_waiter(waiter))
goto out_unlock_pi;
/*
@@ -538,6 +544,23 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
return -EDEADLK;
raw_spin_lock_irqsave(&task->pi_lock, flags);
+
+ /*
+ * In the case of futex requeue PI, this will be a proxy
+ * lock. The task will wake unaware that it is enqueueed on
+ * this lock. Avoid blocking on two locks and corrupting
+ * pi_blocked_on via the PI_WAKEUP_INPROGRESS
+ * flag. futex_wait_requeue_pi() sets this when it wakes up
+ * before requeue (due to a signal or timeout). Do not enqueue
+ * the task if PI_WAKEUP_INPROGRESS is set.
+ */
+ if (task != current && task->pi_blocked_on == PI_WAKEUP_INPROGRESS) {
+ raw_spin_unlock_irqrestore(&task->pi_lock, flags);
+ return -EAGAIN;
+ }
+
+ BUG_ON(rt_mutex_real_waiter(task->pi_blocked_on));
+
__rt_mutex_adjust_prio(task);
waiter->task = task;
waiter->lock = lock;
@@ -562,7 +585,7 @@ 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)
+ if (rt_mutex_real_waiter(owner->pi_blocked_on))
chain_walk = 1;
} else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
chain_walk = 1;
@@ -713,7 +736,8 @@ void rt_mutex_adjust_pi(struct task_struct *task)
raw_spin_lock_irqsave(&task->pi_lock, flags);
waiter = task->pi_blocked_on;
- if (!waiter || waiter->list_entry.prio == task->prio) {
+ if (!rt_mutex_real_waiter(waiter) ||
+ waiter->list_entry.prio == task->prio) {
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
return;
}