xref: /aosp_15_r20/external/liburing/test/link-timeout.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: run various linked timeout cases
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 #include <poll.h>
13 
14 #include "liburing.h"
15 
test_fail_lone_link_timeouts(struct io_uring * ring)16 static int test_fail_lone_link_timeouts(struct io_uring *ring)
17 {
18 	struct __kernel_timespec ts;
19 	struct io_uring_cqe *cqe;
20 	struct io_uring_sqe *sqe;
21 	int ret;
22 
23 	sqe = io_uring_get_sqe(ring);
24 	if (!sqe) {
25 		printf("get sqe failed\n");
26 		goto err;
27 	}
28 	io_uring_prep_link_timeout(sqe, &ts, 0);
29 	ts.tv_sec = 1;
30 	ts.tv_nsec = 0;
31 	sqe->user_data = 1;
32 	sqe->flags |= IOSQE_IO_LINK;
33 
34 	ret = io_uring_submit(ring);
35 	if (ret != 1) {
36 		printf("sqe submit failed: %d\n", ret);
37 		goto err;
38 	}
39 
40 	ret = io_uring_wait_cqe(ring, &cqe);
41 	if (ret < 0) {
42 		printf("wait completion %d\n", ret);
43 		goto err;
44 	}
45 
46 	if (cqe->user_data != 1) {
47 		fprintf(stderr, "invalid user data %d\n", cqe->res);
48 		goto err;
49 	}
50 	if (cqe->res != -EINVAL) {
51 		fprintf(stderr, "got %d, wanted -EINVAL\n", cqe->res);
52 		goto err;
53 	}
54 	io_uring_cqe_seen(ring, cqe);
55 
56 	return 0;
57 err:
58 	return 1;
59 }
60 
test_fail_two_link_timeouts(struct io_uring * ring)61 static int test_fail_two_link_timeouts(struct io_uring *ring)
62 {
63 	struct __kernel_timespec ts;
64 	struct io_uring_cqe *cqe;
65 	struct io_uring_sqe *sqe;
66 	int ret, i, nr_wait;
67 
68 	ts.tv_sec = 1;
69 	ts.tv_nsec = 0;
70 
71 	/*
72 	 * sqe_1: write destined to fail
73 	 * use buf=NULL, to do that during the issuing stage
74 	 */
75 	sqe = io_uring_get_sqe(ring);
76 	if (!sqe) {
77 		printf("get sqe failed\n");
78 		goto err;
79 	}
80 	io_uring_prep_writev(sqe, 0, NULL, 1, 0);
81 	sqe->flags |= IOSQE_IO_LINK;
82 	sqe->user_data = 1;
83 
84 
85 	/* sqe_2: valid linked timeout */
86 	sqe = io_uring_get_sqe(ring);
87 	if (!sqe) {
88 		printf("get sqe failed\n");
89 		goto err;
90 	}
91 	io_uring_prep_link_timeout(sqe, &ts, 0);
92 	sqe->user_data = 2;
93 	sqe->flags |= IOSQE_IO_LINK;
94 
95 
96 	/* sqe_3: invalid linked timeout */
97 	sqe = io_uring_get_sqe(ring);
98 	if (!sqe) {
99 		printf("get sqe failed\n");
100 		goto err;
101 	}
102 	io_uring_prep_link_timeout(sqe, &ts, 0);
103 	sqe->flags |= IOSQE_IO_LINK;
104 	sqe->user_data = 3;
105 
106 	/* sqe_4: invalid linked timeout */
107 	sqe = io_uring_get_sqe(ring);
108 	if (!sqe) {
109 		printf("get sqe failed\n");
110 		goto err;
111 	}
112 	io_uring_prep_link_timeout(sqe, &ts, 0);
113 	sqe->flags |= IOSQE_IO_LINK;
114 	sqe->user_data = 4;
115 
116 	ret = io_uring_submit(ring);
117 	if (ret < 3) {
118 		printf("sqe submit failed: %d\n", ret);
119 		goto err;
120 	}
121 	nr_wait = ret;
122 
123 	for (i = 0; i < nr_wait; i++) {
124 		ret = io_uring_wait_cqe(ring, &cqe);
125 		if (ret < 0) {
126 			printf("wait completion %d\n", ret);
127 			goto err;
128 		}
129 
130 		switch (cqe->user_data) {
131 		case 1:
132 			if (cqe->res != -EFAULT && cqe->res != -ECANCELED) {
133 				fprintf(stderr, "write got %d, wanted -EFAULT "
134 						"or -ECANCELED\n", cqe->res);
135 				goto err;
136 			}
137 			break;
138 		case 2:
139 			if (cqe->res != -ECANCELED) {
140 				fprintf(stderr, "Link timeout got %d, wanted -ECACNCELED\n", cqe->res);
141 				goto err;
142 			}
143 			break;
144 		case 3:
145 			/* fall through */
146 		case 4:
147 			if (cqe->res != -ECANCELED && cqe->res != -EINVAL) {
148 				fprintf(stderr, "Invalid link timeout got %d"
149 					", wanted -ECACNCELED || -EINVAL\n", cqe->res);
150 				goto err;
151 			}
152 			break;
153 		}
154 		io_uring_cqe_seen(ring, cqe);
155 	}
156 
157 	return 0;
158 err:
159 	return 1;
160 }
161 
162 /*
163  * Test linked timeout with timeout (timeoutception)
164  */
test_single_link_timeout_ception(struct io_uring * ring)165 static int test_single_link_timeout_ception(struct io_uring *ring)
166 {
167 	struct __kernel_timespec ts1, ts2;
168 	struct io_uring_cqe *cqe;
169 	struct io_uring_sqe *sqe;
170 	int ret, i;
171 
172 	sqe = io_uring_get_sqe(ring);
173 	if (!sqe) {
174 		printf("get sqe failed\n");
175 		goto err;
176 	}
177 
178 	ts1.tv_sec = 1;
179 	ts1.tv_nsec = 0;
180 	io_uring_prep_timeout(sqe, &ts1, -1U, 0);
181 	sqe->flags |= IOSQE_IO_LINK;
182 	sqe->user_data = 1;
183 
184 	sqe = io_uring_get_sqe(ring);
185 	if (!sqe) {
186 		printf("get sqe failed\n");
187 		goto err;
188 	}
189 
190 	ts2.tv_sec = 2;
191 	ts2.tv_nsec = 0;
192 	io_uring_prep_link_timeout(sqe, &ts2, 0);
193 	sqe->user_data = 2;
194 
195 	ret = io_uring_submit(ring);
196 	if (ret != 2) {
197 		printf("sqe submit failed: %d\n", ret);
198 		goto err;
199 	}
200 
201 	for (i = 0; i < 2; i++) {
202 		ret = io_uring_wait_cqe(ring, &cqe);
203 		if (ret < 0) {
204 			printf("wait completion %d\n", ret);
205 			goto err;
206 		}
207 		switch (cqe->user_data) {
208 		case 1:
209 			/* newer kernels allow timeout links */
210 			if (cqe->res != -EINVAL && cqe->res != -ETIME) {
211 				fprintf(stderr, "Timeout got %d, wanted "
212 					"-EINVAL or -ETIME\n", cqe->res);
213 				goto err;
214 			}
215 			break;
216 		case 2:
217 			if (cqe->res != -ECANCELED) {
218 				fprintf(stderr, "Link timeout got %d, wanted -ECANCELED\n", cqe->res);
219 				goto err;
220 			}
221 			break;
222 		}
223 		io_uring_cqe_seen(ring, cqe);
224 	}
225 
226 	return 0;
227 err:
228 	return 1;
229 }
230 
231 /*
232  * Test linked timeout with NOP
233  */
test_single_link_timeout_nop(struct io_uring * ring)234 static int test_single_link_timeout_nop(struct io_uring *ring)
235 {
236 	struct __kernel_timespec ts;
237 	struct io_uring_cqe *cqe;
238 	struct io_uring_sqe *sqe;
239 	int ret, i;
240 
241 	sqe = io_uring_get_sqe(ring);
242 	if (!sqe) {
243 		printf("get sqe failed\n");
244 		goto err;
245 	}
246 
247 	io_uring_prep_nop(sqe);
248 	sqe->flags |= IOSQE_IO_LINK;
249 	sqe->user_data = 1;
250 
251 	sqe = io_uring_get_sqe(ring);
252 	if (!sqe) {
253 		printf("get sqe failed\n");
254 		goto err;
255 	}
256 
257 	ts.tv_sec = 1;
258 	ts.tv_nsec = 0;
259 	io_uring_prep_link_timeout(sqe, &ts, 0);
260 	sqe->user_data = 2;
261 
262 	ret = io_uring_submit(ring);
263 	if (ret != 2) {
264 		printf("sqe submit failed: %d\n", ret);
265 		goto err;
266 	}
267 
268 	for (i = 0; i < 2; i++) {
269 		ret = io_uring_wait_cqe(ring, &cqe);
270 		if (ret < 0) {
271 			printf("wait completion %d\n", ret);
272 			goto err;
273 		}
274 		switch (cqe->user_data) {
275 		case 1:
276 			if (cqe->res) {
277 				fprintf(stderr, "NOP got %d, wanted 0\n", cqe->res);
278 				goto err;
279 			}
280 			break;
281 		case 2:
282 			if (cqe->res != -ECANCELED) {
283 				fprintf(stderr, "Link timeout got %d, wanted -ECACNCELED\n", cqe->res);
284 				goto err;
285 			}
286 			break;
287 		}
288 		io_uring_cqe_seen(ring, cqe);
289 	}
290 
291 	return 0;
292 err:
293 	return 1;
294 }
295 
296 /*
297  * Test read that will not complete, with a linked timeout behind it that
298  * has errors in the SQE
299  */
test_single_link_timeout_error(struct io_uring * ring)300 static int test_single_link_timeout_error(struct io_uring *ring)
301 {
302 	struct __kernel_timespec ts;
303 	struct io_uring_cqe *cqe;
304 	struct io_uring_sqe *sqe;
305 	int fds[2], ret, i;
306 	struct iovec iov;
307 	char buffer[128];
308 
309 	if (pipe(fds)) {
310 		perror("pipe");
311 		return 1;
312 	}
313 
314 	sqe = io_uring_get_sqe(ring);
315 	if (!sqe) {
316 		printf("get sqe failed\n");
317 		goto err;
318 	}
319 
320 	iov.iov_base = buffer;
321 	iov.iov_len = sizeof(buffer);
322 	io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
323 	sqe->flags |= IOSQE_IO_LINK;
324 	sqe->user_data = 1;
325 
326 	sqe = io_uring_get_sqe(ring);
327 	if (!sqe) {
328 		printf("get sqe failed\n");
329 		goto err;
330 	}
331 
332 	ts.tv_sec = 1;
333 	ts.tv_nsec = 0;
334 	io_uring_prep_link_timeout(sqe, &ts, 0);
335 	/* set invalid field, it'll get failed */
336 	sqe->ioprio = 89;
337 	sqe->user_data = 2;
338 
339 	ret = io_uring_submit(ring);
340 	if (ret != 2) {
341 		printf("sqe submit failed: %d\n", ret);
342 		goto err;
343 	}
344 
345 	for (i = 0; i < 2; i++) {
346 		ret = io_uring_wait_cqe(ring, &cqe);
347 		if (ret < 0) {
348 			printf("wait completion %d\n", ret);
349 			goto err;
350 		}
351 		switch (cqe->user_data) {
352 		case 1:
353 			if (cqe->res != -ECANCELED) {
354 				fprintf(stderr, "Read got %d, wanted -ECANCELED\n",
355 						cqe->res);
356 				goto err;
357 			}
358 			break;
359 		case 2:
360 			if (cqe->res != -EINVAL) {
361 				fprintf(stderr, "Link timeout got %d, wanted -EINVAL\n", cqe->res);
362 				goto err;
363 			}
364 			break;
365 		}
366 		io_uring_cqe_seen(ring, cqe);
367 	}
368 
369 	return 0;
370 err:
371 	return 1;
372 }
373 
374 /*
375  * Test read that will complete, with a linked timeout behind it
376  */
test_single_link_no_timeout(struct io_uring * ring)377 static int test_single_link_no_timeout(struct io_uring *ring)
378 {
379 	struct __kernel_timespec ts;
380 	struct io_uring_cqe *cqe;
381 	struct io_uring_sqe *sqe;
382 	int fds[2], ret, i;
383 	struct iovec iov;
384 	char buffer[128];
385 
386 	if (pipe(fds)) {
387 		perror("pipe");
388 		return 1;
389 	}
390 
391 	sqe = io_uring_get_sqe(ring);
392 	if (!sqe) {
393 		printf("get sqe failed\n");
394 		goto err;
395 	}
396 
397 	iov.iov_base = buffer;
398 	iov.iov_len = sizeof(buffer);
399 	io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
400 	sqe->flags |= IOSQE_IO_LINK;
401 	sqe->user_data = 1;
402 
403 	sqe = io_uring_get_sqe(ring);
404 	if (!sqe) {
405 		printf("get sqe failed\n");
406 		goto err;
407 	}
408 
409 	ts.tv_sec = 1;
410 	ts.tv_nsec = 0;
411 	io_uring_prep_link_timeout(sqe, &ts, 0);
412 	sqe->user_data = 2;
413 
414 	sqe = io_uring_get_sqe(ring);
415 	if (!sqe) {
416 		printf("get sqe failed\n");
417 		goto err;
418 	}
419 
420 	iov.iov_base = buffer;
421 	iov.iov_len = sizeof(buffer);
422 	io_uring_prep_writev(sqe, fds[1], &iov, 1, 0);
423 	sqe->user_data = 3;
424 
425 	ret = io_uring_submit(ring);
426 	if (ret != 3) {
427 		printf("sqe submit failed: %d\n", ret);
428 		goto err;
429 	}
430 
431 	for (i = 0; i < 3; i++) {
432 		ret = io_uring_wait_cqe(ring, &cqe);
433 		if (ret < 0) {
434 			printf("wait completion %d\n", ret);
435 			goto err;
436 		}
437 		switch (cqe->user_data) {
438 		case 1:
439 		case 3:
440 			if (cqe->res != sizeof(buffer)) {
441 				fprintf(stderr, "R/W got %d, wanted %d\n", cqe->res,
442 						(int) sizeof(buffer));
443 				goto err;
444 			}
445 			break;
446 		case 2:
447 			if (cqe->res != -ECANCELED) {
448 				fprintf(stderr, "Link timeout %d, wanted -ECANCELED\n",
449 						cqe->res);
450 				goto err;
451 			}
452 			break;
453 		}
454 		io_uring_cqe_seen(ring, cqe);
455 	}
456 
457 	return 0;
458 err:
459 	return 1;
460 }
461 
462 /*
463  * Test read that will not complete, with a linked timeout behind it
464  */
test_single_link_timeout(struct io_uring * ring,unsigned nsec)465 static int test_single_link_timeout(struct io_uring *ring, unsigned nsec)
466 {
467 	struct __kernel_timespec ts;
468 	struct io_uring_cqe *cqe;
469 	struct io_uring_sqe *sqe;
470 	int fds[2], ret, i;
471 	struct iovec iov;
472 	char buffer[128];
473 
474 	if (pipe(fds)) {
475 		perror("pipe");
476 		return 1;
477 	}
478 
479 	sqe = io_uring_get_sqe(ring);
480 	if (!sqe) {
481 		printf("get sqe failed\n");
482 		goto err;
483 	}
484 
485 	iov.iov_base = buffer;
486 	iov.iov_len = sizeof(buffer);
487 	io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
488 	sqe->flags |= IOSQE_IO_LINK;
489 	sqe->user_data = 1;
490 
491 	sqe = io_uring_get_sqe(ring);
492 	if (!sqe) {
493 		printf("get sqe failed\n");
494 		goto err;
495 	}
496 
497 	ts.tv_sec = 0;
498 	ts.tv_nsec = nsec;
499 	io_uring_prep_link_timeout(sqe, &ts, 0);
500 	sqe->user_data = 2;
501 
502 	ret = io_uring_submit(ring);
503 	if (ret != 2) {
504 		printf("sqe submit failed: %d\n", ret);
505 		goto err;
506 	}
507 
508 	for (i = 0; i < 2; i++) {
509 		ret = io_uring_wait_cqe(ring, &cqe);
510 		if (ret < 0) {
511 			printf("wait completion %d\n", ret);
512 			goto err;
513 		}
514 		switch (cqe->user_data) {
515 		case 1:
516 			if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
517 				fprintf(stderr, "Read got %d\n", cqe->res);
518 				goto err;
519 			}
520 			break;
521 		case 2:
522 			if (cqe->res != -EALREADY && cqe->res != -ETIME &&
523 			    cqe->res != 0) {
524 				fprintf(stderr, "Link timeout got %d\n", cqe->res);
525 				goto err;
526 			}
527 			break;
528 		}
529 		io_uring_cqe_seen(ring, cqe);
530 	}
531 
532 	close(fds[0]);
533 	close(fds[1]);
534 	return 0;
535 err:
536 	return 1;
537 }
538 
test_timeout_link_chain1(struct io_uring * ring)539 static int test_timeout_link_chain1(struct io_uring *ring)
540 {
541 	struct __kernel_timespec ts;
542 	struct io_uring_cqe *cqe;
543 	struct io_uring_sqe *sqe;
544 	int fds[2], ret, i;
545 	struct iovec iov;
546 	char buffer[128];
547 
548 	if (pipe(fds)) {
549 		perror("pipe");
550 		return 1;
551 	}
552 
553 	sqe = io_uring_get_sqe(ring);
554 	if (!sqe) {
555 		printf("get sqe failed\n");
556 		goto err;
557 	}
558 	iov.iov_base = buffer;
559 	iov.iov_len = sizeof(buffer);
560 	io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
561 	sqe->flags |= IOSQE_IO_LINK;
562 	sqe->user_data = 1;
563 
564 	sqe = io_uring_get_sqe(ring);
565 	if (!sqe) {
566 		printf("get sqe failed\n");
567 		goto err;
568 	}
569 	ts.tv_sec = 0;
570 	ts.tv_nsec = 1000000;
571 	io_uring_prep_link_timeout(sqe, &ts, 0);
572 	sqe->flags |= IOSQE_IO_LINK;
573 	sqe->user_data = 2;
574 
575 	sqe = io_uring_get_sqe(ring);
576 	if (!sqe) {
577 		printf("get sqe failed\n");
578 		goto err;
579 	}
580 	io_uring_prep_nop(sqe);
581 	sqe->user_data = 3;
582 
583 	ret = io_uring_submit(ring);
584 	if (ret != 3) {
585 		printf("sqe submit failed: %d\n", ret);
586 		goto err;
587 	}
588 
589 	for (i = 0; i < 3; i++) {
590 		ret = io_uring_wait_cqe(ring, &cqe);
591 		if (ret < 0) {
592 			printf("wait completion %d\n", ret);
593 			goto err;
594 		}
595 		switch (cqe->user_data) {
596 		case 1:
597 			if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
598 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
599 						cqe->res);
600 				goto err;
601 			}
602 			break;
603 		case 2:
604 			/* FASTPOLL kernels can cancel successfully */
605 			if (cqe->res != -EALREADY && cqe->res != -ETIME) {
606 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
607 						cqe->res);
608 				goto err;
609 			}
610 			break;
611 		case 3:
612 			if (cqe->res != -ECANCELED) {
613 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
614 						cqe->res);
615 				goto err;
616 			}
617 			break;
618 		}
619 
620 		io_uring_cqe_seen(ring, cqe);
621 	}
622 
623 	close(fds[0]);
624 	close(fds[1]);
625 	return 0;
626 err:
627 	return 1;
628 }
629 
test_timeout_link_chain2(struct io_uring * ring)630 static int test_timeout_link_chain2(struct io_uring *ring)
631 {
632 	struct __kernel_timespec ts;
633 	struct io_uring_cqe *cqe;
634 	struct io_uring_sqe *sqe;
635 	int fds[2], ret, i;
636 
637 	if (pipe(fds)) {
638 		perror("pipe");
639 		return 1;
640 	}
641 
642 	sqe = io_uring_get_sqe(ring);
643 	if (!sqe) {
644 		printf("get sqe failed\n");
645 		goto err;
646 	}
647 	io_uring_prep_poll_add(sqe, fds[0], POLLIN);
648 	sqe->flags |= IOSQE_IO_LINK;
649 	sqe->user_data = 1;
650 
651 	sqe = io_uring_get_sqe(ring);
652 	if (!sqe) {
653 		printf("get sqe failed\n");
654 		goto err;
655 	}
656 	ts.tv_sec = 0;
657 	ts.tv_nsec = 1000000;
658 	io_uring_prep_link_timeout(sqe, &ts, 0);
659 	sqe->flags |= IOSQE_IO_LINK;
660 	sqe->user_data = 2;
661 
662 	sqe = io_uring_get_sqe(ring);
663 	if (!sqe) {
664 		printf("get sqe failed\n");
665 		goto err;
666 	}
667 	io_uring_prep_nop(sqe);
668 	sqe->flags |= IOSQE_IO_LINK;
669 	sqe->user_data = 3;
670 
671 	sqe = io_uring_get_sqe(ring);
672 	if (!sqe) {
673 		printf("get sqe failed\n");
674 		goto err;
675 	}
676 	io_uring_prep_nop(sqe);
677 	sqe->user_data = 4;
678 
679 	ret = io_uring_submit(ring);
680 	if (ret != 4) {
681 		printf("sqe submit failed: %d\n", ret);
682 		goto err;
683 	}
684 
685 	for (i = 0; i < 4; i++) {
686 		ret = io_uring_wait_cqe(ring, &cqe);
687 		if (ret < 0) {
688 			printf("wait completion %d\n", ret);
689 			goto err;
690 		}
691 		switch (cqe->user_data) {
692 		/* poll cancel really should return -ECANCEL... */
693 		case 1:
694 			if (cqe->res != -ECANCELED) {
695 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
696 						cqe->res);
697 				goto err;
698 			}
699 			break;
700 		case 2:
701 			if (cqe->res != -ETIME) {
702 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
703 						cqe->res);
704 				goto err;
705 			}
706 			break;
707 		case 3:
708 		case 4:
709 			if (cqe->res != -ECANCELED) {
710 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
711 						cqe->res);
712 				goto err;
713 			}
714 			break;
715 		}
716 		io_uring_cqe_seen(ring, cqe);
717 	}
718 
719 	close(fds[0]);
720 	close(fds[1]);
721 	return 0;
722 err:
723 	return 1;
724 }
725 
test_timeout_link_chain3(struct io_uring * ring)726 static int test_timeout_link_chain3(struct io_uring *ring)
727 {
728 	struct __kernel_timespec ts;
729 	struct io_uring_cqe *cqe;
730 	struct io_uring_sqe *sqe;
731 	int fds[2], ret, i;
732 
733 	if (pipe(fds)) {
734 		perror("pipe");
735 		return 1;
736 	}
737 
738 	sqe = io_uring_get_sqe(ring);
739 	if (!sqe) {
740 		printf("get sqe failed\n");
741 		goto err;
742 	}
743 	io_uring_prep_poll_add(sqe, fds[0], POLLIN);
744 	sqe->flags |= IOSQE_IO_LINK;
745 	sqe->user_data = 1;
746 
747 	sqe = io_uring_get_sqe(ring);
748 	if (!sqe) {
749 		printf("get sqe failed\n");
750 		goto err;
751 	}
752 	ts.tv_sec = 0;
753 	ts.tv_nsec = 1000000;
754 	io_uring_prep_link_timeout(sqe, &ts, 0);
755 	sqe->flags |= IOSQE_IO_LINK;
756 	sqe->user_data = 2;
757 
758 	sqe = io_uring_get_sqe(ring);
759 	if (!sqe) {
760 		printf("get sqe failed\n");
761 		goto err;
762 	}
763 	io_uring_prep_nop(sqe);
764 	sqe->flags |= IOSQE_IO_LINK;
765 	sqe->user_data = 3;
766 
767 	/* POLL -> TIMEOUT -> NOP */
768 
769 	sqe = io_uring_get_sqe(ring);
770 	if (!sqe) {
771 		printf("get sqe failed\n");
772 		goto err;
773 	}
774 	io_uring_prep_poll_add(sqe, fds[0], POLLIN);
775 	sqe->flags |= IOSQE_IO_LINK;
776 	sqe->user_data = 4;
777 
778 	sqe = io_uring_get_sqe(ring);
779 	if (!sqe) {
780 		printf("get sqe failed\n");
781 		goto err;
782 	}
783 	ts.tv_sec = 0;
784 	ts.tv_nsec = 1000000;
785 	io_uring_prep_link_timeout(sqe, &ts, 0);
786 	sqe->user_data = 5;
787 
788 	/* poll on pipe + timeout */
789 
790 	sqe = io_uring_get_sqe(ring);
791 	if (!sqe) {
792 		printf("get sqe failed\n");
793 		goto err;
794 	}
795 	io_uring_prep_nop(sqe);
796 	sqe->user_data = 6;
797 
798 	/* nop */
799 
800 	ret = io_uring_submit(ring);
801 	if (ret != 6) {
802 		printf("sqe submit failed: %d\n", ret);
803 		goto err;
804 	}
805 
806 	for (i = 0; i < 6; i++) {
807 		ret = io_uring_wait_cqe(ring, &cqe);
808 		if (ret < 0) {
809 			printf("wait completion %d\n", ret);
810 			goto err;
811 		}
812 		switch (cqe->user_data) {
813 		case 2:
814 			if (cqe->res != -ETIME) {
815 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
816 						cqe->res);
817 				goto err;
818 			}
819 			break;
820 		case 1:
821 		case 3:
822 		case 4:
823 		case 5:
824 			if (cqe->res != -ECANCELED) {
825 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
826 						cqe->res);
827 				goto err;
828 			}
829 			break;
830 		case 6:
831 			if (cqe->res) {
832 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
833 						cqe->res);
834 				goto err;
835 			}
836 			break;
837 		}
838 		io_uring_cqe_seen(ring, cqe);
839 	}
840 
841 	close(fds[0]);
842 	close(fds[1]);
843 	return 0;
844 err:
845 	return 1;
846 }
847 
test_timeout_link_chain4(struct io_uring * ring)848 static int test_timeout_link_chain4(struct io_uring *ring)
849 {
850 	struct __kernel_timespec ts;
851 	struct io_uring_cqe *cqe;
852 	struct io_uring_sqe *sqe;
853 	int fds[2], ret, i;
854 
855 	if (pipe(fds)) {
856 		perror("pipe");
857 		return 1;
858 	}
859 
860 	sqe = io_uring_get_sqe(ring);
861 	if (!sqe) {
862 		printf("get sqe failed\n");
863 		goto err;
864 	}
865 	io_uring_prep_nop(sqe);
866 	sqe->flags |= IOSQE_IO_LINK;
867 	sqe->user_data = 1;
868 
869 	sqe = io_uring_get_sqe(ring);
870 	if (!sqe) {
871 		printf("get sqe failed\n");
872 		goto err;
873 	}
874 	io_uring_prep_poll_add(sqe, fds[0], POLLIN);
875 	sqe->flags |= IOSQE_IO_LINK;
876 	sqe->user_data = 2;
877 
878 	sqe = io_uring_get_sqe(ring);
879 	if (!sqe) {
880 		printf("get sqe failed\n");
881 		goto err;
882 	}
883 	ts.tv_sec = 0;
884 	ts.tv_nsec = 1000000;
885 	io_uring_prep_link_timeout(sqe, &ts, 0);
886 	sqe->user_data = 3;
887 
888 	ret = io_uring_submit(ring);
889 	if (ret != 3) {
890 		printf("sqe submit failed: %d\n", ret);
891 		goto err;
892 	}
893 
894 	for (i = 0; i < 3; i++) {
895 		ret = io_uring_wait_cqe(ring, &cqe);
896 		if (ret < 0) {
897 			printf("wait completion %d\n", ret);
898 			goto err;
899 		}
900 		switch (cqe->user_data) {
901 		/* poll cancel really should return -ECANCEL... */
902 		case 1:
903 			if (cqe->res) {
904 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
905 						cqe->res);
906 				goto err;
907 			}
908 			break;
909 		case 2:
910 			if (cqe->res != -ECANCELED) {
911 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
912 						cqe->res);
913 				goto err;
914 			}
915 			break;
916 		case 3:
917 			if (cqe->res != -ETIME) {
918 				fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data,
919 						cqe->res);
920 				goto err;
921 			}
922 			break;
923 		}
924 		io_uring_cqe_seen(ring, cqe);
925 	}
926 
927 	close(fds[0]);
928 	close(fds[1]);
929 	return 0;
930 err:
931 	return 1;
932 }
933 
test_timeout_link_chain5(struct io_uring * ring)934 static int test_timeout_link_chain5(struct io_uring *ring)
935 {
936 	struct __kernel_timespec ts1, ts2;
937 	struct io_uring_cqe *cqe;
938 	struct io_uring_sqe *sqe;
939 	int ret, i;
940 
941 	sqe = io_uring_get_sqe(ring);
942 	if (!sqe) {
943 		printf("get sqe failed\n");
944 		goto err;
945 	}
946 	io_uring_prep_nop(sqe);
947 	sqe->flags |= IOSQE_IO_LINK;
948 	sqe->user_data = 1;
949 
950 	sqe = io_uring_get_sqe(ring);
951 	if (!sqe) {
952 		printf("get sqe failed\n");
953 		goto err;
954 	}
955 	ts1.tv_sec = 1;
956 	ts1.tv_nsec = 0;
957 	io_uring_prep_link_timeout(sqe, &ts1, 0);
958 	sqe->flags |= IOSQE_IO_LINK;
959 	sqe->user_data = 2;
960 
961 	sqe = io_uring_get_sqe(ring);
962 	if (!sqe) {
963 		printf("get sqe failed\n");
964 		goto err;
965 	}
966 	ts2.tv_sec = 2;
967 	ts2.tv_nsec = 0;
968 	io_uring_prep_link_timeout(sqe, &ts2, 0);
969 	sqe->user_data = 3;
970 
971 	ret = io_uring_submit(ring);
972 	if (ret != 3) {
973 		printf("sqe submit failed: %d\n", ret);
974 		goto err;
975 	}
976 
977 	for (i = 0; i < 3; i++) {
978 		ret = io_uring_wait_cqe(ring, &cqe);
979 		if (ret < 0) {
980 			printf("wait completion %d\n", ret);
981 			goto err;
982 		}
983 		switch (cqe->user_data) {
984 		case 1:
985 		case 2:
986 			if (cqe->res && cqe->res != -ECANCELED) {
987 				fprintf(stderr, "Request got %d, wanted -EINVAL "
988 						"or -ECANCELED\n",
989 						cqe->res);
990 				goto err;
991 			}
992 			break;
993 		case 3:
994 			if (cqe->res != -ECANCELED && cqe->res != -EINVAL) {
995 				fprintf(stderr, "Link timeout got %d, wanted -ECANCELED\n", cqe->res);
996 				goto err;
997 			}
998 			break;
999 		}
1000 		io_uring_cqe_seen(ring, cqe);
1001 	}
1002 
1003 	return 0;
1004 err:
1005 	return 1;
1006 }
1007 
main(int argc,char * argv[])1008 int main(int argc, char *argv[])
1009 {
1010 	struct io_uring ring;
1011 	int ret;
1012 
1013 	if (argc > 1)
1014 		return 0;
1015 
1016 	ret = io_uring_queue_init(8, &ring, 0);
1017 	if (ret) {
1018 		printf("ring setup failed\n");
1019 		return 1;
1020 	}
1021 
1022 	ret = test_timeout_link_chain1(&ring);
1023 	if (ret) {
1024 		printf("test_single_link_chain1 failed\n");
1025 		return ret;
1026 	}
1027 
1028 	ret = test_timeout_link_chain2(&ring);
1029 	if (ret) {
1030 		printf("test_single_link_chain2 failed\n");
1031 		return ret;
1032 	}
1033 
1034 	ret = test_timeout_link_chain3(&ring);
1035 	if (ret) {
1036 		printf("test_single_link_chain3 failed\n");
1037 		return ret;
1038 	}
1039 
1040 	ret = test_timeout_link_chain4(&ring);
1041 	if (ret) {
1042 		printf("test_single_link_chain4 failed\n");
1043 		return ret;
1044 	}
1045 
1046 	ret = test_timeout_link_chain5(&ring);
1047 	if (ret) {
1048 		printf("test_single_link_chain5 failed\n");
1049 		return ret;
1050 	}
1051 
1052 	ret = test_single_link_timeout(&ring, 10);
1053 	if (ret) {
1054 		printf("test_single_link_timeout 10 failed\n");
1055 		return ret;
1056 	}
1057 
1058 	ret = test_single_link_timeout(&ring, 100000ULL);
1059 	if (ret) {
1060 		printf("test_single_link_timeout 100000 failed\n");
1061 		return ret;
1062 	}
1063 
1064 	ret = test_single_link_timeout(&ring, 500000000ULL);
1065 	if (ret) {
1066 		printf("test_single_link_timeout 500000000 failed\n");
1067 		return ret;
1068 	}
1069 
1070 	ret = test_single_link_no_timeout(&ring);
1071 	if (ret) {
1072 		printf("test_single_link_no_timeout failed\n");
1073 		return ret;
1074 	}
1075 
1076 	ret = test_single_link_timeout_error(&ring);
1077 	if (ret) {
1078 		printf("test_single_link_timeout_error failed\n");
1079 		return ret;
1080 	}
1081 
1082 	ret = test_single_link_timeout_nop(&ring);
1083 	if (ret) {
1084 		printf("test_single_link_timeout_nop failed\n");
1085 		return ret;
1086 	}
1087 
1088 	ret = test_single_link_timeout_ception(&ring);
1089 	if (ret) {
1090 		printf("test_single_link_timeout_ception failed\n");
1091 		return ret;
1092 	}
1093 
1094 	ret = test_fail_lone_link_timeouts(&ring);
1095 	if (ret) {
1096 		printf("test_fail_lone_link_timeouts failed\n");
1097 		return ret;
1098 	}
1099 
1100 	ret = test_fail_two_link_timeouts(&ring);
1101 	if (ret) {
1102 		printf("test_fail_two_link_timeouts failed\n");
1103 		return ret;
1104 	}
1105 
1106 	return 0;
1107 }
1108