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