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