diff options
-rw-r--r-- | arch/alpha/kernel/process.c | 35 |
1 files changed, 14 insertions, 21 deletions
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index ad86c099b6f5..a4dc79ba030f 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
@@ -266,18 +266,22 @@ alpha_vfork(void) | |||
266 | int | 266 | int |
267 | copy_thread(unsigned long clone_flags, unsigned long usp, | 267 | copy_thread(unsigned long clone_flags, unsigned long usp, |
268 | unsigned long arg, | 268 | unsigned long arg, |
269 | struct task_struct * p, struct pt_regs * regs) | 269 | struct task_struct *p, struct pt_regs *wontuse) |
270 | { | 270 | { |
271 | extern void ret_from_fork(void); | 271 | extern void ret_from_fork(void); |
272 | extern void ret_from_kernel_thread(void); | 272 | extern void ret_from_kernel_thread(void); |
273 | 273 | ||
274 | struct thread_info *childti = task_thread_info(p); | 274 | struct thread_info *childti = task_thread_info(p); |
275 | struct pt_regs *childregs = task_pt_regs(p); | 275 | struct pt_regs *childregs = task_pt_regs(p); |
276 | struct pt_regs *regs = current_pt_regs(); | ||
276 | struct switch_stack *childstack, *stack; | 277 | struct switch_stack *childstack, *stack; |
277 | unsigned long settls; | 278 | unsigned long settls; |
278 | 279 | ||
279 | childstack = ((struct switch_stack *) childregs) - 1; | 280 | childstack = ((struct switch_stack *) childregs) - 1; |
280 | if (unlikely(!regs)) { | 281 | childti->pcb.ksp = (unsigned long) childstack; |
282 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
283 | |||
284 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
281 | /* kernel thread */ | 285 | /* kernel thread */ |
282 | memset(childstack, 0, | 286 | memset(childstack, 0, |
283 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | 287 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); |
@@ -286,12 +290,17 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
286 | childstack->r10 = arg; | 290 | childstack->r10 = arg; |
287 | childregs->hae = alpha_mv.hae_cache, | 291 | childregs->hae = alpha_mv.hae_cache, |
288 | childti->pcb.usp = 0; | 292 | childti->pcb.usp = 0; |
289 | childti->pcb.ksp = (unsigned long) childstack; | ||
290 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
291 | return 0; | 293 | return 0; |
292 | } | 294 | } |
295 | /* Note: if CLONE_SETTLS is not set, then we must inherit the | ||
296 | value from the parent, which will have been set by the block | ||
297 | copy in dup_task_struct. This is non-intuitive, but is | ||
298 | required for proper operation in the case of a threaded | ||
299 | application calling fork. */ | ||
300 | if (clone_flags & CLONE_SETTLS) | ||
301 | childti->pcb.unique = regs->r20; | ||
302 | childti->pcb.usp = usp ?: rdusp(); | ||
293 | *childregs = *regs; | 303 | *childregs = *regs; |
294 | settls = regs->r20; | ||
295 | childregs->r0 = 0; | 304 | childregs->r0 = 0; |
296 | childregs->r19 = 0; | 305 | childregs->r19 = 0; |
297 | childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ | 306 | childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ |
@@ -299,22 +308,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
299 | stack = ((struct switch_stack *) regs) - 1; | 308 | stack = ((struct switch_stack *) regs) - 1; |
300 | *childstack = *stack; | 309 | *childstack = *stack; |
301 | childstack->r26 = (unsigned long) ret_from_fork; | 310 | childstack->r26 = (unsigned long) ret_from_fork; |
302 | childti->pcb.usp = usp ?: rdusp(); | ||
303 | childti->pcb.ksp = (unsigned long) childstack; | ||
304 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
305 | |||
306 | /* Set a new TLS for the child thread? Peek back into the | ||
307 | syscall arguments that we saved on syscall entry. Oops, | ||
308 | except we'd have clobbered it with the parent/child set | ||
309 | of r20. Read the saved copy. */ | ||
310 | /* Note: if CLONE_SETTLS is not set, then we must inherit the | ||
311 | value from the parent, which will have been set by the block | ||
312 | copy in dup_task_struct. This is non-intuitive, but is | ||
313 | required for proper operation in the case of a threaded | ||
314 | application calling fork. */ | ||
315 | if (clone_flags & CLONE_SETTLS) | ||
316 | childti->pcb.unique = settls; | ||
317 | |||
318 | return 0; | 311 | return 0; |
319 | } | 312 | } |
320 | 313 | ||