Fix: compat_futex should work-around futex signal-restart kernel bug
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 4 Dec 2015 07:03:02 +0000 (08:03 +0100)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 18 Dec 2015 20:10:30 +0000 (15:10 -0500)
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 <mathieu.desnoyers@efficios.com>
CC: Michael Jeanson <mjeanson@efficios.com>
CC: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
CC: Ralf Baechle <ralf@linux-mips.org>
CC: linux-mips@linux-mips.org
CC: linux-kernel@vger.kernel.org
CC: "James E.J. Bottomley" <jejb@parisc-linux.org>
CC: Helge Deller <deller@gmx.de>
CC: linux-parisc@vger.kernel.org
compat_futex.c
urcu/futex.h

index b7f78f0..9e918fe 100644 (file)
@@ -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,
index 4d16cfa..0486ff6 100644 (file)
@@ -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;
This page took 0.031544 seconds and 4 git commands to generate.