futex.h 3.7 KB

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