futex.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. return -EFAULT;
  100. if (val == oldval && unlikely(put_user(newval, uaddr) != 0))
  101. return -EFAULT;
  102. *uval = val;
  103. preempt_enable();
  104. return 0;
  105. }
  106. #else
  107. static inline int
  108. futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
  109. {
  110. int op = (encoded_op >> 28) & 7;
  111. int cmp = (encoded_op >> 24) & 15;
  112. int oparg = (encoded_op << 8) >> 20;
  113. int cmparg = (encoded_op << 20) >> 20;
  114. int oldval = 0, ret;
  115. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  116. oparg = 1 << oparg;
  117. if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
  118. return -EFAULT;
  119. pagefault_disable();
  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. pagefault_enable();
  130. if (!ret) {
  131. switch (cmp) {
  132. case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
  133. case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
  134. case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
  135. case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
  136. case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
  137. case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
  138. default: ret = -ENOSYS;
  139. }
  140. }
  141. return ret;
  142. }
  143. static inline int
  144. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  145. u32 oldval, u32 newval)
  146. {
  147. return -ENOSYS;
  148. }
  149. #endif /* CONFIG_SMP */
  150. #endif