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