Handling of restarting a system call for nosig should be done after all possible calls of do_signal, to see if one of them actually delivers signal or not.
Before this change, restarting a system call for nosig may be followed by a call of handle_signal which would try to change the system call returning -EINTR instead, but it is too late to do so. In this patch, the function name of do_signal is changed, to avoid breakage of building User Mode Linux. Signed-off-by: NIIBE Yutaka <gni...@fsij.org> --- arch/x86/entry/common.c | 6 +++++- arch/x86/include/asm/signal.h | 4 +++- arch/x86/kernel/signal.c | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 74f6eee15179..14e4da298887 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -137,6 +137,8 @@ static long syscall_trace_enter(struct pt_regs *regs) static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags) { + int sig_result = 0; + /* * In order to return to user mode, we need to have IRQs off with * none of EXIT_TO_USERMODE_LOOP_FLAGS set. Several of these flags @@ -159,7 +161,7 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags) /* deal with pending signal delivery */ if (cached_flags & _TIF_SIGPENDING) - do_signal(regs); + sig_result |= do_signal_x86(regs); if (cached_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); @@ -177,6 +179,8 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags) if (!(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS)) break; } + if (unlikely(sig_result == DO_SIGNAL_NOSIG)) + nosig_restart_syscall(regs); } /* Called with IRQs disabled. */ diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 6517df6d9938..32a861950a63 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -34,8 +34,10 @@ typedef sigset_t compat_sigset_t; #endif /* __ASSEMBLY__ */ #include <uapi/asm/signal.h> +#define DO_SIGNAL_DELIVERED 1 +#define DO_SIGNAL_NOSIG 2 #ifndef __ASSEMBLY__ -extern void do_signal(struct pt_regs *regs); +extern int do_signal_x86(struct pt_regs *regs); extern void nosig_restart_syscall(struct pt_regs *regs); #define __ARCH_HAS_SA_RESTORER diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 9c24df5ca2d4..4a852aa60118 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -803,17 +803,17 @@ static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs) * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -void do_signal(struct pt_regs *regs) +int do_signal_x86(struct pt_regs *regs) { struct ksignal ksig; if (get_signal(&ksig)) { /* Whee! Actually deliver the signal. */ handle_signal(&ksig, regs); - return; + return DO_SIGNAL_DELIVERED; } - nosig_restart_syscall(regs); + return DO_SIGNAL_NOSIG; } void nosig_restart_syscall(struct pt_regs *regs) -- 2.11.0