buf-ring.c 10 KB

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