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