Commit 2678fefe authored by David S. Miller's avatar David S. Miller

sparc64: Fix syscall restart, for real...

The change I put into copy_thread() just papered over the real
problem.

When we are looking to see if we should do a syscall restart, when
deliverying a signal, we should only interpret the syscall return
value as an error if the carry condition code(s) are set.

Otherwise it's a success return.

Also, sigreturn paths should do a pt_regs_clear_trap_type().

It turns out that doing a syscall restart when returning from a fork()
does and should happen, from time to time.  Even if copy_thread()
returns success, copy_process() can still unwind and signal
-ERESTARTNOINTR in the parent.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 32039f49
...@@ -591,12 +591,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, ...@@ -591,12 +591,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
if (clone_flags & CLONE_SETTLS) if (clone_flags & CLONE_SETTLS)
t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
/* We do not want to accidently trigger system call restart
* handling in the new thread. Therefore, clear out the trap
* type, which will make pt_regs_regs_is_syscall() return false.
*/
pt_regs_clear_trap_type(t->kregs);
return 0; return 0;
} }
......
...@@ -332,6 +332,9 @@ void do_rt_sigreturn(struct pt_regs *regs) ...@@ -332,6 +332,9 @@ void do_rt_sigreturn(struct pt_regs *regs)
regs->tpc = tpc; regs->tpc = tpc;
regs->tnpc = tnpc; regs->tnpc = tnpc;
/* Prevent syscall restart. */
pt_regs_clear_trap_type(regs);
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
current->blocked = set; current->blocked = set;
...@@ -515,7 +518,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -515,7 +518,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
siginfo_t info; siginfo_t info;
int signr; int signr;
if (pt_regs_is_syscall(regs)) { if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
pt_regs_clear_trap_type(regs); pt_regs_clear_trap_type(regs);
cookie.restart_syscall = 1; cookie.restart_syscall = 1;
} else } else
......
...@@ -268,6 +268,9 @@ void do_sigreturn32(struct pt_regs *regs) ...@@ -268,6 +268,9 @@ void do_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr); regs->tstate |= psr_to_tstate_icc(psr);
/* Prevent syscall restart. */
pt_regs_clear_trap_type(regs);
err |= __get_user(fpu_save, &sf->fpu_save); err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save) if (fpu_save)
err |= restore_fpu_state32(regs, &sf->fpu_state); err |= restore_fpu_state32(regs, &sf->fpu_state);
...@@ -351,6 +354,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) ...@@ -351,6 +354,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr); regs->tstate |= psr_to_tstate_icc(psr);
/* Prevent syscall restart. */
pt_regs_clear_trap_type(regs);
err |= __get_user(fpu_save, &sf->fpu_save); err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save) if (fpu_save)
err |= restore_fpu_state32(regs, &sf->fpu_state); err |= restore_fpu_state32(regs, &sf->fpu_state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment