1 /* $NetBSD: pass6.c,v 1.3 2003/04/02 10:39:28 fvdl 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@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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/time.h> 42 #include <sys/buf.h> 43 #include <sys/mount.h> 44 45 #include <ufs/ufs/ufsmount.h> 46 #include <ufs/ufs/inode.h> 47 #include <ufs/ufs/dir.h> 48 #define vnode uvnode 49 #include <ufs/lfs/lfs.h> 50 #undef vnode 51 52 #include <assert.h> 53 #include <err.h> 54 #include <string.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 58 #include "bufcache.h" 59 #include "vnode.h" 60 #include "lfs.h" 61 #include "segwrite.h" 62 63 #include "fsck.h" 64 #include "extern.h" 65 #include "fsutil.h" 66 67 extern u_int32_t cksum(void *, size_t); 68 extern u_int32_t lfs_sb_cksum(struct dlfs *); 69 70 extern ufs_daddr_t badblk; 71 extern SEGUSE *seg_table; 72 73 /* 74 * Our own copy of lfs_update_single so we can account in seg_table 75 * as well as the Ifile; and so we can add the blocks to their new 76 * segment. 77 * 78 * Change the given block's address to ndaddr, finding its previous 79 * location using ufs_bmaparray(). 80 * 81 * Account for this change in the segment table. 82 */ 83 static void 84 rfw_update_single(struct uvnode *vp, daddr_t lbn, ufs_daddr_t ndaddr, int size) 85 { 86 SEGUSE *sup; 87 struct ubuf *bp; 88 struct indir a[NIADDR + 2], *ap; 89 struct inode *ip; 90 daddr_t daddr, ooff; 91 int num, error; 92 int i, bb, osize, obb; 93 u_int32_t oldsn, sn; 94 95 ip = VTOI(vp); 96 97 error = ufs_bmaparray(fs, vp, lbn, &daddr, a, &num); 98 if (error) 99 errx(1, "lfs_updatemeta: ufs_bmaparray returned %d" 100 " looking up lbn %" PRId64 "\n", error, lbn); 101 if (daddr > 0) 102 daddr = dbtofsb(fs, daddr); 103 104 bb = fragstofsb(fs, numfrags(fs, size)); 105 switch (num) { 106 case 0: 107 ooff = ip->i_ffs1_db[lbn]; 108 if (ooff <= 0) 109 ip->i_ffs1_blocks += bb; 110 else { 111 /* possible fragment truncation or extension */ 112 obb = btofsb(fs, ip->i_lfs_fragsize[lbn]); 113 ip->i_ffs1_blocks += (bb - obb); 114 } 115 ip->i_ffs1_db[lbn] = ndaddr; 116 break; 117 case 1: 118 ooff = ip->i_ffs1_ib[a[0].in_off]; 119 if (ooff <= 0) 120 ip->i_ffs1_blocks += bb; 121 ip->i_ffs1_ib[a[0].in_off] = ndaddr; 122 break; 123 default: 124 ap = &a[num - 1]; 125 if (bread(vp, ap->in_lbn, fs->lfs_bsize, NULL, &bp)) 126 errx(1, "lfs_updatemeta: bread bno %" PRId64, 127 ap->in_lbn); 128 129 ooff = ((ufs_daddr_t *) bp->b_data)[ap->in_off]; 130 if (ooff <= 0) 131 ip->i_ffs1_blocks += bb; 132 ((ufs_daddr_t *) bp->b_data)[ap->in_off] = ndaddr; 133 (void) VOP_BWRITE(bp); 134 } 135 136 /* 137 * Update segment usage information, based on old size 138 * and location. 139 */ 140 if (daddr > 0) { 141 oldsn = dtosn(fs, daddr); 142 if (lbn >= 0 && lbn < NDADDR) 143 osize = ip->i_lfs_fragsize[lbn]; 144 else 145 osize = fs->lfs_bsize; 146 LFS_SEGENTRY(sup, fs, oldsn, bp); 147 seg_table[oldsn].su_nbytes -= osize; 148 sup->su_nbytes -= osize; 149 if (!(bp->b_flags & B_GATHERED)) 150 fs->lfs_flags |= LFS_IFDIRTY; 151 LFS_WRITESEGENTRY(sup, fs, oldsn, bp); 152 for (i = 0; i < btofsb(fs, osize); i++) 153 clrbmap(daddr + i); 154 } 155 156 /* Add block to its new segment */ 157 sn = dtosn(fs, ndaddr); 158 LFS_SEGENTRY(sup, fs, sn, bp); 159 seg_table[sn].su_nbytes += size; 160 sup->su_nbytes += size; 161 if (!(bp->b_flags & B_GATHERED)) 162 fs->lfs_flags |= LFS_IFDIRTY; 163 LFS_WRITESEGENTRY(sup, fs, sn, bp); 164 for (i = 0; i < btofsb(fs, size); i++) 165 setbmap(daddr + i); 166 167 /* Check bfree accounting as well */ 168 if (daddr < 0) { 169 fs->lfs_bfree -= btofsb(fs, size); 170 } else if (size != osize) { 171 fs->lfs_bfree -= (bb - obb); 172 } 173 174 /* 175 * Now that this block has a new address, and its old 176 * segment no longer owns it, we can forget about its 177 * old size. 178 */ 179 if (lbn >= 0 && lbn < NDADDR) 180 ip->i_lfs_fragsize[lbn] = size; 181 } 182 183 /* 184 * Remove the vnode from the cache, including any blocks it 185 * may hold. Account the blocks. Finally account the removal 186 * of the inode from its segment. 187 */ 188 static void 189 remove_ino(struct uvnode *vp, ino_t ino) 190 { 191 IFILE *ifp; 192 SEGUSE *sup; 193 struct ubuf *bp, *sbp; 194 struct inodesc idesc; 195 ufs_daddr_t daddr; 196 int obfree; 197 198 obfree = fs->lfs_bfree; 199 LFS_IENTRY(ifp, fs, ino, bp); 200 daddr = ifp->if_daddr; 201 brelse(bp); 202 203 if (vp == NULL && daddr > 0) { 204 vp = lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr); 205 } 206 207 if (daddr > 0) { 208 LFS_SEGENTRY(sup, fs, dtosn(fs, ifp->if_daddr), sbp); 209 sup->su_nbytes -= DINODE1_SIZE; 210 VOP_BWRITE(sbp); 211 seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes -= DINODE1_SIZE; 212 } 213 214 /* Do on-disk accounting */ 215 if (vp) { 216 idesc.id_number = ino; 217 idesc.id_func = pass4check; /* Delete dinode and blocks */ 218 idesc.id_type = ADDR; 219 idesc.id_lblkno = 0; 220 clri(&idesc, "unknown", 2); /* XXX magic number 2 */ 221 222 /* Get rid of this vnode for good */ 223 vnode_destroy(vp); 224 } 225 } 226 227 /* 228 * Use FIP records to update blocks, if the generation number matches. 229 */ 230 static void 231 pass6harvest(ufs_daddr_t daddr, FINFO *fip) 232 { 233 struct uvnode *vp; 234 int i; 235 size_t size; 236 237 vp = vget(fs, fip->fi_ino); 238 if (vp && vp != fs->lfs_ivnode && 239 VTOI(vp)->i_ffs1_gen == fip->fi_version) { 240 for (i = 0; i < fip->fi_nblocks; i++) { 241 size = (i == fip->fi_nblocks - 1 ? 242 fip->fi_lastlength : fs->lfs_bsize); 243 rfw_update_single(vp, fip->fi_blocks[i], daddr, size); 244 daddr += btofsb(fs, size); 245 } 246 } 247 } 248 249 /* 250 * Check validity of blocks on roll-forward inodes. 251 */ 252 int 253 pass6check(struct inodesc * idesc) 254 { 255 int i, sn, anyout, anynew; 256 257 /* Check that the blocks do not lie within clean segments. */ 258 anyout = anynew = 0; 259 for (i = 0; i < fragstofsb(fs, idesc->id_numfrags); i++) { 260 sn = dtosn(fs, idesc->id_blkno + i); 261 if (sn < 0 || sn >= fs->lfs_nseg || 262 (seg_table[sn].su_flags & SEGUSE_DIRTY) == 0) { 263 anyout = 1; 264 break; 265 } 266 if (seg_table[sn].su_flags & SEGUSE_ACTIVE) { 267 if (sn != dtosn(fs, fs->lfs_offset) || 268 idesc->id_blkno > fs->lfs_offset) { 269 ++anynew; 270 } 271 } 272 if (!anynew) { 273 /* Clear so pass1check won't be surprised */ 274 clrbmap(idesc->id_blkno + i); 275 seg_table[sn].su_nbytes -= fsbtob(fs, 1); 276 } 277 } 278 if (anyout) { 279 blkerror(idesc->id_number, "BAD", idesc->id_blkno); 280 if (badblk++ >= MAXBAD) { 281 pwarn("EXCESSIVE BAD BLKS I=%u", 282 idesc->id_number); 283 if (preen) 284 pwarn(" (SKIPPING)\n"); 285 else if (reply("CONTINUE") == 0) 286 err(8, "%s", ""); 287 return (STOP); 288 } 289 } 290 291 return pass1check(idesc); 292 } 293 294 /* 295 * Add a new block to the Ifile, to accommodate future file creations. 296 */ 297 static int 298 extend_ifile(void) 299 { 300 struct uvnode *vp; 301 struct inode *ip; 302 IFILE *ifp; 303 IFILE_V1 *ifp_v1; 304 struct ubuf *bp, *cbp; 305 daddr_t i, blkno, max; 306 ino_t oldlast; 307 CLEANERINFO *cip; 308 309 vp = fs->lfs_ivnode; 310 ip = VTOI(vp); 311 blkno = lblkno(fs, ip->i_ffs1_size); 312 313 bp = getblk(vp, blkno, fs->lfs_bsize); /* XXX VOP_BALLOC() */ 314 ip->i_ffs1_size += fs->lfs_bsize; 315 316 i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) * 317 fs->lfs_ifpb; 318 LFS_GET_HEADFREE(fs, cip, cbp, &oldlast); 319 LFS_PUT_HEADFREE(fs, cip, cbp, i); 320 max = i + fs->lfs_ifpb; 321 maxino = max; 322 fs->lfs_bfree -= btofsb(fs, fs->lfs_bsize); 323 324 if (fs->lfs_version == 1) { 325 for (ifp_v1 = (IFILE_V1 *)bp->b_data; i < max; ++ifp_v1) { 326 ifp_v1->if_version = 1; 327 ifp_v1->if_daddr = LFS_UNUSED_DADDR; 328 ifp_v1->if_nextfree = ++i; 329 } 330 ifp_v1--; 331 ifp_v1->if_nextfree = oldlast; 332 } else { 333 for (ifp = (IFILE *)bp->b_data; i < max; ++ifp) { 334 ifp->if_version = 1; 335 ifp->if_daddr = LFS_UNUSED_DADDR; 336 ifp->if_nextfree = ++i; 337 } 338 ifp--; 339 ifp->if_nextfree = oldlast; 340 } 341 LFS_PUT_TAILFREE(fs, cip, cbp, max - 1); 342 343 LFS_BWRITE_LOG(bp); 344 345 return 0; 346 } 347 348 /* 349 * Give a previously allocated inode a new address; do segment 350 * accounting if necessary. 351 * 352 * Caller has ensured that this inode is not on the free list, so no 353 * free list accounting is done. 354 */ 355 static void 356 readdress_inode(ino_t thisino, ufs_daddr_t daddr) 357 { 358 IFILE *ifp; 359 SEGUSE *sup; 360 struct ubuf *bp; 361 int sn; 362 ufs_daddr_t odaddr; 363 364 LFS_IENTRY(ifp, fs, thisino, bp); 365 odaddr = ifp->if_daddr; 366 ifp->if_daddr = daddr; 367 VOP_BWRITE(bp); 368 369 sn = dtosn(fs, odaddr); 370 LFS_SEGENTRY(sup, fs, sn, bp); 371 sup->su_nbytes -= DINODE1_SIZE; 372 VOP_BWRITE(bp); 373 seg_table[sn].su_nbytes -= DINODE1_SIZE; 374 375 sn = dtosn(fs, daddr); 376 LFS_SEGENTRY(sup, fs, sn, bp); 377 sup->su_nbytes += DINODE1_SIZE; 378 VOP_BWRITE(bp); 379 seg_table[sn].su_nbytes += DINODE1_SIZE; 380 } 381 382 /* 383 * Allocate the given inode from the free list. 384 */ 385 static void 386 alloc_inode(ino_t thisino, ufs_daddr_t daddr) 387 { 388 ino_t ino, nextfree; 389 IFILE *ifp; 390 SEGUSE *sup; 391 struct ubuf *bp; 392 393 LFS_IENTRY(ifp, fs, thisino, bp); 394 nextfree = ifp->if_nextfree; 395 ifp->if_nextfree = 0; 396 ifp->if_daddr = daddr; 397 VOP_BWRITE(bp); 398 399 while (thisino > (lblkno(fs, VTOI(fs->lfs_ivnode)->i_ffs1_size) - 400 fs->lfs_segtabsz - fs->lfs_cleansz + 1) * 401 fs->lfs_ifpb) { 402 extend_ifile(); 403 } 404 405 if (fs->lfs_freehd == thisino) { 406 fs->lfs_freehd = nextfree; 407 sbdirty(); 408 if (nextfree == 0) { 409 extend_ifile(); 410 } 411 } else { 412 ino = fs->lfs_freehd; 413 while (ino) { 414 LFS_IENTRY(ifp, fs, ino, bp); 415 assert(ifp->if_nextfree != ino); 416 if (ifp->if_nextfree == thisino) { 417 ifp->if_nextfree = nextfree; 418 VOP_BWRITE(bp); 419 break; 420 } else 421 ino = ifp->if_nextfree; 422 brelse(bp); 423 } 424 } 425 426 /* Account for new location */ 427 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), bp); 428 sup->su_nbytes += DINODE1_SIZE; 429 VOP_BWRITE(bp); 430 seg_table[dtosn(fs, daddr)].su_nbytes += DINODE1_SIZE; 431 } 432 433 /* 434 * Roll forward from the last verified checkpoint. 435 * 436 * Basic strategy: 437 * 438 * Run through the summaries finding the last valid partial segment. 439 * Note segment numbers as we go. For each inode that we find, compare 440 * its generation number; if newer than old inode's (or if old inode is 441 * USTATE), change to that inode. Recursively look at inode blocks that 442 * do not have their old disk addresses. These addresses must lie in 443 * segments we have seen already in our roll forward. 444 * 445 * A second pass through the past-checkpoint area verifies the validity 446 * of these new blocks, as well as updating other blocks that do not 447 * have corresponding new inodes (but their generation number must match 448 * the old generation number). 449 */ 450 void 451 pass6(void) 452 { 453 ufs_daddr_t daddr, ibdaddr, odaddr, lastgood, nextseg, *idaddrp; 454 struct uvnode *vp, *devvp; 455 CLEANERINFO *cip; 456 SEGUSE *sup; 457 SEGSUM *sp; 458 struct ubuf *bp, *ibp, *sbp, *cbp; 459 struct ufs1_dinode *dp; 460 struct inodesc idesc; 461 int i, j, bc; 462 ufs_daddr_t hassuper; 463 464 devvp = fs->lfs_unlockvp; 465 466 /* Find last valid partial segment */ 467 lastgood = try_verify(fs, devvp, 0, debug); 468 if (lastgood == fs->lfs_offset) { 469 if (debug) 470 pwarn("not rolling forward, nothing to recover\n"); 471 return; 472 } 473 474 if (!preen && reply("roll forward") == 0) 475 return; 476 477 if (debug) 478 pwarn("rolling forward between %" PRIx32 " and %" PRIx32 "\n", 479 fs->lfs_offset, lastgood); 480 /* 481 * Pass 1: find inode blocks. We ignore the Ifile inode but accept 482 * changes to any other inode. 483 */ 484 485 daddr = fs->lfs_offset; 486 nextseg = fs->lfs_nextseg; 487 while (daddr != lastgood) { 488 seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE; 489 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 490 sup->su_flags |= SEGUSE_DIRTY; 491 VOP_BWRITE(sbp); 492 hassuper = 0; 493 oncemore: 494 /* Read in summary block */ 495 bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp); 496 sp = (SEGSUM *)bp->b_data; 497 498 /* Could be a superblock instead of a segment summary. */ 499 if (sntod(fs, dtosn(fs, daddr)) == daddr && 500 (sp->ss_magic != SS_MAGIC || 501 sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize - 502 sizeof(sp->ss_sumsum)))) { 503 brelse(bp); 504 daddr += btofsb(fs, LFS_SBPAD); 505 hassuper = 1; 506 goto oncemore; 507 } 508 509 /* We have verified that this is a good summary. */ 510 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 511 ++sup->su_nsums; 512 VOP_BWRITE(sbp); 513 fs->lfs_bfree -= btofsb(fs, fs->lfs_sumsize); 514 fs->lfs_dmeta += btofsb(fs, fs->lfs_sumsize); 515 sbdirty(); 516 nextseg = sp->ss_next; 517 if (sntod(fs, dtosn(fs, daddr)) == daddr + 518 hassuper * btofsb(fs, LFS_SBPAD) && 519 dtosn(fs, daddr) != dtosn(fs, fs->lfs_offset)) { 520 --fs->lfs_nclean; 521 sbdirty(); 522 } 523 524 /* Find inodes, look at generation number. */ 525 if (sp->ss_ninos) { 526 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 527 sup->su_ninos += howmany(sp->ss_ninos, INOPB(fs)); 528 VOP_BWRITE(sbp); 529 fs->lfs_dmeta += btofsb(fs, howmany(sp->ss_ninos, 530 INOPB(fs)) * 531 fs->lfs_ibsize); 532 } 533 idaddrp = ((ufs_daddr_t *)((char *)bp->b_data + fs->lfs_sumsize)); 534 for (i = 0; i < howmany(sp->ss_ninos, INOPB(fs)); i++) { 535 ino_t inums[INOPB(fs) + 1]; 536 537 for (j = 0; j < INOPB(fs) + 1; j++) 538 inums[j] = 0; 539 ibdaddr = *--idaddrp; 540 fs->lfs_bfree -= btofsb(fs, fs->lfs_ibsize); 541 sbdirty(); 542 bread(devvp, fsbtodb(fs, ibdaddr), fs->lfs_ibsize, 543 NOCRED, &ibp); 544 j = 0; 545 for (dp = (struct ufs1_dinode *)ibp->b_data; 546 dp < (struct ufs1_dinode *)ibp->b_data + INOPB(fs); 547 ++dp) { 548 if (dp->di_u.inumber == 0 || 549 dp->di_u.inumber == fs->lfs_ifile) 550 continue; 551 /* Basic sanity checks */ 552 if (dp->di_nlink < 0 || 553 dp->di_u.inumber < 0 || 554 dp->di_size < 0) { 555 pwarn("bad inode at %" PRIx32 "\n", 556 ibdaddr); 557 brelse(ibp); 558 brelse(bp); 559 goto out; 560 } 561 562 vp = vget(fs, dp->di_u.inumber); 563 564 /* 565 * Four cases: 566 * (1) Invalid inode (nlink == 0). 567 * If currently allocated, remove. 568 */ 569 if (dp->di_nlink == 0) { 570 remove_ino(vp, dp->di_u.inumber); 571 continue; 572 } 573 /* 574 * (2) New valid inode, previously free. 575 * Nothing to do except account 576 * the inode itself, done after the 577 * loop. 578 */ 579 if (vp == NULL) { 580 inums[j++] = dp->di_u.inumber; 581 continue; 582 } 583 /* 584 * (3) Valid new version of previously 585 * allocated inode. Delete old file 586 * and proceed as in (2). 587 */ 588 if (vp && VTOI(vp)->i_ffs1_gen < dp->di_gen) { 589 remove_ino(vp, dp->di_u.inumber); 590 inums[j++] = dp->di_u.inumber; 591 continue; 592 } 593 /* 594 * (4) Same version of previously 595 * allocated inode. Move inode to 596 * this location, account inode change 597 * only. We'll pick up any new 598 * blocks when we do the block pass. 599 */ 600 if (vp && VTOI(vp)->i_ffs1_gen == dp->di_gen) { 601 readdress_inode(dp->di_u.inumber, ibdaddr); 602 603 /* Update with new info */ 604 VTOD(vp)->di_mode = dp->di_mode; 605 VTOD(vp)->di_nlink = dp->di_nlink; 606 /* XXX size is important */ 607 VTOD(vp)->di_size = dp->di_size; 608 VTOD(vp)->di_atime = dp->di_atime; 609 VTOD(vp)->di_atimensec = dp->di_atimensec; 610 VTOD(vp)->di_mtime = dp->di_mtime; 611 VTOD(vp)->di_mtimensec = dp->di_mtimensec; 612 VTOD(vp)->di_ctime = dp->di_ctime; 613 VTOD(vp)->di_ctimensec = dp->di_ctimensec; 614 VTOD(vp)->di_flags = dp->di_flags; 615 VTOD(vp)->di_uid = dp->di_uid; 616 VTOD(vp)->di_gid = dp->di_gid; 617 inodirty(VTOI(vp)); 618 } 619 } 620 brelse(ibp); 621 for (j = 0; inums[j]; j++) { 622 alloc_inode(inums[j], ibdaddr); 623 vp = lfs_raw_vget(fs, inums[j], 624 devvp->v_fd, ibdaddr); 625 /* We'll get the blocks later */ 626 memset(VTOD(vp)->di_db, 0, (NDADDR + NIADDR) * 627 sizeof(ufs_daddr_t)); 628 VTOD(vp)->di_blocks = 0; 629 630 vp->v_flag |= VDIROP; 631 inodirty(VTOI(vp)); 632 } 633 } 634 635 bc = check_summary(fs, sp, daddr, debug, devvp, NULL); 636 if (bc == 0) { 637 brelse(bp); 638 break; 639 } 640 odaddr = daddr; 641 daddr += btofsb(fs, fs->lfs_sumsize + bc); 642 if (dtosn(fs, odaddr) != dtosn(fs, daddr) || 643 dtosn(fs, daddr) != dtosn(fs, daddr + 644 btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize))) { 645 daddr = ((SEGSUM *)bp->b_data)->ss_next; 646 } 647 brelse(bp); 648 } 649 out: 650 651 /* 652 * Check our new vnodes. Any blocks must lie in segments that 653 * we've seen before (SEGUSE_DIRTY or SEGUSE_RFW); and the rest 654 * of the pass 1 checks as well. 655 */ 656 memset(&idesc, 0, sizeof(struct inodesc)); 657 idesc.id_type = ADDR; 658 idesc.id_func = pass6check; 659 idesc.id_lblkno = 0; 660 LIST_FOREACH(vp, &vnodelist, v_mntvnodes) { 661 if ((vp->v_flag & VDIROP) == 0) 662 --n_files; /* Don't double count */ 663 checkinode(VTOI(vp)->i_number, &idesc); 664 } 665 666 /* 667 * Second pass. Run through FINFO entries looking for blocks 668 * with the same generation number as files we've seen before. 669 * If they have it, pretend like we just wrote them. We don't 670 * do the pretend-write, though, if we've already seen them 671 * (the accounting would have been done for us already). 672 */ 673 daddr = fs->lfs_offset; 674 while (daddr != lastgood) { 675 if (!(seg_table[dtosn(fs, daddr)].su_flags & SEGUSE_DIRTY)) { 676 seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY; 677 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 678 sup->su_flags |= SEGUSE_DIRTY; 679 VOP_BWRITE(sbp); 680 } 681 oncemore2: 682 /* Read in summary block */ 683 bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp); 684 sp = (SEGSUM *)bp->b_data; 685 686 /* Could be a superblock instead of a segment summary. */ 687 if (sntod(fs, dtosn(fs, daddr)) == daddr && 688 (sp->ss_magic != SS_MAGIC || 689 sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize - 690 sizeof(sp->ss_sumsum)))) { 691 brelse(bp); 692 daddr += btofsb(fs, LFS_SBPAD); 693 goto oncemore2; 694 } 695 696 bc = check_summary(fs, sp, daddr, debug, devvp, pass6harvest); 697 if (bc == 0) { 698 brelse(bp); 699 break; 700 } 701 odaddr = daddr; 702 daddr += btofsb(fs, fs->lfs_sumsize + bc); 703 fs->lfs_avail -= btofsb(fs, fs->lfs_sumsize + bc); 704 if (dtosn(fs, odaddr) != dtosn(fs, daddr) || 705 dtosn(fs, daddr) != dtosn(fs, daddr + 706 btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize))) { 707 fs->lfs_avail -= sntod(fs, dtosn(fs, daddr) + 1) - daddr; 708 daddr = ((SEGSUM *)bp->b_data)->ss_next; 709 } 710 LFS_CLEANERINFO(cip, fs, cbp); 711 LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0); 712 bp->b_flags |= B_AGE; 713 brelse(bp); 714 } 715 716 /* Update offset to point at correct location */ 717 fs->lfs_offset = lastgood; 718 fs->lfs_curseg = sntod(fs, dtosn(fs, lastgood)); 719 fs->lfs_nextseg = nextseg; 720 721 if (!preen) { 722 /* Run pass 5 again (it's quick anyway). */ 723 pwarn("** Phase 6b - Recheck Segment Block Accounting\n"); 724 pass5(); 725 } 726 } 727