sys/vfs/hammer2: Remove obsolete comments on hidden inode
[dragonfly.git] / usr.bin / dsynth / mount.c
blob8344891ecc157eddf8d72c6d68d1157246a997da
1 /*
2 * Copyright (c) 2019-2022 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * This code uses concepts and configuration based on 'synth', by
8 * John R. Marino <draco@marino.st>, which was written in ada.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 * 3. Neither the name of The DragonFly Project nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific, prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
37 #include "dsynth.h"
39 static void domount(worker_t *work, int type,
40 const char *spath, const char *dpath,
41 const char *discretefmt);
42 static void dounmount(worker_t *work, const char *rpath);
43 static void makeDiscreteCopies(const char *spath, const char *discretefmt);
46 * Called by the frontend to create a template which will be cpdup'd
47 * into fresh workers.
49 * Template must have been previously destroyed. Errors are fatal
51 int
52 DoCreateTemplate(int force)
54 struct stat st;
55 char *goodbuf;
56 char *buf;
57 const char *reason = "";
58 int rc;
59 int fd;
60 int n;
62 rc = 0;
63 asprintf(&goodbuf, "%s/.template.good", BuildBase);
66 * Conditionally create the template and discrete copies of certain
67 * directories if we think we are missing things.
69 if (force == 1)
70 reason = " (Asked to force template creation)";
71 if (force == 0) {
72 time_t ls_mtime;
74 asprintf(&buf, "%s/Template", BuildBase);
75 if (stat(buf, &st) < 0) {
76 force = 1;
77 reason = " (Template file missing)";
79 free(buf);
82 * Check to see if the worker count changed and some
83 * template dirs are missing or out of date, and also if
84 * a new world was installed (via /bin/ls mtime).
86 asprintf(&buf, "%s/bin/ls", SystemPath);
87 if (stat(buf, &st) < 0)
88 dfatal_errno("Unable to locate %s", buf);
89 free(buf);
90 ls_mtime = st.st_mtime;
92 for (n = 0; n < MaxWorkers; ++n) {
93 asprintf(&buf, "%s/bin.%03d/ls", BuildBase, n);
94 if (stat(buf, &st) < 0 || st.st_mtime != ls_mtime) {
95 force = 1;
96 reason = " (/bin/ls mtime mismatch)";
98 free(buf);
101 if (stat(goodbuf, &st) < 0) {
102 force = 1;
103 reason = " (.template.good file missing)";
107 dlog(DLOG_ALL, "Check Template: %s%s\n",
108 (force ? "Must-Create" : "Good"),
109 reason);
112 * Create the template
114 if (force) {
115 remove(goodbuf); /* ignore exit code */
117 rc = 0;
118 asprintf(&buf, "%s/mktemplate %s %s/Template",
119 SCRIPTPATH(SCRIPTDIR), SystemPath, BuildBase);
120 rc = system(buf);
121 if (rc)
122 dfatal("Command failed: %s\n", buf);
123 dlog(DLOG_ALL | DLOG_FILTER,
124 "Template - rc=%d running %s\n", rc, buf);
125 free(buf);
128 * Make discrete copies of certain extremely heavily used
129 * but small directories.
131 makeDiscreteCopies("$/bin", "/bin.%03d");
132 makeDiscreteCopies("$/lib", "/lib.%03d");
133 makeDiscreteCopies("$/libexec", "/libexec.%03d");
134 makeDiscreteCopies("$/usr/bin", "/usr.bin.%03d");
137 * Mark the template good... ah, do a sync() to really
138 * be sure that it can't get corrupted.
140 sync();
141 fd = open(goodbuf, O_RDWR|O_CREAT|O_TRUNC, 0644);
142 dassert_errno(fd >= 0, "could not create %s", goodbuf);
143 close(fd);
145 dlog(DLOG_ALL | DLOG_FILTER, "Template - done\n");
147 free(goodbuf);
149 return force;
152 void
153 DoDestroyTemplate(void)
155 struct stat st;
156 char *path;
157 char *buf;
158 int rc;
161 * NOTE: rm -rf safety, use a fixed name 'Template' to ensure we
162 * do not accidently blow something up.
164 asprintf(&path, "%s/Template", BuildBase);
165 if (stat(path, &st) == 0) {
166 asprintf(&buf, "chflags -R noschg %s; /bin/rm -rf %s",
167 path, path);
168 rc = system(buf);
169 if (rc)
170 dfatal("Command failed: %s (ignored)\n", buf);
171 free(buf);
173 free(path);
177 * Called by the worker support thread to install a new worker
178 * filesystem topology.
180 void
181 DoWorkerMounts(worker_t *work)
183 char *buf;
184 int rc;
187 * Generate required mounts, domount() will mkdir() the target
188 * directory if necessary and prefix spath with SystemPath if
189 * it starts with $/
191 setNumaDomain(work->index);
192 domount(work, TMPFS_RW, "dummy", "", NULL);
193 asprintf(&buf, "%s/usr", work->basedir);
194 if (mkdir(buf, 0755) != 0) {
195 fprintf(stderr, "Command failed: mkdir %s\n", buf);
196 ++work->mount_error;
198 free(buf);
200 domount(work, NULLFS_RO, "$/boot", "/boot", NULL);
201 domount(work, TMPFS_RW, "dummy", "/boot/modules.local", NULL);
202 domount(work, DEVFS_RW, "dummy", "/dev", NULL);
203 domount(work, PROCFS_RO, "dummy", "/proc", NULL);
204 domount(work, NULLFS_RO, "$/bin", "/bin", "/bin.%03d");
205 domount(work, NULLFS_RO, "$/sbin", "/sbin", NULL);
206 domount(work, NULLFS_RO, "$/lib", "/lib", "/lib.%03d");
207 domount(work, NULLFS_RO, "$/libexec", "/libexec", "/libexec.%03d");
208 domount(work, NULLFS_RO, "$/usr/bin", "/usr/bin", "/usr.bin.%03d");
209 domount(work, NULLFS_RO, "$/usr/include", "/usr/include", NULL);
210 domount(work, NULLFS_RO, "$/usr/lib", "/usr/lib", NULL);
211 domount(work, NULLFS_RO, "$/usr/libdata", "/usr/libdata", NULL);
212 domount(work, NULLFS_RO, "$/usr/libexec", "/usr/libexec", NULL);
213 domount(work, NULLFS_RO, "$/usr/sbin", "/usr/sbin", NULL);
214 domount(work, NULLFS_RO, "$/usr/share", "/usr/share", NULL);
215 domount(work, TMPFS_RW_MED, "dummy", "/usr/local", NULL);
216 domount(work, NULLFS_RO, "$/usr/games", "/usr/games", NULL);
217 if (UseUsrSrc)
218 domount(work, NULLFS_RO, "$/usr/src", "/usr/src", NULL);
219 domount(work, NULLFS_RO, DPortsPath, "/xports", NULL);
220 domount(work, NULLFS_RW, OptionsPath, "/options", NULL);
221 domount(work, NULLFS_RW, PackagesPath, "/packages", NULL);
222 domount(work, NULLFS_RW, DistFilesPath, "/distfiles", NULL);
223 domount(work, TMPFS_RW_BIG, "dummy", "/construction", NULL);
224 if (UseCCache)
225 domount(work, NULLFS_RW, CCachePath, "/ccache", NULL);
228 * NOTE: Uses blah/. to prevent cp from creating 'Template' under
229 * work->basedir. We want to start with the content.
231 asprintf(&buf, "cp -Rp %s/Template/. %s", BuildBase, work->basedir);
232 rc = system(buf);
233 if (rc) {
234 fprintf(stderr, "Command failed: %s\n", buf);
235 ++work->accum_error;
236 snprintf(work->status, sizeof(work->status),
237 "Template copy failed");
239 free(buf);
240 setNumaDomain(-1);
244 * Called by the worker support thread to remove a worker
245 * filesystem topology.
247 * NOTE: No need to conditionalize UseUsrSrc, it doesn't hurt to
248 * issue the umount() if it isn't mounted and it ensures that
249 * everything is unmounted properly on cleanup if the state
250 * changes.
252 void
253 DoWorkerUnmounts(worker_t *work)
255 int retries;
257 setNumaDomain(work->index);
258 work->mount_error = 0;
259 for (retries = 0; retries < 10; ++retries) {
260 dounmount(work, "/proc");
261 dounmount(work, "/dev");
262 dounmount(work, "/usr/src");
263 dounmount(work, "/usr/games");
264 dounmount(work, "/boot/modules.local");
265 dounmount(work, "/boot");
266 dounmount(work, "/usr/local");
267 dounmount(work, "/construction");
268 dounmount(work, "/ccache"); /* in case of config change */
269 dounmount(work, "/distfiles");
270 dounmount(work, "/packages");
271 dounmount(work, "/options");
272 dounmount(work, "/xports");
273 dounmount(work, "/usr/share");
274 dounmount(work, "/usr/sbin");
275 dounmount(work, "/usr/libexec");
276 dounmount(work, "/usr/libdata");
277 dounmount(work, "/usr/lib");
278 dounmount(work, "/usr/include");
279 dounmount(work, "/usr/bin");
280 dounmount(work, "/libexec");
281 dounmount(work, "/lib");
282 dounmount(work, "/sbin");
283 dounmount(work, "/bin");
284 dounmount(work, "");
285 if (work->mount_error == 0)
286 break;
287 sleep(5);
288 work->mount_error = 0;
290 if (work->mount_error) {
291 ++work->accum_error;
292 snprintf(work->status, sizeof(work->status),
293 "Unable to unmount slot");
295 setNumaDomain(-1);
298 static
299 void
300 domount(worker_t *work, int type, const char *spath, const char *dpath,
301 const char *discretefmt)
303 const char *sbase;
304 const char *rwstr;
305 const char *optstr;
306 const char *typestr;
307 const char *debug;
308 struct stat st;
309 char *buf;
310 char *tmp;
311 int rc;
314 * Make target directory if necessary. This must occur in-order
315 * since directories may have to be created under prior mounts
316 * in the sequence.
318 asprintf(&buf, "%s%s", work->basedir, dpath);
319 if (stat(buf, &st) != 0) {
320 if (mkdir(buf, 0755) != 0) {
321 fprintf(stderr, "Command failed: mkdir %s\n", buf);
322 ++work->mount_error;
325 free(buf);
328 * Setup for mount arguments
330 rwstr = (type & MOUNT_TYPE_RW) ? "rw" : "ro";
331 optstr = "";
332 typestr = "";
334 switch(type & MOUNT_TYPE_MASK) {
335 case MOUNT_TYPE_TMPFS:
337 * When creating a tmpfs filesystem, make sure the big ones
338 * requested are big enough for the worst-case dport (which
339 * is usually chromium). If debugging is turned on, its even
340 * worse. You'd better have enough swap!
342 debug = getbuildenv("WITH_DEBUG");
343 typestr = "tmpfs";
344 if (type & MOUNT_TYPE_BIG)
345 optstr = debug ? " -o size=128g" : " -o size=64g";
346 else if (type & MOUNT_TYPE_MED)
347 optstr = debug ? " -o size=32g" : " -o size=16g";
348 else
349 optstr = " -o size=16g";
350 break;
351 case MOUNT_TYPE_NULLFS:
352 #if defined(__DragonFly__)
353 typestr = "null";
354 #else
355 typestr = "nullfs";
356 #endif
357 break;
358 case MOUNT_TYPE_DEVFS:
359 typestr = "devfs";
360 break;
361 case MOUNT_TYPE_PROCFS:
362 typestr = "procfs";
363 break;
364 default:
365 dfatal("Illegal mount type: %08x", type);
366 /* NOT REACHED */
367 break;
371 * Prefix spath
373 if (discretefmt) {
374 sbase = BuildBase;
375 asprintf(&tmp, discretefmt, work->index);
376 spath = tmp;
377 } else {
378 if (spath[0] == '$') {
379 ++spath;
380 sbase = SystemPath;
381 if (strcmp(sbase, "/") == 0)
382 ++sbase;
383 } else {
384 sbase = "";
386 tmp = NULL;
388 asprintf(&buf, "%s%s -t %s -o %s %s%s %s%s",
389 MOUNT_BINARY, optstr, typestr, rwstr,
390 sbase, spath, work->basedir, dpath);
391 rc = system(buf);
392 if (rc) {
393 fprintf(stderr, "Command failed: %s\n", buf);
394 ++work->mount_error;
396 free(buf);
397 if (tmp)
398 free(tmp);
401 static
402 void
403 dounmount(worker_t *work, const char *rpath)
405 char *buf;
407 asprintf(&buf, "%s%s", work->basedir, rpath);
408 if (unmount(buf, 0) < 0) {
409 switch(errno) {
410 case EPERM: /* This is probably fatal later on in mount */
411 case ENOENT: /* Expected if mount already gone */
412 case EINVAL: /* Expected if mount already gone (maybe) */
413 break;
414 default:
415 fprintf(stderr, "Cannot umount %s (%s)\n",
416 buf, strerror(errno));
417 ++work->mount_error;
418 break;
421 free(buf);
424 static
425 void
426 makeDiscreteCopies(const char *spath, const char *discretefmt)
428 char *src;
429 char *dst;
430 char *buf;
431 struct stat st;
432 int i;
433 int rc;
435 for (i = 0; i < MaxWorkers; ++i) {
436 setNumaDomain(i);
437 if (spath[0] == '$') {
438 if (strcmp(SystemPath, "/") == 0)
439 asprintf(&src, "%s%s",
440 SystemPath + 1, spath + 1);
441 else
442 asprintf(&src, "%s%s",
443 SystemPath, spath + 1);
444 } else {
445 src = strdup(spath);
447 asprintf(&buf, discretefmt, i);
448 asprintf(&dst, "%s%s", BuildBase, buf);
449 free(buf);
451 if (stat(dst, &st) < 0) {
452 if (mkdir(dst, 0555) < 0) {
453 dlog(DLOG_ALL, "Template - mkdir %s failed\n",
454 dst);
455 dfatal_errno("Cannot mkdir %s:", dst);
458 asprintf(&buf, "chflags -R noschg %s; "
459 "rm -rf %s; "
460 "cp -Rp %s/. %s",
461 dst, dst, src, dst);
462 rc = system(buf);
463 dlog(DLOG_ALL | DLOG_FILTER,
464 "Template - rc=%d running %s\n", rc, buf);
465 if (rc)
466 dfatal("Command failed: %s", buf);
467 free(buf);
468 free(src);
469 free(dst);
470 setNumaDomain(-1);