xref: /linux/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c (revision f2ad904e923f70a80f478febf001f88dfd65a64c)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 // Copyright (c) 2024 Christian Brauner <brauner@kernel.org>
3 
4 #define _GNU_SOURCE
5 #include <fcntl.h>
6 #include <sched.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/mount.h>
11 #include <unistd.h>
12 
13 #include "../../kselftest_harness.h"
14 
15 #define MNT_NS_COUNT 11
16 #define MNT_NS_LAST_INDEX 10
17 
18 struct mnt_ns_info {
19 	__u32 size;
20 	__u32 nr_mounts;
21 	__u64 mnt_ns_id;
22 };
23 
24 #define MNT_NS_INFO_SIZE_VER0 16 /* size of first published struct */
25 
26 /* Get information about namespace. */
27 #define NS_MNT_GET_INFO _IOR(0xb7, 10, struct mnt_ns_info)
28 /* Get next namespace. */
29 #define NS_MNT_GET_NEXT _IOR(0xb7, 11, struct mnt_ns_info)
30 /* Get previous namespace. */
31 #define NS_MNT_GET_PREV _IOR(0xb7, 12, struct mnt_ns_info)
32 
33 FIXTURE(iterate_mount_namespaces) {
34 	int fd_mnt_ns[MNT_NS_COUNT];
35 	__u64 mnt_ns_id[MNT_NS_COUNT];
36 };
37 
38 FIXTURE_SETUP(iterate_mount_namespaces)
39 {
40 	for (int i = 0; i < MNT_NS_COUNT; i++)
41 		self->fd_mnt_ns[i] = -EBADF;
42 
43 	/*
44 	 * Creating a new user namespace let's us guarantee that we only see
45 	 * mount namespaces that we did actually create.
46 	 */
47 	ASSERT_EQ(unshare(CLONE_NEWUSER), 0);
48 
49 	for (int i = 0; i < MNT_NS_COUNT; i++) {
50 		struct mnt_ns_info info = {};
51 
52 		ASSERT_EQ(unshare(CLONE_NEWNS), 0);
53 		self->fd_mnt_ns[i] = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
54 		ASSERT_GE(self->fd_mnt_ns[i], 0);
55 		ASSERT_EQ(ioctl(self->fd_mnt_ns[i], NS_MNT_GET_INFO, &info), 0);
56 		self->mnt_ns_id[i] = info.mnt_ns_id;
57 	}
58 }
59 
60 FIXTURE_TEARDOWN(iterate_mount_namespaces)
61 {
62 	for (int i = 0; i < MNT_NS_COUNT; i++) {
63 		if (self->fd_mnt_ns[i] < 0)
64 			continue;
65 		ASSERT_EQ(close(self->fd_mnt_ns[i]), 0);
66 	}
67 }
68 
69 TEST_F(iterate_mount_namespaces, iterate_all_forward)
70 {
71 	int fd_mnt_ns_cur, count = 0;
72 
73 	fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[0], F_DUPFD_CLOEXEC);
74 	ASSERT_GE(fd_mnt_ns_cur, 0);
75 
76 	for (;; count++) {
77 		struct mnt_ns_info info = {};
78 		int fd_mnt_ns_next;
79 
80 		fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info);
81 		if (fd_mnt_ns_next < 0 && errno == ENOENT)
82 			break;
83 		ASSERT_GE(fd_mnt_ns_next, 0);
84 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
85 		fd_mnt_ns_cur = fd_mnt_ns_next;
86 	}
87 	ASSERT_EQ(count, MNT_NS_LAST_INDEX);
88 }
89 
90 TEST_F(iterate_mount_namespaces, iterate_all_backwards)
91 {
92 	int fd_mnt_ns_cur, count = 0;
93 
94 	fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[MNT_NS_LAST_INDEX], F_DUPFD_CLOEXEC);
95 	ASSERT_GE(fd_mnt_ns_cur, 0);
96 
97 	for (;; count++) {
98 		struct mnt_ns_info info = {};
99 		int fd_mnt_ns_prev;
100 
101 		fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info);
102 		if (fd_mnt_ns_prev < 0 && errno == ENOENT)
103 			break;
104 		ASSERT_GE(fd_mnt_ns_prev, 0);
105 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
106 		fd_mnt_ns_cur = fd_mnt_ns_prev;
107 	}
108 	ASSERT_EQ(count, MNT_NS_LAST_INDEX);
109 }
110 
111 TEST_F(iterate_mount_namespaces, iterate_forward)
112 {
113 	int fd_mnt_ns_cur;
114 
115 	ASSERT_EQ(setns(self->fd_mnt_ns[0], CLONE_NEWNS), 0);
116 
117 	fd_mnt_ns_cur = self->fd_mnt_ns[0];
118 	for (int i = 1; i < MNT_NS_COUNT; i++) {
119 		struct mnt_ns_info info = {};
120 		int fd_mnt_ns_next;
121 
122 		fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info);
123 		ASSERT_GE(fd_mnt_ns_next, 0);
124 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
125 		fd_mnt_ns_cur = fd_mnt_ns_next;
126 		ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]);
127 	}
128 }
129 
130 TEST_F(iterate_mount_namespaces, iterate_backward)
131 {
132 	int fd_mnt_ns_cur;
133 
134 	ASSERT_EQ(setns(self->fd_mnt_ns[MNT_NS_LAST_INDEX], CLONE_NEWNS), 0);
135 
136 	fd_mnt_ns_cur = self->fd_mnt_ns[MNT_NS_LAST_INDEX];
137 	for (int i = MNT_NS_LAST_INDEX - 1; i >= 0; i--) {
138 		struct mnt_ns_info info = {};
139 		int fd_mnt_ns_prev;
140 
141 		fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info);
142 		ASSERT_GE(fd_mnt_ns_prev, 0);
143 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
144 		fd_mnt_ns_cur = fd_mnt_ns_prev;
145 		ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]);
146 	}
147 }
148 
149 TEST_HARNESS_MAIN
150