diff options
author | Sven Schnelle <svens@linux.ibm.com> | 2021-06-11 10:27:51 +0200 |
---|---|---|
committer | Sasha Levin <sashal@kernel.org> | 2021-06-30 08:47:03 -0400 |
commit | c37ba4086c805c8309cd6a431a0c426de05bcf51 (patch) | |
tree | 260dd1bb342aae61a3de379e399a16ed12135ed3 | |
parent | 24b8aa8c90a86d95600549f2dbdd2fc7381e48d9 (diff) | |
download | linux-stable-c37ba4086c805c8309cd6a431a0c426de05bcf51.tar.gz linux-stable-c37ba4086c805c8309cd6a431a0c426de05bcf51.tar.bz2 linux-stable-c37ba4086c805c8309cd6a431a0c426de05bcf51.zip |
s390: fix system call restart with multiple signals
commit fc66127dc3396338f287c3b494dfbf102547e770 upstream.
glibc complained with "The futex facility returned an unexpected error
code.". It turned out that the futex syscall returned -ERESTARTSYS because
a signal is pending. arch_do_signal_or_restart() restored the syscall
parameters (nameley regs->gprs[2]) and set PIF_SYSCALL_RESTART. When
another signal is made pending later in the exit loop
arch_do_signal_or_restart() is called again. This function clears
PIF_SYSCALL_RESTART and checks the return code which is set in
regs->gprs[2]. However, regs->gprs[2] was restored in the previous run
and no longer contains -ERESTARTSYS, so PIF_SYSCALL_RESTART isn't set
again and the syscall is skipped.
Fix this by not clearing PIF_SYSCALL_RESTART - it is already cleared in
__do_syscall() when the syscall is restarted.
Reported-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Fixes: 56e62a737028 ("s390: convert to generic entry")
Cc: <stable@vger.kernel.org> # 5.12
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | arch/s390/kernel/signal.c | 1 |
1 files changed, 0 insertions, 1 deletions
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 90163e6184f5..080e7aed181f 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -512,7 +512,6 @@ void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) /* No handlers present - check for system call restart */ clear_pt_regs_flag(regs, PIF_SYSCALL); - clear_pt_regs_flag(regs, PIF_SYSCALL_RESTART); if (current->thread.system_call) { regs->int_code = current->thread.system_call; switch (regs->gprs[2]) { |