diff options
author | Arnd Bergmann <arnd@arndb.de> | 2021-10-26 13:03:47 +0300 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2021-11-25 02:02:28 +0300 |
commit | 3f2bedabb62c6210df63b604dc988d2f7f56f947 (patch) | |
tree | fb2f5f27895a06bb5c2a2de7784f991b64375e46 /arch/mips/include/asm/futex.h | |
parent | 2202e15b2b1a946ce760d96748cd7477589701ab (diff) | |
download | linux-3f2bedabb62c6210df63b604dc988d2f7f56f947.tar.xz |
futex: Ensure futex_atomic_cmpxchg_inatomic() is present
The boot-time detection of futex_atomic_cmpxchg_inatomic() has a bug on
some 32-bit arm builds, and Thomas Gleixner suggested that setting
CONFIG_HAVE_FUTEX_CMPXCHG would avoid the problem, as it is always present
anyway.
Looking into which other architectures could do the same showed that almost
all architectures have it, the exceptions being:
- some old 32-bit MIPS uniprocessor cores without ll/sc
- one xtensa variant with no SMP
- 32-bit SPARC when built for SMP
Fix MIPS And Xtensa by rearranging the generic code to let it be used
as a fallback.
For SPARC, the SMP definition just ends up turning off futex anyway, so
this can be done at Kconfig time instead. Note that sparc32 glibc requires
the CASA instruction for its mutexes anyway, which is only available when
running on SPARCv9 or LEON CPUs, but needs to be implemented in the sparc32
kernel for those.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Max Filippov <jcmvbkbc@gmail.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Rich Felker <dalias@libc.org>
Link: https://lore.kernel.org/r/20211026100432.1730393-1-arnd@kernel.org
Diffstat (limited to 'arch/mips/include/asm/futex.h')
-rw-r--r-- | arch/mips/include/asm/futex.h | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index d85248404c52..9287110cb06d 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -19,7 +19,11 @@ #include <asm/sync.h> #include <asm/war.h> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ +#define arch_futex_atomic_op_inuser arch_futex_atomic_op_inuser +#define futex_atomic_cmpxchg_inatomic futex_atomic_cmpxchg_inatomic +#include <asm-generic/futex.h> + +#define __futex_atomic_op(op, insn, ret, oldval, uaddr, oparg) \ { \ if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) { \ __asm__ __volatile__( \ @@ -80,9 +84,11 @@ : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ "i" (-EFAULT) \ : "memory"); \ - } else \ - ret = -ENOSYS; \ -} + } else { \ + /* fallback for non-SMP */ \ + ret = arch_futex_atomic_op_inuser_local(op, oparg, oval,\ + uaddr); \ + } static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) @@ -94,23 +100,23 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); + __futex_atomic_op(op, "move $1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("addu $1, %1, %z5", + __futex_atomic_op(op, "addu $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("or $1, %1, %z5", + __futex_atomic_op(op, "or $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and $1, %1, %z5", + __futex_atomic_op(op, "and $1, %1, %z5", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("xor $1, %1, %z5", + __futex_atomic_op(op, "xor $1, %1, %z5", ret, oldval, uaddr, oparg); break; default: @@ -193,8 +199,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) : "memory"); - } else - return -ENOSYS; + } else { + return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval); + } *uval = val; return ret; |