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