linked-defer-close.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Test that the final close of a file does indeed get it closed, if the
  5. * ring is setup with DEFER_TASKRUN and the task is waiting in cqring_wait()
  6. * during. Also see:
  7. *
  8. * https://github.com/axboe/liburing/issues/1235
  9. *
  10. * for a bug report, and the zig code on which this test program is based.
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <errno.h>
  17. #include <arpa/inet.h>
  18. #include <sys/socket.h>
  19. #include <signal.h>
  20. #include <pthread.h>
  21. #include "liburing.h"
  22. #include "helpers.h"
  23. enum {
  24. IS_ACCEPT = 0,
  25. IS_SEND = 0x100,
  26. IS_SEND2 = 0x101,
  27. IS_SEND3 = 0x102,
  28. IS_CLOSE = 0x200,
  29. };
  30. struct thread_data {
  31. int parent_pid;
  32. };
  33. static void *thread_fn(void *__data)
  34. {
  35. struct thread_data *data = __data;
  36. struct sockaddr_in saddr;
  37. int sockfd, ret;
  38. char msg[64];
  39. memset(&saddr, 0, sizeof(saddr));
  40. saddr.sin_family = AF_INET;
  41. saddr.sin_port = htons(9999);
  42. inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr);
  43. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  44. if (sockfd < 0) {
  45. perror("socket");
  46. goto done;
  47. }
  48. ret = connect(sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
  49. if (ret < 0) {
  50. perror("connect");
  51. close(sockfd);
  52. goto done;
  53. }
  54. do {
  55. memset(msg, 0, sizeof(msg));
  56. ret = recv(sockfd, msg, sizeof(msg), 0);
  57. } while (ret > 0);
  58. close(sockfd);
  59. done:
  60. kill(data->parent_pid, SIGUSR1);
  61. return NULL;
  62. }
  63. /* we got SIGUSR1, exit normally */
  64. static void sig_usr1(int sig)
  65. {
  66. exit(T_EXIT_PASS);
  67. }
  68. /* timed out, failure */
  69. static void sig_timeout(int sig)
  70. {
  71. exit(T_EXIT_FAIL);
  72. }
  73. int main(int argc, char *argv[])
  74. {
  75. struct io_uring ring;
  76. struct io_uring_sqe *sqe;
  77. struct io_uring_cqe *cqe;
  78. struct sockaddr_in saddr;
  79. char *msg1 = "message number 1\n";
  80. char *msg2 = "message number 2\n";
  81. char *msg3 = "message number 3\n";
  82. int val, send_fd, ret, sockfd;
  83. struct sigaction act[2] = { };
  84. struct thread_data td;
  85. pthread_t thread;
  86. if (argc > 1)
  87. return T_EXIT_SKIP;
  88. memset(&saddr, 0, sizeof(saddr));
  89. saddr.sin_family = AF_INET;
  90. saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  91. saddr.sin_port = htons(9999);
  92. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  93. if (sockfd < 0) {
  94. perror("socket");
  95. return T_EXIT_FAIL;
  96. }
  97. val = 1;
  98. setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
  99. setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
  100. ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
  101. if (ret < 0) {
  102. perror("bind");
  103. close(sockfd);
  104. return T_EXIT_FAIL;
  105. }
  106. ret = listen(sockfd, 1);
  107. if (ret < 0) {
  108. perror("listen");
  109. close(sockfd);
  110. return T_EXIT_FAIL;
  111. }
  112. ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
  113. IORING_SETUP_DEFER_TASKRUN);
  114. if (ret == -EINVAL) {
  115. close(sockfd);
  116. return T_EXIT_SKIP;
  117. }
  118. sqe = io_uring_get_sqe(&ring);
  119. io_uring_prep_multishot_accept(sqe, sockfd, NULL, NULL, 0);
  120. sqe->user_data = IS_ACCEPT;
  121. io_uring_submit(&ring);
  122. /* check for no multishot accept */
  123. ret = io_uring_peek_cqe(&ring, &cqe);
  124. if (!ret && cqe->res == -EINVAL) {
  125. close(sockfd);
  126. return T_EXIT_SKIP;
  127. }
  128. /* expected exit */
  129. act[0].sa_handler = sig_usr1;
  130. sigaction(SIGUSR1, &act[0], NULL);
  131. /* if this hits, we have failed */
  132. act[1].sa_handler = sig_timeout;
  133. sigaction(SIGALRM, &act[1], NULL);
  134. alarm(5);
  135. /* start receiver */
  136. td.parent_pid = getpid();
  137. pthread_create(&thread, NULL, thread_fn, &td);
  138. do {
  139. ret = io_uring_submit_and_wait(&ring, 1);
  140. if (ret < 0) {
  141. fprintf(stderr, "submit: %d\n", ret);
  142. return T_EXIT_FAIL;
  143. }
  144. ret = io_uring_peek_cqe(&ring, &cqe);
  145. if (ret) {
  146. fprintf(stderr, "peek: %d\n", ret);
  147. return T_EXIT_FAIL;
  148. }
  149. switch (cqe->user_data) {
  150. case IS_ACCEPT:
  151. send_fd = cqe->res;
  152. io_uring_cqe_seen(&ring, cqe);
  153. /*
  154. * prep two sends, with the 2nd linked to a close
  155. * operation. Once the close has been completed, that
  156. * will terminate the receiving thread and that will
  157. * in turn send this task a SIGUSR1 signal. If the
  158. * kernel is buggy, then we never get SIGUSR1 and we
  159. * will sit forever waiting and be timed out.
  160. */
  161. sqe = io_uring_get_sqe(&ring);
  162. io_uring_prep_send(sqe, send_fd, msg1, strlen(msg1), 0);
  163. sqe->user_data = IS_SEND;
  164. sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK;
  165. sqe = io_uring_get_sqe(&ring);
  166. io_uring_prep_send(sqe, send_fd, msg2, strlen(msg2), 0);
  167. sqe->user_data = IS_SEND2;
  168. sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK;
  169. sqe = io_uring_get_sqe(&ring);
  170. io_uring_prep_send(sqe, send_fd, msg3, strlen(msg3), 0);
  171. sqe->user_data = IS_SEND3;
  172. sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK;
  173. sqe = io_uring_get_sqe(&ring);
  174. io_uring_prep_close(sqe, send_fd);
  175. sqe->user_data = IS_CLOSE;
  176. sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
  177. break;
  178. case IS_SEND:
  179. case IS_SEND2:
  180. fprintf(stderr, "Should not see send response\n");
  181. io_uring_cqe_seen(&ring, cqe);
  182. return T_EXIT_FAIL;
  183. case IS_CLOSE:
  184. fprintf(stderr, "Should not see close response\n");
  185. io_uring_cqe_seen(&ring, cqe);
  186. return T_EXIT_FAIL;
  187. default:
  188. fprintf(stderr, "got unknown cqe\n");
  189. return T_EXIT_FAIL;
  190. }
  191. } while (1);
  192. /* will never get here */
  193. return T_EXIT_FAIL;
  194. }