Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e38c126 authored by David S. Miller's avatar David S. Miller
Browse files

sparc: Fix fork/clone/vfork system call restart.



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: default avatarDavid S. Miller <davem@davemloft.net>
parent 58163393
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -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,
	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
+15 −3
Original line number Diff line number Diff line
@@ -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,
	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