1 /* $NetBSD: make_lfs.c,v 1.61 2026/04/23 16:21:08 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant (at) hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /*- 32 * Copyright (c) 1991, 1993 33 * The Regents of the University of California. All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the University nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 */ 59 60 #include <sys/cdefs.h> 61 #ifndef lint 62 #if 0 63 static char sccsid[] = "@(#)lfs.c 8.5 (Berkeley) 5/24/95"; 64 #else 65 __RCSID("$NetBSD: make_lfs.c,v 1.61 2026/04/23 16:21:08 perseant Exp $"); 66 #endif 67 #endif /* not lint */ 68 69 #include <sys/param.h> 70 #include <sys/disk.h> 71 #include <sys/time.h> 72 #include <sys/mount.h> 73 #include <sys/stat.h> 74 75 /* Override certain things to make <ufs/lfs/lfs.h> work */ 76 # undef simple_lock 77 # define simple_lock(x) 78 # undef simple_unlock 79 # define simple_unlock(x) 80 # define vnode uvnode 81 # define buf ubuf 82 # define panic call_panic 83 #include <ufs/lfs/lfs.h> 84 #include <ufs/lfs/lfs_accessors.h> 85 #include <ufs/lfs/lfs_inode.h> 86 87 #include <err.h> 88 #include <errno.h> 89 #include <stdio.h> 90 #include <stdlib.h> 91 #include <string.h> 92 #include <time.h> 93 #include <unistd.h> 94 95 #include "config.h" 96 #include "extern.h" 97 98 #include "bufcache.h" 99 #include "vnode.h" 100 #include "lfs_user.h" 101 #include "segwrite.h" 102 103 extern int Nflag; /* Don't write anything */ 104 105 static blkcnt_t ifibc; /* How many indirect blocks */ 106 107 #ifdef MAKE_LF_DIR 108 # define HIGHEST_USED_INO LOSTFOUNDINO 109 #else 110 # define HIGHEST_USED_INO ULFS_ROOTINO 111 #endif 112 113 static const struct dlfs dlfs32_default = { 114 .dlfs_magic = LFS_MAGIC, 115 .dlfs_version = LFS_VERSION, 116 .dlfs_size = 0, 117 .dlfs_ssize = DFL_LFSSEG, 118 .dlfs_dsize = 0, 119 .dlfs_bsize = DFL_LFSBLOCK, 120 .dlfs_fsize = DFL_LFSFRAG, 121 .dlfs_frag = DFL_LFSBLOCK/DFL_LFSFRAG, 122 .dlfs_freehd = HIGHEST_USED_INO + 1, 123 .dlfs_bfree = 0, 124 .dlfs_nfiles = 0, 125 .dlfs_avail = 0, 126 .dlfs_uinodes = 0, 127 .dlfs_idaddr = 0, 128 .dlfs_ifile = LFS_IFILE_INUM, 129 .dlfs_lastseg = 0, 130 .dlfs_nextseg = 0, 131 .dlfs_curseg = 0, 132 .dlfs_offset = 0, 133 .dlfs_lastpseg = 0, 134 .dlfs_inopf = 0, 135 .dlfs_minfree = MINFREE, 136 .dlfs_maxfilesize = 0, 137 .dlfs_fsbpseg = 0, 138 .dlfs_inopb = DFL_LFSBLOCK/sizeof(struct lfs32_dinode), 139 .dlfs_ifpb = DFL_LFSBLOCK/sizeof(IFILE32), 140 .dlfs_sepb = DFL_LFSBLOCK/sizeof(SEGUSE), 141 .dlfs_nindir = DFL_LFSBLOCK/sizeof(int32_t), 142 .dlfs_nseg = 0, 143 .dlfs_nspf = 0, 144 .dlfs_cleansz = 0, 145 .dlfs_segtabsz = 0, 146 .dlfs_segmask = DFL_LFSSEG_MASK, 147 .dlfs_segshift = DFL_LFSSEG_SHIFT, 148 .dlfs_bshift = DFL_LFSBLOCK_SHIFT, 149 .dlfs_ffshift = DFL_LFS_FFSHIFT, 150 .dlfs_fbshift = DFL_LFS_FBSHIFT, 151 .dlfs_bmask = DFL_LFSBLOCK_MASK, 152 .dlfs_ffmask = DFL_LFS_FFMASK, 153 .dlfs_fbmask = DFL_LFS_FBMASK, 154 .dlfs_blktodb = 0, 155 .dlfs_sushift = 0, 156 .dlfs_maxsymlinklen = LFS32_MAXSYMLINKLEN, 157 .dlfs_sboffs = { 0 }, 158 .dlfs_nclean = 0, 159 .dlfs_fsmnt = { 0 }, 160 .dlfs_pflags = LFS_PF_CLEAN, 161 .dlfs_dmeta = 0, 162 .dlfs_minfreeseg = 0, 163 .dlfs_sumsize = 0, 164 .dlfs_serial = 0, 165 .dlfs_ibsize = DFL_LFSFRAG, 166 .dlfs_s0addr = 0, 167 .dlfs_tstamp = 0, 168 .dlfs_inodefmt = LFS_44INODEFMT, 169 .dlfs_interleave = 0, 170 .dlfs_ident = 0, 171 .dlfs_fsbtodb = 0, 172 .dlfs_resvseg = 0, 173 174 .dlfs_pad = { 0 }, 175 .dlfs_cksum = 0 176 }; 177 178 static const struct dlfs64 dlfs64_default = { 179 .dlfs_magic = LFS64_MAGIC, 180 .dlfs_version = LFS_VERSION, 181 .dlfs_size = 0, 182 .dlfs_dsize = 0, 183 .dlfs_ssize = DFL_LFSSEG, 184 .dlfs_bsize = DFL_LFSBLOCK, 185 .dlfs_fsize = DFL_LFSFRAG, 186 .dlfs_frag = DFL_LFSBLOCK/DFL_LFSFRAG, 187 .dlfs_freehd = HIGHEST_USED_INO + 1, 188 .dlfs_nfiles = 0, 189 .dlfs_bfree = 0, 190 .dlfs_avail = 0, 191 .dlfs_idaddr = 0, 192 .dlfs_uinodes = 0, 193 .dlfs_unused_0 = 0, 194 .dlfs_lastseg = 0, 195 .dlfs_nextseg = 0, 196 .dlfs_curseg = 0, 197 .dlfs_offset = 0, 198 .dlfs_lastpseg = 0, 199 .dlfs_inopf = 0, 200 .dlfs_minfree = MINFREE, 201 .dlfs_maxfilesize = 0, 202 .dlfs_fsbpseg = 0, 203 .dlfs_inopb = DFL_LFSBLOCK/sizeof(struct lfs64_dinode), 204 .dlfs_ifpb = DFL_LFSBLOCK/sizeof(IFILE64), 205 .dlfs_sepb = DFL_LFSBLOCK/sizeof(SEGUSE), 206 .dlfs_nindir = DFL_LFSBLOCK/sizeof(int64_t), 207 .dlfs_nseg = 0, 208 .dlfs_nspf = 0, 209 .dlfs_cleansz = 0, 210 .dlfs_segtabsz = 0, 211 .dlfs_bshift = DFL_LFSBLOCK_SHIFT, 212 .dlfs_ffshift = DFL_LFS_FFSHIFT, 213 .dlfs_fbshift = DFL_LFS_FBSHIFT, 214 .dlfs_bmask = DFL_LFSBLOCK_MASK, 215 .dlfs_ffmask = DFL_LFS_FFMASK, 216 .dlfs_fbmask = DFL_LFS_FBMASK, 217 .dlfs_blktodb = 0, 218 .dlfs_sushift = 0, 219 .dlfs_sboffs = { 0 }, 220 .dlfs_maxsymlinklen = LFS64_MAXSYMLINKLEN, 221 .dlfs_nclean = 0, 222 .dlfs_fsmnt = { 0 }, 223 .dlfs_pflags = LFS_PF_CLEAN, 224 .dlfs_dmeta = 0, 225 .dlfs_minfreeseg = 0, 226 .dlfs_sumsize = 0, 227 .dlfs_ibsize = DFL_LFSFRAG, 228 .dlfs_inodefmt = LFS_44INODEFMT, 229 .dlfs_serial = 0, 230 .dlfs_s0addr = 0, 231 .dlfs_tstamp = 0, 232 .dlfs_interleave = 0, 233 .dlfs_ident = 0, 234 .dlfs_fsbtodb = 0, 235 .dlfs_resvseg = 0, 236 237 .dlfs_pad = { 0 }, 238 .dlfs_cksum = 0 239 }; 240 241 static const struct lfs lfs_default; 242 243 #define UMASK 0755 244 245 struct dirproto { 246 ino_t dp_ino; 247 const char *dp_name; 248 unsigned dp_type; 249 }; 250 251 static const struct dirproto lfs_root_dir[] = { 252 { ULFS_ROOTINO, ".", LFS_DT_DIR }, 253 { ULFS_ROOTINO, "..", LFS_DT_DIR }, 254 /*{ LFS_IFILE_INUM, "ifile", LFS_DT_REG },*/ 255 #ifdef MAKE_LF_DIR 256 { LOSTFOUNDINO, "lost+found", LFS_DT_DIR }, 257 #endif 258 }; 259 260 #ifdef MAKE_LF_DIR 261 static const struct dirproto lfs_lf_dir[] = { 262 { LOSTFOUNDINO, ".", LFS_DT_DIR }, 263 { ULFS_ROOTINO, "..", LFS_DT_DIR }, 264 }; 265 #endif 266 267 void pwarn(const char *, ...); 268 static void make_dinode(ino_t, union lfs_dinode *, int, struct lfs *); 269 static void make_dir(struct lfs *, void *, 270 const struct dirproto *, unsigned); 271 272 /* 273 * calculate the maximum file size allowed with the specified block shift. 274 */ 275 static uint64_t 276 maxfilesize(struct lfs *fs, int bshift) 277 { 278 uint64_t nptr; /* number of block pointers per block */ 279 uint64_t maxblock; 280 281 nptr = (1 << bshift) / LFS_BLKPTRSIZE(fs); 282 maxblock = ULFS_NDADDR + nptr + nptr * nptr + nptr * nptr * nptr; 283 284 return maxblock << bshift; 285 } 286 287 /* 288 * Create the root directory for this file system and the lost+found 289 * directory. 290 */ 291 static void 292 make_dinode(ino_t ino, union lfs_dinode *dip, int nfrags, struct lfs *fs) 293 { 294 int i; 295 int nblocks, bb, base, factor, lvl; 296 time_t t; 297 298 nblocks = howmany(nfrags, lfs_sb_getfrag(fs)); 299 if (nblocks >= ULFS_NDADDR) 300 nfrags = roundup(nfrags, lfs_sb_getfrag(fs)); 301 302 lfs_dino_setnlink(fs, dip, 1); 303 lfs_dino_setblocks(fs, dip, nfrags); 304 305 lfs_dino_setsize(fs, dip, nfrags << lfs_sb_getffshift(fs)); 306 t = lfs_sb_gettstamp(fs); 307 lfs_dino_setatime(fs, dip, t); 308 lfs_dino_setmtime(fs, dip, t); 309 lfs_dino_setctime(fs, dip, t); 310 lfs_dino_setatimensec(fs, dip, 0); 311 lfs_dino_setmtimensec(fs, dip, 0); 312 lfs_dino_setctimensec(fs, dip, 0); 313 lfs_dino_setinumber(fs, dip, ino); 314 lfs_dino_setgen(fs, dip, 1); 315 316 if (ULFS_NDADDR < nblocks) { 317 /* Count up how many indirect blocks we need, recursively */ 318 /* XXX We are only called with nblocks > 1 for Ifile */ 319 bb = nblocks - ULFS_NDADDR; 320 while (bb > 0) { 321 bb = howmany(bb, LFS_NINDIR(fs)); 322 ifibc += bb; 323 --bb; 324 } 325 lfs_dino_setblocks(fs, dip, 326 lfs_dino_getblocks(fs, dip) + lfs_blkstofrags(fs, ifibc)); 327 } 328 329 /* Assign the block addresses for the ifile */ 330 for (i = 0; i < MIN(nblocks,ULFS_NDADDR); i++) { 331 lfs_dino_setdb(fs, dip, i, 0x0); 332 } 333 if (nblocks > ULFS_NDADDR) { 334 lfs_dino_setib(fs, dip, 0, 0x0); 335 bb = howmany(nblocks - ULFS_NDADDR, LFS_NINDIR(fs)) - 1; 336 factor = LFS_NINDIR(fs); 337 base = -ULFS_NDADDR - factor; 338 lvl = 1; 339 while (bb > 0) { 340 lfs_dino_setib(fs, dip, lvl, 0x0); 341 bb = howmany(bb, LFS_NINDIR(fs)); 342 --bb; 343 factor *= LFS_NINDIR(fs); 344 base -= factor; 345 ++lvl; 346 } 347 } 348 } 349 350 /* 351 * Construct a set of directory entries in "bufp". We assume that all the 352 * entries in protodir fit in the first DIRBLKSIZ. 353 */ 354 static void 355 make_dir(struct lfs *fs, void *bufp, 356 const struct dirproto *protodir, unsigned numentries) 357 { 358 LFS_DIRHEADER *ep; 359 unsigned spaceleft; 360 unsigned namlen, reclen; 361 unsigned i; 362 363 spaceleft = LFS_DIRBLKSIZ; 364 ep = bufp; 365 for (i = 0; i < numentries; i++) { 366 namlen = strlen(protodir[i].dp_name); 367 reclen = LFS_DIRECTSIZ(fs, namlen); 368 if (spaceleft < reclen) 369 fatal("%s: %s", special, "directory too big"); 370 371 /* Last entry includes all the free space. */ 372 if (i + 1 == numentries) { 373 reclen = spaceleft; 374 } 375 spaceleft -= reclen; 376 377 lfs_dir_setino(fs, ep, protodir[i].dp_ino); 378 lfs_dir_setreclen(fs, ep, reclen); 379 lfs_dir_settype(fs, ep, protodir[i].dp_type); 380 lfs_dir_setnamlen(fs, ep, namlen); 381 lfs_copydirname(fs, lfs_dir_nameptr(fs, ep), protodir[i].dp_name, 382 namlen, reclen); 383 ep = LFS_NEXTDIR(fs, ep); 384 } 385 assert(spaceleft == 0); 386 } 387 388 int 389 make_lfs(int devfd, uint secsize, struct dkwedge_info *dkw, int minfree, 390 int block_size, int frag_size, int seg_size, int minfreeseg, 391 int resvseg, int version, daddr_t start, int ibsize, int interleave, 392 u_int32_t roll_id, int bitwidth) 393 { 394 union lfs_dinode *dip; /* Pointer to a disk inode */ 395 CLEANERINFO *cip; /* Segment cleaner information table */ 396 IFILE *ipall; /* Pointer to array of ifile structures */ 397 IFILE64 *ip64 = NULL; 398 IFILE32 *ip32 = NULL; 399 IFILE_V1 *ip_v1 = NULL; 400 struct lfs *fs; /* Superblock */ 401 SEGUSE *segp; /* Segment usage table */ 402 daddr_t sb_addr; /* Address of superblocks */ 403 daddr_t seg_addr; /* Address of current segment */ 404 int bsize; /* Block size */ 405 int fsize; /* Fragment size */ 406 int db_per_blk; /* Disk blocks per file block */ 407 int i, j; 408 int sb_interval; /* number of segs between super blocks */ 409 int ssize; /* Segment size */ 410 double fssize; 411 int warned_segtoobig=0; 412 int label_fsb, sb_fsb; 413 int curw, ww; 414 char tbuf[BUFSIZ]; 415 struct ubuf *bp; 416 struct uvnode *vp, *save_devvp; 417 daddr_t bb, ubb; 418 int dmeta, labelskew; 419 u_int64_t tsepb, tnseg; 420 time_t stamp; 421 bool is64; 422 bool dobyteswap = false; /* XXX notyet */ 423 424 is64 = (bitwidth == 64); 425 426 /* 427 * Initialize buffer cache. Use a ballpark guess of the length of 428 * the segment table for the number of hash chains. 429 */ 430 tnseg = dkw->dkw_size / ((seg_size ? seg_size : DFL_LFSSEG) / secsize); 431 tsepb = (block_size ? block_size : DFL_LFSBLOCK) / sizeof(SEGSUM32); 432 if (tnseg == 0) 433 fatal("zero size partition"); 434 bufinit(tnseg / tsepb); 435 436 /* Initialize LFS subsystem with blank superblock and ifile. */ 437 fs = lfs_init(devfd, start, 0, 1, 1/* XXX debug*/); 438 save_devvp = fs->lfs_devvp; 439 vp = fs->lfs_ivnode; 440 /* XXX this seems like a rubbish */ 441 *fs = lfs_default; 442 if (is64) { 443 fs->lfs_dlfs_u.u_64 = dlfs64_default; 444 } else { 445 fs->lfs_dlfs_u.u_32 = dlfs32_default; 446 } 447 fs->lfs_is64 = is64; 448 fs->lfs_dobyteswap = dobyteswap; 449 fs->lfs_hasolddirfmt = false; 450 fs->lfs_ivnode = vp; 451 fs->lfs_devvp = save_devvp; 452 453 454 /* Set version first of all since it is used to compute other fields */ 455 lfs_sb_setversion(fs, version); 456 457 /* If partition is not an LFS partition, warn that that is the case */ 458 if (strcmp(dkw->dkw_ptype, DKW_PTYPE_LFS) != 0) { 459 fatal("partition label indicated fs type \"%s\", " 460 "expected \"%s\"", dkw->dkw_ptype, DKW_PTYPE_LFS); 461 } 462 463 if (!(bsize = block_size)) { 464 bsize = DFL_LFSBLOCK; 465 if (dkw->dkw_size <= SMALL_FSSIZE) 466 bsize = SMALL_LFSBLOCK; 467 } 468 if (!(fsize = frag_size)) { 469 fsize = DFL_LFSFRAG; 470 if (dkw->dkw_size <= SMALL_FSSIZE) 471 fsize = SMALL_LFSFRAG; 472 } 473 if (!(ssize = seg_size)) { 474 ssize = DFL_LFSSEG; 475 if (dkw->dkw_size <= SMALL_FSSIZE) 476 ssize = SMALL_LFSSEG; 477 } 478 479 /* Sanity check: fsize<=bsize<ssize */ 480 if (fsize > bsize) { 481 /* Only complain if fsize was explicitly set */ 482 if(frag_size) 483 fatal("fragment size must be <= block size %d", bsize); 484 fsize = bsize; 485 } 486 if (bsize >= ssize) { 487 /* Only fatal if ssize was explicitly set */ 488 if(seg_size) 489 fatal("block size must be < segment size"); 490 warnx("%s: disklabel segment size (%d) too small, using default (%d)", 491 progname, ssize, DFL_LFSSEG); 492 ssize = DFL_LFSSEG; 493 } 494 if (start < 0 || start >= dkw->dkw_size) 495 fatal("filesystem offset %ld out of range", (long)start); 496 if (version == 1) { 497 if (start) 498 warnx("filesystem offset ignored for version 1 filesystem"); 499 start = LFS_LABELPAD / secsize; 500 } 501 502 /* Set inode block size according to final fsize/bsize */ 503 if (version > 1) { 504 if (ibsize == 0) 505 ibsize = fsize; 506 if (ibsize <= 0 || ibsize % fsize || ibsize > bsize) 507 fatal("illegal inode block size: %d\n", ibsize); 508 } else { 509 if (ibsize && ibsize != bsize) 510 fatal("cannot specify inode block size when version == 1\n"); 511 ibsize = bsize; 512 } 513 514 tryagain: 515 /* Modify parts of superblock overridden by command line arguments */ 516 if (bsize != DFL_LFSBLOCK || fsize != DFL_LFSFRAG) { 517 lfs_sb_setbshift(fs, lfs_log2(bsize)); 518 if (1 << lfs_sb_getbshift(fs) != bsize) 519 fatal("%d: block size not a power of 2", bsize); 520 lfs_sb_setbsize(fs, bsize); 521 lfs_sb_setfsize(fs, fsize); 522 lfs_sb_setbmask(fs, bsize - 1); 523 lfs_sb_setffmask(fs, fsize - 1); 524 lfs_sb_setffshift(fs, lfs_log2(fsize)); 525 if (1 << lfs_sb_getffshift(fs) != fsize) 526 fatal("%d: frag size not a power of 2", fsize); 527 lfs_sb_setfrag(fs, lfs_numfrags(fs, bsize)); 528 lfs_sb_setfbmask(fs, lfs_sb_getfrag(fs) - 1); 529 lfs_sb_setfbshift(fs, lfs_log2(lfs_sb_getfrag(fs))); 530 lfs_sb_setifpb(fs, bsize / IFILE_ENTRYSIZE(fs)); 531 lfs_sb_setnindir(fs, bsize / LFS_BLKPTRSIZE(fs)); 532 } 533 534 if (lfs_sb_getversion(fs) == 1) { 535 lfs_sb_setsumsize(fs, LFS_V1_SUMMARY_SIZE); 536 if (!is64) { 537 unsigned segshift; 538 539 segshift = lfs_log2(ssize); 540 if (1 << segshift != ssize) 541 fatal("%d: segment size not power of 2", 542 ssize); 543 fs->lfs_dlfs_u.u_32.dlfs_segshift = segshift; 544 fs->lfs_dlfs_u.u_32.dlfs_segmask = ssize - 1; 545 } 546 lfs_sb_setifpb(fs, lfs_sb_getbsize(fs) / sizeof(IFILE_V1)); 547 lfs_sb_setibsize(fs, lfs_sb_getbsize(fs)); 548 lfs_sb_setsepb(fs, bsize / sizeof(SEGUSE_V1)); 549 lfs_sb_setssize(fs, ssize >> lfs_sb_getbshift(fs)); 550 } else { 551 if (ssize % fsize) { 552 fprintf(stderr, 553 "Segment size %d is not a multiple of frag size; ", 554 ssize); 555 ssize = roundup(ssize, fsize); 556 fprintf(stderr, "trying size %d.\n", ssize); 557 goto tryagain; 558 } 559 lfs_sb_setsumsize(fs, fsize); 560 if (!is64) { 561 /* these do not exist in the 64-bit superblock */ 562 fs->lfs_dlfs_u.u_32.dlfs_segshift = 0; 563 fs->lfs_dlfs_u.u_32.dlfs_segmask = 0; 564 } 565 lfs_sb_setsepb(fs, bsize / sizeof(SEGUSE)); 566 lfs_sb_setssize(fs, ssize); 567 lfs_sb_setibsize(fs, ibsize); 568 } 569 lfs_sb_setinopb(fs, lfs_sb_getibsize(fs) / DINOSIZE(fs)); 570 lfs_sb_setminfree(fs, minfree); 571 572 if (version > 1) { 573 lfs_sb_setinopf(fs, secsize/DINOSIZE(fs)); 574 lfs_sb_setinterleave(fs, interleave); 575 if (roll_id == 0) 576 roll_id = arc4random(); 577 lfs_sb_setident(fs, roll_id); 578 } 579 580 /* 581 * Fill in parts of superblock that can be computed from file system 582 * size, disk geometry and current time. 583 * 584 * XXX: this seems to set dlfs_size wrong for version 1... as in, 585 * sets it and then overwrites it a few lines later. 586 */ 587 db_per_blk = bsize/secsize; 588 lfs_sb_setblktodb(fs, lfs_log2(db_per_blk)); 589 lfs_sb_setfsbtodb(fs, lfs_log2(fsize / secsize)); 590 if (version == 1) { 591 lfs_sb_setsushift(fs, lfs_log2(lfs_sb_getsepb(fs))); 592 lfs_sb_setfsbtodb(fs, 0); 593 lfs_sb_setsize(fs, dkw->dkw_size >> lfs_sb_getblktodb(fs)); 594 } 595 label_fsb = lfs_btofsb(fs, roundup(LFS_LABELPAD, fsize)); 596 sb_fsb = lfs_btofsb(fs, roundup(LFS_SBPAD, fsize)); 597 lfs_sb_setfsbpseg(fs, LFS_DBTOFSB(fs, ssize / secsize)); 598 lfs_sb_setsize(fs, dkw->dkw_size >> lfs_sb_getfsbtodb(fs)); 599 lfs_sb_setdsize(fs, LFS_DBTOFSB(fs, dkw->dkw_size) - 600 MAX(label_fsb, LFS_DBTOFSB(fs, start))); 601 lfs_sb_setnseg(fs, lfs_sb_getdsize(fs) / lfs_segtod(fs, 1)); 602 603 lfs_sb_setnclean(fs, lfs_sb_getnseg(fs) - 1); 604 lfs_sb_setmaxfilesize(fs, maxfilesize(fs, lfs_sb_getbshift(fs))); 605 606 if (minfreeseg == 0) 607 lfs_sb_setminfreeseg(fs, lfs_sb_getnseg(fs) / DFL_MIN_FREE_SEGS); 608 else 609 lfs_sb_setminfreeseg(fs, minfreeseg); 610 if (lfs_sb_getminfreeseg(fs) < MIN_FREE_SEGS) 611 lfs_sb_setminfreeseg(fs, MIN_FREE_SEGS); 612 613 if (resvseg == 0) 614 lfs_sb_setresvseg(fs, lfs_sb_getminfreeseg(fs) / 2 + 1); 615 else 616 lfs_sb_setresvseg(fs, resvseg); 617 if (lfs_sb_getresvseg(fs) < MIN_RESV_SEGS) 618 lfs_sb_setresvseg(fs, MIN_RESV_SEGS); 619 620 if(lfs_sb_getnseg(fs) < (4 * lfs_sb_getminfreeseg(fs)) 621 || lfs_sb_getnseg(fs) < LFS_MIN_SBINTERVAL + 1) 622 { 623 if(seg_size == 0 && ssize > (bsize<<1)) { 624 if(!warned_segtoobig) { 625 fprintf(stderr,"Segment size %d is too large; " 626 "trying smaller sizes.\n", ssize); 627 if (ssize == (bsize << 16)) { 628 fprintf(stderr, "(Did you perhaps " 629 "accidentally leave \"16\" " 630 "in the disklabel's sgs " 631 "field?)\n"); 632 } 633 } 634 ++warned_segtoobig; 635 ssize >>= 1; 636 goto tryagain; 637 } 638 fatal("Could not allocate enough segments with segment " 639 "size %d and block size %d;\nplease decrease the " 640 "segment size.\n", ssize, lfs_sb_getbsize(fs)); 641 } 642 if(warned_segtoobig) 643 fprintf(stderr,"Using segment size %d, block size %d, frag size %d.\n", ssize, bsize, fsize); 644 645 /* 646 * Now that we've determined what we're going to do, announce it 647 * to the user. 648 */ 649 printf("Creating a version %d LFS%d", lfs_sb_getversion(fs), bitwidth); 650 if (lfs_sb_getversion(fs) > 1) 651 printf(" with roll-forward ident 0x%x", lfs_sb_getident(fs)); 652 printf("\n"); 653 if (bitwidth == 64) { 654 printf("WARNING: The LFS64 on-disk format is not final.\n"); 655 printf("WARNING: 64-bit volumes should be used only for " 656 "testing.\n"); 657 } 658 fssize = (double)lfs_sb_getnseg(fs); 659 fssize *= (double)ssize; 660 fssize /= 1048576.0; 661 printf("%.1fMB in %d segments of size %d\n", fssize, 662 lfs_sb_getnseg(fs), ssize); 663 664 /* 665 * The number of free blocks is set from the number of segments 666 * times the segment size - lfs_minfreesegs (that we never write 667 * because we need to make sure the cleaner can run). Then 668 * we'll subtract off the room for the superblocks ifile entries 669 * and segment usage table, and half a block per segment that can't 670 * be written due to fragmentation. 671 */ 672 lfs_sb_setdsize(fs, 673 lfs_segtod(fs, lfs_sb_getnseg(fs) - lfs_sb_getminfreeseg(fs))); 674 lfs_sb_setbfree(fs, lfs_sb_getdsize(fs)); 675 lfs_sb_subbfree(fs, LFS_DBTOFSB(fs, ((lfs_sb_getnseg(fs) / 2) << 676 lfs_sb_getblktodb(fs)))); 677 678 lfs_sb_setsegtabsz(fs, SEGTABSIZE_SU(fs)); 679 lfs_sb_setcleansz(fs, CLEANSIZE_SU(fs)); 680 if (time(&stamp) == -1) 681 fatal("time: %s", strerror(errno)); 682 lfs_sb_settstamp(fs, stamp); 683 if (version == 1) 684 lfs_sb_setotstamp(fs, stamp); 685 686 if ((sb_interval = lfs_sb_getnseg(fs) / LFS_MAXNUMSB) < LFS_MIN_SBINTERVAL) 687 sb_interval = LFS_MIN_SBINTERVAL; 688 689 /* 690 * Figure out where the superblocks are going to live. 691 * 692 * Make segment 0 start at either zero, or LFS_LABELPAD, or 693 * >= LFS_SBPAD+LFS_LABELPAD, in order to prevent segment 0 694 * from having half a superblock in it. 695 */ 696 if (LFS_FSBTODB(fs, LFS_DBTOFSB(fs, start)) != start) 697 fatal("Segment 0 offset is not multiple of frag size\n"); 698 if (start != 0 && dbtob(start) != LFS_LABELPAD && 699 dbtob(start) < LFS_SBPAD + LFS_LABELPAD) { 700 fatal("Using flags \"-O %" PRId64 "\" would result in the " 701 "first segment containing only\npart of a superblock. " 702 "Please choose an offset of 0, %d, or %d or more,\n", 703 start, btodb(LFS_LABELPAD), 704 btodb(LFS_LABELPAD + LFS_SBPAD)); 705 } 706 lfs_sb_setsboff(fs, 0, label_fsb); 707 if (version == 1) 708 lfs_sb_sets0addr(fs, lfs_sb_getsboff(fs, 0)); 709 else 710 lfs_sb_sets0addr(fs, LFS_DBTOFSB(fs, start)); 711 lfs_sb_subdsize(fs, sb_fsb); 712 for (i = 1; i < LFS_MAXNUMSB; i++) { 713 sb_addr = ((i * sb_interval) * lfs_segtod(fs, 1)) 714 + lfs_sb_getsboff(fs, 0); 715 /* Segment 0 eats the label, except for version 1 */ 716 if (lfs_sb_getversion(fs) > 1 && lfs_sb_gets0addr(fs) < label_fsb) 717 sb_addr -= label_fsb - start; 718 if (sb_addr + sizeof(struct dlfs) 719 >= LFS_DBTOFSB(fs, dkw->dkw_size)) 720 break; 721 lfs_sb_setsboff(fs, i, sb_addr); 722 lfs_sb_subdsize(fs, sb_fsb); 723 } 724 725 /* We need >= 2 superblocks */ 726 if (lfs_sb_getsboff(fs, 1) == 0x0) { 727 fatal("Could not assign a disk address for the second " 728 "superblock.\nPlease decrease the segment size.\n"); 729 } 730 731 lfs_sb_setlastseg(fs, lfs_sntod(fs, lfs_sb_getnseg(fs) - 2)); 732 lfs_sb_setcurseg(fs, lfs_sntod(fs, lfs_sb_getnseg(fs) - 1)); 733 lfs_sb_setoffset(fs, lfs_sntod(fs, lfs_sb_getnseg(fs))); 734 lfs_sb_setnextseg(fs, lfs_sntod(fs, 0)); 735 736 /* 737 * Initialize the Ifile inode. Do this before we do anything 738 * with the Ifile or segment tables. 739 * 740 * XXX: is there some reason this allocates a new dinode? we 741 * already have an empty one generated by vget. 742 */ 743 dip = malloc(sizeof(*dip)); 744 if (dip == NULL) 745 err(1, NULL); 746 memset(dip, 0, sizeof(*dip)); 747 748 VTOI(fs->lfs_ivnode)->i_din = dip; 749 750 lfs_dino_setmode(fs, dip, LFS_IFREG | 0600); 751 lfs_dino_setflags(fs, dip, SF_IMMUTABLE); 752 make_dinode(LFS_IFILE_INUM, dip, 753 lfs_blkstofrags(fs, lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs) + 1), fs); 754 lfs_dino_setsize(fs, dip, (lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs) + 1) << lfs_sb_getbshift(fs)); 755 for (i = 0; i < ULFS_NDADDR && i < (lfs_dino_getsize(fs, dip) >> lfs_sb_getbshift(fs)); i++) 756 VTOI(fs->lfs_ivnode)->i_lfs_fragsize[i] = lfs_sb_getbsize(fs); 757 758 /* 759 * Initialize the cleanerinfo block 760 */ 761 LFS_CLEANERINFO(cip, fs, bp); 762 lfs_ci_setclean(fs, cip, lfs_sb_getnseg(fs)); 763 lfs_ci_setdirty(fs, cip, 0); 764 if (version > 1) { 765 lfs_ci_setfree_head(fs, cip, HIGHEST_USED_INO + 1); 766 lfs_ci_setfree_tail(fs, cip, lfs_sb_getifpb(fs) - 1); 767 } 768 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 769 770 /* 771 * Run through segment table and initialize that 772 */ 773 for (i = j = 0; i < lfs_sb_getnseg(fs); i++) { 774 LFS_SEGENTRY(segp, fs, i, bp); 775 776 if (i == 0 && 777 lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD + LFS_SBPAD)) { 778 segp->su_flags = SEGUSE_SUPERBLOCK; 779 lfs_sb_subbfree(fs, sb_fsb); 780 ++j; 781 } 782 if (i > 0) { 783 if ((i % sb_interval) == 0 && j < LFS_MAXNUMSB) { 784 segp->su_flags = SEGUSE_SUPERBLOCK; 785 lfs_sb_subbfree(fs, sb_fsb); 786 ++j; 787 } else 788 segp->su_flags = 0; 789 } 790 segp->su_lastmod = 0; 791 segp->su_nbytes = 0; 792 segp->su_ninos = 0; 793 segp->su_nsums = 0; 794 795 LFS_WRITESEGENTRY(segp, fs, i, bp); 796 } 797 798 /* Initialize root directory */ 799 vp = lfs_raw_vget(fs, ULFS_ROOTINO, devfd, 0x0); 800 dip = VTOI(vp)->i_din; 801 make_dinode(ULFS_ROOTINO, dip, howmany(LFS_DIRBLKSIZ, lfs_sb_getfsize(fs)), fs); 802 lfs_dino_setmode(fs, dip, LFS_IFDIR | UMASK); 803 VTOI(vp)->i_lfs_osize = LFS_DIRBLKSIZ; 804 #ifdef MAKE_LF_DIR 805 VTOI(vp)->i_nlink = 3; 806 #else 807 VTOI(vp)->i_nlink = 2; 808 #endif 809 VTOI(vp)->i_lfs_effnblks = 810 lfs_btofsb(fs, roundup(LFS_DIRBLKSIZ, lfs_sb_getfsize(fs))); 811 lfs_dino_setsize(fs, dip, VTOI(vp)->i_lfs_osize); 812 lfs_dino_setnlink(fs, dip, VTOI(vp)->i_nlink); 813 lfs_dino_setblocks(fs, dip, VTOI(vp)->i_lfs_effnblks); 814 for (i = 0; i < ULFS_NDADDR && i < howmany(LFS_DIRBLKSIZ, lfs_sb_getbsize(fs)); i++) 815 VTOI(vp)->i_lfs_fragsize[i] = lfs_sb_getbsize(fs); 816 if (LFS_DIRBLKSIZ < lfs_sb_getbsize(fs)) 817 VTOI(vp)->i_lfs_fragsize[i - 1] = 818 roundup(LFS_DIRBLKSIZ, lfs_sb_getfsize(fs)); 819 bread(vp, 0, lfs_sb_getfsize(fs), 0, &bp); 820 make_dir(fs, bp->b_data, lfs_root_dir, __arraycount(lfs_root_dir)); 821 VOP_BWRITE(bp); 822 823 #ifdef MAKE_LF_DIR 824 /* Initialize lost+found directory */ 825 vp = lfs_raw_vget(fs, LOSTFOUNDINO, devfd, 0x0); 826 dip = VTOI(vp)->i_din.ffs1_din; 827 make_dinode(LOSTFOUNDINO, dip, howmany(DIRBLKSIZ,fs->lfs_fsize), fs); 828 dip->di_mode = IFDIR | UMASK; 829 VTOI(vp)->i_lfs_osize = dip->di_size = DIRBLKSIZ; 830 VTOI(vp)->i_nlink = dip->di_nlink = 2; 831 VTOI(vp)->i_lfs_effnblks = dip->di_blocks = 832 lfs_btofsb(fs, roundup(DIRBLKSIZ,fs->lfs_fsize)); 833 for (i = 0; i < ULFS_NDADDR && i < howmany(DIRBLKSIZ, lfs_sb_getbsize(fs)); i++) 834 VTOI(vp)->i_lfs_fragsize[i] = lfs_sb_getbsize(fs); 835 if (DIRBLKSIZ < lfs_sb_getbsize(fs)) 836 VTOI(vp)->i_lfs_fragsize[i - 1] = 837 roundup(DIRBLKSIZ,fs->lfs_fsize); 838 bread(vp, 0, fs->lfs_fsize, 0, &bp); 839 make_dir(fs, bp->b_data, lfs_lf_dir, __arraycount(lfs_lf_dir)); 840 VOP_BWRITE(bp); 841 #endif /* MAKE_LF_DIR */ 842 843 /* Set their IFILE entry version numbers to 1 */ 844 LFS_IENTRY(ipall, fs, 1, bp); 845 if (is64) { 846 ip64 = &ipall->u_64; 847 for (i = LFS_IFILE_INUM; i <= HIGHEST_USED_INO; i++) { 848 ip64->if_version = 1; 849 ip64->if_daddr = 0x0; 850 ip64->if_nextfree = 0; 851 ++ip64; 852 } 853 } else if (version > 1) { 854 ip32 = &ipall->u_32; 855 for (i = LFS_IFILE_INUM; i <= HIGHEST_USED_INO; i++) { 856 ip32->if_version = 1; 857 ip32->if_daddr = 0x0; 858 ip32->if_nextfree = 0; 859 ++ip32; 860 } 861 } else { 862 ip_v1 = &ipall->u_v1; 863 for (i = LFS_IFILE_INUM; i <= HIGHEST_USED_INO; i++) { 864 ip_v1->if_version = 1; 865 ip_v1->if_daddr = 0x0; 866 ip_v1->if_nextfree = 0; 867 ++ip_v1; 868 } 869 } 870 /* Link remaining IFILE entries in free list */ 871 if (is64) { 872 for (; 873 i < lfs_sb_getifpb(fs); ++ip64) { 874 ip64->if_version = 1; 875 ip64->if_daddr = LFS_UNUSED_DADDR; 876 ip64->if_nextfree = ++i; 877 } 878 --ip64; 879 ip64->if_nextfree = LFS_UNUSED_INUM; 880 } else if (version > 1) { 881 for (; 882 i < lfs_sb_getifpb(fs); ++ip32) { 883 ip32->if_version = 1; 884 ip32->if_daddr = LFS_UNUSED_DADDR; 885 ip32->if_nextfree = ++i; 886 } 887 --ip32; 888 ip32->if_nextfree = LFS_UNUSED_INUM; 889 } else { 890 for (; 891 i < lfs_sb_getifpb(fs); ++ip_v1) { 892 ip_v1->if_version = 1; 893 ip_v1->if_daddr = LFS_UNUSED_DADDR; 894 ip_v1->if_nextfree = ++i; 895 } 896 --ip_v1; 897 ip_v1->if_nextfree = LFS_UNUSED_INUM; 898 } 899 VOP_BWRITE(bp); 900 901 /* Write it all to disk. */ 902 if (!Nflag) 903 lfs_segwrite(fs, SEGM_CKP); 904 905 /* 906 * Now that we've written everything, look to see what's available 907 * for writing. 908 */ 909 lfs_sb_setavail(fs, 0); 910 bb = ubb = dmeta = 0; 911 for (i = 0; i < lfs_sb_getnseg(fs); i++) { 912 LFS_SEGENTRY(segp, fs, i, bp); 913 if (segp->su_flags & SEGUSE_DIRTY) { 914 bb += lfs_btofsb(fs, segp->su_nbytes + 915 segp->su_nsums * lfs_sb_getsumsize(fs)); 916 ubb += lfs_btofsb(fs, segp->su_nbytes + 917 segp->su_nsums * lfs_sb_getsumsize(fs) + 918 segp->su_ninos * lfs_sb_getibsize(fs)); 919 dmeta += lfs_btofsb(fs, 920 lfs_sb_getsumsize(fs) * segp->su_nsums); 921 dmeta += lfs_btofsb(fs, 922 lfs_sb_getibsize(fs) * segp->su_ninos); 923 } else { 924 lfs_sb_addavail(fs, lfs_segtod(fs, 1)); 925 if (segp->su_flags & SEGUSE_SUPERBLOCK) 926 lfs_sb_subavail(fs, lfs_btofsb(fs, LFS_SBPAD)); 927 if (i == 0 && lfs_sb_getversion(fs) > 1 && 928 lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD)) 929 lfs_sb_subavail(fs, lfs_btofsb(fs, LFS_LABELPAD) - 930 lfs_sb_gets0addr(fs)); 931 } 932 brelse(bp, 0); 933 } 934 /* Also may be available bytes in current seg */ 935 i = lfs_dtosn(fs, lfs_sb_getoffset(fs)); 936 lfs_sb_addavail(fs, lfs_sntod(fs, i + 1) - lfs_sb_getoffset(fs)); 937 /* But do not count minfreesegs */ 938 lfs_sb_subavail(fs, lfs_segtod(fs, (lfs_sb_getminfreeseg(fs) - (lfs_sb_getminfreeseg(fs) / 2)))); 939 940 labelskew = 0; 941 if (lfs_sb_getversion(fs) > 1 && lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD)) 942 labelskew = lfs_btofsb(fs, LFS_LABELPAD); 943 lfs_sb_setbfree(fs, lfs_sb_getdsize(fs) - labelskew - (ubb + bb) / 2); 944 945 /* Put that in the Ifile version too, and write it */ 946 LFS_CLEANERINFO(cip, fs, bp); 947 lfs_ci_setbfree(fs, cip, lfs_sb_getbfree(fs)); 948 lfs_ci_setavail(fs, cip, lfs_sb_getavail(fs)); 949 LFS_SYNC_CLEANERINFO(cip, fs, bp, 1); 950 if (!Nflag) 951 lfs_segwrite(fs, SEGM_CKP); 952 953 /* 954 * Finally write out superblocks. 955 */ 956 printf("super-block backups (for fsck -b #) at:\n"); 957 curw = 0; 958 for (i = 0; i < LFS_MAXNUMSB; i++) { 959 seg_addr = lfs_sb_getsboff(fs, i); 960 if (seg_addr == 0) 961 break; 962 963 if (i != 0) 964 curw += printf(", "); 965 ww = snprintf(tbuf, sizeof(tbuf), "%lld", 966 (long long)LFS_FSBTODB(fs, seg_addr)); 967 curw += ww; 968 if (curw >= 78) { 969 printf("\n%s", tbuf); 970 curw = ww; 971 } else 972 printf("%s", tbuf); 973 fflush(stdout); 974 975 /* Leave the time stamp on the alt sb, zero the rest */ 976 if (i == 2) { 977 lfs_sb_settstamp(fs, 0); 978 lfs_sb_setcksum(fs, lfs_sb_cksum(fs)); 979 } 980 if (!Nflag) 981 lfs_writesuper(fs, seg_addr); 982 } 983 printf(".\n"); 984 985 return 0; 986 } 987 988 /* 989 * Compatibility with fsck_lfs, since the "generic" LFS userland code uses it. 990 */ 991 void 992 pwarn(const char *fmt, ...) 993 { 994 va_list ap; 995 996 va_start(ap, fmt); 997 vfprintf(stderr, fmt, ap); 998 va_end(ap); 999 } 1000