msg-ring-fd.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test fd passing with MSG_RING
  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 <pthread.h>
  14. #include "liburing.h"
  15. #include "helpers.h"
  16. static int no_msg;
  17. static int no_sparse;
  18. static int no_fd_pass;
  19. struct data {
  20. pthread_t thread;
  21. pthread_barrier_t barrier;
  22. int ring_flags;
  23. int ring_fd;
  24. char buf[32];
  25. };
  26. static void *thread_fn(void *__data)
  27. {
  28. struct io_uring_sqe *sqe;
  29. struct io_uring_cqe *cqe;
  30. struct data *d = __data;
  31. struct io_uring ring;
  32. int ret, fd = -1;
  33. io_uring_queue_init(8, &ring, d->ring_flags);
  34. ret = io_uring_register_files(&ring, &fd, 1);
  35. if (ret) {
  36. if (ret != -EINVAL && ret != -EBADF)
  37. fprintf(stderr, "thread file register: %d\n", ret);
  38. no_sparse = 1;
  39. pthread_barrier_wait(&d->barrier);
  40. return NULL;
  41. }
  42. d->ring_fd = ring.ring_fd;
  43. pthread_barrier_wait(&d->barrier);
  44. /* wait for MSG */
  45. ret = io_uring_wait_cqe(&ring, &cqe);
  46. if (ret) {
  47. fprintf(stderr, "wait_cqe dst: %d\n", ret);
  48. return NULL;
  49. }
  50. if (cqe->res < 0) {
  51. fprintf(stderr, "cqe error dst: %d\n", cqe->res);
  52. return NULL;
  53. }
  54. fd = cqe->res;
  55. io_uring_cqe_seen(&ring, cqe);
  56. sqe = io_uring_get_sqe(&ring);
  57. io_uring_prep_read(sqe, fd, d->buf, sizeof(d->buf), 0);
  58. sqe->flags |= IOSQE_FIXED_FILE;
  59. io_uring_submit(&ring);
  60. ret = io_uring_wait_cqe(&ring, &cqe);
  61. if (ret) {
  62. fprintf(stderr, "wait_cqe dst: %d\n", ret);
  63. return NULL;
  64. }
  65. if (cqe->res < 0) {
  66. fprintf(stderr, "cqe error dst: %d\n", cqe->res);
  67. return NULL;
  68. }
  69. io_uring_queue_exit(&ring);
  70. return NULL;
  71. }
  72. static int test_remote(struct io_uring *src, int ring_flags)
  73. {
  74. struct io_uring_sqe *sqe;
  75. struct io_uring_cqe *cqe;
  76. int fds[2], fd, ret;
  77. struct data d;
  78. char buf[32];
  79. void *tret;
  80. int i;
  81. if (no_fd_pass)
  82. return 0;
  83. pthread_barrier_init(&d.barrier, NULL, 2);
  84. d.ring_flags = ring_flags;
  85. pthread_create(&d.thread, NULL, thread_fn, &d);
  86. pthread_barrier_wait(&d.barrier);
  87. memset(d.buf, 0, sizeof(d.buf));
  88. if (no_sparse)
  89. return 0;
  90. if (pipe(fds) < 0) {
  91. perror("pipe");
  92. return 1;
  93. }
  94. fd = fds[0];
  95. ret = io_uring_register_files(src, &fd, 1);
  96. if (ret) {
  97. fprintf(stderr, "register files failed: %d\n", ret);
  98. return 1;
  99. }
  100. for (i = 0; i < ARRAY_SIZE(buf); i++)
  101. buf[i] = rand();
  102. sqe = io_uring_get_sqe(src);
  103. io_uring_prep_write(sqe, fds[1], buf, sizeof(buf), 0);
  104. sqe->user_data = 1;
  105. sqe = io_uring_get_sqe(src);
  106. io_uring_prep_msg_ring_fd(sqe, d.ring_fd, 0, 0, 0, 0);
  107. sqe->user_data = 2;
  108. io_uring_submit(src);
  109. for (i = 0; i < 2; i++) {
  110. ret = io_uring_wait_cqe(src, &cqe);
  111. if (ret) {
  112. fprintf(stderr, "wait_cqe: %d\n", ret);
  113. return 1;
  114. }
  115. if (cqe->res < 0) {
  116. fprintf(stderr, "cqe res %d\n", cqe->res);
  117. return 1;
  118. }
  119. if (cqe->user_data == 1 && cqe->res != sizeof(buf)) {
  120. fprintf(stderr, "short write %d\n", cqe->res);
  121. return 1;
  122. }
  123. io_uring_cqe_seen(src, cqe);
  124. }
  125. pthread_join(d.thread, &tret);
  126. if (memcmp(buf, d.buf, sizeof(buf))) {
  127. fprintf(stderr, "buffers differ\n");
  128. return 1;
  129. }
  130. close(fds[0]);
  131. close(fds[1]);
  132. io_uring_unregister_files(src);
  133. return 0;
  134. }
  135. static int test_local(struct io_uring *src, struct io_uring *dst)
  136. {
  137. struct io_uring_sqe *sqe;
  138. struct io_uring_cqe *cqe;
  139. int fds[2], fd, ret;
  140. char buf[32], dst_buf[32];
  141. int i;
  142. if (no_fd_pass)
  143. return 0;
  144. fd = -1;
  145. ret = io_uring_register_files(dst, &fd, 1);
  146. if (ret) {
  147. if (ret == -EBADF || ret == -EINVAL)
  148. return 0;
  149. fprintf(stderr, "register files failed: %d\n", ret);
  150. return 1;
  151. }
  152. if (pipe(fds) < 0) {
  153. perror("pipe");
  154. return 1;
  155. }
  156. fd = fds[0];
  157. ret = io_uring_register_files(src, &fd, 1);
  158. if (ret) {
  159. fprintf(stderr, "register files failed: %d\n", ret);
  160. return 1;
  161. }
  162. memset(dst_buf, 0, sizeof(dst_buf));
  163. for (i = 0; i < ARRAY_SIZE(buf); i++)
  164. buf[i] = rand();
  165. sqe = io_uring_get_sqe(src);
  166. io_uring_prep_write(sqe, fds[1], buf, sizeof(buf), 0);
  167. sqe->user_data = 1;
  168. sqe = io_uring_get_sqe(src);
  169. io_uring_prep_msg_ring_fd(sqe, dst->ring_fd, 0, 0, 10, 0);
  170. sqe->user_data = 2;
  171. io_uring_submit(src);
  172. fd = -1;
  173. for (i = 0; i < 2; i++) {
  174. ret = io_uring_wait_cqe(src, &cqe);
  175. if (ret) {
  176. fprintf(stderr, "wait_cqe: %d\n", ret);
  177. return 1;
  178. }
  179. if (cqe->user_data == 2 && cqe->res == -EINVAL) {
  180. no_fd_pass = 1;
  181. } else if (cqe->res < 0) {
  182. fprintf(stderr, "cqe res %d\n", cqe->res);
  183. return 1;
  184. }
  185. if (cqe->user_data == 1 && cqe->res != sizeof(buf)) {
  186. fprintf(stderr, "short write %d\n", cqe->res);
  187. return 1;
  188. }
  189. io_uring_cqe_seen(src, cqe);
  190. }
  191. if (no_fd_pass)
  192. goto out;
  193. ret = io_uring_wait_cqe(dst, &cqe);
  194. if (ret) {
  195. fprintf(stderr, "wait_cqe dst: %d\n", ret);
  196. return 1;
  197. }
  198. if (cqe->res < 0) {
  199. fprintf(stderr, "cqe error dst: %d\n", cqe->res);
  200. return 1;
  201. }
  202. fd = cqe->res;
  203. io_uring_cqe_seen(dst, cqe);
  204. sqe = io_uring_get_sqe(dst);
  205. io_uring_prep_read(sqe, fd, dst_buf, sizeof(dst_buf), 0);
  206. sqe->flags |= IOSQE_FIXED_FILE;
  207. sqe->user_data = 3;
  208. io_uring_submit(dst);
  209. ret = io_uring_wait_cqe(dst, &cqe);
  210. if (ret) {
  211. fprintf(stderr, "wait_cqe dst: %d\n", ret);
  212. return 1;
  213. }
  214. if (cqe->res < 0) {
  215. fprintf(stderr, "cqe error dst: %d\n", cqe->res);
  216. return 1;
  217. }
  218. if (cqe->res != sizeof(dst_buf)) {
  219. fprintf(stderr, "short read %d\n", cqe->res);
  220. return 1;
  221. }
  222. if (memcmp(buf, dst_buf, sizeof(buf))) {
  223. fprintf(stderr, "buffers differ\n");
  224. return 1;
  225. }
  226. out:
  227. close(fds[0]);
  228. close(fds[1]);
  229. io_uring_unregister_files(src);
  230. io_uring_unregister_files(dst);
  231. return 0;
  232. }
  233. static int test(int ring_flags)
  234. {
  235. struct io_uring ring, ring2;
  236. int ret;
  237. ret = io_uring_queue_init(8, &ring, ring_flags);
  238. if (ret) {
  239. if (ret == -EINVAL)
  240. return 0;
  241. fprintf(stderr, "ring setup failed: %d\n", ret);
  242. return T_EXIT_FAIL;
  243. }
  244. ret = io_uring_queue_init(8, &ring2, ring_flags);
  245. if (ret) {
  246. fprintf(stderr, "ring setup failed: %d\n", ret);
  247. return T_EXIT_FAIL;
  248. }
  249. ret = test_local(&ring, &ring2);
  250. if (ret) {
  251. fprintf(stderr, "test local failed\n");
  252. return T_EXIT_FAIL;
  253. }
  254. if (no_msg)
  255. return T_EXIT_SKIP;
  256. ret = test_remote(&ring, ring_flags);
  257. if (ret) {
  258. fprintf(stderr, "test_remote failed\n");
  259. return T_EXIT_FAIL;
  260. }
  261. io_uring_queue_exit(&ring);
  262. io_uring_queue_exit(&ring2);
  263. return T_EXIT_PASS;
  264. }
  265. int main(int argc, char *argv[])
  266. {
  267. int ret;
  268. if (argc > 1)
  269. return T_EXIT_SKIP;
  270. ret = test(0);
  271. if (ret != T_EXIT_PASS) {
  272. fprintf(stderr, "ring flags 0 failed\n");
  273. return ret;
  274. }
  275. if (no_msg)
  276. return T_EXIT_SKIP;
  277. ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
  278. if (ret != T_EXIT_PASS) {
  279. fprintf(stderr, "ring flags defer failed\n");
  280. return ret;
  281. }
  282. return ret;
  283. }