1 /*- 2 * Copyright (c) 1991 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[] = "@(#)lfs.c 5.16 (Berkeley) 07/23/92"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/uio.h> 14 #include <sys/disklabel.h> 15 #include <sys/time.h> 16 #include <sys/resource.h> 17 #include <sys/proc.h> 18 #include <sys/vnode.h> 19 #include <sys/mount.h> 20 21 #include <ufs/ufs/dir.h> 22 #include <ufs/ufs/quota.h> 23 #include <ufs/ufs/dinode.h> 24 #include <ufs/ufs/ufsmount.h> 25 #include <ufs/lfs/lfs.h> 26 27 #include <unistd.h> 28 #include <errno.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include "config.h" 32 #include "extern.h" 33 34 /* 35 * This table is indexed by the log base 2 of the block size. 36 * It returns the maximum file size allowed in a file system 37 * with the specified block size. For block sizes smaller than 38 * 8K, the size is limited by tha maximum number of blocks that 39 * can be reached by triply indirect blocks: 40 * NDADDR + INOPB(bsize) + INOPB(bsize)^2 + INOPB(bsize)^3 41 * For block size of 8K or larger, the file size is limited by the 42 * number of blocks that can be represented in the file system. Since 43 * we use negative block numbers to represent indirect blocks, we can 44 * have a maximum of 2^31 blocks. 45 */ 46 47 u_quad_t maxtable[] = { 48 /* 1 */ -1, 49 /* 2 */ -1, 50 /* 4 */ -1, 51 /* 8 */ -1, 52 /* 16 */ -1, 53 /* 32 */ -1, 54 /* 64 */ -1, 55 /* 128 */ -1, 56 /* 256 */ -1, 57 /* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128, 58 /* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256, 59 /* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512, 60 /* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024, 61 /* 8192 */ 2 ^ 31, 62 /* 16 K */ 2 ^ 31, 63 /* 32 K */ 2 ^ 31 64 }; 65 66 static struct lfs lfs_default = { 67 /* lfs_magic */ LFS_MAGIC, 68 /* lfs_version */ LFS_VERSION, 69 /* lfs_size */ 0, 70 /* lfs_ssize */ DFL_LFSSEG/DFL_LFSBLOCK, 71 /* lfs_dsize */ 0, 72 /* lfs_bsize */ DFL_LFSBLOCK, 73 /* lfs_fsize */ DFL_LFSBLOCK, 74 /* lfs_frag */ 1, 75 /* lfs_free */ LFS_FIRST_INUM, 76 /* lfs_bfree */ 0, 77 /* lfs_nfiles */ 0, 78 /* lfs_idaddr */ 0, 79 /* lfs_ifile */ LFS_IFILE_INUM, 80 /* lfs_lastseg */ 0, 81 /* lfs_nextseg */ 0, 82 /* lfs_curseg */ 0, 83 /* lfs_offset */ 0, 84 /* lfs_lastpseg */ 0, 85 /* lfs_tstamp */ 0, 86 /* lfs_minfree */ MINFREE, 87 /* lfs_maxfilesize */ 0, 88 /* lfs_dbpseg */ DFL_LFSSEG/DEV_BSIZE, 89 /* lfs_inopb */ DFL_LFSBLOCK/sizeof(struct dinode), 90 /* lfs_ifpb */ DFL_LFSBLOCK/sizeof(IFILE), 91 /* lfs_sepb */ DFL_LFSBLOCK/sizeof(SEGUSE), 92 /* lfs_nindir */ DFL_LFSBLOCK/sizeof(daddr_t), 93 /* lfs_nseg */ 0, 94 /* lfs_nspf */ 0, 95 /* lfs_cleansz */ 0, 96 /* lfs_segtabsz */ 0, 97 /* lfs_segmask */ DFL_LFSSEG_MASK, 98 /* lfs_segshift */ DFL_LFSSEG_SHIFT, 99 /* lfs_bmask */ DFL_LFSBLOCK_MASK, 100 /* lfs_bshift */ DFL_LFSBLOCK_SHIFT, 101 /* lfs_ffmask */ 0, 102 /* lfs_ffshift */ 0, 103 /* lfs_fbmask */ 0, 104 /* lfs_fbshift */ 0, 105 /* lfs_fsbtodb */ 0, 106 /* lfs_sushift */ 0, 107 /* lfs_sboffs */ { 0 }, 108 /* lfs_ivnode */ NULL, 109 /* lfs_seglock */ 0, 110 /* lfs_iocount */ 0, 111 /* lfs_writer */ 0, 112 /* lfs_dirops */ 0, 113 /* lfs_doifile */ 0, 114 /* lfs_fmod */ 0, 115 /* lfs_clean */ 0, 116 /* lfs_ronly */ 0, 117 /* lfs_flags */ 0, 118 /* lfs_fsmnt */ { 0 }, 119 /* lfs_pad */ { 0 }, 120 /* lfs_cksum */ 0 121 }; 122 123 124 struct direct lfs_root_dir[] = { 125 { ROOTINO, sizeof(struct direct), DT_DIR, 1, "."}, 126 { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".."}, 127 { LFS_IFILE_INUM, sizeof(struct direct), DT_REG, 5, "ifile"}, 128 { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found"}, 129 }; 130 131 struct direct lfs_lf_dir[] = { 132 { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." }, 133 { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 134 }; 135 136 static daddr_t make_dinode 137 __P((ino_t, struct dinode *, int, daddr_t, struct lfs *)); 138 static void make_dir __P(( void *, struct direct *, int)); 139 static void put __P((int, off_t, void *, size_t)); 140 141 int 142 make_lfs(fd, lp, partp, minfree, block_size, seg_size) 143 int fd; 144 struct disklabel *lp; 145 struct partition *partp; 146 int minfree; 147 int block_size; 148 int seg_size; 149 { 150 struct dinode *dip; /* Pointer to a disk inode */ 151 struct dinode *dpagep; /* Pointer to page of disk inodes */ 152 CLEANERINFO *cleaninfo; /* Segment cleaner information table */ 153 FINFO file_info; /* File info structure in summary blocks */ 154 IFILE *ifile; /* Pointer to array of ifile structures */ 155 IFILE *ip; /* Pointer to array of ifile structures */ 156 struct lfs *lfsp; /* Superblock */ 157 SEGUSE *segp; /* Segment usage table */ 158 SEGUSE *segtable; /* Segment usage table */ 159 SEGSUM summary; /* Segment summary structure */ 160 SEGSUM *sp; /* Segment summary pointer */ 161 daddr_t last_sb_addr; /* Address of superblocks */ 162 daddr_t last_addr; /* Previous segment address */ 163 daddr_t sb_addr; /* Address of superblocks */ 164 daddr_t seg_addr; /* Address of current segment */ 165 void *ipagep; /* Pointer to the page we use to write stuff */ 166 void *sump; /* Used to copy stuff into segment buffer */ 167 u_long *block_array; /* Array of logical block nos to put in sum */ 168 u_long blocks_used; /* Number of blocks in first segment */ 169 u_long *dp; /* Used to computed checksum on data */ 170 u_long *datasump; /* Used to computed checksum on data */ 171 int block_array_size; /* How many entries in block array */ 172 int bsize; /* Block size */ 173 int db_per_fb; /* Disk blocks per file block */ 174 int i, j; 175 int off; /* Offset at which to write */ 176 int sb_interval; /* number of segs between super blocks */ 177 int seg_seek; /* Seek offset for a segment */ 178 int ssize; /* Segment size */ 179 int sum_size; /* Size of the summary block */ 180 181 lfsp = &lfs_default; 182 183 if (!(bsize = block_size)) 184 bsize = DFL_LFSBLOCK; 185 if (!(ssize = seg_size)) 186 ssize = DFL_LFSSEG; 187 188 /* Modify parts of superblock overridden by command line arguments */ 189 if (bsize != DFL_LFSBLOCK) { 190 lfsp->lfs_bshift = log2(bsize); 191 if (1 << lfsp->lfs_bshift != bsize) 192 fatal("%d: block size not a power of 2", bsize); 193 lfsp->lfs_bsize = bsize; 194 lfsp->lfs_fsize = bsize; 195 lfsp->lfs_bmask = bsize - 1; 196 lfsp->lfs_inopb = bsize / sizeof(struct dinode); 197 /* MIS -- should I round to power of 2 */ 198 lfsp->lfs_ifpb = bsize / sizeof(IFILE); 199 lfsp->lfs_sepb = bsize / sizeof(SEGUSE); 200 lfsp->lfs_nindir = bsize / sizeof(daddr_t); 201 } 202 203 if (ssize != DFL_LFSSEG) { 204 lfsp->lfs_segshift = log2(ssize); 205 if (1 << lfsp->lfs_segshift != ssize) 206 fatal("%d: segment size not power of 2", ssize); 207 lfsp->lfs_ssize = ssize; 208 lfsp->lfs_segmask = ssize - 1; 209 } 210 lfsp->lfs_ssize = ssize >> lfsp->lfs_bshift; 211 212 if (minfree) 213 lfsp->lfs_minfree = minfree; 214 215 /* 216 * Fill in parts of superblock that can be computed from file system 217 * size, disk geometry and current time. 218 */ 219 db_per_fb = bsize/lp->d_secsize; 220 lfsp->lfs_fsbtodb = log2(db_per_fb); 221 lfsp->lfs_sushift = log2(lfsp->lfs_sepb); 222 lfsp->lfs_size = partp->p_size >> lfsp->lfs_fsbtodb; 223 lfsp->lfs_dsize = lfsp->lfs_size - (LFS_LABELPAD >> lfsp->lfs_bshift); 224 lfsp->lfs_nseg = lfsp->lfs_dsize / lfsp->lfs_ssize; 225 lfsp->lfs_maxfilesize = maxtable[lfsp->lfs_bshift] << lfsp->lfs_bshift; 226 227 /* 228 * The number of free blocks is set from the total data size (lfs_dsize) 229 * minus one sector for each segment (for the segment summary). Then 230 * we'll subtract off the room for the superblocks, ifile entries and 231 * segment usage table. 232 */ 233 lfsp->lfs_bfree = lfsp->lfs_dsize * db_per_fb - lfsp->lfs_nseg; 234 lfsp->lfs_segtabsz = SEGTABSIZE_SU(lfsp); 235 lfsp->lfs_cleansz = CLEANSIZE_SU(lfsp); 236 if ((lfsp->lfs_tstamp = time(NULL)) == -1) 237 fatal("time: %s", strerror(errno)); 238 if ((sb_interval = lfsp->lfs_nseg / LFS_MAXNUMSB) < LFS_MIN_SBINTERVAL) 239 sb_interval = LFS_MIN_SBINTERVAL; 240 241 /* 242 * Now, lay out the file system. We need to figure out where 243 * the superblocks go, initialize the checkpoint information 244 * for the first two superblocks, initialize the segment usage 245 * information, put the segusage information in the ifile, create 246 * the first block of IFILE structures, and link all the IFILE 247 * structures into a free list. 248 */ 249 250 /* Figure out where the superblocks are going to live */ 251 lfsp->lfs_sboffs[0] = LFS_LABELPAD/lp->d_secsize; 252 for (i = 1; i < LFS_MAXNUMSB; i++) { 253 sb_addr = ((i * sb_interval) << 254 (lfsp->lfs_segshift - lfsp->lfs_bshift + lfsp->lfs_fsbtodb)) 255 + lfsp->lfs_sboffs[0]; 256 if (sb_addr > partp->p_size) 257 break; 258 lfsp->lfs_sboffs[i] = sb_addr; 259 } 260 last_sb_addr = lfsp->lfs_sboffs[i - 1]; 261 lfsp->lfs_lastseg = lfsp->lfs_sboffs[0]; 262 lfsp->lfs_nextseg = 263 lfsp->lfs_sboffs[1] ? lfsp->lfs_sboffs[1] : lfsp->lfs_sboffs[0]; 264 lfsp->lfs_curseg = lfsp->lfs_lastseg; 265 266 /* 267 * Initialize the segment usage table. The first segment will 268 * contain the superblock, the cleanerinfo (cleansz), the segusage 269 * table * (segtabsz), 1 block's worth of IFILE entries, the root 270 * directory, the lost+found directory and one block's worth of 271 * inodes (containing the ifile, root, and l+f inodes). 272 */ 273 if (!(cleaninfo = malloc(lfsp->lfs_cleansz << lfsp->lfs_bshift))) 274 fatal("%s", strerror(errno)); 275 cleaninfo->clean = lfsp->lfs_nseg - 1; 276 cleaninfo->dirty = 1; 277 278 if (!(segtable = malloc(lfsp->lfs_segtabsz << lfsp->lfs_bshift))) 279 fatal("%s", strerror(errno)); 280 segp = segtable; 281 blocks_used = lfsp->lfs_segtabsz + lfsp->lfs_cleansz + 4; 282 segp->su_nbytes = blocks_used << lfsp->lfs_bshift; 283 segp->su_lastmod = lfsp->lfs_tstamp; 284 segp->su_nsums = 1; /* 1 summary blocks */ 285 segp->su_ninos = 1; /* 1 inode block */ 286 segp->su_flags = SEGUSE_SUPERBLOCK | SEGUSE_DIRTY; 287 lfsp->lfs_bfree -= db_per_fb * 288 (lfsp->lfs_cleansz + lfsp->lfs_segtabsz + 4); 289 290 /* 291 * Now figure out the address of the ifile inode. The inode block 292 * appears immediately after the segment summary. 293 */ 294 lfsp->lfs_idaddr = (LFS_LABELPAD + LFS_SBPAD + LFS_SUMMARY_SIZE) / 295 lp->d_secsize; 296 297 for (segp = segtable + 1, i = 1; i < lfsp->lfs_nseg; i++, segp++) { 298 if ((i % sb_interval) == 0) { 299 segp->su_flags = SEGUSE_SUPERBLOCK; 300 lfsp->lfs_bfree -= (LFS_SBPAD / lp->d_secsize); 301 } else 302 segp->su_flags = 0; 303 segp->su_lastmod = 0; 304 segp->su_nbytes = 0; 305 segp->su_ninos = 0; 306 segp->su_nsums = 1; 307 } 308 309 /* 310 * Ready to start writing segments. The first segment is different 311 * because it contains the segment usage table and the ifile inode 312 * as well as a superblock. For the rest of the segments, set the 313 * time stamp to be 0 so that the first segment is the most recent. 314 * For each segment that is supposed to contain a copy of the super 315 * block, initialize its first few blocks and its segment summary 316 * to indicate this. 317 */ 318 lfsp->lfs_nfiles = LFS_FIRST_INUM - 1; 319 lfsp->lfs_cksum = 320 cksum(lfsp, sizeof(struct lfs) - sizeof(lfsp->lfs_cksum)); 321 322 /* Now create a block of disk inodes */ 323 if (!(dpagep = malloc(lfsp->lfs_bsize))) 324 fatal("%s", strerror(errno)); 325 dip = (struct dinode *)dpagep; 326 bzero(dip, lfsp->lfs_bsize); 327 328 /* Create a block of IFILE structures. */ 329 if (!(ipagep = malloc(lfsp->lfs_bsize))) 330 fatal("%s", strerror(errno)); 331 ifile = (IFILE *)ipagep; 332 333 /* 334 * Initialize IFILE. It is the next block following the 335 * block of inodes (whose address has been calculated in 336 * lfsp->lfs_idaddr; 337 */ 338 sb_addr = lfsp->lfs_idaddr + lfsp->lfs_bsize / lp->d_secsize; 339 sb_addr = make_dinode(LFS_IFILE_INUM, dip, 340 lfsp->lfs_cleansz + lfsp->lfs_segtabsz+1, sb_addr, lfsp); 341 dip->di_mode = IFREG|IREAD|IWRITE; 342 ip = &ifile[LFS_IFILE_INUM]; 343 ip->if_version = 1; 344 ip->if_daddr = lfsp->lfs_idaddr; 345 346 /* Initialize the ROOT Directory */ 347 sb_addr = make_dinode(ROOTINO, ++dip, 1, sb_addr, lfsp); 348 dip->di_mode = IFDIR|IREAD|IWRITE|IEXEC; 349 dip->di_size = DIRBLKSIZ; 350 dip->di_nlink = 3; 351 ip = &ifile[ROOTINO]; 352 ip->if_version = 1; 353 ip->if_daddr = lfsp->lfs_idaddr; 354 355 /* Initialize the lost+found Directory */ 356 sb_addr = make_dinode(LOSTFOUNDINO, ++dip, 1, sb_addr, lfsp); 357 dip->di_mode = IFDIR|IREAD|IWRITE|IEXEC; 358 dip->di_size = DIRBLKSIZ; 359 dip->di_nlink = 2; 360 ip = &ifile[LOSTFOUNDINO]; 361 ip->if_version = 1; 362 ip->if_daddr = lfsp->lfs_idaddr; 363 364 /* Make all the other dinodes invalid */ 365 for (i = INOPB(lfsp)-3, dip++; i; i--, dip++) 366 dip->di_inum = LFS_UNUSED_INUM; 367 368 369 /* Link remaining IFILE entries in free list */ 370 for (ip = &ifile[LFS_FIRST_INUM], i = LFS_FIRST_INUM; 371 i < lfsp->lfs_ifpb; ++ip) { 372 ip->if_version = 1; 373 ip->if_daddr = LFS_UNUSED_DADDR; 374 ip->if_nextfree = ++i; 375 } 376 ifile[lfsp->lfs_ifpb - 1].if_nextfree = LFS_UNUSED_INUM; 377 378 /* Now, write the segment */ 379 380 /* Compute a checksum across all the data you're writing */ 381 dp = datasump = malloc (blocks_used * sizeof(u_long)); 382 *dp++ = ((u_long *)dip)[0]; /* inode block */ 383 for (i = 0; i < lfsp->lfs_cleansz; i++) 384 *dp++ = ((u_long *)cleaninfo)[(i << lfsp->lfs_bshift) / 385 sizeof(u_long)]; /* Cleaner info */ 386 for (i = 0; i < lfsp->lfs_segtabsz; i++) 387 *dp++ = ((u_long *)segtable)[(i << lfsp->lfs_bshift) / 388 sizeof(u_long)]; /* Segusage table */ 389 *dp++ = ((u_long *)ifile)[0]; /* Ifile */ 390 391 /* Still need the root and l+f bytes; get them later */ 392 393 /* Write out the inode block */ 394 off = LFS_LABELPAD + LFS_SBPAD + LFS_SUMMARY_SIZE; 395 put(fd, off, dpagep, lfsp->lfs_bsize); 396 free(dpagep); 397 off += lfsp->lfs_bsize; 398 399 /* Write out the ifile */ 400 401 put(fd, off, cleaninfo, lfsp->lfs_cleansz << lfsp->lfs_bshift); 402 off += (lfsp->lfs_cleansz << lfsp->lfs_bshift); 403 (void)free(cleaninfo); 404 405 put(fd, off, segtable, lfsp->lfs_segtabsz << lfsp->lfs_bshift); 406 off += (lfsp->lfs_segtabsz << lfsp->lfs_bshift); 407 (void)free(segtable); 408 409 put(fd, off, ifile, lfsp->lfs_bsize); 410 off += lfsp->lfs_bsize; 411 412 /* 413 * use ipagep for space for writing out other stuff. It used to 414 * contain the ifile, but we're done with it. 415 */ 416 417 /* Write out the root and lost and found directories */ 418 bzero(ipagep, lfsp->lfs_bsize); 419 make_dir(ipagep, lfs_root_dir, 420 sizeof(lfs_root_dir) / sizeof(struct direct)); 421 *dp++ = ((u_long *)ipagep)[0]; 422 put(fd, off, ipagep, lfsp->lfs_bsize); 423 off += lfsp->lfs_bsize; 424 425 bzero(ipagep, lfsp->lfs_bsize); 426 make_dir(ipagep, lfs_lf_dir, 427 sizeof(lfs_lf_dir) / sizeof(struct direct)); 428 *dp++ = ((u_long *)ipagep)[0]; 429 put(fd, off, ipagep, lfsp->lfs_bsize); 430 431 /* Write Supberblock */ 432 lfsp->lfs_offset = (off + lfsp->lfs_bsize) / lp->d_secsize; 433 put(fd, LFS_LABELPAD, lfsp, sizeof(struct lfs)); 434 435 /* 436 * Finally, calculate all the fields for the summary structure 437 * and write it. 438 */ 439 440 summary.ss_next = lfsp->lfs_nextseg; 441 summary.ss_create = lfsp->lfs_tstamp; 442 summary.ss_nfinfo = 3; 443 summary.ss_ninos = 3; 444 summary.ss_datasum = cksum(datasump, sizeof(u_long) * blocks_used); 445 446 /* 447 * Make sure that we don't overflow a summary block. We have to 448 * record: FINFO structures for ifile, root, and l+f. The number 449 * of blocks recorded for the ifile is determined by the size of 450 * the cleaner info and the segments usage table. There is room 451 * for one block included in sizeof(FINFO) so we don't need to add 452 * any extra space for the ROOT and L+F, and one block of the ifile 453 * is already counted. Finally, we leave room for 1 inode block 454 * address. 455 */ 456 sum_size = 3*sizeof(FINFO) + sizeof(SEGSUM) + sizeof(daddr_t) + 457 (lfsp->lfs_cleansz + lfsp->lfs_segtabsz) * sizeof(u_long); 458 #define SUMERR \ 459 "Multiple summary blocks in segment 1 not yet implemented\nsummary is %d bytes." 460 if (sum_size > LFS_SUMMARY_SIZE) 461 fatal(SUMERR, sum_size); 462 463 block_array_size = lfsp->lfs_cleansz + lfsp->lfs_segtabsz + 1; 464 465 if (!(block_array = malloc(block_array_size *sizeof(int)))) 466 fatal("%s: %s", special, strerror(errno)); 467 468 /* fill in the array */ 469 for (i = 0; i < block_array_size; i++) 470 block_array[i] = i; 471 472 /* copy into segment */ 473 sump = ipagep; 474 bcopy(&summary, sump, sizeof(SEGSUM)); 475 sump += sizeof(SEGSUM); 476 477 /* Now, add the ifile */ 478 file_info.fi_nblocks = block_array_size; 479 file_info.fi_version = 1; 480 file_info.fi_ino = LFS_IFILE_INUM; 481 482 bcopy(&file_info, sump, sizeof(FINFO) - sizeof(u_long)); 483 sump += sizeof(FINFO) - sizeof(u_long); 484 bcopy(block_array, sump, sizeof(u_long) * file_info.fi_nblocks); 485 sump += sizeof(u_long) * file_info.fi_nblocks; 486 487 /* Now, add the root directory */ 488 file_info.fi_nblocks = 1; 489 file_info.fi_version = 1; 490 file_info.fi_ino = ROOTINO; 491 file_info.fi_blocks[0] = 0; 492 bcopy(&file_info, sump, sizeof(FINFO)); 493 sump += sizeof(FINFO); 494 495 /* Now, add the lost and found */ 496 file_info.fi_ino = LOSTFOUNDINO; 497 bcopy(&file_info, sump, sizeof(FINFO)); 498 499 ((daddr_t *)ipagep)[LFS_SUMMARY_SIZE / sizeof(daddr_t) - 1] = 500 lfsp->lfs_idaddr; 501 ((SEGSUM *)ipagep)->ss_sumsum = cksum(ipagep+sizeof(summary.ss_sumsum), 502 LFS_SUMMARY_SIZE - sizeof(summary.ss_sumsum)); 503 put(fd, LFS_LABELPAD + LFS_SBPAD, ipagep, LFS_SUMMARY_SIZE); 504 505 sp = (SEGSUM *)ipagep; 506 sp->ss_create = 0; 507 sp->ss_nfinfo = 0; 508 sp->ss_ninos = 0; 509 sp->ss_datasum = 0; 510 511 /* Now write the summary block for the next partial so it's invalid */ 512 lfsp->lfs_tstamp = 0; 513 off += lfsp->lfs_bsize; 514 sp->ss_sumsum = 515 cksum(&sp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)); 516 put(fd, off, sp, LFS_SUMMARY_SIZE); 517 518 /* Now, write rest of segments containing superblocks */ 519 lfsp->lfs_cksum = 520 cksum(lfsp, sizeof(struct lfs) - sizeof(lfsp->lfs_cksum)); 521 for (seg_addr = last_addr = lfsp->lfs_sboffs[0], j = 1, i = 1; 522 i < lfsp->lfs_nseg; i++) { 523 524 seg_addr += lfsp->lfs_ssize << lfsp->lfs_fsbtodb; 525 sp->ss_next = last_addr; 526 last_addr = seg_addr; 527 seg_seek = seg_addr * lp->d_secsize; 528 529 if (seg_addr == lfsp->lfs_sboffs[j]) { 530 if (j < (LFS_MAXNUMSB - 2)) 531 j++; 532 put(fd, seg_seek, lfsp, sizeof(struct lfs)); 533 seg_seek += LFS_SBPAD; 534 } 535 536 /* Summary */ 537 sp->ss_sumsum = cksum(&sp->ss_datasum, 538 LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)); 539 put(fd, seg_seek, sp, LFS_SUMMARY_SIZE); 540 } 541 free(ipagep); 542 close(fd); 543 return (0); 544 } 545 546 static void 547 put(fd, off, p, len) 548 int fd; 549 off_t off; 550 void *p; 551 size_t len; 552 { 553 int wbytes; 554 555 if (lseek(fd, off, SEEK_SET) < 0) 556 fatal("%s: %s", special, strerror(errno)); 557 if ((wbytes = write(fd, p, len)) < 0) 558 fatal("%s: %s", special, strerror(errno)); 559 if (wbytes != len) 560 fatal("%s: short write (%d, not %d)", special, wbytes, len); 561 } 562 563 /* 564 * Create the root directory for this file system and the lost+found 565 * directory. 566 */ 567 568 u_long d_ino; /* inode number of entry */ 569 u_short d_reclen; /* length of this record */ 570 u_short d_namlen; /* length of string in d_name */ 571 char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */ 572 void 573 lfsinit() 574 {} 575 576 static daddr_t 577 make_dinode(ino, dip, nblocks, saddr, lfsp) 578 ino_t ino; /* inode we're creating */ 579 struct dinode *dip; /* disk inode */ 580 int nblocks; /* number of blocks in file */ 581 daddr_t saddr; /* starting block address */ 582 struct lfs *lfsp; /* superblock */ 583 { 584 int db_per_fb, i; 585 586 dip->di_nlink = 1; 587 dip->di_blocks = nblocks << lfsp->lfs_fsbtodb; 588 589 dip->di_size = (nblocks << lfsp->lfs_bshift); 590 dip->di_atime.ts_sec = dip->di_mtime.ts_sec = 591 dip->di_ctime.ts_sec = lfsp->lfs_tstamp; 592 dip->di_atime.ts_nsec = dip->di_mtime.ts_nsec = 593 dip->di_ctime.ts_nsec = 0; 594 dip->di_inum = ino; 595 596 #define SEGERR \ 597 "File requires more than the number of direct blocks; increase block or segment size." 598 if (NDADDR < nblocks) 599 fatal("%s", SEGERR); 600 601 /* Assign the block addresses for the ifile */ 602 db_per_fb = 1 << lfsp->lfs_fsbtodb; 603 for (i = 0; i < nblocks; i++, saddr += db_per_fb) 604 dip->di_db[i] = saddr; 605 606 return (saddr); 607 } 608 609 610 /* 611 * Construct a set of directory entries in "bufp". We assume that all the 612 * entries in protodir fir in the first DIRBLKSIZ. 613 */ 614 static void 615 make_dir(bufp, protodir, entries) 616 void *bufp; 617 register struct direct *protodir; 618 int entries; 619 { 620 char *cp; 621 int i, spcleft; 622 623 spcleft = DIRBLKSIZ; 624 for (cp = bufp, i = 0; i < entries - 1; i++) { 625 protodir[i].d_reclen = DIRSIZ(NEWDIRFMT, &protodir[i]); 626 bcopy(&protodir[i], cp, protodir[i].d_reclen); 627 cp += protodir[i].d_reclen; 628 if ((spcleft -= protodir[i].d_reclen) < 0) 629 fatal("%s: %s", special, "directory too big"); 630 } 631 protodir[i].d_reclen = spcleft; 632 bcopy(&protodir[i], cp, DIRSIZ(NEWDIRFMT, &protodir[i])); 633 } 634