1 /* 2 * Copyright (c) 1983, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)newfs.c 6.25 (Berkeley) 04/10/91"; 10 #endif /* not lint */ 11 12 #ifndef lint 13 char copyright[] = 14 "@(#) Copyright (c) 1983, 1989 Regents of the University of California.\n\ 15 All rights reserved.\n"; 16 #endif /* not lint */ 17 18 /* 19 * newfs: friendly front end to mkfs 20 */ 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <ufs/fs.h> 24 #include <ufs/dir.h> 25 #include <sys/ioctl.h> 26 #include <sys/disklabel.h> 27 #include <sys/file.h> 28 #include <sys/mount.h> 29 30 #include <errno.h> 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <ctype.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <paths.h> 37 38 #define COMPAT /* allow non-labeled disks */ 39 40 /* 41 * The following two constants set the default block and fragment sizes. 42 * Both constants must be a power of 2 and meet the following constraints: 43 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 44 * sectorsize <= DESFRAGSIZE <= DESBLKSIZE 45 * DESBLKSIZE / DESFRAGSIZE <= 8 46 */ 47 #define DFL_FRAGSIZE 1024 48 #define DFL_BLKSIZE 8192 49 50 /* 51 * Cylinder groups may have up to many cylinders. The actual 52 * number used depends upon how much information can be stored 53 * on a single cylinder. The default is to use 16 cylinders 54 * per group. 55 */ 56 #define DESCPG 16 /* desired fs_cpg */ 57 58 /* 59 * MINFREE gives the minimum acceptable percentage of file system 60 * blocks which may be free. If the freelist drops below this level 61 * only the superuser may continue to allocate blocks. This may 62 * be set to 0 if no reserve of free blocks is deemed necessary, 63 * however throughput drops by fifty percent if the file system 64 * is run at between 90% and 100% full; thus the default value of 65 * fs_minfree is 10%. With 10% free space, fragmentation is not a 66 * problem, so we choose to optimize for time. 67 */ 68 #define MINFREE 10 69 #define DEFAULTOPT FS_OPTTIME 70 71 /* 72 * ROTDELAY gives the minimum number of milliseconds to initiate 73 * another disk transfer on the same cylinder. It is used in 74 * determining the rotationally optimal layout for disk blocks 75 * within a file; the default of fs_rotdelay is 4ms. 76 */ 77 #define ROTDELAY 4 78 79 /* 80 * MAXCONTIG sets the default for the maximum number of blocks 81 * that may be allocated sequentially. Since UNIX drivers are 82 * not capable of scheduling multi-block transfers, this defaults 83 * to 1 (ie no contiguous blocks are allocated). 84 */ 85 #define MAXCONTIG 1 86 87 /* 88 * MAXBLKPG determines the maximum number of data blocks which are 89 * placed in a single cylinder group. The default is one indirect 90 * block worth of data blocks. 91 */ 92 #define MAXBLKPG(bsize) ((bsize) / sizeof(daddr_t)) 93 94 /* 95 * Each file system has a number of inodes statically allocated. 96 * We allocate one inode slot per NFPI fragments, expecting this 97 * to be far more than we will ever need. 98 */ 99 #define NFPI 4 100 101 /* 102 * For each cylinder we keep track of the availability of blocks at different 103 * rotational positions, so that we can lay out the data to be picked 104 * up with minimum rotational latency. NRPOS is the default number of 105 * rotational positions that we distinguish. With NRPOS of 8 the resolution 106 * of our summary information is 2ms for a typical 3600 rpm drive. 107 */ 108 #define NRPOS 8 /* number distinct rotational positions */ 109 110 111 int mfs; /* run as the memory based filesystem */ 112 int Nflag; /* run without writing file system */ 113 int fssize; /* file system size */ 114 int ntracks; /* # tracks/cylinder */ 115 int nsectors; /* # sectors/track */ 116 int nphyssectors; /* # sectors/track including spares */ 117 int secpercyl; /* sectors per cylinder */ 118 int trackspares = -1; /* spare sectors per track */ 119 int cylspares = -1; /* spare sectors per cylinder */ 120 int sectorsize; /* bytes/sector */ 121 #ifdef tahoe 122 int realsectorsize; /* bytes/sector in hardware */ 123 #endif 124 int rpm; /* revolutions/minute of drive */ 125 int interleave; /* hardware sector interleave */ 126 int trackskew = -1; /* sector 0 skew, per track */ 127 int headswitch; /* head switch time, usec */ 128 int trackseek; /* track-to-track seek, usec */ 129 int fsize = 0; /* fragment size */ 130 int bsize = 0; /* block size */ 131 int cpg = DESCPG; /* cylinders/cylinder group */ 132 int cpgflg; /* cylinders/cylinder group flag was given */ 133 int minfree = MINFREE; /* free space threshold */ 134 int opt = DEFAULTOPT; /* optimization preference (space or time) */ 135 int density; /* number of bytes per inode */ 136 int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */ 137 int rotdelay = ROTDELAY; /* rotational delay between blocks */ 138 int maxbpg; /* maximum blocks per file in a cyl group */ 139 int nrpos = NRPOS; /* # of distinguished rotational positions */ 140 int bbsize = BBSIZE; /* boot block size */ 141 int sbsize = SBSIZE; /* superblock size */ 142 int mntflags; /* flags to be passed to mount */ 143 u_long memleft; /* virtual memory available */ 144 caddr_t membase; /* start address of memory based filesystem */ 145 #ifdef COMPAT 146 char *disktype; 147 int unlabeled; 148 #endif 149 150 char device[MAXPATHLEN]; 151 char *progname; 152 153 main(argc, argv) 154 int argc; 155 char *argv[]; 156 { 157 extern char *optarg; 158 extern int optind; 159 register int ch; 160 register struct partition *pp; 161 register struct disklabel *lp; 162 struct disklabel *getdisklabel(); 163 struct partition oldpartition; 164 struct mfs_args args; 165 struct stat st; 166 int fsi, fso; 167 char *cp, *special, *opstring, buf[BUFSIZ]; 168 169 if (progname = rindex(*argv, '/')) 170 ++progname; 171 else 172 progname = *argv; 173 174 if (!strcmp(progname, "mfs")) { 175 mfs = 1; 176 Nflag++; 177 } 178 179 opstring = "F:NS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:"; 180 if (!mfs) 181 opstring += 2; /* -F is mfs only */ 182 183 while ((ch = getopt(argc, argv, opstring)) != EOF) 184 switch(ch) { 185 case 'F': 186 if ((mntflags = atoi(optarg)) == 0) 187 fatal("%s: bad mount flags", optarg); 188 break; 189 case 'N': 190 Nflag++; 191 break; 192 case 'S': 193 if ((sectorsize = atoi(optarg)) <= 0) 194 fatal("%s: bad sector size", optarg); 195 break; 196 #ifdef COMPAT 197 case 'T': 198 disktype = optarg; 199 break; 200 #endif 201 case 'a': 202 if ((maxcontig = atoi(optarg)) <= 0) 203 fatal("%s: bad max contiguous blocks\n", 204 optarg); 205 break; 206 case 'b': 207 if ((bsize = atoi(optarg)) < MINBSIZE) 208 fatal("%s: bad block size", optarg); 209 break; 210 case 'c': 211 if ((cpg = atoi(optarg)) <= 0) 212 fatal("%s: bad cylinders/group", optarg); 213 cpgflg++; 214 break; 215 case 'd': 216 if ((rotdelay = atoi(optarg)) < 0) 217 fatal("%s: bad rotational delay\n", optarg); 218 break; 219 case 'e': 220 if ((maxbpg = atoi(optarg)) <= 0) 221 fatal("%s: bad blocks per file in a cyl group\n", 222 optarg); 223 break; 224 case 'f': 225 if ((fsize = atoi(optarg)) <= 0) 226 fatal("%s: bad frag size", optarg); 227 break; 228 case 'i': 229 if ((density = atoi(optarg)) <= 0) 230 fatal("%s: bad bytes per inode\n", optarg); 231 break; 232 case 'k': 233 if ((trackskew = atoi(optarg)) < 0) 234 fatal("%s: bad track skew", optarg); 235 break; 236 case 'l': 237 if ((interleave = atoi(optarg)) <= 0) 238 fatal("%s: bad interleave", optarg); 239 break; 240 case 'm': 241 if ((minfree = atoi(optarg)) < 0 || minfree > 99) 242 fatal("%s: bad free space %%\n", optarg); 243 break; 244 case 'n': 245 if ((nrpos = atoi(optarg)) <= 0) 246 fatal("%s: bad rotational layout count\n", 247 optarg); 248 break; 249 case 'o': 250 if (strcmp(optarg, "space") == 0) 251 opt = FS_OPTSPACE; 252 else if (strcmp(optarg, "time") == 0) 253 opt = FS_OPTTIME; 254 else 255 fatal("%s: bad optimization preference %s", 256 optarg, "(options are `space' or `time')"); 257 break; 258 case 'p': 259 if ((trackspares = atoi(optarg)) < 0) 260 fatal("%s: bad spare sectors per track", 261 optarg); 262 break; 263 case 'r': 264 if ((rpm = atoi(optarg)) <= 0) 265 fatal("%s: bad revs/minute\n", optarg); 266 break; 267 case 's': 268 if ((fssize = atoi(optarg)) <= 0) 269 fatal("%s: bad file system size", optarg); 270 break; 271 case 't': 272 if ((ntracks = atoi(optarg)) <= 0) 273 fatal("%s: bad total tracks", optarg); 274 break; 275 case 'u': 276 if ((nsectors = atoi(optarg)) <= 0) 277 fatal("%s: bad sectors/track", optarg); 278 break; 279 case 'x': 280 if ((cylspares = atoi(optarg)) < 0) 281 fatal("%s: bad spare sectors per cylinder", 282 optarg); 283 break; 284 case '?': 285 default: 286 usage(); 287 } 288 argc -= optind; 289 argv += optind; 290 291 if (argc != 2 && (mfs || argc != 1)) 292 usage(); 293 294 special = argv[0]; 295 cp = rindex(special, '/'); 296 if (cp == 0) { 297 /* 298 * No path prefix; try /dev/r%s then /dev/%s. 299 */ 300 (void)sprintf(device, "%sr%s", _PATH_DEV, special); 301 if (stat(device, &st) == -1) 302 (void)sprintf(device, "%s%s", _PATH_DEV, special); 303 special = device; 304 } 305 if (!Nflag) { 306 fso = open(special, O_WRONLY); 307 if (fso < 0) 308 fatal("%s: %s", special, strerror(errno)); 309 } else 310 fso = -1; 311 fsi = open(special, O_RDONLY); 312 if (fsi < 0) 313 fatal("%s: %s", special, strerror(errno)); 314 if (fstat(fsi, &st) < 0) 315 fatal("%s: %s", special, strerror(errno)); 316 if ((st.st_mode & S_IFMT) != S_IFCHR && !mfs) 317 printf("%s: %s: not a character-special device\n", 318 progname, special); 319 cp = index(argv[0], '\0') - 1; 320 if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) 321 fatal("%s: can't figure out file system partition", argv[0]); 322 #ifdef COMPAT 323 if (!mfs && disktype == NULL) 324 disktype = argv[1]; 325 #endif 326 lp = getdisklabel(special, fsi); 327 if (isdigit(*cp)) 328 pp = &lp->d_partitions[0]; 329 else 330 pp = &lp->d_partitions[*cp - 'a']; 331 if (pp->p_size == 0) 332 fatal("%s: `%c' partition is unavailable", argv[0], *cp); 333 if (fssize == 0) 334 fssize = pp->p_size; 335 if (fssize > pp->p_size && !mfs) 336 fatal("%s: maximum file system size on the `%c' partition is %d", 337 argv[0], *cp, pp->p_size); 338 if (rpm == 0) { 339 rpm = lp->d_rpm; 340 if (rpm <= 0) 341 rpm = 3600; 342 } 343 if (ntracks == 0) { 344 ntracks = lp->d_ntracks; 345 if (ntracks <= 0) 346 fatal("%s: no default #tracks", argv[0]); 347 } 348 if (nsectors == 0) { 349 nsectors = lp->d_nsectors; 350 if (nsectors <= 0) 351 fatal("%s: no default #sectors/track", argv[0]); 352 } 353 if (sectorsize == 0) { 354 sectorsize = lp->d_secsize; 355 if (sectorsize <= 0) 356 fatal("%s: no default sector size", argv[0]); 357 } 358 if (trackskew == -1) { 359 trackskew = lp->d_trackskew; 360 if (trackskew < 0) 361 trackskew = 0; 362 } 363 if (interleave == 0) { 364 interleave = lp->d_interleave; 365 if (interleave <= 0) 366 interleave = 1; 367 } 368 if (fsize == 0) { 369 fsize = pp->p_fsize; 370 if (fsize <= 0) 371 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); 372 } 373 if (bsize == 0) { 374 bsize = pp->p_frag * pp->p_fsize; 375 if (bsize <= 0) 376 bsize = MIN(DFL_BLKSIZE, 8 * fsize); 377 } 378 if (density == 0) 379 density = NFPI * fsize; 380 if (minfree < 10 && opt != FS_OPTSPACE) { 381 fprintf(stderr, "Warning: changing optimization to space "); 382 fprintf(stderr, "because minfree is less than 10%%\n"); 383 opt = FS_OPTSPACE; 384 } 385 if (trackspares == -1) { 386 trackspares = lp->d_sparespertrack; 387 if (trackspares < 0) 388 trackspares = 0; 389 } 390 nphyssectors = nsectors + trackspares; 391 if (cylspares == -1) { 392 cylspares = lp->d_sparespercyl; 393 if (cylspares < 0) 394 cylspares = 0; 395 } 396 secpercyl = nsectors * ntracks - cylspares; 397 if (secpercyl != lp->d_secpercyl) 398 fprintf(stderr, "%s (%d) %s (%lu)\n", 399 "Warning: calculated sectors per cylinder", secpercyl, 400 "disagrees with disk label", lp->d_secpercyl); 401 if (maxbpg == 0) 402 maxbpg = MAXBLKPG(bsize); 403 headswitch = lp->d_headswitch; 404 trackseek = lp->d_trkseek; 405 #ifdef notdef /* label may be 0 if faked up by kernel */ 406 bbsize = lp->d_bbsize; 407 sbsize = lp->d_sbsize; 408 #endif 409 oldpartition = *pp; 410 #ifdef tahoe 411 realsectorsize = sectorsize; 412 if (sectorsize != DEV_BSIZE) { /* XXX */ 413 int secperblk = DEV_BSIZE / sectorsize; 414 415 sectorsize = DEV_BSIZE; 416 nsectors /= secperblk; 417 nphyssectors /= secperblk; 418 secpercyl /= secperblk; 419 fssize /= secperblk; 420 pp->p_size /= secperblk; 421 } 422 #endif 423 mkfs(pp, special, fsi, fso); 424 #ifdef tahoe 425 if (realsectorsize != DEV_BSIZE) 426 pp->p_size *= DEV_BSIZE / realsectorsize; 427 #endif 428 if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition))) 429 rewritelabel(special, fso, lp); 430 if (!Nflag) 431 close(fso); 432 close(fsi); 433 if (mfs) { 434 sprintf(buf, "mfs:%d", getpid()); 435 args.name = buf; 436 args.base = membase; 437 args.size = fssize * sectorsize; 438 if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0) 439 fatal("%s: %s", argv[1], strerror(errno)); 440 } 441 exit(0); 442 } 443 444 #ifdef COMPAT 445 char lmsg[] = "%s: can't read disk label; disk type must be specified"; 446 #else 447 char lmsg[] = "%s: can't read disk label"; 448 #endif 449 450 struct disklabel * 451 getdisklabel(s, fd) 452 char *s; 453 int fd; 454 { 455 static struct disklabel lab; 456 457 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 458 #ifdef COMPAT 459 if (disktype) { 460 struct disklabel *lp, *getdiskbyname(); 461 462 unlabeled++; 463 lp = getdiskbyname(disktype); 464 if (lp == NULL) 465 fatal("%s: unknown disk type", disktype); 466 return (lp); 467 } 468 #endif 469 (void)fprintf(stderr, 470 "%s: ioctl (GDINFO): %s\n", progname, strerror(errno)); 471 fatal(lmsg, s); 472 } 473 return (&lab); 474 } 475 476 rewritelabel(s, fd, lp) 477 char *s; 478 int fd; 479 register struct disklabel *lp; 480 { 481 #ifdef COMPAT 482 if (unlabeled) 483 return; 484 #endif 485 lp->d_checksum = 0; 486 lp->d_checksum = dkcksum(lp); 487 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 488 (void)fprintf(stderr, 489 "%s: ioctl (WDINFO): %s\n", progname, strerror(errno)); 490 fatal("%s: can't rewrite disk label", s); 491 } 492 #if vax 493 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 494 register i; 495 int cfd; 496 daddr_t alt; 497 char specname[64]; 498 char blk[1024]; 499 char *cp; 500 501 /* 502 * Make name for 'c' partition. 503 */ 504 strcpy(specname, s); 505 cp = specname + strlen(specname) - 1; 506 if (!isdigit(*cp)) 507 *cp = 'c'; 508 cfd = open(specname, O_WRONLY); 509 if (cfd < 0) 510 fatal("%s: %s", specname, strerror(errno)); 511 bzero(blk, sizeof(blk)); 512 *(struct disklabel *)(blk + LABELOFFSET) = *lp; 513 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 514 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 515 if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize, 516 L_SET) == -1) 517 fatal("lseek to badsector area: %s", 518 strerror(errno)); 519 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) 520 fprintf(stderr, 521 "%s: alternate label %d write: %s\n", 522 progname, i/2, strerror(errno)); 523 } 524 close(cfd); 525 } 526 #endif 527 } 528 529 /*VARARGS*/ 530 fatal(fmt) 531 char *fmt; 532 { 533 va_list ap; 534 535 fprintf(stderr, "%s: ", progname); 536 va_start(ap, fmt); 537 (void)vfprintf(stderr, fmt, ap); 538 va_end(ap); 539 putc('\n', stderr); 540 exit(1); 541 } 542 543 usage() 544 { 545 if (mfs) { 546 fprintf(stderr, 547 "usage: mfs [ -fsoptions ] special-device mount-point\n"); 548 } else 549 fprintf(stderr, 550 "usage: newfs [ -fsoptions ] special-device%s\n", 551 #ifdef COMPAT 552 " [device-type]"); 553 #else 554 ""); 555 #endif 556 fprintf(stderr, "where fsoptions are:\n"); 557 fprintf(stderr, 558 "\t-N do not create file system, just print out parameters\n"); 559 fprintf(stderr, "\t-S sector size\n"); 560 #ifdef COMPAT 561 fprintf(stderr, "\t-T disktype\n"); 562 #endif 563 fprintf(stderr, "\t-a maximum contiguous blocks\n"); 564 fprintf(stderr, "\t-b block size\n"); 565 fprintf(stderr, "\t-c cylinders/group\n"); 566 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n"); 567 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); 568 fprintf(stderr, "\t-f frag size\n"); 569 fprintf(stderr, "\t-i number of bytes per inode\n"); 570 fprintf(stderr, "\t-k sector 0 skew, per track\n"); 571 fprintf(stderr, "\t-l hardware sector interleave\n"); 572 fprintf(stderr, "\t-m minimum free space %%\n"); 573 fprintf(stderr, "\t-n number of distinguished rotational positions\n"); 574 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); 575 fprintf(stderr, "\t-p spare sectors per track\n"); 576 fprintf(stderr, "\t-s file system size (sectors)\n"); 577 fprintf(stderr, "\t-r revolutions/minute\n"); 578 fprintf(stderr, "\t-t tracks/cylinder\n"); 579 fprintf(stderr, "\t-u sectors/track\n"); 580 fprintf(stderr, "\t-x spare sectors per cylinder\n"); 581 exit(1); 582 } 583