1 /* $OpenBSD: tunefs.c,v 1.13 2001/05/18 08:27:57 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.13 2001/05/18 08:27:57 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; 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 *); 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 getsb(&sblock, special); 122 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { 123 for (cp = &argv[0][1]; *cp; cp++) 124 switch (*cp) { 125 126 case 'A': 127 Aflag++; 128 continue; 129 130 case 'p': 131 printfs(); 132 return (0); 133 134 case 'a': 135 name = "maximum contiguous block count"; 136 if (argc < 1) 137 errx(10, "-a: missing %s", name); 138 argc--, argv++; 139 i = atoi(*argv); 140 if (i < 1) 141 errx(10, "%s must be >= 1 (was %s)", 142 name, *argv); 143 warnx("%s changes from %d to %d", 144 name, sblock.fs_maxcontig, i); 145 sblock.fs_maxcontig = i; 146 continue; 147 148 case 'd': 149 name = 150 "rotational delay between contiguous blocks"; 151 if (argc < 1) 152 errx(10, "-d: missing %s", name); 153 argc--, argv++; 154 i = atoi(*argv); 155 warnx("%s changes from %dms to %dms", 156 name, sblock.fs_rotdelay, i); 157 sblock.fs_rotdelay = i; 158 continue; 159 160 case 'e': 161 name = 162 "maximum blocks per file in a cylinder group"; 163 if (argc < 1) 164 errx(10, "-e: missing %s", name); 165 argc--, argv++; 166 i = atoi(*argv); 167 if (i < 1) 168 errx(10, "%s must be >= 1 (was %s)", 169 name, *argv); 170 warnx("%s changes from %d to %d", 171 name, sblock.fs_maxbpg, i); 172 sblock.fs_maxbpg = i; 173 continue; 174 175 case 'f': 176 name = "average file size"; 177 if (argc < 1) 178 errx(10, "-f: missing %s", name); 179 argc--, argv++; 180 i = atoi(*argv); 181 if (i < 0) 182 errx(10, "%s must be >= 0 (was %s)", 183 name, *argv); 184 warnx("%s changes from %d to %d", 185 name, sblock.fs_avgfilesize, i); 186 sblock.fs_avgfilesize = i; 187 continue; 188 189 case 'm': 190 name = "minimum percentage of free space"; 191 if (argc < 1) 192 errx(10, "-m: missing %s", name); 193 argc--, argv++; 194 i = atoi(*argv); 195 if (i < 0 || i > 99) 196 errx(10, "bad %s (%s)", name, *argv); 197 warnx("%s changes from %d%% to %d%%", 198 name, sblock.fs_minfree, i); 199 sblock.fs_minfree = i; 200 if (i >= MINFREE && 201 sblock.fs_optim == FS_OPTSPACE) 202 warnx(OPTWARN, "time", ">=", MINFREE); 203 if (i < MINFREE && 204 sblock.fs_optim == FS_OPTTIME) 205 warnx(OPTWARN, "space", "<", MINFREE); 206 continue; 207 208 case 'n': 209 name = "expected number of files per directory"; 210 if (argc < 1) 211 errx(10, "-n: missing %s", name); 212 argc--, argv++; 213 i = atoi(*argv); 214 if (i < 0) 215 errx(10, "%s must be >= 0 (was %s)", 216 name, *argv); 217 warnx("%s changes from %d to %d", 218 name, sblock.fs_avgfpdir, i); 219 sblock.fs_avgfpdir = i; 220 continue; 221 222 case 's': 223 errx(1, "See mount(8) for details about" 224 " how to enable soft updates."); 225 226 case 'o': 227 name = "optimization preference"; 228 if (argc < 1) 229 errx(10, "-o: missing %s", name); 230 argc--, argv++; 231 chg[FS_OPTSPACE] = "space"; 232 chg[FS_OPTTIME] = "time"; 233 if (strcmp(*argv, chg[FS_OPTSPACE]) == 0) 234 i = FS_OPTSPACE; 235 else if (strcmp(*argv, chg[FS_OPTTIME]) == 0) 236 i = FS_OPTTIME; 237 else 238 errx(10, "bad %s (options are `space' or `time')", 239 name); 240 if (sblock.fs_optim == i) { 241 warnx("%s remains unchanged as %s", 242 name, chg[i]); 243 continue; 244 } 245 warnx("%s changes from %s to %s", 246 name, chg[sblock.fs_optim], chg[i]); 247 sblock.fs_optim = i; 248 if (sblock.fs_minfree >= MINFREE && 249 i == FS_OPTSPACE) 250 warnx(OPTWARN, "time", ">=", MINFREE); 251 if (sblock.fs_minfree < MINFREE && 252 i == FS_OPTTIME) 253 warnx(OPTWARN, "space", "<", MINFREE); 254 continue; 255 256 default: 257 usage(); 258 } 259 } 260 if (argc != 1) 261 usage(); 262 bwrite((daddr_t)SBOFF / dev_bsize, (char *)&sblock, SBSIZE); 263 if (Aflag) 264 for (i = 0; i < sblock.fs_ncg; i++) 265 bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)), 266 (char *)&sblock, SBSIZE); 267 close(fi); 268 return (0); 269 } 270 271 void 272 usage() 273 { 274 fprintf(stderr, 275 "Usage: %s tuneup-options special-device\n" 276 "where tuneup-options are:\n" 277 "\t-a maximum contiguous blocks\n" 278 "\t-d rotational delay between contiguous blocks\n" 279 "\t-e maximum blocks per file in a cylinder group\n" 280 "\t-f expected average file size\n" 281 "\t-m minimum percentage of free space\n" 282 "\t-n expected number of files per directory\n" 283 "\t-o optimization preference (`space' or `time')\n" 284 "\t-p no change - just prints current tuneable settings\n", 285 __progname); 286 exit(2); 287 } 288 289 void 290 getsb(fs, file) 291 register struct fs *fs; 292 char *file; 293 { 294 295 fi = open(file, 2); 296 if (fi < 0) 297 err(3, "cannot open %s", file); 298 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 299 err(4, "%s: bad super block", file); 300 if (fs->fs_magic != FS_MAGIC) 301 err(5, "%s: bad magic number", file); 302 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 303 } 304 305 void 306 printfs() 307 { 308 warnx("maximum contiguous block count: (-a) %d", 309 sblock.fs_maxcontig); 310 warnx("rotational delay between contiguous blocks: (-d) %d ms", 311 sblock.fs_rotdelay); 312 warnx("maximum blocks per file in a cylinder group: (-e) %d", 313 sblock.fs_maxbpg); 314 warnx("expected average file size: (-f) %d", 315 sblock.fs_avgfilesize); 316 warnx("minimum percentage of free space: (-m) %d%%", 317 sblock.fs_minfree); 318 warnx("expected number of files per directory: (-n) %d", 319 sblock.fs_avgfpdir); 320 warnx("optimization preference: (-o) %s", 321 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 322 if (sblock.fs_minfree >= MINFREE && 323 sblock.fs_optim == FS_OPTSPACE) 324 warnx(OPTWARN, "time", ">=", MINFREE); 325 if (sblock.fs_minfree < MINFREE && 326 sblock.fs_optim == FS_OPTTIME) 327 warnx(OPTWARN, "space", "<", MINFREE); 328 } 329 330 void 331 bwrite(blk, buf, size) 332 daddr_t blk; 333 char *buf; 334 int size; 335 { 336 337 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 338 err(6, "FS SEEK"); 339 if (write(fi, buf, size) != size) 340 err(7, "FS WRITE"); 341 } 342 343 int 344 bread(bno, buf, cnt) 345 daddr_t bno; 346 char *buf; 347 int cnt; 348 { 349 int i; 350 351 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 352 return(1); 353 if ((i = read(fi, buf, cnt)) != cnt) { 354 for(i=0; i<sblock.fs_bsize; i++) 355 buf[i] = 0; 356 return (1); 357 } 358 return (0); 359 } 360