diff options
author | Steven Rostedt <rostedt@goodmis.org> | 2014-04-10 00:19:23 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-10 00:19:23 (GMT) |
commit | 89c8df1fae8dce3c0651fcf90dcabb8b8e7a10e0 (patch) | |
tree | 99aa03ee4257078dfdd31642223ccb2601c0bd1d /init/noinitramfs.c | |
parent | 0a13c973854b639f936c9a34a8ef5f0df5e75c79 (diff) | |
download | linux-fsl-qoriq-89c8df1fae8dce3c0651fcf90dcabb8b8e7a10e0.tar.xz |
futex: Fix bug on when a requeued RT task times out
Requeue with timeout causes a bug with PREEMPT_RT_FULL.
The bug comes from a timed out condition.
TASK 1 TASK 2
------ ------
futex_wait_requeue_pi()
futex_wait_queue_me()
<timed out>
double_lock_hb();
raw_spin_lock(pi_lock);
if (current->pi_blocked_on) {
} else {
current->pi_blocked_on = PI_WAKE_INPROGRESS;
run_spin_unlock(pi_lock);
spin_lock(hb->lock); <-- blocked!
plist_for_each_entry_safe(this) {
rt_mutex_start_proxy_lock();
task_blocks_on_rt_mutex();
BUG_ON(task->pi_blocked_on)!!!!
The BUG_ON() actually has a check for PI_WAKE_INPROGRESS, but the
problem is that, after TASK 1 sets PI_WAKE_INPROGRESS, it then tries to
grab the hb->lock, which it fails to do so. As the hb->lock is a mutex,
it will block and set the "pi_blocked_on" to the hb->lock.
When TASK 2 goes to requeue it, the check for PI_WAKE_INPROGESS fails
because the task1's pi_blocked_on is no longer set to that, but instead,
set to the hb->lock.
The fix:
When calling rt_mutex_start_proxy_lock() a check is made to see
if the proxy tasks pi_blocked_on is set. If so, exit out early.
Otherwise set it to a new flag PI_REQUEUE_INPROGRESS, which notifies
the proxy task that it is being requeued, and will handle things
appropriately.
Cc: stable-rt@vger.kernel.org
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'init/noinitramfs.c')
0 files changed, 0 insertions, 0 deletions