1 /* $OpenBSD: tunefs.c,v 1.16 2001/12/04 07:23:58 mickey Exp $ */ 2 /* $NetBSD: tunefs.c,v 1.10 1995/03/18 15:01:31 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1983, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)tunefs.c 8.2 (Berkeley) 4/19/94"; 46 #else 47 static char rcsid[] = "$OpenBSD: tunefs.c,v 1.16 2001/12/04 07:23:58 mickey Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 /* 52 * tunefs: change layout parameters to an existing file system. 53 */ 54 #include <sys/param.h> 55 #include <sys/stat.h> 56 57 #include <ufs/ffs/fs.h> 58 59 #include <errno.h> 60 #include <err.h> 61 #include <fcntl.h> 62 #include <fstab.h> 63 #include <stdio.h> 64 #include <paths.h> 65 #include <stdlib.h> 66 #include <unistd.h> 67 68 /* the optimization warning string template */ 69 #define OPTWARN "should optimize for %s with minfree %s %d%%" 70 71 union { 72 struct fs sb; 73 char pad[MAXBSIZE]; 74 } sbun; 75 #define sblock sbun.sb 76 77 int fi = -1; 78 long dev_bsize = 1; 79 80 void bwrite(daddr_t, char *, int); 81 int bread(daddr_t, char *, int); 82 void getsb(struct fs *, char *, int); 83 void usage __P((void)); 84 void printfs __P((void)); 85 86 extern char *__progname; 87 88 int 89 main(argc, argv) 90 int argc; 91 char *argv[]; 92 { 93 char *cp, *special, *name; 94 struct stat st; 95 int i; 96 int Aflag = 0; 97 struct fstab *fs; 98 char *chg[2], device[MAXPATHLEN]; 99 100 argc--, argv++; 101 if (argc < 2) 102 usage(); 103 special = argv[argc - 1]; 104 fs = getfsfile(special); 105 if (fs) 106 special = fs->fs_spec; 107 again: 108 if (stat(special, &st) < 0) { 109 if (*special != '/') { 110 if (*special == 'r') 111 special++; 112 (void)snprintf(device, sizeof(device), "%s/%s", 113 _PATH_DEV, special); 114 special = device; 115 goto again; 116 } 117 err(1, "%s", special); 118 } 119 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) 120 errx(10, "%s: not a block or character device", special); 121 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { 122 for (cp = &argv[0][1]; *cp; cp++) 123 switch (*cp) { 124 125 case 'A': 126 Aflag++; 127 continue; 128 129 case 'p': 130 getsb(&sblock, special, O_RDONLY); 131 printfs(); 132 return (0); 133 134 case 'a': 135 getsb(&sblock, special, O_RDWR); 136 name = "maximum contiguous block count"; 137 if (argc < 1) 138 errx(10, "-a: missing %s", name); 139 argc--, argv++; 140 i = atoi(*argv); 141 if (i < 1) 142 errx(10, "%s must be >= 1 (was %s)", 143 name, *argv); 144 warnx("%s changes from %d to %d", 145 name, sblock.fs_maxcontig, i); 146 sblock.fs_maxcontig = i; 147 continue; 148 149 case 'd': 150 getsb(&sblock, special, O_RDWR); 151 name = 152 "rotational delay between contiguous blocks"; 153 if (argc < 1) 154 errx(10, "-d: missing %s", name); 155 argc--, argv++; 156 i = atoi(*argv); 157 warnx("%s changes from %dms to %dms", 158 name, sblock.fs_rotdelay, i); 159 sblock.fs_rotdelay = i; 160 continue; 161 162 case 'e': 163 getsb(&sblock, special, O_RDWR); 164 name = 165 "maximum blocks per file in a cylinder group"; 166 if (argc < 1) 167 errx(10, "-e: missing %s", name); 168 argc--, argv++; 169 i = atoi(*argv); 170 if (i < 1) 171 errx(10, "%s must be >= 1 (was %s)", 172 name, *argv); 173 warnx("%s changes from %d to %d", 174 name, sblock.fs_maxbpg, i); 175 sblock.fs_maxbpg = i; 176 continue; 177 178 case 'f': 179 getsb(&sblock, special, O_RDWR); 180 name = "average file size"; 181 if (argc < 1) 182 errx(10, "-f: missing %s", name); 183 argc--, argv++; 184 i = atoi(*argv); 185 if (i < 0) 186 errx(10, "%s must be >= 0 (was %s)", 187 name, *argv); 188 warnx("%s changes from %d to %d", 189 name, sblock.fs_avgfilesize, i); 190 sblock.fs_avgfilesize = i; 191 continue; 192 193 case 'm': 194 getsb(&sblock, special, O_RDWR); 195 name = "minimum percentage of free space"; 196 if (argc < 1) 197 errx(10, "-m: missing %s", name); 198 argc--, argv++; 199 i = atoi(*argv); 200 if (i < 0 || i > 99) 201 errx(10, "bad %s (%s)", name, *argv); 202 warnx("%s changes from %d%% to %d%%", 203 name, sblock.fs_minfree, i); 204 sblock.fs_minfree = i; 205 if (i >= MINFREE && 206 sblock.fs_optim == FS_OPTSPACE) 207 warnx(OPTWARN, "time", ">=", MINFREE); 208 if (i < MINFREE && 209 sblock.fs_optim == FS_OPTTIME) 210 warnx(OPTWARN, "space", "<", MINFREE); 211 continue; 212 213 case 'n': 214 getsb(&sblock, special, O_RDWR); 215 name = "expected number of files per directory"; 216 if (argc < 1) 217 errx(10, "-n: missing %s", name); 218 argc--, argv++; 219 i = atoi(*argv); 220 if (i < 0) 221 errx(10, "%s must be >= 0 (was %s)", 222 name, *argv); 223 warnx("%s changes from %d to %d", 224 name, sblock.fs_avgfpdir, i); 225 sblock.fs_avgfpdir = i; 226 continue; 227 228 case 's': 229 errx(1, "See mount(8) for details about" 230 " how to enable soft updates."); 231 232 case 'o': 233 getsb(&sblock, special, O_RDWR); 234 name = "optimization preference"; 235 if (argc < 1) 236 errx(10, "-o: missing %s", name); 237 argc--, argv++; 238 chg[FS_OPTSPACE] = "space"; 239 chg[FS_OPTTIME] = "time"; 240 if (strcmp(*argv, chg[FS_OPTSPACE]) == 0) 241 i = FS_OPTSPACE; 242 else if (strcmp(*argv, chg[FS_OPTTIME]) == 0) 243 i = FS_OPTTIME; 244 else 245 errx(10, "bad %s (options are `space' or `time')", 246 name); 247 if (sblock.fs_optim == i) { 248 warnx("%s remains unchanged as %s", 249 name, chg[i]); 250 continue; 251 } 252 warnx("%s changes from %s to %s", 253 name, chg[sblock.fs_optim], chg[i]); 254 sblock.fs_optim = i; 255 if (sblock.fs_minfree >= MINFREE && 256 i == FS_OPTSPACE) 257 warnx(OPTWARN, "time", ">=", MINFREE); 258 if (sblock.fs_minfree < MINFREE && 259 i == FS_OPTTIME) 260 warnx(OPTWARN, "space", "<", MINFREE); 261 continue; 262 263 default: 264 usage(); 265 } 266 } 267 if (argc != 1) 268 usage(); 269 bwrite((daddr_t)SBOFF / dev_bsize, (char *)&sblock, SBSIZE); 270 if (Aflag) 271 for (i = 0; i < sblock.fs_ncg; i++) 272 bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)), 273 (char *)&sblock, SBSIZE); 274 if (close(fi)) 275 err(1, "close: %s", special); 276 277 return (0); 278 } 279 280 void 281 usage() 282 { 283 fprintf(stderr, 284 "Usage: %s tuneup-options special-device\n" 285 "where tuneup-options are:\n" 286 "\t-A modify all backups of the super-block\n" 287 "\t-a maximum contiguous blocks\n" 288 "\t-d rotational delay between contiguous blocks\n" 289 "\t-e maximum blocks per file in a cylinder group\n" 290 "\t-f expected average file size\n" 291 "\t-m minimum percentage of free space\n" 292 "\t-n expected number of files per directory\n" 293 "\t-o optimization preference (`space' or `time')\n" 294 "\t-p no change - just prints current tuneable settings\n", 295 __progname); 296 exit(2); 297 } 298 299 void 300 getsb(fs, file, flags) 301 struct fs *fs; 302 char *file; 303 int flags; 304 { 305 306 if (fi >= 0) 307 return; 308 fi = open(file, flags); 309 if (fi < 0) 310 err(3, "cannot open %s", file); 311 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 312 err(4, "%s: bad super block", file); 313 if (fs->fs_magic != FS_MAGIC) 314 errx(5, "%s: bad magic number", file); 315 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 316 } 317 318 void 319 printfs() 320 { 321 warnx("maximum contiguous block count: (-a) %d", 322 sblock.fs_maxcontig); 323 warnx("rotational delay between contiguous blocks: (-d) %d ms", 324 sblock.fs_rotdelay); 325 warnx("maximum blocks per file in a cylinder group: (-e) %d", 326 sblock.fs_maxbpg); 327 warnx("expected average file size: (-f) %d", 328 sblock.fs_avgfilesize); 329 warnx("minimum percentage of free space: (-m) %d%%", 330 sblock.fs_minfree); 331 warnx("expected number of files per directory: (-n) %d", 332 sblock.fs_avgfpdir); 333 warnx("optimization preference: (-o) %s", 334 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 335 if (sblock.fs_minfree >= MINFREE && 336 sblock.fs_optim == FS_OPTSPACE) 337 warnx(OPTWARN, "time", ">=", MINFREE); 338 if (sblock.fs_minfree < MINFREE && 339 sblock.fs_optim == FS_OPTTIME) 340 warnx(OPTWARN, "space", "<", MINFREE); 341 } 342 343 void 344 bwrite(blk, buf, size) 345 daddr_t blk; 346 char *buf; 347 int size; 348 { 349 350 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 351 err(6, "FS SEEK"); 352 if (write(fi, buf, size) != size) 353 err(7, "FS WRITE"); 354 } 355 356 int 357 bread(bno, buf, cnt) 358 daddr_t bno; 359 char *buf; 360 int cnt; 361 { 362 int i; 363 364 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 365 return(1); 366 if ((i = read(fi, buf, cnt)) != cnt) { 367 for(i=0; i<sblock.fs_bsize; i++) 368 buf[i] = 0; 369 return (1); 370 } 371 return (0); 372 } 373