link_drain.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test io_uring link io with drain io
  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 "helpers.h"
  14. #include "liburing.h"
  15. static int test_link_drain_one(struct io_uring *ring)
  16. {
  17. struct io_uring_cqe *cqe;
  18. struct io_uring_sqe *sqe[5];
  19. struct iovec iovecs;
  20. int i, fd, ret;
  21. off_t off = 0;
  22. char data[5] = {0};
  23. char expect[5] = {0, 1, 2, 3, 4};
  24. fd = open("testfile", O_WRONLY | O_CREAT, 0644);
  25. if (fd < 0) {
  26. perror("open");
  27. return 1;
  28. }
  29. iovecs.iov_base = t_malloc(4096);
  30. iovecs.iov_len = 4096;
  31. for (i = 0; i < 5; i++) {
  32. sqe[i] = io_uring_get_sqe(ring);
  33. if (!sqe[i]) {
  34. printf("get sqe failed\n");
  35. goto err;
  36. }
  37. }
  38. /* normal heavy io */
  39. io_uring_prep_writev(sqe[0], fd, &iovecs, 1, off);
  40. sqe[0]->user_data = 0;
  41. /* link io */
  42. io_uring_prep_nop(sqe[1]);
  43. sqe[1]->flags |= IOSQE_IO_LINK;
  44. sqe[1]->user_data = 1;
  45. /* link drain io */
  46. io_uring_prep_nop(sqe[2]);
  47. sqe[2]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
  48. sqe[2]->user_data = 2;
  49. /* link io */
  50. io_uring_prep_nop(sqe[3]);
  51. sqe[3]->user_data = 3;
  52. /* normal nop io */
  53. io_uring_prep_nop(sqe[4]);
  54. sqe[4]->user_data = 4;
  55. ret = io_uring_submit(ring);
  56. if (ret < 0) {
  57. printf("sqe submit failed\n");
  58. goto err;
  59. } else if (ret < 5) {
  60. printf("Submitted only %d\n", ret);
  61. goto err;
  62. }
  63. for (i = 0; i < 5; i++) {
  64. ret = io_uring_wait_cqe(ring, &cqe);
  65. if (ret < 0) {
  66. printf("child: wait completion %d\n", ret);
  67. goto err;
  68. }
  69. data[i] = cqe->user_data;
  70. io_uring_cqe_seen(ring, cqe);
  71. }
  72. if (memcmp(data, expect, 5) != 0)
  73. goto err;
  74. free(iovecs.iov_base);
  75. close(fd);
  76. unlink("testfile");
  77. return 0;
  78. err:
  79. free(iovecs.iov_base);
  80. close(fd);
  81. unlink("testfile");
  82. return 1;
  83. }
  84. static int test_link_drain_multi(struct io_uring *ring)
  85. {
  86. struct io_uring_cqe *cqe;
  87. struct io_uring_sqe *sqe[9];
  88. struct iovec iovecs;
  89. int i, fd, ret;
  90. off_t off = 0;
  91. char data[9] = {0};
  92. char expect[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
  93. fd = open("testfile", O_WRONLY | O_CREAT, 0644);
  94. if (fd < 0) {
  95. perror("open");
  96. return 1;
  97. }
  98. unlink("testfile");
  99. iovecs.iov_base = t_malloc(4096);
  100. iovecs.iov_len = 4096;
  101. for (i = 0; i < 9; i++) {
  102. sqe[i] = io_uring_get_sqe(ring);
  103. if (!sqe[i]) {
  104. printf("get sqe failed\n");
  105. goto err;
  106. }
  107. }
  108. /* normal heavy io */
  109. io_uring_prep_writev(sqe[0], fd, &iovecs, 1, off);
  110. sqe[0]->user_data = 0;
  111. /* link1 io head */
  112. io_uring_prep_nop(sqe[1]);
  113. sqe[1]->flags |= IOSQE_IO_LINK;
  114. sqe[1]->user_data = 1;
  115. /* link1 drain io */
  116. io_uring_prep_nop(sqe[2]);
  117. sqe[2]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
  118. sqe[2]->user_data = 2;
  119. /* link1 io end*/
  120. io_uring_prep_nop(sqe[3]);
  121. sqe[3]->user_data = 3;
  122. /* link2 io head */
  123. io_uring_prep_nop(sqe[4]);
  124. sqe[4]->flags |= IOSQE_IO_LINK;
  125. sqe[4]->user_data = 4;
  126. /* link2 io */
  127. io_uring_prep_nop(sqe[5]);
  128. sqe[5]->flags |= IOSQE_IO_LINK;
  129. sqe[5]->user_data = 5;
  130. /* link2 drain io */
  131. io_uring_prep_writev(sqe[6], fd, &iovecs, 1, off);
  132. sqe[6]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
  133. sqe[6]->user_data = 6;
  134. /* link2 io end */
  135. io_uring_prep_nop(sqe[7]);
  136. sqe[7]->user_data = 7;
  137. /* normal io */
  138. io_uring_prep_nop(sqe[8]);
  139. sqe[8]->user_data = 8;
  140. ret = io_uring_submit(ring);
  141. if (ret < 0) {
  142. printf("sqe submit failed\n");
  143. goto err;
  144. } else if (ret < 9) {
  145. printf("Submitted only %d\n", ret);
  146. goto err;
  147. }
  148. for (i = 0; i < 9; i++) {
  149. ret = io_uring_wait_cqe(ring, &cqe);
  150. if (ret < 0) {
  151. printf("child: wait completion %d\n", ret);
  152. goto err;
  153. }
  154. data[i] = cqe->user_data;
  155. io_uring_cqe_seen(ring, cqe);
  156. }
  157. if (memcmp(data, expect, 9) != 0)
  158. goto err;
  159. free(iovecs.iov_base);
  160. close(fd);
  161. return 0;
  162. err:
  163. free(iovecs.iov_base);
  164. close(fd);
  165. return 1;
  166. }
  167. static int test_drain(bool defer)
  168. {
  169. struct io_uring ring;
  170. int i, ret;
  171. unsigned int flags = 0;
  172. if (defer)
  173. flags = IORING_SETUP_SINGLE_ISSUER |
  174. IORING_SETUP_DEFER_TASKRUN;
  175. ret = io_uring_queue_init(100, &ring, flags);
  176. if (ret) {
  177. printf("ring setup failed\n");
  178. return 1;
  179. }
  180. for (i = 0; i < 1000; i++) {
  181. ret = test_link_drain_one(&ring);
  182. if (ret) {
  183. fprintf(stderr, "test_link_drain_one failed\n");
  184. break;
  185. }
  186. ret = test_link_drain_multi(&ring);
  187. if (ret) {
  188. fprintf(stderr, "test_link_drain_multi failed\n");
  189. break;
  190. }
  191. }
  192. return ret;
  193. }
  194. int main(int argc, char *argv[])
  195. {
  196. int ret;
  197. if (argc > 1)
  198. return T_EXIT_SKIP;
  199. ret = test_drain(false);
  200. if (ret) {
  201. fprintf(stderr, "test_drain(false) failed\n");
  202. return T_EXIT_FAIL;
  203. }
  204. if (t_probe_defer_taskrun()) {
  205. ret = test_drain(true);
  206. if (ret) {
  207. fprintf(stderr, "test_drain(true) failed\n");
  208. return T_EXIT_FAIL;
  209. }
  210. }
  211. return T_EXIT_PASS;
  212. }