[PATCH] ARM: futex: preserve oldval in SMP __futex_atomic_op
Nicolas Pitre
nico at fluxnic.net
Thu Sep 22 15:09:41 EDT 2011
On Thu, 22 Sep 2011, Will Deacon wrote:
> The SMP implementation of __futex_atomic_op clobbers oldval with the
> status flag from the exclusive store. This causes it to always read as
> zero when performing the FUTEX_OP_CMP_* operation.
>
> This patch updates the ARM __futex_atomic_op implementations to take a
> tmp argument, allowing us to store the strex status flag without
> overwriting the register containing oldval.
>
> Cc: stable at kernel.org
> Reported-by: Minho Ben <mhban at samsung.com>
> Signed-off-by: Will Deacon <will.deacon at arm.com>
Reviewed-by: Nicolas Pitre <nicolas.pitre at linaro.org>
> ---
>
> Following up on:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/066348.html
>
> it turns out that we don't need to use named arguments after all,
> although it might be nice to add that as a later patch. For now, I'm
> trying to keep this as small as possible for -stable.
Agreed that named arguments would make this code more obvious,
especially with the insn argument of __futex_atomic_op() which uses
numbered registers away from the actual inline asm statement where it is
used.
I'm a bit worried that the LTP tests still passed though. In theory it
shouldn't have worked at all except if you were lucky with test values.
>
> arch/arm/include/asm/futex.h | 34 +++++++++++++++++-----------------
> 1 files changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
> index 8c73900..253cc86 100644
> --- a/arch/arm/include/asm/futex.h
> +++ b/arch/arm/include/asm/futex.h
> @@ -25,17 +25,17 @@
>
> #ifdef CONFIG_SMP
>
> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
> +#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
> smp_mb(); \
> __asm__ __volatile__( \
> - "1: ldrex %1, [%2]\n" \
> + "1: ldrex %1, [%3]\n" \
> " " insn "\n" \
> - "2: strex %1, %0, [%2]\n" \
> - " teq %1, #0\n" \
> + "2: strex %2, %0, [%3]\n" \
> + " teq %2, #0\n" \
> " bne 1b\n" \
> " mov %0, #0\n" \
> - __futex_atomic_ex_table("%4") \
> - : "=&r" (ret), "=&r" (oldval) \
> + __futex_atomic_ex_table("%5") \
> + : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
> : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
> : "cc", "memory")
>
> @@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> #include <linux/preempt.h>
> #include <asm/domain.h>
>
> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
> +#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
> __asm__ __volatile__( \
> - "1: " T(ldr) " %1, [%2]\n" \
> + "1: " T(ldr) " %1, [%3]\n" \
> " " insn "\n" \
> - "2: " T(str) " %0, [%2]\n" \
> + "2: " T(str) " %0, [%3]\n" \
> " mov %0, #0\n" \
> - __futex_atomic_ex_table("%4") \
> - : "=&r" (ret), "=&r" (oldval) \
> + __futex_atomic_ex_table("%5") \
> + : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
> : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
> : "cc", "memory")
>
> @@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> int cmp = (encoded_op >> 24) & 15;
> int oparg = (encoded_op << 8) >> 20;
> int cmparg = (encoded_op << 20) >> 20;
> - int oldval = 0, ret;
> + int oldval = 0, ret, tmp;
>
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
> @@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
>
> switch (op) {
> case FUTEX_OP_SET:
> - __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> case FUTEX_OP_ADD:
> - __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> case FUTEX_OP_OR:
> - __futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> case FUTEX_OP_ANDN:
> - __futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg);
> + __futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
> break;
> case FUTEX_OP_XOR:
> - __futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> default:
> ret = -ENOSYS;
> --
> 1.7.0.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
More information about the linux-arm-kernel
mailing list