Annotation of src/sbin/tunefs/tunefs.c, Revision 1.38
1.38 ! ad 1: /* $NetBSD: tunefs.c,v 1.37 2008/07/31 15:55:41 simonb Exp $ */
1.10 cgd 2:
1.1 cgd 3: /*
1.8 mycroft 4: * Copyright (c) 1983, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.28 agc 15: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
1.11 lukem 32: #include <sys/cdefs.h>
1.1 cgd 33: #ifndef lint
1.34 lukem 34: __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
35: The Regents of the University of California. All rights reserved.");
1.1 cgd 36: #endif /* not lint */
37:
38: #ifndef lint
1.10 cgd 39: #if 0
1.12 lukem 40: static char sccsid[] = "@(#)tunefs.c 8.3 (Berkeley) 5/3/95";
1.10 cgd 41: #else
1.38 ! ad 42: __RCSID("$NetBSD: tunefs.c,v 1.37 2008/07/31 15:55:41 simonb Exp $");
1.10 cgd 43: #endif
1.1 cgd 44: #endif /* not lint */
45:
46: /*
47: * tunefs: change layout parameters to an existing file system.
48: */
49: #include <sys/param.h>
1.8 mycroft 50:
51: #include <ufs/ffs/fs.h>
1.13 bouyer 52: #include <ufs/ffs/ffs_extern.h>
1.35 simonb 53: #include <ufs/ufs/ufs_wapbl.h>
1.18 bouyer 54:
55: #include <machine/bswap.h>
1.8 mycroft 56:
1.22 lukem 57: #include <err.h>
1.8 mycroft 58: #include <errno.h>
1.6 cgd 59: #include <fcntl.h>
1.1 cgd 60: #include <fstab.h>
1.22 lukem 61: #include <paths.h>
1.1 cgd 62: #include <stdio.h>
1.6 cgd 63: #include <stdlib.h>
1.14 thorpej 64: #include <string.h>
1.6 cgd 65: #include <unistd.h>
1.25 lukem 66: #include <util.h>
1.6 cgd 67:
68: /* the optimization warning string template */
1.8 mycroft 69: #define OPTWARN "should optimize for %s with minfree %s %d%%"
1.1 cgd 70:
71: union {
72: struct fs sb;
73: char pad[MAXBSIZE];
74: } sbun;
75: #define sblock sbun.sb
1.13 bouyer 76: char buf[MAXBSIZE];
1.1 cgd 77:
1.22 lukem 78: int fi;
1.27 fvdl 79: long dev_bsize = 512;
1.22 lukem 80: int needswap = 0;
1.27 fvdl 81: int is_ufs2 = 0;
82: off_t sblockloc;
83:
84: static off_t sblock_try[] = SBLOCKSEARCH;
1.22 lukem 85:
1.25 lukem 86: static void bwrite(daddr_t, char *, int, const char *);
87: static void bread(daddr_t, char *, int, const char *);
1.35 simonb 88: static void change_log_info(long long);
1.22 lukem 89: static void getsb(struct fs *, const char *);
1.26 lukem 90: static int openpartition(const char *, int, char *, size_t);
1.35 simonb 91: static void show_log_info(void);
1.22 lukem 92: static void usage(void);
1.6 cgd 93:
94: int
1.22 lukem 95: main(int argc, char *argv[])
1.1 cgd 96: {
1.25 lukem 97: int i, ch, Aflag, Fflag, Nflag, openflags;
1.22 lukem 98: const char *special, *chg[2];
1.26 lukem 99: char device[MAXPATHLEN];
1.27 fvdl 100: int maxbpg, minfree, optim;
1.24 lukem 101: int avgfilesize, avgfpdir;
1.35 simonb 102: long long logfilesize;
1.22 lukem 103:
104: Aflag = Fflag = Nflag = 0;
1.27 fvdl 105: maxbpg = minfree = optim = -1;
1.24 lukem 106: avgfilesize = avgfpdir = -1;
1.35 simonb 107: logfilesize = -1;
1.22 lukem 108: chg[FS_OPTSPACE] = "space";
109: chg[FS_OPTTIME] = "time";
110:
1.38 ! ad 111: while ((ch = getopt(argc, argv, "AFNe:g:h:l:m:o:")) != -1) {
1.22 lukem 112: switch (ch) {
113:
114: case 'A':
115: Aflag++;
116: break;
117:
118: case 'F':
119: Fflag++;
120: break;
121:
122: case 'N':
123: Nflag++;
124: break;
125:
126: case 'e':
1.35 simonb 127: maxbpg = strsuftoll(
1.22 lukem 128: "maximum blocks per file in a cylinder group",
1.35 simonb 129: optarg, 1, INT_MAX);
1.22 lukem 130: break;
131:
1.24 lukem 132: case 'g':
1.35 simonb 133: avgfilesize = strsuftoll("average file size", optarg,
134: 1, INT_MAX);
1.24 lukem 135: break;
136:
137: case 'h':
1.35 simonb 138: avgfpdir = strsuftoll(
1.24 lukem 139: "expected number of files per directory",
1.35 simonb 140: optarg, 1, INT_MAX);
141: break;
142:
143: case 'l':
144: logfilesize = strsuftoll("journal log file size",
145: optarg, 0, INT_MAX);
1.24 lukem 146: break;
1.22 lukem 147:
148: case 'm':
1.35 simonb 149: minfree = strsuftoll("minimum percentage of free space",
150: optarg, 0, 99);
1.22 lukem 151: break;
152:
153: case 'o':
154: if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
155: optim = FS_OPTSPACE;
156: else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
157: optim = FS_OPTTIME;
158: else
159: errx(10,
160: "bad %s (options are `space' or `time')",
161: "optimization preference");
162: break;
163:
164: default:
165: usage();
166: }
167: }
168: argc -= optind;
169: argv += optind;
170: if (argc != 1)
1.6 cgd 171: usage();
1.22 lukem 172:
173: special = argv[0];
1.25 lukem 174: openflags = Nflag ? O_RDONLY : O_RDWR;
1.26 lukem 175: if (Fflag)
1.25 lukem 176: fi = open(special, openflags);
1.26 lukem 177: else {
178: fi = openpartition(special, openflags, device, sizeof(device));
1.25 lukem 179: special = device;
1.1 cgd 180: }
1.26 lukem 181: if (fi == -1)
182: err(1, "%s", special);
1.1 cgd 183: getsb(&sblock, special);
1.22 lukem 184:
1.23 lukem 185: #define CHANGEVAL(old, new, type, suffix) do \
186: if ((new) != -1) { \
187: if ((new) == (old)) \
188: warnx("%s remains unchanged at %d%s", \
189: (type), (old), (suffix)); \
190: else { \
191: warnx("%s changes from %d%s to %d%s", \
192: (type), (old), (suffix), (new), (suffix)); \
193: (old) = (new); \
194: } \
195: } while (/* CONSTCOND */0)
196:
1.25 lukem 197: warnx("tuning %s", special);
1.23 lukem 198: CHANGEVAL(sblock.fs_maxbpg, maxbpg,
199: "maximum blocks per file in a cylinder group", "");
200: CHANGEVAL(sblock.fs_minfree, minfree,
201: "minimum percentage of free space", "%");
1.22 lukem 202: if (minfree != -1) {
203: if (minfree >= MINFREE &&
204: sblock.fs_optim == FS_OPTSPACE)
205: warnx(OPTWARN, "time", ">=", MINFREE);
206: if (minfree < MINFREE &&
207: sblock.fs_optim == FS_OPTTIME)
208: warnx(OPTWARN, "space", "<", MINFREE);
209: }
210: if (optim != -1) {
211: if (sblock.fs_optim == optim) {
212: warnx("%s remains unchanged as %s",
213: "optimization preference",
214: chg[optim]);
215: } else {
216: warnx("%s changes from %s to %s",
217: "optimization preference",
218: chg[sblock.fs_optim], chg[optim]);
219: sblock.fs_optim = optim;
220: if (sblock.fs_minfree >= MINFREE &&
221: optim == FS_OPTSPACE)
222: warnx(OPTWARN, "time", ">=", MINFREE);
223: if (sblock.fs_minfree < MINFREE &&
224: optim == FS_OPTTIME)
225: warnx(OPTWARN, "space", "<", MINFREE);
226: }
227: }
1.24 lukem 228: CHANGEVAL(sblock.fs_avgfilesize, avgfilesize,
229: "average file size", "");
230: CHANGEVAL(sblock.fs_avgfpdir, avgfpdir,
231: "expected number of files per directory", "");
1.1 cgd 232:
1.35 simonb 233: if (logfilesize >= 0)
234: change_log_info(logfilesize);
235:
1.12 lukem 236: if (Nflag) {
1.37 simonb 237: printf("tunefs: current settings of %s\n", special);
238: printf("\tmaximum contiguous block count %d\n",
1.12 lukem 239: sblock.fs_maxcontig);
1.37 simonb 240: printf("\tmaximum blocks per file in a cylinder group %d\n",
1.12 lukem 241: sblock.fs_maxbpg);
1.37 simonb 242: printf("\tminimum percentage of free space %d%%\n",
1.12 lukem 243: sblock.fs_minfree);
1.37 simonb 244: printf("\toptimization preference: %s\n", chg[sblock.fs_optim]);
245: printf("\taverage file size: %d\n", sblock.fs_avgfilesize);
246: printf("\texpected number of files per directory: %d\n",
1.24 lukem 247: sblock.fs_avgfpdir);
1.35 simonb 248: show_log_info();
1.37 simonb 249: printf("tunefs: no changes made\n");
1.12 lukem 250: exit(0);
251: }
1.22 lukem 252:
1.27 fvdl 253: memcpy(buf, (char *)&sblock, SBLOCKSIZE);
1.13 bouyer 254: if (needswap)
1.21 lukem 255: ffs_sb_swap((struct fs*)buf, (struct fs*)buf);
1.27 fvdl 256: bwrite(sblockloc, buf, SBLOCKSIZE, special);
1.1 cgd 257: if (Aflag)
258: for (i = 0; i < sblock.fs_ncg; i++)
259: bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)),
1.27 fvdl 260: buf, SBLOCKSIZE, special);
1.1 cgd 261: close(fi);
262: exit(0);
1.6 cgd 263: }
264:
1.35 simonb 265: static void
266: show_log_info(void)
267: {
268: const char *loc;
1.36 simonb 269: uint64_t size, blksize, logsize;
1.35 simonb 270: int print;
271:
272: switch (sblock.fs_journal_location) {
273: case UFS_WAPBL_JOURNALLOC_NONE:
274: print = blksize = 0;
275: /* nothing */
276: break;
277: case UFS_WAPBL_JOURNALLOC_END_PARTITION:
278: loc = "end of partition";
279: size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT];
280: blksize = sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ];
281: print = 1;
282: break;
283: case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
284: loc = "in filesystem";
285: size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT];
286: blksize = sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ];
287: print = 1;
288: break;
289: default:
290: loc = "unknown";
291: size = blksize = 0;
292: print = 1;
293: break;
294: }
295:
296: if (print) {
1.36 simonb 297: logsize = size * blksize;
298:
1.37 simonb 299: printf("\tjournal log file location: %s\n", loc);
300: printf("\tjournal log file size: ");
1.36 simonb 301: if (logsize == 0)
1.37 simonb 302: printf("0\n");
1.36 simonb 303: else {
304: char sizebuf[8];
305: humanize_number(sizebuf, 6, size * blksize, "B",
306: HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1.37 simonb 307: printf("%s (%" PRId64 " bytes)", sizebuf, logsize);
1.36 simonb 308: }
1.37 simonb 309: printf("\n");
310: printf("\tjournal log flags:");
1.35 simonb 311: if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CREATE_LOG)
1.37 simonb 312: printf(" clear-log");
1.35 simonb 313: if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CLEAR_LOG)
1.37 simonb 314: printf(" clear-log");
315: printf("\n");
1.35 simonb 316: }
317: }
318:
319: static void
320: change_log_info(long long logfilesize)
1.6 cgd 321: {
1.35 simonb 322: /*
323: * NOTES:
324: * - only operate on in-filesystem log sizes
325: * - can't change size of existing log
326: * - if current is same, no action
327: * - if current is zero and new is non-zero, set flag to create log
328: * on next mount
329: * - if current is non-zero and new is zero, set flag to clear log
330: * on next mount
331: */
332: int in_fs_log;
333: uint64_t old_size;
334:
335: old_size = 0;
336: switch (sblock.fs_journal_location) {
337: case UFS_WAPBL_JOURNALLOC_END_PARTITION:
338: in_fs_log = 0;
339: old_size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT] *
340: sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ];
341: break;
342:
343: case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
344: in_fs_log = 1;
345: old_size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] *
346: sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ];
347: break;
348:
349: case UFS_WAPBL_JOURNALLOC_NONE:
350: default:
351: in_fs_log = 0;
352: old_size = 0;
353: break;
354: }
355:
356: if (!in_fs_log)
357: errx(1, "Can't change size of non-in-filesystem log");
358:
359: if (old_size == logfilesize && logfilesize > 0) {
360: /* no action */
361: warnx("log file size remains unchanged at %lld", logfilesize);
362: return;
363: }
364:
365: if (logfilesize == 0) {
366: /*
367: * Don't clear out the locators - the kernel might need
368: * these to find the log! Just set the "clear the log"
369: * flag and let the kernel do the rest.
370: */
371: sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CLEAR_LOG;
372: sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CREATE_LOG;
373: warnx("log file size cleared from %" PRIu64 "", old_size);
374: return;
375: }
1.8 mycroft 376:
1.35 simonb 377: if (old_size == 0) {
378: /* create new log of desired size next mount */
379: sblock.fs_journal_location = UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM;
380: sblock.fs_journallocs[UFS_WAPBL_INFS_ADDR] = 0;
381: sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] = logfilesize;
382: sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ] = 0;
383: sblock.fs_journallocs[UFS_WAPBL_INFS_INO] = 0;
384: sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CREATE_LOG;
385: sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CLEAR_LOG;
386: warnx("log file size set to %lld", logfilesize);
387: } else {
388: errx(1,
389: "Can't change existing log size from %" PRIu64 " to %lld",
390: old_size, logfilesize);
391: }
1.22 lukem 392: }
393:
394: static void
395: usage(void)
396: {
397:
1.29 jmmv 398: fprintf(stderr, "usage: tunefs [-AFN] tuneup-options special-device\n");
1.1 cgd 399: fprintf(stderr, "where tuneup-options are:\n");
400: fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
1.24 lukem 401: fprintf(stderr, "\t-g average file size\n");
402: fprintf(stderr, "\t-h expected number of files per directory\n");
1.35 simonb 403: fprintf(stderr, "\t-l journal log file size (`0' to clear journal)\n");
1.1 cgd 404: fprintf(stderr, "\t-m minimum percentage of free space\n");
1.23 lukem 405: fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
1.8 mycroft 406: exit(2);
1.1 cgd 407: }
408:
1.22 lukem 409: static void
410: getsb(struct fs *fs, const char *file)
1.1 cgd 411: {
1.27 fvdl 412: int i;
1.1 cgd 413:
1.30 dsl 414: for (i = 0; ; i++) {
415: if (sblock_try[i] == -1)
416: errx(5, "cannot find filesystem superblock");
1.27 fvdl 417: bread(sblock_try[i] / dev_bsize, (char *)fs, SBLOCKSIZE, file);
418: switch(fs->fs_magic) {
419: case FS_UFS2_MAGIC:
420: is_ufs2 = 1;
421: /*FALLTHROUGH*/
422: case FS_UFS1_MAGIC:
1.30 dsl 423: break;
1.27 fvdl 424: case FS_UFS2_MAGIC_SWAPPED:
425: is_ufs2 = 1;
426: /*FALLTHROUGH*/
427: case FS_UFS1_MAGIC_SWAPPED:
1.22 lukem 428: warnx("%s: swapping byte order", file);
1.13 bouyer 429: needswap = 1;
1.21 lukem 430: ffs_sb_swap(fs, fs);
1.30 dsl 431: break;
1.27 fvdl 432: default:
1.30 dsl 433: continue;
1.27 fvdl 434: }
1.30 dsl 435: if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2)
436: continue;
1.31 dsl 437: if ((is_ufs2 || fs->fs_old_flags & FS_FLAGS_UPDATED)
1.30 dsl 438: && fs->fs_sblockloc != sblock_try[i])
439: continue;
440: break;
1.17 ross 441: }
1.30 dsl 442:
1.1 cgd 443: dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
1.27 fvdl 444: sblockloc = sblock_try[i] / dev_bsize;
1.1 cgd 445: }
446:
1.22 lukem 447: static void
1.25 lukem 448: bwrite(daddr_t blk, char *buffer, int size, const char *file)
1.1 cgd 449: {
1.25 lukem 450: off_t offset;
1.8 mycroft 451:
1.25 lukem 452: offset = (off_t)blk * dev_bsize;
453: if (lseek(fi, offset, SEEK_SET) == -1)
454: err(6, "%s: seeking to %lld", file, (long long)offset);
1.22 lukem 455: if (write(fi, buffer, size) != size)
1.25 lukem 456: err(7, "%s: writing %d bytes", file, size);
1.1 cgd 457: }
458:
1.25 lukem 459: static void
460: bread(daddr_t blk, char *buffer, int cnt, const char *file)
1.1 cgd 461: {
1.25 lukem 462: off_t offset;
463: int i;
1.1 cgd 464:
1.25 lukem 465: offset = (off_t)blk * dev_bsize;
466: if (lseek(fi, offset, SEEK_SET) == -1)
467: err(4, "%s: seeking to %lld", file, (long long)offset);
468: if ((i = read(fi, buffer, cnt)) != cnt)
469: errx(5, "%s: short read", file);
1.26 lukem 470: }
471:
472: static int
473: openpartition(const char *name, int flags, char *device, size_t devicelen)
474: {
475: char rawspec[MAXPATHLEN], *p;
476: struct fstab *fs;
477: int fd, oerrno;
478:
479: fs = getfsfile(name);
480: if (fs) {
481: if ((p = strrchr(fs->fs_spec, '/')) != NULL) {
482: snprintf(rawspec, sizeof(rawspec), "%.*s/r%s",
483: (int)(p - fs->fs_spec), fs->fs_spec, p + 1);
484: name = rawspec;
485: } else
486: name = fs->fs_spec;
487: }
488: fd = opendisk(name, flags, device, devicelen, 0);
489: if (fd == -1 && errno == ENOENT) {
490: oerrno = errno;
491: strlcpy(device, name, devicelen);
492: errno = oerrno;
493: }
494: return (fd);
1.1 cgd 495: }
CVSweb <webmaster@jp.NetBSD.org>