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