sparc64: Fix syscall restart, for real...
authorDavid S. Miller <davem@davemloft.net>
Thu, 1 May 2008 10:30:22 +0000 (03:30 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 May 2008 12:22:52 +0000 (05:22 -0700)
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: David S. Miller <davem@davemloft.net>
arch/sparc64/kernel/process.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c

index 0560137491578b25b7aba3d1ce321d46ce0e8209..500ac6d483a0cec74f7c8ab51940167813267127 100644 (file)
@@ -591,12 +591,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        if (clone_flags & CLONE_SETTLS)
                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;
 }
 
index f2d88d8f7a427e4ff01d2d3da5d0afbd0ed802ba..45d6bf632daa6a6e4fe5c6826629c3ff9eb1f732 100644 (file)
@@ -332,6 +332,9 @@ void do_rt_sigreturn(struct pt_regs *regs)
        regs->tpc = tpc;
        regs->tnpc = tnpc;
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_trap_type(regs);
+
        sigdelsetmask(&set, ~_BLOCKABLE);
        spin_lock_irq(&current->sighand->siglock);
        current->blocked = set;
@@ -515,7 +518,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
        siginfo_t info;
        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);
                cookie.restart_syscall = 1;
        } else
index 91f8d0826db1084b0abb8c7206431406c9108f23..9415d2c918c5fc8301aa9e45c499fbe86539552c 100644 (file)
@@ -268,6 +268,9 @@ void do_sigreturn32(struct pt_regs *regs)
        regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
        regs->tstate |= psr_to_tstate_icc(psr);
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_trap_type(regs);
+
        err |= __get_user(fpu_save, &sf->fpu_save);
        if (fpu_save)
                err |= restore_fpu_state32(regs, &sf->fpu_state);
@@ -351,6 +354,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
        regs->tstate |= psr_to_tstate_icc(psr);
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_trap_type(regs);
+
        err |= __get_user(fpu_save, &sf->fpu_save);
        if (fpu_save)
                err |= restore_fpu_state32(regs, &sf->fpu_state);