From: Al Viro Date: Sat, 19 May 2012 04:29:22 +0000 (-0400) Subject: parisc: fix double restarts X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=00df111e7eb505558c54f23861e9341e56dd5fb0;p=linux-beck.git parisc: fix double restarts Don't bother restoring r28 on syscall restarts; it's clobbered by syscall anyway. Reuse (now unused) ->orig_r28 as "no restarts allowed" flag. Signed-off-by: Al Viro --- diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S index 38a1c1b8d4e8..011468857e98 100644 --- a/arch/parisc/hpux/gate.S +++ b/arch/parisc/hpux/gate.S @@ -71,7 +71,7 @@ ENTRY(hpux_gateway_page) STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */ STREG %r27, TASK_PT_GR27(%r1) /* user dp */ STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */ - STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */ + STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */ STREG %r29, TASK_PT_GR29(%r1) /* 8th argument */ STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */ diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 594459bde14e..3790a3237172 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) (usp - sigframe_size); DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); + regs->orig_r28 = 1; /* no restarts for sigreturn */ + #ifdef CONFIG_64BIT compat_frame = (struct compat_rt_sigframe __user *)frame; @@ -462,6 +464,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) { + if (regs->orig_r28) + return; + regs->orig_r28 = 1; /* no more restarts */ /* Check the return code */ switch (regs->gr[28]) { case -ERESTART_RESTARTBLOCK: @@ -482,8 +487,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) * we have to do is fiddle the return pointer. */ regs->gr[31] -= 8; /* delayed branching */ - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; break; } } @@ -491,6 +494,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) static inline void insert_restart_trampoline(struct pt_regs *regs) { + if (regs->orig_r28) + return; + regs->orig_r28 = 1; /* no more restarts */ switch(regs->gr[28]) { case -ERESTART_RESTARTBLOCK: { /* Restart the system call - no handlers present */ @@ -525,9 +531,6 @@ insert_restart_trampoline(struct pt_regs *regs) flush_user_icache_range(regs->gr[30], regs->gr[30] + 4); regs->gr[31] = regs->gr[30] + 8; - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - return; } case -ERESTARTNOHAND: @@ -539,9 +542,6 @@ insert_restart_trampoline(struct pt_regs *regs) * slot of the branch external instruction. */ regs->gr[31] -= 8; - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - return; } default: diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 82a52b2fb13f..54a9cbfc08ad 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -156,7 +156,7 @@ linux_gateway_entry: STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */ STREG %r27, TASK_PT_GR27(%r1) /* user dp */ STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */ - STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */ + STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */ STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */ STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */