From b2633d211b186cb201be327ded53ecf523ecf0bd Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 4 Dec 2015 08:03:02 +0100 Subject: [PATCH] Fix: compat_futex should work-around futex signal-restart kernel bug When testing liburcu on a 3.18 Linux kernel, 2-core MIPS (cpu model : Ingenic JZRISC V4.15 FPU V0.0), we notice that a blocked sys_futex FUTEX_WAIT returns -1, errno=ENOSYS when interrupted by a SA_RESTART signal handler. This spurious ENOSYS behavior causes hangs in liburcu 0.9.x. Running a MIPS 3.18 kernel under a QEMU emulator exhibits the same behavior. This might affect earlier kernels. This issue appears to be fixed in 3.19 since commit e967ef022 "MIPS: Fix restart of indirect syscalls", but nevertheless, we should try to handle this kernel bug more gracefully than a user-space hang due to unexpected spurious ENOSYS return value. Therefore, fallback on the "async-safe" version of compat_futex in those situations where FUTEX_WAIT returns ENOSYS. This async-safe fallback has the nice property of being OK to use concurrently with other FUTEX_WAKE and FUTEX_WAIT futex() calls, because it's simply a busy-wait scheme. The 4.2 kernel on parisc, and likely newer kernels too, are also affected by a similar issue. Signed-off-by: Mathieu Desnoyers CC: Michael Jeanson CC: Paul E. McKenney CC: Ralf Baechle CC: linux-mips@linux-mips.org CC: linux-kernel@vger.kernel.org CC: "James E.J. Bottomley" CC: Helge Deller CC: linux-parisc@vger.kernel.org --- compat_futex.c | 2 ++ urcu/futex.h | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compat_futex.c b/compat_futex.c index b7f78f0..9e918fe 100644 --- a/compat_futex.c +++ b/compat_futex.c @@ -111,6 +111,8 @@ end: * _ASYNC SIGNAL-SAFE_. * For now, timeout, uaddr2 and val3 are unused. * Waiter will busy-loop trying to read the condition. + * It is OK to use compat_futex_async() on a futex address on which + * futex() WAKE operations are also performed. */ int compat_futex_async(int32_t *uaddr, int op, int32_t val, diff --git a/urcu/futex.h b/urcu/futex.h index 4d16cfa..0486ff6 100644 --- a/urcu/futex.h +++ b/urcu/futex.h @@ -73,7 +73,16 @@ static inline int futex_noasync(int32_t *uaddr, int op, int32_t val, ret = futex(uaddr, op, val, timeout, uaddr2, val3); if (caa_unlikely(ret < 0 && errno == ENOSYS)) { - return compat_futex_noasync(uaddr, op, val, timeout, + /* + * The fallback on ENOSYS is the async-safe version of + * the compat futex implementation, because the + * async-safe compat implementation allows being used + * concurrently with calls to futex(). Indeed, sys_futex + * FUTEX_WAIT, on some architectures (mips and parisc), + * within a given process, spuriously return ENOSYS due + * to signal restart bugs on some kernel versions. + */ + return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3); } return ret; -- 2.34.1