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