From: William Lee Irwin III <wli@holomorphy.com>

It appears that init_idle() and fork_by_hand() could be combined into a
single method that calls init_idle() on behalf of the caller.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/alpha/kernel/smp.c              |   14 +-------------
 25-akpm/arch/i386/kernel/smpboot.c           |   20 +-------------------
 25-akpm/arch/i386/mach-voyager/voyager_smp.c |   18 +-----------------
 25-akpm/arch/ia64/kernel/smpboot.c           |   27 ++++++---------------------
 25-akpm/arch/mips/kernel/smp.c               |   18 +-----------------
 25-akpm/arch/parisc/kernel/smp.c             |   22 +---------------------
 25-akpm/arch/ppc/kernel/smp.c                |    7 +------
 25-akpm/arch/ppc64/kernel/smp.c              |   10 +---------
 25-akpm/arch/s390/kernel/smp.c               |   11 +----------
 25-akpm/arch/sh/kernel/smp.c                 |    7 +------
 25-akpm/arch/sparc/kernel/sun4d_smp.c        |   11 +----------
 25-akpm/arch/sparc64/kernel/smp.c            |    9 +--------
 25-akpm/arch/x86_64/kernel/smpboot.c         |   18 +-----------------
 25-akpm/include/linux/sched.h                |    2 +-
 25-akpm/init/main.c                          |    9 ---------
 25-akpm/kernel/fork.c                        |   16 +++++++++++++++-
 25-akpm/kernel/sched.c                       |    8 ++++++++
 arch/um/kernel/smp.c                         |    0 
 18 files changed, 42 insertions(+), 185 deletions(-)

diff -puN arch/alpha/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/alpha/kernel/smp.c
--- 25/arch/alpha/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.342841064 -0700
+++ 25-akpm/arch/alpha/kernel/smp.c	2004-08-15 22:47:26.385834528 -0700
@@ -411,15 +411,6 @@ secondary_cpu_start(int cpuid, struct ta
 	return 0;
 }
 
-static struct task_struct * __init
-fork_by_hand(void)
-{
-	/* Don't care about the contents of regs since we'll never
-	   reschedule the forked task. */
-	struct pt_regs regs;
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
 /*
  * Bring one cpu online.
  */
@@ -435,13 +426,10 @@ smp_boot_one_cpu(int cpuid)
 	   the other task-y sort of data structures set up like we
 	   wish.  We can't use kernel_thread since we must avoid
 	   rescheduling the child.  */
-	idle = fork_by_hand();
+	idle = fork_idle(cpuid);
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpuid);
 
-	init_idle(idle, cpuid);
-	unhash_process(idle);
-
 	DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
 	      cpuid, idle->state, idle->flags));
 
diff -puN arch/i386/kernel/smpboot.c~sched-init_idle-fork_by_hand-consolidation arch/i386/kernel/smpboot.c
--- 25/arch/i386/kernel/smpboot.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.344840760 -0700
+++ 25-akpm/arch/i386/kernel/smpboot.c	2004-08-15 22:47:26.387834224 -0700
@@ -496,16 +496,6 @@ extern struct {
 	unsigned short ss;
 } stack_start;
 
-static struct task_struct * __init fork_by_hand(void)
-{
-	struct pt_regs regs;
-	/*
-	 * don't care about the eip and regs settings since
-	 * we'll never reschedule the forked task.
-	 */
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
 #ifdef CONFIG_NUMA
 
 /* which logical CPUs are on which nodes */
@@ -801,18 +791,10 @@ static int __init do_boot_cpu(int apicid
 	 * We can't use kernel_thread since we must avoid to
 	 * reschedule the child.
 	 */
-	idle = fork_by_hand();
+	idle = fork_idle(cpu);
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpu);
-
-	/* Make this the idle thread */
-	init_idle(idle, cpu);
-
 	idle->thread.eip = (unsigned long) start_secondary;
-
-	/* Remove it from the pidhash */
-	unhash_process(idle);
-
 	/* start_eip had better be page-aligned! */
 	start_eip = setup_trampoline();
 
diff -puN arch/i386/mach-voyager/voyager_smp.c~sched-init_idle-fork_by_hand-consolidation arch/i386/mach-voyager/voyager_smp.c
--- 25/arch/i386/mach-voyager/voyager_smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.345840608 -0700
+++ 25-akpm/arch/i386/mach-voyager/voyager_smp.c	2004-08-15 22:47:26.388834072 -0700
@@ -523,15 +523,6 @@ start_secondary(void *unused)
 	return cpu_idle();
 }
 
-static struct task_struct * __init
-fork_by_hand(void)
-{
-	struct pt_regs regs;
-	/* don't care about the eip and regs settings since we'll
-	 * never reschedule the forked task. */
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
 
 /* Routine to kick start the given CPU and wait for it to report ready
  * (or timeout in startup).  When this routine returns, the requested
@@ -587,17 +578,10 @@ do_boot_cpu(__u8 cpu)
 	hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
 
 	cpucount++;
-	idle = fork_by_hand();
+	idle = fork_idle(cpu);
 	if(IS_ERR(idle))
 		panic("failed fork for CPU%d", cpu);
-
-	/* Make this the idle thread */
-	init_idle(idle, cpu);
-
 	idle->thread.eip = (unsigned long) start_secondary;
-
-	/* Remove it from the pidhash */
-	unhash_process(idle);
 	/* init_tasks (in sched.c) is indexed logically */
 	stack_start.esp = (void *) idle->thread.esp;
 
diff -puN arch/ia64/kernel/smpboot.c~sched-init_idle-fork_by_hand-consolidation arch/ia64/kernel/smpboot.c
--- 25/arch/ia64/kernel/smpboot.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.347840304 -0700
+++ 25-akpm/arch/ia64/kernel/smpboot.c	2004-08-15 22:47:26.389833920 -0700
@@ -356,19 +356,10 @@ start_secondary (void *unused)
 	return cpu_idle();
 }
 
-static struct task_struct * __devinit
-fork_by_hand (void)
-{
-	/*
-	 * Don't care about the IP and regs settings since we'll never reschedule the
-	 * forked task.
-	 */
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL);
-}
-
 struct create_idle {
 	struct task_struct *idle;
 	struct completion done;
+	int cpu;
 };
 
 void
@@ -376,7 +367,7 @@ do_fork_idle(void *_c_idle)
 {
 	struct create_idle *c_idle = _c_idle;
 
-	c_idle->idle = fork_by_hand();
+	c_idle->idle = fork_idle(c_idle->cpu);
 	complete(&c_idle->done);
 }
 
@@ -384,10 +375,11 @@ static int __devinit
 do_boot_cpu (int sapicid, int cpu)
 {
 	int timeout;
-	struct create_idle c_idle;
+	struct create_idle c_idle = {
+		.cpu	= cpu,
+		.done	= COMPLETION_INITIALIZER(c_idle.done),
+	};
 	DECLARE_WORK(work, do_fork_idle, &c_idle);
-
-	init_completion(&c_idle.done);
 	/*
 	 * We can't use kernel_thread since we must avoid to reschedule the child.
 	 */
@@ -400,13 +392,6 @@ do_boot_cpu (int sapicid, int cpu)
 
 	if (IS_ERR(c_idle.idle))
 		panic("failed fork for CPU %d", cpu);
-
-	/* Make this the idle thread */
-	init_idle(c_idle.idle, cpu);
-
-	/* Remove it from the pidhash */
-	unhash_process(c_idle.idle);
-
 	task_for_booting_cpu = c_idle.idle;
 
 	Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
diff -puN arch/mips/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/mips/kernel/smp.c
--- 25/arch/mips/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.348840152 -0700
+++ 25-akpm/arch/mips/kernel/smp.c	2004-08-15 22:47:26.390833768 -0700
@@ -254,16 +254,6 @@ void __devinit smp_prepare_boot_cpu(void
 	cpu_set(0, cpu_callin_map);
 }
 
-static struct task_struct * __init fork_by_hand(void)
-{
-	struct pt_regs regs;
-	/*
-	 * don't care about the eip and regs settings since
-	 * we'll never reschedule the forked task.
-	 */
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
 /*
  * Startup the CPU with this logical number
  */
@@ -275,16 +265,10 @@ static int __init do_boot_cpu(int cpu)
 	 * The following code is purely to make sure
 	 * Linux can schedule processes on this slave.
 	 */
-	idle = fork_by_hand();
+	idle = fork_idle(cpu);
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d\n", cpu);
 
-	/* Make this the idle thread */
-	init_idle(idle, cpu);
-
-	/* Remove it from the pidhash */
-	unhash_process(idle);
-
 	prom_boot_secondary(cpu, idle);
 
 	/* XXXKW timeout */
diff -puN arch/parisc/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/parisc/kernel/smp.c
--- 25/arch/parisc/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.349840000 -0700
+++ 25-akpm/arch/parisc/kernel/smp.c	2004-08-15 22:47:26.390833768 -0700
@@ -486,24 +486,6 @@ void __init smp_callin(void)
 }
 
 /*
- * Create the idle task for a new Slave CPU.  DO NOT use kernel_thread()
- * because that could end up calling schedule(). If it did, the new idle
- * task could get scheduled before we had a chance to remove it from the
- * run-queue...
- */
-static struct task_struct *fork_by_hand(void)
-{
-	struct pt_regs regs;  
-
-	/*
-	 * don't care about the regs settings since
-	 * we'll never reschedule the forked task.
-	 */
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
-
-/*
  * Bring one cpu online.
  */
 int __init smp_boot_one_cpu(int cpuid)
@@ -521,12 +503,10 @@ int __init smp_boot_one_cpu(int cpuid)
 	 * Sheesh . . .
 	 */
 
-	idle = fork_by_hand();
 	if (IS_ERR(idle))
 		panic("SMP: fork failed for CPU:%d", cpuid);
 
-	init_idle(idle, cpuid);
-	unhash_process(idle);
+	idle = fork_idle(cpunum);
 	idle->thread_info->cpu = cpuid;
 
 	/* Let _start know what logical CPU we're booting
diff -puN arch/ppc64/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/ppc64/kernel/smp.c
--- 25/arch/ppc64/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.351839696 -0700
+++ 25-akpm/arch/ppc64/kernel/smp.c	2004-08-15 22:47:26.391833616 -0700
@@ -799,20 +799,12 @@ static void __devinit smp_store_cpu_info
 
 static void __init smp_create_idle(unsigned int cpu)
 {
-	struct pt_regs regs;
 	struct task_struct *p;
 
 	/* create a process for the processor */
-	/* only regs.msr is actually used, and 0 is OK for it */
-	memset(&regs, 0, sizeof(struct pt_regs));
-	p = copy_process(CLONE_VM | CLONE_IDLETASK,
-			 0, &regs, 0, NULL, NULL);
+	p = fork_idle(cpu);
 	if (IS_ERR(p))
 		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
-
-	init_idle(p, cpu);
-	unhash_process(p);
-
 	paca[cpu].__current = p;
 	current_set[cpu] = p->thread_info;
 }
diff -puN arch/ppc/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/ppc/kernel/smp.c
--- 25/arch/ppc/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.352839544 -0700
+++ 25-akpm/arch/ppc/kernel/smp.c	2004-08-15 22:47:26.392833464 -0700
@@ -364,20 +364,15 @@ int __devinit start_secondary(void *unus
 
 int __cpu_up(unsigned int cpu)
 {
-	struct pt_regs regs;
 	struct task_struct *p;
 	char buf[32];
 	int c;
 
 	/* create a process for the processor */
 	/* only regs.msr is actually used, and 0 is OK for it */
-	memset(&regs, 0, sizeof(struct pt_regs));
-	p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	p = fork_idle(cpu);
 	if (IS_ERR(p))
 		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
-	init_idle(p, cpu);
-	unhash_process(p);
-
 	secondary_ti = p->thread_info;
 	p->thread_info->cpu = cpu;
 
diff -puN arch/s390/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/s390/kernel/smp.c
--- 25/arch/s390/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.354839240 -0700
+++ 25-akpm/arch/s390/kernel/smp.c	2004-08-15 22:47:26.393833312 -0700
@@ -562,24 +562,15 @@ int __devinit start_secondary(void *cpuv
 
 static void __init smp_create_idle(unsigned int cpu)
 {
-	struct pt_regs regs;
 	struct task_struct *p;
 
 	/*
 	 *  don't care about the psw and regs settings since we'll never
 	 *  reschedule the forked task.
 	 */
-	memset(&regs, 0, sizeof(struct pt_regs));
-	p = copy_process(CLONE_VM | CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	p = fork_idle(cpu);
 	if (IS_ERR(p))
 		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
-
-	/* Make this the idle thread */
-	init_idle(p, cpu);
-
-	/* Remove it from the pidhash */
-	unhash_process(p);
-
 	current_set[cpu] = p;
 }
 
diff -puN arch/sh/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/sh/kernel/smp.c
--- 25/arch/sh/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.355839088 -0700
+++ 25-akpm/arch/sh/kernel/smp.c	2004-08-15 22:47:26.393833312 -0700
@@ -98,17 +98,12 @@ void __devinit smp_prepare_boot_cpu(void
 int __cpu_up(unsigned int cpu)
 {
 	struct task_struct *tsk;
-	struct pt_regs regs;
 
-	memset(&regs, 0, sizeof(struct pt_regs));
-	tsk = copy_process(CLONE_VM | CLONE_IDLETASK, 0, &regs, 0, 0, 0);
+	tsk = fork_idle(cpu);
 
 	if (IS_ERR(tsk))
 		panic("Failed forking idle task for cpu %d\n", cpu);
 	
-	init_idle(tsk, cpu);
-	unhash_process(tsk);
-	
 	tsk->thread_info->cpu = cpu;
 
 	cpu_set(cpu, cpu_online_map);
diff -puN arch/sparc64/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/sparc64/kernel/smp.c
--- 25/arch/sparc64/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.356838936 -0700
+++ 25-akpm/arch/sparc64/kernel/smp.c	2004-08-15 22:47:26.394833160 -0700
@@ -303,14 +303,7 @@ static int __devinit smp_boot_one_cpu(un
 	struct task_struct *p;
 	int timeout, ret, cpu_node;
 
-	kernel_thread(NULL, NULL, CLONE_IDLETASK);
-
-	p = prev_task(&init_task);
-
-	init_idle(p, cpu);
-
-	unhash_process(p);
-
+	p = fork_idle(cpu);
 	callin_flag = 0;
 	cpu_new_thread = p->thread_info;
 	cpu_set(cpu, cpu_callout_map);
diff -puN arch/sparc/kernel/sun4d_smp.c~sched-init_idle-fork_by_hand-consolidation arch/sparc/kernel/sun4d_smp.c
--- 25/arch/sparc/kernel/sun4d_smp.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.358838632 -0700
+++ 25-akpm/arch/sparc/kernel/sun4d_smp.c	2004-08-15 22:47:26.395833008 -0700
@@ -201,18 +201,9 @@ void __init smp4d_boot_cpus(void)
 			int no;
 
 			/* Cook up an idler for this guy. */
-			kernel_thread(start_secondary, NULL, CLONE_IDLETASK);
-
+			p = fork_idle(p, cpu);
 			cpucount++;
-
-			p = prev_task(&init_task);
-
-			init_idle(p, i);
-
 			current_set[i] = p->thread_info;
-
-			unhash_process(p);
-
 			for (no = 0; !cpu_find_by_instance(no, NULL, &mid)
 				     && mid != i; no++) ;
 
diff -puN arch/um/kernel/smp.c~sched-init_idle-fork_by_hand-consolidation arch/um/kernel/smp.c
diff -puN arch/x86_64/kernel/smpboot.c~sched-init_idle-fork_by_hand-consolidation arch/x86_64/kernel/smpboot.c
--- 25/arch/x86_64/kernel/smpboot.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.376835896 -0700
+++ 25-akpm/arch/x86_64/kernel/smpboot.c	2004-08-15 22:47:26.396832856 -0700
@@ -392,16 +392,6 @@ void __init start_secondary(void)
 extern volatile unsigned long init_rsp; 
 extern void (*initial_code)(void);
 
-static struct task_struct * __init fork_by_hand(void)
-{
-	struct pt_regs regs;
-	/*
-	 * don't care about the eip and regs settings since
-	 * we'll never reschedule the forked task.
-	 */
-	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
 #if APIC_DEBUG
 static inline void inquire_remote_apic(int apicid)
 {
@@ -575,17 +565,11 @@ static void __init do_boot_cpu (int apic
 	 * We can't use kernel_thread since we must avoid to
 	 * reschedule the child.
 	 */
-	idle = fork_by_hand();
+	idle = fork_idle(cpu);
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpu);
 	x86_cpu_to_apicid[cpu] = apicid;
 
-	/* Make this the idle thread */
-	init_idle(idle,cpu);
-
-	/* Remove it from the pidhash */
-	unhash_process(idle);
-
 	cpu_pda[cpu].pcurrent = idle;
 
 	start_rip = setup_trampoline();
diff -puN include/linux/sched.h~sched-init_idle-fork_by_hand-consolidation include/linux/sched.h
--- 25/include/linux/sched.h~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.377835744 -0700
+++ 25-akpm/include/linux/sched.h	2004-08-15 22:47:26.397832704 -0700
@@ -788,7 +788,7 @@ extern task_t *child_reaper;
 
 extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
 extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
-extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
+task_t *fork_idle(int);
 
 extern void set_task_comm(struct task_struct *tsk, char *from);
 extern void get_task_comm(char *to, struct task_struct *tsk);
diff -puN init/main.c~sched-init_idle-fork_by_hand-consolidation init/main.c
--- 25/init/main.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.378835592 -0700
+++ 25-akpm/init/main.c	2004-08-15 22:47:26.397832704 -0700
@@ -470,15 +470,6 @@ asmlinkage void __init start_kernel(void
 	 * time - but meanwhile we still have a functioning scheduler.
 	 */
 	sched_init();
-
-	/*
-	 * Make us the idle thread. Technically, schedule() should not be
-	 * called from this thread, however somewhere below it might be,
-	 * but because we are the idle thread, we just pick up running again
-	 * when this runqueue becomes "idle".
-	 */
-	init_idle(current, smp_processor_id());
-
 	build_all_zonelists();
 	page_alloc_init();
 	trap_init();
diff -puN kernel/fork.c~sched-init_idle-fork_by_hand-consolidation kernel/fork.c
--- 25/kernel/fork.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.380835288 -0700
+++ 25-akpm/kernel/fork.c	2004-08-15 22:47:26.398832552 -0700
@@ -864,7 +864,7 @@ asmlinkage long sys_set_tid_address(int 
  * parts of the process environment (as per the clone
  * flags). The actual kick-off is left to the caller.
  */
-struct task_struct *copy_process(unsigned long clone_flags,
+static task_t *copy_process(unsigned long clone_flags,
 				 unsigned long stack_start,
 				 struct pt_regs *regs,
 				 unsigned long stack_size,
@@ -1152,6 +1152,20 @@ bad_fork_free:
 	goto fork_out;
 }
 
+task_t * __init fork_idle(int cpu)
+{
+	task_t *task;
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(struct pt_regs));
+	task = copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	if (!task)
+		return ERR_PTR(-ENOMEM);
+	init_idle(task, cpu);
+	unhash_process(task);
+	return task;
+}
+
 static inline int fork_traceflag (unsigned clone_flags)
 {
 	if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK))
diff -puN kernel/sched.c~sched-init_idle-fork_by_hand-consolidation kernel/sched.c
--- 25/kernel/sched.c~sched-init_idle-fork_by_hand-consolidation	2004-08-15 22:47:26.382834984 -0700
+++ 25-akpm/kernel/sched.c	2004-08-15 22:47:26.402831944 -0700
@@ -4535,6 +4535,14 @@ void __init sched_init(void)
 	 */
 	atomic_inc(&init_mm.mm_count);
 	enter_lazy_tlb(&init_mm, current);
+
+	/*
+	 * Make us the idle thread. Technically, schedule() should not be
+	 * called from this thread, however somewhere below it might be,
+	 * but because we are the idle thread, we just pick up running again
+	 * when this runqueue becomes "idle".
+	 */
+	init_idle(current, smp_processor_id());
 }
 
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
_