link.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: run various linked sqe tests
  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. static int no_hardlink;
  16. /*
  17. * Timer with single nop
  18. */
  19. static int test_single_hardlink(struct io_uring *ring)
  20. {
  21. struct __kernel_timespec ts;
  22. struct io_uring_cqe *cqe;
  23. struct io_uring_sqe *sqe;
  24. int ret, i;
  25. sqe = io_uring_get_sqe(ring);
  26. if (!sqe) {
  27. fprintf(stderr, "get sqe failed\n");
  28. goto err;
  29. }
  30. ts.tv_sec = 0;
  31. ts.tv_nsec = 10000000ULL;
  32. io_uring_prep_timeout(sqe, &ts, 0, 0);
  33. sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
  34. sqe->user_data = 1;
  35. sqe = io_uring_get_sqe(ring);
  36. if (!sqe) {
  37. fprintf(stderr, "get sqe failed\n");
  38. goto err;
  39. }
  40. io_uring_prep_nop(sqe);
  41. sqe->user_data = 2;
  42. ret = io_uring_submit(ring);
  43. if (ret <= 0) {
  44. fprintf(stderr, "sqe submit failed: %d\n", ret);
  45. goto err;
  46. }
  47. for (i = 0; i < 2; i++) {
  48. ret = io_uring_wait_cqe(ring, &cqe);
  49. if (ret < 0) {
  50. fprintf(stderr, "wait completion %d\n", ret);
  51. goto err;
  52. }
  53. if (!cqe) {
  54. fprintf(stderr, "failed to get cqe\n");
  55. goto err;
  56. }
  57. if (no_hardlink)
  58. goto next;
  59. if (cqe->user_data == 1 && cqe->res == -EINVAL) {
  60. fprintf(stdout, "Hard links not supported, skipping\n");
  61. no_hardlink = 1;
  62. goto next;
  63. }
  64. if (cqe->user_data == 1 && cqe->res != -ETIME) {
  65. fprintf(stderr, "timeout failed with %d\n", cqe->res);
  66. goto err;
  67. }
  68. if (cqe->user_data == 2 && cqe->res) {
  69. fprintf(stderr, "nop failed with %d\n", cqe->res);
  70. goto err;
  71. }
  72. next:
  73. io_uring_cqe_seen(ring, cqe);
  74. }
  75. return 0;
  76. err:
  77. return 1;
  78. }
  79. /*
  80. * Timer -> timer -> nop
  81. */
  82. static int test_double_hardlink(struct io_uring *ring)
  83. {
  84. struct __kernel_timespec ts1, ts2;
  85. struct io_uring_cqe *cqe;
  86. struct io_uring_sqe *sqe;
  87. int ret, i;
  88. if (no_hardlink)
  89. return 0;
  90. sqe = io_uring_get_sqe(ring);
  91. if (!sqe) {
  92. fprintf(stderr, "get sqe failed\n");
  93. goto err;
  94. }
  95. ts1.tv_sec = 0;
  96. ts1.tv_nsec = 10000000ULL;
  97. io_uring_prep_timeout(sqe, &ts1, 0, 0);
  98. sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
  99. sqe->user_data = 1;
  100. sqe = io_uring_get_sqe(ring);
  101. if (!sqe) {
  102. fprintf(stderr, "get sqe failed\n");
  103. goto err;
  104. }
  105. ts2.tv_sec = 0;
  106. ts2.tv_nsec = 15000000ULL;
  107. io_uring_prep_timeout(sqe, &ts2, 0, 0);
  108. sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
  109. sqe->user_data = 2;
  110. sqe = io_uring_get_sqe(ring);
  111. if (!sqe) {
  112. fprintf(stderr, "get sqe failed\n");
  113. goto err;
  114. }
  115. io_uring_prep_nop(sqe);
  116. sqe->user_data = 3;
  117. ret = io_uring_submit(ring);
  118. if (ret <= 0) {
  119. fprintf(stderr, "sqe submit failed: %d\n", ret);
  120. goto err;
  121. }
  122. for (i = 0; i < 3; i++) {
  123. ret = io_uring_wait_cqe(ring, &cqe);
  124. if (ret < 0) {
  125. fprintf(stderr, "wait completion %d\n", ret);
  126. goto err;
  127. }
  128. if (!cqe) {
  129. fprintf(stderr, "failed to get cqe\n");
  130. goto err;
  131. }
  132. if (cqe->user_data == 1 && cqe->res != -ETIME) {
  133. fprintf(stderr, "timeout failed with %d\n", cqe->res);
  134. goto err;
  135. }
  136. if (cqe->user_data == 2 && cqe->res != -ETIME) {
  137. fprintf(stderr, "timeout failed with %d\n", cqe->res);
  138. goto err;
  139. }
  140. if (cqe->user_data == 3 && cqe->res) {
  141. fprintf(stderr, "nop failed with %d\n", cqe->res);
  142. goto err;
  143. }
  144. io_uring_cqe_seen(ring, cqe);
  145. }
  146. return 0;
  147. err:
  148. return 1;
  149. }
  150. /*
  151. * Test failing head of chain, and dependent getting -ECANCELED
  152. */
  153. static int test_single_link_fail(struct io_uring *ring)
  154. {
  155. struct io_uring_cqe *cqe;
  156. struct io_uring_sqe *sqe;
  157. int ret, i;
  158. sqe = io_uring_get_sqe(ring);
  159. if (!sqe) {
  160. printf("get sqe failed\n");
  161. goto err;
  162. }
  163. io_uring_prep_remove_buffers(sqe, 10, 1);
  164. sqe->flags |= IOSQE_IO_LINK;
  165. sqe = io_uring_get_sqe(ring);
  166. if (!sqe) {
  167. printf("get sqe failed\n");
  168. goto err;
  169. }
  170. io_uring_prep_nop(sqe);
  171. ret = io_uring_submit(ring);
  172. if (ret <= 0) {
  173. printf("sqe submit failed: %d\n", ret);
  174. goto err;
  175. }
  176. for (i = 0; i < 2; i++) {
  177. ret = io_uring_peek_cqe(ring, &cqe);
  178. if (ret < 0) {
  179. printf("wait completion %d\n", ret);
  180. goto err;
  181. }
  182. if (!cqe) {
  183. printf("failed to get cqe\n");
  184. goto err;
  185. }
  186. if (i == 0 && cqe->res != -ENOENT) {
  187. printf("sqe0 failed with %d, wanted -ENOENT\n", cqe->res);
  188. goto err;
  189. }
  190. if (i == 1 && cqe->res != -ECANCELED) {
  191. printf("sqe1 failed with %d, wanted -ECANCELED\n", cqe->res);
  192. goto err;
  193. }
  194. io_uring_cqe_seen(ring, cqe);
  195. }
  196. return 0;
  197. err:
  198. return 1;
  199. }
  200. /*
  201. * Test two independent chains
  202. */
  203. static int test_double_chain(struct io_uring *ring)
  204. {
  205. struct io_uring_cqe *cqe;
  206. struct io_uring_sqe *sqe;
  207. int ret, i;
  208. sqe = io_uring_get_sqe(ring);
  209. if (!sqe) {
  210. printf("get sqe failed\n");
  211. goto err;
  212. }
  213. io_uring_prep_nop(sqe);
  214. sqe->flags |= IOSQE_IO_LINK;
  215. sqe = io_uring_get_sqe(ring);
  216. if (!sqe) {
  217. printf("get sqe failed\n");
  218. goto err;
  219. }
  220. io_uring_prep_nop(sqe);
  221. sqe = io_uring_get_sqe(ring);
  222. if (!sqe) {
  223. printf("get sqe failed\n");
  224. goto err;
  225. }
  226. io_uring_prep_nop(sqe);
  227. sqe->flags |= IOSQE_IO_LINK;
  228. sqe = io_uring_get_sqe(ring);
  229. if (!sqe) {
  230. printf("get sqe failed\n");
  231. goto err;
  232. }
  233. io_uring_prep_nop(sqe);
  234. ret = io_uring_submit(ring);
  235. if (ret <= 0) {
  236. printf("sqe submit failed: %d\n", ret);
  237. goto err;
  238. }
  239. for (i = 0; i < 4; i++) {
  240. ret = io_uring_wait_cqe(ring, &cqe);
  241. if (ret < 0) {
  242. printf("wait completion %d\n", ret);
  243. goto err;
  244. }
  245. io_uring_cqe_seen(ring, cqe);
  246. }
  247. return 0;
  248. err:
  249. return 1;
  250. }
  251. /*
  252. * Test multiple dependents
  253. */
  254. static int test_double_link(struct io_uring *ring)
  255. {
  256. struct io_uring_cqe *cqe;
  257. struct io_uring_sqe *sqe;
  258. int ret, i;
  259. sqe = io_uring_get_sqe(ring);
  260. if (!sqe) {
  261. printf("get sqe failed\n");
  262. goto err;
  263. }
  264. io_uring_prep_nop(sqe);
  265. sqe->flags |= IOSQE_IO_LINK;
  266. sqe = io_uring_get_sqe(ring);
  267. if (!sqe) {
  268. printf("get sqe failed\n");
  269. goto err;
  270. }
  271. io_uring_prep_nop(sqe);
  272. sqe->flags |= IOSQE_IO_LINK;
  273. sqe = io_uring_get_sqe(ring);
  274. if (!sqe) {
  275. printf("get sqe failed\n");
  276. goto err;
  277. }
  278. io_uring_prep_nop(sqe);
  279. ret = io_uring_submit(ring);
  280. if (ret <= 0) {
  281. printf("sqe submit failed: %d\n", ret);
  282. goto err;
  283. }
  284. for (i = 0; i < 3; i++) {
  285. ret = io_uring_wait_cqe(ring, &cqe);
  286. if (ret < 0) {
  287. printf("wait completion %d\n", ret);
  288. goto err;
  289. }
  290. io_uring_cqe_seen(ring, cqe);
  291. }
  292. return 0;
  293. err:
  294. return 1;
  295. }
  296. /*
  297. * Test single dependency
  298. */
  299. static int test_single_link(struct io_uring *ring)
  300. {
  301. struct io_uring_cqe *cqe;
  302. struct io_uring_sqe *sqe;
  303. int ret, i;
  304. sqe = io_uring_get_sqe(ring);
  305. if (!sqe) {
  306. printf("get sqe failed\n");
  307. goto err;
  308. }
  309. io_uring_prep_nop(sqe);
  310. sqe->flags |= IOSQE_IO_LINK;
  311. sqe = io_uring_get_sqe(ring);
  312. if (!sqe) {
  313. printf("get sqe failed\n");
  314. goto err;
  315. }
  316. io_uring_prep_nop(sqe);
  317. ret = io_uring_submit(ring);
  318. if (ret <= 0) {
  319. printf("sqe submit failed: %d\n", ret);
  320. goto err;
  321. }
  322. for (i = 0; i < 2; i++) {
  323. ret = io_uring_wait_cqe(ring, &cqe);
  324. if (ret < 0) {
  325. printf("wait completion %d\n", ret);
  326. goto err;
  327. }
  328. io_uring_cqe_seen(ring, cqe);
  329. }
  330. return 0;
  331. err:
  332. return 1;
  333. }
  334. static int test_early_fail_and_wait(void)
  335. {
  336. struct io_uring ring;
  337. struct io_uring_sqe *sqe;
  338. int ret, invalid_fd = 42;
  339. struct iovec iov = { .iov_base = NULL, .iov_len = 0 };
  340. /* create a new ring as it leaves it dirty */
  341. ret = io_uring_queue_init(8, &ring, 0);
  342. if (ret) {
  343. printf("ring setup failed\n");
  344. return 1;
  345. }
  346. sqe = io_uring_get_sqe(&ring);
  347. if (!sqe) {
  348. printf("get sqe failed\n");
  349. goto err;
  350. }
  351. io_uring_prep_readv(sqe, invalid_fd, &iov, 1, 0);
  352. sqe->flags |= IOSQE_IO_LINK;
  353. sqe = io_uring_get_sqe(&ring);
  354. if (!sqe) {
  355. printf("get sqe failed\n");
  356. goto err;
  357. }
  358. io_uring_prep_nop(sqe);
  359. ret = io_uring_submit_and_wait(&ring, 2);
  360. if (ret <= 0 && ret != -EAGAIN) {
  361. printf("sqe submit failed: %d\n", ret);
  362. goto err;
  363. }
  364. io_uring_queue_exit(&ring);
  365. return 0;
  366. err:
  367. io_uring_queue_exit(&ring);
  368. return 1;
  369. }
  370. int main(int argc, char *argv[])
  371. {
  372. struct io_uring ring, poll_ring;
  373. int ret;
  374. if (argc > 1)
  375. return T_EXIT_SKIP;
  376. ret = io_uring_queue_init(8, &ring, 0);
  377. if (ret) {
  378. printf("ring setup failed\n");
  379. return T_EXIT_FAIL;
  380. }
  381. ret = io_uring_queue_init(8, &poll_ring, IORING_SETUP_IOPOLL);
  382. if (ret) {
  383. printf("poll_ring setup failed\n");
  384. return T_EXIT_FAIL;
  385. }
  386. ret = test_single_link(&ring);
  387. if (ret) {
  388. printf("test_single_link failed\n");
  389. return ret;
  390. }
  391. ret = test_double_link(&ring);
  392. if (ret) {
  393. printf("test_double_link failed\n");
  394. return ret;
  395. }
  396. ret = test_double_chain(&ring);
  397. if (ret) {
  398. printf("test_double_chain failed\n");
  399. return ret;
  400. }
  401. ret = test_single_link_fail(&poll_ring);
  402. if (ret) {
  403. printf("test_single_link_fail failed\n");
  404. return ret;
  405. }
  406. ret = test_single_hardlink(&ring);
  407. if (ret) {
  408. fprintf(stderr, "test_single_hardlink\n");
  409. return ret;
  410. }
  411. ret = test_double_hardlink(&ring);
  412. if (ret) {
  413. fprintf(stderr, "test_double_hardlink\n");
  414. return ret;
  415. }
  416. ret = test_early_fail_and_wait();
  417. if (ret) {
  418. fprintf(stderr, "test_early_fail_and_wait\n");
  419. return ret;
  420. }
  421. return T_EXIT_PASS;
  422. }