diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-22 22:34:11 -0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-11-28 22:13:44 -0500 | 
| commit | 1d4b4b2994b5fc208963c0b795291f8c1f18becf (patch) | |
| tree | befe27a3e2abc333b5bd81ee7381e4c5541f543f | |
| parent | 71613c3b871c5a9f27cc48f124251bcd3aa23be1 (diff) | |
| download | olio-linux-3.10-1d4b4b2994b5fc208963c0b795291f8c1f18becf.tar.xz olio-linux-3.10-1d4b4b2994b5fc208963c0b795291f8c1f18becf.zip  | |
x86, um: switch to generic fork/vfork/clone
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | arch/um/kernel/syscall.c | 19 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/ia32/ia32entry.S | 7 | ||||
| -rw-r--r-- | arch/x86/ia32/sys_ia32.c | 11 | ||||
| -rw-r--r-- | arch/x86/include/asm/sys_ia32.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/syscalls.h | 13 | ||||
| -rw-r--r-- | arch/x86/include/asm/unistd.h | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_32.S | 18 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 22 | ||||
| -rw-r--r-- | arch/x86/kernel/process.c | 30 | ||||
| -rw-r--r-- | arch/x86/kernel/process_32.c | 11 | ||||
| -rw-r--r-- | arch/x86/kernel/process_64.c | 7 | ||||
| -rw-r--r-- | arch/x86/syscalls/syscall_32.tbl | 6 | ||||
| -rw-r--r-- | arch/x86/um/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/um/sys_call_table_32.c | 3 | ||||
| -rw-r--r-- | arch/x86/um/syscalls_32.c | 15 | 
16 files changed, 52 insertions, 117 deletions
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 3a875226c8e..c1d0ae069b5 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -14,25 +14,6 @@  #include <asm/uaccess.h>  #include <asm/unistd.h> -long sys_fork(void) -{ -	return do_fork(SIGCHLD, 0, -		      ¤t->thread.regs, 0, NULL, NULL); -} - -long sys_vfork(void) -{ -	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, -		      ¤t->thread.regs, 0, NULL, NULL); -} - -long sys_clone(unsigned long clone_flags, unsigned long newsp, -	       void __user *parent_tid, void __user *child_tid) -{ -	return do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, -		      child_tid); -} -  long old_mmap(unsigned long addr, unsigned long len,  	      unsigned long prot, unsigned long flags,  	      unsigned long fd, unsigned long offset) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 46c3bff3ced..0df6e7d8453 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -112,6 +112,7 @@ config X86  	select GENERIC_KERNEL_EXECVE  	select MODULES_USE_ELF_REL if X86_32  	select MODULES_USE_ELF_RELA if X86_64 +	select CLONE_BACKWARDS if X86_32  config INSTRUCTION_DECODER  	def_bool y diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 076745fc804..32e6f05ddaa 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -467,11 +467,16 @@ GLOBAL(\label)  	PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx  	PTREGSCALL stub32_execve, compat_sys_execve, %rcx  	PTREGSCALL stub32_fork, sys_fork, %rdi -	PTREGSCALL stub32_clone, sys32_clone, %rdx  	PTREGSCALL stub32_vfork, sys_vfork, %rdi  	PTREGSCALL stub32_iopl, sys_iopl, %rsi  	ALIGN +GLOBAL(stub32_clone) +	leaq sys_clone(%rip),%rax +	mov	%r8, %rcx +	jmp  ia32_ptregs_common	 + +	ALIGN  ia32_ptregs_common:  	popq %r11  	CFI_ENDPROC diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c index 86d68d1c880..d0b689ba7be 100644 --- a/arch/x86/ia32/sys_ia32.c +++ b/arch/x86/ia32/sys_ia32.c @@ -385,17 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,  	return ret;  } -asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, -			    struct pt_regs *regs) -{ -	void __user *parent_tid = (void __user *)regs->dx; -	void __user *child_tid = (void __user *)regs->di; - -	if (!newsp) -		newsp = regs->sp; -	return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); -} -  /*   * Some system calls that need sign extended arguments. This could be   * done by a generic wrapper. diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h index a9a8cf3da49..c76fae4d90b 100644 --- a/arch/x86/include/asm/sys_ia32.h +++ b/arch/x86/include/asm/sys_ia32.h @@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);  asmlinkage long sys32_personality(unsigned long);  asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); -asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *); -  long sys32_lseek(unsigned int, int, unsigned int);  long sys32_kill(int, int);  long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 9e5aef3a259..f7252d11416 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -21,10 +21,15 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int);  long sys_iopl(unsigned int, struct pt_regs *);  /* kernel/process.c */ -int sys_fork(struct pt_regs *); -int sys_vfork(struct pt_regs *); -long sys_clone(unsigned long, unsigned long, void __user *, -	       void __user *, struct pt_regs *); +asmlinkage long sys_fork(void); +asmlinkage long sys_vfork(void); +#ifdef CONFIG_CLONE_BACKWARDS +asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, int, +	       void __user *); +#else +asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, +	       void __user *, int); +#endif  /* kernel/ldt.c */  asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 16f3fc6ebf2..0e7dea7d366 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -51,6 +51,9 @@  # define __ARCH_WANT_SYS_UTIME  # define __ARCH_WANT_SYS_WAITPID  # define __ARCH_WANT_SYS_EXECVE +# define __ARCH_WANT_SYS_FORK +# define __ARCH_WANT_SYS_VFORK +# define __ARCH_WANT_SYS_CLONE  /*   * "Conditional" syscalls diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 88b725aa1d5..c763116c535 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -739,30 +739,12 @@ ENTRY(ptregs_##name) ; \  ENDPROC(ptregs_##name)  PTREGSCALL1(iopl) -PTREGSCALL0(fork) -PTREGSCALL0(vfork)  PTREGSCALL2(sigaltstack)  PTREGSCALL0(sigreturn)  PTREGSCALL0(rt_sigreturn)  PTREGSCALL2(vm86)  PTREGSCALL1(vm86old) -/* Clone is an oddball.  The 4th arg is in %edi */ -ENTRY(ptregs_clone) -	CFI_STARTPROC -	leal 4(%esp),%eax -	pushl_cfi %eax -	pushl_cfi PT_EDI(%eax) -	movl PT_EDX(%eax),%ecx -	movl PT_ECX(%eax),%edx -	movl PT_EBX(%eax),%eax -	call sys_clone -	addl $8,%esp -	CFI_ADJUST_CFA_OFFSET -8 -	ret -	CFI_ENDPROC -ENDPROC(ptregs_clone) -  .macro FIXUP_ESPFIX_STACK  /*   * Switch back for ESPFIX stack to the normal zerobased stack diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 1328fe49a3f..2363e820ed6 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -845,9 +845,25 @@ ENTRY(\label)  END(\label)  	.endm -	PTREGSCALL stub_clone, sys_clone, %r8 -	PTREGSCALL stub_fork, sys_fork, %rdi -	PTREGSCALL stub_vfork, sys_vfork, %rdi +	.macro FORK_LIKE func +ENTRY(stub_\func) +	CFI_STARTPROC +	popq	%r11			/* save return address */ +	PARTIAL_FRAME 0 +	SAVE_REST +	pushq	%r11			/* put it back on stack */ +	FIXUP_TOP_OF_STACK %r11, 8 +	DEFAULT_FRAME 0 8		/* offset 8: return address */ +	call sys_\func +	RESTORE_TOP_OF_STACK %r11, 8 +	ret $REST_SKIP		/* pop extended registers */ +	CFI_ENDPROC +END(stub_\func) +	.endm + +	FORK_LIKE  clone +	FORK_LIKE  fork +	FORK_LIKE  vfork  	PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx  	PTREGSCALL stub_iopl, sys_iopl, %rsi diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b644e1c765d..fe945959325 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -262,36 +262,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,  	propagate_user_return_notify(prev_p, next_p);  } -int sys_fork(struct pt_regs *regs) -{ -	return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); -} - -/* - * This is trivial, and on the face of it looks like it - * could equally well be done in user mode. - * - * Not so, for quite unobvious reasons - register pressure. - * In user mode vfork() cannot have a stack frame, and if - * done by calling the "clone()" system call directly, you - * do not have enough call-clobbered registers to hold all - * the information you need. - */ -int sys_vfork(struct pt_regs *regs) -{ -	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, -		       NULL, NULL); -} - -long -sys_clone(unsigned long clone_flags, unsigned long newsp, -	  void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) -{ -	if (!newsp) -		newsp = regs->sp; -	return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); -} -  /*   * Idle related variables and functions   */ diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 44e0bff38e7..16efa974532 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -129,7 +129,7 @@ void release_thread(struct task_struct *dead_task)  int copy_thread(unsigned long clone_flags, unsigned long sp,  	unsigned long arg, -	struct task_struct *p, struct pt_regs *regs) +	struct task_struct *p, struct pt_regs *unused)  {  	struct pt_regs *childregs = task_pt_regs(p);  	struct task_struct *tsk; @@ -138,7 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,  	p->thread.sp = (unsigned long) childregs;  	p->thread.sp0 = (unsigned long) (childregs+1); -	if (unlikely(!regs)) { +	if (unlikely(p->flags & PF_KTHREAD)) {  		/* kernel thread */  		memset(childregs, 0, sizeof(struct pt_regs));  		p->thread.ip = (unsigned long) ret_from_kernel_thread; @@ -156,12 +156,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,  		memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));  		return 0;  	} -	*childregs = *regs; +	*childregs = *current_pt_regs();  	childregs->ax = 0; -	childregs->sp = sp; +	if (sp) +		childregs->sp = sp;  	p->thread.ip = (unsigned long) ret_from_fork; -	task_user_gs(p) = get_user_gs(regs); +	task_user_gs(p) = get_user_gs(current_pt_regs());  	p->fpu_counter = 0;  	p->thread.io_bitmap_ptr = NULL; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 16c6365e2b8..74aac76c6e3 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -169,7 +169,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,  	savesegment(ds, p->thread.ds);  	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); -	if (unlikely(!regs)) { +	if (unlikely(p->flags & PF_KTHREAD)) {  		/* kernel thread */  		memset(childregs, 0, sizeof(struct pt_regs));  		childregs->sp = (unsigned long)childregs; @@ -181,10 +181,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,  		childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;  		return 0;  	} -	*childregs = *regs; +	*childregs = *current_pt_regs();  	childregs->ax = 0; -	childregs->sp = sp; +	if (sp) +		childregs->sp = sp;  	err = -ENOMEM;  	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index a47103fbc69..ee3c220ee50 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl @@ -8,7 +8,7 @@  #  0	i386	restart_syscall		sys_restart_syscall  1	i386	exit			sys_exit -2	i386	fork			ptregs_fork			stub32_fork +2	i386	fork			sys_fork			stub32_fork  3	i386	read			sys_read  4	i386	write			sys_write  5	i386	open			sys_open			compat_sys_open @@ -126,7 +126,7 @@  117	i386	ipc			sys_ipc				sys32_ipc  118	i386	fsync			sys_fsync  119	i386	sigreturn		ptregs_sigreturn		stub32_sigreturn -120	i386	clone			ptregs_clone			stub32_clone +120	i386	clone			sys_clone			stub32_clone  121	i386	setdomainname		sys_setdomainname  122	i386	uname			sys_newuname  123	i386	modify_ldt		sys_modify_ldt @@ -196,7 +196,7 @@  187	i386	sendfile		sys_sendfile			sys32_sendfile  188	i386	getpmsg  189	i386	putpmsg -190	i386	vfork			ptregs_vfork			stub32_vfork +190	i386	vfork			sys_vfork			stub32_vfork  191	i386	ugetrlimit		sys_getrlimit			compat_sys_getrlimit  192	i386	mmap2			sys_mmap_pgoff  193	i386	truncate64		sys_truncate64			sys32_truncate64 diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index 07611759ce3..8f51c39750d 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig @@ -25,6 +25,7 @@ config X86_32  	select HAVE_AOUT  	select ARCH_WANT_IPC_PARSE_VERSION  	select MODULES_USE_ELF_REL +	select CLONE_BACKWARDS  config X86_64  	def_bool 64BIT diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c index 232e60504b3..812e98c098e 100644 --- a/arch/x86/um/sys_call_table_32.c +++ b/arch/x86/um/sys_call_table_32.c @@ -24,13 +24,10 @@  #define old_mmap sys_old_mmap -#define ptregs_fork sys_fork  #define ptregs_iopl sys_iopl  #define ptregs_vm86old sys_vm86old -#define ptregs_clone i386_clone  #define ptregs_vm86 sys_vm86  #define ptregs_sigaltstack sys_sigaltstack -#define ptregs_vfork sys_vfork  #define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;  #include <asm/syscalls_32.h> diff --git a/arch/x86/um/syscalls_32.c b/arch/x86/um/syscalls_32.c index db444c7218f..e8bcea99acd 100644 --- a/arch/x86/um/syscalls_32.c +++ b/arch/x86/um/syscalls_32.c @@ -6,21 +6,6 @@  #include <linux/syscalls.h>  #include <sysdep/syscalls.h> -/* - * The prototype on i386 is: - * - *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls - * - * and the "newtls" arg. on i386 is read by copy_thread directly from the - * register saved on the stack. - */ -long i386_clone(unsigned long clone_flags, unsigned long newsp, -		int __user *parent_tid, void *newtls, int __user *child_tid) -{ -	return sys_clone(clone_flags, newsp, parent_tid, child_tid); -} - -  long sys_sigaction(int sig, const struct old_sigaction __user *act,  			 struct old_sigaction __user *oact)  {  |