diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 15:22:13 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 15:22:13 -0500 |
| commit | 9977d9b379cb77e0f67bd6f4563618106e58e11d (patch) | |
| tree | 0191accfddf578edb52c69c933d64521e3dce297 /arch/x86/kernel | |
| parent | cf4af01221579a4e895f43dbfc47598fbfc5a731 (diff) | |
| parent | 541880d9a2c7871f6370071d55aa6662d329c51e (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull big execve/kernel_thread/fork unification series from Al Viro:
"All architectures are converted to new model. Quite a bit of that
stuff is actually shared with architecture trees; in such cases it's
literally shared branch pulled by both, not a cherry-pick.
A lot of ugliness and black magic is gone (-3KLoC total in this one):
- kernel_thread()/kernel_execve()/sys_execve() redesign.
We don't do syscalls from kernel anymore for either kernel_thread()
or kernel_execve():
kernel_thread() is essentially clone(2) with callback run before we
return to userland, the callbacks either never return or do
successful do_execve() before returning.
kernel_execve() is a wrapper for do_execve() - it doesn't need to
do transition to user mode anymore.
As a result kernel_thread() and kernel_execve() are
arch-independent now - they live in kernel/fork.c and fs/exec.c
resp. sys_execve() is also in fs/exec.c and it's completely
architecture-independent.
- daemonize() is gone, along with its parts in fs/*.c
- struct pt_regs * is no longer passed to do_fork/copy_process/
copy_thread/do_execve/search_binary_handler/->load_binary/do_coredump.
- sys_fork()/sys_vfork()/sys_clone() unified; some architectures
still need wrappers (ones with callee-saved registers not saved in
pt_regs on syscall entry), but the main part of those suckers is in
kernel/fork.c now."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (113 commits)
do_coredump(): get rid of pt_regs argument
print_fatal_signal(): get rid of pt_regs argument
ptrace_signal(): get rid of unused arguments
get rid of ptrace_signal_deliver() arguments
new helper: signal_pt_regs()
unify default ptrace_signal_deliver
flagday: kill pt_regs argument of do_fork()
death to idle_regs()
don't pass regs to copy_process()
flagday: don't pass regs to copy_thread()
bfin: switch to generic vfork, get rid of pointless wrappers
xtensa: switch to generic clone()
openrisc: switch to use of generic fork and clone
unicore32: switch to generic clone(2)
score: switch to generic fork/vfork/clone
c6x: sanitize copy_thread(), get rid of clone(2) wrapper, switch to generic clone()
take sys_fork/sys_vfork/sys_clone prototypes to linux/syscalls.h
mn10300: switch to generic fork/vfork/clone
h8300: switch to generic fork/vfork/clone
tile: switch to generic clone()
...
Conflicts:
arch/microblaze/include/asm/Kbuild
Diffstat (limited to 'arch/x86/kernel')
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 9 | ||||
| -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 | 12 | ||||
| -rw-r--r-- | arch/x86/kernel/process_64.c | 10 |
6 files changed, 30 insertions, 71 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ca165ac6793..9c3ab43a695 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
| @@ -1173,15 +1173,6 @@ DEFINE_PER_CPU(struct task_struct *, fpu_owner_task); | |||
| 1173 | DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); | 1173 | DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); |
| 1174 | #endif | 1174 | #endif |
| 1175 | 1175 | ||
| 1176 | /* Make sure %fs and %gs are initialized properly in idle threads */ | ||
| 1177 | struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) | ||
| 1178 | { | ||
| 1179 | memset(regs, 0, sizeof(struct pt_regs)); | ||
| 1180 | regs->fs = __KERNEL_PERCPU; | ||
| 1181 | regs->gs = __KERNEL_STACK_CANARY; | ||
| 1182 | |||
| 1183 | return regs; | ||
| 1184 | } | ||
| 1185 | #endif /* CONFIG_X86_64 */ | 1176 | #endif /* CONFIG_X86_64 */ |
| 1186 | 1177 | ||
| 1187 | /* | 1178 | /* |
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) ; \ | |||
| 739 | ENDPROC(ptregs_##name) | 739 | ENDPROC(ptregs_##name) |
| 740 | 740 | ||
| 741 | PTREGSCALL1(iopl) | 741 | PTREGSCALL1(iopl) |
| 742 | PTREGSCALL0(fork) | ||
| 743 | PTREGSCALL0(vfork) | ||
| 744 | PTREGSCALL2(sigaltstack) | 742 | PTREGSCALL2(sigaltstack) |
| 745 | PTREGSCALL0(sigreturn) | 743 | PTREGSCALL0(sigreturn) |
| 746 | PTREGSCALL0(rt_sigreturn) | 744 | PTREGSCALL0(rt_sigreturn) |
| 747 | PTREGSCALL2(vm86) | 745 | PTREGSCALL2(vm86) |
| 748 | PTREGSCALL1(vm86old) | 746 | PTREGSCALL1(vm86old) |
| 749 | 747 | ||
| 750 | /* Clone is an oddball. The 4th arg is in %edi */ | ||
| 751 | ENTRY(ptregs_clone) | ||
| 752 | CFI_STARTPROC | ||
| 753 | leal 4(%esp),%eax | ||
| 754 | pushl_cfi %eax | ||
| 755 | pushl_cfi PT_EDI(%eax) | ||
| 756 | movl PT_EDX(%eax),%ecx | ||
| 757 | movl PT_ECX(%eax),%edx | ||
| 758 | movl PT_EBX(%eax),%eax | ||
| 759 | call sys_clone | ||
| 760 | addl $8,%esp | ||
| 761 | CFI_ADJUST_CFA_OFFSET -8 | ||
| 762 | ret | ||
| 763 | CFI_ENDPROC | ||
| 764 | ENDPROC(ptregs_clone) | ||
| 765 | |||
| 766 | .macro FIXUP_ESPFIX_STACK | 748 | .macro FIXUP_ESPFIX_STACK |
| 767 | /* | 749 | /* |
| 768 | * Switch back for ESPFIX stack to the normal zerobased stack | 750 | * 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 31b46128a63..70641aff0c2 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -845,9 +845,25 @@ ENTRY(\label) | |||
| 845 | END(\label) | 845 | END(\label) |
| 846 | .endm | 846 | .endm |
| 847 | 847 | ||
| 848 | PTREGSCALL stub_clone, sys_clone, %r8 | 848 | .macro FORK_LIKE func |
| 849 | PTREGSCALL stub_fork, sys_fork, %rdi | 849 | ENTRY(stub_\func) |
| 850 | PTREGSCALL stub_vfork, sys_vfork, %rdi | 850 | CFI_STARTPROC |
| 851 | popq %r11 /* save return address */ | ||
| 852 | PARTIAL_FRAME 0 | ||
| 853 | SAVE_REST | ||
| 854 | pushq %r11 /* put it back on stack */ | ||
| 855 | FIXUP_TOP_OF_STACK %r11, 8 | ||
| 856 | DEFAULT_FRAME 0 8 /* offset 8: return address */ | ||
| 857 | call sys_\func | ||
| 858 | RESTORE_TOP_OF_STACK %r11, 8 | ||
| 859 | ret $REST_SKIP /* pop extended registers */ | ||
| 860 | CFI_ENDPROC | ||
| 861 | END(stub_\func) | ||
| 862 | .endm | ||
| 863 | |||
| 864 | FORK_LIKE clone | ||
| 865 | FORK_LIKE fork | ||
| 866 | FORK_LIKE vfork | ||
| 851 | PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx | 867 | PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx |
| 852 | PTREGSCALL stub_iopl, sys_iopl, %rsi | 868 | PTREGSCALL stub_iopl, sys_iopl, %rsi |
| 853 | 869 | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 2f99e312187..2ed787f15bf 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, | |||
| 262 | propagate_user_return_notify(prev_p, next_p); | 262 | propagate_user_return_notify(prev_p, next_p); |
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | int sys_fork(struct pt_regs *regs) | ||
| 266 | { | ||
| 267 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); | ||
| 268 | } | ||
| 269 | |||
| 270 | /* | ||
| 271 | * This is trivial, and on the face of it looks like it | ||
| 272 | * could equally well be done in user mode. | ||
| 273 | * | ||
| 274 | * Not so, for quite unobvious reasons - register pressure. | ||
| 275 | * In user mode vfork() cannot have a stack frame, and if | ||
| 276 | * done by calling the "clone()" system call directly, you | ||
| 277 | * do not have enough call-clobbered registers to hold all | ||
| 278 | * the information you need. | ||
| 279 | */ | ||
| 280 | int sys_vfork(struct pt_regs *regs) | ||
| 281 | { | ||
| 282 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, | ||
| 283 | NULL, NULL); | ||
| 284 | } | ||
| 285 | |||
| 286 | long | ||
| 287 | sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 288 | void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) | ||
| 289 | { | ||
| 290 | if (!newsp) | ||
| 291 | newsp = regs->sp; | ||
| 292 | return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | 265 | /* |
| 296 | * Idle related variables and functions | 266 | * Idle related variables and functions |
| 297 | */ | 267 | */ |
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 44e0bff38e7..b5a8905785e 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
| @@ -128,8 +128,7 @@ void release_thread(struct task_struct *dead_task) | |||
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 130 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
| 131 | unsigned long arg, | 131 | unsigned long arg, struct task_struct *p) |
| 132 | struct task_struct *p, struct pt_regs *regs) | ||
| 133 | { | 132 | { |
| 134 | struct pt_regs *childregs = task_pt_regs(p); | 133 | struct pt_regs *childregs = task_pt_regs(p); |
| 135 | struct task_struct *tsk; | 134 | struct task_struct *tsk; |
| @@ -138,7 +137,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
| 138 | p->thread.sp = (unsigned long) childregs; | 137 | p->thread.sp = (unsigned long) childregs; |
| 139 | p->thread.sp0 = (unsigned long) (childregs+1); | 138 | p->thread.sp0 = (unsigned long) (childregs+1); |
| 140 | 139 | ||
| 141 | if (unlikely(!regs)) { | 140 | if (unlikely(p->flags & PF_KTHREAD)) { |
| 142 | /* kernel thread */ | 141 | /* kernel thread */ |
| 143 | memset(childregs, 0, sizeof(struct pt_regs)); | 142 | memset(childregs, 0, sizeof(struct pt_regs)); |
| 144 | p->thread.ip = (unsigned long) ret_from_kernel_thread; | 143 | p->thread.ip = (unsigned long) ret_from_kernel_thread; |
| @@ -156,12 +155,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
| 156 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | 155 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
| 157 | return 0; | 156 | return 0; |
| 158 | } | 157 | } |
| 159 | *childregs = *regs; | 158 | *childregs = *current_pt_regs(); |
| 160 | childregs->ax = 0; | 159 | childregs->ax = 0; |
| 161 | childregs->sp = sp; | 160 | if (sp) |
| 161 | childregs->sp = sp; | ||
| 162 | 162 | ||
| 163 | p->thread.ip = (unsigned long) ret_from_fork; | 163 | p->thread.ip = (unsigned long) ret_from_fork; |
| 164 | task_user_gs(p) = get_user_gs(regs); | 164 | task_user_gs(p) = get_user_gs(current_pt_regs()); |
| 165 | 165 | ||
| 166 | p->fpu_counter = 0; | 166 | p->fpu_counter = 0; |
| 167 | p->thread.io_bitmap_ptr = NULL; | 167 | p->thread.io_bitmap_ptr = NULL; |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 16c6365e2b8..6e68a619496 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
| @@ -146,8 +146,7 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls) | |||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 148 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
| 149 | unsigned long arg, | 149 | unsigned long arg, struct task_struct *p) |
| 150 | struct task_struct *p, struct pt_regs *regs) | ||
| 151 | { | 150 | { |
| 152 | int err; | 151 | int err; |
| 153 | struct pt_regs *childregs; | 152 | struct pt_regs *childregs; |
| @@ -169,7 +168,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
| 169 | savesegment(ds, p->thread.ds); | 168 | savesegment(ds, p->thread.ds); |
| 170 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | 169 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
| 171 | 170 | ||
| 172 | if (unlikely(!regs)) { | 171 | if (unlikely(p->flags & PF_KTHREAD)) { |
| 173 | /* kernel thread */ | 172 | /* kernel thread */ |
| 174 | memset(childregs, 0, sizeof(struct pt_regs)); | 173 | memset(childregs, 0, sizeof(struct pt_regs)); |
| 175 | childregs->sp = (unsigned long)childregs; | 174 | childregs->sp = (unsigned long)childregs; |
| @@ -181,10 +180,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
| 181 | childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; | 180 | childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; |
| 182 | return 0; | 181 | return 0; |
| 183 | } | 182 | } |
| 184 | *childregs = *regs; | 183 | *childregs = *current_pt_regs(); |
| 185 | 184 | ||
| 186 | childregs->ax = 0; | 185 | childregs->ax = 0; |
| 187 | childregs->sp = sp; | 186 | if (sp) |
| 187 | childregs->sp = sp; | ||
| 188 | 188 | ||
| 189 | err = -ENOMEM; | 189 | err = -ENOMEM; |
| 190 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | 190 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
