diff options
author | John Wright <john.wright@hp.com> | 2010-04-13 16:55:37 -0600 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-26 07:41:33 -0700 |
commit | c6fc81afa2d7ef2f775e48672693d8a0a8a7325d (patch) | |
tree | d036b80068d3f9df0d4122b3f7ad901f24dae1c8 | |
parent | 328851d3f993704cb61a74cdf8af88d987302812 (diff) |
sched: Fix a race between ttwu() and migrate_task()
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>
-rw-r--r-- | kernel/sched.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 2591562eae1..3261c1986b5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -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; |