| From john.wright@hp.com Wed Apr 21 11:41:33 2010 |
| From: John Wright <john.wright@hp.com> |
| Date: Tue, 13 Apr 2010 16:55:37 -0600 |
| Subject: sched: Fix a race between ttwu() and migrate_task() |
| Cc: Ingo Molnar <mingo@elte.hu>, Peter Zijlstra <peterz@infradead.org>, Greg Kroah-Hartman <gregkh@suse.de>, Terry Loftin <terry.loftin@hp.com>, John Wright <john.wright@hp.com> |
| Message-ID: <1271199337-23284-2-git-send-email-john.wright@hp.com> |
| |
| 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 | 9 +++++---- |
| 1 file changed, 5 insertions(+), 4 deletions(-) |
| |
| --- a/kernel/sched.c |
| +++ b/kernel/sched.c |
| @@ -2116,12 +2116,10 @@ migrate_task(struct task_struct *p, int |
| |
| /* |
| * 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_st |
| /* 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; |