xref: /linux/tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
1af919914SChristian Brauner // SPDX-License-Identifier: GPL-2.0
2af919914SChristian Brauner #define _GNU_SOURCE
3af919914SChristian Brauner #define __SANE_USERSPACE_TYPES__ // Use ll64
4af919914SChristian Brauner 
5af919914SChristian Brauner #include <fcntl.h>
6af919914SChristian Brauner #include <sched.h>
7af919914SChristian Brauner #include <stdio.h>
8af919914SChristian Brauner #include <string.h>
9af919914SChristian Brauner #include <sys/stat.h>
10af919914SChristian Brauner #include <sys/mount.h>
11af919914SChristian Brauner #include <unistd.h>
12af919914SChristian Brauner 
13af919914SChristian Brauner #include "../../kselftest_harness.h"
14af919914SChristian Brauner #include "log.h"
15af919914SChristian Brauner #include "wrappers.h"
16af919914SChristian Brauner 
17af919914SChristian Brauner FIXTURE(set_layers_via_fds) {
18af919914SChristian Brauner };
19af919914SChristian Brauner 
20af919914SChristian Brauner FIXTURE_SETUP(set_layers_via_fds)
21af919914SChristian Brauner {
22af919914SChristian Brauner 	ASSERT_EQ(mkdir("/set_layers_via_fds", 0755), 0);
23af919914SChristian Brauner }
24af919914SChristian Brauner 
25af919914SChristian Brauner FIXTURE_TEARDOWN(set_layers_via_fds)
26af919914SChristian Brauner {
27af919914SChristian Brauner 	umount2("/set_layers_via_fds", 0);
28af919914SChristian Brauner 	ASSERT_EQ(rmdir("/set_layers_via_fds"), 0);
29af919914SChristian Brauner }
30af919914SChristian Brauner 
31af919914SChristian Brauner TEST_F(set_layers_via_fds, set_layers_via_fds)
32af919914SChristian Brauner {
33af919914SChristian Brauner 	int fd_context, fd_tmpfs, fd_overlay;
34af919914SChristian Brauner 	int layer_fds[] = { [0 ... 8] = -EBADF };
35af919914SChristian Brauner 	bool layers_found[] = { [0 ... 8] =  false };
36af919914SChristian Brauner 	size_t len = 0;
37af919914SChristian Brauner 	char *line = NULL;
38af919914SChristian Brauner 	FILE *f_mountinfo;
39af919914SChristian Brauner 
40af919914SChristian Brauner 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
41af919914SChristian Brauner 	ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);
42af919914SChristian Brauner 
43af919914SChristian Brauner 	fd_context = sys_fsopen("tmpfs", 0);
44af919914SChristian Brauner 	ASSERT_GE(fd_context, 0);
45af919914SChristian Brauner 
46af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
47af919914SChristian Brauner 	fd_tmpfs = sys_fsmount(fd_context, 0, 0);
48af919914SChristian Brauner 	ASSERT_GE(fd_tmpfs, 0);
49af919914SChristian Brauner 	ASSERT_EQ(close(fd_context), 0);
50af919914SChristian Brauner 
51af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "w", 0755), 0);
52af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0);
53af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "l1", 0755), 0);
54af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "l2", 0755), 0);
55af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "l3", 0755), 0);
56af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "l4", 0755), 0);
57af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "d1", 0755), 0);
58af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "d2", 0755), 0);
59af919914SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "d3", 0755), 0);
60af919914SChristian Brauner 
61af919914SChristian Brauner 	layer_fds[0] = openat(fd_tmpfs, "w", O_DIRECTORY);
62af919914SChristian Brauner 	ASSERT_GE(layer_fds[0], 0);
63af919914SChristian Brauner 
64af919914SChristian Brauner 	layer_fds[1] = openat(fd_tmpfs, "u", O_DIRECTORY);
65af919914SChristian Brauner 	ASSERT_GE(layer_fds[1], 0);
66af919914SChristian Brauner 
67af919914SChristian Brauner 	layer_fds[2] = openat(fd_tmpfs, "l1", O_DIRECTORY);
68af919914SChristian Brauner 	ASSERT_GE(layer_fds[2], 0);
69af919914SChristian Brauner 
70af919914SChristian Brauner 	layer_fds[3] = openat(fd_tmpfs, "l2", O_DIRECTORY);
71af919914SChristian Brauner 	ASSERT_GE(layer_fds[3], 0);
72af919914SChristian Brauner 
73af919914SChristian Brauner 	layer_fds[4] = openat(fd_tmpfs, "l3", O_DIRECTORY);
74af919914SChristian Brauner 	ASSERT_GE(layer_fds[4], 0);
75af919914SChristian Brauner 
76af919914SChristian Brauner 	layer_fds[5] = openat(fd_tmpfs, "l4", O_DIRECTORY);
77af919914SChristian Brauner 	ASSERT_GE(layer_fds[5], 0);
78af919914SChristian Brauner 
79af919914SChristian Brauner 	layer_fds[6] = openat(fd_tmpfs, "d1", O_DIRECTORY);
80af919914SChristian Brauner 	ASSERT_GE(layer_fds[6], 0);
81af919914SChristian Brauner 
82af919914SChristian Brauner 	layer_fds[7] = openat(fd_tmpfs, "d2", O_DIRECTORY);
83af919914SChristian Brauner 	ASSERT_GE(layer_fds[7], 0);
84af919914SChristian Brauner 
85af919914SChristian Brauner 	layer_fds[8] = openat(fd_tmpfs, "d3", O_DIRECTORY);
86af919914SChristian Brauner 	ASSERT_GE(layer_fds[8], 0);
87af919914SChristian Brauner 
88af919914SChristian Brauner 	ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/tmp", MOVE_MOUNT_F_EMPTY_PATH), 0);
89af919914SChristian Brauner 	ASSERT_EQ(close(fd_tmpfs), 0);
90af919914SChristian Brauner 
91af919914SChristian Brauner 	fd_context = sys_fsopen("overlay", 0);
92af919914SChristian Brauner 	ASSERT_GE(fd_context, 0);
93af919914SChristian Brauner 
94af919914SChristian Brauner 	ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir", NULL, layer_fds[2]), 0);
95af919914SChristian Brauner 
96af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir",   NULL, layer_fds[0]), 0);
97af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir",  NULL, layer_fds[1]), 0);
98af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[2]), 0);
99af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[3]), 0);
100af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[4]), 0);
101af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[5]), 0);
102af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+",  NULL, layer_fds[6]), 0);
103af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+",  NULL, layer_fds[7]), 0);
104af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+",  NULL, layer_fds[8]), 0);
105af919914SChristian Brauner 
106af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_STRING, "metacopy", "on", 0), 0);
107af919914SChristian Brauner 
108af919914SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
109af919914SChristian Brauner 
110af919914SChristian Brauner 	fd_overlay = sys_fsmount(fd_context, 0, 0);
111af919914SChristian Brauner 	ASSERT_GE(fd_overlay, 0);
112af919914SChristian Brauner 
113af919914SChristian Brauner 	ASSERT_EQ(sys_move_mount(fd_overlay, "", -EBADF, "/set_layers_via_fds", MOVE_MOUNT_F_EMPTY_PATH), 0);
114af919914SChristian Brauner 
115af919914SChristian Brauner 	f_mountinfo = fopen("/proc/self/mountinfo", "r");
116af919914SChristian Brauner 	ASSERT_NE(f_mountinfo, NULL);
117af919914SChristian Brauner 
118af919914SChristian Brauner 	while (getline(&line, &len, f_mountinfo) != -1) {
119af919914SChristian Brauner 		char *haystack = line;
120af919914SChristian Brauner 
121af919914SChristian Brauner 		if (strstr(haystack, "workdir=/tmp/w"))
122af919914SChristian Brauner 			layers_found[0] = true;
123af919914SChristian Brauner 		if (strstr(haystack, "upperdir=/tmp/u"))
124af919914SChristian Brauner 			layers_found[1] = true;
125af919914SChristian Brauner 		if (strstr(haystack, "lowerdir+=/tmp/l1"))
126af919914SChristian Brauner 			layers_found[2] = true;
127af919914SChristian Brauner 		if (strstr(haystack, "lowerdir+=/tmp/l2"))
128af919914SChristian Brauner 			layers_found[3] = true;
129af919914SChristian Brauner 		if (strstr(haystack, "lowerdir+=/tmp/l3"))
130af919914SChristian Brauner 			layers_found[4] = true;
131af919914SChristian Brauner 		if (strstr(haystack, "lowerdir+=/tmp/l4"))
132af919914SChristian Brauner 			layers_found[5] = true;
133af919914SChristian Brauner 		if (strstr(haystack, "datadir+=/tmp/d1"))
134af919914SChristian Brauner 			layers_found[6] = true;
135af919914SChristian Brauner 		if (strstr(haystack, "datadir+=/tmp/d2"))
136af919914SChristian Brauner 			layers_found[7] = true;
137af919914SChristian Brauner 		if (strstr(haystack, "datadir+=/tmp/d3"))
138af919914SChristian Brauner 			layers_found[8] = true;
139af919914SChristian Brauner 	}
140af919914SChristian Brauner 	free(line);
141af919914SChristian Brauner 
142af919914SChristian Brauner 	for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
143af919914SChristian Brauner 		ASSERT_EQ(layers_found[i], true);
144af919914SChristian Brauner 		ASSERT_EQ(close(layer_fds[i]), 0);
145af919914SChristian Brauner 	}
146af919914SChristian Brauner 
147af919914SChristian Brauner 	ASSERT_EQ(close(fd_context), 0);
148af919914SChristian Brauner 	ASSERT_EQ(close(fd_overlay), 0);
149af919914SChristian Brauner 	ASSERT_EQ(fclose(f_mountinfo), 0);
150af919914SChristian Brauner }
151af919914SChristian Brauner 
152*d59dfd62SChristian Brauner TEST_F(set_layers_via_fds, set_500_layers_via_fds)
153*d59dfd62SChristian Brauner {
154*d59dfd62SChristian Brauner 	int fd_context, fd_tmpfs, fd_overlay, fd_work, fd_upper, fd_lower;
155*d59dfd62SChristian Brauner 	int layer_fds[500] = { [0 ... 499] = -EBADF };
156*d59dfd62SChristian Brauner 
157*d59dfd62SChristian Brauner 	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
158*d59dfd62SChristian Brauner 	ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);
159*d59dfd62SChristian Brauner 
160*d59dfd62SChristian Brauner 	fd_context = sys_fsopen("tmpfs", 0);
161*d59dfd62SChristian Brauner 	ASSERT_GE(fd_context, 0);
162*d59dfd62SChristian Brauner 
163*d59dfd62SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
164*d59dfd62SChristian Brauner 	fd_tmpfs = sys_fsmount(fd_context, 0, 0);
165*d59dfd62SChristian Brauner 	ASSERT_GE(fd_tmpfs, 0);
166*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_context), 0);
167*d59dfd62SChristian Brauner 
168*d59dfd62SChristian Brauner 	for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
169*d59dfd62SChristian Brauner 		char path[100];
170*d59dfd62SChristian Brauner 
171*d59dfd62SChristian Brauner 		sprintf(path, "l%d", i);
172*d59dfd62SChristian Brauner 		ASSERT_EQ(mkdirat(fd_tmpfs, path, 0755), 0);
173*d59dfd62SChristian Brauner 		layer_fds[i] = openat(fd_tmpfs, path, O_DIRECTORY);
174*d59dfd62SChristian Brauner 		ASSERT_GE(layer_fds[i], 0);
175*d59dfd62SChristian Brauner 	}
176*d59dfd62SChristian Brauner 
177*d59dfd62SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "w", 0755), 0);
178*d59dfd62SChristian Brauner 	fd_work = openat(fd_tmpfs, "w", O_DIRECTORY);
179*d59dfd62SChristian Brauner 	ASSERT_GE(fd_work, 0);
180*d59dfd62SChristian Brauner 
181*d59dfd62SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0);
182*d59dfd62SChristian Brauner 	fd_upper = openat(fd_tmpfs, "u", O_DIRECTORY);
183*d59dfd62SChristian Brauner 	ASSERT_GE(fd_upper, 0);
184*d59dfd62SChristian Brauner 
185*d59dfd62SChristian Brauner 	ASSERT_EQ(mkdirat(fd_tmpfs, "l501", 0755), 0);
186*d59dfd62SChristian Brauner 	fd_lower = openat(fd_tmpfs, "l501", O_DIRECTORY);
187*d59dfd62SChristian Brauner 	ASSERT_GE(fd_lower, 0);
188*d59dfd62SChristian Brauner 
189*d59dfd62SChristian Brauner 	ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/tmp", MOVE_MOUNT_F_EMPTY_PATH), 0);
190*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_tmpfs), 0);
191*d59dfd62SChristian Brauner 
192*d59dfd62SChristian Brauner 	fd_context = sys_fsopen("overlay", 0);
193*d59dfd62SChristian Brauner 	ASSERT_GE(fd_context, 0);
194*d59dfd62SChristian Brauner 
195*d59dfd62SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir",   NULL, fd_work), 0);
196*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_work), 0);
197*d59dfd62SChristian Brauner 
198*d59dfd62SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir",  NULL, fd_upper), 0);
199*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_upper), 0);
200*d59dfd62SChristian Brauner 
201*d59dfd62SChristian Brauner 	for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
202*d59dfd62SChristian Brauner 		ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[i]), 0);
203*d59dfd62SChristian Brauner 		ASSERT_EQ(close(layer_fds[i]), 0);
204*d59dfd62SChristian Brauner 	}
205*d59dfd62SChristian Brauner 
206*d59dfd62SChristian Brauner 	ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower), 0);
207*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_lower), 0);
208*d59dfd62SChristian Brauner 
209*d59dfd62SChristian Brauner 	ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
210*d59dfd62SChristian Brauner 
211*d59dfd62SChristian Brauner 	fd_overlay = sys_fsmount(fd_context, 0, 0);
212*d59dfd62SChristian Brauner 	ASSERT_GE(fd_overlay, 0);
213*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_context), 0);
214*d59dfd62SChristian Brauner 	ASSERT_EQ(close(fd_overlay), 0);
215*d59dfd62SChristian Brauner }
216*d59dfd62SChristian Brauner 
217af919914SChristian Brauner TEST_HARNESS_MAIN
218