From: Ingo Molnar - remove the hotplug lock from around much of fork(), and re-copy the cpus_allowed mask to solve the hotplug race cleanly. Signed-off-by: Ingo Molnar Signed-off-by: Srivatsa Vaddagiri Signed-off-by: Andrew Morton --- 25-akpm/kernel/fork.c | 22 +++++++++++----------- 25-akpm/kernel/sched.c | 14 +------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff -puN kernel/fork.c~sched-fork-hotplug-cleanuppatch kernel/fork.c --- 25/kernel/fork.c~sched-fork-hotplug-cleanuppatch 2004-07-13 13:17:32.675467104 -0700 +++ 25-akpm/kernel/fork.c 2004-07-13 13:17:32.681466192 -0700 @@ -892,16 +892,6 @@ struct task_struct *copy_process(unsigne if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) return ERR_PTR(-EINVAL); - /* - * The newly dup'ed task shares the same cpus_allowed mask as its - * parent (ie. current), and it is not attached to the tasklist. - * The end result is that this CPU might go down and the parent - * be migrated away, leaving the task on a dead CPU. So take the - * hotplug lock here and release it after the child has been attached - * to the tasklist. - */ - lock_cpu_hotplug(); - retval = security_task_create(clone_flags); if (retval) goto fork_out; @@ -1043,6 +1033,17 @@ struct task_struct *copy_process(unsigne /* Need tasklist lock for parent etc handling! */ write_lock_irq(&tasklist_lock); + + /* + * The task hasn't been attached yet, so cpus_allowed mask cannot + * have changed. The cpus_allowed mask of the parent may have + * changed after it was copied first time, and it may then move to + * another CPU - so we re-copy it here and set the child's CPU to + * the parent's CPU. This avoids alot of nasty races. + */ + p->cpus_allowed = current->cpus_allowed; + set_task_cpu(p, smp_processor_id()); + /* * Check for pending SIGKILL! The new thread should not be allowed * to slip out of an OOM kill. (or normal SIGKILL.) @@ -1108,7 +1109,6 @@ struct task_struct *copy_process(unsigne retval = 0; fork_out: - unlock_cpu_hotplug(); if (retval) return ERR_PTR(retval); return p; diff -puN kernel/sched.c~sched-fork-hotplug-cleanuppatch kernel/sched.c --- 25/kernel/sched.c~sched-fork-hotplug-cleanuppatch 2004-07-13 13:17:32.677466800 -0700 +++ 25-akpm/kernel/sched.c 2004-07-13 13:17:32.684465736 -0700 @@ -873,22 +873,10 @@ static int find_idlest_cpu(struct task_s /* * Perform scheduler related setup for a newly forked process p. - * p is forked by current. The cpu hotplug lock is held. + * p is forked by current. */ void fastcall sched_fork(task_t *p) { - int cpu = smp_processor_id(); - - /* - * The task hasn't been attached yet, so cpus_allowed mask cannot - * change. The cpus_allowed mask of the parent may have changed - * after it is copied, and it may then move to a CPU that is not - * allowed for the child. - */ - if (unlikely(!cpu_isset(cpu, p->cpus_allowed))) - cpu = any_online_cpu(p->cpus_allowed); - set_task_cpu(p, cpu); - /* * We mark the process as running here, but have not actually * inserted it onto the runqueue yet. This guarantees that _