ringbuf-status.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test reading provided ring buf head
  5. *
  6. */
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include "liburing.h"
  14. #include "helpers.h"
  15. #define BUF_SIZE 32
  16. #define NR_BUFS 8
  17. #define FSIZE (BUF_SIZE * NR_BUFS)
  18. #define BR_MASK (NR_BUFS - 1)
  19. #define BGID 1
  20. static int no_buf_ring;
  21. static int no_buf_ring_status;
  22. static int test_max(void)
  23. {
  24. struct io_uring_buf_ring *br;
  25. struct io_uring ring;
  26. int nr_bufs = 32768;
  27. int ret, i;
  28. char *buf;
  29. ret = io_uring_queue_init(1, &ring, 0);
  30. if (ret) {
  31. fprintf(stderr, "ring setup failed: %d\n", ret);
  32. return 1;
  33. }
  34. if (posix_memalign((void **) &buf, 4096, FSIZE))
  35. return 1;
  36. br = io_uring_setup_buf_ring(&ring, nr_bufs, BGID, 0, &ret);
  37. if (!br) {
  38. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  39. return 1;
  40. }
  41. ret = io_uring_buf_ring_available(&ring, br, BGID);
  42. if (ret) {
  43. fprintf(stderr, "Bad available count %d\n", ret);
  44. return 1;
  45. }
  46. for (i = 0; i < nr_bufs / 2; i++)
  47. io_uring_buf_ring_add(br, buf, BUF_SIZE, i + 1, nr_bufs - 1, i);
  48. io_uring_buf_ring_advance(br, nr_bufs / 2);
  49. ret = io_uring_buf_ring_available(&ring, br, BGID);
  50. if (ret != nr_bufs / 2) {
  51. fprintf(stderr, "Bad half full available count %d\n", ret);
  52. return 1;
  53. }
  54. for (i = 0; i < nr_bufs / 2; i++)
  55. io_uring_buf_ring_add(br, buf, BUF_SIZE, i + 1, nr_bufs - 1, i);
  56. io_uring_buf_ring_advance(br, nr_bufs / 2);
  57. ret = io_uring_buf_ring_available(&ring, br, BGID);
  58. if (ret != nr_bufs) {
  59. fprintf(stderr, "Bad half full available count %d\n", ret);
  60. return 1;
  61. }
  62. free(buf);
  63. io_uring_queue_exit(&ring);
  64. return T_EXIT_PASS;
  65. }
  66. static int test(int invalid)
  67. {
  68. struct io_uring_sqe *sqe;
  69. struct io_uring_cqe *cqe;
  70. struct io_uring ring;
  71. struct io_uring_buf_ring *br;
  72. int ret, i, fds[2];
  73. uint16_t head;
  74. char *buf;
  75. void *ptr;
  76. char output[16];
  77. memset(output, 0x55, sizeof(output));
  78. ret = io_uring_queue_init(NR_BUFS, &ring, 0);
  79. if (ret) {
  80. fprintf(stderr, "ring setup failed: %d\n", ret);
  81. return 1;
  82. }
  83. if (pipe(fds) < 0) {
  84. perror("pipe");
  85. return T_EXIT_FAIL;
  86. }
  87. if (posix_memalign((void **) &buf, 4096, FSIZE))
  88. return 1;
  89. br = io_uring_setup_buf_ring(&ring, NR_BUFS, BGID, 0, &ret);
  90. if (!br) {
  91. if (ret == -EINVAL) {
  92. no_buf_ring = 1;
  93. free(buf);
  94. return 0;
  95. }
  96. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  97. return 1;
  98. }
  99. ptr = buf;
  100. for (i = 0; i < NR_BUFS; i++) {
  101. io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1, BR_MASK, i);
  102. ptr += BUF_SIZE;
  103. }
  104. io_uring_buf_ring_advance(br, NR_BUFS);
  105. /* head should be zero at this point */
  106. head = 1;
  107. if (!invalid)
  108. ret = io_uring_buf_ring_head(&ring, BGID, &head);
  109. else
  110. ret = io_uring_buf_ring_head(&ring, BGID + 10, &head);
  111. if (ret) {
  112. if (ret == -EINVAL) {
  113. no_buf_ring_status = 1;
  114. free(buf);
  115. return T_EXIT_SKIP;
  116. }
  117. if (invalid && ret == -ENOENT) {
  118. free(buf);
  119. return T_EXIT_PASS;
  120. }
  121. fprintf(stderr, "buf_ring_head: %d\n", ret);
  122. return T_EXIT_FAIL;
  123. }
  124. if (invalid) {
  125. fprintf(stderr, "lookup of bad group id succeeded\n");
  126. return T_EXIT_FAIL;
  127. }
  128. if (head != 0) {
  129. fprintf(stderr, "bad head %d\n", head);
  130. return T_EXIT_FAIL;
  131. }
  132. ret = io_uring_buf_ring_available(&ring, br, BGID);
  133. if (ret != NR_BUFS) {
  134. fprintf(stderr, "ring available %d\n", ret);
  135. return T_EXIT_FAIL;
  136. }
  137. sqe = io_uring_get_sqe(&ring);
  138. io_uring_prep_read(sqe, fds[0], NULL, BUF_SIZE, i * BUF_SIZE);
  139. sqe->buf_group = BGID;
  140. sqe->flags |= IOSQE_BUFFER_SELECT;
  141. sqe->user_data = 1;
  142. ret = io_uring_submit(&ring);
  143. if (ret != 1) {
  144. fprintf(stderr, "submit: %d\n", ret);
  145. return T_EXIT_FAIL;
  146. }
  147. /* head should still be zero at this point, no buffers consumed */
  148. head = 1;
  149. ret = io_uring_buf_ring_head(&ring, BGID, &head);
  150. if (head != 0) {
  151. fprintf(stderr, "bad head after submit %d\n", head);
  152. return T_EXIT_FAIL;
  153. }
  154. ret = write(fds[1], output, sizeof(output));
  155. if (ret != sizeof(output)) {
  156. fprintf(stderr, "pipe buffer write %d\n", ret);
  157. return T_EXIT_FAIL;
  158. }
  159. ret = io_uring_wait_cqe(&ring, &cqe);
  160. if (ret) {
  161. fprintf(stderr, "wait cqe failed %d\n", ret);
  162. return T_EXIT_FAIL;
  163. }
  164. if (cqe->res != sizeof(output)) {
  165. fprintf(stderr, "cqe res %d\n", cqe->res);
  166. return T_EXIT_FAIL;
  167. }
  168. if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
  169. fprintf(stderr, "no buffer selected\n");
  170. return T_EXIT_FAIL;
  171. }
  172. io_uring_cqe_seen(&ring, cqe);
  173. /* head should now be one, we consumed a buffer */
  174. ret = io_uring_buf_ring_head(&ring, BGID, &head);
  175. if (head != 1) {
  176. fprintf(stderr, "bad head after cqe %d\n", head);
  177. return T_EXIT_FAIL;
  178. }
  179. ret = io_uring_buf_ring_available(&ring, br, BGID);
  180. if (ret != NR_BUFS - 1) {
  181. fprintf(stderr, "ring available %d\n", ret);
  182. return T_EXIT_FAIL;
  183. }
  184. close(fds[0]);
  185. close(fds[1]);
  186. free(buf);
  187. io_uring_queue_exit(&ring);
  188. return T_EXIT_PASS;
  189. }
  190. int main(int argc, char *argv[])
  191. {
  192. int ret;
  193. ret = test(0);
  194. if (ret == T_EXIT_FAIL) {
  195. fprintf(stderr, "test 0 failed\n");
  196. return T_EXIT_FAIL;
  197. }
  198. if (no_buf_ring || no_buf_ring_status)
  199. return T_EXIT_SKIP;
  200. ret = test(1);
  201. if (ret == T_EXIT_FAIL) {
  202. fprintf(stderr, "test 1 failed\n");
  203. return T_EXIT_FAIL;
  204. }
  205. ret = test_max();
  206. if (ret == T_EXIT_FAIL) {
  207. fprintf(stderr, "test_max failed\n");
  208. return T_EXIT_FAIL;
  209. }
  210. return T_EXIT_PASS;
  211. }