xref: /freebsd/sbin/tunefs/tunefs.c (revision 5305359514af0eb9a069ad35b3cb745b3b34feb1)
18fae3551SRodney W. Grimes /*
28fae3551SRodney W. Grimes  * Copyright (c) 1983, 1993
38fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
48fae3551SRodney W. Grimes  *
58fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
68fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
78fae3551SRodney W. Grimes  * are met:
88fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
98fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
108fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
128fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
138fae3551SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
148fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
158fae3551SRodney W. Grimes  *    without specific prior written permission.
168fae3551SRodney W. Grimes  *
178fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
188fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
198fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
208fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
218fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
228fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
238fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
248fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
258fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
268fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
278fae3551SRodney W. Grimes  * SUCH DAMAGE.
288fae3551SRodney W. Grimes  */
298fae3551SRodney W. Grimes 
30c69284caSDavid E. O'Brien #if 0
318fae3551SRodney W. Grimes #ifndef lint
328679b1b4SPhilippe Charnier static const char copyright[] =
338fae3551SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\
348fae3551SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
358fae3551SRodney W. Grimes #endif /* not lint */
368fae3551SRodney W. Grimes 
378fae3551SRodney W. Grimes #ifndef lint
388fae3551SRodney W. Grimes static char sccsid[] = "@(#)tunefs.c	8.2 (Berkeley) 4/19/94";
398fae3551SRodney W. Grimes #endif /* not lint */
40c69284caSDavid E. O'Brien #endif
41c69284caSDavid E. O'Brien #include <sys/cdefs.h>
42c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$");
438fae3551SRodney W. Grimes 
448fae3551SRodney W. Grimes /*
458fae3551SRodney W. Grimes  * tunefs: change layout parameters to an existing file system.
468fae3551SRodney W. Grimes  */
478fae3551SRodney W. Grimes #include <sys/param.h>
487382c45aSLuoqi Chen #include <sys/mount.h>
4975766e17SPoul-Henning Kamp #include <sys/disklabel.h>
508fae3551SRodney W. Grimes #include <sys/stat.h>
518fae3551SRodney W. Grimes 
527382c45aSLuoqi Chen #include <ufs/ufs/ufsmount.h>
531c85e6a3SKirk McKusick #include <ufs/ufs/dinode.h>
541c85e6a3SKirk McKusick #include <ufs/ffs/fs.h>
55113db2ddSJeff Roberson #include <ufs/ufs/dir.h>
568fae3551SRodney W. Grimes 
57c715b047SGordon Tetlow #include <ctype.h>
588fae3551SRodney W. Grimes #include <err.h>
598fae3551SRodney W. Grimes #include <fcntl.h>
608fae3551SRodney W. Grimes #include <fstab.h>
61b1f0fda0SJuli Mallett #include <libufs.h>
628fae3551SRodney W. Grimes #include <paths.h>
638679b1b4SPhilippe Charnier #include <stdio.h>
648fae3551SRodney W. Grimes #include <stdlib.h>
65113db2ddSJeff Roberson #include <stdint.h>
66060ac658SSheldon Hearn #include <string.h>
678fae3551SRodney W. Grimes #include <unistd.h>
688fae3551SRodney W. Grimes 
698fae3551SRodney W. Grimes /* the optimization warning string template */
708fae3551SRodney W. Grimes #define	OPTWARN	"should optimize for %s with minfree %s %d%%"
718fae3551SRodney W. Grimes 
72b1f0fda0SJuli Mallett struct uufsd disk;
73b1f0fda0SJuli Mallett #define	sblock disk.d_fs
748fae3551SRodney W. Grimes 
75d476a036SWarner Losh void usage(void);
76d476a036SWarner Losh void printfs(void);
77113db2ddSJeff Roberson int journal_alloc(int64_t size);
78113db2ddSJeff Roberson void journal_clear(void);
79113db2ddSJeff Roberson void sbdirty(void);
808fae3551SRodney W. Grimes 
818fae3551SRodney W. Grimes int
82b1f0fda0SJuli Mallett main(int argc, char *argv[])
838fae3551SRodney W. Grimes {
84113db2ddSJeff Roberson 	char *avalue, *jvalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue;
85907db4ddSJuli Mallett 	const char *special, *on;
86c33fa91fSDima Dorfman 	const char *name;
8776444424SBruce Evans 	int active;
88113db2ddSJeff Roberson 	int Aflag, aflag, eflag, evalue, fflag, fvalue, jflag, Jflag, Lflag;
89113db2ddSJeff Roberson 	int lflag, mflag, mvalue, Nflag, nflag, oflag, ovalue, pflag, sflag;
90113db2ddSJeff Roberson 	int svalue, Sflag, Svalue;
9129f9611dSBruce Evans 	int ch, found_arg, i;
92c33fa91fSDima Dorfman 	const char *chg[2];
937382c45aSLuoqi Chen 	struct ufs_args args;
947382c45aSLuoqi Chen 	struct statfs stfs;
958fae3551SRodney W. Grimes 
962af14b60SPhilippe Charnier 	if (argc < 3)
978fae3551SRodney W. Grimes 		usage();
98113db2ddSJeff Roberson 	Aflag = aflag = eflag = fflag = jflag = Jflag = Lflag = lflag = 0;
99113db2ddSJeff Roberson 	mflag = Nflag = nflag = oflag = pflag = sflag = 0;
100113db2ddSJeff Roberson 	avalue = jvalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL;
101113db2ddSJeff Roberson 	evalue = fvalue = mvalue = ovalue = svalue = Svalue = 0;
10276444424SBruce Evans 	active = 0;
10329f9611dSBruce Evans 	found_arg = 0;		/* At least one arg is required. */
104113db2ddSJeff Roberson 	while ((ch = getopt(argc, argv, "Aa:e:f:j:J:L:l:m:N:n:o:ps:S:")) != -1)
10577edab90SPhilippe Charnier 		switch (ch) {
10629f9611dSBruce Evans 
107a2325efeSRobert Watson 		case 'A':
108a2325efeSRobert Watson 			found_arg = 1;
109a2325efeSRobert Watson 			Aflag++;
110a2325efeSRobert Watson 			break;
11129f9611dSBruce Evans 
112289e09eeSRobert Watson 		case 'a':
113289e09eeSRobert Watson 			found_arg = 1;
1149340fc72SEdward Tomasz Napierala 			name = "POSIX.1e ACLs";
115289e09eeSRobert Watson 			avalue = optarg;
11629f9611dSBruce Evans 			if (strcmp(avalue, "enable") &&
11729f9611dSBruce Evans 			    strcmp(avalue, "disable")) {
11829f9611dSBruce Evans 				errx(10, "bad %s (options are %s)",
11929f9611dSBruce Evans 				    name, "`enable' or `disable'");
120289e09eeSRobert Watson 			}
121289e09eeSRobert Watson 			aflag = 1;
122289e09eeSRobert Watson 			break;
12329f9611dSBruce Evans 
12477edab90SPhilippe Charnier 		case 'e':
12577edab90SPhilippe Charnier 			found_arg = 1;
12677edab90SPhilippe Charnier 			name = "maximum blocks per file in a cylinder group";
12777edab90SPhilippe Charnier 			evalue = atoi(optarg);
12877edab90SPhilippe Charnier 			if (evalue < 1)
12929f9611dSBruce Evans 				errx(10, "%s must be >= 1 (was %s)",
13029f9611dSBruce Evans 				    name, optarg);
13177edab90SPhilippe Charnier 			eflag = 1;
13277edab90SPhilippe Charnier 			break;
13329f9611dSBruce Evans 
134a61ab64aSKirk McKusick 		case 'f':
135a61ab64aSKirk McKusick 			found_arg = 1;
136a61ab64aSKirk McKusick 			name = "average file size";
137a61ab64aSKirk McKusick 			fvalue = atoi(optarg);
138a61ab64aSKirk McKusick 			if (fvalue < 1)
13929f9611dSBruce Evans 				errx(10, "%s must be >= 1 (was %s)",
14029f9611dSBruce Evans 				    name, optarg);
141a61ab64aSKirk McKusick 			fflag = 1;
142a61ab64aSKirk McKusick 			break;
14329f9611dSBruce Evans 
144113db2ddSJeff Roberson 		case 'j':
145113db2ddSJeff Roberson 			found_arg = 1;
146113db2ddSJeff Roberson 			name = "softdep journaled file system";
147113db2ddSJeff Roberson 			jvalue = optarg;
148113db2ddSJeff Roberson 			if (strcmp(jvalue, "enable") &&
149113db2ddSJeff Roberson 			    strcmp(jvalue, "disable")) {
150113db2ddSJeff Roberson 				errx(10, "bad %s (options are %s)",
151113db2ddSJeff Roberson 				    name, "`enable' or `disable'");
152113db2ddSJeff Roberson 			}
153113db2ddSJeff Roberson 			jflag = 1;
154113db2ddSJeff Roberson 			break;
155113db2ddSJeff Roberson 
156868c68edSPawel Jakub Dawidek 		case 'J':
157868c68edSPawel Jakub Dawidek 			found_arg = 1;
158868c68edSPawel Jakub Dawidek 			name = "gjournaled file system";
159868c68edSPawel Jakub Dawidek 			Jvalue = optarg;
160868c68edSPawel Jakub Dawidek 			if (strcmp(Jvalue, "enable") &&
161868c68edSPawel Jakub Dawidek 			    strcmp(Jvalue, "disable")) {
162868c68edSPawel Jakub Dawidek 				errx(10, "bad %s (options are %s)",
163868c68edSPawel Jakub Dawidek 				    name, "`enable' or `disable'");
164868c68edSPawel Jakub Dawidek 			}
165868c68edSPawel Jakub Dawidek 			Jflag = 1;
166868c68edSPawel Jakub Dawidek 			break;
167868c68edSPawel Jakub Dawidek 
168868c68edSPawel Jakub Dawidek 
1691f6a4631SRuslan Ermilov 		case 'L':
1701f6a4631SRuslan Ermilov 			found_arg = 1;
1711f6a4631SRuslan Ermilov 			name = "volume label";
1721f6a4631SRuslan Ermilov 			Lvalue = optarg;
1731f6a4631SRuslan Ermilov 			i = -1;
1741f6a4631SRuslan Ermilov 			while (isalnum(Lvalue[++i]));
1751f6a4631SRuslan Ermilov 			if (Lvalue[i] != '\0') {
17629f9611dSBruce Evans 				errx(10,
17729f9611dSBruce Evans 				"bad %s. Valid characters are alphanumerics.",
1781f6a4631SRuslan Ermilov 				    name);
1791f6a4631SRuslan Ermilov 			}
1801f6a4631SRuslan Ermilov 			if (strlen(Lvalue) >= MAXVOLLEN) {
1811f6a4631SRuslan Ermilov 				errx(10, "bad %s. Length is longer than %d.",
1821f6a4631SRuslan Ermilov 				    name, MAXVOLLEN - 1);
1831f6a4631SRuslan Ermilov 			}
1841f6a4631SRuslan Ermilov 			Lflag = 1;
1851f6a4631SRuslan Ermilov 			break;
18629f9611dSBruce Evans 
187289e09eeSRobert Watson 		case 'l':
188289e09eeSRobert Watson 			found_arg = 1;
189289e09eeSRobert Watson 			name = "multilabel MAC file system";
190289e09eeSRobert Watson 			lvalue = optarg;
19129f9611dSBruce Evans 			if (strcmp(lvalue, "enable") &&
19229f9611dSBruce Evans 			    strcmp(lvalue, "disable")) {
19329f9611dSBruce Evans 				errx(10, "bad %s (options are %s)",
19429f9611dSBruce Evans 				    name, "`enable' or `disable'");
195289e09eeSRobert Watson 			}
196289e09eeSRobert Watson 			lflag = 1;
197289e09eeSRobert Watson 			break;
19829f9611dSBruce Evans 
19977edab90SPhilippe Charnier 		case 'm':
20077edab90SPhilippe Charnier 			found_arg = 1;
20177edab90SPhilippe Charnier 			name = "minimum percentage of free space";
20277edab90SPhilippe Charnier 			mvalue = atoi(optarg);
20377edab90SPhilippe Charnier 			if (mvalue < 0 || mvalue > 99)
20477edab90SPhilippe Charnier 				errx(10, "bad %s (%s)", name, optarg);
20577edab90SPhilippe Charnier 			mflag = 1;
20677edab90SPhilippe Charnier 			break;
20729f9611dSBruce Evans 
2089340fc72SEdward Tomasz Napierala 		case 'N':
2099340fc72SEdward Tomasz Napierala 			found_arg = 1;
2109340fc72SEdward Tomasz Napierala 			name = "NFSv4 ACLs";
2119340fc72SEdward Tomasz Napierala 			Nvalue = optarg;
2129340fc72SEdward Tomasz Napierala 			if (strcmp(Nvalue, "enable") &&
2139340fc72SEdward Tomasz Napierala 			    strcmp(Nvalue, "disable")) {
2149340fc72SEdward Tomasz Napierala 				errx(10, "bad %s (options are %s)",
2159340fc72SEdward Tomasz Napierala 				    name, "`enable' or `disable'");
2169340fc72SEdward Tomasz Napierala 			}
2179340fc72SEdward Tomasz Napierala 			Nflag = 1;
2189340fc72SEdward Tomasz Napierala 			break;
2199340fc72SEdward Tomasz Napierala 
22077edab90SPhilippe Charnier 		case 'n':
22177edab90SPhilippe Charnier 			found_arg = 1;
22277edab90SPhilippe Charnier 			name = "soft updates";
22377edab90SPhilippe Charnier 			nvalue = optarg;
22476444424SBruce Evans 			if (strcmp(nvalue, "enable") != 0 &&
22576444424SBruce Evans 			    strcmp(nvalue, "disable") != 0) {
22677edab90SPhilippe Charnier 				errx(10, "bad %s (options are %s)",
22777edab90SPhilippe Charnier 				    name, "`enable' or `disable'");
22877edab90SPhilippe Charnier 			}
22977edab90SPhilippe Charnier 			nflag = 1;
23077edab90SPhilippe Charnier 			break;
23129f9611dSBruce Evans 
23277edab90SPhilippe Charnier 		case 'o':
23377edab90SPhilippe Charnier 			found_arg = 1;
23477edab90SPhilippe Charnier 			name = "optimization preference";
23576444424SBruce Evans 			if (strcmp(optarg, "space") == 0)
23677edab90SPhilippe Charnier 				ovalue = FS_OPTSPACE;
23776444424SBruce Evans 			else if (strcmp(optarg, "time") == 0)
23877edab90SPhilippe Charnier 				ovalue = FS_OPTTIME;
23977edab90SPhilippe Charnier 			else
24029f9611dSBruce Evans 				errx(10,
24129f9611dSBruce Evans 				    "bad %s (options are `space' or `time')",
24277edab90SPhilippe Charnier 				    name);
24377edab90SPhilippe Charnier 			oflag = 1;
24477edab90SPhilippe Charnier 			break;
24529f9611dSBruce Evans 
24677edab90SPhilippe Charnier 		case 'p':
247e50fa3d2SBen Smithurst 			found_arg = 1;
24877edab90SPhilippe Charnier 			pflag = 1;
24977edab90SPhilippe Charnier 			break;
25029f9611dSBruce Evans 
251a61ab64aSKirk McKusick 		case 's':
252a61ab64aSKirk McKusick 			found_arg = 1;
253a61ab64aSKirk McKusick 			name = "expected number of files per directory";
254a61ab64aSKirk McKusick 			svalue = atoi(optarg);
255a61ab64aSKirk McKusick 			if (svalue < 1)
25629f9611dSBruce Evans 				errx(10, "%s must be >= 1 (was %s)",
25729f9611dSBruce Evans 				    name, optarg);
258a61ab64aSKirk McKusick 			sflag = 1;
259a61ab64aSKirk McKusick 			break;
26029f9611dSBruce Evans 
261113db2ddSJeff Roberson 		case 'S':
262113db2ddSJeff Roberson 			found_arg = 1;
263113db2ddSJeff Roberson 			name = "Softdep Journal Size";
264113db2ddSJeff Roberson 			Svalue = atoi(optarg);
265113db2ddSJeff Roberson 			if (Svalue < SUJ_MIN)
266113db2ddSJeff Roberson 				errx(10, "%s must be >= %d (was %s)",
267113db2ddSJeff Roberson 				    name, SUJ_MIN, optarg);
268113db2ddSJeff Roberson 			Sflag = 1;
269113db2ddSJeff Roberson 			break;
270113db2ddSJeff Roberson 
27177edab90SPhilippe Charnier 		default:
27277edab90SPhilippe Charnier 			usage();
27377edab90SPhilippe Charnier 		}
27477edab90SPhilippe Charnier 	argc -= optind;
27577edab90SPhilippe Charnier 	argv += optind;
27677edab90SPhilippe Charnier 	if (found_arg == 0 || argc != 1)
27777edab90SPhilippe Charnier 		usage();
27877edab90SPhilippe Charnier 
279907db4ddSJuli Mallett 	on = special = argv[0];
280907db4ddSJuli Mallett 	if (ufs_disk_fillout(&disk, special) == -1)
281907db4ddSJuli Mallett 		goto err;
282907db4ddSJuli Mallett 	if (disk.d_name != special) {
283a6e09ef1SJeff Roberson 		if (statfs(special, &stfs) != 0)
284a6e09ef1SJeff Roberson 			warn("Can't stat %s", special);
285a6e09ef1SJeff Roberson 		if (strcmp(special, stfs.f_mntonname) == 0)
2867382c45aSLuoqi Chen 			active = 1;
287b20ae6a0SLuoqi Chen 	}
2888fae3551SRodney W. Grimes 
28977edab90SPhilippe Charnier 	if (pflag) {
29077edab90SPhilippe Charnier 		printfs();
29177edab90SPhilippe Charnier 		exit(0);
29277edab90SPhilippe Charnier 	}
293c715b047SGordon Tetlow 	if (Lflag) {
294c715b047SGordon Tetlow 		name = "volume label";
295c715b047SGordon Tetlow 		strlcpy(sblock.fs_volname, Lvalue, MAXVOLLEN);
296c715b047SGordon Tetlow 	}
297289e09eeSRobert Watson 	if (aflag) {
2989340fc72SEdward Tomasz Napierala 		name = "POSIX.1e ACLs";
299289e09eeSRobert Watson 		if (strcmp(avalue, "enable") == 0) {
300289e09eeSRobert Watson 			if (sblock.fs_flags & FS_ACLS) {
301289e09eeSRobert Watson 				warnx("%s remains unchanged as enabled", name);
3029340fc72SEdward Tomasz Napierala 			} else if (sblock.fs_flags & FS_NFS4ACLS) {
3039340fc72SEdward Tomasz Napierala 				warnx("%s and NFSv4 ACLs are mutually "
3049340fc72SEdward Tomasz Napierala 				    "exclusive", name);
305289e09eeSRobert Watson 			} else {
306289e09eeSRobert Watson 				sblock.fs_flags |= FS_ACLS;
307289e09eeSRobert Watson 				warnx("%s set", name);
308289e09eeSRobert Watson 			}
309289e09eeSRobert Watson 		} else if (strcmp(avalue, "disable") == 0) {
310289e09eeSRobert Watson 			if ((~sblock.fs_flags & FS_ACLS) ==
311289e09eeSRobert Watson 			    FS_ACLS) {
312289e09eeSRobert Watson 				warnx("%s remains unchanged as disabled",
313289e09eeSRobert Watson 				    name);
314289e09eeSRobert Watson 			} else {
315289e09eeSRobert Watson 				sblock.fs_flags &= ~FS_ACLS;
316273500c2SRobert Watson 				warnx("%s cleared", name);
317289e09eeSRobert Watson 			}
318289e09eeSRobert Watson 		}
319289e09eeSRobert Watson 	}
32077edab90SPhilippe Charnier 	if (eflag) {
3212af14b60SPhilippe Charnier 		name = "maximum blocks per file in a cylinder group";
32276444424SBruce Evans 		if (sblock.fs_maxbpg == evalue)
32377edab90SPhilippe Charnier 			warnx("%s remains unchanged as %d", name, evalue);
32477edab90SPhilippe Charnier 		else {
32577edab90SPhilippe Charnier 			warnx("%s changes from %d to %d",
32677edab90SPhilippe Charnier 			    name, sblock.fs_maxbpg, evalue);
32777edab90SPhilippe Charnier 			sblock.fs_maxbpg = evalue;
32877edab90SPhilippe Charnier 		}
32977edab90SPhilippe Charnier 	}
330a61ab64aSKirk McKusick 	if (fflag) {
331a61ab64aSKirk McKusick 		name = "average file size";
332a6cc0cf6SKirk McKusick 		if (sblock.fs_avgfilesize == (unsigned)fvalue) {
333a61ab64aSKirk McKusick 			warnx("%s remains unchanged as %d", name, fvalue);
334a61ab64aSKirk McKusick 		}
335a61ab64aSKirk McKusick 		else {
336a61ab64aSKirk McKusick 			warnx("%s changes from %d to %d",
337a61ab64aSKirk McKusick 					name, sblock.fs_avgfilesize, fvalue);
338a61ab64aSKirk McKusick 			sblock.fs_avgfilesize = fvalue;
339a61ab64aSKirk McKusick 		}
340a61ab64aSKirk McKusick 	}
341113db2ddSJeff Roberson 	if (jflag) {
342113db2ddSJeff Roberson  		name = "soft updates journaling";
343113db2ddSJeff Roberson  		if (strcmp(jvalue, "enable") == 0) {
344113db2ddSJeff Roberson 			if ((sblock.fs_flags & (FS_DOSOFTDEP | FS_SUJ)) ==
345113db2ddSJeff Roberson 			    (FS_DOSOFTDEP | FS_SUJ)) {
346113db2ddSJeff Roberson 				warnx("%s remains unchanged as enabled", name);
347113db2ddSJeff Roberson 			} else if (sblock.fs_clean == 0) {
348113db2ddSJeff Roberson 				warnx("%s cannot be enabled until fsck is run",
349113db2ddSJeff Roberson 				    name);
350113db2ddSJeff Roberson 			} else if (journal_alloc(Svalue) != 0) {
351113db2ddSJeff Roberson 				warnx("%s can not be enabled", name);
352113db2ddSJeff Roberson 			} else {
353113db2ddSJeff Roberson  				sblock.fs_flags |= FS_DOSOFTDEP | FS_SUJ;
354113db2ddSJeff Roberson  				warnx("%s set", name);
355113db2ddSJeff Roberson 			}
356113db2ddSJeff Roberson  		} else if (strcmp(jvalue, "disable") == 0) {
357113db2ddSJeff Roberson 			if ((~sblock.fs_flags & FS_SUJ) == FS_SUJ) {
358113db2ddSJeff Roberson 				warnx("%s remains unchanged as disabled", name);
359113db2ddSJeff Roberson 			} else {
360113db2ddSJeff Roberson 				journal_clear();
361*53053595SJeff Roberson  				sblock.fs_flags &= ~FS_SUJ;
362113db2ddSJeff Roberson 				sblock.fs_sujfree = 0;
363*53053595SJeff Roberson  				warnx("%s cleared but soft updates still set.",
364*53053595SJeff Roberson 				    name);
365*53053595SJeff Roberson 
366*53053595SJeff Roberson 				warnx("remove .sujournal to reclaim space");
367113db2ddSJeff Roberson 			}
368113db2ddSJeff Roberson  		}
369113db2ddSJeff Roberson 	}
370868c68edSPawel Jakub Dawidek 	if (Jflag) {
371868c68edSPawel Jakub Dawidek 		name = "gjournal";
372868c68edSPawel Jakub Dawidek 		if (strcmp(Jvalue, "enable") == 0) {
373868c68edSPawel Jakub Dawidek 			if (sblock.fs_flags & FS_GJOURNAL) {
374868c68edSPawel Jakub Dawidek 				warnx("%s remains unchanged as enabled", name);
375868c68edSPawel Jakub Dawidek 			} else {
376868c68edSPawel Jakub Dawidek 				sblock.fs_flags |= FS_GJOURNAL;
377868c68edSPawel Jakub Dawidek 				warnx("%s set", name);
378868c68edSPawel Jakub Dawidek 			}
379868c68edSPawel Jakub Dawidek 		} else if (strcmp(Jvalue, "disable") == 0) {
380868c68edSPawel Jakub Dawidek 			if ((~sblock.fs_flags & FS_GJOURNAL) ==
381868c68edSPawel Jakub Dawidek 			    FS_GJOURNAL) {
382868c68edSPawel Jakub Dawidek 				warnx("%s remains unchanged as disabled",
383868c68edSPawel Jakub Dawidek 				    name);
384868c68edSPawel Jakub Dawidek 			} else {
385868c68edSPawel Jakub Dawidek 				sblock.fs_flags &= ~FS_GJOURNAL;
386868c68edSPawel Jakub Dawidek 				warnx("%s cleared", name);
387868c68edSPawel Jakub Dawidek 			}
388868c68edSPawel Jakub Dawidek 		}
389868c68edSPawel Jakub Dawidek 	}
390289e09eeSRobert Watson 	if (lflag) {
391289e09eeSRobert Watson 		name = "multilabel";
392289e09eeSRobert Watson 		if (strcmp(lvalue, "enable") == 0) {
393289e09eeSRobert Watson 			if (sblock.fs_flags & FS_MULTILABEL) {
394289e09eeSRobert Watson 				warnx("%s remains unchanged as enabled", name);
395289e09eeSRobert Watson 			} else {
396289e09eeSRobert Watson 				sblock.fs_flags |= FS_MULTILABEL;
397289e09eeSRobert Watson 				warnx("%s set", name);
398289e09eeSRobert Watson 			}
399289e09eeSRobert Watson 		} else if (strcmp(lvalue, "disable") == 0) {
400289e09eeSRobert Watson 			if ((~sblock.fs_flags & FS_MULTILABEL) ==
401289e09eeSRobert Watson 			    FS_MULTILABEL) {
402289e09eeSRobert Watson 				warnx("%s remains unchanged as disabled",
403289e09eeSRobert Watson 				    name);
404289e09eeSRobert Watson 			} else {
405289e09eeSRobert Watson 				sblock.fs_flags &= ~FS_MULTILABEL;
406273500c2SRobert Watson 				warnx("%s cleared", name);
407289e09eeSRobert Watson 			}
408289e09eeSRobert Watson 		}
409289e09eeSRobert Watson 	}
41077edab90SPhilippe Charnier 	if (mflag) {
4118fae3551SRodney W. Grimes 		name = "minimum percentage of free space";
41276444424SBruce Evans 		if (sblock.fs_minfree == mvalue)
41377edab90SPhilippe Charnier 			warnx("%s remains unchanged as %d%%", name, mvalue);
41477edab90SPhilippe Charnier 		else {
4158fae3551SRodney W. Grimes 			warnx("%s changes from %d%% to %d%%",
41677edab90SPhilippe Charnier 				    name, sblock.fs_minfree, mvalue);
41777edab90SPhilippe Charnier 			sblock.fs_minfree = mvalue;
41877edab90SPhilippe Charnier 			if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
4198fae3551SRodney W. Grimes 				warnx(OPTWARN, "time", ">=", MINFREE);
42077edab90SPhilippe Charnier 			if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
4218fae3551SRodney W. Grimes 				warnx(OPTWARN, "space", "<", MINFREE);
422b1897c19SJulian Elischer 		}
42377edab90SPhilippe Charnier 	}
4249340fc72SEdward Tomasz Napierala 	if (Nflag) {
4259340fc72SEdward Tomasz Napierala 		name = "NFSv4 ACLs";
4269340fc72SEdward Tomasz Napierala 		if (strcmp(Nvalue, "enable") == 0) {
4279340fc72SEdward Tomasz Napierala 			if (sblock.fs_flags & FS_NFS4ACLS) {
4289340fc72SEdward Tomasz Napierala 				warnx("%s remains unchanged as enabled", name);
4299340fc72SEdward Tomasz Napierala 			} else if (sblock.fs_flags & FS_ACLS) {
4309340fc72SEdward Tomasz Napierala 				warnx("%s and POSIX.1e ACLs are mutually "
4319340fc72SEdward Tomasz Napierala 				    "exclusive", name);
4329340fc72SEdward Tomasz Napierala 			} else {
4339340fc72SEdward Tomasz Napierala 				sblock.fs_flags |= FS_NFS4ACLS;
4349340fc72SEdward Tomasz Napierala 				warnx("%s set", name);
4359340fc72SEdward Tomasz Napierala 			}
4369340fc72SEdward Tomasz Napierala 		} else if (strcmp(Nvalue, "disable") == 0) {
4379340fc72SEdward Tomasz Napierala 			if ((~sblock.fs_flags & FS_NFS4ACLS) ==
4389340fc72SEdward Tomasz Napierala 			    FS_NFS4ACLS) {
4399340fc72SEdward Tomasz Napierala 				warnx("%s remains unchanged as disabled",
4409340fc72SEdward Tomasz Napierala 				    name);
4419340fc72SEdward Tomasz Napierala 			} else {
4429340fc72SEdward Tomasz Napierala 				sblock.fs_flags &= ~FS_NFS4ACLS;
4439340fc72SEdward Tomasz Napierala 				warnx("%s cleared", name);
4449340fc72SEdward Tomasz Napierala 			}
4459340fc72SEdward Tomasz Napierala 		}
4469340fc72SEdward Tomasz Napierala 	}
44777edab90SPhilippe Charnier 	if (nflag) {
44877edab90SPhilippe Charnier  		name = "soft updates";
44977edab90SPhilippe Charnier  		if (strcmp(nvalue, "enable") == 0) {
45076444424SBruce Evans 			if (sblock.fs_flags & FS_DOSOFTDEP)
45177edab90SPhilippe Charnier 				warnx("%s remains unchanged as enabled", name);
45276444424SBruce Evans 			else if (sblock.fs_clean == 0) {
4531c2665d8SKirk McKusick 				warnx("%s cannot be enabled until fsck is run",
4541c2665d8SKirk McKusick 				    name);
45577edab90SPhilippe Charnier 			} else {
45677edab90SPhilippe Charnier  				sblock.fs_flags |= FS_DOSOFTDEP;
45777edab90SPhilippe Charnier  				warnx("%s set", name);
45877edab90SPhilippe Charnier 			}
45977edab90SPhilippe Charnier  		} else if (strcmp(nvalue, "disable") == 0) {
46076444424SBruce Evans 			if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP)
46177edab90SPhilippe Charnier 				warnx("%s remains unchanged as disabled", name);
46276444424SBruce Evans 			else {
46377edab90SPhilippe Charnier  				sblock.fs_flags &= ~FS_DOSOFTDEP;
46477edab90SPhilippe Charnier  				warnx("%s cleared", name);
46577edab90SPhilippe Charnier 			}
46677edab90SPhilippe Charnier  		}
46777edab90SPhilippe Charnier 	}
46877edab90SPhilippe Charnier 	if (oflag) {
4698fae3551SRodney W. Grimes 		name = "optimization preference";
4708fae3551SRodney W. Grimes 		chg[FS_OPTSPACE] = "space";
4718fae3551SRodney W. Grimes 		chg[FS_OPTTIME] = "time";
47276444424SBruce Evans 		if (sblock.fs_optim == ovalue)
47377edab90SPhilippe Charnier 			warnx("%s remains unchanged as %s", name, chg[ovalue]);
47477edab90SPhilippe Charnier 		else {
4758fae3551SRodney W. Grimes 			warnx("%s changes from %s to %s",
47677edab90SPhilippe Charnier 				    name, chg[sblock.fs_optim], chg[ovalue]);
47777edab90SPhilippe Charnier 			sblock.fs_optim = ovalue;
47877edab90SPhilippe Charnier 			if (sblock.fs_minfree >= MINFREE &&
47977edab90SPhilippe Charnier 			    ovalue == FS_OPTSPACE)
4808fae3551SRodney W. Grimes 				warnx(OPTWARN, "time", ">=", MINFREE);
48176444424SBruce Evans 			if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME)
4828fae3551SRodney W. Grimes 				warnx(OPTWARN, "space", "<", MINFREE);
4838fae3551SRodney W. Grimes 		}
48477edab90SPhilippe Charnier 	}
485a61ab64aSKirk McKusick 	if (sflag) {
486a61ab64aSKirk McKusick 		name = "expected number of files per directory";
487a6cc0cf6SKirk McKusick 		if (sblock.fs_avgfpdir == (unsigned)svalue) {
488a61ab64aSKirk McKusick 			warnx("%s remains unchanged as %d", name, svalue);
489a61ab64aSKirk McKusick 		}
490a61ab64aSKirk McKusick 		else {
491a61ab64aSKirk McKusick 			warnx("%s changes from %d to %d",
492a61ab64aSKirk McKusick 					name, sblock.fs_avgfpdir, svalue);
493a61ab64aSKirk McKusick 			sblock.fs_avgfpdir = svalue;
494a61ab64aSKirk McKusick 		}
495a61ab64aSKirk McKusick 	}
4962af14b60SPhilippe Charnier 
497907db4ddSJuli Mallett 	if (sbwrite(&disk, Aflag) == -1)
498907db4ddSJuli Mallett 		goto err;
499907db4ddSJuli Mallett 	ufs_disk_close(&disk);
5007382c45aSLuoqi Chen 	if (active) {
5017382c45aSLuoqi Chen 		bzero(&args, sizeof(args));
502907db4ddSJuli Mallett 		if (mount("ufs", on,
5037382c45aSLuoqi Chen 		    stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
5047382c45aSLuoqi Chen 			err(9, "%s: reload", special);
5057382c45aSLuoqi Chen 		warnx("file system reloaded");
5067382c45aSLuoqi Chen 	}
5078fae3551SRodney W. Grimes 	exit(0);
508907db4ddSJuli Mallett err:
509907db4ddSJuli Mallett 	if (disk.d_error != NULL)
510907db4ddSJuli Mallett 		errx(11, "%s: %s", special, disk.d_error);
511907db4ddSJuli Mallett 	else
512907db4ddSJuli Mallett 		err(12, "%s", special);
5138fae3551SRodney W. Grimes }
5148fae3551SRodney W. Grimes 
5158fae3551SRodney W. Grimes void
516113db2ddSJeff Roberson sbdirty(void)
517113db2ddSJeff Roberson {
518113db2ddSJeff Roberson 	disk.d_fs.fs_flags |= FS_UNCLEAN | FS_NEEDSFSCK;
519113db2ddSJeff Roberson 	disk.d_fs.fs_clean = 0;
520113db2ddSJeff Roberson }
521113db2ddSJeff Roberson 
522113db2ddSJeff Roberson int blocks;
523113db2ddSJeff Roberson static char clrbuf[MAXBSIZE];
524113db2ddSJeff Roberson 
525113db2ddSJeff Roberson static ufs2_daddr_t
526113db2ddSJeff Roberson journal_balloc(void)
527113db2ddSJeff Roberson {
528113db2ddSJeff Roberson 	ufs2_daddr_t blk;
529113db2ddSJeff Roberson 	struct cg *cgp;
530113db2ddSJeff Roberson 	int valid;
531113db2ddSJeff Roberson 	static int contig = 1;
532113db2ddSJeff Roberson 
533113db2ddSJeff Roberson 	cgp = &disk.d_cg;
534113db2ddSJeff Roberson 	for (;;) {
535113db2ddSJeff Roberson 		blk = cgballoc(&disk);
536113db2ddSJeff Roberson 		if (blk > 0)
537113db2ddSJeff Roberson 			break;
538113db2ddSJeff Roberson 		/*
539113db2ddSJeff Roberson 		 * If we failed to allocate a block from this cg, move to
540113db2ddSJeff Roberson 		 * the next.
541113db2ddSJeff Roberson 		 */
542113db2ddSJeff Roberson 		if (cgwrite(&disk) < 0) {
543113db2ddSJeff Roberson 			warn("Failed to write updated cg");
544113db2ddSJeff Roberson 			return (-1);
545113db2ddSJeff Roberson 		}
546113db2ddSJeff Roberson 		while ((valid = cgread(&disk)) == 1) {
547113db2ddSJeff Roberson 			/*
548113db2ddSJeff Roberson 			 * Try to minimize fragmentation by requiring a minimum
549113db2ddSJeff Roberson 			 * number of blocks present.
550113db2ddSJeff Roberson 			 */
551*53053595SJeff Roberson 			if (cgp->cg_cs.cs_nbfree > 256 * 1024)
552113db2ddSJeff Roberson 				break;
553113db2ddSJeff Roberson 			if (contig == 0 && cgp->cg_cs.cs_nbfree)
554113db2ddSJeff Roberson 				break;
555113db2ddSJeff Roberson 		}
556113db2ddSJeff Roberson 		if (valid)
557113db2ddSJeff Roberson 			continue;
558113db2ddSJeff Roberson 		/*
559113db2ddSJeff Roberson 		 * Try once through looking only for large contiguous regions
560113db2ddSJeff Roberson 		 * and again taking any space we can find.
561113db2ddSJeff Roberson 		 */
562113db2ddSJeff Roberson 		if (contig) {
563113db2ddSJeff Roberson 			contig = 0;
564113db2ddSJeff Roberson 			disk.d_ccg = 0;
565113db2ddSJeff Roberson 			warnx("Journal file fragmented.");
566113db2ddSJeff Roberson 			continue;
567113db2ddSJeff Roberson 		}
568113db2ddSJeff Roberson 		warnx("Failed to find sufficient free blocks for the journal");
569113db2ddSJeff Roberson 		return -1;
570113db2ddSJeff Roberson 	}
571113db2ddSJeff Roberson 	if (bwrite(&disk, fsbtodb(&sblock, blk), clrbuf,
572113db2ddSJeff Roberson 	    sblock.fs_bsize) <= 0) {
573113db2ddSJeff Roberson 		warn("Failed to initialize new block");
574113db2ddSJeff Roberson 		return -1;
575113db2ddSJeff Roberson 	}
576113db2ddSJeff Roberson 	return (blk);
577113db2ddSJeff Roberson }
578113db2ddSJeff Roberson 
579113db2ddSJeff Roberson /*
580113db2ddSJeff Roberson  * Search a directory block for the SUJ_FILE.
581113db2ddSJeff Roberson  */
582113db2ddSJeff Roberson static ino_t
583113db2ddSJeff Roberson dir_search(ufs2_daddr_t blk, int bytes)
584113db2ddSJeff Roberson {
585113db2ddSJeff Roberson 	char block[MAXBSIZE];
586113db2ddSJeff Roberson 	struct direct *dp;
587113db2ddSJeff Roberson 	int off;
588113db2ddSJeff Roberson 
589113db2ddSJeff Roberson 	if (bread(&disk, fsbtodb(&sblock, blk), block, bytes) <= 0) {
590113db2ddSJeff Roberson 		warn("Failed to read dir block");
591113db2ddSJeff Roberson 		return (-1);
592113db2ddSJeff Roberson 	}
593113db2ddSJeff Roberson 	for (off = 0; off < bytes; off += dp->d_reclen) {
594113db2ddSJeff Roberson 		dp = (struct direct *)&block[off];
595113db2ddSJeff Roberson 		if (dp->d_reclen == 0)
596113db2ddSJeff Roberson 			break;
597113db2ddSJeff Roberson 		if (dp->d_ino == 0)
598113db2ddSJeff Roberson 			continue;
599113db2ddSJeff Roberson 		if (dp->d_namlen != strlen(SUJ_FILE))
600113db2ddSJeff Roberson 			continue;
601113db2ddSJeff Roberson 		if (bcmp(dp->d_name, SUJ_FILE, dp->d_namlen) != 0)
602113db2ddSJeff Roberson 			continue;
603113db2ddSJeff Roberson 		return (dp->d_ino);
604113db2ddSJeff Roberson 	}
605113db2ddSJeff Roberson 
606113db2ddSJeff Roberson 	return (0);
607113db2ddSJeff Roberson }
608113db2ddSJeff Roberson 
609113db2ddSJeff Roberson /*
610113db2ddSJeff Roberson  * Search in the ROOTINO for the SUJ_FILE.  If it exists we can not enable
611113db2ddSJeff Roberson  * journaling.
612113db2ddSJeff Roberson  */
613113db2ddSJeff Roberson static ino_t
614113db2ddSJeff Roberson journal_findfile(void)
615113db2ddSJeff Roberson {
616113db2ddSJeff Roberson 	struct ufs1_dinode *dp1;
617113db2ddSJeff Roberson 	struct ufs2_dinode *dp2;
618113db2ddSJeff Roberson 	ino_t ino;
619113db2ddSJeff Roberson 	int mode;
620113db2ddSJeff Roberson 	void *ip;
621113db2ddSJeff Roberson 	int i;
622113db2ddSJeff Roberson 
623113db2ddSJeff Roberson 	if (getino(&disk, &ip, ROOTINO, &mode) != 0) {
624113db2ddSJeff Roberson 		warn("Failed to get root inode");
625113db2ddSJeff Roberson 		return (-1);
626113db2ddSJeff Roberson 	}
627113db2ddSJeff Roberson 	dp2 = ip;
628113db2ddSJeff Roberson 	dp1 = ip;
629113db2ddSJeff Roberson 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
630113db2ddSJeff Roberson 		if ((off_t)dp1->di_size >= lblktosize(&sblock, NDADDR)) {
631113db2ddSJeff Roberson 			warnx("ROOTINO extends beyond direct blocks.");
632113db2ddSJeff Roberson 			return (-1);
633113db2ddSJeff Roberson 		}
634113db2ddSJeff Roberson 		for (i = 0; i < NDADDR; i++) {
635113db2ddSJeff Roberson 			if (dp1->di_db[i] == 0)
636113db2ddSJeff Roberson 				break;
637113db2ddSJeff Roberson 			if ((ino = dir_search(dp1->di_db[i],
638113db2ddSJeff Roberson 			    sblksize(&sblock, (off_t)dp1->di_size, i))) != 0)
639113db2ddSJeff Roberson 				return (ino);
640113db2ddSJeff Roberson 		}
641113db2ddSJeff Roberson 	} else {
642113db2ddSJeff Roberson 		if ((off_t)dp1->di_size >= lblktosize(&sblock, NDADDR)) {
643113db2ddSJeff Roberson 			warnx("ROOTINO extends beyond direct blocks.");
644113db2ddSJeff Roberson 			return (-1);
645113db2ddSJeff Roberson 		}
646113db2ddSJeff Roberson 		for (i = 0; i < NDADDR; i++) {
647113db2ddSJeff Roberson 			if (dp2->di_db[i] == 0)
648113db2ddSJeff Roberson 				break;
649113db2ddSJeff Roberson 			if ((ino = dir_search(dp2->di_db[i],
650113db2ddSJeff Roberson 			    sblksize(&sblock, (off_t)dp2->di_size, i))) != 0)
651113db2ddSJeff Roberson 				return (ino);
652113db2ddSJeff Roberson 		}
653113db2ddSJeff Roberson 	}
654113db2ddSJeff Roberson 
655113db2ddSJeff Roberson 	return (0);
656113db2ddSJeff Roberson }
657113db2ddSJeff Roberson 
658113db2ddSJeff Roberson /*
659113db2ddSJeff Roberson  * Insert the journal at inode 'ino' into directory blk 'blk' at the first
660113db2ddSJeff Roberson  * free offset of 'off'.  DIRBLKSIZ blocks after off are initialized as
661113db2ddSJeff Roberson  * empty.
662113db2ddSJeff Roberson  */
663113db2ddSJeff Roberson static int
664113db2ddSJeff Roberson dir_insert(ufs2_daddr_t blk, off_t off, ino_t ino)
665113db2ddSJeff Roberson {
666113db2ddSJeff Roberson 	struct direct *dp;
667113db2ddSJeff Roberson 	char block[MAXBSIZE];
668113db2ddSJeff Roberson 
669113db2ddSJeff Roberson 	if (bread(&disk, fsbtodb(&sblock, blk), block, sblock.fs_bsize) <= 0) {
670113db2ddSJeff Roberson 		warn("Failed to read dir block");
671113db2ddSJeff Roberson 		return (-1);
672113db2ddSJeff Roberson 	}
673113db2ddSJeff Roberson 	bzero(&block[off], sblock.fs_bsize - off);
674113db2ddSJeff Roberson 	dp = (struct direct *)&block[off];
675113db2ddSJeff Roberson 	dp->d_ino = ino;
676113db2ddSJeff Roberson 	dp->d_reclen = DIRBLKSIZ;
677113db2ddSJeff Roberson 	dp->d_type = DT_REG;
678113db2ddSJeff Roberson 	dp->d_namlen = strlen(SUJ_FILE);
679113db2ddSJeff Roberson 	bcopy(SUJ_FILE, &dp->d_name, strlen(SUJ_FILE));
680113db2ddSJeff Roberson 	off += DIRBLKSIZ;
681113db2ddSJeff Roberson 	for (; off < sblock.fs_bsize; off += DIRBLKSIZ) {
682113db2ddSJeff Roberson 		dp = (struct direct *)&block[off];
683113db2ddSJeff Roberson 		dp->d_ino = 0;
684113db2ddSJeff Roberson 		dp->d_reclen = DIRBLKSIZ;
685113db2ddSJeff Roberson 		dp->d_type = DT_UNKNOWN;
686113db2ddSJeff Roberson 	}
687113db2ddSJeff Roberson 	if (bwrite(&disk, fsbtodb(&sblock, blk), block, sblock.fs_bsize) <= 0) {
688113db2ddSJeff Roberson 		warn("Failed to write dir block");
689113db2ddSJeff Roberson 		return (-1);
690113db2ddSJeff Roberson 	}
691113db2ddSJeff Roberson 	return (0);
692113db2ddSJeff Roberson }
693113db2ddSJeff Roberson 
694113db2ddSJeff Roberson /*
695113db2ddSJeff Roberson  * Extend a directory block in 'blk' by copying it to a full size block
696113db2ddSJeff Roberson  * and inserting the new journal inode into .sujournal.
697113db2ddSJeff Roberson  */
698113db2ddSJeff Roberson static int
699113db2ddSJeff Roberson dir_extend(ufs2_daddr_t blk, ufs2_daddr_t nblk, off_t size, ino_t ino)
700113db2ddSJeff Roberson {
701113db2ddSJeff Roberson 	char block[MAXBSIZE];
702113db2ddSJeff Roberson 
703113db2ddSJeff Roberson 	if (bread(&disk, fsbtodb(&sblock, blk), block, size) <= 0) {
704113db2ddSJeff Roberson 		warn("Failed to read dir block");
705113db2ddSJeff Roberson 		return (-1);
706113db2ddSJeff Roberson 	}
707113db2ddSJeff Roberson 	if (bwrite(&disk, fsbtodb(&sblock, nblk), block, size) <= 0) {
708113db2ddSJeff Roberson 		warn("Failed to write dir block");
709113db2ddSJeff Roberson 		return (-1);
710113db2ddSJeff Roberson 	}
711113db2ddSJeff Roberson 
712113db2ddSJeff Roberson 	return dir_insert(nblk, size, ino);
713113db2ddSJeff Roberson }
714113db2ddSJeff Roberson 
715113db2ddSJeff Roberson /*
716113db2ddSJeff Roberson  * Insert the journal file into the ROOTINO directory.  We always extend the
717113db2ddSJeff Roberson  * last frag
718113db2ddSJeff Roberson  */
719113db2ddSJeff Roberson static int
720113db2ddSJeff Roberson journal_insertfile(ino_t ino)
721113db2ddSJeff Roberson {
722113db2ddSJeff Roberson 	struct ufs1_dinode *dp1;
723113db2ddSJeff Roberson 	struct ufs2_dinode *dp2;
724113db2ddSJeff Roberson 	void *ip;
725113db2ddSJeff Roberson 	ufs2_daddr_t nblk;
726113db2ddSJeff Roberson 	ufs2_daddr_t blk;
727113db2ddSJeff Roberson 	ufs_lbn_t lbn;
728113db2ddSJeff Roberson 	int size;
729113db2ddSJeff Roberson 	int mode;
730113db2ddSJeff Roberson 	int off;
731113db2ddSJeff Roberson 
732113db2ddSJeff Roberson 	if (getino(&disk, &ip, ROOTINO, &mode) != 0) {
733113db2ddSJeff Roberson 		warn("Failed to get root inode");
734113db2ddSJeff Roberson 		sbdirty();
735113db2ddSJeff Roberson 		return (-1);
736113db2ddSJeff Roberson 	}
737113db2ddSJeff Roberson 	dp2 = ip;
738113db2ddSJeff Roberson 	dp1 = ip;
739113db2ddSJeff Roberson 	blk = 0;
740113db2ddSJeff Roberson 	size = 0;
741113db2ddSJeff Roberson 	nblk = journal_balloc();
742113db2ddSJeff Roberson 	if (nblk <= 0)
743113db2ddSJeff Roberson 		return (-1);
744113db2ddSJeff Roberson 	/*
745113db2ddSJeff Roberson 	 * For simplicity sake we aways extend the ROOTINO into a new
746113db2ddSJeff Roberson 	 * directory block rather than searching for space and inserting
747113db2ddSJeff Roberson 	 * into an existing block.  However, if the rootino has frags
748113db2ddSJeff Roberson 	 * have to free them and extend the block.
749113db2ddSJeff Roberson 	 */
750113db2ddSJeff Roberson 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
751113db2ddSJeff Roberson 		lbn = lblkno(&sblock, dp1->di_size);
752113db2ddSJeff Roberson 		off = blkoff(&sblock, dp1->di_size);
753113db2ddSJeff Roberson 		blk = dp1->di_db[lbn];
754113db2ddSJeff Roberson 		size = sblksize(&sblock, (off_t)dp1->di_size, lbn);
755113db2ddSJeff Roberson 	} else {
756113db2ddSJeff Roberson 		lbn = lblkno(&sblock, dp2->di_size);
757113db2ddSJeff Roberson 		off = blkoff(&sblock, dp2->di_size);
758113db2ddSJeff Roberson 		blk = dp2->di_db[lbn];
759113db2ddSJeff Roberson 		size = sblksize(&sblock, (off_t)dp2->di_size, lbn);
760113db2ddSJeff Roberson 	}
761113db2ddSJeff Roberson 	if (off != 0) {
762113db2ddSJeff Roberson 		if (dir_extend(blk, nblk, off, ino) == -1)
763113db2ddSJeff Roberson 			return (-1);
764113db2ddSJeff Roberson 	} else {
765113db2ddSJeff Roberson 		blk = 0;
766113db2ddSJeff Roberson 		if (dir_insert(nblk, 0, ino) == -1)
767113db2ddSJeff Roberson 			return (-1);
768113db2ddSJeff Roberson 	}
769113db2ddSJeff Roberson 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
770113db2ddSJeff Roberson 		dp1->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE;
771113db2ddSJeff Roberson 		dp1->di_db[lbn] = nblk;
772113db2ddSJeff Roberson 		dp1->di_size = lblktosize(&sblock, lbn+1);
773113db2ddSJeff Roberson 	} else {
774113db2ddSJeff Roberson 		dp2->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE;
775113db2ddSJeff Roberson 		dp2->di_db[lbn] = nblk;
776113db2ddSJeff Roberson 		dp2->di_size = lblktosize(&sblock, lbn+1);
777113db2ddSJeff Roberson 	}
778113db2ddSJeff Roberson 	if (putino(&disk) < 0) {
779113db2ddSJeff Roberson 		warn("Failed to write root inode");
780113db2ddSJeff Roberson 		return (-1);
781113db2ddSJeff Roberson 	}
782113db2ddSJeff Roberson 	if (cgwrite(&disk) < 0) {
783113db2ddSJeff Roberson 		warn("Failed to write updated cg");
784113db2ddSJeff Roberson 		sbdirty();
785113db2ddSJeff Roberson 		return (-1);
786113db2ddSJeff Roberson 	}
787113db2ddSJeff Roberson 	if (blk) {
788113db2ddSJeff Roberson 		if (cgbfree(&disk, blk, size) < 0) {
789113db2ddSJeff Roberson 			warn("Failed to write cg");
790113db2ddSJeff Roberson 			return (-1);
791113db2ddSJeff Roberson 		}
792113db2ddSJeff Roberson 	}
793113db2ddSJeff Roberson 
794113db2ddSJeff Roberson 	return (0);
795113db2ddSJeff Roberson }
796113db2ddSJeff Roberson 
797113db2ddSJeff Roberson static int
798113db2ddSJeff Roberson indir_fill(ufs2_daddr_t blk, int level, int *resid)
799113db2ddSJeff Roberson {
800113db2ddSJeff Roberson 	char indirbuf[MAXBSIZE];
801113db2ddSJeff Roberson 	ufs1_daddr_t *bap1;
802113db2ddSJeff Roberson 	ufs2_daddr_t *bap2;
803113db2ddSJeff Roberson 	ufs2_daddr_t nblk;
804113db2ddSJeff Roberson 	int ncnt;
805113db2ddSJeff Roberson 	int cnt;
806113db2ddSJeff Roberson 	int i;
807113db2ddSJeff Roberson 
808113db2ddSJeff Roberson 	bzero(indirbuf, sizeof(indirbuf));
809113db2ddSJeff Roberson 	bap1 = (ufs1_daddr_t *)indirbuf;
810113db2ddSJeff Roberson 	bap2 = (void *)bap1;
811113db2ddSJeff Roberson 	cnt = 0;
812113db2ddSJeff Roberson 	for (i = 0; i < NINDIR(&sblock) && *resid != 0; i++) {
813113db2ddSJeff Roberson 		nblk = journal_balloc();
814113db2ddSJeff Roberson 		if (nblk <= 0)
815113db2ddSJeff Roberson 			return (-1);
816113db2ddSJeff Roberson 		cnt++;
817113db2ddSJeff Roberson 		if (sblock.fs_magic == FS_UFS1_MAGIC)
818113db2ddSJeff Roberson 			*bap1++ = nblk;
819113db2ddSJeff Roberson 		else
820113db2ddSJeff Roberson 			*bap2++ = nblk;
821113db2ddSJeff Roberson 		if (level != 0) {
822113db2ddSJeff Roberson 			ncnt = indir_fill(nblk, level - 1, resid);
823113db2ddSJeff Roberson 			if (ncnt <= 0)
824113db2ddSJeff Roberson 				return (-1);
825113db2ddSJeff Roberson 			cnt += ncnt;
826113db2ddSJeff Roberson 		} else
827113db2ddSJeff Roberson 			(*resid)--;
828113db2ddSJeff Roberson 	}
829113db2ddSJeff Roberson 	if (bwrite(&disk, fsbtodb(&sblock, blk), indirbuf,
830113db2ddSJeff Roberson 	    sblock.fs_bsize) <= 0) {
831113db2ddSJeff Roberson 		warn("Failed to write indirect");
832113db2ddSJeff Roberson 		return (-1);
833113db2ddSJeff Roberson 	}
834113db2ddSJeff Roberson 	return (cnt);
835113db2ddSJeff Roberson }
836113db2ddSJeff Roberson 
837113db2ddSJeff Roberson /*
838113db2ddSJeff Roberson  * Clear the flag bits so the journal can be removed.
839113db2ddSJeff Roberson  */
840113db2ddSJeff Roberson void
841113db2ddSJeff Roberson journal_clear(void)
842113db2ddSJeff Roberson {
843113db2ddSJeff Roberson 	struct ufs1_dinode *dp1;
844113db2ddSJeff Roberson 	struct ufs2_dinode *dp2;
845113db2ddSJeff Roberson 	ino_t ino;
846113db2ddSJeff Roberson 	int mode;
847113db2ddSJeff Roberson 	void *ip;
848113db2ddSJeff Roberson 
849113db2ddSJeff Roberson 	ino = journal_findfile();
850113db2ddSJeff Roberson 	if (ino == (ino_t)-1 || ino == 0) {
851113db2ddSJeff Roberson 		warnx("Journal file does not exist");
852113db2ddSJeff Roberson 		return;
853113db2ddSJeff Roberson 	}
854113db2ddSJeff Roberson 	printf("Clearing journal flags from inode %d\n", ino);
855113db2ddSJeff Roberson 	if (getino(&disk, &ip, ino, &mode) != 0) {
856113db2ddSJeff Roberson 		warn("Failed to get journal inode");
857113db2ddSJeff Roberson 		return;
858113db2ddSJeff Roberson 	}
859113db2ddSJeff Roberson 	dp2 = ip;
860113db2ddSJeff Roberson 	dp1 = ip;
861113db2ddSJeff Roberson 	if (sblock.fs_magic == FS_UFS1_MAGIC)
862113db2ddSJeff Roberson 		dp1->di_flags = 0;
863113db2ddSJeff Roberson 	else
864113db2ddSJeff Roberson 		dp2->di_flags = 0;
865113db2ddSJeff Roberson 	if (putino(&disk) < 0) {
866113db2ddSJeff Roberson 		warn("Failed to write journal inode");
867113db2ddSJeff Roberson 		return;
868113db2ddSJeff Roberson 	}
869113db2ddSJeff Roberson }
870113db2ddSJeff Roberson 
871113db2ddSJeff Roberson int
872113db2ddSJeff Roberson journal_alloc(int64_t size)
873113db2ddSJeff Roberson {
874113db2ddSJeff Roberson 	struct ufs1_dinode *dp1;
875113db2ddSJeff Roberson 	struct ufs2_dinode *dp2;
876113db2ddSJeff Roberson 	ufs2_daddr_t blk;
877113db2ddSJeff Roberson 	void *ip;
878113db2ddSJeff Roberson 	struct cg *cgp;
879113db2ddSJeff Roberson 	int resid;
880113db2ddSJeff Roberson 	ino_t ino;
881113db2ddSJeff Roberson 	int blks;
882113db2ddSJeff Roberson 	int mode;
883113db2ddSJeff Roberson 	int i;
884113db2ddSJeff Roberson 
885113db2ddSJeff Roberson 	cgp = &disk.d_cg;
886113db2ddSJeff Roberson 	ino = 0;
887113db2ddSJeff Roberson 
888113db2ddSJeff Roberson 	/*
889113db2ddSJeff Roberson 	 * If the journal file exists we can't allocate it.
890113db2ddSJeff Roberson 	 */
891113db2ddSJeff Roberson 	ino = journal_findfile();
892113db2ddSJeff Roberson 	if (ino == (ino_t)-1)
893113db2ddSJeff Roberson 		return (-1);
894113db2ddSJeff Roberson 	if (ino > 0) {
895113db2ddSJeff Roberson 		warnx("Journal file %s already exists, please remove.",
896113db2ddSJeff Roberson 		    SUJ_FILE);
897113db2ddSJeff Roberson 		return (-1);
898113db2ddSJeff Roberson 	}
899113db2ddSJeff Roberson 	/*
900113db2ddSJeff Roberson 	 * If the user didn't supply a size pick one based on the filesystem
901113db2ddSJeff Roberson 	 * size constrained with hardcoded MIN and MAX values.  We opt for
902113db2ddSJeff Roberson 	 * 1/1024th of the filesystem up to MAX but not exceeding one CG and
903113db2ddSJeff Roberson 	 * not less than the MIN.
904113db2ddSJeff Roberson 	 */
905113db2ddSJeff Roberson 	if (size == 0) {
906113db2ddSJeff Roberson 		size = (sblock.fs_size * sblock.fs_bsize) / 1024;
907113db2ddSJeff Roberson 		size = MIN(SUJ_MAX, size);
908113db2ddSJeff Roberson 		if (size / sblock.fs_fsize > sblock.fs_fpg)
909113db2ddSJeff Roberson 			size = sblock.fs_fpg * sblock.fs_fsize;
910113db2ddSJeff Roberson 		size = MAX(SUJ_MIN, size);
911*53053595SJeff Roberson 		/* fsck does not support fragments in journal files. */
912*53053595SJeff Roberson 		size = roundup(size, sblock.fs_bsize);
913113db2ddSJeff Roberson 	}
914113db2ddSJeff Roberson 	resid = blocks = size / sblock.fs_bsize;
915113db2ddSJeff Roberson 	if (sblock.fs_cstotal.cs_nbfree < blocks) {
916113db2ddSJeff Roberson 		warn("Insufficient free space for %jd byte journal", size);
917113db2ddSJeff Roberson 		return (-1);
918113db2ddSJeff Roberson 	}
919113db2ddSJeff Roberson 	/*
920113db2ddSJeff Roberson 	 * Find a cg with enough blocks to satisfy the journal
921113db2ddSJeff Roberson 	 * size.  Presently the journal does not span cgs.
922113db2ddSJeff Roberson 	 */
923113db2ddSJeff Roberson 	while (cgread(&disk) == 1) {
924113db2ddSJeff Roberson 		if (cgp->cg_cs.cs_nifree == 0)
925113db2ddSJeff Roberson 			continue;
926113db2ddSJeff Roberson 		ino = cgialloc(&disk);
927113db2ddSJeff Roberson 		if (ino <= 0)
928113db2ddSJeff Roberson 			break;
929113db2ddSJeff Roberson 		printf("Using inode %d in cg %d for %jd byte journal\n",
930113db2ddSJeff Roberson 		    ino, cgp->cg_cgx, size);
931113db2ddSJeff Roberson 		if (getino(&disk, &ip, ino, &mode) != 0) {
932113db2ddSJeff Roberson 			warn("Failed to get allocated inode");
933113db2ddSJeff Roberson 			sbdirty();
934113db2ddSJeff Roberson 			goto out;
935113db2ddSJeff Roberson 		}
936113db2ddSJeff Roberson 		/*
937113db2ddSJeff Roberson 		 * We leave fields unrelated to the number of allocated
938113db2ddSJeff Roberson 		 * blocks and size uninitialized.  This causes legacy
939113db2ddSJeff Roberson 		 * fsck implementations to clear the inode.
940113db2ddSJeff Roberson 		 */
941113db2ddSJeff Roberson 		dp2 = ip;
942113db2ddSJeff Roberson 		dp1 = ip;
943113db2ddSJeff Roberson 		if (sblock.fs_magic == FS_UFS1_MAGIC) {
944113db2ddSJeff Roberson 			bzero(dp1, sizeof(*dp1));
945113db2ddSJeff Roberson 			dp1->di_size = size;
946113db2ddSJeff Roberson 			dp1->di_mode = IFREG | IREAD;
947113db2ddSJeff Roberson 			dp1->di_nlink = 1;
948113db2ddSJeff Roberson 			dp1->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
949113db2ddSJeff Roberson 		} else {
950113db2ddSJeff Roberson 			bzero(dp2, sizeof(*dp2));
951113db2ddSJeff Roberson 			dp2->di_size = size;
952113db2ddSJeff Roberson 			dp2->di_mode = IFREG | IREAD;
953113db2ddSJeff Roberson 			dp2->di_nlink = 1;
954113db2ddSJeff Roberson 			dp2->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
955113db2ddSJeff Roberson 		}
956113db2ddSJeff Roberson 		for (i = 0; i < NDADDR && resid; i++, resid--) {
957113db2ddSJeff Roberson 			blk = journal_balloc();
958113db2ddSJeff Roberson 			if (blk <= 0)
959113db2ddSJeff Roberson 				goto out;
960113db2ddSJeff Roberson 			if (sblock.fs_magic == FS_UFS1_MAGIC) {
961113db2ddSJeff Roberson 				dp1->di_db[i] = blk;
962113db2ddSJeff Roberson 				dp1->di_blocks++;
963113db2ddSJeff Roberson 			} else {
964113db2ddSJeff Roberson 				dp2->di_db[i] = blk;
965113db2ddSJeff Roberson 				dp2->di_blocks++;
966113db2ddSJeff Roberson 			}
967113db2ddSJeff Roberson 		}
968113db2ddSJeff Roberson 		for (i = 0; i < NIADDR && resid; i++) {
969113db2ddSJeff Roberson 			blk = journal_balloc();
970113db2ddSJeff Roberson 			if (blk <= 0)
971113db2ddSJeff Roberson 				goto out;
972113db2ddSJeff Roberson 			blks = indir_fill(blk, i, &resid) + 1;
973113db2ddSJeff Roberson 			if (blks <= 0) {
974113db2ddSJeff Roberson 				sbdirty();
975113db2ddSJeff Roberson 				goto out;
976113db2ddSJeff Roberson 			}
977113db2ddSJeff Roberson 			if (sblock.fs_magic == FS_UFS1_MAGIC) {
978113db2ddSJeff Roberson 				dp1->di_ib[i] = blk;
979113db2ddSJeff Roberson 				dp1->di_blocks += blks;
980113db2ddSJeff Roberson 			} else {
981113db2ddSJeff Roberson 				dp2->di_ib[i] = blk;
982113db2ddSJeff Roberson 				dp2->di_blocks += blks;
983113db2ddSJeff Roberson 			}
984113db2ddSJeff Roberson 		}
985113db2ddSJeff Roberson 		if (sblock.fs_magic == FS_UFS1_MAGIC)
986113db2ddSJeff Roberson 			dp1->di_blocks *= sblock.fs_bsize / disk.d_bsize;
987113db2ddSJeff Roberson 		else
988113db2ddSJeff Roberson 			dp2->di_blocks *= sblock.fs_bsize / disk.d_bsize;
989113db2ddSJeff Roberson 		if (putino(&disk) < 0) {
990113db2ddSJeff Roberson 			warn("Failed to write inode");
991113db2ddSJeff Roberson 			sbdirty();
992113db2ddSJeff Roberson 			return (-1);
993113db2ddSJeff Roberson 		}
994113db2ddSJeff Roberson 		if (cgwrite(&disk) < 0) {
995113db2ddSJeff Roberson 			warn("Failed to write updated cg");
996113db2ddSJeff Roberson 			sbdirty();
997113db2ddSJeff Roberson 			return (-1);
998113db2ddSJeff Roberson 		}
999113db2ddSJeff Roberson 		if (journal_insertfile(ino) < 0) {
1000113db2ddSJeff Roberson 			sbdirty();
1001113db2ddSJeff Roberson 			return (-1);
1002113db2ddSJeff Roberson 		}
1003113db2ddSJeff Roberson 		sblock.fs_sujfree = 0;
1004113db2ddSJeff Roberson 		return (0);
1005113db2ddSJeff Roberson 	}
1006113db2ddSJeff Roberson 	warnx("Insufficient free space for the journal.");
1007113db2ddSJeff Roberson out:
1008113db2ddSJeff Roberson 	return (-1);
1009113db2ddSJeff Roberson }
1010113db2ddSJeff Roberson 
1011113db2ddSJeff Roberson void
1012b1f0fda0SJuli Mallett usage(void)
10138fae3551SRodney W. Grimes {
1014727c1288SEdwin Groothuis 	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
10151f6a4631SRuslan Ermilov "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]",
1016727c1288SEdwin Groothuis "              [-J enable | disable] [-j enable | disable]",
1017727c1288SEdwin Groothuis "              [-L volname] [-l enable | disable] [-m minfree]",
1018727c1288SEdwin Groothuis "              [-N enable | disable] [-n enable | disable]",
10199340fc72SEdward Tomasz Napierala "              [-o space | time] [-p] [-s avgfpdir] special | filesystem");
10208fae3551SRodney W. Grimes 	exit(2);
10218fae3551SRodney W. Grimes }
10228fae3551SRodney W. Grimes 
10238fae3551SRodney W. Grimes void
1024b1f0fda0SJuli Mallett printfs(void)
102516a7269eSJoerg Wunsch {
10269340fc72SEdward Tomasz Napierala 	warnx("POSIX.1e ACLs: (-a)                                %s",
102781dc101cSRobert Watson 		(sblock.fs_flags & FS_ACLS)? "enabled" : "disabled");
10289340fc72SEdward Tomasz Napierala 	warnx("NFSv4 ACLs: (-N)                                   %s",
10299340fc72SEdward Tomasz Napierala 		(sblock.fs_flags & FS_NFS4ACLS)? "enabled" : "disabled");
103081dc101cSRobert Watson 	warnx("MAC multilabel: (-l)                               %s",
103181dc101cSRobert Watson 		(sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled");
1032b1897c19SJulian Elischer 	warnx("soft updates: (-n)                                 %s",
1033b1897c19SJulian Elischer 		(sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
1034113db2ddSJeff Roberson 	warnx("soft update journaling: (-j)                       %s",
1035113db2ddSJeff Roberson 		(sblock.fs_flags & FS_SUJ)? "enabled" : "disabled");
1036868c68edSPawel Jakub Dawidek 	warnx("gjournal: (-J)                                     %s",
1037868c68edSPawel Jakub Dawidek 		(sblock.fs_flags & FS_GJOURNAL)? "enabled" : "disabled");
103816a7269eSJoerg Wunsch 	warnx("maximum blocks per file in a cylinder group: (-e)  %d",
103916a7269eSJoerg Wunsch 	      sblock.fs_maxbpg);
1040a61ab64aSKirk McKusick 	warnx("average file size: (-f)                            %d",
1041a61ab64aSKirk McKusick 	      sblock.fs_avgfilesize);
1042a61ab64aSKirk McKusick 	warnx("average number of files in a directory: (-s)       %d",
1043a61ab64aSKirk McKusick 	      sblock.fs_avgfpdir);
104416a7269eSJoerg Wunsch 	warnx("minimum percentage of free space: (-m)             %d%%",
104516a7269eSJoerg Wunsch 	      sblock.fs_minfree);
104616a7269eSJoerg Wunsch 	warnx("optimization preference: (-o)                      %s",
104716a7269eSJoerg Wunsch 	      sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
104816a7269eSJoerg Wunsch 	if (sblock.fs_minfree >= MINFREE &&
104916a7269eSJoerg Wunsch 	    sblock.fs_optim == FS_OPTSPACE)
105016a7269eSJoerg Wunsch 		warnx(OPTWARN, "time", ">=", MINFREE);
105116a7269eSJoerg Wunsch 	if (sblock.fs_minfree < MINFREE &&
105216a7269eSJoerg Wunsch 	    sblock.fs_optim == FS_OPTTIME)
105316a7269eSJoerg Wunsch 		warnx(OPTWARN, "space", "<", MINFREE);
1054c715b047SGordon Tetlow 	warnx("volume label: (-L)                                 %s",
1055c715b047SGordon Tetlow 		sblock.fs_volname);
105616a7269eSJoerg Wunsch }
1057