diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-21 16:44:27 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-11-28 22:44:37 -0500 |
commit | 87f1ca8fd9f00cc024a141623d042ca4319e12c1 (patch) | |
tree | d2826a08eda6b3fcbe55dcde75f89661cbaefbfd | |
parent | f3268edbe6fe0ce56e62c6d6b14640aeb04864b7 (diff) |
s390: switch to generic fork/vfork/clone
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/unistd.h | 3 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 52 |
3 files changed, 14 insertions, 42 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index a163784e72c8..3cbb8757704e 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -141,6 +141,7 @@ config S390 | |||
141 | select GENERIC_KERNEL_EXECVE | 141 | select GENERIC_KERNEL_EXECVE |
142 | select HAVE_MOD_ARCH_SPECIFIC | 142 | select HAVE_MOD_ARCH_SPECIFIC |
143 | select MODULES_USE_ELF_RELA | 143 | select MODULES_USE_ELF_RELA |
144 | select CLONE_BACKWARDS2 | ||
144 | 145 | ||
145 | config SCHED_OMIT_FRAME_POINTER | 146 | config SCHED_OMIT_FRAME_POINTER |
146 | def_bool y | 147 | def_bool y |
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index ccbcab7742cd..086bb8eaf6ab 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
@@ -54,6 +54,9 @@ | |||
54 | # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | 54 | # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND |
55 | # endif | 55 | # endif |
56 | #define __ARCH_WANT_SYS_EXECVE | 56 | #define __ARCH_WANT_SYS_EXECVE |
57 | #define __ARCH_WANT_SYS_FORK | ||
58 | #define __ARCH_WANT_SYS_VFORK | ||
59 | #define __ARCH_WANT_SYS_CLONE | ||
57 | 60 | ||
58 | /* | 61 | /* |
59 | * "Conditional" syscalls | 62 | * "Conditional" syscalls |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index cd31ad457a9b..e37677796a09 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -118,7 +118,7 @@ void release_thread(struct task_struct *dead_task) | |||
118 | 118 | ||
119 | int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | 119 | int copy_thread(unsigned long clone_flags, unsigned long new_stackp, |
120 | unsigned long arg, | 120 | unsigned long arg, |
121 | struct task_struct *p, struct pt_regs *regs) | 121 | struct task_struct *p, struct pt_regs *unused) |
122 | { | 122 | { |
123 | struct thread_info *ti; | 123 | struct thread_info *ti; |
124 | struct fake_frame | 124 | struct fake_frame |
@@ -150,7 +150,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
150 | frame->sf.gprs[9] = (unsigned long) frame; | 150 | frame->sf.gprs[9] = (unsigned long) frame; |
151 | 151 | ||
152 | /* Store access registers to kernel stack of new process. */ | 152 | /* Store access registers to kernel stack of new process. */ |
153 | if (unlikely(!regs)) { | 153 | if (unlikely(p->flags & PF_KTHREAD)) { |
154 | /* kernel thread */ | 154 | /* kernel thread */ |
155 | memset(&frame->childregs, 0, sizeof(struct pt_regs)); | 155 | memset(&frame->childregs, 0, sizeof(struct pt_regs)); |
156 | frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | | 156 | frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | |
@@ -164,9 +164,10 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
164 | 164 | ||
165 | return 0; | 165 | return 0; |
166 | } | 166 | } |
167 | frame->childregs = *regs; | 167 | frame->childregs = *current_pt_regs(); |
168 | frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ | 168 | frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ |
169 | frame->childregs.gprs[15] = new_stackp; | 169 | if (new_stackp) |
170 | frame->childregs.gprs[15] = new_stackp; | ||
170 | 171 | ||
171 | /* Don't copy runtime instrumentation info */ | 172 | /* Don't copy runtime instrumentation info */ |
172 | p->thread.ri_cb = NULL; | 173 | p->thread.ri_cb = NULL; |
@@ -183,57 +184,24 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
183 | sizeof(s390_fp_regs)); | 184 | sizeof(s390_fp_regs)); |
184 | /* Set a new TLS ? */ | 185 | /* Set a new TLS ? */ |
185 | if (clone_flags & CLONE_SETTLS) | 186 | if (clone_flags & CLONE_SETTLS) |
186 | p->thread.acrs[0] = regs->gprs[6]; | 187 | p->thread.acrs[0] = frame->childregs.gprs[6]; |
187 | #else /* CONFIG_64BIT */ | 188 | #else /* CONFIG_64BIT */ |
188 | /* Save the fpu registers to new thread structure. */ | 189 | /* Save the fpu registers to new thread structure. */ |
189 | save_fp_regs(&p->thread.fp_regs); | 190 | save_fp_regs(&p->thread.fp_regs); |
190 | /* Set a new TLS ? */ | 191 | /* Set a new TLS ? */ |
191 | if (clone_flags & CLONE_SETTLS) { | 192 | if (clone_flags & CLONE_SETTLS) { |
193 | unsigned long tls = frame->childregs.gprs[6]; | ||
192 | if (is_compat_task()) { | 194 | if (is_compat_task()) { |
193 | p->thread.acrs[0] = (unsigned int) regs->gprs[6]; | 195 | p->thread.acrs[0] = (unsigned int)tls; |
194 | } else { | 196 | } else { |
195 | p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32); | 197 | p->thread.acrs[0] = (unsigned int)(tls >> 32); |
196 | p->thread.acrs[1] = (unsigned int) regs->gprs[6]; | 198 | p->thread.acrs[1] = (unsigned int)tls; |
197 | } | 199 | } |
198 | } | 200 | } |
199 | #endif /* CONFIG_64BIT */ | 201 | #endif /* CONFIG_64BIT */ |
200 | return 0; | 202 | return 0; |
201 | } | 203 | } |
202 | 204 | ||
203 | SYSCALL_DEFINE0(fork) | ||
204 | { | ||
205 | struct pt_regs *regs = task_pt_regs(current); | ||
206 | return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); | ||
207 | } | ||
208 | |||
209 | SYSCALL_DEFINE4(clone, unsigned long, newsp, unsigned long, clone_flags, | ||
210 | int __user *, parent_tidptr, int __user *, child_tidptr) | ||
211 | { | ||
212 | struct pt_regs *regs = task_pt_regs(current); | ||
213 | |||
214 | if (!newsp) | ||
215 | newsp = regs->gprs[15]; | ||
216 | return do_fork(clone_flags, newsp, regs, 0, | ||
217 | parent_tidptr, child_tidptr); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * This is trivial, and on the face of it looks like it | ||
222 | * could equally well be done in user mode. | ||
223 | * | ||
224 | * Not so, for quite unobvious reasons - register pressure. | ||
225 | * In user mode vfork() cannot have a stack frame, and if | ||
226 | * done by calling the "clone()" system call directly, you | ||
227 | * do not have enough call-clobbered registers to hold all | ||
228 | * the information you need. | ||
229 | */ | ||
230 | SYSCALL_DEFINE0(vfork) | ||
231 | { | ||
232 | struct pt_regs *regs = task_pt_regs(current); | ||
233 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, | ||
234 | regs->gprs[15], regs, 0, NULL, NULL); | ||
235 | } | ||
236 | |||
237 | asmlinkage void execve_tail(void) | 205 | asmlinkage void execve_tail(void) |
238 | { | 206 | { |
239 | current->thread.fp_regs.fpc = 0; | 207 | current->thread.fp_regs.fpc = 0; |