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