xref: /linux/tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c (revision 2487b6b9bf2874cfca7efb59c95650c5b1d88d43)
1*e1c24b52SMiklos Szeredi // SPDX-License-Identifier: GPL-2.0-or-later
2*e1c24b52SMiklos Szeredi // Copyright (c) 2025 Miklos Szeredi <miklos@szeredi.hu>
3*e1c24b52SMiklos Szeredi 
4*e1c24b52SMiklos Szeredi #define _GNU_SOURCE
5*e1c24b52SMiklos Szeredi #include <fcntl.h>
6*e1c24b52SMiklos Szeredi #include <sched.h>
7*e1c24b52SMiklos Szeredi #include <stdio.h>
8*e1c24b52SMiklos Szeredi #include <string.h>
9*e1c24b52SMiklos Szeredi #include <sys/stat.h>
10*e1c24b52SMiklos Szeredi #include <sys/mount.h>
11*e1c24b52SMiklos Szeredi #include <linux/fanotify.h>
12*e1c24b52SMiklos Szeredi #include <unistd.h>
13*e1c24b52SMiklos Szeredi #include <sys/fanotify.h>
14*e1c24b52SMiklos Szeredi #include <sys/syscall.h>
15*e1c24b52SMiklos Szeredi 
16*e1c24b52SMiklos Szeredi #include "../../kselftest_harness.h"
17*e1c24b52SMiklos Szeredi #include "../statmount/statmount.h"
18*e1c24b52SMiklos Szeredi 
19*e1c24b52SMiklos Szeredi #ifndef FAN_MNT_ATTACH
20*e1c24b52SMiklos Szeredi struct fanotify_event_info_mnt {
21*e1c24b52SMiklos Szeredi 	struct fanotify_event_info_header hdr;
22*e1c24b52SMiklos Szeredi 	__u64 mnt_id;
23*e1c24b52SMiklos Szeredi };
24*e1c24b52SMiklos Szeredi #define FAN_MNT_ATTACH 0x01000000 /* Mount was attached */
25*e1c24b52SMiklos Szeredi #endif
26*e1c24b52SMiklos Szeredi 
27*e1c24b52SMiklos Szeredi #ifndef FAN_MNT_DETACH
28*e1c24b52SMiklos Szeredi #define FAN_MNT_DETACH 0x02000000 /* Mount was detached */
29*e1c24b52SMiklos Szeredi #endif
30*e1c24b52SMiklos Szeredi 
31*e1c24b52SMiklos Szeredi #ifndef FAN_REPORT_MNT
32*e1c24b52SMiklos Szeredi #define FAN_REPORT_MNT 0x00004000 /* Report mount events */
33*e1c24b52SMiklos Szeredi #endif
34*e1c24b52SMiklos Szeredi 
35*e1c24b52SMiklos Szeredi #ifndef FAN_MARK_MNTNS
36*e1c24b52SMiklos Szeredi #define FAN_MARK_MNTNS 0x00000110
37*e1c24b52SMiklos Szeredi #endif
38*e1c24b52SMiklos Szeredi 
39*e1c24b52SMiklos Szeredi static uint64_t get_mnt_id(struct __test_metadata *const _metadata,
40*e1c24b52SMiklos Szeredi 			   const char *path)
41*e1c24b52SMiklos Szeredi {
42*e1c24b52SMiklos Szeredi 	struct statx sx;
43*e1c24b52SMiklos Szeredi 
44*e1c24b52SMiklos Szeredi 	ASSERT_EQ(statx(AT_FDCWD, path, 0, STATX_MNT_ID_UNIQUE, &sx), 0);
45*e1c24b52SMiklos Szeredi 	ASSERT_TRUE(!!(sx.stx_mask & STATX_MNT_ID_UNIQUE));
46*e1c24b52SMiklos Szeredi 	return sx.stx_mnt_id;
47*e1c24b52SMiklos Szeredi }
48*e1c24b52SMiklos Szeredi 
49*e1c24b52SMiklos Szeredi static const char root_mntpoint_templ[] = "/tmp/mount-notify_test_root.XXXXXX";
50*e1c24b52SMiklos Szeredi 
51*e1c24b52SMiklos Szeredi FIXTURE(fanotify) {
52*e1c24b52SMiklos Szeredi 	int fan_fd;
53*e1c24b52SMiklos Szeredi 	char buf[256];
54*e1c24b52SMiklos Szeredi 	unsigned int rem;
55*e1c24b52SMiklos Szeredi 	void *next;
56*e1c24b52SMiklos Szeredi 	char root_mntpoint[sizeof(root_mntpoint_templ)];
57*e1c24b52SMiklos Szeredi 	int orig_root;
58*e1c24b52SMiklos Szeredi 	int ns_fd;
59*e1c24b52SMiklos Szeredi 	uint64_t root_id;
60*e1c24b52SMiklos Szeredi };
61*e1c24b52SMiklos Szeredi 
62*e1c24b52SMiklos Szeredi FIXTURE_SETUP(fanotify)
63*e1c24b52SMiklos Szeredi {
64*e1c24b52SMiklos Szeredi 	int ret;
65*e1c24b52SMiklos Szeredi 
66*e1c24b52SMiklos Szeredi 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
67*e1c24b52SMiklos Szeredi 
68*e1c24b52SMiklos Szeredi 	self->ns_fd = open("/proc/self/ns/mnt", O_RDONLY);
69*e1c24b52SMiklos Szeredi 	ASSERT_GE(self->ns_fd, 0);
70*e1c24b52SMiklos Szeredi 
71*e1c24b52SMiklos Szeredi 	ASSERT_EQ(mount("", "/", NULL, MS_REC|MS_PRIVATE, NULL), 0);
72*e1c24b52SMiklos Szeredi 
73*e1c24b52SMiklos Szeredi 	strcpy(self->root_mntpoint, root_mntpoint_templ);
74*e1c24b52SMiklos Szeredi 	ASSERT_NE(mkdtemp(self->root_mntpoint), NULL);
75*e1c24b52SMiklos Szeredi 
76*e1c24b52SMiklos Szeredi 	self->orig_root = open("/", O_PATH | O_CLOEXEC);
77*e1c24b52SMiklos Szeredi 	ASSERT_GE(self->orig_root, 0);
78*e1c24b52SMiklos Szeredi 
79*e1c24b52SMiklos Szeredi 	ASSERT_EQ(mount("tmpfs", self->root_mntpoint, "tmpfs", 0, NULL), 0);
80*e1c24b52SMiklos Szeredi 
81*e1c24b52SMiklos Szeredi 	ASSERT_EQ(chroot(self->root_mntpoint), 0);
82*e1c24b52SMiklos Szeredi 
83*e1c24b52SMiklos Szeredi 	ASSERT_EQ(chdir("/"), 0);
84*e1c24b52SMiklos Szeredi 
85*e1c24b52SMiklos Szeredi 	ASSERT_EQ(mkdir("a", 0700), 0);
86*e1c24b52SMiklos Szeredi 
87*e1c24b52SMiklos Szeredi 	ASSERT_EQ(mkdir("b", 0700), 0);
88*e1c24b52SMiklos Szeredi 
89*e1c24b52SMiklos Szeredi 	self->root_id = get_mnt_id(_metadata, "/");
90*e1c24b52SMiklos Szeredi 	ASSERT_NE(self->root_id, 0);
91*e1c24b52SMiklos Szeredi 
92*e1c24b52SMiklos Szeredi 	self->fan_fd = fanotify_init(FAN_REPORT_MNT, 0);
93*e1c24b52SMiklos Szeredi 	ASSERT_GE(self->fan_fd, 0);
94*e1c24b52SMiklos Szeredi 
95*e1c24b52SMiklos Szeredi 	ret = fanotify_mark(self->fan_fd, FAN_MARK_ADD | FAN_MARK_MNTNS,
96*e1c24b52SMiklos Szeredi 			    FAN_MNT_ATTACH | FAN_MNT_DETACH, self->ns_fd, NULL);
97*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
98*e1c24b52SMiklos Szeredi 
99*e1c24b52SMiklos Szeredi 	self->rem = 0;
100*e1c24b52SMiklos Szeredi }
101*e1c24b52SMiklos Szeredi 
102*e1c24b52SMiklos Szeredi FIXTURE_TEARDOWN(fanotify)
103*e1c24b52SMiklos Szeredi {
104*e1c24b52SMiklos Szeredi 	ASSERT_EQ(self->rem, 0);
105*e1c24b52SMiklos Szeredi 	close(self->fan_fd);
106*e1c24b52SMiklos Szeredi 
107*e1c24b52SMiklos Szeredi 	ASSERT_EQ(fchdir(self->orig_root), 0);
108*e1c24b52SMiklos Szeredi 
109*e1c24b52SMiklos Szeredi 	ASSERT_EQ(chroot("."), 0);
110*e1c24b52SMiklos Szeredi 
111*e1c24b52SMiklos Szeredi 	EXPECT_EQ(umount2(self->root_mntpoint, MNT_DETACH), 0);
112*e1c24b52SMiklos Szeredi 	EXPECT_EQ(chdir(self->root_mntpoint), 0);
113*e1c24b52SMiklos Szeredi 	EXPECT_EQ(chdir("/"), 0);
114*e1c24b52SMiklos Szeredi 	EXPECT_EQ(rmdir(self->root_mntpoint), 0);
115*e1c24b52SMiklos Szeredi }
116*e1c24b52SMiklos Szeredi 
117*e1c24b52SMiklos Szeredi static uint64_t expect_notify(struct __test_metadata *const _metadata,
118*e1c24b52SMiklos Szeredi 			      FIXTURE_DATA(fanotify) *self,
119*e1c24b52SMiklos Szeredi 			      uint64_t *mask)
120*e1c24b52SMiklos Szeredi {
121*e1c24b52SMiklos Szeredi 	struct fanotify_event_metadata *meta;
122*e1c24b52SMiklos Szeredi 	struct fanotify_event_info_mnt *mnt;
123*e1c24b52SMiklos Szeredi 	unsigned int thislen;
124*e1c24b52SMiklos Szeredi 
125*e1c24b52SMiklos Szeredi 	if (!self->rem) {
126*e1c24b52SMiklos Szeredi 		ssize_t len = read(self->fan_fd, self->buf, sizeof(self->buf));
127*e1c24b52SMiklos Szeredi 		ASSERT_GT(len, 0);
128*e1c24b52SMiklos Szeredi 
129*e1c24b52SMiklos Szeredi 		self->rem = len;
130*e1c24b52SMiklos Szeredi 		self->next = (void *) self->buf;
131*e1c24b52SMiklos Szeredi 	}
132*e1c24b52SMiklos Szeredi 
133*e1c24b52SMiklos Szeredi 	meta = self->next;
134*e1c24b52SMiklos Szeredi 	ASSERT_TRUE(FAN_EVENT_OK(meta, self->rem));
135*e1c24b52SMiklos Szeredi 
136*e1c24b52SMiklos Szeredi 	thislen = meta->event_len;
137*e1c24b52SMiklos Szeredi 	self->rem -= thislen;
138*e1c24b52SMiklos Szeredi 	self->next += thislen;
139*e1c24b52SMiklos Szeredi 
140*e1c24b52SMiklos Szeredi 	*mask = meta->mask;
141*e1c24b52SMiklos Szeredi 	thislen -= sizeof(*meta);
142*e1c24b52SMiklos Szeredi 
143*e1c24b52SMiklos Szeredi 	mnt = ((void *) meta) + meta->event_len - thislen;
144*e1c24b52SMiklos Szeredi 
145*e1c24b52SMiklos Szeredi 	ASSERT_EQ(thislen, sizeof(*mnt));
146*e1c24b52SMiklos Szeredi 
147*e1c24b52SMiklos Szeredi 	return mnt->mnt_id;
148*e1c24b52SMiklos Szeredi }
149*e1c24b52SMiklos Szeredi 
150*e1c24b52SMiklos Szeredi static void expect_notify_n(struct __test_metadata *const _metadata,
151*e1c24b52SMiklos Szeredi 				 FIXTURE_DATA(fanotify) *self,
152*e1c24b52SMiklos Szeredi 				 unsigned int n, uint64_t mask[], uint64_t mnts[])
153*e1c24b52SMiklos Szeredi {
154*e1c24b52SMiklos Szeredi 	unsigned int i;
155*e1c24b52SMiklos Szeredi 
156*e1c24b52SMiklos Szeredi 	for (i = 0; i < n; i++)
157*e1c24b52SMiklos Szeredi 		mnts[i] = expect_notify(_metadata, self, &mask[i]);
158*e1c24b52SMiklos Szeredi }
159*e1c24b52SMiklos Szeredi 
160*e1c24b52SMiklos Szeredi static uint64_t expect_notify_mask(struct __test_metadata *const _metadata,
161*e1c24b52SMiklos Szeredi 				   FIXTURE_DATA(fanotify) *self,
162*e1c24b52SMiklos Szeredi 				   uint64_t expect_mask)
163*e1c24b52SMiklos Szeredi {
164*e1c24b52SMiklos Szeredi 	uint64_t mntid, mask;
165*e1c24b52SMiklos Szeredi 
166*e1c24b52SMiklos Szeredi 	mntid = expect_notify(_metadata, self, &mask);
167*e1c24b52SMiklos Szeredi 	ASSERT_EQ(expect_mask, mask);
168*e1c24b52SMiklos Szeredi 
169*e1c24b52SMiklos Szeredi 	return mntid;
170*e1c24b52SMiklos Szeredi }
171*e1c24b52SMiklos Szeredi 
172*e1c24b52SMiklos Szeredi 
173*e1c24b52SMiklos Szeredi static void expect_notify_mask_n(struct __test_metadata *const _metadata,
174*e1c24b52SMiklos Szeredi 				 FIXTURE_DATA(fanotify) *self,
175*e1c24b52SMiklos Szeredi 				 uint64_t mask, unsigned int n, uint64_t mnts[])
176*e1c24b52SMiklos Szeredi {
177*e1c24b52SMiklos Szeredi 	unsigned int i;
178*e1c24b52SMiklos Szeredi 
179*e1c24b52SMiklos Szeredi 	for (i = 0; i < n; i++)
180*e1c24b52SMiklos Szeredi 		mnts[i] = expect_notify_mask(_metadata, self, mask);
181*e1c24b52SMiklos Szeredi }
182*e1c24b52SMiklos Szeredi 
183*e1c24b52SMiklos Szeredi static void verify_mount_ids(struct __test_metadata *const _metadata,
184*e1c24b52SMiklos Szeredi 			     const uint64_t list1[], const uint64_t list2[],
185*e1c24b52SMiklos Szeredi 			     size_t num)
186*e1c24b52SMiklos Szeredi {
187*e1c24b52SMiklos Szeredi 	unsigned int i, j;
188*e1c24b52SMiklos Szeredi 
189*e1c24b52SMiklos Szeredi 	// Check that neither list has any duplicates
190*e1c24b52SMiklos Szeredi 	for (i = 0; i < num; i++) {
191*e1c24b52SMiklos Szeredi 		for (j = 0; j < num; j++) {
192*e1c24b52SMiklos Szeredi 			if (i != j) {
193*e1c24b52SMiklos Szeredi 				ASSERT_NE(list1[i], list1[j]);
194*e1c24b52SMiklos Szeredi 				ASSERT_NE(list2[i], list2[j]);
195*e1c24b52SMiklos Szeredi 			}
196*e1c24b52SMiklos Szeredi 		}
197*e1c24b52SMiklos Szeredi 	}
198*e1c24b52SMiklos Szeredi 	// Check that all list1 memebers can be found in list2. Together with
199*e1c24b52SMiklos Szeredi 	// the above it means that the list1 and list2 represent the same sets.
200*e1c24b52SMiklos Szeredi 	for (i = 0; i < num; i++) {
201*e1c24b52SMiklos Szeredi 		for (j = 0; j < num; j++) {
202*e1c24b52SMiklos Szeredi 			if (list1[i] == list2[j])
203*e1c24b52SMiklos Szeredi 				break;
204*e1c24b52SMiklos Szeredi 		}
205*e1c24b52SMiklos Szeredi 		ASSERT_NE(j, num);
206*e1c24b52SMiklos Szeredi 	}
207*e1c24b52SMiklos Szeredi }
208*e1c24b52SMiklos Szeredi 
209*e1c24b52SMiklos Szeredi static void check_mounted(struct __test_metadata *const _metadata,
210*e1c24b52SMiklos Szeredi 			  const uint64_t mnts[], size_t num)
211*e1c24b52SMiklos Szeredi {
212*e1c24b52SMiklos Szeredi 	ssize_t ret;
213*e1c24b52SMiklos Szeredi 	uint64_t *list;
214*e1c24b52SMiklos Szeredi 
215*e1c24b52SMiklos Szeredi 	list = malloc((num + 1) * sizeof(list[0]));
216*e1c24b52SMiklos Szeredi 	ASSERT_NE(list, NULL);
217*e1c24b52SMiklos Szeredi 
218*e1c24b52SMiklos Szeredi 	ret = listmount(LSMT_ROOT, 0, 0, list, num + 1, 0);
219*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, num);
220*e1c24b52SMiklos Szeredi 
221*e1c24b52SMiklos Szeredi 	verify_mount_ids(_metadata, mnts, list, num);
222*e1c24b52SMiklos Szeredi 
223*e1c24b52SMiklos Szeredi 	free(list);
224*e1c24b52SMiklos Szeredi }
225*e1c24b52SMiklos Szeredi 
226*e1c24b52SMiklos Szeredi static void setup_mount_tree(struct __test_metadata *const _metadata,
227*e1c24b52SMiklos Szeredi 			    int log2_num)
228*e1c24b52SMiklos Szeredi {
229*e1c24b52SMiklos Szeredi 	int ret, i;
230*e1c24b52SMiklos Szeredi 
231*e1c24b52SMiklos Szeredi 	ret = mount("", "/", NULL, MS_SHARED, NULL);
232*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
233*e1c24b52SMiklos Szeredi 
234*e1c24b52SMiklos Szeredi 	for (i = 0; i < log2_num; i++) {
235*e1c24b52SMiklos Szeredi 		ret = mount("/", "/", NULL, MS_BIND, NULL);
236*e1c24b52SMiklos Szeredi 		ASSERT_EQ(ret, 0);
237*e1c24b52SMiklos Szeredi 	}
238*e1c24b52SMiklos Szeredi }
239*e1c24b52SMiklos Szeredi 
240*e1c24b52SMiklos Szeredi TEST_F(fanotify, bind)
241*e1c24b52SMiklos Szeredi {
242*e1c24b52SMiklos Szeredi 	int ret;
243*e1c24b52SMiklos Szeredi 	uint64_t mnts[2] = { self->root_id };
244*e1c24b52SMiklos Szeredi 
245*e1c24b52SMiklos Szeredi 	ret = mount("/", "/", NULL, MS_BIND, NULL);
246*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
247*e1c24b52SMiklos Szeredi 
248*e1c24b52SMiklos Szeredi 	mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
249*e1c24b52SMiklos Szeredi 	ASSERT_NE(mnts[0], mnts[1]);
250*e1c24b52SMiklos Szeredi 
251*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 2);
252*e1c24b52SMiklos Szeredi 
253*e1c24b52SMiklos Szeredi 	// Cleanup
254*e1c24b52SMiklos Szeredi 	uint64_t detach_id;
255*e1c24b52SMiklos Szeredi 	ret = umount("/");
256*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
257*e1c24b52SMiklos Szeredi 
258*e1c24b52SMiklos Szeredi 	detach_id = expect_notify_mask(_metadata, self, FAN_MNT_DETACH);
259*e1c24b52SMiklos Szeredi 	ASSERT_EQ(detach_id, mnts[1]);
260*e1c24b52SMiklos Szeredi 
261*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
262*e1c24b52SMiklos Szeredi }
263*e1c24b52SMiklos Szeredi 
264*e1c24b52SMiklos Szeredi TEST_F(fanotify, move)
265*e1c24b52SMiklos Szeredi {
266*e1c24b52SMiklos Szeredi 	int ret;
267*e1c24b52SMiklos Szeredi 	uint64_t mnts[2] = { self->root_id };
268*e1c24b52SMiklos Szeredi 	uint64_t move_id;
269*e1c24b52SMiklos Szeredi 
270*e1c24b52SMiklos Szeredi 	ret = mount("/", "/a", NULL, MS_BIND, NULL);
271*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
272*e1c24b52SMiklos Szeredi 
273*e1c24b52SMiklos Szeredi 	mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
274*e1c24b52SMiklos Szeredi 	ASSERT_NE(mnts[0], mnts[1]);
275*e1c24b52SMiklos Szeredi 
276*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 2);
277*e1c24b52SMiklos Szeredi 
278*e1c24b52SMiklos Szeredi 	ret = move_mount(AT_FDCWD, "/a", AT_FDCWD, "/b", 0);
279*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
280*e1c24b52SMiklos Szeredi 
281*e1c24b52SMiklos Szeredi 	move_id = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH | FAN_MNT_DETACH);
282*e1c24b52SMiklos Szeredi 	ASSERT_EQ(move_id, mnts[1]);
283*e1c24b52SMiklos Szeredi 
284*e1c24b52SMiklos Szeredi 	// Cleanup
285*e1c24b52SMiklos Szeredi 	ret = umount("/b");
286*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
287*e1c24b52SMiklos Szeredi 
288*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
289*e1c24b52SMiklos Szeredi }
290*e1c24b52SMiklos Szeredi 
291*e1c24b52SMiklos Szeredi TEST_F(fanotify, propagate)
292*e1c24b52SMiklos Szeredi {
293*e1c24b52SMiklos Szeredi 	const unsigned int log2_num = 4;
294*e1c24b52SMiklos Szeredi 	const unsigned int num = (1 << log2_num);
295*e1c24b52SMiklos Szeredi 	uint64_t mnts[num];
296*e1c24b52SMiklos Szeredi 
297*e1c24b52SMiklos Szeredi 	setup_mount_tree(_metadata, log2_num);
298*e1c24b52SMiklos Szeredi 
299*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, num - 1, mnts + 1);
300*e1c24b52SMiklos Szeredi 
301*e1c24b52SMiklos Szeredi 	mnts[0] = self->root_id;
302*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, num);
303*e1c24b52SMiklos Szeredi 
304*e1c24b52SMiklos Szeredi 	// Cleanup
305*e1c24b52SMiklos Szeredi 	int ret;
306*e1c24b52SMiklos Szeredi 	uint64_t mnts2[num];
307*e1c24b52SMiklos Szeredi 	ret = umount2("/", MNT_DETACH);
308*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
309*e1c24b52SMiklos Szeredi 
310*e1c24b52SMiklos Szeredi 	ret = mount("", "/", NULL, MS_PRIVATE, NULL);
311*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
312*e1c24b52SMiklos Szeredi 
313*e1c24b52SMiklos Szeredi 	mnts2[0] = self->root_id;
314*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_DETACH, num - 1, mnts2 + 1);
315*e1c24b52SMiklos Szeredi 	verify_mount_ids(_metadata, mnts, mnts2, num);
316*e1c24b52SMiklos Szeredi 
317*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
318*e1c24b52SMiklos Szeredi }
319*e1c24b52SMiklos Szeredi 
320*e1c24b52SMiklos Szeredi TEST_F(fanotify, fsmount)
321*e1c24b52SMiklos Szeredi {
322*e1c24b52SMiklos Szeredi 	int ret, fs, mnt;
323*e1c24b52SMiklos Szeredi 	uint64_t mnts[2] = { self->root_id };
324*e1c24b52SMiklos Szeredi 
325*e1c24b52SMiklos Szeredi 	fs = fsopen("tmpfs", 0);
326*e1c24b52SMiklos Szeredi 	ASSERT_GE(fs, 0);
327*e1c24b52SMiklos Szeredi 
328*e1c24b52SMiklos Szeredi         ret = fsconfig(fs, FSCONFIG_CMD_CREATE, 0, 0, 0);
329*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
330*e1c24b52SMiklos Szeredi 
331*e1c24b52SMiklos Szeredi         mnt = fsmount(fs, 0, 0);
332*e1c24b52SMiklos Szeredi 	ASSERT_GE(mnt, 0);
333*e1c24b52SMiklos Szeredi 
334*e1c24b52SMiklos Szeredi         close(fs);
335*e1c24b52SMiklos Szeredi 
336*e1c24b52SMiklos Szeredi 	ret = move_mount(mnt, "", AT_FDCWD, "/a", MOVE_MOUNT_F_EMPTY_PATH);
337*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
338*e1c24b52SMiklos Szeredi 
339*e1c24b52SMiklos Szeredi         close(mnt);
340*e1c24b52SMiklos Szeredi 
341*e1c24b52SMiklos Szeredi 	mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
342*e1c24b52SMiklos Szeredi 	ASSERT_NE(mnts[0], mnts[1]);
343*e1c24b52SMiklos Szeredi 
344*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 2);
345*e1c24b52SMiklos Szeredi 
346*e1c24b52SMiklos Szeredi 	// Cleanup
347*e1c24b52SMiklos Szeredi 	uint64_t detach_id;
348*e1c24b52SMiklos Szeredi 	ret = umount("/a");
349*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
350*e1c24b52SMiklos Szeredi 
351*e1c24b52SMiklos Szeredi 	detach_id = expect_notify_mask(_metadata, self, FAN_MNT_DETACH);
352*e1c24b52SMiklos Szeredi 	ASSERT_EQ(detach_id, mnts[1]);
353*e1c24b52SMiklos Szeredi 
354*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
355*e1c24b52SMiklos Szeredi }
356*e1c24b52SMiklos Szeredi 
357*e1c24b52SMiklos Szeredi TEST_F(fanotify, reparent)
358*e1c24b52SMiklos Szeredi {
359*e1c24b52SMiklos Szeredi 	uint64_t mnts[6] = { self->root_id };
360*e1c24b52SMiklos Szeredi 	uint64_t dmnts[3];
361*e1c24b52SMiklos Szeredi 	uint64_t masks[3];
362*e1c24b52SMiklos Szeredi 	unsigned int i;
363*e1c24b52SMiklos Szeredi 	int ret;
364*e1c24b52SMiklos Szeredi 
365*e1c24b52SMiklos Szeredi 	// Create setup with a[1] -> b[2] propagation
366*e1c24b52SMiklos Szeredi 	ret = mount("/", "/a", NULL, MS_BIND, NULL);
367*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
368*e1c24b52SMiklos Szeredi 
369*e1c24b52SMiklos Szeredi 	ret = mount("", "/a", NULL, MS_SHARED, NULL);
370*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
371*e1c24b52SMiklos Szeredi 
372*e1c24b52SMiklos Szeredi 	ret = mount("/a", "/b", NULL, MS_BIND, NULL);
373*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
374*e1c24b52SMiklos Szeredi 
375*e1c24b52SMiklos Szeredi 	ret = mount("", "/b", NULL, MS_SLAVE, NULL);
376*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
377*e1c24b52SMiklos Szeredi 
378*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, 2, mnts + 1);
379*e1c24b52SMiklos Szeredi 
380*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 3);
381*e1c24b52SMiklos Szeredi 
382*e1c24b52SMiklos Szeredi 	// Mount on a[3], which is propagated to b[4]
383*e1c24b52SMiklos Szeredi 	ret = mount("/", "/a", NULL, MS_BIND, NULL);
384*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
385*e1c24b52SMiklos Szeredi 
386*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, 2, mnts + 3);
387*e1c24b52SMiklos Szeredi 
388*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 5);
389*e1c24b52SMiklos Szeredi 
390*e1c24b52SMiklos Szeredi 	// Mount on b[5], not propagated
391*e1c24b52SMiklos Szeredi 	ret = mount("/", "/b", NULL, MS_BIND, NULL);
392*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
393*e1c24b52SMiklos Szeredi 
394*e1c24b52SMiklos Szeredi 	mnts[5] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
395*e1c24b52SMiklos Szeredi 
396*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 6);
397*e1c24b52SMiklos Szeredi 
398*e1c24b52SMiklos Szeredi 	// Umount a[3], which is propagated to b[4], but not b[5]
399*e1c24b52SMiklos Szeredi 	// This will result in b[5] "falling" on b[2]
400*e1c24b52SMiklos Szeredi 	ret = umount("/a");
401*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
402*e1c24b52SMiklos Szeredi 
403*e1c24b52SMiklos Szeredi 	expect_notify_n(_metadata, self, 3, masks, dmnts);
404*e1c24b52SMiklos Szeredi 	verify_mount_ids(_metadata, mnts + 3, dmnts, 3);
405*e1c24b52SMiklos Szeredi 
406*e1c24b52SMiklos Szeredi 	for (i = 0; i < 3; i++) {
407*e1c24b52SMiklos Szeredi 		if (dmnts[i] == mnts[5]) {
408*e1c24b52SMiklos Szeredi 			ASSERT_EQ(masks[i], FAN_MNT_ATTACH | FAN_MNT_DETACH);
409*e1c24b52SMiklos Szeredi 		} else {
410*e1c24b52SMiklos Szeredi 			ASSERT_EQ(masks[i], FAN_MNT_DETACH);
411*e1c24b52SMiklos Szeredi 		}
412*e1c24b52SMiklos Szeredi 	}
413*e1c24b52SMiklos Szeredi 
414*e1c24b52SMiklos Szeredi 	mnts[3] = mnts[5];
415*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 4);
416*e1c24b52SMiklos Szeredi 
417*e1c24b52SMiklos Szeredi 	// Cleanup
418*e1c24b52SMiklos Szeredi 	ret = umount("/b");
419*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
420*e1c24b52SMiklos Szeredi 
421*e1c24b52SMiklos Szeredi 	ret = umount("/a");
422*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
423*e1c24b52SMiklos Szeredi 
424*e1c24b52SMiklos Szeredi 	ret = umount("/b");
425*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
426*e1c24b52SMiklos Szeredi 
427*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_DETACH, 3, dmnts);
428*e1c24b52SMiklos Szeredi 	verify_mount_ids(_metadata, mnts + 1, dmnts, 3);
429*e1c24b52SMiklos Szeredi 
430*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
431*e1c24b52SMiklos Szeredi }
432*e1c24b52SMiklos Szeredi 
433*e1c24b52SMiklos Szeredi TEST_F(fanotify, rmdir)
434*e1c24b52SMiklos Szeredi {
435*e1c24b52SMiklos Szeredi 	uint64_t mnts[3] = { self->root_id };
436*e1c24b52SMiklos Szeredi 	int ret;
437*e1c24b52SMiklos Szeredi 
438*e1c24b52SMiklos Szeredi 	ret = mount("/", "/a", NULL, MS_BIND, NULL);
439*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
440*e1c24b52SMiklos Szeredi 
441*e1c24b52SMiklos Szeredi 	ret = mount("/", "/a/b", NULL, MS_BIND, NULL);
442*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
443*e1c24b52SMiklos Szeredi 
444*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH, 2, mnts + 1);
445*e1c24b52SMiklos Szeredi 
446*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 3);
447*e1c24b52SMiklos Szeredi 
448*e1c24b52SMiklos Szeredi 	ret = chdir("/a");
449*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
450*e1c24b52SMiklos Szeredi 
451*e1c24b52SMiklos Szeredi 	ret = fork();
452*e1c24b52SMiklos Szeredi 	ASSERT_GE(ret, 0);
453*e1c24b52SMiklos Szeredi 
454*e1c24b52SMiklos Szeredi 	if (ret == 0) {
455*e1c24b52SMiklos Szeredi 		chdir("/");
456*e1c24b52SMiklos Szeredi 		unshare(CLONE_NEWNS);
457*e1c24b52SMiklos Szeredi 		mount("", "/", NULL, MS_REC|MS_PRIVATE, NULL);
458*e1c24b52SMiklos Szeredi 		umount2("/a", MNT_DETACH);
459*e1c24b52SMiklos Szeredi 		// This triggers a detach in the other namespace
460*e1c24b52SMiklos Szeredi 		rmdir("/a");
461*e1c24b52SMiklos Szeredi 		exit(0);
462*e1c24b52SMiklos Szeredi 	}
463*e1c24b52SMiklos Szeredi 	wait(NULL);
464*e1c24b52SMiklos Szeredi 
465*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_DETACH, 2, mnts + 1);
466*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
467*e1c24b52SMiklos Szeredi 
468*e1c24b52SMiklos Szeredi 	// Cleanup
469*e1c24b52SMiklos Szeredi 	ret = chdir("/");
470*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
471*e1c24b52SMiklos Szeredi }
472*e1c24b52SMiklos Szeredi 
473*e1c24b52SMiklos Szeredi TEST_F(fanotify, pivot_root)
474*e1c24b52SMiklos Szeredi {
475*e1c24b52SMiklos Szeredi 	uint64_t mnts[3] = { self->root_id };
476*e1c24b52SMiklos Szeredi 	uint64_t mnts2[3];
477*e1c24b52SMiklos Szeredi 	int ret;
478*e1c24b52SMiklos Szeredi 
479*e1c24b52SMiklos Szeredi 	ret = mount("tmpfs", "/a", "tmpfs", 0, NULL);
480*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
481*e1c24b52SMiklos Szeredi 
482*e1c24b52SMiklos Szeredi 	mnts[2] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
483*e1c24b52SMiklos Szeredi 
484*e1c24b52SMiklos Szeredi 	ret = mkdir("/a/new", 0700);
485*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
486*e1c24b52SMiklos Szeredi 
487*e1c24b52SMiklos Szeredi 	ret = mkdir("/a/old", 0700);
488*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
489*e1c24b52SMiklos Szeredi 
490*e1c24b52SMiklos Szeredi 	ret = mount("/a", "/a/new", NULL, MS_BIND, NULL);
491*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
492*e1c24b52SMiklos Szeredi 
493*e1c24b52SMiklos Szeredi 	mnts[1] = expect_notify_mask(_metadata, self, FAN_MNT_ATTACH);
494*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 3);
495*e1c24b52SMiklos Szeredi 
496*e1c24b52SMiklos Szeredi 	ret = syscall(SYS_pivot_root, "/a/new", "/a/new/old");
497*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
498*e1c24b52SMiklos Szeredi 
499*e1c24b52SMiklos Szeredi 	expect_notify_mask_n(_metadata, self, FAN_MNT_ATTACH | FAN_MNT_DETACH, 2, mnts2);
500*e1c24b52SMiklos Szeredi 	verify_mount_ids(_metadata, mnts, mnts2, 2);
501*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 3);
502*e1c24b52SMiklos Szeredi 
503*e1c24b52SMiklos Szeredi 	// Cleanup
504*e1c24b52SMiklos Szeredi 	ret = syscall(SYS_pivot_root, "/old", "/old/a/new");
505*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
506*e1c24b52SMiklos Szeredi 
507*e1c24b52SMiklos Szeredi 	ret = umount("/a/new");
508*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
509*e1c24b52SMiklos Szeredi 
510*e1c24b52SMiklos Szeredi 	ret = umount("/a");
511*e1c24b52SMiklos Szeredi 	ASSERT_EQ(ret, 0);
512*e1c24b52SMiklos Szeredi 
513*e1c24b52SMiklos Szeredi 	check_mounted(_metadata, mnts, 1);
514*e1c24b52SMiklos Szeredi }
515*e1c24b52SMiklos Szeredi 
516*e1c24b52SMiklos Szeredi TEST_HARNESS_MAIN
517