lkml.org 
[lkml]   [2010]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectsched: Fix wake up race with rt_mutex_setprio()
rt_mutex_setprio() can race with try_to_wake_up():

CPU 0 CPU 1
try_to_wake_up(p)
task_rq_lock(p)
p->state = TASK_WAKING;
task_rq_unlock() rt_mutex_setprio(p)
task_rq_lock(p) <- succeeds (old CPU)
newcpu = select_task_rq(p)
set_task_cpu(p)

task_rq_lock(p) <- succeeds (new CPU)

activate_task(p) change sched_class(p)

That way we end up with the task enqueued in the wrong sched class.

Solve this by waiting for p->state != TASK_WAKING in rt_mutex_setprio().

Debugged and tested in the preempt-rt tree.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/sched.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
Index: linux-2.6/kernel/sched.c
===================================================================
--- linux-2.6.orig/kernel/sched.c
+++ linux-2.6/kernel/sched.c
@@ -6058,7 +6058,25 @@ void rt_mutex_setprio(struct task_struct

BUG_ON(prio < 0 || prio > MAX_PRIO);

+again:
rq = task_rq_lock(p, &flags);
+
+ /*
+ * Prevent a nasty race with ttwu(). ttwu() sets the task
+ * state to WAKING and drops the runqueue lock. So we can
+ * acquire the runqueue lock while ttwu() migrates the
+ * task. We need to wait until ttwu() set the target cpu and
+ * enqueued the task on whatever CPU it decided to select.
+ * Otherwise ttwu() might enqueue with the old class on
+ * another cpu while we are changing the class on the previous
+ * cpu.
+ */
+ if (unlikely(p->state == TASK_WAKING)) {
+ task_rq_unlock(rq, &flags);
+ cpu_relax();
+ goto again;
+ }
+
update_rq_clock(rq);

oldprio = p->prio;

\
 
 \ /
  Last update: 2010-02-14 20:49    [from the cache]
©2003-2011 Jasper Spaans