tunefs.c revision 75498
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3538040Scharnierstatic const char copyright[] = 361558Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 371558Srgrimes The Regents of the University of California. All rights reserved.\n"; 381558Srgrimes#endif /* not lint */ 391558Srgrimes 401558Srgrimes#ifndef lint 4138040Scharnier#if 0 421558Srgrimesstatic char sccsid[] = "@(#)tunefs.c 8.2 (Berkeley) 4/19/94"; 4338040Scharnier#endif 4438040Scharnierstatic const char rcsid[] = 4550476Speter "$FreeBSD: head/sbin/tunefs/tunefs.c 75498 2001-04-13 23:54:49Z mckusick $"; 461558Srgrimes#endif /* not lint */ 471558Srgrimes 481558Srgrimes/* 491558Srgrimes * tunefs: change layout parameters to an existing file system. 501558Srgrimes */ 511558Srgrimes#include <sys/param.h> 5242873Sluoqi#include <sys/mount.h> 531558Srgrimes#include <sys/stat.h> 541558Srgrimes 551558Srgrimes#include <ufs/ffs/fs.h> 5642873Sluoqi#include <ufs/ufs/ufsmount.h> 571558Srgrimes 581558Srgrimes#include <err.h> 591558Srgrimes#include <fcntl.h> 601558Srgrimes#include <fstab.h> 6138040Scharnier#include <paths.h> 621558Srgrimes#include <stdio.h> 631558Srgrimes#include <stdlib.h> 6458047Ssheldonh#include <string.h> 651558Srgrimes#include <unistd.h> 661558Srgrimes 671558Srgrimes/* the optimization warning string template */ 681558Srgrimes#define OPTWARN "should optimize for %s with minfree %s %d%%" 691558Srgrimes 701558Srgrimesunion { 711558Srgrimes struct fs sb; 721558Srgrimes char pad[MAXBSIZE]; 731558Srgrimes} sbun; 741558Srgrimes#define sblock sbun.sb 751558Srgrimes 761558Srgrimesint fi; 771558Srgrimeslong dev_bsize = 1; 781558Srgrimes 7958047Ssheldonhvoid bwrite __P((daddr_t, char *, int)); 8058047Ssheldonhint bread __P((daddr_t, char *, int)); 8158047Ssheldonhvoid getsb __P((struct fs *, char *)); 8258047Ssheldonhvoid putsb __P((struct fs *, char *, int)); 831558Srgrimesvoid usage __P((void)); 849315Sjoergvoid printfs __P((void)); 851558Srgrimes 861558Srgrimesint 871558Srgrimesmain(argc, argv) 881558Srgrimes int argc; 891558Srgrimes char *argv[]; 901558Srgrimes{ 9169829Scharnier char *special, *name; 921558Srgrimes struct stat st; 9342873Sluoqi int Aflag = 0, active = 0; 9475377Smckusick int aflag = 0, dflag = 0, eflag = 0, fflag = 0, mflag = 0; 9575377Smckusick int nflag = 0, oflag = 0, pflag = 0, sflag = 0; 9675377Smckusick int avalue = 0, dvalue = 0, evalue = 0, fvalue = 0; 9775377Smckusick int mvalue = 0, ovalue = 0, svalue = 0; 9869829Scharnier char *nvalue = NULL; 991558Srgrimes struct fstab *fs; 1001558Srgrimes char *chg[2], device[MAXPATHLEN]; 10142873Sluoqi struct ufs_args args; 10242873Sluoqi struct statfs stfs; 10369314Scharnier int found_arg, ch; 1041558Srgrimes 10569314Scharnier if (argc < 3) 10669314Scharnier usage(); 10769314Scharnier found_arg = 0; /* at least one arg is required */ 10875377Smckusick while ((ch = getopt(argc, argv, "Aa:d:e:f:m:n:o:ps:")) != -1) 10969314Scharnier switch (ch) { 11069314Scharnier case 'A': 11169314Scharnier found_arg = 1; 11269314Scharnier Aflag++; 11369314Scharnier break; 11469314Scharnier case 'a': 11569314Scharnier found_arg = 1; 11669314Scharnier name = "maximum contiguous block count"; 11769829Scharnier avalue = atoi(optarg); 11869829Scharnier if (avalue < 1) 11969314Scharnier errx(10, "%s must be >= 1 (was %s)", name, optarg); 12069829Scharnier aflag = 1; 12169314Scharnier break; 12269314Scharnier case 'd': 12369314Scharnier found_arg = 1; 12469314Scharnier name = "rotational delay between contiguous blocks"; 12569829Scharnier dvalue = atoi(optarg); 12669829Scharnier dflag = 1; 12769314Scharnier break; 12869314Scharnier case 'e': 12969314Scharnier found_arg = 1; 13069314Scharnier name = "maximum blocks per file in a cylinder group"; 13169829Scharnier evalue = atoi(optarg); 13269829Scharnier if (evalue < 1) 13369314Scharnier errx(10, "%s must be >= 1 (was %s)", name, optarg); 13469829Scharnier eflag = 1; 13569314Scharnier break; 13675377Smckusick case 'f': 13775377Smckusick found_arg = 1; 13875377Smckusick name = "average file size"; 13975377Smckusick fvalue = atoi(optarg); 14075377Smckusick if (fvalue < 1) 14175377Smckusick errx(10, "%s must be >= 1 (was %s)", name, optarg); 14275377Smckusick fflag = 1; 14375377Smckusick break; 14469314Scharnier case 'm': 14569314Scharnier found_arg = 1; 14669314Scharnier name = "minimum percentage of free space"; 14769829Scharnier mvalue = atoi(optarg); 14869829Scharnier if (mvalue < 0 || mvalue > 99) 14969314Scharnier errx(10, "bad %s (%s)", name, optarg); 15069829Scharnier mflag = 1; 15169314Scharnier break; 15269314Scharnier case 'n': 15369314Scharnier found_arg = 1; 15469314Scharnier name = "soft updates"; 15569829Scharnier nvalue = optarg; 15669829Scharnier if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) { 15769314Scharnier errx(10, "bad %s (options are %s)", 15869314Scharnier name, "`enable' or `disable'"); 15969314Scharnier } 16069829Scharnier nflag = 1; 16169314Scharnier break; 16269314Scharnier case 'o': 16369314Scharnier found_arg = 1; 16469314Scharnier name = "optimization preference"; 16569314Scharnier chg[FS_OPTSPACE] = "space"; 16669314Scharnier chg[FS_OPTTIME] = "time"; 16769314Scharnier if (strcmp(optarg, chg[FS_OPTSPACE]) == 0) 16869829Scharnier ovalue = FS_OPTSPACE; 16969314Scharnier else if (strcmp(optarg, chg[FS_OPTTIME]) == 0) 17069829Scharnier ovalue = FS_OPTTIME; 17169314Scharnier else 17269314Scharnier errx(10, "bad %s (options are `space' or `time')", 1731558Srgrimes name); 17469829Scharnier oflag = 1; 17569314Scharnier break; 17669314Scharnier case 'p': 17771790Sben found_arg = 1; 17869829Scharnier pflag = 1; 17969829Scharnier break; 18075377Smckusick case 's': 18175377Smckusick found_arg = 1; 18275377Smckusick name = "expected number of files per directory"; 18375377Smckusick svalue = atoi(optarg); 18475377Smckusick if (svalue < 1) 18575377Smckusick errx(10, "%s must be >= 1 (was %s)", name, optarg); 18675377Smckusick sflag = 1; 18775377Smckusick break; 18869314Scharnier default: 18969314Scharnier usage(); 19069314Scharnier } 19169314Scharnier argc -= optind; 19269314Scharnier argv += optind; 1931558Srgrimes 19469314Scharnier if (found_arg == 0 || argc != 1) 19569314Scharnier usage(); 19669314Scharnier 19769829Scharnier special = argv[0]; 19869829Scharnier fs = getfsfile(special); 19969829Scharnier if (fs) { 20069829Scharnier if (statfs(special, &stfs) == 0 && 20169829Scharnier strcmp(special, stfs.f_mntonname) == 0) { 20269829Scharnier active = 1; 20369829Scharnier } 20469829Scharnier special = fs->fs_spec; 20569829Scharnier } 20669829Scharnieragain: 20769829Scharnier if (stat(special, &st) < 0) { 20869829Scharnier if (*special != '/') { 20969829Scharnier if (*special == 'r') 21069829Scharnier special++; 21169829Scharnier (void)sprintf(device, "%s/%s", _PATH_DEV, special); 21269829Scharnier special = device; 21369829Scharnier goto again; 21469829Scharnier } 21569829Scharnier err(1, "%s", special); 21669829Scharnier } 21769829Scharnier if ((st.st_mode & S_IFMT) != S_IFBLK && 21869829Scharnier (st.st_mode & S_IFMT) != S_IFCHR) 21969829Scharnier errx(10, "%s: not a block or character device", special); 22069829Scharnier getsb(&sblock, special); 22169829Scharnier 22269829Scharnier if (pflag) { 22369829Scharnier printfs(); 22469829Scharnier exit(0); 22569829Scharnier } 22669829Scharnier if (aflag) { 22769829Scharnier name = "maximum contiguous block count"; 22869829Scharnier if (sblock.fs_maxcontig == avalue) { 22969829Scharnier warnx("%s remains unchanged as %d", name, avalue); 23069829Scharnier } 23169829Scharnier else { 23269829Scharnier warnx("%s changes from %d to %d", 23369829Scharnier name, sblock.fs_maxcontig, avalue); 23469829Scharnier sblock.fs_maxcontig = avalue; 23569829Scharnier } 23669829Scharnier } 23769829Scharnier if (dflag) { 23869829Scharnier name = "rotational delay between contiguous blocks"; 23969829Scharnier if (sblock.fs_rotdelay == dvalue) { 24069829Scharnier warnx("%s remains unchanged as %dms", name, dvalue); 24169829Scharnier } 24269829Scharnier else { 24369829Scharnier warnx("%s changes from %dms to %dms", 24469829Scharnier name, sblock.fs_rotdelay, dvalue); 24569829Scharnier sblock.fs_rotdelay = dvalue; 24669829Scharnier } 24769829Scharnier } 24869829Scharnier if (eflag) { 24969829Scharnier name = "maximum blocks per file in a cylinder group"; 25069829Scharnier if (sblock.fs_maxbpg == evalue) { 25169829Scharnier warnx("%s remains unchanged as %d", name, evalue); 25269829Scharnier } 25369829Scharnier else { 25469829Scharnier warnx("%s changes from %d to %d", 25569829Scharnier name, sblock.fs_maxbpg, evalue); 25669829Scharnier sblock.fs_maxbpg = evalue; 25769829Scharnier } 25869829Scharnier } 25975377Smckusick if (fflag) { 26075377Smckusick name = "average file size"; 26175377Smckusick if (sblock.fs_avgfilesize == fvalue) { 26275377Smckusick warnx("%s remains unchanged as %d", name, fvalue); 26375377Smckusick } 26475377Smckusick else { 26575377Smckusick warnx("%s changes from %d to %d", 26675377Smckusick name, sblock.fs_avgfilesize, fvalue); 26775377Smckusick sblock.fs_avgfilesize = fvalue; 26875377Smckusick } 26975377Smckusick } 27069829Scharnier if (mflag) { 27169829Scharnier name = "minimum percentage of free space"; 27269829Scharnier if (sblock.fs_minfree == mvalue) { 27369829Scharnier warnx("%s remains unchanged as %d%%", name, mvalue); 27469829Scharnier } 27569829Scharnier else { 27669829Scharnier warnx("%s changes from %d%% to %d%%", 27769829Scharnier name, sblock.fs_minfree, mvalue); 27869829Scharnier sblock.fs_minfree = mvalue; 27969829Scharnier if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 28069829Scharnier warnx(OPTWARN, "time", ">=", MINFREE); 28169829Scharnier if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 28269829Scharnier warnx(OPTWARN, "space", "<", MINFREE); 28369829Scharnier } 28469829Scharnier } 28569829Scharnier if (nflag) { 28669829Scharnier name = "soft updates"; 28769829Scharnier if (strcmp(nvalue, "enable") == 0) { 28875498Smckusick if (sblock.fs_flags & FS_DOSOFTDEP) { 28969829Scharnier warnx("%s remains unchanged as enabled", name); 29075498Smckusick } else if (sblock.fs_clean == 0) { 29175498Smckusick warnx("%s cannot be enabled until fsck is run", 29275498Smckusick name); 29369829Scharnier } else { 29469829Scharnier sblock.fs_flags |= FS_DOSOFTDEP; 29569829Scharnier warnx("%s set", name); 29669829Scharnier } 29769829Scharnier } else if (strcmp(nvalue, "disable") == 0) { 29869829Scharnier if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) { 29969829Scharnier warnx("%s remains unchanged as disabled", name); 30069829Scharnier } else { 30169829Scharnier sblock.fs_flags &= ~FS_DOSOFTDEP; 30269829Scharnier warnx("%s cleared", name); 30369829Scharnier } 30469829Scharnier } 30569829Scharnier } 30669829Scharnier if (oflag) { 30769829Scharnier name = "optimization preference"; 30869829Scharnier chg[FS_OPTSPACE] = "space"; 30969829Scharnier chg[FS_OPTTIME] = "time"; 31069829Scharnier if (sblock.fs_optim == ovalue) { 31169829Scharnier warnx("%s remains unchanged as %s", name, chg[ovalue]); 31269829Scharnier } 31369829Scharnier else { 31469829Scharnier warnx("%s changes from %s to %s", 31569829Scharnier name, chg[sblock.fs_optim], chg[ovalue]); 31669829Scharnier sblock.fs_optim = ovalue; 31769829Scharnier if (sblock.fs_minfree >= MINFREE && 31869829Scharnier ovalue == FS_OPTSPACE) 31969829Scharnier warnx(OPTWARN, "time", ">=", MINFREE); 32069829Scharnier if (sblock.fs_minfree < MINFREE && 32169829Scharnier ovalue == FS_OPTTIME) 32269829Scharnier warnx(OPTWARN, "space", "<", MINFREE); 32369829Scharnier } 32469829Scharnier } 32575377Smckusick if (sflag) { 32675377Smckusick name = "expected number of files per directory"; 32775377Smckusick if (sblock.fs_avgfpdir == svalue) { 32875377Smckusick warnx("%s remains unchanged as %d", name, svalue); 32975377Smckusick } 33075377Smckusick else { 33175377Smckusick warnx("%s changes from %d to %d", 33275377Smckusick name, sblock.fs_avgfpdir, svalue); 33375377Smckusick sblock.fs_avgfpdir = svalue; 33475377Smckusick } 33575377Smckusick } 33669829Scharnier 33758047Ssheldonh putsb(&sblock, special, Aflag); 33842873Sluoqi if (active) { 33942873Sluoqi bzero(&args, sizeof(args)); 34042873Sluoqi if (mount("ufs", fs->fs_file, 34142873Sluoqi stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 34242873Sluoqi err(9, "%s: reload", special); 34342873Sluoqi warnx("file system reloaded"); 34442873Sluoqi } 3451558Srgrimes exit(0); 3461558Srgrimes} 3471558Srgrimes 3481558Srgrimesvoid 3491558Srgrimesusage() 3501558Srgrimes{ 35138040Scharnier fprintf(stderr, "%s\n%s\n%s\n", 35275377Smckusick"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]", 35375377Smckusick" [-m minfree] [-p] [-n enable | disable] [-o space | time]", 35475377Smckusick" [-s filesperdir] special | filesystem"); 3551558Srgrimes exit(2); 3561558Srgrimes} 3571558Srgrimes 3581558Srgrimesvoid 3591558Srgrimesgetsb(fs, file) 3601558Srgrimes register struct fs *fs; 3611558Srgrimes char *file; 3621558Srgrimes{ 3631558Srgrimes 36458047Ssheldonh fi = open(file, O_RDONLY); 3651558Srgrimes if (fi < 0) 3661558Srgrimes err(3, "cannot open %s", file); 3671558Srgrimes if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 3681558Srgrimes err(4, "%s: bad super block", file); 3691558Srgrimes if (fs->fs_magic != FS_MAGIC) 3701558Srgrimes err(5, "%s: bad magic number", file); 3711558Srgrimes dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 3721558Srgrimes} 3731558Srgrimes 3741558Srgrimesvoid 37558047Ssheldonhputsb(fs, file, all) 37658047Ssheldonh register struct fs *fs; 37758047Ssheldonh char *file; 37858047Ssheldonh int all; 37958047Ssheldonh{ 38058047Ssheldonh int i; 38158047Ssheldonh 38258047Ssheldonh /* 38358047Ssheldonh * Re-open the device read-write. Use the read-only file 38458047Ssheldonh * descriptor as an interlock to prevent the device from 38558047Ssheldonh * being mounted while we are switching mode. 38658047Ssheldonh */ 38758047Ssheldonh i = fi; 38858047Ssheldonh fi = open(file, O_RDWR); 38958047Ssheldonh close(i); 39058047Ssheldonh if (fi < 0) 39158047Ssheldonh err(3, "cannot open %s", file); 39258047Ssheldonh bwrite((daddr_t)SBOFF / dev_bsize, (char *)fs, SBSIZE); 39358047Ssheldonh if (all) 39458047Ssheldonh for (i = 0; i < fs->fs_ncg; i++) 39558047Ssheldonh bwrite(fsbtodb(fs, cgsblock(fs, i)), 39658047Ssheldonh (char *)fs, SBSIZE); 39758047Ssheldonh close(fi); 39858047Ssheldonh} 39958047Ssheldonh 40058047Ssheldonhvoid 4019315Sjoergprintfs() 4029315Sjoerg{ 40334266Sjulian warnx("soft updates: (-n) %s", 40434266Sjulian (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 4059315Sjoerg warnx("maximum contiguous block count: (-a) %d", 4069315Sjoerg sblock.fs_maxcontig); 4079315Sjoerg warnx("rotational delay between contiguous blocks: (-d) %d ms", 4089315Sjoerg sblock.fs_rotdelay); 4099315Sjoerg warnx("maximum blocks per file in a cylinder group: (-e) %d", 4109315Sjoerg sblock.fs_maxbpg); 41175377Smckusick warnx("average file size: (-f) %d", 41275377Smckusick sblock.fs_avgfilesize); 41375377Smckusick warnx("average number of files in a directory: (-s) %d", 41475377Smckusick sblock.fs_avgfpdir); 4159315Sjoerg warnx("minimum percentage of free space: (-m) %d%%", 4169315Sjoerg sblock.fs_minfree); 4179315Sjoerg warnx("optimization preference: (-o) %s", 4189315Sjoerg sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 4199315Sjoerg if (sblock.fs_minfree >= MINFREE && 4209315Sjoerg sblock.fs_optim == FS_OPTSPACE) 4219315Sjoerg warnx(OPTWARN, "time", ">=", MINFREE); 4229315Sjoerg if (sblock.fs_minfree < MINFREE && 4239315Sjoerg sblock.fs_optim == FS_OPTTIME) 4249315Sjoerg warnx(OPTWARN, "space", "<", MINFREE); 4259315Sjoerg} 4269315Sjoerg 4279315Sjoergvoid 4281558Srgrimesbwrite(blk, buf, size) 4291558Srgrimes daddr_t blk; 4301558Srgrimes char *buf; 4311558Srgrimes int size; 4321558Srgrimes{ 4331558Srgrimes 4341558Srgrimes if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 4351558Srgrimes err(6, "FS SEEK"); 4361558Srgrimes if (write(fi, buf, size) != size) 4371558Srgrimes err(7, "FS WRITE"); 4381558Srgrimes} 4391558Srgrimes 4401558Srgrimesint 4411558Srgrimesbread(bno, buf, cnt) 4421558Srgrimes daddr_t bno; 4431558Srgrimes char *buf; 4441558Srgrimes int cnt; 4451558Srgrimes{ 4461558Srgrimes int i; 4471558Srgrimes 4481558Srgrimes if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 4491558Srgrimes return(1); 4501558Srgrimes if ((i = read(fi, buf, cnt)) != cnt) { 4511558Srgrimes for(i=0; i<sblock.fs_bsize; i++) 4521558Srgrimes buf[i] = 0; 4531558Srgrimes return (1); 4541558Srgrimes } 4551558Srgrimes return (0); 4561558Srgrimes} 457