From 69a331470ff02561cf1898eeb152ccca9f22bf53 Mon Sep 17 00:00:00 2001 From: Kaz Kojima Date: Mon, 18 Jun 2007 10:08:20 +0900 Subject: 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 Signed-off-by: Paul Mundt --- arch/sh/kernel/signal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index b32c35a7c0a3..fdca038e4b91 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 -- cgit v1.2.3 From 5527398218aae85f37552a69fad163fa500c39e4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 18 Jun 2007 18:57:13 +0900 Subject: sh: oops_enter()/oops_exit() in die(). As Russell helpfully pointed out on linux-arch: http://marc.info/?l=linux-arch&m=118208089204630&w=2 We were missing the oops_enter/exit() in the sh die() implementation. As we do support lockdep, it's beneficial to add these calls so lockdep properly disables itself in the die() case. Signed-off-by: Paul Mundt --- arch/sh/kernel/traps.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch') diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 5b75cb6f8f9b..8f18930d5bf8 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -83,6 +83,8 @@ void die(const char * str, struct pt_regs * regs, long err) { static int die_counter; + oops_enter(); + console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); @@ -112,6 +114,7 @@ void die(const char * str, struct pt_regs * regs, long err) if (panic_on_oops) panic("Fatal exception"); + oops_exit(); do_exit(SIGSEGV); } -- cgit v1.2.3 From 3aeb884b4ec442719a2d8aa15316415a7412efd8 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 19 Jun 2007 12:33:21 +0900 Subject: sh: Handle -ERESTART_RESTARTBLOCK for restartable syscalls. The current implementation only handles -ERESTARTNOHAND, whereas we also need to handle -ERESTART_RESTARTBLOCK in the handle_signal() case for restartable system calls. As noted by Carl: This fixes the LTP test nanosleep03 - the current kernel causes -ERESTART_RESTARTBLOCK to reach user space rather than the correct -EINTR. Reported-by: Carl Shaw Signed-off-by: Paul Mundt --- arch/sh/kernel/signal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index fdca038e4b91..e323e299878b 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -268,7 +268,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, badframe: force_sig(SIGSEGV, current); return 0; -} +} /* * Set up a signal frame. @@ -489,6 +489,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, if (regs->tra >= 0) { /* If so, check system call restarting.. */ switch (regs->regs[0]) { + case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: regs->regs[0] = -EINTR; break; @@ -584,8 +585,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, save_r0) - == 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 -- cgit v1.2.3