parisc: fix double restarts
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 19 May 2012 04:29:22 +0000 (00:29 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 1 Oct 2012 13:58:13 +0000 (09:58 -0400)
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 <viro@zeniv.linux.org.uk>
arch/parisc/hpux/gate.S
arch/parisc/kernel/signal.c
arch/parisc/kernel/syscall.S

index 38a1c1b..0114688 100644 (file)
@@ -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 */
        
index 594459b..3790a32 100644 (file)
@@ -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:
index 82a52b2..54a9cbf 100644 (file)
@@ -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 */