• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4  */
5 
6 /*\
7  * [Description]
8  *
9  * This test verifies that listmount() is properly reading groups of mount IDs,
10  * checking that both oneshoot and iterator API for listmount() return the same
11  * array.
12  *
13  * [Algorithm]
14  *
15  * - move into a new unshared namespace
16  * - mount() our new root inside temporary folder
17  * - generate a full mounts tree inside root folder, doubling the number of
18  *   mounted filesystems each bind mount
19  * - read the full list of mounted IDs using listmount(LSMT_ROOT, ..)
20  * - read the list of mounted IDs using groups of fixed size
21  * - compare the first mount list with the second mount list
22  */
23 
24 #include "listmount.h"
25 #include "lapi/sched.h"
26 
27 #define MNTPOINT "mntpoint"
28 #define BIND_MOUNTS 7
29 #define GROUPS_SIZE 3
30 #define LISTSIZE (1 << BIND_MOUNTS)
31 
run(void)32 static void run(void)
33 {
34 	ssize_t ret;
35 	size_t id, tot_ids, count = 0;
36 	uint64_t mount_ids[LISTSIZE];
37 	uint64_t list[LISTSIZE];
38 
39 	for (int i = 0; i < BIND_MOUNTS; i++)
40 		SAFE_MOUNT("/", "/", NULL, MS_BIND, NULL);
41 
42 	tst_res(TINFO, "Reading all %d mount IDs in once", LISTSIZE);
43 
44 	TST_EXP_POSITIVE(listmount(LSMT_ROOT, 0, mount_ids, LISTSIZE, 0));
45 	if (!TST_PASS)
46 		goto end;
47 
48 	tot_ids = (size_t)TST_RET;
49 
50 	if (tot_ids != LISTSIZE) {
51 		tst_res(TFAIL, "listmount() returned %lu but %d was expected",
52 			tot_ids, LISTSIZE);
53 		goto end;
54 	}
55 
56 	tst_res(TINFO, "Reading groups of %d mount IDs", GROUPS_SIZE);
57 
58 	while (count < LISTSIZE) {
59 		id = count ? list[count - 1] : 0;
60 		ret = listmount(LSMT_ROOT, id, list + count, GROUPS_SIZE, 0);
61 
62 		tst_res(TDEBUG, "listmount(LSMT_ROOT, %lu, list + %lu, %d, 0)",
63 			id, count, GROUPS_SIZE);
64 
65 		if (ret == -1) {
66 			tst_res(TFAIL, "listmount() failed with %s", tst_strerrno(errno));
67 			goto end;
68 		}
69 
70 		count += ret;
71 
72 		if (TST_RET < GROUPS_SIZE)
73 			break;
74 	}
75 
76 	for (size_t i = 0; i < LISTSIZE; i++) {
77 		if (mount_ids[i] != list[i]) {
78 			tst_res(TFAIL, "Mount ID differs at %ld index", i);
79 			goto end;
80 		}
81 	}
82 
83 	tst_res(TPASS, "All mount IDs have been correctly read");
84 
85 end:
86 	for (int i = 0; i < BIND_MOUNTS; i++)
87 		SAFE_UMOUNT("/");
88 }
89 
setup(void)90 static void setup(void)
91 {
92 	SAFE_UNSHARE(CLONE_NEWNS);
93 	SAFE_CHROOT(MNTPOINT);
94 
95 	SAFE_MOUNT("", "/", NULL, MS_REC | MS_SHARED, NULL);
96 }
97 
98 static struct tst_test test = {
99 	.test_all = run,
100 	.setup = setup,
101 	.forks_child = 1,
102 	.min_kver = "6.8",
103 	.mount_device = 1,
104 	.mntpoint = MNTPOINT,
105 };
106