Skip to content

Commit 9d87b10

Browse files
committed
selftests: add tests for mntns iteration
Test that forward and backward iteration works correctly. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent cae73d3 commit 9d87b10

File tree

3 files changed

+151
-1
lines changed

3 files changed

+151
-1
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
owner
33
pidns
4+
iterate_mntns

tools/testing/selftests/filesystems/nsfs/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
2-
TEST_GEN_PROGS := owner pidns
2+
TEST_GEN_PROGS := owner pidns iterate_mntns
33

44
CFLAGS := -Wall -Werror
55

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Copyright (c) 2024 Christian Brauner <[email protected]>
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

0 commit comments

Comments
 (0)