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.23 (Berkeley) 07/25/90"; 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 special = cp + 1; 298 if (*special == 'r' 299 #if defined(vax) || defined(tahoe) 300 && special[1] != 'a' && special[1] != 'b') 301 #endif 302 #if defined(hp300) 303 && special[1] != 'd') 304 #endif 305 special++; 306 (void)sprintf(device, "%s/r%s", _PATH_DEV, special); 307 special = device; 308 if (!Nflag) { 309 fso = open(special, O_WRONLY); 310 if (fso < 0) 311 fatal("%s: %s", special, strerror(errno)); 312 } else 313 fso = -1; 314 fsi = open(special, O_RDONLY); 315 if (fsi < 0) 316 fatal("%s: %s", special, strerror(errno)); 317 if (fstat(fsi, &st) < 0) 318 fatal("%s: %s", special, strerror(errno)); 319 if ((st.st_mode & S_IFMT) != S_IFCHR) 320 fatal("%s: not a character device", special); 321 cp = index(argv[0], '\0') - 1; 322 if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) 323 fatal("%s: can't figure out file system partition", argv[0]); 324 #ifdef COMPAT 325 if (!mfs && disktype == NULL) 326 disktype = argv[1]; 327 #endif 328 lp = getdisklabel(special, fsi); 329 if (isdigit(*cp)) 330 pp = &lp->d_partitions[0]; 331 else 332 pp = &lp->d_partitions[*cp - 'a']; 333 if (pp->p_size == 0) 334 fatal("%s: `%c' partition is unavailable", argv[0], *cp); 335 if (fssize == 0) 336 fssize = pp->p_size; 337 if (fssize > pp->p_size && !mfs) 338 fatal("%s: maximum file system size on the `%c' partition is %d", 339 argv[0], *cp, pp->p_size); 340 if (rpm == 0) { 341 rpm = lp->d_rpm; 342 if (rpm <= 0) 343 rpm = 3600; 344 } 345 if (ntracks == 0) { 346 ntracks = lp->d_ntracks; 347 if (ntracks <= 0) 348 fatal("%s: no default #tracks", argv[0]); 349 } 350 if (nsectors == 0) { 351 nsectors = lp->d_nsectors; 352 if (nsectors <= 0) 353 fatal("%s: no default #sectors/track", argv[0]); 354 } 355 if (sectorsize == 0) { 356 sectorsize = lp->d_secsize; 357 if (sectorsize <= 0) 358 fatal("%s: no default sector size", argv[0]); 359 } 360 if (trackskew == -1) { 361 trackskew = lp->d_trackskew; 362 if (trackskew < 0) 363 trackskew = 0; 364 } 365 if (interleave == 0) { 366 interleave = lp->d_interleave; 367 if (interleave <= 0) 368 interleave = 1; 369 } 370 if (fsize == 0) { 371 fsize = pp->p_fsize; 372 if (fsize <= 0) 373 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); 374 } 375 if (bsize == 0) { 376 bsize = pp->p_frag * pp->p_fsize; 377 if (bsize <= 0) 378 bsize = MIN(DFL_BLKSIZE, 8 * fsize); 379 } 380 if (density == 0) 381 density = NFPI * fsize; 382 if (minfree < 10 && opt != FS_OPTSPACE) { 383 fprintf(stderr, "Warning: changing optimization to space "); 384 fprintf(stderr, "because minfree is less than 10%%\n"); 385 opt = FS_OPTSPACE; 386 } 387 if (trackspares == -1) { 388 trackspares = lp->d_sparespertrack; 389 if (trackspares < 0) 390 trackspares = 0; 391 } 392 nphyssectors = nsectors + trackspares; 393 if (cylspares == -1) { 394 cylspares = lp->d_sparespercyl; 395 if (cylspares < 0) 396 cylspares = 0; 397 } 398 secpercyl = nsectors * ntracks - cylspares; 399 if (secpercyl != lp->d_secpercyl) 400 fprintf(stderr, "%s (%d) %s (%lu)\n", 401 "Warning: calculated sectors per cylinder", secpercyl, 402 "disagrees with disk label", lp->d_secpercyl); 403 if (maxbpg == 0) 404 maxbpg = MAXBLKPG(bsize); 405 headswitch = lp->d_headswitch; 406 trackseek = lp->d_trkseek; 407 bbsize = lp->d_bbsize; 408 sbsize = lp->d_sbsize; 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 *getdiskbyname(); 461 462 unlabeled++; 463 return (getdiskbyname(disktype)); 464 } 465 #endif 466 (void)fprintf(stderr, 467 "%s: ioctl (GDINFO): %s\n", progname, strerror(errno)); 468 fatal(lmsg, s); 469 } 470 return (&lab); 471 } 472 473 rewritelabel(s, fd, lp) 474 char *s; 475 int fd; 476 register struct disklabel *lp; 477 { 478 #ifdef COMPAT 479 if (unlabeled) 480 return; 481 #endif 482 lp->d_checksum = 0; 483 lp->d_checksum = dkcksum(lp); 484 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 485 (void)fprintf(stderr, 486 "%s: ioctl (WDINFO): %s\n", progname, strerror(errno)); 487 fatal("%s: can't rewrite disk label", s); 488 } 489 #if vax 490 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 491 register i; 492 int cfd; 493 daddr_t alt; 494 char specname[64]; 495 char blk[1024]; 496 char *cp; 497 498 /* 499 * Make name for 'c' partition. 500 */ 501 strcpy(specname, s); 502 cp = specname + strlen(specname) - 1; 503 if (!isdigit(*cp)) 504 *cp = 'c'; 505 cfd = open(specname, O_WRONLY); 506 if (cfd < 0) 507 fatal("%s: %s", specname, strerror(errno)); 508 bzero(blk, sizeof(blk)); 509 *(struct disklabel *)(blk + LABELOFFSET) = *lp; 510 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 511 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 512 if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize, L_SET) == -1) { 513 fatal("lseek to badsector area: %s", 514 strerror(errno)); 515 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) 516 fprintf(stderr, 517 "%s: alternate label %d write: %s\n", 518 progname, i/2, strerror(errno)); 519 } 520 close(cfd); 521 } 522 #endif 523 } 524 525 /*VARARGS*/ 526 fatal(fmt) 527 char *fmt; 528 { 529 va_list ap; 530 531 fprintf(stderr, "%s: ", progname); 532 va_start(ap, fmt); 533 (void)vfprintf(stderr, fmt, ap); 534 va_end(ap); 535 putc('\n', stderr); 536 exit(1); 537 } 538 539 usage() 540 { 541 if (mfs) { 542 fprintf(stderr, 543 "usage: mfs [ -fsoptions ] special-device mount-point\n"); 544 } else 545 fprintf(stderr, 546 "usage: newfs [ -fsoptions ] special-device%s\n", 547 #ifdef COMPAT 548 " [device-type]"); 549 #else 550 ""); 551 #endif 552 fprintf(stderr, "where fsoptions are:\n"); 553 fprintf(stderr, 554 "\t-N do not create file system, just print out parameters\n"); 555 fprintf(stderr, "\t-S sector size\n"); 556 #ifdef COMPAT 557 fprintf(stderr, "\t-T disktype\n"); 558 #endif 559 fprintf(stderr, "\t-a maximum contiguous blocks\n"); 560 fprintf(stderr, "\t-b block size\n"); 561 fprintf(stderr, "\t-c cylinders/group\n"); 562 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n"); 563 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); 564 fprintf(stderr, "\t-f frag size\n"); 565 fprintf(stderr, "\t-i number of bytes per inode\n"); 566 fprintf(stderr, "\t-k sector 0 skew, per track\n"); 567 fprintf(stderr, "\t-l hardware sector interleave\n"); 568 fprintf(stderr, "\t-m minimum free space %%\n"); 569 fprintf(stderr, "\t-n number of distinguished rotational positions\n"); 570 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); 571 fprintf(stderr, "\t-p spare sectors per track\n"); 572 fprintf(stderr, "\t-s file system size (sectors)\n"); 573 fprintf(stderr, "\t-r revolutions/minute\n"); 574 fprintf(stderr, "\t-t tracks/cylinder\n"); 575 fprintf(stderr, "\t-u sectors/track\n"); 576 fprintf(stderr, "\t-x spare sectors per cylinder\n"); 577 exit(1); 578 } 579