From: Mathieu Desnoyers Date: Fri, 4 Dec 2015 07:03:02 +0000 (+0100) Subject: Fix: compat_futex should work-around futex signal-restart kernel bug X-Git-Tag: v0.8.9~2 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=e9529b91ce756b476f5ad339512482c93c03c046;p=userspace-rcu.git 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 --- diff --git a/compat_futex.c b/compat_futex.c index 6fe378f..dd5bf8a 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 2630354..7f17564 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;