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