poll-race-mshot.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: check that racing wakeups don't re-issue a poll multishot,
  5. * this can leak ring provided buffers. also test if ring
  6. * provided buffers for regular receive can leak if we hit a
  7. * poll race.
  8. */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <unistd.h>
  12. #include <pthread.h>
  13. #include <string.h>
  14. #include <sys/socket.h>
  15. #include "liburing.h"
  16. #include "helpers.h"
  17. #define NREQS 64
  18. #define BUF_SIZE 64
  19. static int no_buf_ring;
  20. struct data {
  21. pthread_barrier_t barrier;
  22. int fd;
  23. };
  24. static void *thread(void *data)
  25. {
  26. struct data *d = data;
  27. char buf[BUF_SIZE];
  28. int ret, i, fd;
  29. memset(buf, 0x5a, BUF_SIZE);
  30. pthread_barrier_wait(&d->barrier);
  31. fd = d->fd;
  32. for (i = 0; i < NREQS; i++) {
  33. ret = write(fd, buf, sizeof(buf));
  34. if (ret != BUF_SIZE) {
  35. if (ret < 0) {
  36. perror("write");
  37. printf("bad fd %d\n", fd);
  38. } else
  39. fprintf(stderr, "wrote short %d\n", ret);
  40. }
  41. }
  42. return NULL;
  43. }
  44. static int test(struct io_uring *ring, struct data *d)
  45. {
  46. struct io_uring_buf_ring *br;
  47. struct io_uring_sqe *sqe;
  48. struct io_uring_cqe *cqe;
  49. int fd[2], ret, i;
  50. pthread_t t;
  51. void *buf, *ptr;
  52. void *ret2;
  53. if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) < 0) {
  54. perror("socketpair");
  55. return T_EXIT_FAIL;
  56. }
  57. d->fd = fd[1];
  58. if (posix_memalign((void **) &buf, 16384, BUF_SIZE * NREQS))
  59. return T_EXIT_FAIL;
  60. br = io_uring_setup_buf_ring(ring, NREQS, 1, 0, &ret);
  61. if (!br) {
  62. if (ret == -EINVAL) {
  63. no_buf_ring = 1;
  64. return T_EXIT_SKIP;
  65. }
  66. fprintf(stderr, "buf ring reg %d\n", ret);
  67. return T_EXIT_FAIL;
  68. }
  69. ptr = buf;
  70. for (i = 0; i < NREQS; i++) {
  71. io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1,
  72. io_uring_buf_ring_mask(NREQS), i);
  73. ptr += BUF_SIZE;
  74. }
  75. io_uring_buf_ring_advance(br, NREQS);
  76. pthread_create(&t, NULL, thread, d);
  77. for (i = 0; i < NREQS; i++) {
  78. sqe = io_uring_get_sqe(ring);
  79. io_uring_prep_recv(sqe, fd[0], NULL, 0, 0);
  80. sqe->flags |= IOSQE_BUFFER_SELECT;
  81. sqe->buf_group = 1;
  82. }
  83. pthread_barrier_wait(&d->barrier);
  84. ret = io_uring_submit(ring);
  85. if (ret != NREQS) {
  86. fprintf(stderr, "submit %d\n", ret);
  87. return T_EXIT_FAIL;
  88. }
  89. i = 0;
  90. do {
  91. ret = io_uring_wait_cqe(ring, &cqe);
  92. if (ret) {
  93. fprintf(stderr, "cqe wait %d\n", ret);
  94. return T_EXIT_FAIL;
  95. }
  96. i++;
  97. if (cqe->res != BUF_SIZE) {
  98. fprintf(stderr, "Bad cqe res %d\n", cqe->res);
  99. break;
  100. }
  101. if (cqe->flags & IORING_CQE_F_BUFFER) {
  102. int bid = cqe->flags >> 16;
  103. if (bid > NREQS) {
  104. fprintf(stderr, "Bad BID %d\n", bid);
  105. return T_EXIT_FAIL;
  106. }
  107. } else {
  108. fprintf(stderr, "No BID set!\n");
  109. printf("ret=%d\n", cqe->res);
  110. return T_EXIT_FAIL;
  111. }
  112. io_uring_cqe_seen(ring, cqe);
  113. if (i > NREQS) {
  114. fprintf(stderr, "Got too many requests?\n");
  115. return T_EXIT_FAIL;
  116. }
  117. } while (i < NREQS);
  118. pthread_join(t, &ret2);
  119. free(buf);
  120. io_uring_free_buf_ring(ring, br, NREQS, 1);
  121. close(fd[0]);
  122. close(fd[1]);
  123. return T_EXIT_PASS;
  124. }
  125. static int test_mshot(struct io_uring *ring, struct data *d)
  126. {
  127. struct io_uring_buf_ring *br;
  128. struct io_uring_sqe *sqe;
  129. struct io_uring_cqe *cqe;
  130. int fd[2], ret, i;
  131. pthread_t t;
  132. void *buf, *ptr;
  133. void *ret2;
  134. if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) < 0) {
  135. perror("socketpair");
  136. return T_EXIT_FAIL;
  137. }
  138. d->fd = fd[1];
  139. if (posix_memalign((void *) &buf, 16384, BUF_SIZE * NREQS))
  140. return T_EXIT_FAIL;
  141. br = io_uring_setup_buf_ring(ring, NREQS, 1, 0, &ret);
  142. if (!br) {
  143. fprintf(stderr, "buf ring reg %d\n", ret);
  144. return T_EXIT_FAIL;
  145. }
  146. ptr = buf;
  147. for (i = 0; i < NREQS; i++) {
  148. io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1,
  149. io_uring_buf_ring_mask(NREQS), i);
  150. ptr += BUF_SIZE;
  151. }
  152. io_uring_buf_ring_advance(br, NREQS);
  153. pthread_create(&t, NULL, thread, d);
  154. sqe = io_uring_get_sqe(ring);
  155. io_uring_prep_recv_multishot(sqe, fd[0], NULL, 0, 0);
  156. sqe->flags |= IOSQE_BUFFER_SELECT;
  157. sqe->buf_group = 1;
  158. pthread_barrier_wait(&d->barrier);
  159. ret = io_uring_submit(ring);
  160. if (ret != 1) {
  161. fprintf(stderr, "submit %d\n", ret);
  162. return T_EXIT_FAIL;
  163. }
  164. i = 0;
  165. do {
  166. ret = io_uring_wait_cqe(ring, &cqe);
  167. if (ret) {
  168. fprintf(stderr, "cqe wait %d\n", ret);
  169. return T_EXIT_FAIL;
  170. }
  171. i++;
  172. if (!(cqe->flags & IORING_CQE_F_MORE))
  173. break;
  174. if (cqe->res != BUF_SIZE) {
  175. fprintf(stderr, "Bad cqe res %d\n", cqe->res);
  176. break;
  177. }
  178. if (cqe->flags & IORING_CQE_F_BUFFER) {
  179. int bid = cqe->flags >> 16;
  180. if (bid > NREQS) {
  181. fprintf(stderr, "Bad BID %d\n", bid);
  182. return T_EXIT_FAIL;
  183. }
  184. } else {
  185. fprintf(stderr, "No BID set!\n");
  186. printf("ret=%d\n", cqe->res);
  187. return T_EXIT_FAIL;
  188. }
  189. io_uring_cqe_seen(ring, cqe);
  190. if (i > NREQS) {
  191. fprintf(stderr, "Got too many requests?\n");
  192. return T_EXIT_FAIL;
  193. }
  194. } while (1);
  195. if (i != NREQS + 1) {
  196. fprintf(stderr, "Only got %d requests\n", i);
  197. return T_EXIT_FAIL;
  198. }
  199. pthread_join(t, &ret2);
  200. io_uring_free_buf_ring(ring, br, NREQS, 1);
  201. free(buf);
  202. close(fd[0]);
  203. close(fd[1]);
  204. return T_EXIT_PASS;
  205. }
  206. int main(int argc, char *argv[])
  207. {
  208. struct io_uring ring;
  209. struct data d;
  210. int i, ret;
  211. if (argc > 1)
  212. return T_EXIT_SKIP;
  213. pthread_barrier_init(&d.barrier, NULL, 2);
  214. for (i = 0; i < 1000; i++) {
  215. io_uring_queue_init(NREQS, &ring, 0);
  216. ret = test(&ring, &d);
  217. if (ret != T_EXIT_PASS) {
  218. if (no_buf_ring)
  219. break;
  220. fprintf(stderr, "Test failed loop %d\n", i);
  221. return T_EXIT_FAIL;
  222. }
  223. io_uring_queue_exit(&ring);
  224. }
  225. if (no_buf_ring)
  226. return T_EXIT_SKIP;
  227. for (i = 0; i < 1000; i++) {
  228. io_uring_queue_init(NREQS, &ring, 0);
  229. ret = test_mshot(&ring, &d);
  230. if (ret != T_EXIT_PASS) {
  231. fprintf(stderr, "Test mshot failed loop %d\n", i);
  232. return T_EXIT_FAIL;
  233. }
  234. io_uring_queue_exit(&ring);
  235. }
  236. return T_EXIT_PASS;
  237. }