summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorKaz Kojima <kkojima@rr.iij4u.or.jp>2007-06-18 10:08:20 +0900
committerPaul Mundt <lethal@linux-sh.org>2007-06-18 10:08:20 +0900
commit69a331470ff02561cf1898eeb152ccca9f22bf53 (patch)
treee097e9317f5c2e3e03125dfd1e232dfbcebd4a3a /arch/sh/kernel
parent188e1f81ba31af1b65a2f3611df4c670b092bbac (diff)
sh: Fix restartable syscall arg5 clobbering.
We use R0 as the 5th argument of syscall. When the syscall restarts after signal handling, we should restore the old value of R0. The attached patch does it. Without this patch, I've experienced random failures in the situation which signals are issued frequently. Signed-off-by: Kaz Kojima <kkojima@rr.iij4u.or.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/signal.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index b32c35a7c0a..fdca038e4b9 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -481,7 +481,7 @@ give_sigsegv:
static int
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *oldset, struct pt_regs *regs)
+ sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0)
{
int ret;
@@ -500,6 +500,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
}
/* fallthrough */
case -ERESTARTNOINTR:
+ regs->regs[0] = save_r0;
regs->pc -= instruction_size(
ctrl_inw(regs->pc - 4));
break;
@@ -583,7 +584,8 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+ if (handle_signal(signr, &ka, &info, oldset, regs, save_r0)
+ == 0) {
/* a signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply