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