regbuf-clone.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test buffer cloning between rings
  5. *
  6. */
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <sys/uio.h>
  12. #include "liburing.h"
  13. #include "helpers.h"
  14. #define NR_VECS 64
  15. #define BUF_SIZE 8192
  16. static int no_buf_clone;
  17. static int test(int reg_src, int reg_dst)
  18. {
  19. struct iovec vecs[NR_VECS];
  20. struct io_uring src, dst;
  21. int ret, i;
  22. ret = io_uring_queue_init(1, &src, 0);
  23. if (ret) {
  24. fprintf(stderr, "ring_init: %d\n", ret);
  25. return T_EXIT_FAIL;
  26. }
  27. ret = io_uring_queue_init(1, &dst, 0);
  28. if (ret) {
  29. fprintf(stderr, "ring_init: %d\n", ret);
  30. return T_EXIT_FAIL;
  31. }
  32. if (reg_src) {
  33. ret = io_uring_register_ring_fd(&src);
  34. if (ret < 0) {
  35. if (ret == -EINVAL)
  36. return T_EXIT_SKIP;
  37. fprintf(stderr, "register ring: %d\n", ret);
  38. return T_EXIT_FAIL;
  39. }
  40. }
  41. if (reg_dst) {
  42. ret = io_uring_register_ring_fd(&dst);
  43. if (ret < 0) {
  44. if (ret == -EINVAL)
  45. return T_EXIT_SKIP;
  46. fprintf(stderr, "register ring: %d\n", ret);
  47. return T_EXIT_FAIL;
  48. }
  49. }
  50. /* test fail with no buffers in src */
  51. ret = io_uring_clone_buffers(&dst, &src);
  52. if (ret == -EINVAL) {
  53. /* no buffer copy support */
  54. no_buf_clone = true;
  55. return T_EXIT_SKIP;
  56. } else if (ret != -ENXIO) {
  57. fprintf(stderr, "empty copy: %d\n", ret);
  58. return T_EXIT_FAIL;
  59. }
  60. for (i = 0; i < NR_VECS; i++) {
  61. if (posix_memalign(&vecs[i].iov_base, 4096, BUF_SIZE))
  62. return T_EXIT_FAIL;
  63. vecs[i].iov_len = BUF_SIZE;
  64. }
  65. ret = io_uring_register_buffers(&src, vecs, NR_VECS);
  66. if (ret < 0) {
  67. if (ret == -ENOMEM)
  68. return T_EXIT_SKIP;
  69. return T_EXIT_FAIL;
  70. }
  71. /* copy should work now */
  72. ret = io_uring_clone_buffers(&dst, &src);
  73. if (ret) {
  74. fprintf(stderr, "buffer copy: %d\n", ret);
  75. return T_EXIT_FAIL;
  76. }
  77. /* try copy again, should get -EBUSY */
  78. ret = io_uring_clone_buffers(&dst, &src);
  79. if (ret != -EBUSY) {
  80. fprintf(stderr, "busy copy: %d\n", ret);
  81. return T_EXIT_FAIL;
  82. }
  83. ret = io_uring_unregister_buffers(&dst);
  84. if (ret) {
  85. fprintf(stderr, "dst unregister buffers: %d\n", ret);
  86. return T_EXIT_FAIL;
  87. }
  88. ret = io_uring_unregister_buffers(&dst);
  89. if (ret != -ENXIO) {
  90. fprintf(stderr, "dst unregister empty buffers: %d\n", ret);
  91. return T_EXIT_FAIL;
  92. }
  93. ret = io_uring_unregister_buffers(&src);
  94. if (ret) {
  95. fprintf(stderr, "src unregister buffers: %d\n", ret);
  96. return T_EXIT_FAIL;
  97. }
  98. ret = io_uring_register_buffers(&dst, vecs, NR_VECS);
  99. if (ret < 0) {
  100. fprintf(stderr, "register buffers dst; %d\n", ret);
  101. return T_EXIT_FAIL;
  102. }
  103. ret = io_uring_clone_buffers(&src, &dst);
  104. if (ret) {
  105. fprintf(stderr, "buffer copy reverse: %d\n", ret);
  106. return T_EXIT_FAIL;
  107. }
  108. ret = io_uring_unregister_buffers(&dst);
  109. if (ret) {
  110. fprintf(stderr, "dst unregister buffers: %d\n", ret);
  111. return T_EXIT_FAIL;
  112. }
  113. ret = io_uring_unregister_buffers(&dst);
  114. if (ret != -ENXIO) {
  115. fprintf(stderr, "dst unregister empty buffers: %d\n", ret);
  116. return T_EXIT_FAIL;
  117. }
  118. ret = io_uring_unregister_buffers(&src);
  119. if (ret) {
  120. fprintf(stderr, "src unregister buffers: %d\n", ret);
  121. return T_EXIT_FAIL;
  122. }
  123. io_uring_queue_exit(&src);
  124. io_uring_queue_exit(&dst);
  125. for (i = 0; i < NR_VECS; i++)
  126. free(vecs[i].iov_base);
  127. return T_EXIT_PASS;
  128. }
  129. static int test_dummy(void)
  130. {
  131. struct iovec vec = { };
  132. struct io_uring src, dst;
  133. int ret;
  134. ret = io_uring_queue_init(1, &src, 0);
  135. if (ret) {
  136. fprintf(stderr, "ring_init: %d\n", ret);
  137. return T_EXIT_FAIL;
  138. }
  139. ret = io_uring_queue_init(1, &dst, 0);
  140. if (ret) {
  141. fprintf(stderr, "ring_init: %d\n", ret);
  142. return T_EXIT_FAIL;
  143. }
  144. ret = io_uring_register_buffers(&src, &vec, 1);
  145. if (ret < 0) {
  146. fprintf(stderr, "failed to register dummy buffer: %d\n", ret);
  147. return T_EXIT_FAIL;
  148. }
  149. ret = io_uring_clone_buffers(&dst, &src);
  150. if (ret) {
  151. fprintf(stderr, "clone dummy buf: %d\n", ret);
  152. return T_EXIT_FAIL;
  153. }
  154. ret = io_uring_unregister_buffers(&src);
  155. if (ret) {
  156. fprintf(stderr, "rsc unregister buffers: %d\n", ret);
  157. return T_EXIT_FAIL;
  158. }
  159. ret = io_uring_unregister_buffers(&dst);
  160. if (ret) {
  161. fprintf(stderr, "dst unregister buffers: %d\n", ret);
  162. return T_EXIT_FAIL;
  163. }
  164. io_uring_queue_exit(&src);
  165. io_uring_queue_exit(&dst);
  166. return T_EXIT_PASS;
  167. }
  168. int main(int argc, char *argv[])
  169. {
  170. int ret;
  171. if (argc > 1)
  172. return T_EXIT_SKIP;
  173. ret = test(0, 0);
  174. if (ret == T_EXIT_SKIP) {
  175. return T_EXIT_SKIP;
  176. } else if (ret != T_EXIT_PASS) {
  177. fprintf(stderr, "test 0 0 failed\n");
  178. return T_EXIT_FAIL;
  179. }
  180. if (no_buf_clone)
  181. return T_EXIT_SKIP;
  182. ret = test(0, 1);
  183. if (ret == T_EXIT_SKIP) {
  184. return T_EXIT_SKIP;
  185. } else if (ret != T_EXIT_PASS) {
  186. fprintf(stderr, "test 0 1 failed\n");
  187. return T_EXIT_FAIL;
  188. }
  189. ret = test(1, 0);
  190. if (ret == T_EXIT_SKIP) {
  191. return T_EXIT_SKIP;
  192. } else if (ret != T_EXIT_PASS) {
  193. fprintf(stderr, "test 1 0 failed\n");
  194. return T_EXIT_FAIL;
  195. }
  196. ret = test(1, 1);
  197. if (ret == T_EXIT_SKIP) {
  198. return T_EXIT_SKIP;
  199. } else if (ret != T_EXIT_PASS) {
  200. fprintf(stderr, "test 1 1 failed\n");
  201. return T_EXIT_FAIL;
  202. }
  203. ret = test_dummy();
  204. if (ret == T_EXIT_SKIP) {
  205. return T_EXIT_SKIP;
  206. } else if (ret != T_EXIT_PASS) {
  207. fprintf(stderr, "test_dummy failed\n");
  208. return T_EXIT_FAIL;
  209. }
  210. return T_EXIT_PASS;
  211. }