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