Skip to content

Commit

Permalink
sparc: Fix fork/clone/vfork system call restart.
Browse files Browse the repository at this point in the history
We clobber %i1 as well as %i0 for these system calls,
because they give two return values.

Therefore, on error, we have to restore %i1 properly
or else the restart explodes since it uses the wrong
arguments.

This fixes glibc's nptl/tst-eintr1.c testcase.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed May 7, 2008
1 parent 5816339 commit 1e38c12
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
20 changes: 16 additions & 4 deletions arch/sparc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 15 additions & 3 deletions arch/sparc64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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
Expand Down

0 comments on commit 1e38c12

Please sign in to comment.