diff options
author | David S. Miller <davem@davemloft.net> | 2008-05-01 06:30:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-05-02 08:22:52 -0400 |
commit | 2678fefedbbc03a3ae6f5c254791bf147d6c52fd (patch) | |
tree | 23052dffe4591f06192b8ee9cd17a1160fe4520f /arch/sparc64 | |
parent | 32039f4954938e4d761032d7046254d08d0db54c (diff) |
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: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/process.c | 6 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal.c | 6 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal32.c | 6 |
3 files changed, 11 insertions, 7 deletions
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 056013749157..500ac6d483a0 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
@@ -591,12 +591,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
591 | if (clone_flags & CLONE_SETTLS) | 591 | if (clone_flags & CLONE_SETTLS) |
592 | t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; | 592 | t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; |
593 | 593 | ||
594 | /* We do not want to accidently trigger system call restart | ||
595 | * handling in the new thread. Therefore, clear out the trap | ||
596 | * type, which will make pt_regs_regs_is_syscall() return false. | ||
597 | */ | ||
598 | pt_regs_clear_trap_type(t->kregs); | ||
599 | |||
600 | return 0; | 594 | return 0; |
601 | } | 595 | } |
602 | 596 | ||
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index f2d88d8f7a42..45d6bf632daa 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c | |||
@@ -332,6 +332,9 @@ void do_rt_sigreturn(struct pt_regs *regs) | |||
332 | regs->tpc = tpc; | 332 | regs->tpc = tpc; |
333 | regs->tnpc = tnpc; | 333 | regs->tnpc = tnpc; |
334 | 334 | ||
335 | /* Prevent syscall restart. */ | ||
336 | pt_regs_clear_trap_type(regs); | ||
337 | |||
335 | sigdelsetmask(&set, ~_BLOCKABLE); | 338 | sigdelsetmask(&set, ~_BLOCKABLE); |
336 | spin_lock_irq(¤t->sighand->siglock); | 339 | spin_lock_irq(¤t->sighand->siglock); |
337 | current->blocked = set; | 340 | current->blocked = set; |
@@ -515,7 +518,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
515 | siginfo_t info; | 518 | siginfo_t info; |
516 | int signr; | 519 | int signr; |
517 | 520 | ||
518 | if (pt_regs_is_syscall(regs)) { | 521 | if (pt_regs_is_syscall(regs) && |
522 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { | ||
519 | pt_regs_clear_trap_type(regs); | 523 | pt_regs_clear_trap_type(regs); |
520 | cookie.restart_syscall = 1; | 524 | cookie.restart_syscall = 1; |
521 | } else | 525 | } else |
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 91f8d0826db1..9415d2c918c5 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c | |||
@@ -268,6 +268,9 @@ void do_sigreturn32(struct pt_regs *regs) | |||
268 | regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); | 268 | regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); |
269 | regs->tstate |= psr_to_tstate_icc(psr); | 269 | regs->tstate |= psr_to_tstate_icc(psr); |
270 | 270 | ||
271 | /* Prevent syscall restart. */ | ||
272 | pt_regs_clear_trap_type(regs); | ||
273 | |||
271 | err |= __get_user(fpu_save, &sf->fpu_save); | 274 | err |= __get_user(fpu_save, &sf->fpu_save); |
272 | if (fpu_save) | 275 | if (fpu_save) |
273 | err |= restore_fpu_state32(regs, &sf->fpu_state); | 276 | err |= restore_fpu_state32(regs, &sf->fpu_state); |
@@ -351,6 +354,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) | |||
351 | regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); | 354 | regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); |
352 | regs->tstate |= psr_to_tstate_icc(psr); | 355 | regs->tstate |= psr_to_tstate_icc(psr); |
353 | 356 | ||
357 | /* Prevent syscall restart. */ | ||
358 | pt_regs_clear_trap_type(regs); | ||
359 | |||
354 | err |= __get_user(fpu_save, &sf->fpu_save); | 360 | err |= __get_user(fpu_save, &sf->fpu_save); |
355 | if (fpu_save) | 361 | if (fpu_save) |
356 | err |= restore_fpu_state32(regs, &sf->fpu_state); | 362 | err |= restore_fpu_state32(regs, &sf->fpu_state); |