]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
sched: Fix a race between ttwu() and migrate_task()
authorJohn Wright <john.wright@hp.com>
Tue, 13 Apr 2010 22:55:37 +0000 (16:55 -0600)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 26 Apr 2010 14:41:33 +0000 (07:41 -0700)
Based on commit e2912009fb7b715728311b0d8fe327a1432b3f79 upstream, but
done differently as this issue is not present in .33 or .34 kernels due
to rework in this area.

If a task is in the TASK_WAITING state, then try_to_wake_up() is working
on it, and it will place it on the correct cpu.

This commit ensures that neither migrate_task() nor __migrate_task()
calls set_task_cpu(p) while p is in the TASK_WAKING state.  Otherwise,
there could be two concurrent calls to set_task_cpu(p), resulting in
the task's cfs_rq being inconsistent with its cpu.

Signed-off-by: John Wright <john.wright@hp.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
kernel/sched.c

index 2591562eae13d2525337fff83d5653ef51c640fa..3261c1986b5bfc0e92346dbf3c19876750c9c470 100644 (file)
@@ -2116,12 +2116,10 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req)
 
        /*
         * If the task is not on a runqueue (and not running), then
-        * it is sufficient to simply update the task's cpu field.
+        * the next wake-up will properly place the task.
         */
-       if (!p->se.on_rq && !task_running(rq, p)) {
-               set_task_cpu(p, dest_cpu);
+       if (!p->se.on_rq && !task_running(rq, p))
                return 0;
-       }
 
        init_completion(&req->done);
        req->task = p;
@@ -7167,6 +7165,9 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
        /* Already moved. */
        if (task_cpu(p) != src_cpu)
                goto done;
+       /* Waking up, don't get in the way of try_to_wake_up(). */
+       if (p->state == TASK_WAKING)
+               goto fail;
        /* Affinity changed (again). */
        if (!cpumask_test_cpu(dest_cpu, &p->cpus_allowed))
                goto fail;