1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: run various file registration tests
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/resource.h>
13
14 #include "helpers.h"
15 #include "liburing.h"
16
17 static int no_update = 0;
18
close_files(int * files,int nr_files,int add)19 static void close_files(int *files, int nr_files, int add)
20 {
21 char fname[32];
22 int i;
23
24 for (i = 0; i < nr_files; i++) {
25 if (files)
26 close(files[i]);
27 if (!add)
28 sprintf(fname, ".reg.%d", i);
29 else
30 sprintf(fname, ".add.%d", i + add);
31 unlink(fname);
32 }
33 if (files)
34 free(files);
35 }
36
open_files(int nr_files,int extra,int add)37 static int *open_files(int nr_files, int extra, int add)
38 {
39 char fname[32];
40 int *files;
41 int i;
42
43 files = t_calloc(nr_files + extra, sizeof(int));
44
45 for (i = 0; i < nr_files; i++) {
46 if (!add)
47 sprintf(fname, ".reg.%d", i);
48 else
49 sprintf(fname, ".add.%d", i + add);
50 files[i] = open(fname, O_RDWR | O_CREAT, 0644);
51 if (files[i] < 0) {
52 perror("open");
53 free(files);
54 files = NULL;
55 break;
56 }
57 }
58 if (extra) {
59 for (i = nr_files; i < nr_files + extra; i++)
60 files[i] = -1;
61 }
62
63 return files;
64 }
65
test_shrink(struct io_uring * ring)66 static int test_shrink(struct io_uring *ring)
67 {
68 int ret, off, fd;
69 int *files;
70
71 files = open_files(50, 0, 0);
72 ret = io_uring_register_files(ring, files, 50);
73 if (ret) {
74 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
75 goto err;
76 }
77
78 off = 0;
79 do {
80 fd = -1;
81 ret = io_uring_register_files_update(ring, off, &fd, 1);
82 if (ret != 1) {
83 if (off == 50 && ret == -EINVAL)
84 break;
85 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
86 break;
87 }
88 off++;
89 } while (1);
90
91 ret = io_uring_unregister_files(ring);
92 if (ret) {
93 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
94 goto err;
95 }
96
97 close_files(files, 50, 0);
98 return 0;
99 err:
100 close_files(files, 50, 0);
101 return 1;
102 }
103
104
test_grow(struct io_uring * ring)105 static int test_grow(struct io_uring *ring)
106 {
107 int ret, off;
108 int *files, *fds = NULL;
109
110 files = open_files(50, 250, 0);
111 ret = io_uring_register_files(ring, files, 300);
112 if (ret) {
113 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
114 goto err;
115 }
116
117 off = 50;
118 do {
119 fds = open_files(1, 0, off);
120 ret = io_uring_register_files_update(ring, off, fds, 1);
121 if (ret != 1) {
122 if (off == 300 && ret == -EINVAL)
123 break;
124 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
125 break;
126 }
127 if (off >= 300) {
128 fprintf(stderr, "%s: Succeeded beyond end-of-list?\n", __FUNCTION__);
129 goto err;
130 }
131 off++;
132 } while (1);
133
134 ret = io_uring_unregister_files(ring);
135 if (ret) {
136 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
137 goto err;
138 }
139
140 close_files(files, 100, 0);
141 close_files(NULL, 251, 50);
142 return 0;
143 err:
144 close_files(files, 100, 0);
145 close_files(NULL, 251, 50);
146 return 1;
147 }
148
test_replace_all(struct io_uring * ring)149 static int test_replace_all(struct io_uring *ring)
150 {
151 int *files, *fds = NULL;
152 int ret, i;
153
154 files = open_files(100, 0, 0);
155 ret = io_uring_register_files(ring, files, 100);
156 if (ret) {
157 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
158 goto err;
159 }
160
161 fds = t_malloc(100 * sizeof(int));
162 for (i = 0; i < 100; i++)
163 fds[i] = -1;
164
165 ret = io_uring_register_files_update(ring, 0, fds, 100);
166 if (ret != 100) {
167 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
168 goto err;
169 }
170
171 ret = io_uring_unregister_files(ring);
172 if (ret) {
173 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
174 goto err;
175 }
176
177 close_files(files, 100, 0);
178 if (fds)
179 free(fds);
180 return 0;
181 err:
182 close_files(files, 100, 0);
183 if (fds)
184 free(fds);
185 return 1;
186 }
187
test_replace(struct io_uring * ring)188 static int test_replace(struct io_uring *ring)
189 {
190 int *files, *fds = NULL;
191 int ret;
192
193 files = open_files(100, 0, 0);
194 ret = io_uring_register_files(ring, files, 100);
195 if (ret) {
196 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
197 goto err;
198 }
199
200 fds = open_files(10, 0, 1);
201 ret = io_uring_register_files_update(ring, 90, fds, 10);
202 if (ret != 10) {
203 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
204 goto err;
205 }
206
207 ret = io_uring_unregister_files(ring);
208 if (ret) {
209 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
210 goto err;
211 }
212
213 close_files(files, 100, 0);
214 if (fds)
215 close_files(fds, 10, 1);
216 return 0;
217 err:
218 close_files(files, 100, 0);
219 if (fds)
220 close_files(fds, 10, 1);
221 return 1;
222 }
223
test_removals(struct io_uring * ring)224 static int test_removals(struct io_uring *ring)
225 {
226 int *files, *fds = NULL;
227 int ret, i;
228
229 files = open_files(100, 0, 0);
230 ret = io_uring_register_files(ring, files, 100);
231 if (ret) {
232 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
233 goto err;
234 }
235
236 fds = t_calloc(10, sizeof(int));
237 for (i = 0; i < 10; i++)
238 fds[i] = -1;
239
240 ret = io_uring_register_files_update(ring, 50, fds, 10);
241 if (ret != 10) {
242 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
243 goto err;
244 }
245
246 ret = io_uring_unregister_files(ring);
247 if (ret) {
248 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
249 goto err;
250 }
251
252 close_files(files, 100, 0);
253 if (fds)
254 free(fds);
255 return 0;
256 err:
257 close_files(files, 100, 0);
258 if (fds)
259 free(fds);
260 return 1;
261 }
262
test_additions(struct io_uring * ring)263 static int test_additions(struct io_uring *ring)
264 {
265 int *files, *fds = NULL;
266 int ret;
267
268 files = open_files(100, 100, 0);
269 ret = io_uring_register_files(ring, files, 200);
270 if (ret) {
271 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
272 goto err;
273 }
274
275 fds = open_files(2, 0, 1);
276 ret = io_uring_register_files_update(ring, 100, fds, 2);
277 if (ret != 2) {
278 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
279 goto err;
280 }
281
282 ret = io_uring_unregister_files(ring);
283 if (ret) {
284 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
285 goto err;
286 }
287
288 close_files(files, 100, 0);
289 if (fds)
290 close_files(fds, 2, 1);
291 return 0;
292 err:
293 close_files(files, 100, 0);
294 if (fds)
295 close_files(fds, 2, 1);
296 return 1;
297 }
298
test_sparse(struct io_uring * ring)299 static int test_sparse(struct io_uring *ring)
300 {
301 int *files;
302 int ret;
303
304 files = open_files(100, 100, 0);
305 ret = io_uring_register_files(ring, files, 200);
306 if (ret) {
307 if (ret == -EBADF) {
308 fprintf(stdout, "Sparse files not supported\n");
309 no_update = 1;
310 goto done;
311 }
312 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
313 goto err;
314 }
315 ret = io_uring_unregister_files(ring);
316 if (ret) {
317 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
318 goto err;
319 }
320 done:
321 close_files(files, 100, 0);
322 return 0;
323 err:
324 close_files(files, 100, 0);
325 return 1;
326 }
327
test_basic_many(struct io_uring * ring)328 static int test_basic_many(struct io_uring *ring)
329 {
330 int *files;
331 int ret;
332
333 files = open_files(768, 0, 0);
334 ret = io_uring_register_files(ring, files, 768);
335 if (ret) {
336 fprintf(stderr, "%s: register %d\n", __FUNCTION__, ret);
337 goto err;
338 }
339 ret = io_uring_unregister_files(ring);
340 if (ret) {
341 fprintf(stderr, "%s: unregister %d\n", __FUNCTION__, ret);
342 goto err;
343 }
344 close_files(files, 768, 0);
345 return 0;
346 err:
347 close_files(files, 768, 0);
348 return 1;
349 }
350
test_basic(struct io_uring * ring,int fail)351 static int test_basic(struct io_uring *ring, int fail)
352 {
353 int *files;
354 int ret;
355 int nr_files = fail ? 10 : 100;
356
357 files = open_files(nr_files, 0, 0);
358 ret = io_uring_register_files(ring, files, 100);
359 if (ret) {
360 if (fail) {
361 if (ret == -EBADF || ret == -EFAULT)
362 return 0;
363 }
364 fprintf(stderr, "%s: register %d\n", __FUNCTION__, ret);
365 goto err;
366 }
367 if (fail) {
368 fprintf(stderr, "Registration succeeded, but expected fail\n");
369 goto err;
370 }
371 ret = io_uring_unregister_files(ring);
372 if (ret) {
373 fprintf(stderr, "%s: unregister %d\n", __FUNCTION__, ret);
374 goto err;
375 }
376 close_files(files, nr_files, 0);
377 return 0;
378 err:
379 close_files(files, nr_files, 0);
380 return 1;
381 }
382
383 /*
384 * Register 0 files, but reserve space for 10. Then add one file.
385 */
test_zero(struct io_uring * ring)386 static int test_zero(struct io_uring *ring)
387 {
388 int *files, *fds = NULL;
389 int ret;
390
391 files = open_files(0, 10, 0);
392 ret = io_uring_register_files(ring, files, 10);
393 if (ret) {
394 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
395 goto err;
396 }
397
398 fds = open_files(1, 0, 1);
399 ret = io_uring_register_files_update(ring, 0, fds, 1);
400 if (ret != 1) {
401 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
402 goto err;
403 }
404
405 ret = io_uring_unregister_files(ring);
406 if (ret) {
407 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
408 goto err;
409 }
410
411 if (fds)
412 close_files(fds, 1, 1);
413 free(files);
414 return 0;
415 err:
416 if (fds)
417 close_files(fds, 1, 1);
418 free(files);
419 return 1;
420 }
421
test_fixed_read_write(struct io_uring * ring,int index)422 static int test_fixed_read_write(struct io_uring *ring, int index)
423 {
424 struct io_uring_sqe *sqe;
425 struct io_uring_cqe *cqe;
426 struct iovec iov[2];
427 int ret;
428
429 iov[0].iov_base = t_malloc(4096);
430 iov[0].iov_len = 4096;
431 memset(iov[0].iov_base, 0x5a, 4096);
432
433 iov[1].iov_base = t_malloc(4096);
434 iov[1].iov_len = 4096;
435
436 sqe = io_uring_get_sqe(ring);
437 if (!sqe) {
438 fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
439 return 1;
440 }
441 io_uring_prep_writev(sqe, index, &iov[0], 1, 0);
442 sqe->flags |= IOSQE_FIXED_FILE;
443 sqe->user_data = 1;
444
445 ret = io_uring_submit(ring);
446 if (ret != 1) {
447 fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
448 return 1;
449 }
450
451 ret = io_uring_wait_cqe(ring, &cqe);
452 if (ret < 0) {
453 fprintf(stderr, "%s: io_uring_wait_cqe=%d\n", __FUNCTION__, ret);
454 return 1;
455 }
456 if (cqe->res != 4096) {
457 fprintf(stderr, "%s: write cqe->res=%d\n", __FUNCTION__, cqe->res);
458 return 1;
459 }
460 io_uring_cqe_seen(ring, cqe);
461
462 sqe = io_uring_get_sqe(ring);
463 if (!sqe) {
464 fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
465 return 1;
466 }
467 io_uring_prep_readv(sqe, index, &iov[1], 1, 0);
468 sqe->flags |= IOSQE_FIXED_FILE;
469 sqe->user_data = 2;
470
471 ret = io_uring_submit(ring);
472 if (ret != 1) {
473 fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
474 return 1;
475 }
476
477 ret = io_uring_wait_cqe(ring, &cqe);
478 if (ret < 0) {
479 fprintf(stderr, "%s: io_uring_wait_cqe=%d\n", __FUNCTION__, ret);
480 return 1;
481 }
482 if (cqe->res != 4096) {
483 fprintf(stderr, "%s: read cqe->res=%d\n", __FUNCTION__, cqe->res);
484 return 1;
485 }
486 io_uring_cqe_seen(ring, cqe);
487
488 if (memcmp(iov[1].iov_base, iov[0].iov_base, 4096)) {
489 fprintf(stderr, "%s: data mismatch\n", __FUNCTION__);
490 return 1;
491 }
492
493 free(iov[0].iov_base);
494 free(iov[1].iov_base);
495 return 0;
496 }
497
adjust_nfiles(int want_files)498 static void adjust_nfiles(int want_files)
499 {
500 struct rlimit rlim;
501
502 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
503 return;
504 if (rlim.rlim_cur >= want_files)
505 return;
506 rlim.rlim_cur = want_files;
507 setrlimit(RLIMIT_NOFILE, &rlim);
508 }
509
510 /*
511 * Register 8K of sparse files, update one at a random spot, then do some
512 * file IO to verify it works.
513 */
test_huge(struct io_uring * ring)514 static int test_huge(struct io_uring *ring)
515 {
516 int *files;
517 int ret;
518
519 adjust_nfiles(16384);
520
521 files = open_files(0, 8192, 0);
522 ret = io_uring_register_files(ring, files, 8192);
523 if (ret) {
524 /* huge sets not supported */
525 if (ret == -EMFILE) {
526 fprintf(stdout, "%s: No huge file set support, skipping\n", __FUNCTION__);
527 goto out;
528 }
529 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
530 goto err;
531 }
532
533 files[7193] = open(".reg.7193", O_RDWR | O_CREAT, 0644);
534 if (files[7193] < 0) {
535 fprintf(stderr, "%s: open=%d\n", __FUNCTION__, errno);
536 goto err;
537 }
538
539 ret = io_uring_register_files_update(ring, 7193, &files[7193], 1);
540 if (ret != 1) {
541 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
542 goto err;
543 }
544
545 if (test_fixed_read_write(ring, 7193))
546 goto err;
547
548 ret = io_uring_unregister_files(ring);
549 if (ret) {
550 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
551 goto err;
552 }
553
554 if (files[7193] != -1) {
555 close(files[7193]);
556 unlink(".reg.7193");
557 }
558 out:
559 free(files);
560 return 0;
561 err:
562 if (files[7193] != -1) {
563 close(files[7193]);
564 unlink(".reg.7193");
565 }
566 free(files);
567 return 1;
568 }
569
test_skip(struct io_uring * ring)570 static int test_skip(struct io_uring *ring)
571 {
572 int *files;
573 int ret;
574
575 files = open_files(100, 0, 0);
576 ret = io_uring_register_files(ring, files, 100);
577 if (ret) {
578 fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
579 goto err;
580 }
581
582 files[90] = IORING_REGISTER_FILES_SKIP;
583 ret = io_uring_register_files_update(ring, 90, &files[90], 1);
584 if (ret != 1) {
585 if (ret == -EBADF) {
586 fprintf(stdout, "Skipping files not supported\n");
587 goto done;
588 }
589 fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret);
590 goto err;
591 }
592
593 /* verify can still use file index 90 */
594 if (test_fixed_read_write(ring, 90))
595 goto err;
596
597 ret = io_uring_unregister_files(ring);
598 if (ret) {
599 fprintf(stderr, "%s: unregister ret=%d\n", __FUNCTION__, ret);
600 goto err;
601 }
602
603 done:
604 close_files(files, 100, 0);
605 return 0;
606 err:
607 close_files(files, 100, 0);
608 return 1;
609 }
610
test_sparse_updates(void)611 static int test_sparse_updates(void)
612 {
613 struct io_uring ring;
614 int ret, i, *fds, newfd;
615
616 ret = io_uring_queue_init(8, &ring, 0);
617 if (ret) {
618 fprintf(stderr, "queue_init: %d\n", ret);
619 return ret;
620 }
621
622 fds = t_malloc(256 * sizeof(int));
623 for (i = 0; i < 256; i++)
624 fds[i] = -1;
625
626 ret = io_uring_register_files(&ring, fds, 256);
627 if (ret) {
628 fprintf(stderr, "file_register: %d\n", ret);
629 return ret;
630 }
631
632 newfd = 1;
633 for (i = 0; i < 256; i++) {
634 ret = io_uring_register_files_update(&ring, i, &newfd, 1);
635 if (ret != 1) {
636 fprintf(stderr, "file_update: %d\n", ret);
637 return ret;
638 }
639 }
640 io_uring_unregister_files(&ring);
641
642 for (i = 0; i < 256; i++)
643 fds[i] = 1;
644
645 ret = io_uring_register_files(&ring, fds, 256);
646 if (ret) {
647 fprintf(stderr, "file_register: %d\n", ret);
648 return ret;
649 }
650
651 newfd = -1;
652 for (i = 0; i < 256; i++) {
653 ret = io_uring_register_files_update(&ring, i, &newfd, 1);
654 if (ret != 1) {
655 fprintf(stderr, "file_update: %d\n", ret);
656 return ret;
657 }
658 }
659 io_uring_unregister_files(&ring);
660
661 io_uring_queue_exit(&ring);
662 return 0;
663 }
664
test_fixed_removal_ordering(void)665 static int test_fixed_removal_ordering(void)
666 {
667 char buffer[128];
668 struct io_uring ring;
669 struct io_uring_sqe *sqe;
670 struct io_uring_cqe *cqe;
671 struct __kernel_timespec ts;
672 int ret, fd, i, fds[2];
673
674 ret = io_uring_queue_init(8, &ring, 0);
675 if (ret < 0) {
676 fprintf(stderr, "failed to init io_uring: %s\n", strerror(-ret));
677 return ret;
678 }
679 if (pipe(fds)) {
680 perror("pipe");
681 return -1;
682 }
683 ret = io_uring_register_files(&ring, fds, 2);
684 if (ret) {
685 fprintf(stderr, "file_register: %d\n", ret);
686 return ret;
687 }
688 /* ring should have fds referenced, can close them */
689 close(fds[0]);
690 close(fds[1]);
691
692 sqe = io_uring_get_sqe(&ring);
693 if (!sqe) {
694 fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
695 return 1;
696 }
697 /* outwait file recycling delay */
698 ts.tv_sec = 3;
699 ts.tv_nsec = 0;
700 io_uring_prep_timeout(sqe, &ts, 0, 0);
701 sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
702 sqe->user_data = 1;
703
704 sqe = io_uring_get_sqe(&ring);
705 if (!sqe) {
706 printf("get sqe failed\n");
707 return -1;
708 }
709 io_uring_prep_write(sqe, 1, buffer, sizeof(buffer), 0);
710 sqe->flags |= IOSQE_FIXED_FILE;
711 sqe->user_data = 2;
712
713 ret = io_uring_submit(&ring);
714 if (ret != 2) {
715 fprintf(stderr, "%s: got %d, wanted 2\n", __FUNCTION__, ret);
716 return -1;
717 }
718
719 /* remove unused pipe end */
720 fd = -1;
721 ret = io_uring_register_files_update(&ring, 0, &fd, 1);
722 if (ret != 1) {
723 fprintf(stderr, "update off=0 failed\n");
724 return -1;
725 }
726
727 /* remove used pipe end */
728 fd = -1;
729 ret = io_uring_register_files_update(&ring, 1, &fd, 1);
730 if (ret != 1) {
731 fprintf(stderr, "update off=1 failed\n");
732 return -1;
733 }
734
735 for (i = 0; i < 2; ++i) {
736 ret = io_uring_wait_cqe(&ring, &cqe);
737 if (ret < 0) {
738 fprintf(stderr, "%s: io_uring_wait_cqe=%d\n", __FUNCTION__, ret);
739 return 1;
740 }
741 io_uring_cqe_seen(&ring, cqe);
742 }
743
744 io_uring_queue_exit(&ring);
745 return 0;
746 }
747
748 /* mix files requiring SCM-accounting and not in a single register */
test_mixed_af_unix(void)749 static int test_mixed_af_unix(void)
750 {
751 struct io_uring ring;
752 int i, ret, fds[2];
753 int reg_fds[32];
754 int sp[2];
755
756 ret = io_uring_queue_init(8, &ring, 0);
757 if (ret < 0) {
758 fprintf(stderr, "failed to init io_uring: %s\n", strerror(-ret));
759 return ret;
760 }
761 if (pipe(fds)) {
762 perror("pipe");
763 return -1;
764 }
765 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp) != 0) {
766 perror("Failed to create Unix-domain socket pair\n");
767 return 1;
768 }
769
770 for (i = 0; i < 16; i++) {
771 reg_fds[i * 2] = fds[0];
772 reg_fds[i * 2 + 1] = sp[0];
773 }
774
775 ret = io_uring_register_files(&ring, reg_fds, 32);
776 if (ret) {
777 fprintf(stderr, "file_register: %d\n", ret);
778 return ret;
779 }
780
781 close(fds[0]);
782 close(fds[1]);
783 close(sp[0]);
784 close(sp[1]);
785 io_uring_queue_exit(&ring);
786 return 0;
787 }
788
test_partial_register_fail(void)789 static int test_partial_register_fail(void)
790 {
791 char buffer[128];
792 struct io_uring ring;
793 int ret, fds[2];
794 int reg_fds[5];
795
796 ret = io_uring_queue_init(8, &ring, 0);
797 if (ret < 0) {
798 fprintf(stderr, "failed to init io_uring: %s\n", strerror(-ret));
799 return ret;
800 }
801 if (pipe(fds)) {
802 perror("pipe");
803 return -1;
804 }
805
806 /*
807 * Expect register to fail as it doesn't support io_uring fds, shouldn't
808 * leave any fds referenced afterwards.
809 */
810 reg_fds[0] = fds[0];
811 reg_fds[1] = fds[1];
812 reg_fds[2] = -1;
813 reg_fds[3] = ring.ring_fd;
814 reg_fds[4] = -1;
815 ret = io_uring_register_files(&ring, reg_fds, 5);
816 if (!ret) {
817 fprintf(stderr, "file_register unexpectedly succeeded\n");
818 return 1;
819 }
820
821 /* ring should have fds referenced, can close them */
822 close(fds[1]);
823
824 /* confirm that fds[1] is actually close and to ref'ed by io_uring */
825 ret = read(fds[0], buffer, 10);
826 if (ret < 0)
827 perror("read");
828 close(fds[0]);
829 io_uring_queue_exit(&ring);
830 return 0;
831 }
832
main(int argc,char * argv[])833 int main(int argc, char *argv[])
834 {
835 struct io_uring ring;
836 int ret;
837
838 if (argc > 1)
839 return 0;
840
841 ret = io_uring_queue_init(8, &ring, 0);
842 if (ret) {
843 printf("ring setup failed\n");
844 return 1;
845 }
846
847 ret = test_basic(&ring, 0);
848 if (ret) {
849 printf("test_basic failed\n");
850 return ret;
851 }
852
853 ret = test_basic(&ring, 1);
854 if (ret) {
855 printf("test_basic failed\n");
856 return ret;
857 }
858
859 ret = test_basic_many(&ring);
860 if (ret) {
861 printf("test_basic_many failed\n");
862 return ret;
863 }
864
865 ret = test_sparse(&ring);
866 if (ret) {
867 printf("test_sparse failed\n");
868 return ret;
869 }
870
871 if (no_update)
872 return 0;
873
874 ret = test_additions(&ring);
875 if (ret) {
876 printf("test_additions failed\n");
877 return ret;
878 }
879
880 ret = test_removals(&ring);
881 if (ret) {
882 printf("test_removals failed\n");
883 return ret;
884 }
885
886 ret = test_replace(&ring);
887 if (ret) {
888 printf("test_replace failed\n");
889 return ret;
890 }
891
892 ret = test_replace_all(&ring);
893 if (ret) {
894 printf("test_replace_all failed\n");
895 return ret;
896 }
897
898 ret = test_grow(&ring);
899 if (ret) {
900 printf("test_grow failed\n");
901 return ret;
902 }
903
904 ret = test_shrink(&ring);
905 if (ret) {
906 printf("test_shrink failed\n");
907 return ret;
908 }
909
910 ret = test_zero(&ring);
911 if (ret) {
912 printf("test_zero failed\n");
913 return ret;
914 }
915
916 ret = test_huge(&ring);
917 if (ret) {
918 printf("test_huge failed\n");
919 return ret;
920 }
921
922 ret = test_skip(&ring);
923 if (ret) {
924 printf("test_skip failed\n");
925 return 1;
926 }
927
928 ret = test_sparse_updates();
929 if (ret) {
930 printf("test_sparse_updates failed\n");
931 return ret;
932 }
933
934 ret = test_fixed_removal_ordering();
935 if (ret) {
936 printf("test_fixed_removal_ordering failed\n");
937 return 1;
938 }
939
940 ret = test_mixed_af_unix();
941 if (ret) {
942 printf("test_mixed_af_unix failed\n");
943 return 1;
944 }
945
946 ret = test_partial_register_fail();
947 if (ret) {
948 printf("test_partial_register_fail failed\n");
949 return ret;
950 }
951
952 return 0;
953 }
954