tunefs.c revision 79750
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 79750 2001-07-15 05:47:47Z dd $"; 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 7979750Sddvoid bwrite __P((daddr_t, const char *, int)); 8058047Ssheldonhint bread __P((daddr_t, char *, int)); 8179750Sddvoid getsb __P((struct fs *, const char *)); 8279750Sddvoid putsb __P((struct fs *, const char *, int)); 831558Srgrimesvoid usage __P((void)); 849315Sjoergvoid printfs __P((void)); 851558Srgrimes 861558Srgrimesint 871558Srgrimesmain(argc, argv) 881558Srgrimes int argc; 891558Srgrimes char *argv[]; 901558Srgrimes{ 9179750Sdd char *special; 9279750Sdd const char *name; 931558Srgrimes struct stat st; 9442873Sluoqi int Aflag = 0, active = 0; 9575377Smckusick int aflag = 0, dflag = 0, eflag = 0, fflag = 0, mflag = 0; 9675377Smckusick int nflag = 0, oflag = 0, pflag = 0, sflag = 0; 9775377Smckusick int avalue = 0, dvalue = 0, evalue = 0, fvalue = 0; 9875377Smckusick int mvalue = 0, ovalue = 0, svalue = 0; 9969829Scharnier char *nvalue = NULL; 1001558Srgrimes struct fstab *fs; 10179750Sdd const char *chg[2]; 10279750Sdd char device[MAXPATHLEN]; 10342873Sluoqi struct ufs_args args; 10442873Sluoqi struct statfs stfs; 10569314Scharnier int found_arg, ch; 1061558Srgrimes 10769314Scharnier if (argc < 3) 10869314Scharnier usage(); 10969314Scharnier found_arg = 0; /* at least one arg is required */ 11075377Smckusick while ((ch = getopt(argc, argv, "Aa:d:e:f:m:n:o:ps:")) != -1) 11169314Scharnier switch (ch) { 11269314Scharnier case 'A': 11369314Scharnier found_arg = 1; 11469314Scharnier Aflag++; 11569314Scharnier break; 11669314Scharnier case 'a': 11769314Scharnier found_arg = 1; 11869314Scharnier name = "maximum contiguous block count"; 11969829Scharnier avalue = atoi(optarg); 12069829Scharnier if (avalue < 1) 12169314Scharnier errx(10, "%s must be >= 1 (was %s)", name, optarg); 12269829Scharnier aflag = 1; 12369314Scharnier break; 12469314Scharnier case 'd': 12569314Scharnier found_arg = 1; 12669314Scharnier name = "rotational delay between contiguous blocks"; 12769829Scharnier dvalue = atoi(optarg); 12869829Scharnier dflag = 1; 12969314Scharnier break; 13069314Scharnier case 'e': 13169314Scharnier found_arg = 1; 13269314Scharnier name = "maximum blocks per file in a cylinder group"; 13369829Scharnier evalue = atoi(optarg); 13469829Scharnier if (evalue < 1) 13569314Scharnier errx(10, "%s must be >= 1 (was %s)", name, optarg); 13669829Scharnier eflag = 1; 13769314Scharnier break; 13875377Smckusick case 'f': 13975377Smckusick found_arg = 1; 14075377Smckusick name = "average file size"; 14175377Smckusick fvalue = atoi(optarg); 14275377Smckusick if (fvalue < 1) 14375377Smckusick errx(10, "%s must be >= 1 (was %s)", name, optarg); 14475377Smckusick fflag = 1; 14575377Smckusick break; 14669314Scharnier case 'm': 14769314Scharnier found_arg = 1; 14869314Scharnier name = "minimum percentage of free space"; 14969829Scharnier mvalue = atoi(optarg); 15069829Scharnier if (mvalue < 0 || mvalue > 99) 15169314Scharnier errx(10, "bad %s (%s)", name, optarg); 15269829Scharnier mflag = 1; 15369314Scharnier break; 15469314Scharnier case 'n': 15569314Scharnier found_arg = 1; 15669314Scharnier name = "soft updates"; 15769829Scharnier nvalue = optarg; 15869829Scharnier if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) { 15969314Scharnier errx(10, "bad %s (options are %s)", 16069314Scharnier name, "`enable' or `disable'"); 16169314Scharnier } 16269829Scharnier nflag = 1; 16369314Scharnier break; 16469314Scharnier case 'o': 16569314Scharnier found_arg = 1; 16669314Scharnier name = "optimization preference"; 16769314Scharnier chg[FS_OPTSPACE] = "space"; 16869314Scharnier chg[FS_OPTTIME] = "time"; 16969314Scharnier if (strcmp(optarg, chg[FS_OPTSPACE]) == 0) 17069829Scharnier ovalue = FS_OPTSPACE; 17169314Scharnier else if (strcmp(optarg, chg[FS_OPTTIME]) == 0) 17269829Scharnier ovalue = FS_OPTTIME; 17369314Scharnier else 17469314Scharnier errx(10, "bad %s (options are `space' or `time')", 1751558Srgrimes name); 17669829Scharnier oflag = 1; 17769314Scharnier break; 17869314Scharnier case 'p': 17971790Sben found_arg = 1; 18069829Scharnier pflag = 1; 18169829Scharnier break; 18275377Smckusick case 's': 18375377Smckusick found_arg = 1; 18475377Smckusick name = "expected number of files per directory"; 18575377Smckusick svalue = atoi(optarg); 18675377Smckusick if (svalue < 1) 18775377Smckusick errx(10, "%s must be >= 1 (was %s)", name, optarg); 18875377Smckusick sflag = 1; 18975377Smckusick break; 19069314Scharnier default: 19169314Scharnier usage(); 19269314Scharnier } 19369314Scharnier argc -= optind; 19469314Scharnier argv += optind; 1951558Srgrimes 19669314Scharnier if (found_arg == 0 || argc != 1) 19769314Scharnier usage(); 19869314Scharnier 19969829Scharnier special = argv[0]; 20069829Scharnier fs = getfsfile(special); 20169829Scharnier if (fs) { 20269829Scharnier if (statfs(special, &stfs) == 0 && 20369829Scharnier strcmp(special, stfs.f_mntonname) == 0) { 20469829Scharnier active = 1; 20569829Scharnier } 20669829Scharnier special = fs->fs_spec; 20769829Scharnier } 20869829Scharnieragain: 20969829Scharnier if (stat(special, &st) < 0) { 21069829Scharnier if (*special != '/') { 21169829Scharnier if (*special == 'r') 21269829Scharnier special++; 21369829Scharnier (void)sprintf(device, "%s/%s", _PATH_DEV, special); 21469829Scharnier special = device; 21569829Scharnier goto again; 21669829Scharnier } 21769829Scharnier err(1, "%s", special); 21869829Scharnier } 21969829Scharnier if ((st.st_mode & S_IFMT) != S_IFBLK && 22069829Scharnier (st.st_mode & S_IFMT) != S_IFCHR) 22169829Scharnier errx(10, "%s: not a block or character device", special); 22269829Scharnier getsb(&sblock, special); 22369829Scharnier 22469829Scharnier if (pflag) { 22569829Scharnier printfs(); 22669829Scharnier exit(0); 22769829Scharnier } 22869829Scharnier if (aflag) { 22969829Scharnier name = "maximum contiguous block count"; 23069829Scharnier if (sblock.fs_maxcontig == avalue) { 23169829Scharnier warnx("%s remains unchanged as %d", name, avalue); 23269829Scharnier } 23369829Scharnier else { 23469829Scharnier warnx("%s changes from %d to %d", 23569829Scharnier name, sblock.fs_maxcontig, avalue); 23669829Scharnier sblock.fs_maxcontig = avalue; 23769829Scharnier } 23869829Scharnier } 23969829Scharnier if (dflag) { 24069829Scharnier name = "rotational delay between contiguous blocks"; 24169829Scharnier if (sblock.fs_rotdelay == dvalue) { 24269829Scharnier warnx("%s remains unchanged as %dms", name, dvalue); 24369829Scharnier } 24469829Scharnier else { 24569829Scharnier warnx("%s changes from %dms to %dms", 24669829Scharnier name, sblock.fs_rotdelay, dvalue); 24769829Scharnier sblock.fs_rotdelay = dvalue; 24869829Scharnier } 24969829Scharnier } 25069829Scharnier if (eflag) { 25169829Scharnier name = "maximum blocks per file in a cylinder group"; 25269829Scharnier if (sblock.fs_maxbpg == evalue) { 25369829Scharnier warnx("%s remains unchanged as %d", name, evalue); 25469829Scharnier } 25569829Scharnier else { 25669829Scharnier warnx("%s changes from %d to %d", 25769829Scharnier name, sblock.fs_maxbpg, evalue); 25869829Scharnier sblock.fs_maxbpg = evalue; 25969829Scharnier } 26069829Scharnier } 26175377Smckusick if (fflag) { 26275377Smckusick name = "average file size"; 26375377Smckusick if (sblock.fs_avgfilesize == fvalue) { 26475377Smckusick warnx("%s remains unchanged as %d", name, fvalue); 26575377Smckusick } 26675377Smckusick else { 26775377Smckusick warnx("%s changes from %d to %d", 26875377Smckusick name, sblock.fs_avgfilesize, fvalue); 26975377Smckusick sblock.fs_avgfilesize = fvalue; 27075377Smckusick } 27175377Smckusick } 27269829Scharnier if (mflag) { 27369829Scharnier name = "minimum percentage of free space"; 27469829Scharnier if (sblock.fs_minfree == mvalue) { 27569829Scharnier warnx("%s remains unchanged as %d%%", name, mvalue); 27669829Scharnier } 27769829Scharnier else { 27869829Scharnier warnx("%s changes from %d%% to %d%%", 27969829Scharnier name, sblock.fs_minfree, mvalue); 28069829Scharnier sblock.fs_minfree = mvalue; 28169829Scharnier if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 28269829Scharnier warnx(OPTWARN, "time", ">=", MINFREE); 28369829Scharnier if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 28469829Scharnier warnx(OPTWARN, "space", "<", MINFREE); 28569829Scharnier } 28669829Scharnier } 28769829Scharnier if (nflag) { 28869829Scharnier name = "soft updates"; 28969829Scharnier if (strcmp(nvalue, "enable") == 0) { 29075498Smckusick if (sblock.fs_flags & FS_DOSOFTDEP) { 29169829Scharnier warnx("%s remains unchanged as enabled", name); 29275498Smckusick } else if (sblock.fs_clean == 0) { 29375498Smckusick warnx("%s cannot be enabled until fsck is run", 29475498Smckusick name); 29569829Scharnier } else { 29669829Scharnier sblock.fs_flags |= FS_DOSOFTDEP; 29769829Scharnier warnx("%s set", name); 29869829Scharnier } 29969829Scharnier } else if (strcmp(nvalue, "disable") == 0) { 30069829Scharnier if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) { 30169829Scharnier warnx("%s remains unchanged as disabled", name); 30269829Scharnier } else { 30369829Scharnier sblock.fs_flags &= ~FS_DOSOFTDEP; 30469829Scharnier warnx("%s cleared", name); 30569829Scharnier } 30669829Scharnier } 30769829Scharnier } 30869829Scharnier if (oflag) { 30969829Scharnier name = "optimization preference"; 31069829Scharnier chg[FS_OPTSPACE] = "space"; 31169829Scharnier chg[FS_OPTTIME] = "time"; 31269829Scharnier if (sblock.fs_optim == ovalue) { 31369829Scharnier warnx("%s remains unchanged as %s", name, chg[ovalue]); 31469829Scharnier } 31569829Scharnier else { 31669829Scharnier warnx("%s changes from %s to %s", 31769829Scharnier name, chg[sblock.fs_optim], chg[ovalue]); 31869829Scharnier sblock.fs_optim = ovalue; 31969829Scharnier if (sblock.fs_minfree >= MINFREE && 32069829Scharnier ovalue == FS_OPTSPACE) 32169829Scharnier warnx(OPTWARN, "time", ">=", MINFREE); 32269829Scharnier if (sblock.fs_minfree < MINFREE && 32369829Scharnier ovalue == FS_OPTTIME) 32469829Scharnier warnx(OPTWARN, "space", "<", MINFREE); 32569829Scharnier } 32669829Scharnier } 32775377Smckusick if (sflag) { 32875377Smckusick name = "expected number of files per directory"; 32975377Smckusick if (sblock.fs_avgfpdir == svalue) { 33075377Smckusick warnx("%s remains unchanged as %d", name, svalue); 33175377Smckusick } 33275377Smckusick else { 33375377Smckusick warnx("%s changes from %d to %d", 33475377Smckusick name, sblock.fs_avgfpdir, svalue); 33575377Smckusick sblock.fs_avgfpdir = svalue; 33675377Smckusick } 33775377Smckusick } 33869829Scharnier 33958047Ssheldonh putsb(&sblock, special, Aflag); 34042873Sluoqi if (active) { 34142873Sluoqi bzero(&args, sizeof(args)); 34242873Sluoqi if (mount("ufs", fs->fs_file, 34342873Sluoqi stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 34442873Sluoqi err(9, "%s: reload", special); 34542873Sluoqi warnx("file system reloaded"); 34642873Sluoqi } 3471558Srgrimes exit(0); 3481558Srgrimes} 3491558Srgrimes 3501558Srgrimesvoid 3511558Srgrimesusage() 3521558Srgrimes{ 35338040Scharnier fprintf(stderr, "%s\n%s\n%s\n", 35475377Smckusick"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]", 35575377Smckusick" [-m minfree] [-p] [-n enable | disable] [-o space | time]", 35675377Smckusick" [-s filesperdir] special | filesystem"); 3571558Srgrimes exit(2); 3581558Srgrimes} 3591558Srgrimes 3601558Srgrimesvoid 3611558Srgrimesgetsb(fs, file) 36279750Sdd struct fs *fs; 36379750Sdd const char *file; 3641558Srgrimes{ 3651558Srgrimes 36658047Ssheldonh fi = open(file, O_RDONLY); 3671558Srgrimes if (fi < 0) 3681558Srgrimes err(3, "cannot open %s", file); 3691558Srgrimes if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 3701558Srgrimes err(4, "%s: bad super block", file); 3711558Srgrimes if (fs->fs_magic != FS_MAGIC) 3721558Srgrimes err(5, "%s: bad magic number", file); 3731558Srgrimes dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 3741558Srgrimes} 3751558Srgrimes 3761558Srgrimesvoid 37758047Ssheldonhputsb(fs, file, all) 37879750Sdd struct fs *fs; 37979750Sdd const char *file; 38058047Ssheldonh int all; 38158047Ssheldonh{ 38258047Ssheldonh int i; 38358047Ssheldonh 38458047Ssheldonh /* 38558047Ssheldonh * Re-open the device read-write. Use the read-only file 38658047Ssheldonh * descriptor as an interlock to prevent the device from 38758047Ssheldonh * being mounted while we are switching mode. 38858047Ssheldonh */ 38958047Ssheldonh i = fi; 39058047Ssheldonh fi = open(file, O_RDWR); 39158047Ssheldonh close(i); 39258047Ssheldonh if (fi < 0) 39358047Ssheldonh err(3, "cannot open %s", file); 39479750Sdd bwrite((daddr_t)SBOFF / dev_bsize, (const char *)fs, SBSIZE); 39558047Ssheldonh if (all) 39658047Ssheldonh for (i = 0; i < fs->fs_ncg; i++) 39758047Ssheldonh bwrite(fsbtodb(fs, cgsblock(fs, i)), 39879750Sdd (const char *)fs, SBSIZE); 39958047Ssheldonh close(fi); 40058047Ssheldonh} 40158047Ssheldonh 40258047Ssheldonhvoid 4039315Sjoergprintfs() 4049315Sjoerg{ 40534266Sjulian warnx("soft updates: (-n) %s", 40634266Sjulian (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 4079315Sjoerg warnx("maximum contiguous block count: (-a) %d", 4089315Sjoerg sblock.fs_maxcontig); 4099315Sjoerg warnx("rotational delay between contiguous blocks: (-d) %d ms", 4109315Sjoerg sblock.fs_rotdelay); 4119315Sjoerg warnx("maximum blocks per file in a cylinder group: (-e) %d", 4129315Sjoerg sblock.fs_maxbpg); 41375377Smckusick warnx("average file size: (-f) %d", 41475377Smckusick sblock.fs_avgfilesize); 41575377Smckusick warnx("average number of files in a directory: (-s) %d", 41675377Smckusick sblock.fs_avgfpdir); 4179315Sjoerg warnx("minimum percentage of free space: (-m) %d%%", 4189315Sjoerg sblock.fs_minfree); 4199315Sjoerg warnx("optimization preference: (-o) %s", 4209315Sjoerg sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 4219315Sjoerg if (sblock.fs_minfree >= MINFREE && 4229315Sjoerg sblock.fs_optim == FS_OPTSPACE) 4239315Sjoerg warnx(OPTWARN, "time", ">=", MINFREE); 4249315Sjoerg if (sblock.fs_minfree < MINFREE && 4259315Sjoerg sblock.fs_optim == FS_OPTTIME) 4269315Sjoerg warnx(OPTWARN, "space", "<", MINFREE); 4279315Sjoerg} 4289315Sjoerg 4299315Sjoergvoid 4301558Srgrimesbwrite(blk, buf, size) 4311558Srgrimes daddr_t blk; 43279750Sdd const char *buf; 4331558Srgrimes int size; 4341558Srgrimes{ 4351558Srgrimes 4361558Srgrimes if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 4371558Srgrimes err(6, "FS SEEK"); 4381558Srgrimes if (write(fi, buf, size) != size) 4391558Srgrimes err(7, "FS WRITE"); 4401558Srgrimes} 4411558Srgrimes 4421558Srgrimesint 4431558Srgrimesbread(bno, buf, cnt) 4441558Srgrimes daddr_t bno; 4451558Srgrimes char *buf; 4461558Srgrimes int cnt; 4471558Srgrimes{ 4481558Srgrimes int i; 4491558Srgrimes 4501558Srgrimes if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 4511558Srgrimes return(1); 4521558Srgrimes if ((i = read(fi, buf, cnt)) != cnt) { 4531558Srgrimes for(i=0; i<sblock.fs_bsize; i++) 4541558Srgrimes buf[i] = 0; 4551558Srgrimes return (1); 4561558Srgrimes } 4571558Srgrimes return (0); 4581558Srgrimes} 459