futex: cmpxchg_futex_value_locked API change
Subsystems (12)
PATCH 1/1 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.
--- 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(-)
arch/alpha/include/asm/futex.h +12 -10
@@ -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__ */
arch/arm/include/asm/futex.h +12 -11
@@ -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 */
arch/frv/include/asm/futex.h +2 -1
@@ -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 ; }
arch/ia64/include/asm/futex.h +6 -3
@@ -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 ; { - registerunsigned 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; } }
arch/microblaze/include/asm/futex.h +13 -11
@@ -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__ */
arch/mips/include/asm/futex.h +17 -15
@@ -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
arch/parisc/include/asm/futex.h +9 -9
@@ -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__*/
arch/powerpc/include/asm/futex.h +11 -9
@@ -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__ */
arch/s390/include/asm/futex.h +2 -2
@@ -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__ */
arch/s390/include/asm/uaccess.h +1 -1
@@ -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;
arch/s390/lib/uaccess.h +2 -2
@@ -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 */
arch/s390/lib/uaccess_pt.c +8 -5
@@ -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; asmvolatile ("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 (¤t->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 (¤t->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; }
arch/s390/lib/uaccess_std.c +4 -2
@@ -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; asmvolatile (" 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; }
arch/sh/include/asm/futex-irq.h +4 -5
@@ -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 */
arch/sh/include/asm/futex.h +3 -2
@@ -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__ */
arch/sparc/include/asm/futex_64.h +10 -6
@@ -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) */
arch/tile/include/asm/futex.h +4 -3
@@ -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__
arch/x86/include/asm/futex.h +9 -7
@@ -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" + asmvolatile ("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
include/asm-generic/futex.h +2 -1
@@ -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 ; }
kernel/futex.c +16 -30
105 lines not on this page · raw message
Signature · 7 lines
1.7.3.1 -- Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
Quoted 13 lines · 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...
arch/s390/lib/uaccess_pt.c +2
-1-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"
arch/s390/lib/uaccess_pt.c int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) · line 371
Quoted 10 lines
arch/s390/lib/uaccess_pt.c +2
-1-"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".
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
arch/tile/include/asm/futex.h
Quoted 11 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.
[...]arch/tile/include/asm/futex.h +0
-0
Makes sense to me; that API is a little crazy.
For the tile changes:
Signature · 2 lines
Chris Metcalf, Tilera Corp. http://www.tilera.com
Tried out the ia64 bits. They seem fine.
Quoted 9 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.
Ack.
arch/alpha/include/asm/futex.h static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) · line 85
Quoted 4 lines
static inline int
arch/alpha/include/asm/futex.h +2
-1-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
Michel Lespinasse
Acked-by Chris Metcalf Acked-by Tony Luck Acked-by Thomas Gleixner Tested-by Michal SimekQuoted 13 lines · Thomas Gleixner
Quoted 9 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.Ack.
Quoted 7 lines
Review
Quoted 4 lines
static inline int
(quoted diff) +2
-1-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.
--- 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(-)
arch/alpha/include/asm/futex.h +16 -13
@@ -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__ */
arch/arm/include/asm/futex.h +16 -14
@@ -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 */
arch/frv/include/asm/futex.h +3 -2
@@ -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 ; }
arch/frv/kernel/futex.c +7 -7
@@ -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 *_oreturn 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 *_oreturn 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 *_olreturn 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 *_oreturn 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 ();
arch/ia64/include/asm/futex.h +9 -6
@@ -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 ; { - registerunsigned 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; } }
arch/microblaze/include/asm/futex.h +17 -14
@@ -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__ */
arch/mips/include/asm/futex.h +21 -18
@@ -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
arch/parisc/include/asm/futex.h +12 -12
@@ -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__*/
arch/powerpc/include/asm/futex.h +15 -12
@@ -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__ */
arch/s390/include/asm/futex.h +6 -6
@@ -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__ */
arch/s390/include/asm/uaccess.h +2 -2
@@ -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;
arch/s390/lib/uaccess.h +4 -4
@@ -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 */
arch/s390/lib/uaccess_pt.c +10 -7
@@ -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; asmvolatile ("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 (¤t->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 (¤t->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; }
arch/s390/lib/uaccess_std.c +5 -3
@@ -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; asmvolatile (" 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; }
arch/sh/include/asm/futex-irq.h +12 -12
@@ -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 */
arch/sh/include/asm/futex.h +6 -5
@@ -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__ */
arch/sparc/include/asm/futex_64.h +12 -8
@@ -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) */
arch/tile/include/asm/futex.h +14 -13
@@ -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__
arch/x86/include/asm/futex.h +12 -10
@@ -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" + asmvolatile ("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
include/asm-generic/futex.h +4 -3
@@ -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 ; }
kernel/futex.c +16 -30
105 lines not on this page · raw message
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
Quoted 22 lines · Michel Lespinasse
Quoted 13 lines · Thomas Gleixner
Quoted 9 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.Ack.
Quoted 7 lines
Review
Quoted 4 lines
static inline int
(quoted diff) +2
-1-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.
Quoted 5 lines
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
Quoted 1,280 lines
--------------------------------------8<-------------------------------
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, 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_inatomicandfutex_atomic_op_inuserinternal APIs as suggested by Thomas Gleixner.Signed-off-by Michel Lespinasse <[email protected]>Acked-by Thomas Gleixner <[email protected]>--- 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(-)arch/alpha/include/asm/futex.h +16
-13@@ -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__ */ arch/arm/include/asm/futex.h +16
-14@@ -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 */ arch/frv/include/asm/futex.h +3
-2@@ -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 ; }arch/frv/kernel/futex.c +7
-7@@ -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 *_oreturn 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 *_oreturn 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 *_olreturn 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 *_oreturn 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 ();arch/ia64/include/asm/futex.h +9
-6@@ -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 ; { - registerunsigned 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; } }arch/microblaze/include/asm/futex.h +17
-14@@ -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__ */ arch/mips/include/asm/futex.h +21
-18@@ -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 arch/parisc/include/asm/futex.h +12
-12@@ -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__*/ arch/powerpc/include/asm/futex.h +15
-12@@ -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__ */ arch/s390/include/asm/futex.h +6
-6@@ -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__ */ arch/s390/include/asm/uaccess.h +2
-2@@ -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;arch/s390/lib/uaccess.h +4
-4@@ -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 */ arch/s390/lib/uaccess_pt.c +10
-7@@ -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; asmvolatile ("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 (¤t->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 (¤t->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; }arch/s390/lib/uaccess_std.c +5
-3@@ -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; asmvolatile (" 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; }arch/sh/include/asm/futex-irq.h +12
-12@@ -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 */ arch/sh/include/asm/futex.h +6
-5@@ -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__ */ arch/sparc/include/asm/futex_64.h +12
-8@@ -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) */ arch/tile/include/asm/futex.h +14
-13@@ -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__arch/x86/include/asm/futex.h +12
-10@@ -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" + asmvolatile ("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 include/asm-generic/futex.h +4
-3@@ -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 ; }kernel/futex.c +16
-30@@ -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++) {Signature · 3 lines
-- Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
Quoted 22 lines · On Wed, 9 Mar 2011 03:25:50 -0800 Michel Lespinasse <[email protected]> wrote:
Quoted 13 lines · Thomas Gleixner
Quoted 9 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.Ack.
Quoted 7 lines
Review
Quoted 4 lines
static inline int
(quoted diff) +2
-1-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.
Quoted 2 lines
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.oarch/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.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Quoted 5 lines · Martin Schwidefsky
Quoted 2 lines · 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.
Quoted 7 lines
The inline assmeblies look good now but I get this compile error on s390:
CC
arch/s390/lib/uaccess_pt.oarch/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 herearch/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 :)
arch/s390/lib/uaccess_pt.c +2 -2
@@ -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;
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
Quoted 36 lines · Michel Lespinasse
Quoted 13 lines · Thomas Gleixner
Quoted 9 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.Ack.
Quoted 7 lines
Review
Quoted 4 lines
static inline int
(quoted diff) +2
-1-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_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().
Quoted 8 lines
This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, 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_inatomicandfutex_atomic_op_inuserinternal 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
Quoted 1,264 lines
Signed-off-by Michel Lespinasse <[email protected]>Acked-by Thomas Gleixner <[email protected]>---
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(-)arch/alpha/include/asm/futex.h +2
-2@@ -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
arch/alpha/include/asm/futex.h +2
-1-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"arch/alpha/include/asm/futex.h +0
-0@@ -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__*/arch/arm/include/asm/futex.h +0
-0@@ -35,7 +35,7 @@ : "cc", "memory")static inline int
arch/arm/include/asm/futex.h +1
-1-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;arch/arm/include/asm/futex.h +1
-1@@ -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()*/arch/arm/include/asm/futex.h +0
-0@@ -88,36 +88,38 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) }static inline int
arch/arm/include/asm/futex.h +2
-1-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(); /* impliespreempt_disable()*/
+ /* Note that preemption is disabled byfutex_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(); /* subsumespreempt_enable()*/ -
- return val;
+ *uval = val;
+ return ret;
}#endif /* !SMP */
arch/frv/include/asm/futex.h +1
-1@@ -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
arch/frv/include/asm/futex.h +2
-1-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;
}arch/frv/kernel/futex.c +7
-7@@ -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();arch/ia64/include/asm/futex.h +0
-0@@ -46,7 +46,7 @@ do { \ } while (0)static inline int
arch/ia64/include/asm/futex.h +1
-1-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;arch/ia64/include/asm/futex.h +1
-1@@ -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
arch/ia64/include/asm/futex.h +2
-1-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;
}
}arch/microblaze/include/asm/futex.h +0
-0@@ -29,7 +29,7 @@ })static inline int
arch/microblaze/include/asm/futex.h +1
-1-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;arch/microblaze/include/asm/futex.h +1
-1@@ -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
arch/microblaze/include/asm/futex.h +2
-1-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__*/arch/mips/include/asm/futex.h +0
-0@@ -75,7 +75,7 @@ }static inline int
arch/mips/include/asm/futex.h +1
-1-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;arch/mips/include/asm/futex.h +1
-1@@ -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
arch/mips/include/asm/futex.h +2
-1-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) {arch/mips/include/asm/futex.h +0
-0@@ -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) {arch/mips/include/asm/futex.h +0
-0@@ -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
arch/parisc/include/asm/futex.h +0
-0@@ -8,7 +8,7 @@ #include <asm/errno.h>static inline int
arch/parisc/include/asm/futex.h +1
-1-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;arch/parisc/include/asm/futex.h +1
-1@@ -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
arch/parisc/include/asm/futex.h +2
-1-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.cwants to do acmpxchg_inatomicon kernel NULL, which is
* our gateway page, and causes no end of trouble...arch/parisc/include/asm/futex.h +7
-7@@ -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__*/arch/powerpc/include/asm/futex.h +2
-2@@ -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
arch/powerpc/include/asm/futex.h +2
-1-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__*/arch/s390/include/asm/futex.h +6
-6@@ -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__ */arch/s390/include/asm/uaccess.h +2
-2@@ -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;arch/s390/lib/uaccess.h +4
-4@@ -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 */arch/s390/lib/uaccess_pt.c +4
-3@@ -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;
}arch/s390/lib/uaccess_pt.c +2
-1-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(¤t->mm->page_table_lock);
uaddr = (int__user*)__dat_user_addr((unsigned long) uaddr); if (!uaddr) {arch/s390/lib/uaccess_pt.c +1
-1@@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) } get_page(virt_to_page(uaddr)); spin_unlock(¤t->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; }arch/s390/lib/uaccess_std.c +3
-2@@ -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;
}arch/sh/include/asm/futex-irq.h +12
-12@@ -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 */arch/sh/include/asm/futex.h +2
-2@@ -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
arch/sh/include/asm/futex.h +2
-1-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);
+ returnatomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); }#endif /*
__KERNEL__*/arch/sparc/include/asm/futex_64.h +2
-2@@ -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
arch/sparc/include/asm/futex_64.h +2
-1-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) */
arch/tile/include/asm/futex.h +14
-13@@ -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__arch/x86/include/asm/futex.h +7
-6@@ -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
include/asm-generic/futex.h +0
-0@@ -6,7 +6,7 @@ #include <asm/errno.h>static inline int
include/asm-generic/futex.h +1
-1-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;include/asm-generic/futex.h +1
-1@@ -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
include/asm-generic/futex.h +2
-1-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;
}kernel/futex.c +16
-31@@ -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.
Signature · 1 line
Darren Hart
Quoted 1 line · Michel Lespinasse
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 ?
arch/arm/include/asm/futex.h futex_atomic_op_inuser (int encoded_op, int __user *uaddr) · line 101
Quoted 4 lines
arch/arm/include/asm/futex.h +2
-1-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.
Quoted 6 lines
arch/frv/kernel/futex.c +1
-1-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 ;
arch/frv/kernel/futex.c int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) · line 203
Quoted 8 lines
arch/frv/kernel/futex.c +1
-1@@ -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
Quoted 11 lines · Thomas Gleixner
Quoted 1 line · Michel Lespinasse
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 ?
arch/arm/include/asm/futex.h futex_atomic_op_inuser (int encoded_op, int __user *uaddr) · line 101
Quoted 3 lines
arch/arm/include/asm/futex.h +2
-1-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.
Quoted 9 lines
Quoted 9 lines
arch/frv/kernel/futex.c +1
-1-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;
Quoted 8 lines
arch/alpha/include/asm/futex.h static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) · line 45
Quoted 5 lines
arch/alpha/include/asm/futex.h +1
-1-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.
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
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.
arch/arm/include/asm/futex.h +2 -3
@@ -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; }
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
[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.
LKML-Reference: <[email protected]>
--- arch/arm/include/asm/futex.h | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
arch/arm/include/asm/futex.h +2 -3
@@ -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; }
Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
In reply to Michel LespinasseQuoted 3 lines · Michel Lespinasse
kernel/futex.cdisables page faults before callingfutex_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
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
Quoted 32 lines · Linus Torvalds
Quoted 3 lines · Michel Lespinasse
kernel/futex.cdisables page faults before callingfutex_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 theexit_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
Signature · 1 line
Darren Hart
Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
Quoted 11 lines · Darren Hart
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.cwith 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,
Signature · 3 lines
Darren Hart Intel Open Source Technology Center Yocto Project - Linux Kernel
Peter Zijlstra
reviewerRe: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
In reply to Darren HartQuoted 1 line · Darren Hart
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.
Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
In reply to Linus TorvaldsQuoted 23 lines · Linus Torvalds
Quoted 3 lines · Michel Lespinasse
kernel/futex.cdisables page faults before callingfutex_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 theexit_robust_list()->handle_futex_death(), for example.
Quoted 6 lines
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
Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
Quoted 9 lines · Thomas Gleixner
Quoted 1 line · Linus Torvalds
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 inhandle_futex_death()which does not use the helper functioncmpxchg_futex_value_locked(). That helper function is safe and does the right thing:
Quoted 7 lines
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.
--- kernel/futex.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
kernel/futex.c +14 -3
@@ -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;
Darren Hart
Acked-byRe: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
Quoted 47 lines · Thomas Gleixner
Quoted 9 lines · Thomas Gleixner
Quoted 1 line · Linus Torvalds
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 inhandle_futex_death()which does not use the helper functioncmpxchg_futex_value_locked(). That helper function is safe and does the right thing:Quoted 7 lines
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. Theget_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: Deobfuscatehandle_futex_death()
From: Thomas Gleixner<[email protected]>
Date: Mon, 14 Mar 2011 10:34:35 +0100
handle_futex_death()usesfutex_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()beforefutex_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.
Quoted 6 lines
Use the helper function which disables page faults around the
futex_atomic_cmpxchg_inatomic()and handle a fault with a call tofault_in_user_writeable()as all other places in the futex code do as well.Signed-off-by Thomas Gleixner<[email protected]>
Quoted 37 lines
--- kernel/futex.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)Index:
linux-2.6-tip/kernel/futex.c
===================================================================kernel/futex.c +14
-4@@ -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/
Signature · 3 lines
Darren Hart Intel Open Source Technology Center Yocto Project - Linux Kernel
[tip:core/futexes] arm: Remove bogus comment in futex_atomic_cmpxchg_inatomic()
In reply to Thomas GleixnerCommit-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. :(
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(-)
arch/arm/include/asm/futex.h +0 -3
@@ -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"
[tip:core/futexes] futex: Deobfuscate handle_futex_death()
In reply to Thomas GleixnerCommit-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.
LKML-Reference: <[email protected]>
--- kernel/futex.c | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-)
kernel/futex.c +14 -3
@@ -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;
Re: [PATCH 1/3] futex: do not pagefault_disable in futex_atomic_cmpxchg_inatomic()
In reply to Linus TorvaldsQuoted 5 lines · Linus Torvalds
Quoted 3 lines · Michel Lespinasse
kernel/futex.cdisables page faults before callingfutex_atomic_cmpxchg_inatomic(), so there is no need to do it again within that function.
Quoted 7 lines
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...
Quoted 1 line
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.
Quoted 7 lines
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 theexit_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 :/
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
PATCH 2/3 futex: cmpxchg_futex_value_locked API change
In reply to Michel LespinasseThe 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.
arch/alpha/include/asm/futex.h +12 -10
@@ -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__ */
arch/arm/include/asm/futex.h +10 -8
@@ -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 */
arch/frv/include/asm/futex.h +2 -1
@@ -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 ; }
arch/ia64/include/asm/futex.h +6 -3
@@ -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 ; { - registerunsigned 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; } }
arch/microblaze/include/asm/futex.h +13 -11
@@ -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__ */
arch/mips/include/asm/futex.h +17 -15
@@ -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
arch/parisc/include/asm/futex.h +9 -9
@@ -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__*/
arch/powerpc/include/asm/futex.h +11 -9
@@ -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__ */
arch/s390/include/asm/futex.h +2 -2
@@ -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__ */
arch/s390/include/asm/uaccess.h +1 -1
@@ -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;
arch/s390/lib/uaccess.h +2 -2
@@ -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 */
arch/s390/lib/uaccess_pt.c +8 -5
@@ -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; asmvolatile ("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 (¤t->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 (¤t->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; }
arch/s390/lib/uaccess_std.c +4 -2
@@ -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; asmvolatile (" 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; }
arch/sh/include/asm/futex-irq.h +4 -5
@@ -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 */
arch/sh/include/asm/futex.h +3 -2
@@ -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__ */
arch/sparc/include/asm/futex_64.h +10 -6
@@ -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) */
arch/tile/include/asm/futex.h +4 -3
@@ -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__
arch/x86/include/asm/futex.h +9 -7
@@ -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" + asmvolatile ("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
include/asm-generic/futex.h +2 -1
@@ -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 ; }
kernel/futex.c +16 -30
105 lines not on this page · raw message
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
[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.
LKML-Reference: <[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(-)
arch/alpha/include/asm/futex.h +12 -10
@@ -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__ */
arch/arm/include/asm/futex.h +10 -8
@@ -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 */
arch/frv/include/asm/futex.h +2 -1
@@ -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 ; }
arch/ia64/include/asm/futex.h +6 -3
@@ -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 ; { - registerunsigned 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; } }
arch/microblaze/include/asm/futex.h +13 -11
@@ -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__ */
arch/mips/include/asm/futex.h +17 -15
@@ -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
arch/parisc/include/asm/futex.h +9 -9
@@ -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__*/
arch/powerpc/include/asm/futex.h +11 -9
@@ -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__ */
arch/s390/include/asm/futex.h +2 -2
@@ -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__ */
arch/s390/include/asm/uaccess.h +1 -1
@@ -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;
arch/s390/lib/uaccess.h +2 -2
@@ -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 */
arch/s390/lib/uaccess_pt.c +8 -5
@@ -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; asmvolatile ("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 (¤t->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 (¤t->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; }
arch/s390/lib/uaccess_std.c +4 -2
@@ -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; asmvolatile (" 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; }
arch/sh/include/asm/futex-irq.h +4 -5
@@ -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 */
arch/sh/include/asm/futex.h +3 -2
@@ -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__ */
arch/sparc/include/asm/futex_64.h +10 -6
@@ -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) */
arch/tile/include/asm/futex.h +4 -3
@@ -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__
arch/x86/include/asm/futex.h +9 -7
@@ -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" + asmvolatile ("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
include/asm-generic/futex.h +2 -1
@@ -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 ; }
kernel/futex.c +15 -30
104 lines not on this page · raw message
[regression] Re: [PATCH 2/3] futex: Sanitize cmpxchg_futex_value_locked API
In reply to Michel Lespinasse(reset cc list)
Hi,
Quoted 3 lines · Michel Lespinasse
This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.
[...]
Quoted 1 line
Acked-by Tony Luck <[email protected]> [ia64]
Émeric Maschino (cc-ed) is experiencing random crashes, X restarts, and so on on Itanium. Bisects to this patch[1].
Patrick Baggett, investigating, wrote[2]:
Quoted 7 lines
It doesn't look like the return value (r8) is actually being set beyond initialized to 0. If there is some ia64 instruction that modifies it, GCC doesn't know about it from the inline assembly (r8 doesn't appear in the inputs/outputs list). From looking at the x86 version (agh, inline asm is hard to parse), it does modify the return value based on whether the comparison was a success or not, and the return value is certainly used by the callers.
And indeed, pinning that variable to that register (why not "prev" instead?) looks suspicious.
Anywhere, here's the potentially problematic patch hunk. Ideas?
Quoted 22 lines
arch/ia64/include/asm/futex.h +4
-2@@ -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 ; { - registerunsigned 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"
arch/ia64/include/asm/futex.h futex_atomic_op_inuser (int encoded_op, int __user *uaddr) · line 125
Quoted 10 lines
arch/ia64/include/asm/futex.h +2
-1"[2:]" - : "=r" (r8) + : "=r" (prev) : "r" (uaddr), "r" (newval), "rO" ((long) (unsigned) oldval) : "memory"); + *uval = prev;return r8; } }
Jonathan
[1] https://bugzilla.kernel.org/show_bug.cgi?idB757
[2] http://thread.gmane.org/gmane.linux.debian.ports.ia64/3121/focus123
RE: [regression] Re: [PATCH 2/3] futex: Sanitize cmpxchg_futex_value_locked API
PiBJdCBkb2Vzbid0IGxvb2sgbGlrZSB0aGUgcmV0dXJuIHZhbHVlIChyOCkgaXMgYWN0dWFsbHkg YmVpbmcgc2V0IGJleW9uZA0KPiBpbml0aWFsaXplZCB0byAwLiBJZiB0aGVyZSBpcyBzb21lIGlh NjQgaW5zdHJ1Y3Rpb24gdGhhdCBtb2RpZmllcyBpdCwgR0NDDQo+IGRvZXNuJ3Qga25vdyBhYm91 dCBpdCBmcm9tIHRoZSBpbmxpbmUgYXNzZW1ibHkgKHI4IGRvZXNuJ3QgYXBwZWFyIGluIHRoZQ0K PiBpbnB1dHMvb3V0cHV0cyBsaXN0KS4gRnJvbSBsb29raW5nIGF0IHRoZSB4ODYgdmVyc2lvbiAo YWdoLCBpbmxpbmUgYXNtIGlzDQo+IGhhcmQgdG8gcGFyc2UpLCBpdCBkb2VzIG1vZGlmeSB0aGUg cmV0dXJuIHZhbHVlIGJhc2VkIG9uIHdoZXRoZXIgdGhlDQo+IGNvbXBhcmlzb24gd2FzIGEgc3Vj Y2VzcyBvciBub3QsIGFuZCB0aGUgcmV0dXJuIHZhbHVlIGlzIGNlcnRhaW5seSB1c2VkIGJ5DQo+ IHRoZSBjYWxsZXJzLg0KDQpUaGUgY29tbWl0IGNvbW1lbnQgZm9yIHRoZSBjaGFuZ2UgbWFrZXMg aXQgc291bmQgbGlrZSB0aGUgcmV0dXJuIHZhbHVlDQppcyBhbiBlcnJvciBjb2RlICgtRU5PU1lT IGlmIHRoZSBmdW5jdGlvbiBpc24ndCBpbXBsZW1lbnRlZC9jb25maWd1cmVkOw0KLUVGQVVMVCBp ZiB0aGUgdXNlciBhZGRyZXNzIGlzIGJvZ3VzKSAtIG9yIHplcm8gaWYgbm90aGluZyBiYWQgaGFw cGVuZWQuDQoNCk5vdCAidGhlIGNvbXBhcmlzb24gd2FzIGEgc3VjY2VzcyBvciBub3QiLg0KDQpX aGF0J3MgdGhlIHJlYWwgYW5zd2VyPyBUaGUgaWE2NCBjb2RlIGlzIHJldHVybmluZyAwIHJlZ2Fy ZGxlc3Mgb2Ygd2hldGhlciB0aGUNCmNvbXBhcmUvZXhjaGFuZ2UgZm91bmQgdGhlIG9sZCB2YWx1 ZSBvciBub3QuICBJcyB0aGlzIGEgYmFkIGFzc3VtcHRpb24/DQoNCi1Ub255DQo
Re: [regression] Re: [PATCH 2/3] futex: Sanitize cmpxchg_futex_value_locked API
Quoted 11 lines · Tony
Quoted 7 lines
It doesn't look like the return value (r8) is actually being set beyond initialized to 0. If there is some ia64 instruction that modifies it, GCC doesn't know about it from the inline assembly (r8 doesn't appear in the inputs/outputs list). From looking at the x86 version (agh, inline asm is hard to parse), it does modify the return value based on whether the comparison was a success or not, and the return value is certainly used by the callers.
The commit comment for the change makes it sound like the return value is an error code (
-ENOSYSif the function isn't implemented/configured;-EFAULTif the user address is bogus) - or zero if nothing bad happened.
Yes, that's right.
Quoted 4 lines
Not "the comparison was a success or not".
What's the real answer? The ia64 code is returning 0 regardless of whether the compare/exchange found the old value or not. Is this a bad assumption?
No, I think something else is wrong, though I don't know what it would be.
Émeric, was the bisection result reproducible? E.g., if you try building 37a9d912b24f and 37a9d912b24f^ again, does the former consistently produce and the latter consistently not produce a crashy system?
Re: [regression] Re: [PATCH 2/3] futex: Sanitize cmpxchg_futex_value_locked API
Hello,
Warning, long answer...
Quoted 4 lines · Jonathan Nieder
Émeric, was the bisection result reproducible? E.g., if you try building
37a9d912b24fand 37a9d912b24f^ again, does the former consistently produce and the latter consistently not produce a crashy system?
Yes, definitely.
Building 37a9d912b24f leads to a broken kernel-2.6.38-rc8+ with the symptoms described in [1]. Simply reverting 37a9d912b24f produces a 100% working kernel (well, w.r.t. the symptoms described in [1] of course).
We exchanged a couple PMs with Tony on this subject. He first asked me to check whether the issue is really because of the change in the ia64 bits of futex_atomic_cmpxchg_inatomic or not:
(Tony Luck, by PM, wrote to Emeric Maschino)
Could you try a half-revert of the kernel change. Take the original code for futex_atomic_cmpxchg_inatomic() but name it ORIG_futex_atomic_cmpxchg_inatomic() then write the new as a wrapper around the old one - something like:
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval)
{
int ret;
ret = ORIG_futex_atomic_cmpxchg_inatomic(uaddr, oldval, newval);
*uval = oldval;
return (ret != oldval) ? ret : 0; /* ret<0 ?? ... this can'tcover all cases, but should be able to do something good enough */ }
If this makes the problem go away - we can start staring at the asm bits some more to see just what is wrong with this new version of the function.
I thus followed Tony's recommendation. Below is the result:
(Emeric Maschino, by PM, wrote to Tony Luck)
Well, partly. (about Tony's last remark: "If this makes the problem go away")
With a wrapper around the original API like you suggested above:
- the terminal window no more crashes when you hit the Tab key
- Iceweasel/Firefox no more triggers a X restart when clicking on a menu or a button
- gdb no more exits early with a SIGTRAP signal.
That's for the good news.
The bad news: with the wrapper around the original API, I nevertheless experience new side-effects:
- GDM3 no more displays user list, nor buttons, so you can't enter a X session from there. I had to shut GDM3 down and manually enter a X session with startx
- ioquake3-based Quake3 demo freezes while initializing sound. As you already did noticed, perhaps are we hitting ret < 0 values there.
Is there something else I can try to help debugging further?
Tony then asked me to provide him with a reduced test case he could play with:
(Tony Luck, by PM, wrote to Emeric Maschino)
OK - so we do have a problem in the new implementation of this function (otherwise this change shouldn't have had much effect).
I'd like a simple user mode test case that uses futexes to some trivial thing. Doesn't matter whether it shows a problem, I can tweak the test to try running into whatever corner case is causing the problem.
And this is where I'm actually stuck.
Tony also pointed to me a futex test suite:
(Tony Luck, by PM, wrote to Emeric Maschino)
I found a futex test suite:
git:://git.kernel.org/pub/scm/linux/kernel/git/dvhart/futextest.git
but it runs equally badly on kernel pre/post this change (I compared v2.6.36 as the pre version, and current linus tree as the post).
Bah! an x86 system fails in the same way (pthread_create calls fail for many tests - meaning they get skipped).
I don't know exactly how Tony run the test suite. On my side, kernel-2.6.38-rc8+ (minus 37a9d912b24f) passed successfully. But it had to be run as root, otherwise you'll get pthread_create errors as experienced by Tony.
By contrast, rebuilding with 37a9d912b24f, test suite failed at second test (futex_requeue_pi with locked argument). In fact, the test never returns. Looking at the code, it seems to wait for the completion of started threads, returning a value computed from the return value of the individual futex_cmp_requeue_pi calls:
(in signal_wakerfn)
[...]
while (task_count < THREAD_MAX [...] ) {
[...]
args->ret = futex_cmp_requeue_pi([...]);
[...]
task_count += args->ret;
[...]
}So, if the meaning of the futex API has changed, perhaps some programs (like this test) need to be updated accordingly.
Anyway, as Tony and Jonathan may remember, we recently had an issue on ia64 about udev > 167 running bad because of missing accept4 syscall into (Debian) kernel 2.6.38-2-mckinley. It thus wasn't easy to me to stick with old 2.6.38 while udev was updated. Since this issue has been fixed in Debian kernel 3.2.0-1-mckinley, I switched to this one, that brought the futex issue we're now talking about.
Now, recompiling and running futex test suite under kernel 3.2.0-1-mckinley, I'm getting different results. Running futex_requeue_pi without any parameter gives:
ERROR: No such process: FUTEX_CMP_REQUEUE_PI failed
For memories, this test passed successfully with 2.6.38-rc8+, with AND without 37a9d912b24f included.
Now, adding locked argument, I'm getting:
ERROR: Function not implemented: FUTEX_REQUEUE_PI failed
Huh? Both these tests nevertheless gracefully return with kernel 3.2, while the second test enters in an unfinite loop with buggy 2.6.38-rc8+.
Here's where I am for now: I still didn't found a simple futex user code sample for Tony (or others) to play with.
Any help and guidance greatly appreciated ;-)
Emeric
Re: [regression] Re: [PATCH 2/3] futex: Sanitize cmpxchg_futex_value_locked API
Oops, just to correct myself: the tests described below DON'T return gracefully with kernel 3.2. Sorry for the mistake.
Emeric
Quoted 12 lines · Émeric Maschino
ERROR: No such process:
FUTEX_CMP_REQUEUE_PIfailedFor memories, this test passed successfully with 2.6.38-rc8+, with AND without
37a9d912b24fincluded.Now, adding locked argument, I'm getting:
ERROR: Function not implemented:
FUTEX_REQUEUE_PIfailedHuh? Both these tests nevertheless gracefully return with kernel 3.2, while the second test enters in an unfinite loop with buggy 2.6.38-rc8+.
Re: [regression] Re: [PATCH 2/3] futex: Sanitize cmpxchg_futex_value_locked API
Hi,
Patch proposed by Tony in
https://bugzilla.kernel.org/show_bug.cgi?idB757 works for me :-)
Many thanks,
Emeric
Quoted 19 lines · Émeric Maschino
Oops, just to correct myself: the tests described below DON'T return gracefully with kernel 3.2. Sorry for the mistake.
Emeric
Quoted 12 lines · Émeric Maschino
ERROR: No such process:
FUTEX_CMP_REQUEUE_PIfailedFor memories, this test passed successfully with 2.6.38-rc8+, with AND without
37a9d912b24fincluded.Now, adding locked argument, I'm getting:
ERROR: Function not implemented:
FUTEX_REQUEUE_PIfailedHuh? Both these tests nevertheless gracefully return with kernel 3.2, while the second test enters in an unfinite loop with buggy 2.6.38-rc8+.
PATCH 3/3 futex: fix futex operation types
In reply to Michel LespinasseFix futex_atomic_op_inuser and futex_atomic_cmpxchg_inatomic prototypes to use u32 types for the futex.
arch/alpha/include/asm/futex.h +7 -6
@@ -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__ (
arch/arm/include/asm/futex.h +7 -6
@@ -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
arch/frv/include/asm/futex.h +3 -3
@@ -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 ; }
arch/frv/kernel/futex.c +7 -7
@@ -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 *_oreturn 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 *_oreturn 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 *_olreturn 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 *_oreturn 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 ();
arch/ia64/include/asm/futex.h +5 -5
@@ -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 ; {
arch/microblaze/include/asm/futex.h +7 -6
@@ -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; \
arch/mips/include/asm/futex.h +7 -6
@@ -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 ) {
arch/parisc/include/asm/futex.h +6 -6
@@ -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))
arch/powerpc/include/asm/futex.h +7 -6
@@ -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__ (
arch/s390/include/asm/futex.h +5 -5
@@ -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);
arch/s390/include/asm/uaccess.h +2 -2
@@ -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;
arch/s390/lib/uaccess.h +4 -4
@@ -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 */
arch/s390/lib/uaccess_pt.c +6 -6
@@ -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;
arch/s390/lib/uaccess_std.c +3 -3
@@ -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;
arch/sh/include/asm/futex-irq.h +10 -9
@@ -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);
arch/sh/include/asm/futex.h +5 -5
@@ -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);
arch/sparc/include/asm/futex_64.h +4 -4
@@ -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 ;
arch/tile/include/asm/futex.h +12 -12
@@ -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);
arch/x86/include/asm/futex.h +5 -5
@@ -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"
include/asm-generic/futex.h +4 -4
@@ -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 ; }
Signature · 2 lines
Michel "Walken" Lespinasse A program is never fully debugged until the last user dies.
[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.
LKML-Reference: <[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(-)
arch/alpha/include/asm/futex.h +7 -6
@@ -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__ (
arch/arm/include/asm/futex.h +7 -6
@@ -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
arch/frv/include/asm/futex.h +3 -3
@@ -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 ; }
arch/frv/kernel/futex.c +7 -7
@@ -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 *_oreturn 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 *_oreturn 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 *_olreturn 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 *_oreturn 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 ();
arch/ia64/include/asm/futex.h +5 -5
@@ -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 ; {
arch/microblaze/include/asm/futex.h +7 -6
@@ -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; \
arch/mips/include/asm/futex.h +7 -6
@@ -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 ) {
arch/parisc/include/asm/futex.h +6 -6
@@ -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))
arch/powerpc/include/asm/futex.h +7 -6
@@ -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__ (
arch/s390/include/asm/futex.h +5 -5
@@ -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);
arch/s390/include/asm/uaccess.h +2 -2
@@ -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;
arch/s390/lib/uaccess.h +4 -4
@@ -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 */
arch/s390/lib/uaccess_pt.c +6 -6
@@ -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;
arch/s390/lib/uaccess_std.c +3 -3
@@ -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;
arch/sh/include/asm/futex-irq.h +10 -9
@@ -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);
arch/sh/include/asm/futex.h +5 -5
@@ -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);
arch/sparc/include/asm/futex_64.h +4 -4
@@ -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 ;
arch/tile/include/asm/futex.h +12 -12
@@ -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);
arch/x86/include/asm/futex.h +5 -5
@@ -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"
include/asm-generic/futex.h +4 -4
@@ -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 ; }
Quoted 18 lines · Michel Lespinasse
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_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.
Quoted 7 lines
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:
M
Signature · 4 lines
Michal Simek, Ing. (M.Eng) w: www.monstr.eu p: +42-0-721842854 Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/ Microblaze U-BOOT custodian
Quoted 11 lines · Michel Lespinasse
The
cmpxchg_futex_value_lockedAPI 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 thecmpxchg_futex_value_lockedafter trying to fix the issue by runningfault_in_user_writeable().This change makes the
cmpxchg_futex_value_lockedAPI more similar to theget_futex_value_lockedone, returning an error code and updating the original value through a reference argument.Signed-off-by Michel Lespinasse <[email protected]>