• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: Test IORING_ASYNC_CANCEL_{ALL,FD}
4  *
5  */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <poll.h>
12 
13 #include "liburing.h"
14 
15 static int no_cancel_flags;
16 
test1(struct io_uring * ring,int * fd,int fixed)17 static int test1(struct io_uring *ring, int *fd, int fixed)
18 {
19 	struct io_uring_sqe *sqe;
20 	struct io_uring_cqe *cqe;
21 	int ret, i, __fd = fd[0];
22 
23 	if (fixed)
24 		__fd = 0;
25 
26 	if (fixed) {
27 		ret = io_uring_register_files(ring, fd, 1);
28 		if (ret) {
29 			fprintf(stderr, "failed file register %d\n", ret);
30 			return 1;
31 		}
32 	}
33 
34 	for (i = 0; i < 8; i++) {
35 		sqe = io_uring_get_sqe(ring);
36 		if (!sqe) {
37 			fprintf(stderr, "get sqe failed\n");
38 			return 1;
39 		}
40 
41 		io_uring_prep_poll_add(sqe, __fd, POLLIN);
42 		sqe->user_data = i + 1;
43 		if (fixed)
44 			sqe->flags |= IOSQE_FIXED_FILE;
45 	}
46 
47 	ret = io_uring_submit(ring);
48 	if (ret < 8) {
49 		fprintf(stderr, "sqe submit failed: %d\n", ret);
50 		return 1;
51 	}
52 
53 	sqe = io_uring_get_sqe(ring);
54 	if (!sqe) {
55 		fprintf(stderr, "get sqe failed\n");
56 		return 1;
57 	}
58 
59 	/*
60 	 * Mark CANCEL_ALL to cancel all matching the key, and use
61 	 * CANCEL_FD to cancel requests matching the specified fd.
62 	 * This should cancel all the pending poll requests on the pipe
63 	 * input.
64 	 */
65 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
66 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
67 	if (fixed)
68 		sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD_FIXED;
69 	sqe->fd = __fd;
70 	sqe->user_data = 100;
71 
72 	ret = io_uring_submit(ring);
73 	if (ret < 1) {
74 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
75 		return 1;
76 	}
77 
78 	for (i = 0; i < 9; i++) {
79 		if (no_cancel_flags)
80 			break;
81 		ret = io_uring_wait_cqe(ring, &cqe);
82 		if (ret) {
83 			fprintf(stderr, "wait=%d\n", ret);
84 			return 1;
85 		}
86 		switch (cqe->user_data) {
87 		case 100:
88 			if (cqe->res == -EINVAL) {
89 				no_cancel_flags = 1;
90 				break;
91 			}
92 			if (cqe->res != 8) {
93 				fprintf(stderr, "canceled %d\n", cqe->res);
94 				return 1;
95 			}
96 			break;
97 		case 1 ... 8:
98 			if (cqe->res != -ECANCELED) {
99 				fprintf(stderr, "poll res %d\n", cqe->res);
100 				return 1;
101 			}
102 			break;
103 		default:
104 			fprintf(stderr, "invalid user_data %lu\n",
105 					(unsigned long) cqe->user_data);
106 			return 1;
107 		}
108 		io_uring_cqe_seen(ring, cqe);
109 	}
110 
111 	if (fixed)
112 		io_uring_unregister_files(ring);
113 
114 	return 0;
115 }
116 
test2(struct io_uring * ring,int * fd)117 static int test2(struct io_uring *ring, int *fd)
118 {
119 	struct io_uring_sqe *sqe;
120 	struct io_uring_cqe *cqe;
121 	int ret, i, fd2[2];
122 
123 	if (pipe(fd2) < 0) {
124 		perror("pipe");
125 		return 1;
126 	}
127 
128 	for (i = 0; i < 8; i++) {
129 		sqe = io_uring_get_sqe(ring);
130 		if (!sqe) {
131 			fprintf(stderr, "get sqe failed\n");
132 			goto err;
133 		}
134 
135 		if (!(i & 1))
136 			io_uring_prep_poll_add(sqe, fd[0], POLLIN);
137 		else
138 			io_uring_prep_poll_add(sqe, fd2[0], POLLIN);
139 		sqe->user_data = i & 1;
140 	}
141 
142 	ret = io_uring_submit(ring);
143 	if (ret < 8) {
144 		fprintf(stderr, "sqe submit failed: %d\n", ret);
145 		goto err;
146 	}
147 
148 	sqe = io_uring_get_sqe(ring);
149 	if (!sqe) {
150 		fprintf(stderr, "get sqe failed\n");
151 		goto err;
152 	}
153 
154 	/*
155 	 * Mark CANCEL_ALL to cancel all matching the key, and use
156 	 * CANCEL_FD to cancel requests matching the specified fd.
157 	 * This should cancel all the pending poll requests on the pipe
158 	 * input.
159 	 */
160 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
161 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
162 	sqe->fd = fd[0];
163 	sqe->user_data = 100;
164 
165 	ret = io_uring_submit(ring);
166 	if (ret < 1) {
167 		fprintf(stderr, "sqe submit failed: %d\n", ret);
168 		goto err;
169 	}
170 
171 	for (i = 0; i < 5; i++) {
172 		ret = io_uring_wait_cqe(ring, &cqe);
173 		if (ret) {
174 			fprintf(stderr, "wait=%d\n", ret);
175 			goto err;
176 		}
177 		switch (cqe->user_data) {
178 		case 100:
179 			if (cqe->res != 4) {
180 				fprintf(stderr, "canceled %d\n", cqe->res);
181 				goto err;
182 			}
183 			break;
184 		case 0:
185 			if (cqe->res != -ECANCELED) {
186 				fprintf(stderr, "poll res %d\n", cqe->res);
187 				goto err;
188 			}
189 			break;
190 		default:
191 			fprintf(stderr, "invalid user_data %lu\n",
192 					(unsigned long) cqe->user_data);
193 			goto err;
194 		}
195 		io_uring_cqe_seen(ring, cqe);
196 	}
197 
198 	usleep(1000);
199 
200 	/*
201 	 * Should not have any pending CQEs now
202 	 */
203 	ret = io_uring_peek_cqe(ring, &cqe);
204 	if (!ret) {
205 		fprintf(stderr, "Unexpected extra cancel cqe\n");
206 		goto err;
207 	}
208 
209 	sqe = io_uring_get_sqe(ring);
210 	if (!sqe) {
211 		fprintf(stderr, "get sqe failed\n");
212 		goto err;
213 	}
214 
215 	/*
216 	 * Mark CANCEL_ALL to cancel all matching the key, and use
217 	 * CANCEL_FD to cancel requests matching the specified fd.
218 	 * This should cancel all the pending poll requests on the pipe
219 	 * input.
220 	 */
221 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
222 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
223 	sqe->fd = fd2[0];
224 	sqe->user_data = 100;
225 
226 	ret = io_uring_submit(ring);
227 	if (ret < 1) {
228 		fprintf(stderr, "sqe submit failed: %d\n", ret);
229 		goto err;
230 	}
231 
232 	for (i = 0; i < 5; i++) {
233 		ret = io_uring_wait_cqe(ring, &cqe);
234 		if (ret) {
235 			fprintf(stderr, "wait=%d\n", ret);
236 			goto err;
237 		}
238 		switch (cqe->user_data) {
239 		case 100:
240 			if (cqe->res != 4) {
241 				fprintf(stderr, "canceled %d\n", cqe->res);
242 				goto err;
243 			}
244 			break;
245 		case 1:
246 			if (cqe->res != -ECANCELED) {
247 				fprintf(stderr, "poll res %d\n", cqe->res);
248 				goto err;
249 			}
250 			break;
251 		default:
252 			fprintf(stderr, "invalid user_data %lu\n",
253 					(unsigned long) cqe->user_data);
254 			goto err;
255 		}
256 		io_uring_cqe_seen(ring, cqe);
257 	}
258 
259 	close(fd2[0]);
260 	close(fd2[1]);
261 	return 0;
262 err:
263 	close(fd2[0]);
264 	close(fd2[1]);
265 	return 1;
266 }
267 
test3(struct io_uring * ring,int * fd)268 static int test3(struct io_uring *ring, int *fd)
269 {
270 	struct io_uring_sqe *sqe;
271 	struct io_uring_cqe *cqe;
272 	int ret, i, fd2[2];
273 
274 	if (pipe(fd2) < 0) {
275 		perror("pipe");
276 		return 1;
277 	}
278 
279 	for (i = 0; i < 8; i++) {
280 		sqe = io_uring_get_sqe(ring);
281 		if (!sqe) {
282 			fprintf(stderr, "get sqe failed\n");
283 			goto err;
284 		}
285 
286 		if (!(i & 1)) {
287 			io_uring_prep_poll_add(sqe, fd[0], POLLIN);
288 			sqe->flags |= IOSQE_ASYNC;
289 		} else
290 			io_uring_prep_poll_add(sqe, fd2[0], POLLIN);
291 		sqe->user_data = i & 1;
292 	}
293 
294 	ret = io_uring_submit(ring);
295 	if (ret < 8) {
296 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
297 		goto err;
298 	}
299 
300 	usleep(10000);
301 
302 	sqe = io_uring_get_sqe(ring);
303 	if (!sqe) {
304 		fprintf(stderr, "get sqe failed\n");
305 		goto err;
306 	}
307 
308 	/*
309 	 * Mark CANCEL_ALL to cancel all matching the key, and use
310 	 * CANCEL_FD to cancel requests matching the specified fd.
311 	 * This should cancel all the pending poll requests on the pipe
312 	 * input.
313 	 */
314 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
315 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_ANY;
316 	sqe->fd = 0;
317 	sqe->user_data = 100;
318 
319 	ret = io_uring_submit(ring);
320 	if (ret < 1) {
321 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
322 		goto err;
323 	}
324 
325 	for (i = 0; i < 9; i++) {
326 		ret = io_uring_wait_cqe(ring, &cqe);
327 		if (ret) {
328 			fprintf(stderr, "wait=%d\n", ret);
329 			goto err;
330 		}
331 		switch (cqe->user_data) {
332 		case 100:
333 			if (cqe->res != 8) {
334 				fprintf(stderr, "canceled %d\n", cqe->res);
335 				goto err;
336 			}
337 			break;
338 		case 0:
339 		case 1:
340 			if (cqe->res != -ECANCELED) {
341 				fprintf(stderr, "poll res %d\n", cqe->res);
342 				goto err;
343 			}
344 			break;
345 		default:
346 			fprintf(stderr, "invalid user_data %lu\n",
347 					(unsigned long) cqe->user_data);
348 			goto err;
349 		}
350 		io_uring_cqe_seen(ring, cqe);
351 	}
352 
353 	close(fd2[0]);
354 	close(fd2[1]);
355 	return 0;
356 err:
357 	close(fd2[0]);
358 	close(fd2[1]);
359 	return 1;
360 }
361 
test4(struct io_uring * ring,int * fd)362 static int test4(struct io_uring *ring, int *fd)
363 {
364 	struct io_uring_sqe *sqe;
365 	struct io_uring_cqe *cqe;
366 	char buffer[32];
367 	int ret, i;
368 
369 	for (i = 0; i < 8; i++) {
370 		sqe = io_uring_get_sqe(ring);
371 		if (!sqe) {
372 			fprintf(stderr, "get sqe failed\n");
373 			goto err;
374 		}
375 
376 		io_uring_prep_read(sqe, fd[0], &buffer, sizeof(buffer), 0);
377 		sqe->flags |= IOSQE_ASYNC;
378 		sqe->user_data = i + 1;
379 	}
380 
381 	ret = io_uring_submit(ring);
382 	if (ret < 8) {
383 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
384 		goto err;
385 	}
386 
387 	usleep(10000);
388 
389 	sqe = io_uring_get_sqe(ring);
390 	if (!sqe) {
391 		fprintf(stderr, "get sqe failed\n");
392 		goto err;
393 	}
394 
395 	/*
396 	 * Mark CANCEL_ALL to cancel all matching the key, and use
397 	 * CANCEL_FD to cancel requests matching the specified fd.
398 	 * This should cancel all the pending poll requests on the pipe
399 	 * input.
400 	 */
401 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
402 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_ANY;
403 	sqe->fd = 0;
404 	sqe->user_data = 100;
405 
406 	ret = io_uring_submit(ring);
407 	if (ret < 1) {
408 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
409 		goto err;
410 	}
411 
412 	for (i = 0; i < 9; i++) {
413 		ret = io_uring_wait_cqe(ring, &cqe);
414 		if (ret) {
415 			fprintf(stderr, "wait=%d\n", ret);
416 			goto err;
417 		}
418 		switch (cqe->user_data) {
419 		case 100:
420 			if (cqe->res != 8) {
421 				fprintf(stderr, "canceled %d\n", cqe->res);
422 				goto err;
423 			}
424 			break;
425 		case 1 ... 8:
426 			if (cqe->res != -ECANCELED) {
427 				fprintf(stderr, "poll res %d\n", cqe->res);
428 				goto err;
429 			}
430 			break;
431 		default:
432 			fprintf(stderr, "invalid user_data %lu\n",
433 					(unsigned long) cqe->user_data);
434 			goto err;
435 		}
436 		io_uring_cqe_seen(ring, cqe);
437 	}
438 
439 	return 0;
440 err:
441 	return 1;
442 }
443 
main(int argc,char * argv[])444 int main(int argc, char *argv[])
445 {
446 	struct io_uring ring;
447 	int ret, fd[2];
448 
449 	if (argc > 1)
450 		return 0;
451 
452 	if (pipe(fd) < 0) {
453 		perror("pipe");
454 		return 1;
455 	}
456 
457 	ret = io_uring_queue_init(8, &ring, 0);
458 	if (ret) {
459 		fprintf(stderr, "ring setup failed: %d\n", ret);
460 		return 1;
461 	}
462 
463 	ret = test1(&ring, fd, 0);
464 	if (ret) {
465 		fprintf(stderr, "test1 failed\n");
466 		return ret;
467 	}
468 	if (no_cancel_flags)
469 		return 0;
470 
471 	ret = test1(&ring, fd, 1);
472 	if (ret) {
473 		fprintf(stderr, "test1 fixed failed\n");
474 		return ret;
475 	}
476 
477 	ret = test2(&ring, fd);
478 	if (ret) {
479 		fprintf(stderr, "test2 failed\n");
480 		return ret;
481 	}
482 
483 	ret = test3(&ring, fd);
484 	if (ret) {
485 		fprintf(stderr, "test3 failed\n");
486 		return ret;
487 	}
488 
489 	ret = test4(&ring, fd);
490 	if (ret) {
491 		fprintf(stderr, "test4 failed\n");
492 		return ret;
493 	}
494 
495 	return 0;
496 }
497