diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-07 17:04:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-07 17:04:49 -0700 |
commit | 3de2403e6659d71b36ec820dc9b942762ddfe6eb (patch) | |
tree | 55516c669ffc2cbe9fd52c3a4d2d6f8e90d4644a /arch/sparc/kernel/process.c | |
parent | e0164af66b6ec165836d1d862b3f800890713452 (diff) | |
parent | 1e38c126c9252b612697e34f43b1b3371c8ee31d (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
sparc: Fix fork/clone/vfork system call restart.
sparc: Fix mmap VA span checking.
Diffstat (limited to 'arch/sparc/kernel/process.c')
-rw-r--r-- | arch/sparc/kernel/process.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index e7f35198ae3..36431f377de 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -419,14 +419,26 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, unsigned long stack_size) { unsigned long parent_tid_ptr, child_tid_ptr; + unsigned long orig_i1 = regs->u_regs[UREG_I1]; + long ret; parent_tid_ptr = regs->u_regs[UREG_I2]; child_tid_ptr = regs->u_regs[UREG_I4]; - return do_fork(clone_flags, stack_start, - regs, stack_size, - (int __user *) parent_tid_ptr, - (int __user *) child_tid_ptr); + ret = do_fork(clone_flags, stack_start, + regs, stack_size, + (int __user *) parent_tid_ptr, + (int __user *) child_tid_ptr); + + /* If we get an error and potentially restart the system + * call, we're screwed because copy_thread() clobbered + * the parent's %o1. So detect that case and restore it + * here. + */ + if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) + regs->u_regs[UREG_I1] = orig_i1; + + return ret; } /* Copy a Sparc thread. The fork() return value conventions |