1 #ifndef _ASM_GENERIC_FUTEX_H 2 #define _ASM_GENERIC_FUTEX_H 3 4 #include <linux/futex.h> 5 #include <linux/uaccess.h> 6 #include <asm/errno.h> 7 8 #ifndef CONFIG_SMP 9 /* 10 * The following implementation only for uniprocessor machines. 11 * It relies on preempt_disable() ensuring mutual exclusion. 12 * 13 */ 14 15 /** 16 * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant 17 * argument and comparison of the previous 18 * futex value with another constant. 19 * 20 * @encoded_op: encoded operation to execute 21 * @uaddr: pointer to user space address 22 * 23 * Return: 24 * 0 - On success 25 * <0 - On error 26 */ 27 static inline int 28 arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) 29 { 30 int oldval, ret; 31 u32 tmp; 32 33 preempt_disable(); 34 pagefault_disable(); 35 36 ret = -EFAULT; 37 if (unlikely(get_user(oldval, uaddr) != 0)) 38 goto out_pagefault_enable; 39 40 ret = 0; 41 tmp = oldval; 42 43 switch (op) { 44 case FUTEX_OP_SET: 45 tmp = oparg; 46 break; 47 case FUTEX_OP_ADD: 48 tmp += oparg; 49 break; 50 case FUTEX_OP_OR: 51 tmp |= oparg; 52 break; 53 case FUTEX_OP_ANDN: 54 tmp &= ~oparg; 55 break; 56 case FUTEX_OP_XOR: 57 tmp ^= oparg; 58 break; 59 default: 60 ret = -ENOSYS; 61 } 62 63 if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) 64 ret = -EFAULT; 65 66 out_pagefault_enable: 67 pagefault_enable(); 68 preempt_enable(); 69 70 if (ret == 0) 71 *oval = oldval; 72 73 return ret; 74 } 75 76 /** 77 * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the 78 * uaddr with newval if the current value is 79 * oldval. 80 * @uval: pointer to store content of @uaddr 81 * @uaddr: pointer to user space address 82 * @oldval: old value 83 * @newval: new value to store to @uaddr 84 * 85 * Return: 86 * 0 - On success 87 * <0 - On error 88 */ 89 static inline int 90 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 91 u32 oldval, u32 newval) 92 { 93 u32 val; 94 95 preempt_disable(); 96 if (unlikely(get_user(val, uaddr) != 0)) { 97 preempt_enable(); 98 return -EFAULT; 99 } 100 101 if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { 102 preempt_enable(); 103 return -EFAULT; 104 } 105 106 *uval = val; 107 preempt_enable(); 108 109 return 0; 110 } 111 112 #else 113 static inline int 114 arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) 115 { 116 int oldval = 0, ret; 117 118 pagefault_disable(); 119 120 switch (op) { 121 case FUTEX_OP_SET: 122 case FUTEX_OP_ADD: 123 case FUTEX_OP_OR: 124 case FUTEX_OP_ANDN: 125 case FUTEX_OP_XOR: 126 default: 127 ret = -ENOSYS; 128 } 129 130 pagefault_enable(); 131 132 if (!ret) 133 *oval = oldval; 134 135 return ret; 136 } 137 138 static inline int 139 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 140 u32 oldval, u32 newval) 141 { 142 return -ENOSYS; 143 } 144 145 #endif /* CONFIG_SMP */ 146 #endif 147