buf-ring.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: run various shared buffer ring sanity checks
  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 <sys/mman.h>
  14. #include "liburing.h"
  15. #include "helpers.h"
  16. static int no_buf_ring;
  17. static int pagesize;
  18. /* test trying to register classic group when ring group exists */
  19. static int test_mixed_reg2(int bgid)
  20. {
  21. struct io_uring_buf_ring *br;
  22. struct io_uring_sqe *sqe;
  23. struct io_uring_cqe *cqe;
  24. struct io_uring ring;
  25. void *bufs;
  26. int ret;
  27. ret = t_create_ring(1, &ring, 0);
  28. if (ret == T_SETUP_SKIP)
  29. return 0;
  30. else if (ret != T_SETUP_OK)
  31. return 1;
  32. br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
  33. if (!br) {
  34. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  35. return 1;
  36. }
  37. /* provide classic buffers, group 1 */
  38. bufs = malloc(8 * 1024);
  39. sqe = io_uring_get_sqe(&ring);
  40. io_uring_prep_provide_buffers(sqe, bufs, 1024, 8, bgid, 0);
  41. io_uring_submit(&ring);
  42. ret = io_uring_wait_cqe(&ring, &cqe);
  43. if (ret) {
  44. fprintf(stderr, "wait_cqe %d\n", ret);
  45. return 1;
  46. }
  47. if (cqe->res != -EEXIST && cqe->res != -EINVAL) {
  48. fprintf(stderr, "cqe res %d\n", cqe->res);
  49. return 1;
  50. }
  51. io_uring_cqe_seen(&ring, cqe);
  52. io_uring_free_buf_ring(&ring, br, 32, bgid);
  53. io_uring_queue_exit(&ring);
  54. return 0;
  55. }
  56. /* test trying to register ring group when classic group exists */
  57. static int test_mixed_reg(int bgid)
  58. {
  59. struct io_uring_buf_ring *br;
  60. struct io_uring_sqe *sqe;
  61. struct io_uring_cqe *cqe;
  62. struct io_uring ring;
  63. void *bufs;
  64. int ret;
  65. ret = t_create_ring(1, &ring, 0);
  66. if (ret == T_SETUP_SKIP)
  67. return 0;
  68. else if (ret != T_SETUP_OK)
  69. return 1;
  70. /* provide classic buffers, group 1 */
  71. bufs = malloc(8 * 1024);
  72. sqe = io_uring_get_sqe(&ring);
  73. io_uring_prep_provide_buffers(sqe, bufs, 1024, 8, bgid, 0);
  74. io_uring_submit(&ring);
  75. ret = io_uring_wait_cqe(&ring, &cqe);
  76. if (ret) {
  77. fprintf(stderr, "wait_cqe %d\n", ret);
  78. return 1;
  79. }
  80. if (cqe->res) {
  81. fprintf(stderr, "cqe res %d\n", cqe->res);
  82. return 1;
  83. }
  84. io_uring_cqe_seen(&ring, cqe);
  85. br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
  86. if (br) {
  87. fprintf(stderr, "Buffer ring setup succeeded unexpectedly %d\n", ret);
  88. return 1;
  89. }
  90. io_uring_queue_exit(&ring);
  91. return 0;
  92. }
  93. static int test_double_reg_unreg(int bgid)
  94. {
  95. struct io_uring_buf_reg reg = { };
  96. struct io_uring_buf_ring *br;
  97. struct io_uring ring;
  98. int ret;
  99. ret = t_create_ring(1, &ring, 0);
  100. if (ret == T_SETUP_SKIP)
  101. return 0;
  102. else if (ret != T_SETUP_OK)
  103. return 1;
  104. br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
  105. if (!br) {
  106. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  107. return 1;
  108. }
  109. /* check that 2nd register with same bgid fails */
  110. reg.ring_addr = (unsigned long) br;
  111. reg.ring_entries = 32;
  112. reg.bgid = bgid;
  113. ret = io_uring_register_buf_ring(&ring, &reg, 0);
  114. if (ret != -EEXIST) {
  115. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  116. return 1;
  117. }
  118. ret = io_uring_free_buf_ring(&ring, br, 32, bgid);
  119. if (ret) {
  120. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  121. return 1;
  122. }
  123. ret = io_uring_unregister_buf_ring(&ring, bgid);
  124. if (ret != -EINVAL && ret != -ENOENT) {
  125. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  126. return 1;
  127. }
  128. io_uring_queue_exit(&ring);
  129. return 0;
  130. }
  131. static int test_reg_unreg(int bgid)
  132. {
  133. struct io_uring_buf_ring *br;
  134. struct io_uring ring;
  135. int ret;
  136. ret = t_create_ring(1, &ring, 0);
  137. if (ret == T_SETUP_SKIP)
  138. return 0;
  139. else if (ret != T_SETUP_OK)
  140. return 1;
  141. br = io_uring_setup_buf_ring(&ring, 32, bgid, 0, &ret);
  142. if (!br) {
  143. if (ret == -EINVAL) {
  144. no_buf_ring = 1;
  145. return 0;
  146. }
  147. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  148. return 1;
  149. }
  150. ret = io_uring_free_buf_ring(&ring, br, 32, bgid);
  151. if (ret) {
  152. fprintf(stderr, "Buffer ring unregister failed %d\n", ret);
  153. return 1;
  154. }
  155. io_uring_queue_exit(&ring);
  156. return 0;
  157. }
  158. static int test_bad_reg(int bgid)
  159. {
  160. struct io_uring ring;
  161. int ret;
  162. struct io_uring_buf_reg reg = { };
  163. ret = t_create_ring(1, &ring, 0);
  164. if (ret == T_SETUP_SKIP)
  165. return 0;
  166. else if (ret != T_SETUP_OK)
  167. return 1;
  168. reg.ring_addr = 4096;
  169. reg.ring_entries = 32;
  170. reg.bgid = bgid;
  171. ret = io_uring_register_buf_ring(&ring, &reg, 0);
  172. if (!ret)
  173. fprintf(stderr, "Buffer ring register worked unexpectedly\n");
  174. io_uring_queue_exit(&ring);
  175. return !ret;
  176. }
  177. static int test_full_page_reg(int bgid)
  178. {
  179. #if defined(__hppa__)
  180. return T_EXIT_SKIP;
  181. #else
  182. struct io_uring ring;
  183. int ret;
  184. void *ptr;
  185. struct io_uring_buf_reg reg = { };
  186. int entries = pagesize / sizeof(struct io_uring_buf);
  187. ret = io_uring_queue_init(1, &ring, 0);
  188. if (ret) {
  189. fprintf(stderr, "queue init failed %d\n", ret);
  190. return T_EXIT_FAIL;
  191. }
  192. ret = posix_memalign(&ptr, pagesize, pagesize * 2);
  193. if (ret) {
  194. fprintf(stderr, "posix_memalign failed %d\n", ret);
  195. goto err;
  196. }
  197. ret = mprotect(ptr + pagesize, pagesize, PROT_NONE);
  198. if (ret) {
  199. fprintf(stderr, "mprotect failed %d\n", errno);
  200. goto err1;
  201. }
  202. reg.ring_addr = (unsigned long) ptr;
  203. reg.ring_entries = entries;
  204. reg.bgid = bgid;
  205. ret = io_uring_register_buf_ring(&ring, &reg, 0);
  206. if (ret)
  207. fprintf(stderr, "register buf ring failed %d\n", ret);
  208. if (mprotect(ptr + pagesize, pagesize, PROT_READ | PROT_WRITE))
  209. fprintf(stderr, "reverting mprotect failed %d\n", errno);
  210. err1:
  211. free(ptr);
  212. err:
  213. io_uring_queue_exit(&ring);
  214. return ret ? T_EXIT_FAIL : T_EXIT_PASS;
  215. #endif
  216. }
  217. static int test_one_read(int fd, int bgid, struct io_uring *ring)
  218. {
  219. int ret;
  220. struct io_uring_cqe *cqe;
  221. struct io_uring_sqe *sqe;
  222. sqe = io_uring_get_sqe(ring);
  223. if (!sqe) {
  224. fprintf(stderr, "get sqe failed\n");
  225. return -1;
  226. }
  227. io_uring_prep_read(sqe, fd, NULL, 1, 0);
  228. sqe->flags |= IOSQE_BUFFER_SELECT;
  229. sqe->buf_group = bgid;
  230. ret = io_uring_submit(ring);
  231. if (ret <= 0) {
  232. fprintf(stderr, "sqe submit failed: %d\n", ret);
  233. return -1;
  234. }
  235. ret = io_uring_wait_cqe(ring, &cqe);
  236. if (ret < 0) {
  237. fprintf(stderr, "wait completion %d\n", ret);
  238. return -1;
  239. }
  240. ret = cqe->res;
  241. io_uring_cqe_seen(ring, cqe);
  242. if (ret == -ENOBUFS)
  243. return ret;
  244. if (ret != 1) {
  245. fprintf(stderr, "read result %d\n", ret);
  246. return -1;
  247. }
  248. return cqe->flags >> 16;
  249. }
  250. static int test_running(int bgid, int entries, int loops)
  251. {
  252. int ring_mask = io_uring_buf_ring_mask(entries);
  253. struct io_uring_buf_ring *br;
  254. int ret, loop, idx, read_fd;
  255. struct io_uring ring;
  256. char buffer[8];
  257. bool *buffers;
  258. ret = t_create_ring(1, &ring, 0);
  259. if (ret == T_SETUP_SKIP)
  260. return 0;
  261. else if (ret != T_SETUP_OK)
  262. return 1;
  263. br = io_uring_setup_buf_ring(&ring, entries, bgid, 0, &ret);
  264. if (!br) {
  265. /* by now should have checked if this is supported or not */
  266. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  267. return 1;
  268. }
  269. buffers = malloc(sizeof(bool) * entries);
  270. if (!buffers)
  271. return 1;
  272. read_fd = open("/dev/zero", O_RDONLY);
  273. if (read_fd < 0)
  274. return 1;
  275. for (loop = 0; loop < loops; loop++) {
  276. memset(buffers, 0, sizeof(bool) * entries);
  277. for (idx = 0; idx < entries; idx++)
  278. io_uring_buf_ring_add(br, buffer, sizeof(buffer), idx, ring_mask, idx);
  279. io_uring_buf_ring_advance(br, entries);
  280. for (idx = 0; idx < entries; idx++) {
  281. memset(buffer, 1, sizeof(buffer));
  282. ret = test_one_read(read_fd, bgid, &ring);
  283. if (ret < 0) {
  284. fprintf(stderr, "bad run %d/%d = %d\n", loop, idx, ret);
  285. return ret;
  286. }
  287. if (buffers[ret]) {
  288. fprintf(stderr, "reused buffer %d/%d = %d!\n", loop, idx, ret);
  289. return 1;
  290. }
  291. if (buffer[0] != 0) {
  292. fprintf(stderr, "unexpected read %d %d/%d = %d!\n",
  293. (int)buffer[0], loop, idx, ret);
  294. return 1;
  295. }
  296. if (buffer[1] != 1) {
  297. fprintf(stderr, "unexpected spilled read %d %d/%d = %d!\n",
  298. (int)buffer[1], loop, idx, ret);
  299. return 1;
  300. }
  301. buffers[ret] = true;
  302. }
  303. ret = test_one_read(read_fd, bgid, &ring);
  304. if (ret != -ENOBUFS) {
  305. fprintf(stderr, "expected enobufs run %d = %d\n", loop, ret);
  306. return 1;
  307. }
  308. }
  309. ret = io_uring_unregister_buf_ring(&ring, bgid);
  310. if (ret) {
  311. fprintf(stderr, "Buffer ring register failed %d\n", ret);
  312. return 1;
  313. }
  314. close(read_fd);
  315. io_uring_queue_exit(&ring);
  316. free(buffers);
  317. return 0;
  318. }
  319. int main(int argc, char *argv[])
  320. {
  321. int bgids[] = { 1, 127, -1 };
  322. int entries[] = {1, 32768, 4096, -1 };
  323. int ret, i;
  324. if (argc > 1)
  325. return T_EXIT_SKIP;
  326. pagesize = getpagesize();
  327. for (i = 0; bgids[i] != -1; i++) {
  328. ret = test_reg_unreg(bgids[i]);
  329. if (ret) {
  330. fprintf(stderr, "test_reg_unreg failed\n");
  331. return T_EXIT_FAIL;
  332. }
  333. if (no_buf_ring)
  334. break;
  335. ret = test_bad_reg(bgids[i]);
  336. if (ret) {
  337. fprintf(stderr, "test_bad_reg failed\n");
  338. return T_EXIT_FAIL;
  339. }
  340. ret = test_double_reg_unreg(bgids[i]);
  341. if (ret) {
  342. fprintf(stderr, "test_double_reg_unreg failed\n");
  343. return T_EXIT_FAIL;
  344. }
  345. ret = test_mixed_reg(bgids[i]);
  346. if (ret) {
  347. fprintf(stderr, "test_mixed_reg failed\n");
  348. return T_EXIT_FAIL;
  349. }
  350. ret = test_mixed_reg2(bgids[i]);
  351. if (ret) {
  352. fprintf(stderr, "test_mixed_reg2 failed\n");
  353. return T_EXIT_FAIL;
  354. }
  355. ret = test_full_page_reg(bgids[i]);
  356. if (ret == T_EXIT_FAIL) {
  357. fprintf(stderr, "test_full_page_reg failed\n");
  358. return T_EXIT_FAIL;
  359. }
  360. }
  361. for (i = 0; !no_buf_ring && entries[i] != -1; i++) {
  362. ret = test_running(2, entries[i], 3);
  363. if (ret) {
  364. fprintf(stderr, "test_running(%d) failed\n", entries[i]);
  365. return T_EXIT_FAIL;
  366. }
  367. }
  368. return T_EXIT_PASS;
  369. }