2011-03-07 02:11:40

by Michel Lespinasse

[permalink] [raw]
Subject: [PATCH] futex: cmpxchg_futex_value_locked API change

Aplogies for the long CC list - as this proposal involves asm changes
in many architectures, and I have only been able to test on x86,
I have tried to include one maintainer from every arch so they can
hopefully double check me. I do think I got all architectures right,
but you can never be 100% sure...

------------------------------------8<---------------------------------

The cmpxchg_futex_value_locked API was funny in that it returned either
the original, user-exposed futex value OR an error code such as -EFAULT.
This was confusing at best, and could be a source of livelocks in places
that retry the cmpxchg_futex_value_locked after trying to fix the issue
by running fault_in_user_writeable().

This change makes the cmpxchg_futex_value_locked API more similar to the
get_futex_value_locked one, returning an error code and updating the
original value through a reference argument.

Signed-off-by: Michel Lespinasse <[email protected]>
---
arch/alpha/include/asm/futex.h | 22 +++++++++-------
arch/arm/include/asm/futex.h | 23 +++++++++--------
arch/frv/include/asm/futex.h | 3 +-
arch/ia64/include/asm/futex.h | 9 ++++--
arch/microblaze/include/asm/futex.h | 24 ++++++++++--------
arch/mips/include/asm/futex.h | 32 +++++++++++++-----------
arch/parisc/include/asm/futex.h | 18 +++++++-------
arch/powerpc/include/asm/futex.h | 20 ++++++++-------
arch/s390/include/asm/futex.h | 4 +-
arch/s390/include/asm/uaccess.h | 2 +-
arch/s390/lib/uaccess.h | 4 +-
arch/s390/lib/uaccess_pt.c | 13 ++++++----
arch/s390/lib/uaccess_std.c | 6 +++-
arch/sh/include/asm/futex-irq.h | 9 +++----
arch/sh/include/asm/futex.h | 5 ++-
arch/sparc/include/asm/futex_64.h | 16 +++++++----
arch/tile/include/asm/futex.h | 7 +++--
arch/x86/include/asm/futex.h | 16 +++++++-----
include/asm-generic/futex.h | 3 +-
kernel/futex.c | 46 ++++++++++++----------------------
20 files changed, 147 insertions(+), 135 deletions(-)

diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index 945de22..c4e5c28 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -81,21 +81,22 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev, cmp;
+ int ret = 0, prev, cmp;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

__asm__ __volatile__ (
__ASM_SMP_MB
- "1: ldl_l %0,0(%2)\n"
- " cmpeq %0,%3,%1\n"
- " beq %1,3f\n"
- " mov %4,%1\n"
- "2: stl_c %1,0(%2)\n"
- " beq %1,4f\n"
+ "1: ldl_l %1,0(%3)\n"
+ " cmpeq %1,%4,%2\n"
+ " beq %2,3f\n"
+ " mov %5,%2\n"
+ "2: stl_c %2,0(%3)\n"
+ " beq %2,4f\n"
"3: .subsection 2\n"
"4: br 1b\n"
" .previous\n"
@@ -105,11 +106,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .long 2b-.\n"
" lda $31,3b-2b(%0)\n"
" .previous\n"
- : "=&r"(prev), "=&r"(cmp)
+ : "+r"(ret), "=&r"(prev), "=&r"(cmp)
: "r"(uaddr), "r"((long)oldval), "r"(newval)
: "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index b33fe70..d20b78f 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -88,36 +88,37 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int val;
+ int ret = 0, val;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- pagefault_disable(); /* implies preempt_disable() */
+ /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
+ * call sites. */

__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
- "1: " T(ldr) " %0, [%3]\n"
- " teq %0, %1\n"
+ "1: " T(ldr) " %1, [%4]\n"
+ " teq %1, %2\n"
" it eq @ explicit IT needed for the 2b label\n"
- "2: " T(streq) " %2, [%3]\n"
+ "2: " T(streq) " %3, [%4]\n"
"3:\n"
" .pushsection __ex_table,\"a\"\n"
" .align 3\n"
" .long 1b, 4f, 2b, 4f\n"
" .popsection\n"
" .pushsection .fixup,\"ax\"\n"
- "4: mov %0, %4\n"
+ "4: mov %0, %5\n"
" b 3b\n"
" .popsection"
- : "=&r" (val)
+ : "+r" (ret), "=&r" (val)
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
: "cc", "memory");

- pagefault_enable(); /* subsumes preempt_enable() */
-
- return val;
+ *uval = val;
+ return ret;
}

#endif /* !SMP */
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 08b3d1d..0548f8e 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -10,7 +10,8 @@
extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
return -ENOSYS;
}
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index c7f0f06..b072840 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

{
- register unsigned long r8 __asm ("r8");
+ register unsigned long r8 __asm ("r8") = 0;
+ unsigned long prev;
__asm__ __volatile__(
" mf;; \n"
" mov ar.ccv=%3;; \n"
"[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
" .xdata4 \"__ex_table\", 1b-., 2f-. \n"
"[2:]"
- : "=r" (r8)
+ : "=r" (prev)
: "r" (uaddr), "r" (newval),
"rO" ((long) (unsigned) oldval)
: "memory");
+ *uval = prev;
return r8;
}
}
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index ad3fd61..fa019ed 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -94,31 +94,33 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev, cmp;
+ int ret = 0, prev, cmp;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- __asm__ __volatile__ ("1: lwx %0, %2, r0; \
- cmp %1, %0, %3; \
- beqi %1, 3f; \
- 2: swx %4, %2, r0; \
- addic %1, r0, 0; \
- bnei %1, 1b; \
+ __asm__ __volatile__ ("1: lwx %1, %3, r0; \
+ cmp %2, %1, %4; \
+ beqi %2, 3f; \
+ 2: swx %5, %3, r0; \
+ addic %2, r0, 0; \
+ bnei %2, 1b; \
3: \
.section .fixup,\"ax\"; \
4: brid 3b; \
- addik %0, r0, %5; \
+ addik %0, r0, %6; \
.previous; \
.section __ex_table,\"a\"; \
.word 1b,4b,2b,4b; \
.previous;" \
- : "=&r" (prev), "=&r"(cmp) \
+ : "+r" (ret), "=&r" (prev), "=&r"(cmp) \
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index b9cce90..692a24b 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -132,9 +132,10 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int retval;
+ int ret = 0, val;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
@@ -145,25 +146,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqzl $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else if (cpu_has_llsc) {
@@ -172,31 +173,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else
return -ENOSYS;

- return retval;
+ *uval = val;
+ return ret;
}

#endif
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 0c705c3..4c6d867 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)

/* Non-atomic version */
static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int err = 0;
- int uval;
+ int val;

/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -65,12 +65,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- err = get_user(uval, uaddr);
- if (err) return -EFAULT;
- if (uval == oldval)
- err = put_user(newval, uaddr);
- if (err) return -EFAULT;
- return uval;
+ if (get_user(val, uaddr))
+ return -EFAULT;
+ if (val == oldval && put_user(newval, uaddr))
+ return -EFAULT;
+ *uval = val;
+ return 0;
}

#endif /*__KERNEL__*/
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 7c589ef..631e8da 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -82,35 +82,37 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev;
+ int ret = 0, prev;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

__asm__ __volatile__ (
PPC_RELEASE_BARRIER
-"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
- cmpw 0,%0,%3\n\
+"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
+ cmpw 0,%1,%4\n\
bne- 3f\n"
- PPC405_ERR77(0,%2)
-"2: stwcx. %4,0,%2\n\
+ PPC405_ERR77(0,%3)
+"2: stwcx. %5,0,%3\n\
bne- 1b\n"
PPC_ACQUIRE_BARRIER
"3: .section .fixup,\"ax\"\n\
-4: li %0,%5\n\
+4: li %0,%6\n\
b 3b\n\
.previous\n\
.section __ex_table,\"a\"\n\
.align 3\n\
" PPC_LONG "1b,4b,2b,4b\n\
.previous" \
- : "=&r" (prev), "+m" (*uaddr)
+ : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
: "cc", "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 5c5d02d..27ac515 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
int oldval, int newval)
{
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
+ return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index d6b1ed0..549adf6 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -84,7 +84,7 @@ struct uaccess_ops {
size_t (*strnlen_user)(size_t, const char __user *);
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
+ int (*futex_atomic_cmpxchg)(int *, int __user *, int old, int new);
};

extern struct uaccess_ops uaccess;
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index 126011d..89a8067 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
extern size_t copy_to_user_std(size_t, void __user *, const void *);
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_cmpxchg_std(int *, int __user *, int, int);
extern int futex_atomic_op_std(int, int __user *, int, int *);

extern size_t copy_from_user_pt(size_t, const void __user *, void *);
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+extern int futex_atomic_cmpxchg_pt(int *, int __user *, int, int);

#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 404f2de..e4f9ad8 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

asm volatile("0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: l %0,0\n"
"2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

if (segment_eq(get_fs(), KERNEL_DS))
- return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
spin_lock(&current->mm->page_table_lock);
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
if (!uaddr) {
@@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
}
get_page(virt_to_page(uaddr));
spin_unlock(&current->mm->page_table_lock);
- ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
put_page(virt_to_page(uaddr));
return ret;
}
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index a6c4f7e..5c568b3 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -287,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

asm volatile(
" sacf 256\n"
"0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: l %0,0\n"
"2: sacf 0\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index a9f16a7..7b701cb 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -88,7 +88,8 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
+static inline int atomic_futex_op_cmpxchg_inatomic(int *uval,
+ int __user *uaddr,
int oldval, int newval)
{
unsigned long flags;
@@ -102,10 +103,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,

local_irq_restore(flags);

- if (ret)
- return ret;
-
- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __ASM_SH_FUTEX_IRQ_H */
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index 68256ec..a8a5125 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
+ return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index 47f9583..e086220 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
+ int ret = 0;
+
__asm__ __volatile__(
- "\n1: casa [%3] %%asi, %2, %0\n"
+ "\n1: casa [%4] %%asi, %3, %1\n"
"2:\n"
" .section .fixup,#alloc,#execinstr\n"
" .align 4\n"
"3: sethi %%hi(2b), %0\n"
" jmpl %0 + %%lo(2b), %%g0\n"
- " mov %4, %0\n"
+ " mov %5, %0\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .align 4\n"
" .word 1b, 3b\n"
" .previous\n"
- : "=r" (newval)
- : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
+ : "+r" (ret), "=r" (newval)
+ : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
: "memory");

- return newval;
+ *uval = newval;
+ return ret;
}

#endif /* !(_SPARC64_FUTEX_H) */
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index fe0d10d..664b20a 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -119,8 +119,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
struct __get_user asm_ret;

@@ -128,7 +128,8 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
return -EFAULT;

asm_ret = futex_cmpxchg(uaddr, oldval, newval);
- return asm_ret.err ? asm_ret.err : asm_ret.val;
+ *uval = asm_ret.val;
+ return asm_ret.err;
}

#ifndef __tilegx__
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 1f11ce4..884c0b5 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
+ int ret = 0;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
/* Real i386 machines have no cmpxchg instruction */
@@ -122,18 +123,19 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
+ asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
"2:\t.section .fixup, \"ax\"\n"
- "3:\tmov %2, %0\n"
+ "3:\tmov %3, %0\n"
"\tjmp 2b\n"
"\t.previous\n"
_ASM_EXTABLE(1b, 3b)
- : "=a" (oldval), "+m" (*uaddr)
- : "i" (-EFAULT), "r" (newval), "0" (oldval)
+ : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
+ : "i" (-EFAULT), "r" (newval), "1" (oldval)
: "memory"
);

- return oldval;
+ *uval = oldval;
+ return ret;
}

#endif
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 3c2344f..132bf52 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
return -ENOSYS;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 3184d3b..53b783f 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
return NULL;
}

-static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
+static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
+ u32 uval, u32 newval)
{
- u32 curval;
+ int ret;

pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+ ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
pagefault_enable();

- return curval;
+ return ret;
}

static int get_futex_value_locked(u32 *dest, u32 __user *from)
@@ -688,9 +689,7 @@ retry:
if (set_waiters)
newval |= FUTEX_WAITERS;

- curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
return -EFAULT;

/*
@@ -728,9 +727,7 @@ retry:
lock_taken = 1;
}

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
return -EFAULT;
if (unlikely(curval != uval))
goto retry;
@@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)

newval = FUTEX_WAITERS | task_pid_vnr(new_owner);

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
ret = -EFAULT;
else if (curval != uval)
ret = -EINVAL;
@@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
* There is no waiter, so we unlock the futex. The owner died
* bit has not to be preserved here. We are the owner:
*/
- oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
-
- if (oldval == -EFAULT)
- return oldval;
+ if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
+ return -EFAULT;
if (oldval != uval)
return -EAGAIN;

@@ -1578,9 +1571,7 @@ retry:
while (1) {
newval = (uval & FUTEX_OWNER_DIED) | newtid;

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
goto handle_fault;
if (curval == uval)
break;
@@ -2073,11 +2064,9 @@ retry:
* again. If it succeeds then we can return without waking
* anyone else up:
*/
- if (!(uval & FUTEX_OWNER_DIED))
- uval = cmpxchg_futex_value_locked(uaddr, task_pid_vnr(current), 0);
-
-
- if (unlikely(uval == -EFAULT))
+ if (!(uval & FUTEX_OWNER_DIED) &&
+ unlikely(cmpxchg_futex_value_locked(&uval, uaddr,
+ task_pid_vnr(current), 0)))
goto pi_faulted;
/*
* Rare case: we managed to release the lock atomically,
@@ -2464,9 +2453,7 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
-
- if (nval == -EFAULT)
+ if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
return -1;

if (nval != uval)
@@ -2679,8 +2666,7 @@ static int __init futex_init(void)
* implementation, the non-functional ones will return
* -ENOSYS.
*/
- curval = cmpxchg_futex_value_locked(NULL, 0, 0);
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
futex_cmpxchg_enabled = 1;

for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
--
1.7.3.1



--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.


2011-03-07 08:54:55

by Martin Schwidefsky

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Sun, 6 Mar 2011 18:11:27 -0800
Michel Lespinasse <[email protected]> wrote:

> Aplogies for the long CC list - as this proposal involves asm changes
> in many architectures, and I have only been able to test on x86,
> I have tried to include one maintainer from every arch so they can
> hopefully double check me. I do think I got all architectures right,
> but you can never be 100% sure...
>
> -static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> +static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
> + int oldval, int newval)
> {
> int ret;
>
> asm volatile("0: cs %1,%4,0(%5)\n"
> - "1: lr %0,%1\n"
> + "1: l %0,0\n"
> "2:\n"
> EX_TABLE(0b,2b) EX_TABLE(1b,2b)
> : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
> : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
> : "cc", "memory" );
> + *uval = oldval;
> return ret;
> }

That "l %0,0" is incorrect; if you want to load a zero into %0 you can use "la %0,0".

--
blue skies,
Martin.

"Reality continues to ruin my life." - Calvin.

2011-03-07 14:25:38

by Chris Metcalf

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On 3/6/2011 9:11 PM, Michel Lespinasse wrote:
> The cmpxchg_futex_value_locked API was funny in that it returned either
> the original, user-exposed futex value OR an error code such as -EFAULT.
> This was confusing at best, and could be a source of livelocks in places
> that retry the cmpxchg_futex_value_locked after trying to fix the issue
> by running fault_in_user_writeable().
>
> This change makes the cmpxchg_futex_value_locked API more similar to the
> get_futex_value_locked one, returning an error code and updating the
> original value through a reference argument.
> [...]
> diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h

Makes sense to me; that API is a little crazy.

For the tile changes:

Acked-by: Chris Metcalf <[email protected]>

--
Chris Metcalf, Tilera Corp.
http://www.tilera.com

2011-03-07 21:58:34

by Tony Luck

[permalink] [raw]
Subject: RE: [PATCH] futex: cmpxchg_futex_value_locked API change

Tried out the ia64 bits. They seem fine.

Acked-by: Tony Luck <[email protected]>

2011-03-08 20:18:35

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Sun, 6 Mar 2011, Michel Lespinasse wrote:
> The cmpxchg_futex_value_locked API was funny in that it returned either
> the original, user-exposed futex value OR an error code such as -EFAULT.
> This was confusing at best, and could be a source of livelocks in places
> that retry the cmpxchg_futex_value_locked after trying to fix the issue
> by running fault_in_user_writeable().
>
> This change makes the cmpxchg_futex_value_locked API more similar to the
> get_futex_value_locked one, returning an error code and updating the
> original value through a reference argument.

Ack.

> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
> + int oldval, int newval)

Can we please change the arguments to u32 while at it? The futex core
code uses u32 all over the place so those inlines should do the same.

Thanks,

tglx

2011-03-09 11:08:27

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

Michel Lespinasse wrote:
> Aplogies for the long CC list - as this proposal involves asm changes
> in many architectures, and I have only been able to test on x86,
> I have tried to include one maintainer from every arch so they can
> hopefully double check me. I do think I got all architectures right,
> but you can never be 100% sure...
>
> ------------------------------------8<---------------------------------
>
> The cmpxchg_futex_value_locked API was funny in that it returned either
> the original, user-exposed futex value OR an error code such as -EFAULT.
> This was confusing at best, and could be a source of livelocks in places
> that retry the cmpxchg_futex_value_locked after trying to fix the issue
> by running fault_in_user_writeable().
>
> This change makes the cmpxchg_futex_value_locked API more similar to the
> get_futex_value_locked one, returning an error code and updating the
> original value through a reference argument.
>
> Signed-off-by: Michel Lespinasse <[email protected]>
> ---
> arch/alpha/include/asm/futex.h | 22 +++++++++-------
> arch/arm/include/asm/futex.h | 23 +++++++++--------
> arch/frv/include/asm/futex.h | 3 +-
> arch/ia64/include/asm/futex.h | 9 ++++--
> arch/microblaze/include/asm/futex.h | 24 ++++++++++--------

For microblaze:
Tested-by: Michal Simek <[email protected]>

M

--
Michal Simek, Ing. (M.Eng)
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian

2011-03-09 11:30:58

by Michel Lespinasse

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Tue, Mar 08, 2011 at 09:17:11PM +0100, Thomas Gleixner wrote:
> On Sun, 6 Mar 2011, Michel Lespinasse wrote:
> > The cmpxchg_futex_value_locked API was funny in that it returned either
> > the original, user-exposed futex value OR an error code such as -EFAULT.
> > This was confusing at best, and could be a source of livelocks in places
> > that retry the cmpxchg_futex_value_locked after trying to fix the issue
> > by running fault_in_user_writeable().
> >
> > This change makes the cmpxchg_futex_value_locked API more similar to the
> > get_futex_value_locked one, returning an error code and updating the
> > original value through a reference argument.
>
> Ack.
>
> > static inline int
> > -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> > +futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
> > + int oldval, int newval)
>
> Can we please change the arguments to u32 while at it? The futex core
> code uses u32 all over the place so those inlines should do the same.

All right. Attaching updated version of the diff. I also fixed the s390
issue reported by Martin Schwidefsky.

What's the proper path to check this in, could you send it towards
the -next tree so it gets more testing ?

--------------------------------------8<-------------------------------

The cmpxchg_futex_value_locked API was funny in that it returned either
the original, user-exposed futex value OR an error code such as -EFAULT.
This was confusing at best, and could be a source of livelocks in places
that retry the cmpxchg_futex_value_locked after trying to fix the issue
by running fault_in_user_writeable().

This change makes the cmpxchg_futex_value_locked API more similar to the
get_futex_value_locked one, returning an error code and updating the
original value through a reference argument.

Additionally, the futex pointer types have been changed to u32 * in both
futex_atomic_cmpxchg_inatomic and futex_atomic_op_inuser internal APIs
as suggested by Thomas Gleixner.

Signed-off-by: Michel Lespinasse <[email protected]>
Acked-by: Chris Metcalf <[email protected]> (for tile)
Acked-by: Tony Luck <[email protected]> (for ia64)
Acked-by: Thomas Gleixner <[email protected]>
Tested-by: Michal Simek <[email protected]> (for microblaze)

---
arch/alpha/include/asm/futex.h | 29 ++++++++++++----------
arch/arm/include/asm/futex.h | 30 ++++++++++++----------
arch/frv/include/asm/futex.h | 5 ++-
arch/frv/kernel/futex.c | 14 +++++-----
arch/ia64/include/asm/futex.h | 15 +++++++----
arch/microblaze/include/asm/futex.h | 31 +++++++++++++----------
arch/mips/include/asm/futex.h | 39 ++++++++++++++++-------------
arch/parisc/include/asm/futex.h | 24 +++++++++---------
arch/powerpc/include/asm/futex.h | 27 +++++++++++---------
arch/s390/include/asm/futex.h | 12 ++++----
arch/s390/include/asm/uaccess.h | 4 +-
arch/s390/lib/uaccess.h | 8 +++---
arch/s390/lib/uaccess_pt.c | 17 +++++++-----
arch/s390/lib/uaccess_std.c | 8 ++++--
arch/sh/include/asm/futex-irq.h | 24 +++++++++---------
arch/sh/include/asm/futex.h | 11 ++++----
arch/sparc/include/asm/futex_64.h | 20 +++++++++------
arch/tile/include/asm/futex.h | 27 ++++++++++----------
arch/x86/include/asm/futex.h | 22 +++++++++-------
include/asm-generic/futex.h | 7 +++--
kernel/futex.c | 46 ++++++++++++----------------------
21 files changed, 219 insertions(+), 201 deletions(-)

diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index 945de22..e8a761a 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -29,7 +29,7 @@
: "r" (uaddr), "r"(oparg) \
: "memory")

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -81,21 +81,23 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int prev, cmp;
+ int ret = 0, cmp;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ (
__ASM_SMP_MB
- "1: ldl_l %0,0(%2)\n"
- " cmpeq %0,%3,%1\n"
- " beq %1,3f\n"
- " mov %4,%1\n"
- "2: stl_c %1,0(%2)\n"
- " beq %1,4f\n"
+ "1: ldl_l %1,0(%3)\n"
+ " cmpeq %1,%4,%2\n"
+ " beq %2,3f\n"
+ " mov %5,%2\n"
+ "2: stl_c %2,0(%3)\n"
+ " beq %2,4f\n"
"3: .subsection 2\n"
"4: br 1b\n"
" .previous\n"
@@ -105,11 +107,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .long 2b-.\n"
" lda $31,3b-2b(%0)\n"
" .previous\n"
- : "=&r"(prev), "=&r"(cmp)
+ : "+r"(ret), "=&r"(prev), "=&r"(cmp)
: "r"(uaddr), "r"((long)oldval), "r"(newval)
: "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index b33fe70..0e29d8e 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -35,7 +35,7 @@
: "cc", "memory")

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -46,7 +46,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable(); /* implies preempt_disable() */
@@ -88,36 +88,38 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int val;
+ int ret = 0;
+ u32 val;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- pagefault_disable(); /* implies preempt_disable() */
+ /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
+ * call sites. */

__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
- "1: " T(ldr) " %0, [%3]\n"
- " teq %0, %1\n"
+ "1: " T(ldr) " %1, [%4]\n"
+ " teq %1, %2\n"
" it eq @ explicit IT needed for the 2b label\n"
- "2: " T(streq) " %2, [%3]\n"
+ "2: " T(streq) " %3, [%4]\n"
"3:\n"
" .pushsection __ex_table,\"a\"\n"
" .align 3\n"
" .long 1b, 4f, 2b, 4f\n"
" .popsection\n"
" .pushsection .fixup,\"ax\"\n"
- "4: mov %0, %4\n"
+ "4: mov %0, %5\n"
" b 3b\n"
" .popsection"
- : "=&r" (val)
+ : "+r" (ret), "=&r" (val)
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
: "cc", "memory");

- pagefault_enable(); /* subsumes preempt_enable() */
-
- return val;
+ *uval = val;
+ return ret;
}

#endif /* !SMP */
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 08b3d1d..4bea27f 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -7,10 +7,11 @@
#include <asm/errno.h>
#include <asm/uaccess.h>

-extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
+extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
return -ENOSYS;
}
diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
index 14f64b0..d155ca9 100644
--- a/arch/frv/kernel/futex.c
+++ b/arch/frv/kernel/futex.c
@@ -18,7 +18,7 @@
* the various futex operations; MMU fault checking is ignored under no-MMU
* conditions
*/
-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -50,7 +50,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -83,7 +83,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -116,7 +116,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_ol
return ret;
}

-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -149,7 +149,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -186,7 +186,7 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_o
/*
* do the futex operations
*/
-int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index c7f0f06..8428525 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -46,7 +46,7 @@ do { \
} while (0)

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

{
- register unsigned long r8 __asm ("r8");
+ register unsigned long r8 __asm ("r8") = 0;
+ unsigned long prev;
__asm__ __volatile__(
" mf;; \n"
" mov ar.ccv=%3;; \n"
"[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
" .xdata4 \"__ex_table\", 1b-., 2f-. \n"
"[2:]"
- : "=r" (r8)
+ : "=r" (prev)
: "r" (uaddr), "r" (newval),
"rO" ((long) (unsigned) oldval)
: "memory");
+ *uval = prev;
return r8;
}
}
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index ad3fd61..b0526d2 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -29,7 +29,7 @@
})

static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -94,31 +94,34 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int prev, cmp;
+ int ret = 0, cmp;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- __asm__ __volatile__ ("1: lwx %0, %2, r0; \
- cmp %1, %0, %3; \
- beqi %1, 3f; \
- 2: swx %4, %2, r0; \
- addic %1, r0, 0; \
- bnei %1, 1b; \
+ __asm__ __volatile__ ("1: lwx %1, %3, r0; \
+ cmp %2, %1, %4; \
+ beqi %2, 3f; \
+ 2: swx %5, %3, r0; \
+ addic %2, r0, 0; \
+ bnei %2, 1b; \
3: \
.section .fixup,\"ax\"; \
4: brid 3b; \
- addik %0, r0, %5; \
+ addik %0, r0, %6; \
.previous; \
.section __ex_table,\"a\"; \
.word 1b,4b,2b,4b; \
.previous;" \
- : "=&r" (prev), "=&r"(cmp) \
+ : "+r" (ret), "=&r" (prev), "=&r"(cmp) \
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index b9cce90..6ebf173 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -75,7 +75,7 @@
}

static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -85,7 +85,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -132,11 +132,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int retval;
+ int ret = 0;
+ u32 val;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

if (cpu_has_llsc && R10000_LLSC_WAR) {
@@ -145,25 +147,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqzl $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else if (cpu_has_llsc) {
@@ -172,31 +174,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else
return -ENOSYS;

- return retval;
+ *uval = val;
+ return ret;
}

#endif
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 0c705c3..67a33cc 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,7 +8,7 @@
#include <asm/errno.h>

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)

/* Non-atomic version */
static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int err = 0;
- int uval;
+ u32 val;

/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -62,15 +62,15 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
return -EFAULT;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- err = get_user(uval, uaddr);
- if (err) return -EFAULT;
- if (uval == oldval)
- err = put_user(newval, uaddr);
- if (err) return -EFAULT;
- return uval;
+ if (get_user(val, uaddr))
+ return -EFAULT;
+ if (val == oldval && put_user(newval, uaddr))
+ return -EFAULT;
+ *uval = val;
+ return 0;
}

#endif /*__KERNEL__*/
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 7c589ef..c94e4a3 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -30,7 +30,7 @@
: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
: "cr0", "memory")

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -40,7 +40,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -82,35 +82,38 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int prev;
+ int ret = 0;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ (
PPC_RELEASE_BARRIER
-"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
- cmpw 0,%0,%3\n\
+"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
+ cmpw 0,%1,%4\n\
bne- 3f\n"
- PPC405_ERR77(0,%2)
-"2: stwcx. %4,0,%2\n\
+ PPC405_ERR77(0,%3)
+"2: stwcx. %5,0,%3\n\
bne- 1b\n"
PPC_ACQUIRE_BARRIER
"3: .section .fixup,\"ax\"\n\
-4: li %0,%5\n\
+4: li %0,%6\n\
b 3b\n\
.previous\n\
.section __ex_table,\"a\"\n\
.align 3\n\
" PPC_LONG "1b,4b,2b,4b\n\
.previous" \
- : "=&r" (prev), "+m" (*uaddr)
+ : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
: "cc", "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 5c5d02d..81cf36b 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -7,7 +7,7 @@
#include <linux/uaccess.h>
#include <asm/errno.h>

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
+ return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index d6b1ed0..2d9ea11f 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -83,8 +83,8 @@ struct uaccess_ops {
size_t (*clear_user)(size_t, void __user *);
size_t (*strnlen_user)(size_t, const char __user *);
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
- int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
+ int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
+ int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
};

extern struct uaccess_ops uaccess;
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index 126011d..1d2536c 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
extern size_t copy_to_user_std(size_t, void __user *, const void *);
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int __user *, int, int);
-extern int futex_atomic_op_std(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
+extern int futex_atomic_op_std(int, u32 __user *, int, int *);

extern size_t copy_from_user_pt(size_t, const void __user *, void *);
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
-extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);

#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 404f2de..afc716a 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -302,7 +302,7 @@ fault:
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc" );

-static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;

@@ -335,7 +335,7 @@ static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
{
int ret;

@@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

asm volatile("0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: la %0,0\n"
"2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

if (segment_eq(get_fs(), KERNEL_DS))
- return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
spin_lock(&current->mm->page_table_lock);
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
if (!uaddr) {
@@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
}
get_page(virt_to_page(uaddr));
spin_unlock(&current->mm->page_table_lock);
- ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
put_page(virt_to_page(uaddr));
return ret;
}
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index a6c4f7e..bb1a7ee 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -255,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc");

-int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, u32 __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;

@@ -287,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

asm volatile(
" sacf 256\n"
"0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: la %0,0\n"
"2: sacf 0\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index a9f16a7..6cb9f19 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -3,7 +3,7 @@

#include <asm/system.h>

-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -20,7 +20,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -37,7 +37,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -54,7 +54,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -71,7 +71,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -88,11 +88,13 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
- int oldval, int newval)
+static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
+ u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
unsigned long flags;
- int ret, prev = 0;
+ int ret;
+ u32 prev = 0;

local_irq_save(flags);

@@ -102,10 +104,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,

local_irq_restore(flags);

- if (ret)
- return ret;
-
- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __ASM_SH_FUTEX_IRQ_H */
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index 68256ec..7be39a6 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -10,7 +10,7 @@
/* XXX: UP variants, fix for SH-4A and SMP.. */
#include <asm/futex-irq.h>

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -21,7 +21,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
+ return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index 47f9583..444e7be 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -30,7 +30,7 @@
: "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
: "memory")

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -38,7 +38,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
int cmparg = (encoded_op << 20) >> 20;
int oldval = 0, ret, tem;

- if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int))))
+ if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
return -EFAULT;
if (unlikely((((unsigned long) uaddr) & 0x3UL)))
return -EINVAL;
@@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
+ int ret = 0;
+
__asm__ __volatile__(
- "\n1: casa [%3] %%asi, %2, %0\n"
+ "\n1: casa [%4] %%asi, %3, %1\n"
"2:\n"
" .section .fixup,#alloc,#execinstr\n"
" .align 4\n"
"3: sethi %%hi(2b), %0\n"
" jmpl %0 + %%lo(2b), %%g0\n"
- " mov %4, %0\n"
+ " mov %5, %0\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .align 4\n"
" .word 1b, 3b\n"
" .previous\n"
- : "=r" (newval)
- : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
+ : "+r" (ret), "=r" (newval)
+ : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
: "memory");

- return newval;
+ *uval = newval;
+ return ret;
}

#endif /* !(_SPARC64_FUTEX_H) */
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index fe0d10d..d03ec12 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -29,16 +29,16 @@
#include <linux/uaccess.h>
#include <linux/errno.h>

-extern struct __get_user futex_set(int __user *v, int i);
-extern struct __get_user futex_add(int __user *v, int n);
-extern struct __get_user futex_or(int __user *v, int n);
-extern struct __get_user futex_andn(int __user *v, int n);
-extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
+extern struct __get_user futex_set(u32 __user *v, int i);
+extern struct __get_user futex_add(u32 __user *v, int n);
+extern struct __get_user futex_or(u32 __user *v, int n);
+extern struct __get_user futex_andn(u32 __user *v, int n);
+extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);

#ifndef __tilegx__
-extern struct __get_user futex_xor(int __user *v, int n);
+extern struct __get_user futex_xor(u32 __user *v, int n);
#else
-static inline struct __get_user futex_xor(int __user *uaddr, int n)
+static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
{
struct __get_user asm_ret = __get_user_4(uaddr);
if (!asm_ret.err) {
@@ -53,7 +53,7 @@ static inline struct __get_user futex_xor(int __user *uaddr, int n)
}
#endif

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -119,16 +119,17 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
struct __get_user asm_ret;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

asm_ret = futex_cmpxchg(uaddr, oldval, newval);
- return asm_ret.err ? asm_ret.err : asm_ret.val;
+ *uval = asm_ret.val;
+ return asm_ret.err;
}

#ifndef __tilegx__
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 1f11ce4..d09bb03 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -37,7 +37,7 @@
"+m" (*uaddr), "=&r" (tem) \
: "r" (oparg), "i" (-EFAULT), "1" (0))

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -48,7 +48,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
@@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
+ int ret = 0;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
/* Real i386 machines have no cmpxchg instruction */
@@ -119,21 +120,22 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
return -ENOSYS;
#endif

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
+ asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
"2:\t.section .fixup, \"ax\"\n"
- "3:\tmov %2, %0\n"
+ "3:\tmov %3, %0\n"
"\tjmp 2b\n"
"\t.previous\n"
_ASM_EXTABLE(1b, 3b)
- : "=a" (oldval), "+m" (*uaddr)
- : "i" (-EFAULT), "r" (newval), "0" (oldval)
+ : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
+ : "i" (-EFAULT), "r" (newval), "1" (oldval)
: "memory"
);

- return oldval;
+ *uval = oldval;
+ return ret;
}

#endif
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 3c2344f..01f227e 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -6,7 +6,7 @@
#include <asm/errno.h>

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -16,7 +16,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
return -ENOSYS;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 3184d3b..53b783f 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
return NULL;
}

-static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
+static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
+ u32 uval, u32 newval)
{
- u32 curval;
+ int ret;

pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+ ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
pagefault_enable();

- return curval;
+ return ret;
}

static int get_futex_value_locked(u32 *dest, u32 __user *from)
@@ -688,9 +689,7 @@ retry:
if (set_waiters)
newval |= FUTEX_WAITERS;

- curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
return -EFAULT;

/*
@@ -728,9 +727,7 @@ retry:
lock_taken = 1;
}

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
return -EFAULT;
if (unlikely(curval != uval))
goto retry;
@@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)

newval = FUTEX_WAITERS | task_pid_vnr(new_owner);

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
ret = -EFAULT;
else if (curval != uval)
ret = -EINVAL;
@@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
* There is no waiter, so we unlock the futex. The owner died
* bit has not to be preserved here. We are the owner:
*/
- oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
-
- if (oldval == -EFAULT)
- return oldval;
+ if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
+ return -EFAULT;
if (oldval != uval)
return -EAGAIN;

@@ -1578,9 +1571,7 @@ retry:
while (1) {
newval = (uval & FUTEX_OWNER_DIED) | newtid;

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
goto handle_fault;
if (curval == uval)
break;
@@ -2073,11 +2064,9 @@ retry:
* again. If it succeeds then we can return without waking
* anyone else up:
*/
- if (!(uval & FUTEX_OWNER_DIED))
- uval = cmpxchg_futex_value_locked(uaddr, task_pid_vnr(current), 0);
-
-
- if (unlikely(uval == -EFAULT))
+ if (!(uval & FUTEX_OWNER_DIED) &&
+ unlikely(cmpxchg_futex_value_locked(&uval, uaddr,
+ task_pid_vnr(current), 0)))
goto pi_faulted;
/*
* Rare case: we managed to release the lock atomically,
@@ -2464,9 +2453,7 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
-
- if (nval == -EFAULT)
+ if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
return -1;

if (nval != uval)
@@ -2679,8 +2666,7 @@ static int __init futex_init(void)
* implementation, the non-functional ones will return
* -ENOSYS.
*/
- curval = cmpxchg_futex_value_locked(NULL, 0, 0);
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
futex_cmpxchg_enabled = 1;

for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {


--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-09 12:42:53

by David Howells

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

Michel Lespinasse <[email protected]> wrote:

> The cmpxchg_futex_value_locked API was funny in that it returned either
> the original, user-exposed futex value OR an error code such as -EFAULT.
> This was confusing at best, and could be a source of livelocks in places
> that retry the cmpxchg_futex_value_locked after trying to fix the issue
> by running fault_in_user_writeable().
>
> This change makes the cmpxchg_futex_value_locked API more similar to the
> get_futex_value_locked one, returning an error code and updating the
> original value through a reference argument.
>
> Signed-off-by: Michel Lespinasse <[email protected]>

Acked-by: David Howells <[email protected]> [FRV]

2011-03-09 15:06:31

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Wed, 9 Mar 2011, Michel Lespinasse wrote:

> On Tue, Mar 08, 2011 at 09:17:11PM +0100, Thomas Gleixner wrote:
> > On Sun, 6 Mar 2011, Michel Lespinasse wrote:
> > > The cmpxchg_futex_value_locked API was funny in that it returned either
> > > the original, user-exposed futex value OR an error code such as -EFAULT.
> > > This was confusing at best, and could be a source of livelocks in places
> > > that retry the cmpxchg_futex_value_locked after trying to fix the issue
> > > by running fault_in_user_writeable().
> > >
> > > This change makes the cmpxchg_futex_value_locked API more similar to the
> > > get_futex_value_locked one, returning an error code and updating the
> > > original value through a reference argument.
> >
> > Ack.
> >
> > > static inline int
> > > -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> > > +futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
> > > + int oldval, int newval)
> >
> > Can we please change the arguments to u32 while at it? The futex core
> > code uses u32 all over the place so those inlines should do the same.
>
> All right. Attaching updated version of the diff. I also fixed the s390
> issue reported by Martin Schwidefsky.
>
> What's the proper path to check this in, could you send it towards
> the -next tree so it gets more testing ?

I'll pick it up and wait what explodes :)

Thanks,

tglx

> --------------------------------------8<-------------------------------
>
> The cmpxchg_futex_value_locked API was funny in that it returned either
> the original, user-exposed futex value OR an error code such as -EFAULT.
> This was confusing at best, and could be a source of livelocks in places
> that retry the cmpxchg_futex_value_locked after trying to fix the issue
> by running fault_in_user_writeable().
>
> This change makes the cmpxchg_futex_value_locked API more similar to the
> get_futex_value_locked one, returning an error code and updating the
> original value through a reference argument.
>
> Additionally, the futex pointer types have been changed to u32 * in both
> futex_atomic_cmpxchg_inatomic and futex_atomic_op_inuser internal APIs
> as suggested by Thomas Gleixner.
>
> Signed-off-by: Michel Lespinasse <[email protected]>
> Acked-by: Chris Metcalf <[email protected]> (for tile)
> Acked-by: Tony Luck <[email protected]> (for ia64)
> Acked-by: Thomas Gleixner <[email protected]>
> Tested-by: Michal Simek <[email protected]> (for microblaze)
>
> ---
> arch/alpha/include/asm/futex.h | 29 ++++++++++++----------
> arch/arm/include/asm/futex.h | 30 ++++++++++++----------
> arch/frv/include/asm/futex.h | 5 ++-
> arch/frv/kernel/futex.c | 14 +++++-----
> arch/ia64/include/asm/futex.h | 15 +++++++----
> arch/microblaze/include/asm/futex.h | 31 +++++++++++++----------
> arch/mips/include/asm/futex.h | 39 ++++++++++++++++-------------
> arch/parisc/include/asm/futex.h | 24 +++++++++---------
> arch/powerpc/include/asm/futex.h | 27 +++++++++++---------
> arch/s390/include/asm/futex.h | 12 ++++----
> arch/s390/include/asm/uaccess.h | 4 +-
> arch/s390/lib/uaccess.h | 8 +++---
> arch/s390/lib/uaccess_pt.c | 17 +++++++-----
> arch/s390/lib/uaccess_std.c | 8 ++++--
> arch/sh/include/asm/futex-irq.h | 24 +++++++++---------
> arch/sh/include/asm/futex.h | 11 ++++----
> arch/sparc/include/asm/futex_64.h | 20 +++++++++------
> arch/tile/include/asm/futex.h | 27 ++++++++++----------
> arch/x86/include/asm/futex.h | 22 +++++++++-------
> include/asm-generic/futex.h | 7 +++--
> kernel/futex.c | 46 ++++++++++++----------------------
> 21 files changed, 219 insertions(+), 201 deletions(-)
>
> diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
> index 945de22..e8a761a 100644
> --- a/arch/alpha/include/asm/futex.h
> +++ b/arch/alpha/include/asm/futex.h
> @@ -29,7 +29,7 @@
> : "r" (uaddr), "r"(oparg) \
> : "memory")
>
> -static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -39,7 +39,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -81,21 +81,23 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - int prev, cmp;
> + int ret = 0, cmp;
> + u32 prev;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> __asm__ __volatile__ (
> __ASM_SMP_MB
> - "1: ldl_l %0,0(%2)\n"
> - " cmpeq %0,%3,%1\n"
> - " beq %1,3f\n"
> - " mov %4,%1\n"
> - "2: stl_c %1,0(%2)\n"
> - " beq %1,4f\n"
> + "1: ldl_l %1,0(%3)\n"
> + " cmpeq %1,%4,%2\n"
> + " beq %2,3f\n"
> + " mov %5,%2\n"
> + "2: stl_c %2,0(%3)\n"
> + " beq %2,4f\n"
> "3: .subsection 2\n"
> "4: br 1b\n"
> " .previous\n"
> @@ -105,11 +107,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> " .long 2b-.\n"
> " lda $31,3b-2b(%0)\n"
> " .previous\n"
> - : "=&r"(prev), "=&r"(cmp)
> + : "+r"(ret), "=&r"(prev), "=&r"(cmp)
> : "r"(uaddr), "r"((long)oldval), "r"(newval)
> : "memory");
>
> - return prev;
> + *uval = prev;
> + return ret;
> }
>
> #endif /* __KERNEL__ */
> diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
> index b33fe70..0e29d8e 100644
> --- a/arch/arm/include/asm/futex.h
> +++ b/arch/arm/include/asm/futex.h
> @@ -35,7 +35,7 @@
> : "cc", "memory")
>
> static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -46,7 +46,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable(); /* implies preempt_disable() */
> @@ -88,36 +88,38 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - int val;
> + int ret = 0;
> + u32 val;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> - pagefault_disable(); /* implies preempt_disable() */
> + /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
> + * call sites. */
>
> __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
> - "1: " T(ldr) " %0, [%3]\n"
> - " teq %0, %1\n"
> + "1: " T(ldr) " %1, [%4]\n"
> + " teq %1, %2\n"
> " it eq @ explicit IT needed for the 2b label\n"
> - "2: " T(streq) " %2, [%3]\n"
> + "2: " T(streq) " %3, [%4]\n"
> "3:\n"
> " .pushsection __ex_table,\"a\"\n"
> " .align 3\n"
> " .long 1b, 4f, 2b, 4f\n"
> " .popsection\n"
> " .pushsection .fixup,\"ax\"\n"
> - "4: mov %0, %4\n"
> + "4: mov %0, %5\n"
> " b 3b\n"
> " .popsection"
> - : "=&r" (val)
> + : "+r" (ret), "=&r" (val)
> : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
> : "cc", "memory");
>
> - pagefault_enable(); /* subsumes preempt_enable() */
> -
> - return val;
> + *uval = val;
> + return ret;
> }
>
> #endif /* !SMP */
> diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
> index 08b3d1d..4bea27f 100644
> --- a/arch/frv/include/asm/futex.h
> +++ b/arch/frv/include/asm/futex.h
> @@ -7,10 +7,11 @@
> #include <asm/errno.h>
> #include <asm/uaccess.h>
>
> -extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
> +extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> return -ENOSYS;
> }
> diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
> index 14f64b0..d155ca9 100644
> --- a/arch/frv/kernel/futex.c
> +++ b/arch/frv/kernel/futex.c
> @@ -18,7 +18,7 @@
> * the various futex operations; MMU fault checking is ignored under no-MMU
> * conditions
> */
> -static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
> {
> int oldval, ret;
>
> @@ -50,7 +50,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_o
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
> {
> int oldval, ret;
>
> @@ -83,7 +83,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_o
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
> {
> int oldval, ret;
>
> @@ -116,7 +116,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_ol
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
> {
> int oldval, ret;
>
> @@ -149,7 +149,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_o
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
> {
> int oldval, ret;
>
> @@ -186,7 +186,7 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_o
> /*
> * do the futex operations
> */
> -int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
> index c7f0f06..8428525 100644
> --- a/arch/ia64/include/asm/futex.h
> +++ b/arch/ia64/include/asm/futex.h
> @@ -46,7 +46,7 @@ do { \
> } while (0)
>
> static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> {
> - register unsigned long r8 __asm ("r8");
> + register unsigned long r8 __asm ("r8") = 0;
> + unsigned long prev;
> __asm__ __volatile__(
> " mf;; \n"
> " mov ar.ccv=%3;; \n"
> "[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
> " .xdata4 \"__ex_table\", 1b-., 2f-. \n"
> "[2:]"
> - : "=r" (r8)
> + : "=r" (prev)
> : "r" (uaddr), "r" (newval),
> "rO" ((long) (unsigned) oldval)
> : "memory");
> + *uval = prev;
> return r8;
> }
> }
> diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
> index ad3fd61..b0526d2 100644
> --- a/arch/microblaze/include/asm/futex.h
> +++ b/arch/microblaze/include/asm/futex.h
> @@ -29,7 +29,7 @@
> })
>
> static inline int
> -futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -39,7 +39,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -94,31 +94,34 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - int prev, cmp;
> + int ret = 0, cmp;
> + u32 prev;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> - __asm__ __volatile__ ("1: lwx %0, %2, r0; \
> - cmp %1, %0, %3; \
> - beqi %1, 3f; \
> - 2: swx %4, %2, r0; \
> - addic %1, r0, 0; \
> - bnei %1, 1b; \
> + __asm__ __volatile__ ("1: lwx %1, %3, r0; \
> + cmp %2, %1, %4; \
> + beqi %2, 3f; \
> + 2: swx %5, %3, r0; \
> + addic %2, r0, 0; \
> + bnei %2, 1b; \
> 3: \
> .section .fixup,\"ax\"; \
> 4: brid 3b; \
> - addik %0, r0, %5; \
> + addik %0, r0, %6; \
> .previous; \
> .section __ex_table,\"a\"; \
> .word 1b,4b,2b,4b; \
> .previous;" \
> - : "=&r" (prev), "=&r"(cmp) \
> + : "+r" (ret), "=&r" (prev), "=&r"(cmp) \
> : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
>
> - return prev;
> + *uval = prev;
> + return ret;
> }
>
> #endif /* __KERNEL__ */
> diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
> index b9cce90..6ebf173 100644
> --- a/arch/mips/include/asm/futex.h
> +++ b/arch/mips/include/asm/futex.h
> @@ -75,7 +75,7 @@
> }
>
> static inline int
> -futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -85,7 +85,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -132,11 +132,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - int retval;
> + int ret = 0;
> + u32 val;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> if (cpu_has_llsc && R10000_LLSC_WAR) {
> @@ -145,25 +147,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> " .set push \n"
> " .set noat \n"
> " .set mips3 \n"
> - "1: ll %0, %2 \n"
> - " bne %0, %z3, 3f \n"
> + "1: ll %1, %3 \n"
> + " bne %1, %z4, 3f \n"
> " .set mips0 \n"
> - " move $1, %z4 \n"
> + " move $1, %z5 \n"
> " .set mips3 \n"
> - "2: sc $1, %1 \n"
> + "2: sc $1, %2 \n"
> " beqzl $1, 1b \n"
> __WEAK_LLSC_MB
> "3: \n"
> " .set pop \n"
> " .section .fixup,\"ax\" \n"
> - "4: li %0, %5 \n"
> + "4: li %0, %6 \n"
> " j 3b \n"
> " .previous \n"
> " .section __ex_table,\"a\" \n"
> " "__UA_ADDR "\t1b, 4b \n"
> " "__UA_ADDR "\t2b, 4b \n"
> " .previous \n"
> - : "=&r" (retval), "=R" (*uaddr)
> + : "+r" (ret), "=&r" (val), "=R" (*uaddr)
> : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
> : "memory");
> } else if (cpu_has_llsc) {
> @@ -172,31 +174,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> " .set push \n"
> " .set noat \n"
> " .set mips3 \n"
> - "1: ll %0, %2 \n"
> - " bne %0, %z3, 3f \n"
> + "1: ll %1, %3 \n"
> + " bne %1, %z4, 3f \n"
> " .set mips0 \n"
> - " move $1, %z4 \n"
> + " move $1, %z5 \n"
> " .set mips3 \n"
> - "2: sc $1, %1 \n"
> + "2: sc $1, %2 \n"
> " beqz $1, 1b \n"
> __WEAK_LLSC_MB
> "3: \n"
> " .set pop \n"
> " .section .fixup,\"ax\" \n"
> - "4: li %0, %5 \n"
> + "4: li %0, %6 \n"
> " j 3b \n"
> " .previous \n"
> " .section __ex_table,\"a\" \n"
> " "__UA_ADDR "\t1b, 4b \n"
> " "__UA_ADDR "\t2b, 4b \n"
> " .previous \n"
> - : "=&r" (retval), "=R" (*uaddr)
> + : "+r" (ret), "=&r" (val), "=R" (*uaddr)
> : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
> : "memory");
> } else
> return -ENOSYS;
>
> - return retval;
> + *uval = val;
> + return ret;
> }
>
> #endif
> diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
> index 0c705c3..67a33cc 100644
> --- a/arch/parisc/include/asm/futex.h
> +++ b/arch/parisc/include/asm/futex.h
> @@ -8,7 +8,7 @@
> #include <asm/errno.h>
>
> static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -18,7 +18,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
>
> /* Non-atomic version */
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - int err = 0;
> - int uval;
> + u32 val;
>
> /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
> * our gateway page, and causes no end of trouble...
> @@ -62,15 +62,15 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
> return -EFAULT;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> - err = get_user(uval, uaddr);
> - if (err) return -EFAULT;
> - if (uval == oldval)
> - err = put_user(newval, uaddr);
> - if (err) return -EFAULT;
> - return uval;
> + if (get_user(val, uaddr))
> + return -EFAULT;
> + if (val == oldval && put_user(newval, uaddr))
> + return -EFAULT;
> + *uval = val;
> + return 0;
> }
>
> #endif /*__KERNEL__*/
> diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
> index 7c589ef..c94e4a3 100644
> --- a/arch/powerpc/include/asm/futex.h
> +++ b/arch/powerpc/include/asm/futex.h
> @@ -30,7 +30,7 @@
> : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
> : "cr0", "memory")
>
> -static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -40,7 +40,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -82,35 +82,38 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - int prev;
> + int ret = 0;
> + u32 prev;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> __asm__ __volatile__ (
> PPC_RELEASE_BARRIER
> -"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
> - cmpw 0,%0,%3\n\
> +"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
> + cmpw 0,%1,%4\n\
> bne- 3f\n"
> - PPC405_ERR77(0,%2)
> -"2: stwcx. %4,0,%2\n\
> + PPC405_ERR77(0,%3)
> +"2: stwcx. %5,0,%3\n\
> bne- 1b\n"
> PPC_ACQUIRE_BARRIER
> "3: .section .fixup,\"ax\"\n\
> -4: li %0,%5\n\
> +4: li %0,%6\n\
> b 3b\n\
> .previous\n\
> .section __ex_table,\"a\"\n\
> .align 3\n\
> " PPC_LONG "1b,4b,2b,4b\n\
> .previous" \
> - : "=&r" (prev), "+m" (*uaddr)
> + : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
> : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
> : "cc", "memory");
>
> - return prev;
> + *uval = prev;
> + return ret;
> }
>
> #endif /* __KERNEL__ */
> diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
> index 5c5d02d..81cf36b 100644
> --- a/arch/s390/include/asm/futex.h
> +++ b/arch/s390/include/asm/futex.h
> @@ -7,7 +7,7 @@
> #include <linux/uaccess.h>
> #include <asm/errno.h>
>
> -static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -18,7 +18,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> return ret;
> }
>
> -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
> - int oldval, int newval)
> +static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> - return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
> + return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
> }
>
> #endif /* __KERNEL__ */
> diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
> index d6b1ed0..2d9ea11f 100644
> --- a/arch/s390/include/asm/uaccess.h
> +++ b/arch/s390/include/asm/uaccess.h
> @@ -83,8 +83,8 @@ struct uaccess_ops {
> size_t (*clear_user)(size_t, void __user *);
> size_t (*strnlen_user)(size_t, const char __user *);
> size_t (*strncpy_from_user)(size_t, const char __user *, char *);
> - int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
> - int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
> + int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
> + int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
> };
>
> extern struct uaccess_ops uaccess;
> diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
> index 126011d..1d2536c 100644
> --- a/arch/s390/lib/uaccess.h
> +++ b/arch/s390/lib/uaccess.h
> @@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
> extern size_t copy_to_user_std(size_t, void __user *, const void *);
> extern size_t strnlen_user_std(size_t, const char __user *);
> extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
> -extern int futex_atomic_cmpxchg_std(int __user *, int, int);
> -extern int futex_atomic_op_std(int, int __user *, int, int *);
> +extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
> +extern int futex_atomic_op_std(int, u32 __user *, int, int *);
>
> extern size_t copy_from_user_pt(size_t, const void __user *, void *);
> extern size_t copy_to_user_pt(size_t, void __user *, const void *);
> -extern int futex_atomic_op_pt(int, int __user *, int, int *);
> -extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
> +extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
> +extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
>
> #endif /* __ARCH_S390_LIB_UACCESS_H */
> diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
> index 404f2de..afc716a 100644
> --- a/arch/s390/lib/uaccess_pt.c
> +++ b/arch/s390/lib/uaccess_pt.c
> @@ -302,7 +302,7 @@ fault:
> : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
> "m" (*uaddr) : "cc" );
>
> -static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> +static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
> {
> int oldval = 0, newval, ret;
>
> @@ -335,7 +335,7 @@ static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> return ret;
> }
>
> -int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> +int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
> {
> int ret;
>
> @@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> return ret;
> }
>
> -static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> +static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> int ret;
>
> asm volatile("0: cs %1,%4,0(%5)\n"
> - "1: lr %0,%1\n"
> + "1: la %0,0\n"
> "2:\n"
> EX_TABLE(0b,2b) EX_TABLE(1b,2b)
> : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
> : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
> : "cc", "memory" );
> + *uval = oldval;
> return ret;
> }
>
> -int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> +int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
> + int oldval, int newval)
> {
> int ret;
>
> if (segment_eq(get_fs(), KERNEL_DS))
> - return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
> + return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
> spin_lock(&current->mm->page_table_lock);
> uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
> if (!uaddr) {
> @@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> }
> get_page(virt_to_page(uaddr));
> spin_unlock(&current->mm->page_table_lock);
> - ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
> + ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
> put_page(virt_to_page(uaddr));
> return ret;
> }
> diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
> index a6c4f7e..bb1a7ee 100644
> --- a/arch/s390/lib/uaccess_std.c
> +++ b/arch/s390/lib/uaccess_std.c
> @@ -255,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
> : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
> "m" (*uaddr) : "cc");
>
> -int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
> +int futex_atomic_op_std(int op, u32 __user *uaddr, int oparg, int *old)
> {
> int oldval = 0, newval, ret;
>
> @@ -287,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
> return ret;
> }
>
> -int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
> +int futex_atomic_cmpxchg_std(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> int ret;
>
> asm volatile(
> " sacf 256\n"
> "0: cs %1,%4,0(%5)\n"
> - "1: lr %0,%1\n"
> + "1: la %0,0\n"
> "2: sacf 0\n"
> EX_TABLE(0b,2b) EX_TABLE(1b,2b)
> : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
> : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
> : "cc", "memory" );
> + *uval = oldval;
> return ret;
> }
>
> diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
> index a9f16a7..6cb9f19 100644
> --- a/arch/sh/include/asm/futex-irq.h
> +++ b/arch/sh/include/asm/futex-irq.h
> @@ -3,7 +3,7 @@
>
> #include <asm/system.h>
>
> -static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
> int *oldval)
> {
> unsigned long flags;
> @@ -20,7 +20,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
> int *oldval)
> {
> unsigned long flags;
> @@ -37,7 +37,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
> int *oldval)
> {
> unsigned long flags;
> @@ -54,7 +54,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
> int *oldval)
> {
> unsigned long flags;
> @@ -71,7 +71,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
> return ret;
> }
>
> -static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
> int *oldval)
> {
> unsigned long flags;
> @@ -88,11 +88,13 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
> return ret;
> }
>
> -static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
> - int oldval, int newval)
> +static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
> + u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> unsigned long flags;
> - int ret, prev = 0;
> + int ret;
> + u32 prev = 0;
>
> local_irq_save(flags);
>
> @@ -102,10 +104,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
>
> local_irq_restore(flags);
>
> - if (ret)
> - return ret;
> -
> - return prev;
> + *uval = prev;
> + return ret;
> }
>
> #endif /* __ASM_SH_FUTEX_IRQ_H */
> diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
> index 68256ec..7be39a6 100644
> --- a/arch/sh/include/asm/futex.h
> +++ b/arch/sh/include/asm/futex.h
> @@ -10,7 +10,7 @@
> /* XXX: UP variants, fix for SH-4A and SMP.. */
> #include <asm/futex-irq.h>
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -21,7 +21,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> - return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
> + return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
> }
>
> #endif /* __KERNEL__ */
> diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
> index 47f9583..444e7be 100644
> --- a/arch/sparc/include/asm/futex_64.h
> +++ b/arch/sparc/include/asm/futex_64.h
> @@ -30,7 +30,7 @@
> : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
> : "memory")
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -38,7 +38,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> int cmparg = (encoded_op << 20) >> 20;
> int oldval = 0, ret, tem;
>
> - if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int))))
> + if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
> return -EFAULT;
> if (unlikely((((unsigned long) uaddr) & 0x3UL)))
> return -EINVAL;
> @@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> + int ret = 0;
> +
> __asm__ __volatile__(
> - "\n1: casa [%3] %%asi, %2, %0\n"
> + "\n1: casa [%4] %%asi, %3, %1\n"
> "2:\n"
> " .section .fixup,#alloc,#execinstr\n"
> " .align 4\n"
> "3: sethi %%hi(2b), %0\n"
> " jmpl %0 + %%lo(2b), %%g0\n"
> - " mov %4, %0\n"
> + " mov %5, %0\n"
> " .previous\n"
> " .section __ex_table,\"a\"\n"
> " .align 4\n"
> " .word 1b, 3b\n"
> " .previous\n"
> - : "=r" (newval)
> - : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
> + : "+r" (ret), "=r" (newval)
> + : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
> : "memory");
>
> - return newval;
> + *uval = newval;
> + return ret;
> }
>
> #endif /* !(_SPARC64_FUTEX_H) */
> diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
> index fe0d10d..d03ec12 100644
> --- a/arch/tile/include/asm/futex.h
> +++ b/arch/tile/include/asm/futex.h
> @@ -29,16 +29,16 @@
> #include <linux/uaccess.h>
> #include <linux/errno.h>
>
> -extern struct __get_user futex_set(int __user *v, int i);
> -extern struct __get_user futex_add(int __user *v, int n);
> -extern struct __get_user futex_or(int __user *v, int n);
> -extern struct __get_user futex_andn(int __user *v, int n);
> -extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
> +extern struct __get_user futex_set(u32 __user *v, int i);
> +extern struct __get_user futex_add(u32 __user *v, int n);
> +extern struct __get_user futex_or(u32 __user *v, int n);
> +extern struct __get_user futex_andn(u32 __user *v, int n);
> +extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);
>
> #ifndef __tilegx__
> -extern struct __get_user futex_xor(int __user *v, int n);
> +extern struct __get_user futex_xor(u32 __user *v, int n);
> #else
> -static inline struct __get_user futex_xor(int __user *uaddr, int n)
> +static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
> {
> struct __get_user asm_ret = __get_user_4(uaddr);
> if (!asm_ret.err) {
> @@ -53,7 +53,7 @@ static inline struct __get_user futex_xor(int __user *uaddr, int n)
> }
> #endif
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -119,16 +119,17 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> return ret;
> }
>
> -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
> - int newval)
> +static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> struct __get_user asm_ret;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> asm_ret = futex_cmpxchg(uaddr, oldval, newval);
> - return asm_ret.err ? asm_ret.err : asm_ret.val;
> + *uval = asm_ret.val;
> + return asm_ret.err;
> }
>
> #ifndef __tilegx__
> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
> index 1f11ce4..d09bb03 100644
> --- a/arch/x86/include/asm/futex.h
> +++ b/arch/x86/include/asm/futex.h
> @@ -37,7 +37,7 @@
> "+m" (*uaddr), "=&r" (tem) \
> : "r" (oparg), "i" (-EFAULT), "1" (0))
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -48,7 +48,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
> @@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> return ret;
> }
>
> -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
> - int newval)
> +static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> + int ret = 0;
>
> #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
> /* Real i386 machines have no cmpxchg instruction */
> @@ -119,21 +120,22 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
> return -ENOSYS;
> #endif
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> - asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
> + asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
> "2:\t.section .fixup, \"ax\"\n"
> - "3:\tmov %2, %0\n"
> + "3:\tmov %3, %0\n"
> "\tjmp 2b\n"
> "\t.previous\n"
> _ASM_EXTABLE(1b, 3b)
> - : "=a" (oldval), "+m" (*uaddr)
> - : "i" (-EFAULT), "r" (newval), "0" (oldval)
> + : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
> + : "i" (-EFAULT), "r" (newval), "1" (oldval)
> : "memory"
> );
>
> - return oldval;
> + *uval = oldval;
> + return ret;
> }
>
> #endif
> diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
> index 3c2344f..01f227e 100644
> --- a/include/asm-generic/futex.h
> +++ b/include/asm-generic/futex.h
> @@ -6,7 +6,7 @@
> #include <asm/errno.h>
>
> static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -16,7 +16,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();
> @@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> }
>
> static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + u32 oldval, u32 newval)
> {
> return -ENOSYS;
> }
> diff --git a/kernel/futex.c b/kernel/futex.c
> index 3184d3b..53b783f 100644
> --- a/kernel/futex.c
> +++ b/kernel/futex.c
> @@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
> return NULL;
> }
>
> -static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
> +static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
> + u32 uval, u32 newval)
> {
> - u32 curval;
> + int ret;
>
> pagefault_disable();
> - curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
> + ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
> pagefault_enable();
>
> - return curval;
> + return ret;
> }
>
> static int get_futex_value_locked(u32 *dest, u32 __user *from)
> @@ -688,9 +689,7 @@ retry:
> if (set_waiters)
> newval |= FUTEX_WAITERS;
>
> - curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
> -
> - if (unlikely(curval == -EFAULT))
> + if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
> return -EFAULT;
>
> /*
> @@ -728,9 +727,7 @@ retry:
> lock_taken = 1;
> }
>
> - curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
> -
> - if (unlikely(curval == -EFAULT))
> + if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
> return -EFAULT;
> if (unlikely(curval != uval))
> goto retry;
> @@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
>
> newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
>
> - curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
> -
> - if (curval == -EFAULT)
> + if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
> ret = -EFAULT;
> else if (curval != uval)
> ret = -EINVAL;
> @@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
> * There is no waiter, so we unlock the futex. The owner died
> * bit has not to be preserved here. We are the owner:
> */
> - oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
> -
> - if (oldval == -EFAULT)
> - return oldval;
> + if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
> + return -EFAULT;
> if (oldval != uval)
> return -EAGAIN;
>
> @@ -1578,9 +1571,7 @@ retry:
> while (1) {
> newval = (uval & FUTEX_OWNER_DIED) | newtid;
>
> - curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
> -
> - if (curval == -EFAULT)
> + if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
> goto handle_fault;
> if (curval == uval)
> break;
> @@ -2073,11 +2064,9 @@ retry:
> * again. If it succeeds then we can return without waking
> * anyone else up:
> */
> - if (!(uval & FUTEX_OWNER_DIED))
> - uval = cmpxchg_futex_value_locked(uaddr, task_pid_vnr(current), 0);
> -
> -
> - if (unlikely(uval == -EFAULT))
> + if (!(uval & FUTEX_OWNER_DIED) &&
> + unlikely(cmpxchg_futex_value_locked(&uval, uaddr,
> + task_pid_vnr(current), 0)))
> goto pi_faulted;
> /*
> * Rare case: we managed to release the lock atomically,
> @@ -2464,9 +2453,7 @@ retry:
> * userspace.
> */
> mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
> - nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
> -
> - if (nval == -EFAULT)
> + if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
> return -1;
>
> if (nval != uval)
> @@ -2679,8 +2666,7 @@ static int __init futex_init(void)
> * implementation, the non-functional ones will return
> * -ENOSYS.
> */
> - curval = cmpxchg_futex_value_locked(NULL, 0, 0);
> - if (curval == -EFAULT)
> + if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
> futex_cmpxchg_enabled = 1;
>
> for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
>
>
> --
> Michel "Walken" Lespinasse
> A program is never fully debugged until the last user dies.
>

2011-03-09 15:08:42

by Martin Schwidefsky

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Wed, 9 Mar 2011 03:25:50 -0800
Michel Lespinasse <[email protected]> wrote:

> On Tue, Mar 08, 2011 at 09:17:11PM +0100, Thomas Gleixner wrote:
> > On Sun, 6 Mar 2011, Michel Lespinasse wrote:
> > > The cmpxchg_futex_value_locked API was funny in that it returned either
> > > the original, user-exposed futex value OR an error code such as -EFAULT.
> > > This was confusing at best, and could be a source of livelocks in places
> > > that retry the cmpxchg_futex_value_locked after trying to fix the issue
> > > by running fault_in_user_writeable().
> > >
> > > This change makes the cmpxchg_futex_value_locked API more similar to the
> > > get_futex_value_locked one, returning an error code and updating the
> > > original value through a reference argument.
> >
> > Ack.
> >
> > > static inline int
> > > -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> > > +futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
> > > + int oldval, int newval)
> >
> > Can we please change the arguments to u32 while at it? The futex core
> > code uses u32 all over the place so those inlines should do the same.
>
> All right. Attaching updated version of the diff. I also fixed the s390
> issue reported by Martin Schwidefsky.

The inline assmeblies look good now but I get this compile error on s390:

CC arch/s390/lib/uaccess_pt.o
arch/s390/lib/uaccess_pt.c:373: error: conflicting types for 'futex_atomic_cmpxchg_pt'
arch/s390/lib/uaccess.h:21: note: previous declaration of 'futex_atomic_cmpxchg_pt' was here
arch/s390/lib/uaccess_pt.c:403: warning: initialization from incompatible pointer type
make[1]: *** [arch/s390/lib/uaccess_pt.o] Error 1

The trouble is this part of the patch:

-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)

You need to change these "int"s to "u32"s.

--
blue skies,
Martin.

"Reality continues to ruin my life." - Calvin.

2011-03-09 17:50:54

by Darren Hart

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Wed, Mar 9, 2011 at 3:25 AM, Michel Lespinasse <[email protected]> wrote:
> On Tue, Mar 08, 2011 at 09:17:11PM +0100, Thomas Gleixner wrote:
>> On Sun, 6 Mar 2011, Michel Lespinasse wrote:
>> > The cmpxchg_futex_value_locked API was funny in that it returned either
>> > the original, user-exposed futex value OR an error code such as -EFAULT.
>> > This was confusing at best, and could be a source of livelocks in places
>> > that retry the cmpxchg_futex_value_locked after trying to fix the issue
>> > by running fault_in_user_writeable().
>> >
>> > This change makes the cmpxchg_futex_value_locked API more similar to the
>> > get_futex_value_locked one, returning an error code and updating the
>> > original value through a reference argument.
>>
>> Ack.
>>
>> > ?static inline int
>> > -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
>> > +futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
>> > + ? ? ? ? ? ? ? ? ? ? ? ? int oldval, int newval)
>>
>> Can we please change the arguments to u32 while at it? The futex core
>> code uses u32 all over the place so those inlines should do the same.
>
> All right. Attaching updated version of the diff. I also fixed the s390
> issue reported by Martin Schwidefsky.
>
> What's the proper path to check this in, could you send it towards
> the -next tree so it gets more testing ?
>
> --------------------------------------8<-------------------------------
>
> The cmpxchg_futex_value_locked API was funny in that it returned either
> the original, user-exposed futex value OR an error code such as -EFAULT.
> This was confusing at best, and could be a source of livelocks in places
> that retry the cmpxchg_futex_value_locked after trying to fix the issue
> by running fault_in_user_writeable().
>
> This change makes the cmpxchg_futex_value_locked API more similar to the
> get_futex_value_locked one, returning an error code and updating the
> original value through a reference argument.
>
> Additionally, the futex pointer types have been changed to u32 * in both
> futex_atomic_cmpxchg_inatomic and futex_atomic_op_inuser internal APIs
> as suggested by Thomas Gleixner.
>

Hi Michel, have you run the patches through futextest? Particularly
the functional tests (you can comment out the requeue pi tests as they
are known to be failing atm).

No objections from me, but I'd like to see things like this run
through futextest to help avoid subtle issues.

--
Darren

> Signed-off-by: Michel Lespinasse <[email protected]>
> Acked-by: Chris Metcalf <[email protected]> ?(for tile)
> Acked-by: Tony Luck <[email protected]> ?(for ia64)
> Acked-by: Thomas Gleixner <[email protected]>
> Tested-by: Michal Simek <[email protected]> ?(for microblaze)
>
> ---
> ?arch/alpha/include/asm/futex.h ? ? ?| ? 29 ++++++++++++----------
> ?arch/arm/include/asm/futex.h ? ? ? ?| ? 30 ++++++++++++----------
> ?arch/frv/include/asm/futex.h ? ? ? ?| ? ?5 ++-
> ?arch/frv/kernel/futex.c ? ? ? ? ? ? | ? 14 +++++-----
> ?arch/ia64/include/asm/futex.h ? ? ? | ? 15 +++++++----
> ?arch/microblaze/include/asm/futex.h | ? 31 +++++++++++++----------
> ?arch/mips/include/asm/futex.h ? ? ? | ? 39 ++++++++++++++++-------------
> ?arch/parisc/include/asm/futex.h ? ? | ? 24 +++++++++---------
> ?arch/powerpc/include/asm/futex.h ? ?| ? 27 +++++++++++---------
> ?arch/s390/include/asm/futex.h ? ? ? | ? 12 ++++----
> ?arch/s390/include/asm/uaccess.h ? ? | ? ?4 +-
> ?arch/s390/lib/uaccess.h ? ? ? ? ? ? | ? ?8 +++---
> ?arch/s390/lib/uaccess_pt.c ? ? ? ? ?| ? 17 +++++++-----
> ?arch/s390/lib/uaccess_std.c ? ? ? ? | ? ?8 ++++--
> ?arch/sh/include/asm/futex-irq.h ? ? | ? 24 +++++++++---------
> ?arch/sh/include/asm/futex.h ? ? ? ? | ? 11 ++++----
> ?arch/sparc/include/asm/futex_64.h ? | ? 20 +++++++++------
> ?arch/tile/include/asm/futex.h ? ? ? | ? 27 ++++++++++----------
> ?arch/x86/include/asm/futex.h ? ? ? ?| ? 22 +++++++++-------
> ?include/asm-generic/futex.h ? ? ? ? | ? ?7 +++--
> ?kernel/futex.c ? ? ? ? ? ? ? ? ? ? ?| ? 46 ++++++++++++----------------------
> ?21 files changed, 219 insertions(+), 201 deletions(-)
>
> diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
> index 945de22..e8a761a 100644
> --- a/arch/alpha/include/asm/futex.h
> +++ b/arch/alpha/include/asm/futex.h
> @@ -29,7 +29,7 @@
> ? ? ? ?: ? ? ? "r" (uaddr), "r"(oparg) ? ? ? ? ? ? ? ? ? ? ? ? \
> ? ? ? ?: ? ? ? "memory")
>
> -static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -39,7 +39,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -81,21 +81,23 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? int prev, cmp;
> + ? ? ? int ret = 0, cmp;
> + ? ? ? u32 prev;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?__asm__ __volatile__ (
> ? ? ? ? ? ? ? ?__ASM_SMP_MB
> - ? ? ? "1: ? ? ldl_l ? %0,0(%2)\n"
> - ? ? ? " ? ? ? cmpeq ? %0,%3,%1\n"
> - ? ? ? " ? ? ? beq ? ? %1,3f\n"
> - ? ? ? " ? ? ? mov ? ? %4,%1\n"
> - ? ? ? "2: ? ? stl_c ? %1,0(%2)\n"
> - ? ? ? " ? ? ? beq ? ? %1,4f\n"
> + ? ? ? "1: ? ? ldl_l ? %1,0(%3)\n"
> + ? ? ? " ? ? ? cmpeq ? %1,%4,%2\n"
> + ? ? ? " ? ? ? beq ? ? %2,3f\n"
> + ? ? ? " ? ? ? mov ? ? %5,%2\n"
> + ? ? ? "2: ? ? stl_c ? %2,0(%3)\n"
> + ? ? ? " ? ? ? beq ? ? %2,4f\n"
> ? ? ? ?"3: ? ? .subsection 2\n"
> ? ? ? ?"4: ? ? br ? ? ?1b\n"
> ? ? ? ?" ? ? ? .previous\n"
> @@ -105,11 +107,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> ? ? ? ?" ? ? ? .long ? 2b-.\n"
> ? ? ? ?" ? ? ? lda ? ? $31,3b-2b(%0)\n"
> ? ? ? ?" ? ? ? .previous\n"
> - ? ? ? : ? ? ? "=&r"(prev), "=&r"(cmp)
> + ? ? ? : ? ? ? "+r"(ret), "=&r"(prev), "=&r"(cmp)
> ? ? ? ?: ? ? ? "r"(uaddr), "r"((long)oldval), "r"(newval)
> ? ? ? ?: ? ? ? "memory");
>
> - ? ? ? return prev;
> + ? ? ? *uval = prev;
> + ? ? ? return ret;
> ?}
>
> ?#endif /* __KERNEL__ */
> diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
> index b33fe70..0e29d8e 100644
> --- a/arch/arm/include/asm/futex.h
> +++ b/arch/arm/include/asm/futex.h
> @@ -35,7 +35,7 @@
> ? ? ? ?: "cc", "memory")
>
> ?static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -46,7 +46,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable(); ? ?/* implies preempt_disable() */
> @@ -88,36 +88,38 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? int val;
> + ? ? ? int ret = 0;
> + ? ? ? u32 val;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? pagefault_disable(); ? ?/* implies preempt_disable() */
> + ? ? ? /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
> + ? ? ? ?* call sites. */
>
> ? ? ? ?__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
> - ? ? ? "1: ? ? " T(ldr) " ? ? ?%0, [%3]\n"
> - ? ? ? " ? ? ? teq ? ? %0, %1\n"
> + ? ? ? "1: ? ? " T(ldr) " ? ? ?%1, [%4]\n"
> + ? ? ? " ? ? ? teq ? ? %1, %2\n"
> ? ? ? ?" ? ? ? it ? ? ?eq ? ? ?@ explicit IT needed for the 2b label\n"
> - ? ? ? "2: ? ? " T(streq) " ? ?%2, [%3]\n"
> + ? ? ? "2: ? ? " T(streq) " ? ?%3, [%4]\n"
> ? ? ? ?"3:\n"
> ? ? ? ?" ? ? ? .pushsection __ex_table,\"a\"\n"
> ? ? ? ?" ? ? ? .align ?3\n"
> ? ? ? ?" ? ? ? .long ? 1b, 4f, 2b, 4f\n"
> ? ? ? ?" ? ? ? .popsection\n"
> ? ? ? ?" ? ? ? .pushsection .fixup,\"ax\"\n"
> - ? ? ? "4: ? ? mov ? ? %0, %4\n"
> + ? ? ? "4: ? ? mov ? ? %0, %5\n"
> ? ? ? ?" ? ? ? b ? ? ? 3b\n"
> ? ? ? ?" ? ? ? .popsection"
> - ? ? ? : "=&r" (val)
> + ? ? ? : "+r" (ret), "=&r" (val)
> ? ? ? ?: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
> ? ? ? ?: "cc", "memory");
>
> - ? ? ? pagefault_enable(); ? ? /* subsumes preempt_enable() */
> -
> - ? ? ? return val;
> + ? ? ? *uval = val;
> + ? ? ? return ret;
> ?}
>
> ?#endif /* !SMP */
> diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
> index 08b3d1d..4bea27f 100644
> --- a/arch/frv/include/asm/futex.h
> +++ b/arch/frv/include/asm/futex.h
> @@ -7,10 +7,11 @@
> ?#include <asm/errno.h>
> ?#include <asm/uaccess.h>
>
> -extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
> +extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> ? ? ? ?return -ENOSYS;
> ?}
> diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
> index 14f64b0..d155ca9 100644
> --- a/arch/frv/kernel/futex.c
> +++ b/arch/frv/kernel/futex.c
> @@ -18,7 +18,7 @@
> ?* the various futex operations; MMU fault checking is ignored under no-MMU
> ?* conditions
> ?*/
> -static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
> ?{
> ? ? ? ?int oldval, ret;
>
> @@ -50,7 +50,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_o
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
> ?{
> ? ? ? ?int oldval, ret;
>
> @@ -83,7 +83,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_o
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
> ?{
> ? ? ? ?int oldval, ret;
>
> @@ -116,7 +116,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_ol
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
> ?{
> ? ? ? ?int oldval, ret;
>
> @@ -149,7 +149,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_o
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval)
> +static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
> ?{
> ? ? ? ?int oldval, ret;
>
> @@ -186,7 +186,7 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_o
> ?/*
> ?* do the futex operations
> ?*/
> -int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
> index c7f0f06..8428525 100644
> --- a/arch/ia64/include/asm/futex.h
> +++ b/arch/ia64/include/asm/futex.h
> @@ -46,7 +46,7 @@ do { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> ?} while (0)
>
> ?static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?{
> - ? ? ? ? ? ? ? register unsigned long r8 __asm ("r8");
> + ? ? ? ? ? ? ? register unsigned long r8 __asm ("r8") = 0;
> + ? ? ? ? ? ? ? unsigned long prev;
> ? ? ? ? ? ? ? ?__asm__ __volatile__(
> ? ? ? ? ? ? ? ? ? ? ? ?" ? ? ? mf;; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ? ? ? ? ?" ? ? ? mov ar.ccv=%3;; ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ? ? ? ? ?"[1:] ? cmpxchg4.acq %0=[%1],%2,ar.ccv ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ? ? ? ? ?" ? ? ? .xdata4 \"__ex_table\", 1b-., 2f-. ? ? ?\n"
> ? ? ? ? ? ? ? ? ? ? ? ?"[2:]"
> - ? ? ? ? ? ? ? ? ? ? ? : "=r" (r8)
> + ? ? ? ? ? ? ? ? ? ? ? : "=r" (prev)
> ? ? ? ? ? ? ? ? ? ? ? ?: "r" (uaddr), "r" (newval),
> ? ? ? ? ? ? ? ? ? ? ? ? ?"rO" ((long) (unsigned) oldval)
> ? ? ? ? ? ? ? ? ? ? ? ?: "memory");
> + ? ? ? ? ? ? ? *uval = prev;
> ? ? ? ? ? ? ? ?return r8;
> ? ? ? ?}
> ?}
> diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
> index ad3fd61..b0526d2 100644
> --- a/arch/microblaze/include/asm/futex.h
> +++ b/arch/microblaze/include/asm/futex.h
> @@ -29,7 +29,7 @@
> ?})
>
> ?static inline int
> -futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -39,7 +39,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -94,31 +94,34 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? int prev, cmp;
> + ? ? ? int ret = 0, cmp;
> + ? ? ? u32 prev;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? __asm__ __volatile__ ("1: ? ? ? lwx ? ? %0, %2, r0; ? ? ? ? ? ? \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cmp ? ? %1, %0, %3; ? ? ? ? ? ? \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? beqi ? ?%1, 3f; ? ? ? ? ? ? ? ? \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2: ? ? ?swx ? ? %4, %2, r0; ? ? ? ? ? ? \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? addic ? %1, r0, 0; ? ? ? ? ? ? ?\
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bnei ? ?%1, 1b; ? ? ? ? ? ? ? ? \
> + ? ? ? __asm__ __volatile__ ("1: ? ? ? lwx ? ? %1, %3, r0; ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cmp ? ? %2, %1, %4; ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? beqi ? ?%2, 3f; ? ? ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2: ? ? ?swx ? ? %5, %3, r0; ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? addic ? %2, r0, 0; ? ? ? ? ? ? ?\
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bnei ? ?%2, 1b; ? ? ? ? ? ? ? ? \
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?3: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.section .fixup,\"ax\"; ? ? ? ? ? ? ? ? \
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?4: ? ? ?brid ? ?3b; ? ? ? ? ? ? ? ? ? ? \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? addik ? %0, r0, %5; ? ? ? ? ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? addik ? %0, r0, %6; ? ? ? ? ? ? \
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.previous; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.section __ex_table,\"a\"; ? ? ? ? ? ? ?\
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.word ? 1b,4b,2b,4b; ? ? ? ? ? ? ? ? ? ?\
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.previous;" ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> - ? ? ? ? ? ? ? : "=&r" (prev), "=&r"(cmp) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ? ? ? ? ? : "+r" (ret), "=&r" (prev), "=&r"(cmp) ?\
> ? ? ? ? ? ? ? ?: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
>
> - ? ? ? return prev;
> + ? ? ? *uval = prev;
> + ? ? ? return ret;
> ?}
>
> ?#endif /* __KERNEL__ */
> diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
> index b9cce90..6ebf173 100644
> --- a/arch/mips/include/asm/futex.h
> +++ b/arch/mips/include/asm/futex.h
> @@ -75,7 +75,7 @@
> ?}
>
> ?static inline int
> -futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -85,7 +85,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -132,11 +132,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? int retval;
> + ? ? ? int ret = 0;
> + ? ? ? u32 val;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?if (cpu_has_llsc && R10000_LLSC_WAR) {
> @@ -145,25 +147,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?push ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?noat ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?mips3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? "1: ? ? ll ? ? ?%0, %2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> - ? ? ? ? ? ? ? " ? ? ? bne ? ? %0, %z3, 3f ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> + ? ? ? ? ? ? ? "1: ? ? ll ? ? ?%1, %3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> + ? ? ? ? ? ? ? " ? ? ? bne ? ? %1, %z4, 3f ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?mips0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? " ? ? ? move ? ?$1, %z4 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> + ? ? ? ? ? ? ? " ? ? ? move ? ?$1, %z5 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?mips3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? "2: ? ? sc ? ? ?$1, %1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> + ? ? ? ? ? ? ? "2: ? ? sc ? ? ?$1, %2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? beqzl ? $1, 1b ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?__WEAK_LLSC_MB
> ? ? ? ? ? ? ? ?"3: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?pop ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .section .fixup,\"ax\" ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> - ? ? ? ? ? ? ? "4: ? ? li ? ? ?%0, %5 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> + ? ? ? ? ? ? ? "4: ? ? li ? ? ?%0, %6 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? j ? ? ? 3b ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .previous ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .section __ex_table,\"a\" ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? "__UA_ADDR "\t1b, 4b ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? "__UA_ADDR "\t2b, 4b ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .previous ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? : "=&r" (retval), "=R" (*uaddr)
> + ? ? ? ? ? ? ? : "+r" (ret), "=&r" (val), "=R" (*uaddr)
> ? ? ? ? ? ? ? ?: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
> ? ? ? ? ? ? ? ?: "memory");
> ? ? ? ?} else if (cpu_has_llsc) {
> @@ -172,31 +174,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?push ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?noat ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?mips3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? "1: ? ? ll ? ? ?%0, %2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> - ? ? ? ? ? ? ? " ? ? ? bne ? ? %0, %z3, 3f ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> + ? ? ? ? ? ? ? "1: ? ? ll ? ? ?%1, %3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> + ? ? ? ? ? ? ? " ? ? ? bne ? ? %1, %z4, 3f ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?mips0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? " ? ? ? move ? ?$1, %z4 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> + ? ? ? ? ? ? ? " ? ? ? move ? ?$1, %z5 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?mips3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? "2: ? ? sc ? ? ?$1, %1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> + ? ? ? ? ? ? ? "2: ? ? sc ? ? ?$1, %2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? beqz ? ?$1, 1b ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?__WEAK_LLSC_MB
> ? ? ? ? ? ? ? ?"3: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .set ? ?pop ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .section .fixup,\"ax\" ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> - ? ? ? ? ? ? ? "4: ? ? li ? ? ?%0, %5 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> + ? ? ? ? ? ? ? "4: ? ? li ? ? ?%0, %6 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? j ? ? ? 3b ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .previous ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? .section __ex_table,\"a\" ? ? ? ? ? ? ? ? ? ? ? \n"
> ? ? ? ? ? ? ? ?" ? ? ? "__UA_ADDR "\t1b, 4b ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? "__UA_ADDR "\t2b, 4b ? ? ? ? ? ? ? ? ? ? ? ? ? ?\n"
> ? ? ? ? ? ? ? ?" ? ? ? .previous ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
> - ? ? ? ? ? ? ? : "=&r" (retval), "=R" (*uaddr)
> + ? ? ? ? ? ? ? : "+r" (ret), "=&r" (val), "=R" (*uaddr)
> ? ? ? ? ? ? ? ?: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
> ? ? ? ? ? ? ? ?: "memory");
> ? ? ? ?} else
> ? ? ? ? ? ? ? ?return -ENOSYS;
>
> - ? ? ? return retval;
> + ? ? ? *uval = val;
> + ? ? ? return ret;
> ?}
>
> ?#endif
> diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
> index 0c705c3..67a33cc 100644
> --- a/arch/parisc/include/asm/futex.h
> +++ b/arch/parisc/include/asm/futex.h
> @@ -8,7 +8,7 @@
> ?#include <asm/errno.h>
>
> ?static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -18,7 +18,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
>
> ?/* Non-atomic version */
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? int err = 0;
> - ? ? ? int uval;
> + ? ? ? u32 val;
>
> ? ? ? ?/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
> ? ? ? ? * our gateway page, and causes no end of trouble...
> @@ -62,15 +62,15 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> ? ? ? ?if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? err = get_user(uval, uaddr);
> - ? ? ? if (err) return -EFAULT;
> - ? ? ? if (uval == oldval)
> - ? ? ? ? ? ? ? err = put_user(newval, uaddr);
> - ? ? ? if (err) return -EFAULT;
> - ? ? ? return uval;
> + ? ? ? if (get_user(val, uaddr))
> + ? ? ? ? ? ? ? return -EFAULT;
> + ? ? ? if (val == oldval && put_user(newval, uaddr))
> + ? ? ? ? ? ? ? return -EFAULT;
> + ? ? ? *uval = val;
> + ? ? ? return 0;
> ?}
>
> ?#endif /*__KERNEL__*/
> diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
> index 7c589ef..c94e4a3 100644
> --- a/arch/powerpc/include/asm/futex.h
> +++ b/arch/powerpc/include/asm/futex.h
> @@ -30,7 +30,7 @@
> ? ? ? ?: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
> ? ? ? ?: "cr0", "memory")
>
> -static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -40,7 +40,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -82,35 +82,38 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? int prev;
> + ? ? ? int ret = 0;
> + ? ? ? u32 prev;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ? __asm__ __volatile__ (
> ? ? ? ? PPC_RELEASE_BARRIER
> -"1: ? ? lwarx ? %0,0,%2 ? ? ? ? # futex_atomic_cmpxchg_inatomic\n\
> - ? ? ? ?cmpw ? ?0,%0,%3\n\
> +"1: ? ? lwarx ? %1,0,%3 ? ? ? ? # futex_atomic_cmpxchg_inatomic\n\
> + ? ? ? ?cmpw ? ?0,%1,%4\n\
> ? ? ? ? bne- ? ?3f\n"
> - ? ? ? ?PPC405_ERR77(0,%2)
> -"2: ? ? stwcx. ?%4,0,%2\n\
> + ? ? ? ?PPC405_ERR77(0,%3)
> +"2: ? ? stwcx. ?%5,0,%3\n\
> ? ? ? ? bne- ? ?1b\n"
> ? ? ? ? PPC_ACQUIRE_BARRIER
> ?"3: ? ?.section .fixup,\"ax\"\n\
> -4: ? ? li ? ? ?%0,%5\n\
> +4: ? ? li ? ? ?%0,%6\n\
> ? ? ? ?b ? ? ? 3b\n\
> ? ? ? ?.previous\n\
> ? ? ? ?.section __ex_table,\"a\"\n\
> ? ? ? ?.align 3\n\
> ? ? ? ?" PPC_LONG "1b,4b,2b,4b\n\
> ? ? ? ?.previous" \
> - ? ? ? ?: "=&r" (prev), "+m" (*uaddr)
> + ? ? ? ?: "+r" (ret), "=&r" (prev), "+m" (*uaddr)
> ? ? ? ? : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
> ? ? ? ? : "cc", "memory");
>
> - ? ? ? ?return prev;
> + ? ? ? *uval = prev;
> + ? ? ? ?return ret;
> ?}
>
> ?#endif /* __KERNEL__ */
> diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
> index 5c5d02d..81cf36b 100644
> --- a/arch/s390/include/asm/futex.h
> +++ b/arch/s390/include/asm/futex.h
> @@ -7,7 +7,7 @@
> ?#include <linux/uaccess.h>
> ?#include <asm/errno.h>
>
> -static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -18,7 +18,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?return ret;
> ?}
>
> -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int oldval, int newval)
> +static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
> + ? ? ? return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
> ?}
>
> ?#endif /* __KERNEL__ */
> diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
> index d6b1ed0..2d9ea11f 100644
> --- a/arch/s390/include/asm/uaccess.h
> +++ b/arch/s390/include/asm/uaccess.h
> @@ -83,8 +83,8 @@ struct uaccess_ops {
> ? ? ? ?size_t (*clear_user)(size_t, void __user *);
> ? ? ? ?size_t (*strnlen_user)(size_t, const char __user *);
> ? ? ? ?size_t (*strncpy_from_user)(size_t, const char __user *, char *);
> - ? ? ? int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
> - ? ? ? int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
> + ? ? ? int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
> + ? ? ? int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
> ?};
>
> ?extern struct uaccess_ops uaccess;
> diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
> index 126011d..1d2536c 100644
> --- a/arch/s390/lib/uaccess.h
> +++ b/arch/s390/lib/uaccess.h
> @@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
> ?extern size_t copy_to_user_std(size_t, void __user *, const void *);
> ?extern size_t strnlen_user_std(size_t, const char __user *);
> ?extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
> -extern int futex_atomic_cmpxchg_std(int __user *, int, int);
> -extern int futex_atomic_op_std(int, int __user *, int, int *);
> +extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
> +extern int futex_atomic_op_std(int, u32 __user *, int, int *);
>
> ?extern size_t copy_from_user_pt(size_t, const void __user *, void *);
> ?extern size_t copy_to_user_pt(size_t, void __user *, const void *);
> -extern int futex_atomic_op_pt(int, int __user *, int, int *);
> -extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
> +extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
> +extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
>
> ?#endif /* __ARCH_S390_LIB_UACCESS_H */
> diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
> index 404f2de..afc716a 100644
> --- a/arch/s390/lib/uaccess_pt.c
> +++ b/arch/s390/lib/uaccess_pt.c
> @@ -302,7 +302,7 @@ fault:
> ? ? ? ? ? ? ? ? ? ? : "0" (-EFAULT), "d" (oparg), "a" (uaddr), ? ? ? ? \
> ? ? ? ? ? ? ? ? ? ? ? "m" (*uaddr) : "cc" );
>
> -static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> +static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
> ?{
> ? ? ? ?int oldval = 0, newval, ret;
>
> @@ -335,7 +335,7 @@ static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> ? ? ? ?return ret;
> ?}
>
> -int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> +int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
> ?{
> ? ? ? ?int ret;
>
> @@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
> ? ? ? ?return ret;
> ?}
>
> -static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> +static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 oldval, u32 newval)
> ?{
> ? ? ? ?int ret;
>
> ? ? ? ?asm volatile("0: cs ? %1,%4,0(%5)\n"
> - ? ? ? ? ? ? ? ? ? ?"1: lr ? %0,%1\n"
> + ? ? ? ? ? ? ? ? ? ?"1: la ? %0,0\n"
> ? ? ? ? ? ? ? ? ? ? "2:\n"
> ? ? ? ? ? ? ? ? ? ? EX_TABLE(0b,2b) EX_TABLE(1b,2b)
> ? ? ? ? ? ? ? ? ? ? : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
> ? ? ? ? ? ? ? ? ? ? : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
> ? ? ? ? ? ? ? ? ? ? : "cc", "memory" );
> + ? ? ? *uval = oldval;
> ? ? ? ?return ret;
> ?}
>
> -int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> +int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? int oldval, int newval)
> ?{
> ? ? ? ?int ret;
>
> ? ? ? ?if (segment_eq(get_fs(), KERNEL_DS))
> - ? ? ? ? ? ? ? return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
> + ? ? ? ? ? ? ? return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
> ? ? ? ?spin_lock(&current->mm->page_table_lock);
> ? ? ? ?uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
> ? ? ? ?if (!uaddr) {
> @@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
> ? ? ? ?}
> ? ? ? ?get_page(virt_to_page(uaddr));
> ? ? ? ?spin_unlock(&current->mm->page_table_lock);
> - ? ? ? ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
> + ? ? ? ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
> ? ? ? ?put_page(virt_to_page(uaddr));
> ? ? ? ?return ret;
> ?}
> diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
> index a6c4f7e..bb1a7ee 100644
> --- a/arch/s390/lib/uaccess_std.c
> +++ b/arch/s390/lib/uaccess_std.c
> @@ -255,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
> ? ? ? ? ? ? ? ?: "0" (-EFAULT), "d" (oparg), "a" (uaddr), ? ? ? ? ? ? ?\
> ? ? ? ? ? ? ? ? ?"m" (*uaddr) : "cc");
>
> -int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
> +int futex_atomic_op_std(int op, u32 __user *uaddr, int oparg, int *old)
> ?{
> ? ? ? ?int oldval = 0, newval, ret;
>
> @@ -287,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
> ? ? ? ?return ret;
> ?}
>
> -int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
> +int futex_atomic_cmpxchg_std(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 oldval, u32 newval)
> ?{
> ? ? ? ?int ret;
>
> ? ? ? ?asm volatile(
> ? ? ? ? ? ? ? ?" ? sacf 256\n"
> ? ? ? ? ? ? ? ?"0: cs ? %1,%4,0(%5)\n"
> - ? ? ? ? ? ? ? "1: lr ? %0,%1\n"
> + ? ? ? ? ? ? ? "1: la ? %0,0\n"
> ? ? ? ? ? ? ? ?"2: sacf 0\n"
> ? ? ? ? ? ? ? ?EX_TABLE(0b,2b) EX_TABLE(1b,2b)
> ? ? ? ? ? ? ? ?: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
> ? ? ? ? ? ? ? ?: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
> ? ? ? ? ? ? ? ?: "cc", "memory" );
> + ? ? ? *uval = oldval;
> ? ? ? ?return ret;
> ?}
>
> diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
> index a9f16a7..6cb9f19 100644
> --- a/arch/sh/include/asm/futex-irq.h
> +++ b/arch/sh/include/asm/futex-irq.h
> @@ -3,7 +3,7 @@
>
> ?#include <asm/system.h>
>
> -static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *oldval)
> ?{
> ? ? ? ?unsigned long flags;
> @@ -20,7 +20,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *oldval)
> ?{
> ? ? ? ?unsigned long flags;
> @@ -37,7 +37,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int *oldval)
> ?{
> ? ? ? ?unsigned long flags;
> @@ -54,7 +54,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *oldval)
> ?{
> ? ? ? ?unsigned long flags;
> @@ -71,7 +71,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
> +static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *oldval)
> ?{
> ? ? ? ?unsigned long flags;
> @@ -88,11 +88,13 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
> ? ? ? ?return ret;
> ?}
>
> -static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int oldval, int newval)
> +static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 oldval, u32 newval)
> ?{
> ? ? ? ?unsigned long flags;
> - ? ? ? int ret, prev = 0;
> + ? ? ? int ret;
> + ? ? ? u32 prev = 0;
>
> ? ? ? ?local_irq_save(flags);
>
> @@ -102,10 +104,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
>
> ? ? ? ?local_irq_restore(flags);
>
> - ? ? ? if (ret)
> - ? ? ? ? ? ? ? return ret;
> -
> - ? ? ? return prev;
> + ? ? ? *uval = prev;
> + ? ? ? return ret;
> ?}
>
> ?#endif /* __ASM_SH_FUTEX_IRQ_H */
> diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
> index 68256ec..7be39a6 100644
> --- a/arch/sh/include/asm/futex.h
> +++ b/arch/sh/include/asm/futex.h
> @@ -10,7 +10,7 @@
> ?/* XXX: UP variants, fix for SH-4A and SMP.. */
> ?#include <asm/futex-irq.h>
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -21,7 +21,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
> + ? ? ? return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
> ?}
>
> ?#endif /* __KERNEL__ */
> diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
> index 47f9583..444e7be 100644
> --- a/arch/sparc/include/asm/futex_64.h
> +++ b/arch/sparc/include/asm/futex_64.h
> @@ -30,7 +30,7 @@
> ? ? ? ?: "r" (uaddr), "r" (oparg), "i" (-EFAULT) ? ? ? \
> ? ? ? ?: "memory")
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -38,7 +38,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?int cmparg = (encoded_op << 20) >> 20;
> ? ? ? ?int oldval = 0, ret, tem;
>
> - ? ? ? if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int))))
> + ? ? ? if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
> ? ? ? ? ? ? ? ?return -EFAULT;
> ? ? ? ?if (unlikely((((unsigned long) uaddr) & 0x3UL)))
> ? ? ? ? ? ? ? ?return -EINVAL;
> @@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> + ? ? ? int ret = 0;
> +
> ? ? ? ?__asm__ __volatile__(
> - ? ? ? "\n1: ? casa ? ?[%3] %%asi, %2, %0\n"
> + ? ? ? "\n1: ? casa ? ?[%4] %%asi, %3, %1\n"
> ? ? ? ?"2:\n"
> ? ? ? ?" ? ? ? .section .fixup,#alloc,#execinstr\n"
> ? ? ? ?" ? ? ? .align ?4\n"
> ? ? ? ?"3: ? ? sethi ? %%hi(2b), %0\n"
> ? ? ? ?" ? ? ? jmpl ? ?%0 + %%lo(2b), %%g0\n"
> - ? ? ? " ? ? ? ?mov ? ?%4, %0\n"
> + ? ? ? " ? ? ? mov ? ? %5, %0\n"
> ? ? ? ?" ? ? ? .previous\n"
> ? ? ? ?" ? ? ? .section __ex_table,\"a\"\n"
> ? ? ? ?" ? ? ? .align ?4\n"
> ? ? ? ?" ? ? ? .word ? 1b, 3b\n"
> ? ? ? ?" ? ? ? .previous\n"
> - ? ? ? : "=r" (newval)
> - ? ? ? : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
> + ? ? ? : "+r" (ret), "=r" (newval)
> + ? ? ? : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
> ? ? ? ?: "memory");
>
> - ? ? ? return newval;
> + ? ? ? *uval = newval;
> + ? ? ? return ret;
> ?}
>
> ?#endif /* !(_SPARC64_FUTEX_H) */
> diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
> index fe0d10d..d03ec12 100644
> --- a/arch/tile/include/asm/futex.h
> +++ b/arch/tile/include/asm/futex.h
> @@ -29,16 +29,16 @@
> ?#include <linux/uaccess.h>
> ?#include <linux/errno.h>
>
> -extern struct __get_user futex_set(int __user *v, int i);
> -extern struct __get_user futex_add(int __user *v, int n);
> -extern struct __get_user futex_or(int __user *v, int n);
> -extern struct __get_user futex_andn(int __user *v, int n);
> -extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
> +extern struct __get_user futex_set(u32 __user *v, int i);
> +extern struct __get_user futex_add(u32 __user *v, int n);
> +extern struct __get_user futex_or(u32 __user *v, int n);
> +extern struct __get_user futex_andn(u32 __user *v, int n);
> +extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);
>
> ?#ifndef __tilegx__
> -extern struct __get_user futex_xor(int __user *v, int n);
> +extern struct __get_user futex_xor(u32 __user *v, int n);
> ?#else
> -static inline struct __get_user futex_xor(int __user *uaddr, int n)
> +static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
> ?{
> ? ? ? ?struct __get_user asm_ret = __get_user_4(uaddr);
> ? ? ? ?if (!asm_ret.err) {
> @@ -53,7 +53,7 @@ static inline struct __get_user futex_xor(int __user *uaddr, int n)
> ?}
> ?#endif
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -119,16 +119,17 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?return ret;
> ?}
>
> -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int newval)
> +static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> ? ? ? ?struct __get_user asm_ret;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?asm_ret = futex_cmpxchg(uaddr, oldval, newval);
> - ? ? ? return asm_ret.err ? asm_ret.err : asm_ret.val;
> + ? ? ? *uval = asm_ret.val;
> + ? ? ? return asm_ret.err;
> ?}
>
> ?#ifndef __tilegx__
> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
> index 1f11ce4..d09bb03 100644
> --- a/arch/x86/include/asm/futex.h
> +++ b/arch/x86/include/asm/futex.h
> @@ -37,7 +37,7 @@
> ? ? ? ? ? ? ? ? ? ? ? "+m" (*uaddr), "=&r" (tem) ? ? ? ? ? ? ? \
> ? ? ? ? ? ? ? ? ? ? : "r" (oparg), "i" (-EFAULT), "1" (0))
>
> -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -48,7 +48,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ?#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
> @@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> ? ? ? ?return ret;
> ?}
>
> -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int newval)
> +static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> + ? ? ? int ret = 0;
>
> ?#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
> ? ? ? ?/* Real i386 machines have no cmpxchg instruction */
> @@ -119,21 +120,22 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
> ? ? ? ? ? ? ? ?return -ENOSYS;
> ?#endif
>
> - ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> - ? ? ? asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
> + ? ? ? asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
> ? ? ? ? ? ? ? ? ? ? "2:\t.section .fixup, \"ax\"\n"
> - ? ? ? ? ? ? ? ? ? ?"3:\tmov ? ? %2, %0\n"
> + ? ? ? ? ? ? ? ? ? ?"3:\tmov ? ? %3, %0\n"
> ? ? ? ? ? ? ? ? ? ? "\tjmp ? ? 2b\n"
> ? ? ? ? ? ? ? ? ? ? "\t.previous\n"
> ? ? ? ? ? ? ? ? ? ? _ASM_EXTABLE(1b, 3b)
> - ? ? ? ? ? ? ? ? ? ?: "=a" (oldval), "+m" (*uaddr)
> - ? ? ? ? ? ? ? ? ? ?: "i" (-EFAULT), "r" (newval), "0" (oldval)
> + ? ? ? ? ? ? ? ? ? ?: "+r" (ret), "=a" (oldval), "+m" (*uaddr)
> + ? ? ? ? ? ? ? ? ? ?: "i" (-EFAULT), "r" (newval), "1" (oldval)
> ? ? ? ? ? ? ? ? ? ? : "memory"
> ? ? ? ?);
>
> - ? ? ? return oldval;
> + ? ? ? *uval = oldval;
> + ? ? ? return ret;
> ?}
>
> ?#endif
> diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
> index 3c2344f..01f227e 100644
> --- a/include/asm-generic/futex.h
> +++ b/include/asm-generic/futex.h
> @@ -6,7 +6,7 @@
> ?#include <asm/errno.h>
>
> ?static inline int
> -futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> ?{
> ? ? ? ?int op = (encoded_op >> 28) & 7;
> ? ? ? ?int cmp = (encoded_op >> 24) & 15;
> @@ -16,7 +16,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ? ? ? ?if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> ? ? ? ? ? ? ? ?oparg = 1 << oparg;
>
> - ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
> + ? ? ? if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?pagefault_disable();
> @@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
> ?}
>
> ?static inline int
> -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
> +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 oldval, u32 newval)
> ?{
> ? ? ? ?return -ENOSYS;
> ?}
> diff --git a/kernel/futex.c b/kernel/futex.c
> index 3184d3b..53b783f 100644
> --- a/kernel/futex.c
> +++ b/kernel/futex.c
> @@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
> ? ? ? ?return NULL;
> ?}
>
> -static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
> +static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 uval, u32 newval)
> ?{
> - ? ? ? u32 curval;
> + ? ? ? int ret;
>
> ? ? ? ?pagefault_disable();
> - ? ? ? curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
> + ? ? ? ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
> ? ? ? ?pagefault_enable();
>
> - ? ? ? return curval;
> + ? ? ? return ret;
> ?}
>
> ?static int get_futex_value_locked(u32 *dest, u32 __user *from)
> @@ -688,9 +689,7 @@ retry:
> ? ? ? ?if (set_waiters)
> ? ? ? ? ? ? ? ?newval |= FUTEX_WAITERS;
>
> - ? ? ? curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
> -
> - ? ? ? if (unlikely(curval == -EFAULT))
> + ? ? ? if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
> ? ? ? ? ? ? ? ?return -EFAULT;
>
> ? ? ? ?/*
> @@ -728,9 +727,7 @@ retry:
> ? ? ? ? ? ? ? ?lock_taken = 1;
> ? ? ? ?}
>
> - ? ? ? curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
> -
> - ? ? ? if (unlikely(curval == -EFAULT))
> + ? ? ? if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
> ? ? ? ? ? ? ? ?return -EFAULT;
> ? ? ? ?if (unlikely(curval != uval))
> ? ? ? ? ? ? ? ?goto retry;
> @@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
>
> ? ? ? ? ? ? ? ?newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
>
> - ? ? ? ? ? ? ? curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
> -
> - ? ? ? ? ? ? ? if (curval == -EFAULT)
> + ? ? ? ? ? ? ? if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
> ? ? ? ? ? ? ? ? ? ? ? ?ret = -EFAULT;
> ? ? ? ? ? ? ? ?else if (curval != uval)
> ? ? ? ? ? ? ? ? ? ? ? ?ret = -EINVAL;
> @@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
> ? ? ? ? * There is no waiter, so we unlock the futex. The owner died
> ? ? ? ? * bit has not to be preserved here. We are the owner:
> ? ? ? ? */
> - ? ? ? oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
> -
> - ? ? ? if (oldval == -EFAULT)
> - ? ? ? ? ? ? ? return oldval;
> + ? ? ? if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
> + ? ? ? ? ? ? ? return -EFAULT;
> ? ? ? ?if (oldval != uval)
> ? ? ? ? ? ? ? ?return -EAGAIN;
>
> @@ -1578,9 +1571,7 @@ retry:
> ? ? ? ?while (1) {
> ? ? ? ? ? ? ? ?newval = (uval & FUTEX_OWNER_DIED) | newtid;
>
> - ? ? ? ? ? ? ? curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
> -
> - ? ? ? ? ? ? ? if (curval == -EFAULT)
> + ? ? ? ? ? ? ? if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
> ? ? ? ? ? ? ? ? ? ? ? ?goto handle_fault;
> ? ? ? ? ? ? ? ?if (curval == uval)
> ? ? ? ? ? ? ? ? ? ? ? ?break;
> @@ -2073,11 +2064,9 @@ retry:
> ? ? ? ? * again. If it succeeds then we can return without waking
> ? ? ? ? * anyone else up:
> ? ? ? ? */
> - ? ? ? if (!(uval & FUTEX_OWNER_DIED))
> - ? ? ? ? ? ? ? uval = cmpxchg_futex_value_locked(uaddr, task_pid_vnr(current), 0);
> -
> -
> - ? ? ? if (unlikely(uval == -EFAULT))
> + ? ? ? if (!(uval & FUTEX_OWNER_DIED) &&
> + ? ? ? ? ? unlikely(cmpxchg_futex_value_locked(&uval, uaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? task_pid_vnr(current), 0)))
> ? ? ? ? ? ? ? ?goto pi_faulted;
> ? ? ? ?/*
> ? ? ? ? * Rare case: we managed to release the lock atomically,
> @@ -2464,9 +2453,7 @@ retry:
> ? ? ? ? ? ? ? ? * userspace.
> ? ? ? ? ? ? ? ? */
> ? ? ? ? ? ? ? ?mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
> - ? ? ? ? ? ? ? nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
> -
> - ? ? ? ? ? ? ? if (nval == -EFAULT)
> + ? ? ? ? ? ? ? if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
> ? ? ? ? ? ? ? ? ? ? ? ?return -1;
>
> ? ? ? ? ? ? ? ?if (nval != uval)
> @@ -2679,8 +2666,7 @@ static int __init futex_init(void)
> ? ? ? ? * implementation, the non-functional ones will return
> ? ? ? ? * -ENOSYS.
> ? ? ? ? */
> - ? ? ? curval = cmpxchg_futex_value_locked(NULL, 0, 0);
> - ? ? ? if (curval == -EFAULT)
> + ? ? ? if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
> ? ? ? ? ? ? ? ?futex_cmpxchg_enabled = 1;
>
> ? ? ? ?for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
>
>
> --
> Michel "Walken" Lespinasse
> A program is never fully debugged until the last user dies.
>



--
Darren Hart

2011-03-09 22:17:34

by Michel Lespinasse

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Wed, Mar 09, 2011 at 04:08:39PM +0100, Martin Schwidefsky wrote:
> On Wed, 9 Mar 2011 03:25:50 -0800
> Michel Lespinasse <[email protected]> wrote:
> > All right. Attaching updated version of the diff. I also fixed the s390
> > issue reported by Martin Schwidefsky.
>
> The inline assmeblies look good now but I get this compile error on s390:
>
> CC arch/s390/lib/uaccess_pt.o
> arch/s390/lib/uaccess_pt.c:373: error: conflicting types for 'futex_atomic_cmpxchg_pt'
> arch/s390/lib/uaccess.h:21: note: previous declaration of 'futex_atomic_cmpxchg_pt' was here
> arch/s390/lib/uaccess_pt.c:403: warning: initialization from incompatible pointer type
> make[1]: *** [arch/s390/lib/uaccess_pt.o] Error 1

My bad. Somehow I made the change in arch/s390/lib/uaccess_std.c but missed
it in arch/s390/lib/uaccess_pt.c ... Attached patch below goes on top of
the previous changes - Thomas, if you have picked the previous patch,
please squash this one on top of it :)

Signed-off-by: Michel Lespinasse <[email protected]>

diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index afc716a..7483383 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -370,8 +370,8 @@ static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
return ret;
}

-int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
- int oldval, int newval)
+int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;


--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-10 18:56:19

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Wed, 9 Mar 2011, Michel Lespinasse wrote:
> On Tue, Mar 08, 2011 at 09:17:11PM +0100, Thomas Gleixner wrote:

Just looked at it again in detail before picking it up. Can we please
separate the s/int/u32/ changes from the real API change ?

>
> - pagefault_disable(); /* implies preempt_disable() */
> + /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
> + * call sites. */

That wants to be a separate patch as well.

> -int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> +int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> {
> int op = (encoded_op >> 28) & 7;
> int cmp = (encoded_op >> 24) & 15;
> @@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
>
> - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>
> pagefault_disable();

So following the reasoning above, shouldn't that be the same for
futex_atomic_op_inuser() ?

Thanks,

tglx

2011-03-11 02:17:08

by Michel Lespinasse

[permalink] [raw]
Subject: Re: [PATCH] futex: cmpxchg_futex_value_locked API change

On Thu, Mar 10, 2011 at 07:55:05PM +0100, Thomas Gleixner wrote:
> On Wed, 9 Mar 2011, Michel Lespinasse wrote:
> > On Tue, Mar 08, 2011 at 09:17:11PM +0100, Thomas Gleixner wrote:
>
> Just looked at it again in detail before picking it up. Can we please
> separate the s/int/u32/ changes from the real API change ?
>
> > - pagefault_disable(); /* implies preempt_disable() */
> > + /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
> > + * call sites. */
>
> That wants to be a separate patch as well.

No problems. That makes it 3 patches, will send as replies to this.

> > -int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> > +int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> > {
> > int op = (encoded_op >> 28) & 7;
> > int cmp = (encoded_op >> 24) & 15;
> > @@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
> > if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> > oparg = 1 << oparg;
> >
> > - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
> > + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> > return -EFAULT;
> >
> > pagefault_disable();
>
> So following the reasoning above, shouldn't that be the same for
> futex_atomic_op_inuser() ?

futex_atomic_op_inuser() is currently called by core futex code with
page faults enabled. I think that's OK - for futex_atomic_cmpxchg_inatomic
I fixed the arm implementation because it was inconsistent with the
other ones, but for futex_atomic_op_inuser() every arch does it
that way.

--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-11 02:47:42

by Michel Lespinasse

[permalink] [raw]
Subject: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

kernel/futex.c disables page faults before calling
futex_atomic_cmpxchg_inatomic(), so there is no need to do it again
within that function.

Signed-off-by: Michel Lespinasse <[email protected]>

diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index b33fe70..7133a86 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -95,7 +95,8 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- pagefault_disable(); /* implies preempt_disable() */
+ /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
+ * call sites. */

__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: " T(ldr) " %0, [%3]\n"
@@ -115,8 +116,6 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
: "cc", "memory");

- pagefault_enable(); /* subsumes preempt_enable() */
-
return val;
}

--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-11 02:49:04

by Michel Lespinasse

[permalink] [raw]
Subject: [PATCH 2/3] futex: cmpxchg_futex_value_locked API change

The cmpxchg_futex_value_locked API was funny in that it returned either
the original, user-exposed futex value OR an error code such as -EFAULT.
This was confusing at best, and could be a source of livelocks in places
that retry the cmpxchg_futex_value_locked after trying to fix the issue
by running fault_in_user_writeable().

This change makes the cmpxchg_futex_value_locked API more similar to the
get_futex_value_locked one, returning an error code and updating the
original value through a reference argument.

Signed-off-by: Michel Lespinasse <[email protected]>
Acked-by: Chris Metcalf <[email protected]> [tile]
Acked-by: Tony Luck <[email protected]> [ia64]
Acked-by: Thomas Gleixner <[email protected]>
Tested-by: Michal Simek <[email protected]> [microblaze]

diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index 945de22..c4e5c28 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -81,21 +81,22 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev, cmp;
+ int ret = 0, prev, cmp;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

__asm__ __volatile__ (
__ASM_SMP_MB
- "1: ldl_l %0,0(%2)\n"
- " cmpeq %0,%3,%1\n"
- " beq %1,3f\n"
- " mov %4,%1\n"
- "2: stl_c %1,0(%2)\n"
- " beq %1,4f\n"
+ "1: ldl_l %1,0(%3)\n"
+ " cmpeq %1,%4,%2\n"
+ " beq %2,3f\n"
+ " mov %5,%2\n"
+ "2: stl_c %2,0(%3)\n"
+ " beq %2,4f\n"
"3: .subsection 2\n"
"4: br 1b\n"
" .previous\n"
@@ -105,11 +106,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .long 2b-.\n"
" lda $31,3b-2b(%0)\n"
" .previous\n"
- : "=&r"(prev), "=&r"(cmp)
+ : "+r"(ret), "=&r"(prev), "=&r"(cmp)
: "r"(uaddr), "r"((long)oldval), "r"(newval)
: "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 7133a86..d20b78f 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -88,9 +88,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int val;
+ int ret = 0, val;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
@@ -99,24 +100,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
* call sites. */

__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
- "1: " T(ldr) " %0, [%3]\n"
- " teq %0, %1\n"
+ "1: " T(ldr) " %1, [%4]\n"
+ " teq %1, %2\n"
" it eq @ explicit IT needed for the 2b label\n"
- "2: " T(streq) " %2, [%3]\n"
+ "2: " T(streq) " %3, [%4]\n"
"3:\n"
" .pushsection __ex_table,\"a\"\n"
" .align 3\n"
" .long 1b, 4f, 2b, 4f\n"
" .popsection\n"
" .pushsection .fixup,\"ax\"\n"
- "4: mov %0, %4\n"
+ "4: mov %0, %5\n"
" b 3b\n"
" .popsection"
- : "=&r" (val)
+ : "+r" (ret), "=&r" (val)
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
: "cc", "memory");

- return val;
+ *uval = val;
+ return ret;
}

#endif /* !SMP */
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 08b3d1d..0548f8e 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -10,7 +10,8 @@
extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
return -ENOSYS;
}
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index c7f0f06..b072840 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

{
- register unsigned long r8 __asm ("r8");
+ register unsigned long r8 __asm ("r8") = 0;
+ unsigned long prev;
__asm__ __volatile__(
" mf;; \n"
" mov ar.ccv=%3;; \n"
"[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
" .xdata4 \"__ex_table\", 1b-., 2f-. \n"
"[2:]"
- : "=r" (r8)
+ : "=r" (prev)
: "r" (uaddr), "r" (newval),
"rO" ((long) (unsigned) oldval)
: "memory");
+ *uval = prev;
return r8;
}
}
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index ad3fd61..fa019ed 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -94,31 +94,33 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev, cmp;
+ int ret = 0, prev, cmp;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- __asm__ __volatile__ ("1: lwx %0, %2, r0; \
- cmp %1, %0, %3; \
- beqi %1, 3f; \
- 2: swx %4, %2, r0; \
- addic %1, r0, 0; \
- bnei %1, 1b; \
+ __asm__ __volatile__ ("1: lwx %1, %3, r0; \
+ cmp %2, %1, %4; \
+ beqi %2, 3f; \
+ 2: swx %5, %3, r0; \
+ addic %2, r0, 0; \
+ bnei %2, 1b; \
3: \
.section .fixup,\"ax\"; \
4: brid 3b; \
- addik %0, r0, %5; \
+ addik %0, r0, %6; \
.previous; \
.section __ex_table,\"a\"; \
.word 1b,4b,2b,4b; \
.previous;" \
- : "=&r" (prev), "=&r"(cmp) \
+ : "+r" (ret), "=&r" (prev), "=&r"(cmp) \
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index b9cce90..692a24b 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -132,9 +132,10 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int retval;
+ int ret = 0, val;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
@@ -145,25 +146,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqzl $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else if (cpu_has_llsc) {
@@ -172,31 +173,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else
return -ENOSYS;

- return retval;
+ *uval = val;
+ return ret;
}

#endif
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 0c705c3..4c6d867 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)

/* Non-atomic version */
static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int err = 0;
- int uval;
+ int val;

/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -65,12 +65,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- err = get_user(uval, uaddr);
- if (err) return -EFAULT;
- if (uval == oldval)
- err = put_user(newval, uaddr);
- if (err) return -EFAULT;
- return uval;
+ if (get_user(val, uaddr))
+ return -EFAULT;
+ if (val == oldval && put_user(newval, uaddr))
+ return -EFAULT;
+ *uval = val;
+ return 0;
}

#endif /*__KERNEL__*/
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 7c589ef..631e8da 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -82,35 +82,37 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev;
+ int ret = 0, prev;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

__asm__ __volatile__ (
PPC_RELEASE_BARRIER
-"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
- cmpw 0,%0,%3\n\
+"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
+ cmpw 0,%1,%4\n\
bne- 3f\n"
- PPC405_ERR77(0,%2)
-"2: stwcx. %4,0,%2\n\
+ PPC405_ERR77(0,%3)
+"2: stwcx. %5,0,%3\n\
bne- 1b\n"
PPC_ACQUIRE_BARRIER
"3: .section .fixup,\"ax\"\n\
-4: li %0,%5\n\
+4: li %0,%6\n\
b 3b\n\
.previous\n\
.section __ex_table,\"a\"\n\
.align 3\n\
" PPC_LONG "1b,4b,2b,4b\n\
.previous" \
- : "=&r" (prev), "+m" (*uaddr)
+ : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
: "cc", "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 5c5d02d..27ac515 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
int oldval, int newval)
{
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
+ return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index d6b1ed0..549adf6 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -84,7 +84,7 @@ struct uaccess_ops {
size_t (*strnlen_user)(size_t, const char __user *);
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
+ int (*futex_atomic_cmpxchg)(int *, int __user *, int old, int new);
};

extern struct uaccess_ops uaccess;
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index 126011d..89a8067 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
extern size_t copy_to_user_std(size_t, void __user *, const void *);
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_cmpxchg_std(int *, int __user *, int, int);
extern int futex_atomic_op_std(int, int __user *, int, int *);

extern size_t copy_from_user_pt(size_t, const void __user *, void *);
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+extern int futex_atomic_cmpxchg_pt(int *, int __user *, int, int);

#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 404f2de..b3cebcd 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

asm volatile("0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: la %0,0\n"
"2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

if (segment_eq(get_fs(), KERNEL_DS))
- return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
spin_lock(&current->mm->page_table_lock);
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
if (!uaddr) {
@@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
}
get_page(virt_to_page(uaddr));
spin_unlock(&current->mm->page_table_lock);
- ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
put_page(virt_to_page(uaddr));
return ret;
}
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index a6c4f7e..1d6643c 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -287,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

asm volatile(
" sacf 256\n"
"0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: la %0,0\n"
"2: sacf 0\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index a9f16a7..7b701cb 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -88,7 +88,8 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
+static inline int atomic_futex_op_cmpxchg_inatomic(int *uval,
+ int __user *uaddr,
int oldval, int newval)
{
unsigned long flags;
@@ -102,10 +103,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,

local_irq_restore(flags);

- if (ret)
- return ret;
-
- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __ASM_SH_FUTEX_IRQ_H */
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index 68256ec..a8a5125 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
+ return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index 47f9583..e086220 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
+ int ret = 0;
+
__asm__ __volatile__(
- "\n1: casa [%3] %%asi, %2, %0\n"
+ "\n1: casa [%4] %%asi, %3, %1\n"
"2:\n"
" .section .fixup,#alloc,#execinstr\n"
" .align 4\n"
"3: sethi %%hi(2b), %0\n"
" jmpl %0 + %%lo(2b), %%g0\n"
- " mov %4, %0\n"
+ " mov %5, %0\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .align 4\n"
" .word 1b, 3b\n"
" .previous\n"
- : "=r" (newval)
- : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
+ : "+r" (ret), "=r" (newval)
+ : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
: "memory");

- return newval;
+ *uval = newval;
+ return ret;
}

#endif /* !(_SPARC64_FUTEX_H) */
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index fe0d10d..664b20a 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -119,8 +119,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
struct __get_user asm_ret;

@@ -128,7 +128,8 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
return -EFAULT;

asm_ret = futex_cmpxchg(uaddr, oldval, newval);
- return asm_ret.err ? asm_ret.err : asm_ret.val;
+ *uval = asm_ret.val;
+ return asm_ret.err;
}

#ifndef __tilegx__
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 1f11ce4..884c0b5 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
+ int ret = 0;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
/* Real i386 machines have no cmpxchg instruction */
@@ -122,18 +123,19 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
+ asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
"2:\t.section .fixup, \"ax\"\n"
- "3:\tmov %2, %0\n"
+ "3:\tmov %3, %0\n"
"\tjmp 2b\n"
"\t.previous\n"
_ASM_EXTABLE(1b, 3b)
- : "=a" (oldval), "+m" (*uaddr)
- : "i" (-EFAULT), "r" (newval), "0" (oldval)
+ : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
+ : "i" (-EFAULT), "r" (newval), "1" (oldval)
: "memory"
);

- return oldval;
+ *uval = oldval;
+ return ret;
}

#endif
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 3c2344f..132bf52 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
return -ENOSYS;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 3184d3b..53b783f 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
return NULL;
}

-static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
+static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
+ u32 uval, u32 newval)
{
- u32 curval;
+ int ret;

pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+ ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
pagefault_enable();

- return curval;
+ return ret;
}

static int get_futex_value_locked(u32 *dest, u32 __user *from)
@@ -688,9 +689,7 @@ retry:
if (set_waiters)
newval |= FUTEX_WAITERS;

- curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
return -EFAULT;

/*
@@ -728,9 +727,7 @@ retry:
lock_taken = 1;
}

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
return -EFAULT;
if (unlikely(curval != uval))
goto retry;
@@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)

newval = FUTEX_WAITERS | task_pid_vnr(new_owner);

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
ret = -EFAULT;
else if (curval != uval)
ret = -EINVAL;
@@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
* There is no waiter, so we unlock the futex. The owner died
* bit has not to be preserved here. We are the owner:
*/
- oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
-
- if (oldval == -EFAULT)
- return oldval;
+ if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
+ return -EFAULT;
if (oldval != uval)
return -EAGAIN;

@@ -1578,9 +1571,7 @@ retry:
while (1) {
newval = (uval & FUTEX_OWNER_DIED) | newtid;

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
goto handle_fault;
if (curval == uval)
break;
@@ -2073,11 +2064,9 @@ retry:
* again. If it succeeds then we can return without waking
* anyone else up:
*/
- if (!(uval & FUTEX_OWNER_DIED))
- uval = cmpxchg_futex_value_locked(uaddr, task_pid_vnr(current), 0);
-
-
- if (unlikely(uval == -EFAULT))
+ if (!(uval & FUTEX_OWNER_DIED) &&
+ unlikely(cmpxchg_futex_value_locked(&uval, uaddr,
+ task_pid_vnr(current), 0)))
goto pi_faulted;
/*
* Rare case: we managed to release the lock atomically,
@@ -2464,9 +2453,7 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
-
- if (nval == -EFAULT)
+ if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
return -1;

if (nval != uval)
@@ -2679,8 +2666,7 @@ static int __init futex_init(void)
* implementation, the non-functional ones will return
* -ENOSYS.
*/
- curval = cmpxchg_futex_value_locked(NULL, 0, 0);
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
futex_cmpxchg_enabled = 1;

for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-11 02:51:11

by Michel Lespinasse

[permalink] [raw]
Subject: [PATCH 3/3] futex: fix futex operation types

Fix futex_atomic_op_inuser and futex_atomic_cmpxchg_inatomic
prototypes to use u32 types for the futex.

Signed-off-by: Michel Lespinasse <[email protected]>

diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index c4e5c28..e8a761a 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -29,7 +29,7 @@
: "r" (uaddr), "r"(oparg) \
: "memory")

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -81,12 +81,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, prev, cmp;
+ int ret = 0, cmp;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ (
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index d20b78f..0e29d8e 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -35,7 +35,7 @@
: "cc", "memory")

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -46,7 +46,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable(); /* implies preempt_disable() */
@@ -88,12 +88,13 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, val;
+ int ret = 0;
+ u32 val;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

/* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 0548f8e..4bea27f 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -7,11 +7,11 @@
#include <asm/errno.h>
#include <asm/uaccess.h>

-extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
+extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
return -ENOSYS;
}
diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
index 14f64b0..d155ca9 100644
--- a/arch/frv/kernel/futex.c
+++ b/arch/frv/kernel/futex.c
@@ -18,7 +18,7 @@
* the various futex operations; MMU fault checking is ignored under no-MMU
* conditions
*/
-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -50,7 +50,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -83,7 +83,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -116,7 +116,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_ol
return ret;
}

-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -149,7 +149,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -186,7 +186,7 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_o
/*
* do the futex operations
*/
-int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index b072840..8428525 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -46,7 +46,7 @@ do { \
} while (0)

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -100,10 +100,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

{
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index fa019ed..b0526d2 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -29,7 +29,7 @@
})

static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -94,12 +94,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, prev, cmp;
+ int ret = 0, cmp;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ ("1: lwx %1, %3, r0; \
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index 692a24b..6ebf173 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -75,7 +75,7 @@
}

static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -85,7 +85,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -132,12 +132,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, val;
+ int ret = 0;
+ u32 val;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

if (cpu_has_llsc && R10000_LLSC_WAR) {
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 4c6d867..67a33cc 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,7 +8,7 @@
#include <asm/errno.h>

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)

/* Non-atomic version */
static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int val;
+ u32 val;

/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -62,7 +62,7 @@ futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
return -EFAULT;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

if (get_user(val, uaddr))
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 631e8da..c94e4a3 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -30,7 +30,7 @@
: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
: "cr0", "memory")

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -40,7 +40,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -82,12 +82,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, prev;
+ int ret = 0;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ (
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 27ac515..81cf36b 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -7,7 +7,7 @@
#include <linux/uaccess.h>
#include <asm/errno.h>

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -39,10 +39,10 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 549adf6..2d9ea11f 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -83,8 +83,8 @@ struct uaccess_ops {
size_t (*clear_user)(size_t, void __user *);
size_t (*strnlen_user)(size_t, const char __user *);
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
- int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(int *, int __user *, int old, int new);
+ int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
+ int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
};

extern struct uaccess_ops uaccess;
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index 89a8067..1d2536c 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
extern size_t copy_to_user_std(size_t, void __user *, const void *);
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int *, int __user *, int, int);
-extern int futex_atomic_op_std(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
+extern int futex_atomic_op_std(int, u32 __user *, int, int *);

extern size_t copy_from_user_pt(size_t, const void __user *, void *);
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
-extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int *, int __user *, int, int);
+extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);

#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index b3cebcd..7483383 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -302,7 +302,7 @@ fault:
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc" );

-static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;

@@ -335,7 +335,7 @@ static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
{
int ret;

@@ -354,8 +354,8 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
- int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

@@ -370,8 +370,8 @@ static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
return ret;
}

-int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
- int oldval, int newval)
+int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 1d6643c..bb1a7ee 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -255,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc");

-int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, u32 __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;

@@ -287,8 +287,8 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_cmpxchg_std(int *uval, int __user *uaddr,
- int oldval, int newval)
+int futex_atomic_cmpxchg_std(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index 7b701cb..6cb9f19 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -3,7 +3,7 @@

#include <asm/system.h>

-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -20,7 +20,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -37,7 +37,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -54,7 +54,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -71,7 +71,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -88,12 +88,13 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_cmpxchg_inatomic(int *uval,
- int __user *uaddr,
- int oldval, int newval)
+static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
+ u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
unsigned long flags;
- int ret, prev = 0;
+ int ret;
+ u32 prev = 0;

local_irq_save(flags);

diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index a8a5125..7be39a6 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -10,7 +10,7 @@
/* XXX: UP variants, fix for SH-4A and SMP.. */
#include <asm/futex-irq.h>

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -21,7 +21,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -65,10 +65,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index e086220..444e7be 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -30,7 +30,7 @@
: "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
: "memory")

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -38,7 +38,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
int cmparg = (encoded_op << 20) >> 20;
int oldval = 0, ret, tem;

- if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int))))
+ if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
return -EFAULT;
if (unlikely((((unsigned long) uaddr) & 0x3UL)))
return -EINVAL;
@@ -85,8 +85,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret = 0;

diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index 664b20a..d03ec12 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -29,16 +29,16 @@
#include <linux/uaccess.h>
#include <linux/errno.h>

-extern struct __get_user futex_set(int __user *v, int i);
-extern struct __get_user futex_add(int __user *v, int n);
-extern struct __get_user futex_or(int __user *v, int n);
-extern struct __get_user futex_andn(int __user *v, int n);
-extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
+extern struct __get_user futex_set(u32 __user *v, int i);
+extern struct __get_user futex_add(u32 __user *v, int n);
+extern struct __get_user futex_or(u32 __user *v, int n);
+extern struct __get_user futex_andn(u32 __user *v, int n);
+extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);

#ifndef __tilegx__
-extern struct __get_user futex_xor(int __user *v, int n);
+extern struct __get_user futex_xor(u32 __user *v, int n);
#else
-static inline struct __get_user futex_xor(int __user *uaddr, int n)
+static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
{
struct __get_user asm_ret = __get_user_4(uaddr);
if (!asm_ret.err) {
@@ -53,7 +53,7 @@ static inline struct __get_user futex_xor(int __user *uaddr, int n)
}
#endif

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -119,12 +119,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
struct __get_user asm_ret;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

asm_ret = futex_cmpxchg(uaddr, oldval, newval);
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 884c0b5..d09bb03 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -37,7 +37,7 @@
"+m" (*uaddr), "=&r" (tem) \
: "r" (oparg), "i" (-EFAULT), "1" (0))

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -48,7 +48,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
@@ -109,8 +109,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret = 0;

@@ -120,7 +120,7 @@ static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
return -ENOSYS;
#endif

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 132bf52..01f227e 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -6,7 +6,7 @@
#include <asm/errno.h>

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -16,7 +16,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -48,8 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
return -ENOSYS;
}
--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-11 11:32:46

by Michel Lespinasse

[permalink] [raw]
Subject: [tip:core/futexes] futex: Remove redundant pagefault_disable in futex_atomic_cmpxchg_inatomic()

Commit-ID: 522d7decc0370070448a8c28982c8dfd8970489e
Gitweb: http://git.kernel.org/tip/522d7decc0370070448a8c28982c8dfd8970489e
Author: Michel Lespinasse <[email protected]>
AuthorDate: Thu, 10 Mar 2011 18:47:31 -0800
Committer: Thomas Gleixner <[email protected]>
CommitDate: Fri, 11 Mar 2011 12:23:08 +0100

futex: Remove redundant pagefault_disable in futex_atomic_cmpxchg_inatomic()

kernel/futex.c disables page faults before calling
futex_atomic_cmpxchg_inatomic(), so there is no need to do it again
within that function.

Signed-off-by: Michel Lespinasse <[email protected]>
Cc: Darren Hart <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Matt Turner <[email protected]>
Cc: Russell King <[email protected]>
Cc: David Howells <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Michal Simek <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Chris Metcalf <[email protected]>
Cc: Linus Torvalds <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>

---
arch/arm/include/asm/futex.h | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index b33fe70..7133a86 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -95,7 +95,8 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- pagefault_disable(); /* implies preempt_disable() */
+ /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
+ * call sites. */

__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: " T(ldr) " %0, [%3]\n"
@@ -115,8 +116,6 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
: "cc", "memory");

- pagefault_enable(); /* subsumes preempt_enable() */
-
return val;
}

2011-03-11 11:33:07

by Michel Lespinasse

[permalink] [raw]
Subject: [tip:core/futexes] futex: Sanitize cmpxchg_futex_value_locked API

Commit-ID: 37a9d912b24f96a0591773e6e6c3642991ae5a70
Gitweb: http://git.kernel.org/tip/37a9d912b24f96a0591773e6e6c3642991ae5a70
Author: Michel Lespinasse <[email protected]>
AuthorDate: Thu, 10 Mar 2011 18:48:51 -0800
Committer: Thomas Gleixner <[email protected]>
CommitDate: Fri, 11 Mar 2011 12:23:08 +0100

futex: Sanitize cmpxchg_futex_value_locked API

The cmpxchg_futex_value_locked API was funny in that it returned either
the original, user-exposed futex value OR an error code such as -EFAULT.
This was confusing at best, and could be a source of livelocks in places
that retry the cmpxchg_futex_value_locked after trying to fix the issue
by running fault_in_user_writeable().

This change makes the cmpxchg_futex_value_locked API more similar to the
get_futex_value_locked one, returning an error code and updating the
original value through a reference argument.

Signed-off-by: Michel Lespinasse <[email protected]>
Acked-by: Chris Metcalf <[email protected]> [tile]
Acked-by: Tony Luck <[email protected]> [ia64]
Acked-by: Thomas Gleixner <[email protected]>
Tested-by: Michal Simek <[email protected]> [microblaze]
Acked-by: David Howells <[email protected]> [frv]
Cc: Darren Hart <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Matt Turner <[email protected]>
Cc: Russell King <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Linus Torvalds <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>

---
arch/alpha/include/asm/futex.h | 22 +++++++++-------
arch/arm/include/asm/futex.h | 18 +++++++------
arch/frv/include/asm/futex.h | 3 +-
arch/ia64/include/asm/futex.h | 9 ++++--
arch/microblaze/include/asm/futex.h | 24 ++++++++++--------
arch/mips/include/asm/futex.h | 32 +++++++++++++-----------
arch/parisc/include/asm/futex.h | 18 +++++++-------
arch/powerpc/include/asm/futex.h | 20 ++++++++-------
arch/s390/include/asm/futex.h | 4 +-
arch/s390/include/asm/uaccess.h | 2 +-
arch/s390/lib/uaccess.h | 4 +-
arch/s390/lib/uaccess_pt.c | 13 ++++++----
arch/s390/lib/uaccess_std.c | 6 +++-
arch/sh/include/asm/futex-irq.h | 9 +++----
arch/sh/include/asm/futex.h | 5 ++-
arch/sparc/include/asm/futex_64.h | 16 +++++++----
arch/tile/include/asm/futex.h | 7 +++--
arch/x86/include/asm/futex.h | 16 +++++++-----
include/asm-generic/futex.h | 3 +-
kernel/futex.c | 45 +++++++++++-----------------------
20 files changed, 144 insertions(+), 132 deletions(-)

diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index 945de22..c4e5c28 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -81,21 +81,22 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev, cmp;
+ int ret = 0, prev, cmp;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

__asm__ __volatile__ (
__ASM_SMP_MB
- "1: ldl_l %0,0(%2)\n"
- " cmpeq %0,%3,%1\n"
- " beq %1,3f\n"
- " mov %4,%1\n"
- "2: stl_c %1,0(%2)\n"
- " beq %1,4f\n"
+ "1: ldl_l %1,0(%3)\n"
+ " cmpeq %1,%4,%2\n"
+ " beq %2,3f\n"
+ " mov %5,%2\n"
+ "2: stl_c %2,0(%3)\n"
+ " beq %2,4f\n"
"3: .subsection 2\n"
"4: br 1b\n"
" .previous\n"
@@ -105,11 +106,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .long 2b-.\n"
" lda $31,3b-2b(%0)\n"
" .previous\n"
- : "=&r"(prev), "=&r"(cmp)
+ : "+r"(ret), "=&r"(prev), "=&r"(cmp)
: "r"(uaddr), "r"((long)oldval), "r"(newval)
: "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 7133a86..d20b78f 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -88,9 +88,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int val;
+ int ret = 0, val;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
@@ -99,24 +100,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
* call sites. */

__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
- "1: " T(ldr) " %0, [%3]\n"
- " teq %0, %1\n"
+ "1: " T(ldr) " %1, [%4]\n"
+ " teq %1, %2\n"
" it eq @ explicit IT needed for the 2b label\n"
- "2: " T(streq) " %2, [%3]\n"
+ "2: " T(streq) " %3, [%4]\n"
"3:\n"
" .pushsection __ex_table,\"a\"\n"
" .align 3\n"
" .long 1b, 4f, 2b, 4f\n"
" .popsection\n"
" .pushsection .fixup,\"ax\"\n"
- "4: mov %0, %4\n"
+ "4: mov %0, %5\n"
" b 3b\n"
" .popsection"
- : "=&r" (val)
+ : "+r" (ret), "=&r" (val)
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
: "cc", "memory");

- return val;
+ *uval = val;
+ return ret;
}

#endif /* !SMP */
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 08b3d1d..0548f8e 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -10,7 +10,8 @@
extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
return -ENOSYS;
}
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index c7f0f06..b072840 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

{
- register unsigned long r8 __asm ("r8");
+ register unsigned long r8 __asm ("r8") = 0;
+ unsigned long prev;
__asm__ __volatile__(
" mf;; \n"
" mov ar.ccv=%3;; \n"
"[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
" .xdata4 \"__ex_table\", 1b-., 2f-. \n"
"[2:]"
- : "=r" (r8)
+ : "=r" (prev)
: "r" (uaddr), "r" (newval),
"rO" ((long) (unsigned) oldval)
: "memory");
+ *uval = prev;
return r8;
}
}
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index ad3fd61..fa019ed 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -94,31 +94,33 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev, cmp;
+ int ret = 0, prev, cmp;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- __asm__ __volatile__ ("1: lwx %0, %2, r0; \
- cmp %1, %0, %3; \
- beqi %1, 3f; \
- 2: swx %4, %2, r0; \
- addic %1, r0, 0; \
- bnei %1, 1b; \
+ __asm__ __volatile__ ("1: lwx %1, %3, r0; \
+ cmp %2, %1, %4; \
+ beqi %2, 3f; \
+ 2: swx %5, %3, r0; \
+ addic %2, r0, 0; \
+ bnei %2, 1b; \
3: \
.section .fixup,\"ax\"; \
4: brid 3b; \
- addik %0, r0, %5; \
+ addik %0, r0, %6; \
.previous; \
.section __ex_table,\"a\"; \
.word 1b,4b,2b,4b; \
.previous;" \
- : "=&r" (prev), "=&r"(cmp) \
+ : "+r" (ret), "=&r" (prev), "=&r"(cmp) \
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index b9cce90..692a24b 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -132,9 +132,10 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int retval;
+ int ret = 0, val;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
@@ -145,25 +146,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqzl $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else if (cpu_has_llsc) {
@@ -172,31 +173,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set push \n"
" .set noat \n"
" .set mips3 \n"
- "1: ll %0, %2 \n"
- " bne %0, %z3, 3f \n"
+ "1: ll %1, %3 \n"
+ " bne %1, %z4, 3f \n"
" .set mips0 \n"
- " move $1, %z4 \n"
+ " move $1, %z5 \n"
" .set mips3 \n"
- "2: sc $1, %1 \n"
+ "2: sc $1, %2 \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
- "4: li %0, %5 \n"
+ "4: li %0, %6 \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\"a\" \n"
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
- : "=&r" (retval), "=R" (*uaddr)
+ : "+r" (ret), "=&r" (val), "=R" (*uaddr)
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
: "memory");
} else
return -ENOSYS;

- return retval;
+ *uval = val;
+ return ret;
}

#endif
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 0c705c3..4c6d867 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)

/* Non-atomic version */
static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int err = 0;
- int uval;
+ int val;

/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -65,12 +65,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- err = get_user(uval, uaddr);
- if (err) return -EFAULT;
- if (uval == oldval)
- err = put_user(newval, uaddr);
- if (err) return -EFAULT;
- return uval;
+ if (get_user(val, uaddr))
+ return -EFAULT;
+ if (val == oldval && put_user(newval, uaddr))
+ return -EFAULT;
+ *uval = val;
+ return 0;
}

#endif /*__KERNEL__*/
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 7c589ef..631e8da 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -82,35 +82,37 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
- int prev;
+ int ret = 0, prev;

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

__asm__ __volatile__ (
PPC_RELEASE_BARRIER
-"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
- cmpw 0,%0,%3\n\
+"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
+ cmpw 0,%1,%4\n\
bne- 3f\n"
- PPC405_ERR77(0,%2)
-"2: stwcx. %4,0,%2\n\
+ PPC405_ERR77(0,%3)
+"2: stwcx. %5,0,%3\n\
bne- 1b\n"
PPC_ACQUIRE_BARRIER
"3: .section .fixup,\"ax\"\n\
-4: li %0,%5\n\
+4: li %0,%6\n\
b 3b\n\
.previous\n\
.section __ex_table,\"a\"\n\
.align 3\n\
" PPC_LONG "1b,4b,2b,4b\n\
.previous" \
- : "=&r" (prev), "+m" (*uaddr)
+ : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
: "cc", "memory");

- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 5c5d02d..27ac515 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
int oldval, int newval)
{
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
+ return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index d6b1ed0..549adf6 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -84,7 +84,7 @@ struct uaccess_ops {
size_t (*strnlen_user)(size_t, const char __user *);
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
+ int (*futex_atomic_cmpxchg)(int *, int __user *, int old, int new);
};

extern struct uaccess_ops uaccess;
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index 126011d..89a8067 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
extern size_t copy_to_user_std(size_t, void __user *, const void *);
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_cmpxchg_std(int *, int __user *, int, int);
extern int futex_atomic_op_std(int, int __user *, int, int *);

extern size_t copy_from_user_pt(size_t, const void __user *, void *);
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+extern int futex_atomic_cmpxchg_pt(int *, int __user *, int, int);

#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 404f2de..b3cebcd 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

asm volatile("0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: la %0,0\n"
"2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

if (segment_eq(get_fs(), KERNEL_DS))
- return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
spin_lock(&current->mm->page_table_lock);
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
if (!uaddr) {
@@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
}
get_page(virt_to_page(uaddr));
spin_unlock(&current->mm->page_table_lock);
- ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+ ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
put_page(virt_to_page(uaddr));
return ret;
}
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index a6c4f7e..1d6643c 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -287,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
int ret;

asm volatile(
" sacf 256\n"
"0: cs %1,%4,0(%5)\n"
- "1: lr %0,%1\n"
+ "1: la %0,0\n"
"2: sacf 0\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
: "cc", "memory" );
+ *uval = oldval;
return ret;
}

diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index a9f16a7..7b701cb 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -88,7 +88,8 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
+static inline int atomic_futex_op_cmpxchg_inatomic(int *uval,
+ int __user *uaddr,
int oldval, int newval)
{
unsigned long flags;
@@ -102,10 +103,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,

local_irq_restore(flags);

- if (ret)
- return ret;
-
- return prev;
+ *uval = prev;
+ return ret;
}

#endif /* __ASM_SH_FUTEX_IRQ_H */
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index 68256ec..a8a5125 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
+ return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
}

#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index 47f9583..e086220 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
+ int ret = 0;
+
__asm__ __volatile__(
- "\n1: casa [%3] %%asi, %2, %0\n"
+ "\n1: casa [%4] %%asi, %3, %1\n"
"2:\n"
" .section .fixup,#alloc,#execinstr\n"
" .align 4\n"
"3: sethi %%hi(2b), %0\n"
" jmpl %0 + %%lo(2b), %%g0\n"
- " mov %4, %0\n"
+ " mov %5, %0\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .align 4\n"
" .word 1b, 3b\n"
" .previous\n"
- : "=r" (newval)
- : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
+ : "+r" (ret), "=r" (newval)
+ : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
: "memory");

- return newval;
+ *uval = newval;
+ return ret;
}

#endif /* !(_SPARC64_FUTEX_H) */
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index fe0d10d..664b20a 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -119,8 +119,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
struct __get_user asm_ret;

@@ -128,7 +128,8 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
return -EFAULT;

asm_ret = futex_cmpxchg(uaddr, oldval, newval);
- return asm_ret.err ? asm_ret.err : asm_ret.val;
+ *uval = asm_ret.val;
+ return asm_ret.err;
}

#ifndef __tilegx__
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 1f11ce4..884c0b5 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
- int newval)
+static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
+ int ret = 0;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
/* Real i386 machines have no cmpxchg instruction */
@@ -122,18 +123,19 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;

- asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
+ asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
"2:\t.section .fixup, \"ax\"\n"
- "3:\tmov %2, %0\n"
+ "3:\tmov %3, %0\n"
"\tjmp 2b\n"
"\t.previous\n"
_ASM_EXTABLE(1b, 3b)
- : "=a" (oldval), "+m" (*uaddr)
- : "i" (-EFAULT), "r" (newval), "0" (oldval)
+ : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
+ : "i" (-EFAULT), "r" (newval), "1" (oldval)
: "memory"
);

- return oldval;
+ *uval = oldval;
+ return ret;
}

#endif
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 3c2344f..132bf52 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
+ int oldval, int newval)
{
return -ENOSYS;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 7738154..237f14b 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
return NULL;
}

-static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
+static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
+ u32 uval, u32 newval)
{
- u32 curval;
+ int ret;

pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+ ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
pagefault_enable();

- return curval;
+ return ret;
}

static int get_futex_value_locked(u32 *dest, u32 __user *from)
@@ -688,9 +689,7 @@ retry:
if (set_waiters)
newval |= FUTEX_WAITERS;

- curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
return -EFAULT;

/*
@@ -728,9 +727,7 @@ retry:
lock_taken = 1;
}

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (unlikely(curval == -EFAULT))
+ if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
return -EFAULT;
if (unlikely(curval != uval))
goto retry;
@@ -843,9 +840,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)

newval = FUTEX_WAITERS | task_pid_vnr(new_owner);

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
ret = -EFAULT;
else if (curval != uval)
ret = -EINVAL;
@@ -880,10 +875,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
* There is no waiter, so we unlock the futex. The owner died
* bit has not to be preserved here. We are the owner:
*/
- oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
-
- if (oldval == -EFAULT)
- return oldval;
+ if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
+ return -EFAULT;
if (oldval != uval)
return -EAGAIN;

@@ -1578,9 +1571,7 @@ retry:
while (1) {
newval = (uval & FUTEX_OWNER_DIED) | newtid;

- curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
goto handle_fault;
if (curval == uval)
break;
@@ -2073,11 +2064,8 @@ retry:
* again. If it succeeds then we can return without waking
* anyone else up:
*/
- if (!(uval & FUTEX_OWNER_DIED))
- uval = cmpxchg_futex_value_locked(uaddr, vpid, 0);
-
-
- if (unlikely(uval == -EFAULT))
+ if (!(uval & FUTEX_OWNER_DIED) &&
+ cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
goto pi_faulted;
/*
* Rare case: we managed to release the lock atomically,
@@ -2464,9 +2452,7 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
-
- if (nval == -EFAULT)
+ if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
return -1;

if (nval != uval)
@@ -2679,8 +2665,7 @@ static int __init futex_init(void)
* implementation, the non-functional ones will return
* -ENOSYS.
*/
- curval = cmpxchg_futex_value_locked(NULL, 0, 0);
- if (curval == -EFAULT)
+ if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
futex_cmpxchg_enabled = 1;

for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {

2011-03-11 11:33:30

by Michel Lespinasse

[permalink] [raw]
Subject: [tip:core/futexes] futex: Sanitize futex ops argument types

Commit-ID: 8d7718aa082aaf30a0b4989e1f04858952f941bc
Gitweb: http://git.kernel.org/tip/8d7718aa082aaf30a0b4989e1f04858952f941bc
Author: Michel Lespinasse <[email protected]>
AuthorDate: Thu, 10 Mar 2011 18:50:58 -0800
Committer: Thomas Gleixner <[email protected]>
CommitDate: Fri, 11 Mar 2011 12:23:31 +0100

futex: Sanitize futex ops argument types

Change futex_atomic_op_inuser and futex_atomic_cmpxchg_inatomic
prototypes to use u32 types for the futex as this is the data type the
futex core code uses all over the place.

Signed-off-by: Michel Lespinasse <[email protected]>
Cc: Darren Hart <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Matt Turner <[email protected]>
Cc: Russell King <[email protected]>
Cc: David Howells <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Michal Simek <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Chris Metcalf <[email protected]>
Cc: Linus Torvalds <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
---
arch/alpha/include/asm/futex.h | 13 +++++++------
arch/arm/include/asm/futex.h | 13 +++++++------
arch/frv/include/asm/futex.h | 6 +++---
arch/frv/kernel/futex.c | 14 +++++++-------
arch/ia64/include/asm/futex.h | 10 +++++-----
arch/microblaze/include/asm/futex.h | 13 +++++++------
arch/mips/include/asm/futex.h | 13 +++++++------
arch/parisc/include/asm/futex.h | 12 ++++++------
arch/powerpc/include/asm/futex.h | 13 +++++++------
arch/s390/include/asm/futex.h | 10 +++++-----
arch/s390/include/asm/uaccess.h | 4 ++--
arch/s390/lib/uaccess.h | 8 ++++----
arch/s390/lib/uaccess_pt.c | 12 ++++++------
arch/s390/lib/uaccess_std.c | 6 +++---
arch/sh/include/asm/futex-irq.h | 19 ++++++++++---------
arch/sh/include/asm/futex.h | 10 +++++-----
arch/sparc/include/asm/futex_64.h | 8 ++++----
arch/tile/include/asm/futex.h | 24 ++++++++++++------------
arch/x86/include/asm/futex.h | 10 +++++-----
include/asm-generic/futex.h | 8 ++++----
20 files changed, 116 insertions(+), 110 deletions(-)

diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index c4e5c28..e8a761a 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -29,7 +29,7 @@
: "r" (uaddr), "r"(oparg) \
: "memory")

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -81,12 +81,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, prev, cmp;
+ int ret = 0, cmp;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ (
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index d20b78f..0e29d8e 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -35,7 +35,7 @@
: "cc", "memory")

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -46,7 +46,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable(); /* implies preempt_disable() */
@@ -88,12 +88,13 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, val;
+ int ret = 0;
+ u32 val;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

/* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
index 0548f8e..4bea27f 100644
--- a/arch/frv/include/asm/futex.h
+++ b/arch/frv/include/asm/futex.h
@@ -7,11 +7,11 @@
#include <asm/errno.h>
#include <asm/uaccess.h>

-extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
+extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
return -ENOSYS;
}
diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
index 14f64b0..d155ca9 100644
--- a/arch/frv/kernel/futex.c
+++ b/arch/frv/kernel/futex.c
@@ -18,7 +18,7 @@
* the various futex operations; MMU fault checking is ignored under no-MMU
* conditions
*/
-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -50,7 +50,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -83,7 +83,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -116,7 +116,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_ol
return ret;
}

-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -149,7 +149,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_o
return ret;
}

-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
{
int oldval, ret;

@@ -186,7 +186,7 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_o
/*
* do the futex operations
*/
-int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index b072840..8428525 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -46,7 +46,7 @@ do { \
} while (0)

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -100,10 +100,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

{
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index fa019ed..b0526d2 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -29,7 +29,7 @@
})

static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -94,12 +94,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, prev, cmp;
+ int ret = 0, cmp;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ ("1: lwx %1, %3, r0; \
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index 692a24b..6ebf173 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -75,7 +75,7 @@
}

static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -85,7 +85,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -132,12 +132,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, val;
+ int ret = 0;
+ u32 val;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

if (cpu_has_llsc && R10000_LLSC_WAR) {
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 4c6d867..67a33cc 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,7 +8,7 @@
#include <asm/errno.h>

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)

/* Non-atomic version */
static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int val;
+ u32 val;

/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
@@ -62,7 +62,7 @@ futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
return -EFAULT;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

if (get_user(val, uaddr))
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 631e8da..c94e4a3 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -30,7 +30,7 @@
: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
: "cr0", "memory")

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -40,7 +40,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -82,12 +82,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- int ret = 0, prev;
+ int ret = 0;
+ u32 prev;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

__asm__ __volatile__ (
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 27ac515..81cf36b 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -7,7 +7,7 @@
#include <linux/uaccess.h>
#include <asm/errno.h>

-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -39,10 +39,10 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 549adf6..2d9ea11f 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -83,8 +83,8 @@ struct uaccess_ops {
size_t (*clear_user)(size_t, void __user *);
size_t (*strnlen_user)(size_t, const char __user *);
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
- int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(int *, int __user *, int old, int new);
+ int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
+ int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
};

extern struct uaccess_ops uaccess;
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index 89a8067..1d2536c 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
extern size_t copy_to_user_std(size_t, void __user *, const void *);
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int *, int __user *, int, int);
-extern int futex_atomic_op_std(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
+extern int futex_atomic_op_std(int, u32 __user *, int, int *);

extern size_t copy_from_user_pt(size_t, const void __user *, void *);
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
-extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int *, int __user *, int, int);
+extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);

#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index b3cebcd..7483383 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -302,7 +302,7 @@ fault:
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc" );

-static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;

@@ -335,7 +335,7 @@ static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
{
int ret;

@@ -354,8 +354,8 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
- int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

@@ -370,8 +370,8 @@ static int __futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
return ret;
}

-int futex_atomic_cmpxchg_pt(int *uval, int __user *uaddr,
- int oldval, int newval)
+int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 1d6643c..bb1a7ee 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -255,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc");

-int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, u32 __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;

@@ -287,8 +287,8 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
return ret;
}

-int futex_atomic_cmpxchg_std(int *uval, int __user *uaddr,
- int oldval, int newval)
+int futex_atomic_cmpxchg_std(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;

diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index 7b701cb..6cb9f19 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -3,7 +3,7 @@

#include <asm/system.h>

-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -20,7 +20,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -37,7 +37,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -54,7 +54,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -71,7 +71,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
@@ -88,12 +88,13 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
return ret;
}

-static inline int atomic_futex_op_cmpxchg_inatomic(int *uval,
- int __user *uaddr,
- int oldval, int newval)
+static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
+ u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
unsigned long flags;
- int ret, prev = 0;
+ int ret;
+ u32 prev = 0;

local_irq_save(flags);

diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index a8a5125..7be39a6 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -10,7 +10,7 @@
/* XXX: UP variants, fix for SH-4A and SMP.. */
#include <asm/futex-irq.h>

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -21,7 +21,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -65,10 +65,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index e086220..444e7be 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -30,7 +30,7 @@
: "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
: "memory")

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -38,7 +38,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
int cmparg = (encoded_op << 20) >> 20;
int oldval = 0, ret, tem;

- if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int))))
+ if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
return -EFAULT;
if (unlikely((((unsigned long) uaddr) & 0x3UL)))
return -EINVAL;
@@ -85,8 +85,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret = 0;

diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index 664b20a..d03ec12 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
@@ -29,16 +29,16 @@
#include <linux/uaccess.h>
#include <linux/errno.h>

-extern struct __get_user futex_set(int __user *v, int i);
-extern struct __get_user futex_add(int __user *v, int n);
-extern struct __get_user futex_or(int __user *v, int n);
-extern struct __get_user futex_andn(int __user *v, int n);
-extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
+extern struct __get_user futex_set(u32 __user *v, int i);
+extern struct __get_user futex_add(u32 __user *v, int n);
+extern struct __get_user futex_or(u32 __user *v, int n);
+extern struct __get_user futex_andn(u32 __user *v, int n);
+extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);

#ifndef __tilegx__
-extern struct __get_user futex_xor(int __user *v, int n);
+extern struct __get_user futex_xor(u32 __user *v, int n);
#else
-static inline struct __get_user futex_xor(int __user *uaddr, int n)
+static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
{
struct __get_user asm_ret = __get_user_4(uaddr);
if (!asm_ret.err) {
@@ -53,7 +53,7 @@ static inline struct __get_user futex_xor(int __user *uaddr, int n)
}
#endif

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -119,12 +119,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
struct __get_user asm_ret;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

asm_ret = futex_cmpxchg(uaddr, oldval, newval);
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index 884c0b5..d09bb03 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -37,7 +37,7 @@
"+m" (*uaddr), "=&r" (tem) \
: "r" (oparg), "i" (-EFAULT), "1" (0))

-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -48,7 +48,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
@@ -109,8 +109,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
return ret;
}

-static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret = 0;

@@ -120,7 +120,7 @@ static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
return -ENOSYS;
#endif

- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 132bf52..01f227e 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -6,7 +6,7 @@
#include <asm/errno.h>

static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -16,7 +16,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;

- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

pagefault_disable();
@@ -48,8 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
}

static inline int
-futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
- int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
return -ENOSYS;
}

2011-03-13 22:49:43

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On Thu, Mar 10, 2011 at 6:47 PM, Michel Lespinasse <[email protected]> wrote:
> kernel/futex.c disables page faults before calling
> futex_atomic_cmpxchg_inatomic(), so there is no need to do it again
> within that function.

This seems totally bogus.

Even the comment is crap.

Sure, the callers may disable preemption, but that has NOTHING to do
with "pagefault_disable()". Th epagefault_[en/dis]able functions will
touch the preempt count EVEN IF PREEMPTION ISN'T EVEN ENABLED!

So what the f*ck does that "Note that preemption is disabled.." crap even mean?

The thing is made even worse by the fact that as far as I can tell,
the comment simply isn't true at all (even if you were to ignore the
fundamental confusion about preemption vs the pagefault
disable/enable). Not all callers of futex_atomic_cmpxchg_inatomic() do
anything of the sort, whether it's preemptibility _or_ the proper
pagefault_disable/enable(). Just look at the exit_robust_list() ->
handle_futex_death(), for example.

This kind of patch is the kind that personally makes me want to put
you on a spam-list. Misleading commit messages with bogus and
fundamentally incorrect added comments in the code. WTF?

Did I miss some patch that changed that, or is this really as horribly
bad as I think it is? I see it already made it into -tip.

Linus

2011-03-14 00:55:47

by Darren Hart

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

I have to apologize. These landed right as I was leaving for OSTS and
I didn't have time to review them properly. I wondered about the
preempt vs pagefault disable and wondered how exit_robust_list() was
covered in Michel's comments (perhaps somewhere higher up the call
chain). I leaned on the review of others when I should have raised the
questions even if I didn't have the time to dig into them myself.
Linus shouldn't have had to raise those questions, I'll do better at
this in the future.

I noticed that my name is the only one in futex.c with an email
address in the header - that email address is no longer valid, and it
delayed the patches getting to my inbox - I will submit a patch to fix
that. I should catch them sooner now, regardless, with improved LKML
filters.

Thanks,

Darren Hart


On Sun, Mar 13, 2011 at 3:49 PM, Linus Torvalds
<[email protected]> wrote:
> On Thu, Mar 10, 2011 at 6:47 PM, Michel Lespinasse <[email protected]> wrote:
>> kernel/futex.c disables page faults before calling
>> futex_atomic_cmpxchg_inatomic(), so there is no need to do it again
>> within that function.
>
> This seems totally bogus.
>
> Even the comment is crap.
>
> Sure, the callers may disable preemption, but that has NOTHING to do
> with "pagefault_disable()". Th epagefault_[en/dis]able functions will
> touch the preempt count EVEN IF PREEMPTION ISN'T EVEN ENABLED!
>
> So what the f*ck does that "Note that preemption is disabled.." crap even mean?
>
> The thing is made even worse by the fact that as far as I can tell,
> the comment simply isn't true at all (even if you were to ignore the
> fundamental confusion about preemption vs the pagefault
> disable/enable). Not all callers of futex_atomic_cmpxchg_inatomic() do
> anything of the sort, whether it's preemptibility _or_ the proper
> pagefault_disable/enable(). Just look at the exit_robust_list() ->
> handle_futex_death(), for example.
>
> This kind of patch is the kind that personally makes me want to put
> you on a spam-list. Misleading commit messages with bogus and
> fundamentally incorrect added comments in the code. WTF?
>
> Did I miss some patch that changed that, or is this really as horribly
> bad as I think it is? I see it already made it into -tip.
>
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Linus
>



--
Darren Hart

2011-03-14 01:15:47

by Darren Hart

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On 03/13/2011 05:55 PM, Darren Hart wrote:
> I have to apologize. These landed right as I was leaving for OSTS and
> I didn't have time to review them properly. I wondered about the
> preempt vs pagefault disable and wondered how exit_robust_list() was
> covered in Michel's comments (perhaps somewhere higher up the call
> chain). I leaned on the review of others when I should have raised the
> questions even if I didn't have the time to dig into them myself.
> Linus shouldn't have had to raise those questions, I'll do better at
> this in the future.
>
> I noticed that my name is the only one in futex.c with an email
> address in the header

Scratch that, the others are just on the Copyright line instead of the
feature line. What is the policy for updating email addresses in source
files? With git, I suppose they are no longer particularly useful.
Should I remove a bad address, or just learn from it and not include it
in future work?

Thanks,

--
Darren Hart
Intel Open Source Technology Center
Yocto Project - Linux Kernel

2011-03-14 09:14:10

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On Sun, 2011-03-13 at 17:55 -0700, Darren Hart wrote:
> I wondered about the preempt vs pagefault disable

In current mainline they happen to be the same, but for -rt they're not.

Its also conceptually different, with preempt disable we dis-allow any
scheduling, which thus also precludes most fault handlers.

Disabling pagefault can be done without also disabling preemption (as is
done in -rt) and simply means that we'll never try to handle the fault
and fallback to the exception table or give up and segfault the kernel.

Its not dis-similar to the whole rcu_read_lock() vs preempt_disable()
stuff, for a while one implied the other.

2011-03-14 09:15:24

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On Sun, 13 Mar 2011, Linus Torvalds wrote:
> On Thu, Mar 10, 2011 at 6:47 PM, Michel Lespinasse <[email protected]> wrote:
> > kernel/futex.c disables page faults before calling
> > futex_atomic_cmpxchg_inatomic(), so there is no need to do it again
> > within that function.
>
> This seems totally bogus.
>
> Even the comment is crap.
>
> Sure, the callers may disable preemption, but that has NOTHING to do
> with "pagefault_disable()". Th epagefault_[en/dis]able functions will
> touch the preempt count EVEN IF PREEMPTION ISN'T EVEN ENABLED!
>
> So what the f*ck does that "Note that preemption is disabled.." crap even mean?
>
> The thing is made even worse by the fact that as far as I can tell,
> the comment simply isn't true at all (even if you were to ignore the
> fundamental confusion about preemption vs the pagefault
> disable/enable). Not all callers of futex_atomic_cmpxchg_inatomic() do
> anything of the sort, whether it's preemptibility _or_ the proper
> pagefault_disable/enable(). Just look at the exit_robust_list() ->
> handle_futex_death(), for example.
>
> This kind of patch is the kind that personally makes me want to put
> you on a spam-list. Misleading commit messages with bogus and
> fundamentally incorrect added comments in the code. WTF?
>
> Did I miss some patch that changed that, or is this really as horribly
> bad as I think it is? I see it already made it into -tip.

That's my fault.

I really checked the call sites of futex_atomic_cmpxchg_inatomic() and
totally failed to see the one in handle_futex_death() which does not
use the helper function cmpxchg_futex_value_locked(). That helper
function is safe and does the right thing:

pagefault_disable();
curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
pagefault_enable();

So, that means we have all call sites covered except one, which needs
to be fixed _AND_ also pushed into stable as all arch implementations
except ARM rely on the caller doing the pagefault_disable().

And I missed the bogus comment as well. Sigh.

Thanks,

tglx

2011-03-14 09:15:37

by Michel Lespinasse

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On Sun, Mar 13, 2011 at 3:49 PM, Linus Torvalds
<[email protected]> wrote:
> On Thu, Mar 10, 2011 at 6:47 PM, Michel Lespinasse <[email protected]> wrote:
>> kernel/futex.c disables page faults before calling
>> futex_atomic_cmpxchg_inatomic(), so there is no need to do it again
>> within that function.
>
> This seems totally bogus.
>
> Even the comment is crap.
>
> Sure, the callers may disable preemption, but that has NOTHING to do
> with "pagefault_disable()". Th epagefault_[en/dis]able functions will
> touch the preempt count EVEN IF PREEMPTION ISN'T EVEN ENABLED!

I understand pagefault_disable() and preempt_disable() are different
concepts, but their implementations have a lot in common...

> So what the f*ck does that "Note that preemption is disabled.." crap even mean?

I was thinking that if cmpxchg_futex_value_locked() already raised the
preempt count, it seemed redundant to do it again (and then decrement
it back) in a nested way within futex_atomic_cmpxchg_inatomic on arm.

> The thing is made even worse by the fact that as far as I can tell,
> the comment simply isn't true at all (even if you were to ignore the
> fundamental confusion about preemption vs the pagefault
> disable/enable). Not all callers of futex_atomic_cmpxchg_inatomic() do
> anything of the sort, whether it's preemptibility _or_ the proper
> pagefault_disable/enable(). Just look at the exit_robust_list() ->
> handle_futex_death(), for example.

You got me there - clearly I f*cked up. What really irks me is that I
have a retrospectively bogus memory of actually looking at that call
site and seeing a pagefault_disable there... But as is now obvious,
it's never been there :/

--
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

2011-03-14 13:57:31

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On Mon, 14 Mar 2011, Thomas Gleixner wrote:
> On Sun, 13 Mar 2011, Linus Torvalds wrote:
> > On Thu, Mar 10, 2011 at 6:47 PM, Michel Lespinasse <[email protected]> wrote:
> That's my fault.
>
> I really checked the call sites of futex_atomic_cmpxchg_inatomic() and
> totally failed to see the one in handle_futex_death() which does not
> use the helper function cmpxchg_futex_value_locked(). That helper
> function is safe and does the right thing:
>
> pagefault_disable();
> curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
> pagefault_enable();
>
> So, that means we have all call sites covered except one, which needs
> to be fixed _AND_ also pushed into stable as all arch implementations
> except ARM rely on the caller doing the pagefault_disable().

After applying some coffee to my brain, I noticed that the ability to
fault in handle_futex_death() is desired. The get_user() before that
call covers the case where the futex is paged out, but it does not
handle the case where the futex is in a non writeable mapping. That
lacks a big fat comment at least.

So the removal of the pagefault_disable() in ARM is correct, just the
changelog and the comment there sucks. Sorry for not catching it.

Thinking more about it. Adding a comment is to handle_futex_death() is
good, but changing the code to make it entirely clear what is going on
is even better.

-------->
Subject: futex: Deobfuscate handle_futex_death()
From: Thomas Gleixner <[email protected]>
Date: Mon, 14 Mar 2011 10:34:35 +0100

handle_futex_death() uses futex_atomic_cmpxchg_inatomic() without
disabling page faults. That's ok, but totally non obvious.

We don't hold locks so we actually can and want to fault here, because
the get_user() before futex_atomic_cmpxchg_inatomic() does not
guarantee a R/W mapping.

We could just add a big fat comment to explain this, but actually
changing the code so that the functionality is entirely clear is
better.

Use the helper function which disables page faults around the
futex_atomic_cmpxchg_inatomic() and handle a fault with a call to
fault_in_user_writeable() as all other places in the futex code do as
well.

Signed-off-by: Thomas Gleixner <[email protected]>
---
kernel/futex.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)

Index: linux-2.6-tip/kernel/futex.c
===================================================================
--- linux-2.6-tip.orig/kernel/futex.c
+++ linux-2.6-tip/kernel/futex.c
@@ -2458,9 +2458,20 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
- return -1;
-
+ /*
+ * We are not holding a lock here, but we want to have
+ * the pagefault_disable/enable() protection because
+ * we want to handle the fault gracefully. If the
+ * access fails we try to fault in the futex with R/W
+ * verification via get_user_pages. get_user() above
+ * does not guarantee R/W access. If that fails we
+ * give up and leave the futex locked.
+ */
+ if (cmpxchg_futex_value_locked(&nval, uaddr, uval, mval)) {
+ if (fault_in_user_writeable(uaddr))
+ return -1;
+ goto retry;
+ }
if (nval != uval)
goto retry;

2011-03-14 20:07:22

by Darren Hart

[permalink] [raw]
Subject: Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()

On 03/14/2011 06:56 AM, Thomas Gleixner wrote:
> On Mon, 14 Mar 2011, Thomas Gleixner wrote:
>> On Sun, 13 Mar 2011, Linus Torvalds wrote:
>>> On Thu, Mar 10, 2011 at 6:47 PM, Michel Lespinasse<[email protected]> wrote:
>> That's my fault.
>>
>> I really checked the call sites of futex_atomic_cmpxchg_inatomic() and
>> totally failed to see the one in handle_futex_death() which does not
>> use the helper function cmpxchg_futex_value_locked(). That helper
>> function is safe and does the right thing:
>>
>> pagefault_disable();
>> curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
>> pagefault_enable();
>>
>> So, that means we have all call sites covered except one, which needs
>> to be fixed _AND_ also pushed into stable as all arch implementations
>> except ARM rely on the caller doing the pagefault_disable().
>
> After applying some coffee to my brain, I noticed that the ability to
> fault in handle_futex_death() is desired. The get_user() before that
> call covers the case where the futex is paged out, but it does not
> handle the case where the futex is in a non writeable mapping. That
> lacks a big fat comment at least.
>
> So the removal of the pagefault_disable() in ARM is correct, just the
> changelog and the comment there sucks. Sorry for not catching it.
>
> Thinking more about it. Adding a comment is to handle_futex_death() is
> good, but changing the code to make it entirely clear what is going on
> is even better.
>
> -------->
> Subject: futex: Deobfuscate handle_futex_death()
> From: Thomas Gleixner<[email protected]>
> Date: Mon, 14 Mar 2011 10:34:35 +0100
>
> handle_futex_death() uses futex_atomic_cmpxchg_inatomic() without
> disabling page faults. That's ok, but totally non obvious.
>
> We don't hold locks so we actually can and want to fault here, because
> the get_user() before futex_atomic_cmpxchg_inatomic() does not
> guarantee a R/W mapping.
>
> We could just add a big fat comment to explain this, but actually
> changing the code so that the functionality is entirely clear is
> better.
>
> Use the helper function which disables page faults around the
> futex_atomic_cmpxchg_inatomic() and handle a fault with a call to
> fault_in_user_writeable() as all other places in the futex code do as
> well.
>
> Signed-off-by: Thomas Gleixner<[email protected]>

Acked-by: Darren Hart <[email protected]>

> ---
> kernel/futex.c | 17 ++++++++++++++---
> 1 file changed, 14 insertions(+), 3 deletions(-)
>
> Index: linux-2.6-tip/kernel/futex.c
> ===================================================================
> --- linux-2.6-tip.orig/kernel/futex.c
> +++ linux-2.6-tip/kernel/futex.c
> @@ -2458,9 +2458,20 @@ retry:
> * userspace.
> */
> mval = (uval& FUTEX_WAITERS) | FUTEX_OWNER_DIED;
> - if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
> - return -1;
> -
> + /*
> + * We are not holding a lock here, but we want to have
> + * the pagefault_disable/enable() protection because
> + * we want to handle the fault gracefully. If the
> + * access fails we try to fault in the futex with R/W
> + * verification via get_user_pages. get_user() above
> + * does not guarantee R/W access. If that fails we
> + * give up and leave the futex locked.
> + */
> + if (cmpxchg_futex_value_locked(&nval, uaddr, uval, mval)) {
> + if (fault_in_user_writeable(uaddr))
> + return -1;
> + goto retry;
> + }
> if (nval != uval)
> goto retry;
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/


--
Darren Hart
Intel Open Source Technology Center
Yocto Project - Linux Kernel

2011-03-14 20:16:58

by Thomas Gleixner

[permalink] [raw]
Subject: [tip:core/futexes] arm: Remove bogus comment in futex_atomic_cmpxchg_inatomic()

Commit-ID: 07d5ecae2940ddd77746e2fb597dcf57d3c2e277
Gitweb: http://git.kernel.org/tip/07d5ecae2940ddd77746e2fb597dcf57d3c2e277
Author: Thomas Gleixner <[email protected]>
AuthorDate: Mon, 14 Mar 2011 20:00:30 +0100
Committer: Thomas Gleixner <[email protected]>
CommitDate: Mon, 14 Mar 2011 21:10:26 +0100

arm: Remove bogus comment in futex_atomic_cmpxchg_inatomic()

commit 522d7dec(futex: Remove redundant pagefault_disable in
futex_atomic_cmpxchg_inatomic()) added a bogus comment.

/* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
* call sites. */

Bogus in two aspects:

1) pagefault_disable != preempt_disable even if the mechanism we use
is the same

2) we have a call site which deliberately does not disable pagefaults
as it wants the possible fault to be handled - though that has been
changed for consistency reasons now.

Sigh. I really should have seen that when committing the above. :(

Catched-by-and-rightfully-ranted-at-by: Linus Torvalds <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
LKML-Reference: <[email protected]>
Cc: Michel Lespinasse <[email protected]>
Cc: Darren Hart <[email protected]>
---
arch/arm/include/asm/futex.h | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 0e29d8e..199a6b6 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -97,9 +97,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;

- /* Note that preemption is disabled by futex_atomic_cmpxchg_inatomic
- * call sites. */
-
__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: " T(ldr) " %1, [%4]\n"
" teq %1, %2\n"

2011-03-14 20:17:39

by Thomas Gleixner

[permalink] [raw]
Subject: [tip:core/futexes] futex: Deobfuscate handle_futex_death()

Commit-ID: 6e0aa9f8a8190e0879a29bd67aa606b51734a122
Gitweb: http://git.kernel.org/tip/6e0aa9f8a8190e0879a29bd67aa606b51734a122
Author: Thomas Gleixner <[email protected]>
AuthorDate: Mon, 14 Mar 2011 10:34:35 +0100
Committer: Thomas Gleixner <[email protected]>
CommitDate: Mon, 14 Mar 2011 21:08:47 +0100

futex: Deobfuscate handle_futex_death()

handle_futex_death() uses futex_atomic_cmpxchg_inatomic() without
disabling page faults. That's ok, but totally non obvious.

We don't hold locks so we actually can and want to fault here, because
the get_user() before futex_atomic_cmpxchg_inatomic() does not
guarantee a R/W mapping.

We could just add a big fat comment to explain this, but actually
changing the code so that the functionality is entirely clear is
better.

Use the helper function which disables page faults around the
futex_atomic_cmpxchg_inatomic() and handle a fault with a call to
fault_in_user_writeable() as all other places in the futex code do as
well.

Pointed-out-by: Linus Torvalds <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Acked-by: Darren Hart <[email protected]>
Cc: Michel Lespinasse <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Matt Turner <[email protected]>
Cc: Russell King <[email protected]>
Cc: David Howells <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Michal Simek <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Chris Metcalf <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
---
kernel/futex.c | 17 ++++++++++++++---
1 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/kernel/futex.c b/kernel/futex.c
index c6bef6e..e9251d9 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -2458,9 +2458,20 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
- if (futex_atomic_cmpxchg_inatomic(&nval, uaddr, uval, mval))
- return -1;
-
+ /*
+ * We are not holding a lock here, but we want to have
+ * the pagefault_disable/enable() protection because
+ * we want to handle the fault gracefully. If the
+ * access fails we try to fault in the futex with R/W
+ * verification via get_user_pages. get_user() above
+ * does not guarantee R/W access. If that fails we
+ * give up and leave the futex locked.
+ */
+ if (cmpxchg_futex_value_locked(&nval, uaddr, uval, mval)) {
+ if (fault_in_user_writeable(uaddr))
+ return -1;
+ goto retry;
+ }
if (nval != uval)
goto retry;