aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKirill Korotaev <dev@sw.ru>2006-06-27 05:54:32 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-27 20:32:44 -0400
commitefc30814a88bdbe2bfe4ac94de2eb089ad80bee3 (patch)
tree1134d7ccda13c09cf426af0524c13633292eac5b /kernel
parentcc94abfcbc9fed0048365ce1fb8dc81353408bf8 (diff)
[PATCH] sched: CPU hotplug race vs. set_cpus_allowed()
There is a race between set_cpus_allowed() and move_task_off_dead_cpu(). __migrate_task() doesn't report any err code, so task can be left on its runqueue if its cpus_allowed mask changed so that dest_cpu is not longer a possible target. Also, chaning cpus_allowed mask requires rq->lock being held. Signed-off-by: Kirill Korotaev <dev@openvz.org> Acked-By: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 235c421631d..678335a8b39 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4412,13 +4412,16 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed);
4412 * 4412 *
4413 * So we race with normal scheduler movements, but that's OK, as long 4413 * So we race with normal scheduler movements, but that's OK, as long
4414 * as the task is no longer on this CPU. 4414 * as the task is no longer on this CPU.
4415 *
4416 * Returns non-zero if task was successfully migrated.
4415 */ 4417 */
4416static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) 4418static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
4417{ 4419{
4418 runqueue_t *rq_dest, *rq_src; 4420 runqueue_t *rq_dest, *rq_src;
4421 int ret = 0;
4419 4422
4420 if (unlikely(cpu_is_offline(dest_cpu))) 4423 if (unlikely(cpu_is_offline(dest_cpu)))
4421 return; 4424 return ret;
4422 4425
4423 rq_src = cpu_rq(src_cpu); 4426 rq_src = cpu_rq(src_cpu);
4424 rq_dest = cpu_rq(dest_cpu); 4427 rq_dest = cpu_rq(dest_cpu);
@@ -4446,9 +4449,10 @@ static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
4446 if (TASK_PREEMPTS_CURR(p, rq_dest)) 4449 if (TASK_PREEMPTS_CURR(p, rq_dest))
4447 resched_task(rq_dest->curr); 4450 resched_task(rq_dest->curr);
4448 } 4451 }
4449 4452 ret = 1;
4450out: 4453out:
4451 double_rq_unlock(rq_src, rq_dest); 4454 double_rq_unlock(rq_src, rq_dest);
4455 return ret;
4452} 4456}
4453 4457
4454/* 4458/*
@@ -4518,9 +4522,12 @@ wait_to_die:
4518/* Figure out where task on dead CPU should go, use force if neccessary. */ 4522/* Figure out where task on dead CPU should go, use force if neccessary. */
4519static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk) 4523static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
4520{ 4524{
4525 runqueue_t *rq;
4526 unsigned long flags;
4521 int dest_cpu; 4527 int dest_cpu;
4522 cpumask_t mask; 4528 cpumask_t mask;
4523 4529
4530restart:
4524 /* On same node? */ 4531 /* On same node? */
4525 mask = node_to_cpumask(cpu_to_node(dead_cpu)); 4532 mask = node_to_cpumask(cpu_to_node(dead_cpu));
4526 cpus_and(mask, mask, tsk->cpus_allowed); 4533 cpus_and(mask, mask, tsk->cpus_allowed);
@@ -4532,8 +4539,10 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
4532 4539
4533 /* No more Mr. Nice Guy. */ 4540 /* No more Mr. Nice Guy. */
4534 if (dest_cpu == NR_CPUS) { 4541 if (dest_cpu == NR_CPUS) {
4542 rq = task_rq_lock(tsk, &flags);
4535 cpus_setall(tsk->cpus_allowed); 4543 cpus_setall(tsk->cpus_allowed);
4536 dest_cpu = any_online_cpu(tsk->cpus_allowed); 4544 dest_cpu = any_online_cpu(tsk->cpus_allowed);
4545 task_rq_unlock(rq, &flags);
4537 4546
4538 /* 4547 /*
4539 * Don't tell them about moving exiting tasks or 4548 * Don't tell them about moving exiting tasks or
@@ -4545,7 +4554,8 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
4545 "longer affine to cpu%d\n", 4554 "longer affine to cpu%d\n",
4546 tsk->pid, tsk->comm, dead_cpu); 4555 tsk->pid, tsk->comm, dead_cpu);
4547 } 4556 }
4548 __migrate_task(tsk, dead_cpu, dest_cpu); 4557 if (!__migrate_task(tsk, dead_cpu, dest_cpu))
4558 goto restart;
4549} 4559}
4550 4560
4551/* 4561/*