Commit 27568369 authored by Rusty Russell's avatar Rusty Russell Committed by David Woodhouse

[PATCH] Hotplug CPU prep

This changes do_fork() to return the task struct, rather than the PID.

Also changes CLONE_PID ("if my pid is 0, copy it") to CLONE_IDLETASK
("set child's pid to zero"), and disallows access to the flag from user
mode.
parent 5e8a4a7d
...@@ -260,16 +260,22 @@ int ...@@ -260,16 +260,22 @@ int
alpha_clone(unsigned long clone_flags, unsigned long usp, alpha_clone(unsigned long clone_flags, unsigned long usp,
struct switch_stack * swstack) struct switch_stack * swstack)
{ {
struct task_struct *p;
if (!usp) if (!usp)
usp = rdusp(); usp = rdusp();
return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1), 0);
p = do_fork(clone_flags & ~CLONE_IDLETASK,
usp, (struct pt_regs *) (swstack+1), 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int int
alpha_vfork(struct switch_stack * swstack) alpha_vfork(struct switch_stack * swstack)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), struct task_struct *p;
(struct pt_regs *) (swstack+1), 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(),
(struct pt_regs *) (swstack+1), 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -433,13 +433,13 @@ secondary_cpu_start(int cpuid, struct task_struct *idle) ...@@ -433,13 +433,13 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
return 0; return 0;
} }
static int __init static struct task_struct * __init
fork_by_hand(void) fork_by_hand(void)
{ {
/* Don't care about the contents of regs since we'll never /* Don't care about the contents of regs since we'll never
reschedule the forked task. */ reschedule the forked task. */
struct pt_regs regs; struct pt_regs regs;
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0); return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
} }
/* /*
...@@ -457,13 +457,10 @@ smp_boot_one_cpu(int cpuid, int cpunum) ...@@ -457,13 +457,10 @@ smp_boot_one_cpu(int cpuid, int cpunum)
the other task-y sort of data structures set up like we the other task-y sort of data structures set up like we
wish. We can't use kernel_thread since we must avoid wish. We can't use kernel_thread since we must avoid
rescheduling the child. */ rescheduling the child. */
if (fork_by_hand() < 0) idle = fork_by_hand();
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpuid); panic("failed fork for CPU %d", cpuid);
idle = prev_task(&init_task);
if (!idle)
panic("No idle process for CPU %d", cpuid);
init_idle(idle, cpuid); init_idle(idle, cpuid);
unhash_process(idle); unhash_process(idle);
......
...@@ -238,7 +238,9 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, ...@@ -238,7 +238,9 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
*/ */
asmlinkage int sys_fork(struct pt_regs *regs) asmlinkage int sys_fork(struct pt_regs *regs)
{ {
return do_fork(SIGCHLD, regs->ARM_sp, regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs->ARM_sp, regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* Clone a task - this clones the calling program thread. /* Clone a task - this clones the calling program thread.
...@@ -246,14 +248,18 @@ asmlinkage int sys_fork(struct pt_regs *regs) ...@@ -246,14 +248,18 @@ asmlinkage int sys_fork(struct pt_regs *regs)
*/ */
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
{ {
struct task_struct *p;
if (!newsp) if (!newsp)
newsp = regs->ARM_sp; newsp = regs->ARM_sp;
return do_fork(clone_flags, newsp, regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys_vfork(struct pt_regs *regs) asmlinkage int sys_vfork(struct pt_regs *regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* sys_execve() executes a new program. /* sys_execve() executes a new program.
......
...@@ -299,7 +299,9 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) ...@@ -299,7 +299,9 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
struct pt_regs *regs) struct pt_regs *regs)
{ {
return do_fork(SIGCHLD, rdusp(), regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, rdusp(), regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* if newusp is 0, we just grab the old usp */ /* if newusp is 0, we just grab the old usp */
...@@ -308,9 +310,11 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, ...@@ -308,9 +310,11 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
long r12, long r13, long mof, long srp, long r12, long r13, long mof, long srp,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct task_struct *p;
if (!newusp) if (!newusp)
newusp = rdusp(); newusp = rdusp();
return do_fork(flags, newusp, regs, 0); p = do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* vfork is a system call in i386 because of register-pressure - maybe /* vfork is a system call in i386 because of register-pressure - maybe
...@@ -320,7 +324,9 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, ...@@ -320,7 +324,9 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
struct pt_regs *regs) struct pt_regs *regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -711,11 +711,15 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) ...@@ -711,11 +711,15 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
asmlinkage int sys_fork(struct pt_regs regs) asmlinkage int sys_fork(struct pt_regs regs)
{ {
return do_fork(SIGCHLD, regs.esp, &regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs.esp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys_clone(struct pt_regs regs) asmlinkage int sys_clone(struct pt_regs regs)
{ {
struct task_struct *p;
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
...@@ -723,7 +727,8 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -723,7 +727,8 @@ asmlinkage int sys_clone(struct pt_regs regs)
newsp = regs.ecx; newsp = regs.ecx;
if (!newsp) if (!newsp)
newsp = regs.esp; newsp = regs.esp;
return do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
...@@ -738,7 +743,10 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -738,7 +743,10 @@ asmlinkage int sys_clone(struct pt_regs regs)
*/ */
asmlinkage int sys_vfork(struct pt_regs regs) asmlinkage int sys_vfork(struct pt_regs regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -529,14 +529,14 @@ extern struct { ...@@ -529,14 +529,14 @@ extern struct {
unsigned short ss; unsigned short ss;
} stack_start; } stack_start;
static int __init fork_by_hand(void) static struct task_struct * __init fork_by_hand(void)
{ {
struct pt_regs regs; struct pt_regs regs;
/* /*
* don't care about the eip and regs settings since * don't care about the eip and regs settings since
* we'll never reschedule the forked task. * we'll never reschedule the forked task.
*/ */
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0); return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
} }
/* which physical APIC ID maps to which logical CPU number */ /* which physical APIC ID maps to which logical CPU number */
...@@ -822,17 +822,14 @@ static void __init do_boot_cpu (int apicid) ...@@ -822,17 +822,14 @@ static void __init do_boot_cpu (int apicid)
* We can't use kernel_thread since we must avoid to * We can't use kernel_thread since we must avoid to
* reschedule the child. * reschedule the child.
*/ */
if (fork_by_hand() < 0) idle = fork_by_hand();
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu); panic("failed fork for CPU %d", cpu);
/* /*
* We remove it from the pidhash and the runqueue * We remove it from the pidhash and the runqueue
* once we got the process: * once we got the process:
*/ */
idle = prev_task(&init_task);
if (!idle)
panic("No idle process for CPU %d", cpu);
init_idle(idle, cpu); init_idle(idle, cpu);
map_cpu_to_boot_apicid(cpu, apicid); map_cpu_to_boot_apicid(cpu, apicid);
......
...@@ -41,7 +41,7 @@ ENTRY(ia32_clone) ...@@ -41,7 +41,7 @@ ENTRY(ia32_clone)
mov out3=16 // stacksize (compensates for 16-byte scratch area) mov out3=16 // stacksize (compensates for 16-byte scratch area)
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
zxt4 out0=in0 // out0 = clone_flags zxt4 out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork br.call.sptk.many rp=do_fork_WITHOUT_CLONE_IDLETASK // FIXME: mask out CLONE_IDLETASK from flags, and return value now task_struct *.
.ret0: .restore sp .ret0: .restore sp
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
mov ar.pfs=loc1 mov ar.pfs=loc1
...@@ -167,7 +167,7 @@ GLOBAL_ENTRY(sys32_fork) ...@@ -167,7 +167,7 @@ GLOBAL_ENTRY(sys32_fork)
mov out1=0 mov out1=0
mov out3=0 mov out3=0
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
br.call.sptk.few rp=do_fork br.call.sptk.few rp=do_fork_FIXME_RETURNS_TASK_STRUCT
.ret5: mov ar.pfs=loc1 .ret5: mov ar.pfs=loc1
.restore sp .restore sp
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
......
...@@ -101,7 +101,7 @@ GLOBAL_ENTRY(sys_clone2) ...@@ -101,7 +101,7 @@ GLOBAL_ENTRY(sys_clone2)
mov out3=in2 mov out3=in2
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
mov out0=in0 // out0 = clone_flags mov out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork br.call.sptk.many rp=do_fork_WITHOUT_CLONE_IDLETASK // FIXME: mask out CLONE_IDLETASK from flags, and now returns task_struct *.
.ret1: .restore sp .ret1: .restore sp
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
mov ar.pfs=loc1 mov ar.pfs=loc1
...@@ -120,7 +120,7 @@ GLOBAL_ENTRY(sys_clone) ...@@ -120,7 +120,7 @@ GLOBAL_ENTRY(sys_clone)
mov out3=16 // stacksize (compensates for 16-byte scratch area) mov out3=16 // stacksize (compensates for 16-byte scratch area)
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
mov out0=in0 // out0 = clone_flags mov out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork br.call.sptk.many rp=do_fork_WITHOUT_CLONE_IDLETASK // FIXME: mask out CLONE_IDLETASK from flags, and now return task_struct *.
.ret2: .restore sp .ret2: .restore sp
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
mov ar.pfs=loc1 mov ar.pfs=loc1
......
...@@ -391,14 +391,14 @@ start_secondary (void *unused) ...@@ -391,14 +391,14 @@ start_secondary (void *unused)
return cpu_idle(); return cpu_idle();
} }
static int __init static struct task_struct * __init
fork_by_hand (void) fork_by_hand (void)
{ {
/* /*
* don't care about the eip and regs settings since * don't care about the eip and regs settings since
* we'll never reschedule the forked task. * we'll never reschedule the forked task.
*/ */
return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0); return do_fork(CLONE_VM|CLONE_IDLETASK, 0, 0, 0);
} }
static void __init static void __init
...@@ -412,17 +412,14 @@ do_boot_cpu (int sapicid) ...@@ -412,17 +412,14 @@ do_boot_cpu (int sapicid)
* We can't use kernel_thread since we must avoid to * We can't use kernel_thread since we must avoid to
* reschedule the child. * reschedule the child.
*/ */
if (fork_by_hand() < 0) idle = fork_by_hand();
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu); panic("failed fork for CPU %d", cpu);
/* /*
* We remove it from the pidhash and the runqueue * We remove it from the pidhash and the runqueue
* once we got the process: * once we got the process:
*/ */
idle = prev_task(&init_task);
if (!idle)
panic("No idle process for CPU %d", cpu);
init_idle(idle, cpu); init_idle(idle, cpu);
ia64_cpu_to_sapicid[cpu] = sapicid; ia64_cpu_to_sapicid[cpu] = sapicid;
......
...@@ -177,25 +177,31 @@ void flush_thread(void) ...@@ -177,25 +177,31 @@ void flush_thread(void)
asmlinkage int m68k_fork(struct pt_regs *regs) asmlinkage int m68k_fork(struct pt_regs *regs)
{ {
return do_fork(SIGCHLD, rdusp(), regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, rdusp(), regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int m68k_vfork(struct pt_regs *regs) asmlinkage int m68k_vfork(struct pt_regs *regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int m68k_clone(struct pt_regs *regs) asmlinkage int m68k_clone(struct pt_regs *regs)
{ {
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
struct task_struct *p;
/* syscall2 puts clone_flags in d1 and usp in d2 */ /* syscall2 puts clone_flags in d1 and usp in d2 */
clone_flags = regs->d1; clone_flags = regs->d1;
newsp = regs->d2; newsp = regs->d2;
if (!newsp) if (!newsp)
newsp = rdusp(); newsp = rdusp();
return do_fork(clone_flags, newsp, regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
......
...@@ -122,8 +122,7 @@ void __init smp_boot_cpus(void) ...@@ -122,8 +122,7 @@ void __init smp_boot_cpus(void)
/* Spawn a new process normally. Grab a pointer to /* Spawn a new process normally. Grab a pointer to
its task struct so we can mess with it */ its task struct so we can mess with it */
do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0); p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
p = prev_task(&init_task);
/* Schedule the first task manually */ /* Schedule the first task manually */
p->processor = i; p->processor = i;
...@@ -151,7 +150,7 @@ void __init smp_boot_cpus(void) ...@@ -151,7 +150,7 @@ void __init smp_boot_cpus(void)
* The following code is purely to make sure * The following code is purely to make sure
* Linux can schedule processes on this slave. * Linux can schedule processes on this slave.
*/ */
kernel_thread(0, NULL, CLONE_PID); kernel_thread(0, NULL, CLONE_IDLETASK);
p = prev_task(&init_task); p = prev_task(&init_task);
sprintf(p->comm, "%s%d", "Idle", i); sprintf(p->comm, "%s%d", "Idle", i);
init_tasks[i] = p; init_tasks[i] = p;
......
...@@ -95,10 +95,10 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, ...@@ -95,10 +95,10 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
save_static_function(sys_fork); save_static_function(sys_fork);
static_unused int _sys_fork(struct pt_regs regs) static_unused int _sys_fork(struct pt_regs regs)
{ {
int res; struct task_struct *p;
res = do_fork(SIGCHLD, regs.regs[29], &regs, 0); p = do_fork(SIGCHLD, regs.regs[29], &regs, 0);
return res; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -107,14 +107,14 @@ static_unused int _sys_clone(struct pt_regs regs) ...@@ -107,14 +107,14 @@ static_unused int _sys_clone(struct pt_regs regs)
{ {
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
int res; struct task_struct *p;
clone_flags = regs.regs[4]; clone_flags = regs.regs[4];
newsp = regs.regs[5]; newsp = regs.regs[5];
if (!newsp) if (!newsp)
newsp = regs.regs[29]; newsp = regs.regs[29];
res = do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return res; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -77,26 +77,26 @@ sys_mmap(unsigned long addr, size_t len, unsigned long prot, ...@@ -77,26 +77,26 @@ sys_mmap(unsigned long addr, size_t len, unsigned long prot,
asmlinkage int sys_fork(abi64_no_regargs, struct pt_regs regs) asmlinkage int sys_fork(abi64_no_regargs, struct pt_regs regs)
{ {
int res; struct task_struct *p;
save_static(&regs); save_static(&regs);
res = do_fork(SIGCHLD, regs.regs[29], &regs, 0); p = do_fork(SIGCHLD, regs.regs[29], &regs, 0);
return res; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys_clone(abi64_no_regargs, struct pt_regs regs) asmlinkage int sys_clone(abi64_no_regargs, struct pt_regs regs)
{ {
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
int res; struct task_struct *p;
save_static(&regs); save_static(&regs);
clone_flags = regs.regs[4]; clone_flags = regs.regs[4];
newsp = regs.regs[5]; newsp = regs.regs[5];
if (!newsp) if (!newsp)
newsp = regs.regs[29]; newsp = regs.regs[29];
res = do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return res; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -490,7 +490,7 @@ void allowboot(void) ...@@ -490,7 +490,7 @@ void allowboot(void)
* The following code is purely to make sure * The following code is purely to make sure
* Linux can schedule processes on this slave. * Linux can schedule processes on this slave.
*/ */
kernel_thread(0, NULL, CLONE_PID); kernel_thread(0, NULL, CLONE_IDLETASK);
p = prev_task(&init_task); p = prev_task(&init_task);
sprintf(p->comm, "%s%d", "Idle", num_cpus); sprintf(p->comm, "%s%d", "Idle", num_cpus);
init_tasks[num_cpus] = p; init_tasks[num_cpus] = p;
......
...@@ -500,7 +500,7 @@ __kernel_thread: ...@@ -500,7 +500,7 @@ __kernel_thread:
ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */ ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */
or %r26, %r24, %r26 /* will have kernel mappings. */ or %r26, %r24, %r26 /* will have kernel mappings. */
copy %r0, %r25 copy %r0, %r25
bl do_fork, %r2 bl do_fork_FIXME_NOW_RETURNS_TASK_STRUCT, %r2
copy %r1, %r24 copy %r1, %r24
/* Parent Returns here */ /* Parent Returns here */
......
...@@ -159,14 +159,17 @@ int ...@@ -159,14 +159,17 @@ int
sys_clone(unsigned long clone_flags, unsigned long usp, sys_clone(unsigned long clone_flags, unsigned long usp,
struct pt_regs *regs) struct pt_regs *regs)
{ {
return do_fork(clone_flags, usp, regs, 0); struct task_struct *p;
p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int int
sys_vfork(struct pt_regs *regs) sys_vfork(struct pt_regs *regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, struct task_struct *p;
regs->gr[30], regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int int
......
...@@ -437,22 +437,28 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val) ...@@ -437,22 +437,28 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct task_struct *p;
CHECK_FULL_REGS(regs); CHECK_FULL_REGS(regs);
return do_fork(p1, regs->gpr[1], regs, 0); p = do_fork(p1 & ~CLONE_IDLETASK, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct task_struct *p;
CHECK_FULL_REGS(regs); CHECK_FULL_REGS(regs);
return do_fork(SIGCHLD, regs->gpr[1], regs, 0); p = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct task_struct *p;
CHECK_FULL_REGS(regs); CHECK_FULL_REGS(regs);
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
......
...@@ -343,11 +343,9 @@ void __init smp_boot_cpus(void) ...@@ -343,11 +343,9 @@ void __init smp_boot_cpus(void)
/* create a process for the processor */ /* create a process for the processor */
/* only regs.msr is actually used, and 0 is OK for it */ /* only regs.msr is actually used, and 0 is OK for it */
memset(&regs, 0, sizeof(struct pt_regs)); memset(&regs, 0, sizeof(struct pt_regs));
if (do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0) < 0) p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
if (IS_ERR(p))
panic("failed fork for CPU %d", i); panic("failed fork for CPU %d", i);
p = prev_task(&init_task);
if (!p)
panic("No idle task for CPU %d", i);
init_idle(p, i); init_idle(p, i);
unhash_process(p); unhash_process(p);
......
...@@ -256,19 +256,25 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) ...@@ -256,19 +256,25 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs) struct pt_regs *regs)
{ {
return do_fork(p1, regs->gpr[1], regs, 0); struct task_struct *p;
p = do_fork(p1 & ~CLONE_IDLETASK, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs) struct pt_regs *regs)
{ {
return do_fork(SIGCHLD, regs->gpr[1], regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs) struct pt_regs *regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
......
...@@ -640,11 +640,9 @@ void __init smp_boot_cpus(void) ...@@ -640,11 +640,9 @@ void __init smp_boot_cpus(void)
memset(&regs, 0, sizeof(struct pt_regs)); memset(&regs, 0, sizeof(struct pt_regs));
if (do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0) < 0) p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
if (IS_ERR(p))
panic("failed fork for CPU %d", i); panic("failed fork for CPU %d", i);
p = prev_task(&init_task);
if (!p)
panic("No idle task for CPU %d", i);
init_idle(p, i); init_idle(p, i);
......
...@@ -332,19 +332,23 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -332,19 +332,23 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage int sys_fork(struct pt_regs regs) asmlinkage int sys_fork(struct pt_regs regs)
{ {
return do_fork(SIGCHLD, regs.gprs[15], &regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys_clone(struct pt_regs regs) asmlinkage int sys_clone(struct pt_regs regs)
{ {
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
struct task_struct *p;
clone_flags = regs.gprs[3]; clone_flags = regs.gprs[3];
newsp = regs.orig_gpr2; newsp = regs.orig_gpr2;
if (!newsp) if (!newsp)
newsp = regs.gprs[15]; newsp = regs.gprs[15];
return do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
...@@ -359,8 +363,9 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -359,8 +363,9 @@ asmlinkage int sys_clone(struct pt_regs regs)
*/ */
asmlinkage int sys_vfork(struct pt_regs regs) asmlinkage int sys_vfork(struct pt_regs regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, struct task_struct *p;
regs.gprs[15], &regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.gprs[15], &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -505,13 +505,13 @@ void __init initialize_secondary(void) ...@@ -505,13 +505,13 @@ void __init initialize_secondary(void)
{ {
} }
static int __init fork_by_hand(void) static struct task_struct *__init fork_by_hand(void)
{ {
struct pt_regs regs; struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never /* don't care about the psw and regs settings since we'll never
reschedule the forked task. */ reschedule the forked task. */
memset(&regs,0,sizeof(struct pt_regs)); memset(&regs,0,sizeof(struct pt_regs));
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0); return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
} }
static void __init do_boot_cpu(int cpu) static void __init do_boot_cpu(int cpu)
...@@ -521,16 +521,14 @@ static void __init do_boot_cpu(int cpu) ...@@ -521,16 +521,14 @@ static void __init do_boot_cpu(int cpu)
/* We can't use kernel_thread since we must _avoid_ to reschedule /* We can't use kernel_thread since we must _avoid_ to reschedule
the child. */ the child. */
if (fork_by_hand() < 0) idle = fork_by_hand();
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu); panic("failed fork for CPU %d", cpu);
/* /*
* We remove it from the pidhash and the runqueue * We remove it from the pidhash and the runqueue
* once we got the process: * once we got the process:
*/ */
idle = prev_task(&init_task);
if (!idle)
panic("No idle process for CPU %d",cpu);
idle->processor = cpu; idle->processor = cpu;
idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
......
...@@ -331,19 +331,23 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -331,19 +331,23 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage int sys_fork(struct pt_regs regs) asmlinkage int sys_fork(struct pt_regs regs)
{ {
return do_fork(SIGCHLD, regs.gprs[15], &regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys_clone(struct pt_regs regs) asmlinkage int sys_clone(struct pt_regs regs)
{ {
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
struct task_struct *p;
clone_flags = regs.gprs[3]; clone_flags = regs.gprs[3];
newsp = regs.orig_gpr2; newsp = regs.orig_gpr2;
if (!newsp) if (!newsp)
newsp = regs.gprs[15]; newsp = regs.gprs[15];
return do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
...@@ -358,8 +362,9 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -358,8 +362,9 @@ asmlinkage int sys_clone(struct pt_regs regs)
*/ */
asmlinkage int sys_vfork(struct pt_regs regs) asmlinkage int sys_vfork(struct pt_regs regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, struct task_struct *p;
regs.gprs[15], &regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.gprs[15], &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -484,13 +484,13 @@ void __init initialize_secondary(void) ...@@ -484,13 +484,13 @@ void __init initialize_secondary(void)
{ {
} }
static int __init fork_by_hand(void) static struct task_struct * __init fork_by_hand(void)
{ {
struct pt_regs regs; struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never /* don't care about the psw and regs settings since we'll never
reschedule the forked task. */ reschedule the forked task. */
memset(&regs,0,sizeof(struct pt_regs)); memset(&regs,0,sizeof(struct pt_regs));
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0); return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
} }
static void __init do_boot_cpu(int cpu) static void __init do_boot_cpu(int cpu)
...@@ -500,16 +500,14 @@ static void __init do_boot_cpu(int cpu) ...@@ -500,16 +500,14 @@ static void __init do_boot_cpu(int cpu)
/* We can't use kernel_thread since we must _avoid_ to reschedule /* We can't use kernel_thread since we must _avoid_ to reschedule
the child. */ the child. */
if (fork_by_hand() < 0) idle = fork_by_hand();
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu); panic("failed fork for CPU %d", cpu);
/* /*
* We remove it from the pidhash and the runqueue * We remove it from the pidhash and the runqueue
* once we got the process: * once we got the process:
*/ */
idle = prev_task(&init_task);
if (!idle)
panic("No idle process for CPU %d",cpu);
idle->processor = cpu; idle->processor = cpu;
idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
......
...@@ -276,16 +276,20 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5, ...@@ -276,16 +276,20 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7, unsigned long r6, unsigned long r7,
struct pt_regs regs) struct pt_regs regs)
{ {
return do_fork(SIGCHLD, regs.regs[15], &regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs.regs[15], &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
unsigned long r6, unsigned long r7, unsigned long r6, unsigned long r7,
struct pt_regs regs) struct pt_regs regs)
{ {
struct task_struct *p;
if (!newsp) if (!newsp)
newsp = regs.regs[15]; newsp = regs.regs[15];
return do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
...@@ -302,7 +306,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, ...@@ -302,7 +306,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7, unsigned long r6, unsigned long r7,
struct pt_regs regs) struct pt_regs regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], &regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -1393,7 +1393,7 @@ flush_patch_two: ...@@ -1393,7 +1393,7 @@ flush_patch_two:
std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr]
add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr
mov 0, %o3 mov 0, %o3
call C_LABEL(do_fork) call C_LABEL(do_fork_FIXME_NOW_RETURNS_TASK_STRUCT)
mov %l5, %o7 mov %l5, %o7
/* Whee, kernel threads! */ /* Whee, kernel threads! */
...@@ -1416,7 +1416,8 @@ flush_patch_three: ...@@ -1416,7 +1416,8 @@ flush_patch_three:
std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr]
add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr
mov 0, %o3 mov 0, %o3
call C_LABEL(do_fork) /* FIXME: remove CLONE_IDLETASK from flags first */
call C_LABEL(do_fork_WITHOUT_CLONE_IDLETASK)
mov %l5, %o7 mov %l5, %o7
/* Whee, real vfork! */ /* Whee, real vfork! */
...@@ -1432,9 +1433,9 @@ flush_patch_four: ...@@ -1432,9 +1433,9 @@ flush_patch_four:
sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
mov %fp, %o1 mov %fp, %o1
or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
sethi %hi(C_LABEL(do_fork)), %l1 sethi %hi(C_LABEL(do_fork_FIXME_NOW_RETURNS_TASK_STRUCT)), %l1
mov 0, %o3 mov 0, %o3
jmpl %l1 + %lo(C_LABEL(do_fork)), %g0 jmpl %l1 + %lo(C_LABEL(do_fork_FIXME_NOW_RETURNS_TASK_STRUCT)), %g0
add %sp, REGWIN_SZ, %o2 add %sp, REGWIN_SZ, %o2
.align 4 .align 4
......
...@@ -214,7 +214,7 @@ void __init smp4d_boot_cpus(void) ...@@ -214,7 +214,7 @@ void __init smp4d_boot_cpus(void)
int no; int no;
/* Cook up an idler for this guy. */ /* Cook up an idler for this guy. */
kernel_thread(start_secondary, NULL, CLONE_PID); kernel_thread(start_secondary, NULL, CLONE_IDLETASK);
cpucount++; cpucount++;
......
...@@ -187,7 +187,7 @@ void __init smp4m_boot_cpus(void) ...@@ -187,7 +187,7 @@ void __init smp4m_boot_cpus(void)
int timeout; int timeout;
/* Cook up an idler for this guy. */ /* Cook up an idler for this guy. */
kernel_thread(start_secondary, NULL, CLONE_PID); kernel_thread(start_secondary, NULL, CLONE_IDLETASK);
cpucount++; cpucount++;
......
...@@ -1429,7 +1429,7 @@ sys_fork: clr %o1 ...@@ -1429,7 +1429,7 @@ sys_fork: clr %o1
sys_clone: flushw sys_clone: flushw
movrz %o1, %fp, %o1 movrz %o1, %fp, %o1
mov 0, %o3 mov 0, %o3
ba,pt %xcc, do_fork ba,pt %xcc, do_fork_FIXME_NOW_RETURNS_TASK_STRUCT
add %sp, STACK_BIAS + REGWIN_SZ, %o2 add %sp, STACK_BIAS + REGWIN_SZ, %o2
ret_from_syscall: ret_from_syscall:
/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in
......
...@@ -268,7 +268,7 @@ void __init smp_boot_cpus(void) ...@@ -268,7 +268,7 @@ void __init smp_boot_cpus(void)
int no; int no;
prom_printf("Starting CPU %d... ", i); prom_printf("Starting CPU %d... ", i);
kernel_thread(NULL, NULL, CLONE_PID); kernel_thread(NULL, NULL, CLONE_IDLETASK);
cpucount++; cpucount++;
p = prev_task(&init_task); p = prev_task(&init_task);
......
...@@ -2683,14 +2683,18 @@ int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs) ...@@ -2683,14 +2683,18 @@ int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
asmlinkage int sys32_fork(struct pt_regs regs) asmlinkage int sys32_fork(struct pt_regs regs)
{ {
return do_fork(SIGCHLD, regs.rsp, &regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs.rsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs) asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
{ {
struct task_struct *p;
if (!newsp) if (!newsp)
newsp = regs.rsp; newsp = regs.rsp;
return do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
...@@ -2705,7 +2709,9 @@ asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct ...@@ -2705,7 +2709,9 @@ asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct
*/ */
asmlinkage int sys32_vfork(struct pt_regs regs) asmlinkage int sys32_vfork(struct pt_regs regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -570,7 +570,7 @@ ENTRY(kernel_thread) ...@@ -570,7 +570,7 @@ ENTRY(kernel_thread)
movq %rsp, %rdx movq %rsp, %rdx
# clone now # clone now
call do_fork call do_fork_FIXME_NOW_RETURNS_TASK_STRUCT
# save retval on the stack so it's popped before `ret` # save retval on the stack so it's popped before `ret`
movq %rax, RAX(%rsp) movq %rax, RAX(%rsp)
......
...@@ -608,14 +608,18 @@ void set_personality_64bit(void) ...@@ -608,14 +608,18 @@ void set_personality_64bit(void)
asmlinkage long sys_fork(struct pt_regs regs) asmlinkage long sys_fork(struct pt_regs regs)
{ {
return do_fork(SIGCHLD, regs.rsp, &regs, 0); struct task_struct *p;
p = do_fork(SIGCHLD, regs.rsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs regs) asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs regs)
{ {
struct task_struct *p;
if (!newsp) if (!newsp)
newsp = regs.rsp; newsp = regs.rsp;
return do_fork(clone_flags, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
...@@ -630,7 +634,9 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct ...@@ -630,7 +634,9 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct
*/ */
asmlinkage long sys_vfork(struct pt_regs regs) asmlinkage long sys_vfork(struct pt_regs regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0); struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
/* /*
......
...@@ -476,14 +476,14 @@ void __init initialize_secondary(void) ...@@ -476,14 +476,14 @@ void __init initialize_secondary(void)
extern volatile unsigned long init_rsp; extern volatile unsigned long init_rsp;
extern void (*initial_code)(void); extern void (*initial_code)(void);
static int __init fork_by_hand(void) static struct task_struct * __init fork_by_hand(void)
{ {
struct pt_regs regs; struct pt_regs regs;
/* /*
* don't care about the rip and regs settings since * don't care about the rip and regs settings since
* we'll never reschedule the forked task. * we'll never reschedule the forked task.
*/ */
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0); return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
} }
#if APIC_DEBUG #if APIC_DEBUG
...@@ -538,17 +538,14 @@ static void __init do_boot_cpu (int apicid) ...@@ -538,17 +538,14 @@ static void __init do_boot_cpu (int apicid)
* We can't use kernel_thread since we must avoid to * We can't use kernel_thread since we must avoid to
* reschedule the child. * reschedule the child.
*/ */
if (fork_by_hand() < 0) idle = fork_by_hand();
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu); panic("failed fork for CPU %d", cpu);
/* /*
* We remove it from the pidhash and the runqueue * We remove it from the pidhash and the runqueue
* once we got the process: * once we got the process:
*/ */
idle = prev_task(&init_task);
if (!idle)
panic("No idle process for CPU %d", cpu);
init_idle(idle,cpu); init_idle(idle,cpu);
x86_cpu_to_apicid[cpu] = apicid; x86_cpu_to_apicid[cpu] = apicid;
......
...@@ -39,7 +39,7 @@ struct exec_domain; ...@@ -39,7 +39,7 @@ struct exec_domain;
#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ #define CLONE_FS 0x00000200 /* set if fs info shared between processes */
#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ #define CLONE_FILES 0x00000400 /* set if open files shared between processes */
#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ #define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */
#define CLONE_PID 0x00001000 /* set if pid shared */ #define CLONE_IDLETASK 0x00001000 /* set if new pid should be 0 (kernel only)*/
#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */
...@@ -663,7 +663,7 @@ extern void daemonize(void); ...@@ -663,7 +663,7 @@ extern void daemonize(void);
extern task_t *child_reaper; extern task_t *child_reaper;
extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_execve(char *, char **, char **, struct pt_regs *);
extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long);
extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));
......
...@@ -136,8 +136,8 @@ static int get_pid(unsigned long flags) ...@@ -136,8 +136,8 @@ static int get_pid(unsigned long flags)
struct task_struct *p; struct task_struct *p;
int pid; int pid;
if (flags & CLONE_PID) if (flags & CLONE_IDLETASK)
return current->pid; return 0;
spin_lock(&lastpid_lock); spin_lock(&lastpid_lock);
if((++last_pid) & 0xffff8000) { if((++last_pid) & 0xffff8000) {
...@@ -608,27 +608,18 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) ...@@ -608,27 +608,18 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
* For an example that's using stack_top, see * For an example that's using stack_top, see
* arch/ia64/kernel/process.c. * arch/ia64/kernel/process.c.
*/ */
int do_fork(unsigned long clone_flags, unsigned long stack_start, struct task_struct *do_fork(unsigned long clone_flags,
struct pt_regs *regs, unsigned long stack_size) unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size)
{ {
int retval; int retval;
unsigned long flags; unsigned long flags;
struct task_struct *p; struct task_struct *p = NULL;
struct completion vfork; struct completion vfork;
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
return -EINVAL; return ERR_PTR(-EINVAL);
retval = -EPERM;
/*
* CLONE_PID is only allowed for the initial SMP swapper
* calls
*/
if (clone_flags & CLONE_PID) {
if (current->pid)
goto fork_out;
}
retval = -ENOMEM; retval = -ENOMEM;
p = dup_task_struct(current); p = dup_task_struct(current);
...@@ -768,8 +759,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, ...@@ -768,8 +759,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
* *
* Let it rip! * Let it rip!
*/ */
retval = p->pid; p->tgid = p->pid;
p->tgid = retval;
INIT_LIST_HEAD(&p->thread_group); INIT_LIST_HEAD(&p->thread_group);
/* Need tasklist lock for parent etc handling! */ /* Need tasklist lock for parent etc handling! */
...@@ -807,9 +797,12 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, ...@@ -807,9 +797,12 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
* COW overhead when the child exec()s afterwards. * COW overhead when the child exec()s afterwards.
*/ */
set_need_resched(); set_need_resched();
retval = 0;
fork_out: fork_out:
return retval; if (retval)
return ERR_PTR(retval);
return p;
bad_fork_cleanup_namespace: bad_fork_cleanup_namespace:
exit_namespace(p); exit_namespace(p);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment