xref: /aosp_15_r20/external/liburing/test/file-register.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
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