diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-05-02 21:02:03 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-05-21 14:39:11 -0400 |
commit | 6b5c8045ecc7e726cdaa2a9d9c8e5008050e1252 (patch) | |
tree | 2bf168797818da579310adcd192765fcbe34ae87 /arch/arm/kernel | |
parent | 21c1176a72bd019d513b26e05d491a31b50b18d2 (diff) |
arm: new way of handling ERESTART_RESTARTBLOCK
new "syscall start" flag; handled in syscall_trace() by switching
syscall number to that of syscall_restart(2). Restarts of that
kind (ERESTART_RESTARTBLOCK) are handled by setting that bit;
syscall number is not modified until the actual call.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/ptrace.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 33 |
2 files changed, 9 insertions, 27 deletions
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9650c143afc1..d407ebf41801 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/hw_breakpoint.h> | 24 | #include <linux/hw_breakpoint.h> |
25 | #include <linux/regset.h> | 25 | #include <linux/regset.h> |
26 | #include <linux/audit.h> | 26 | #include <linux/audit.h> |
27 | #include <linux/unistd.h> | ||
27 | 28 | ||
28 | #include <asm/pgtable.h> | 29 | #include <asm/pgtable.h> |
29 | #include <asm/traps.h> | 30 | #include <asm/traps.h> |
@@ -916,6 +917,8 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) | |||
916 | audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, | 917 | audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, |
917 | regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); | 918 | regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); |
918 | 919 | ||
920 | if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS)) | ||
921 | scno = __NR_restart_syscall - __NR_SYSCALL_BASE; | ||
919 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | 922 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) |
920 | return scno; | 923 | return scno; |
921 | if (!(current->ptrace & PT_PTRACED)) | 924 | if (!(current->ptrace & PT_PTRACED)) |
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 6b37d4ddf0b6..75c70d1850df 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
@@ -624,12 +624,10 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
624 | case -ERESTARTNOHAND: | 624 | case -ERESTARTNOHAND: |
625 | case -ERESTARTSYS: | 625 | case -ERESTARTSYS: |
626 | case -ERESTARTNOINTR: | 626 | case -ERESTARTNOINTR: |
627 | case -ERESTART_RESTARTBLOCK: | ||
627 | regs->ARM_r0 = regs->ARM_ORIG_r0; | 628 | regs->ARM_r0 = regs->ARM_ORIG_r0; |
628 | regs->ARM_pc = restart_addr; | 629 | regs->ARM_pc = restart_addr; |
629 | break; | 630 | break; |
630 | case -ERESTART_RESTARTBLOCK: | ||
631 | regs->ARM_r0 = -EINTR; | ||
632 | break; | ||
633 | } | 631 | } |
634 | } | 632 | } |
635 | 633 | ||
@@ -647,12 +645,14 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
647 | * debugger has chosen to restart at a different PC. | 645 | * debugger has chosen to restart at a different PC. |
648 | */ | 646 | */ |
649 | if (regs->ARM_pc == restart_addr) { | 647 | if (regs->ARM_pc == restart_addr) { |
650 | if (retval == -ERESTARTNOHAND | 648 | if (retval == -ERESTARTNOHAND || |
649 | retval == -ERESTART_RESTARTBLOCK | ||
651 | || (retval == -ERESTARTSYS | 650 | || (retval == -ERESTARTSYS |
652 | && !(ka.sa.sa_flags & SA_RESTART))) { | 651 | && !(ka.sa.sa_flags & SA_RESTART))) { |
653 | regs->ARM_r0 = -EINTR; | 652 | regs->ARM_r0 = -EINTR; |
654 | regs->ARM_pc = continue_addr; | 653 | regs->ARM_pc = continue_addr; |
655 | } | 654 | } |
655 | clear_thread_flag(TIF_SYSCALL_RESTARTSYS); | ||
656 | } | 656 | } |
657 | 657 | ||
658 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 658 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
@@ -679,29 +679,8 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
679 | * ignore the restart. | 679 | * ignore the restart. |
680 | */ | 680 | */ |
681 | if (retval == -ERESTART_RESTARTBLOCK | 681 | if (retval == -ERESTART_RESTARTBLOCK |
682 | && regs->ARM_pc == continue_addr) { | 682 | && regs->ARM_pc == restart_addr) |
683 | if (thumb_mode(regs)) { | 683 | set_thread_flag(TIF_SYSCALL_RESTARTSYS); |
684 | regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; | ||
685 | regs->ARM_pc -= 2; | ||
686 | } else { | ||
687 | #if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) | ||
688 | regs->ARM_r7 = __NR_restart_syscall; | ||
689 | regs->ARM_pc -= 4; | ||
690 | #else | ||
691 | u32 __user *usp; | ||
692 | |||
693 | regs->ARM_sp -= 4; | ||
694 | usp = (u32 __user *)regs->ARM_sp; | ||
695 | |||
696 | if (put_user(regs->ARM_pc, usp) == 0) { | ||
697 | regs->ARM_pc = KERN_RESTART_CODE; | ||
698 | } else { | ||
699 | regs->ARM_sp += 4; | ||
700 | force_sigsegv(0, current); | ||
701 | } | ||
702 | #endif | ||
703 | } | ||
704 | } | ||
705 | } | 684 | } |
706 | 685 | ||
707 | /* If there's no signal to deliver, we just put the saved sigmask | 686 | /* If there's no signal to deliver, we just put the saved sigmask |