diff options
| -rw-r--r-- | arch/sparc/kernel/process.c | 20 | ||||
| -rw-r--r-- | arch/sparc64/kernel/process.c | 18 | 
2 files changed, 31 insertions, 7 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 diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 500ac6d483a..4129c044985 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -503,6 +503,8 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,  			      unsigned long stack_size)  {  	int __user *parent_tid_ptr, *child_tid_ptr; +	unsigned long orig_i1 = regs->u_regs[UREG_I1]; +	long ret;  #ifdef CONFIG_COMPAT  	if (test_thread_flag(TIF_32BIT)) { @@ -515,9 +517,19 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,  		child_tid_ptr = (int __user *) regs->u_regs[UREG_I4];  	} -	return do_fork(clone_flags, stack_start, -		       regs, stack_size, -		       parent_tid_ptr, child_tid_ptr); +	ret = do_fork(clone_flags, stack_start, +		      regs, stack_size, +		      parent_tid_ptr, 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  |