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