• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: test io_uring_register_sync_cancel()
4  *
5  */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 
13 #include "liburing.h"
14 #include "helpers.h"
15 
16 static int no_sync_cancel;
17 
test_sync_cancel_timeout(struct io_uring * ring,int async)18 static int test_sync_cancel_timeout(struct io_uring *ring, int async)
19 {
20 	struct io_uring_sync_cancel_reg reg = { };
21 	struct io_uring_sqe *sqe;
22 	struct io_uring_cqe *cqe;
23 	int ret, fds[2], to_prep;
24 	char buf[32];
25 
26 	if (pipe(fds) < 0) {
27 		perror("pipe");
28 		return 1;
29 	}
30 
31 	to_prep = 1;
32 	sqe = io_uring_get_sqe(ring);
33 	io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
34 	sqe->user_data = 0x89;
35 	if (async)
36 		sqe->flags |= IOSQE_ASYNC;
37 
38 	ret = io_uring_submit(ring);
39 	if (ret != to_prep) {
40 		fprintf(stderr, "submit=%d\n", ret);
41 		return 1;
42 	}
43 
44 	usleep(10000);
45 
46 	reg.addr = 0x89;
47 	reg.timeout.tv_nsec = 1;
48 	ret = io_uring_register_sync_cancel(ring, &reg);
49 	if (async) {
50 		/* we expect -ETIME here, but can race and get 0 */
51 		if (ret != -ETIME && ret != 0) {
52 			fprintf(stderr, "sync_cancel=%d\n", ret);
53 			return 1;
54 		}
55 	} else {
56 		if (ret < 0) {
57 			fprintf(stderr, "sync_cancel=%d\n", ret);
58 			return 1;
59 		}
60 	}
61 
62 	/*
63 	 * we could _almost_ use peek_cqe() here, but there is still
64 	 * a small gap where io-wq is done with the request and on
65 	 * its way to posting a completion, but hasn't done it just
66 	 * yet. the request is canceled and won't be doing any IO
67 	 * to buffers etc, but the cqe may not have quite arrived yet.
68 	 */
69 	ret = io_uring_wait_cqe(ring, &cqe);
70 	if (ret) {
71 		fprintf(stderr, "peek=%d\n", ret);
72 		return 1;
73 	}
74 	if (cqe->res >= 0) {
75 		fprintf(stderr, "cqe->res=%d\n", cqe->res);
76 		return 1;
77 	}
78 	io_uring_cqe_seen(ring, cqe);
79 	return 0;
80 }
81 
test_sync_cancel(struct io_uring * ring,int async,int nr_all,int use_fd)82 static int test_sync_cancel(struct io_uring *ring, int async, int nr_all,
83 			    int use_fd)
84 {
85 	struct io_uring_sync_cancel_reg reg = { };
86 	struct io_uring_sqe *sqe;
87 	struct io_uring_cqe *cqe;
88 	int ret, fds[2], to_prep, i;
89 	char buf[32];
90 
91 	if (pipe(fds) < 0) {
92 		perror("pipe");
93 		return 1;
94 	}
95 
96 	to_prep = 1;
97 	if (nr_all)
98 		to_prep = 4;
99 	for (i = 0; i < to_prep; i++) {
100 		sqe = io_uring_get_sqe(ring);
101 		io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
102 		sqe->user_data = 0x89;
103 		if (async)
104 			sqe->flags |= IOSQE_ASYNC;
105 	}
106 
107 	ret = io_uring_submit(ring);
108 	if (ret != to_prep) {
109 		fprintf(stderr, "submit=%d\n", ret);
110 		return 1;
111 	}
112 
113 	usleep(10000);
114 
115 	if (!use_fd)
116 		reg.addr = 0x89;
117 	else
118 		reg.fd = fds[0];
119 	reg.timeout.tv_sec = 200;
120 	if (nr_all)
121 		reg.flags |= IORING_ASYNC_CANCEL_ALL;
122 	if (use_fd)
123 		reg.flags |= IORING_ASYNC_CANCEL_FD;
124 	ret = io_uring_register_sync_cancel(ring, &reg);
125 	if (ret < 0) {
126 		if (ret == -EINVAL && !no_sync_cancel) {
127 			no_sync_cancel = 1;
128 			return 0;
129 		}
130 		fprintf(stderr, "sync_cancel=%d\n", ret);
131 		return 1;
132 	}
133 
134 	for (i = 0; i < to_prep; i++) {
135 		/*
136 		 * we could _almost_ use peek_cqe() here, but there is still
137 		 * a small gap where io-wq is done with the request and on
138 		 * its way to posting a completion, but hasn't done it just
139 		 * yet. the request is canceled and won't be doing any IO
140 		 * to buffers etc, but the cqe may not have quite arrived yet.
141 		 */
142 		ret = io_uring_wait_cqe(ring, &cqe);
143 		if (ret) {
144 			fprintf(stderr, "peek=%d\n", ret);
145 			return 1;
146 		}
147 		if (cqe->res >= 0) {
148 			fprintf(stderr, "cqe->res=%d\n", cqe->res);
149 			return 1;
150 		}
151 		io_uring_cqe_seen(ring, cqe);
152 	}
153 
154 	return 0;
155 }
156 
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159 	struct io_uring ring;
160 	int ret;
161 
162 	if (argc > 1)
163 		return T_EXIT_SKIP;
164 
165 	ret = t_create_ring(7, &ring, 0);
166 	if (ret == T_SETUP_SKIP)
167 		return T_EXIT_SKIP;
168 	else if (ret != T_SETUP_OK)
169 		return ret;
170 
171 	ret = test_sync_cancel(&ring, 0, 0, 0);
172 	if (ret) {
173 		fprintf(stderr, "test_sync_cancel 0 0 0 failed\n");
174 		return T_EXIT_FAIL;
175 	}
176 	if (no_sync_cancel)
177 		return T_EXIT_SKIP;
178 
179 	ret = test_sync_cancel(&ring, 1, 0, 0);
180 	if (ret) {
181 		fprintf(stderr, "test_sync_cancel 1 0 0 failed\n");
182 		return T_EXIT_FAIL;
183 	}
184 
185 	ret = test_sync_cancel(&ring, 0, 1, 0);
186 	if (ret) {
187 		fprintf(stderr, "test_sync_cancel 0 1 0 failed\n");
188 		return T_EXIT_FAIL;
189 	}
190 
191 	ret = test_sync_cancel(&ring, 1, 1, 0);
192 	if (ret) {
193 		fprintf(stderr, "test_sync_cancel 1 1 0 failed\n");
194 		return T_EXIT_FAIL;
195 	}
196 
197 	ret = test_sync_cancel(&ring, 0, 0, 1);
198 	if (ret) {
199 		fprintf(stderr, "test_sync_cancel 0 0 1 failed\n");
200 		return T_EXIT_FAIL;
201 	}
202 
203 	ret = test_sync_cancel(&ring, 1, 0, 1);
204 	if (ret) {
205 		fprintf(stderr, "test_sync_cancel 1 0 1 failed\n");
206 		return T_EXIT_FAIL;
207 	}
208 
209 	ret = test_sync_cancel(&ring, 0, 1, 1);
210 	if (ret) {
211 		fprintf(stderr, "test_sync_cancel 0 1 1 failed\n");
212 		return T_EXIT_FAIL;
213 	}
214 
215 	ret = test_sync_cancel(&ring, 1, 1, 1);
216 	if (ret) {
217 		fprintf(stderr, "test_sync_cancel 1 1 1 failed\n");
218 		return T_EXIT_FAIL;
219 	}
220 
221 	ret = test_sync_cancel_timeout(&ring, 0);
222 	if (ret) {
223 		fprintf(stderr, "test_sync_cancel_timeout 0\n");
224 		return T_EXIT_FAIL;
225 	}
226 
227 	/* must be last, leaves request */
228 	ret = test_sync_cancel_timeout(&ring, 1);
229 	if (ret) {
230 		fprintf(stderr, "test_sync_cancel_timeout 1\n");
231 		return T_EXIT_FAIL;
232 	}
233 
234 	return T_EXIT_PASS;
235 }
236