1 /* $NetBSD: pass6.c,v 1.10 2005/09/13 04:14:17 christos 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_user.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 = 0, obb = 0; 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 /* vp has been destroyed */ 222 } 223 } 224 225 /* 226 * Use FIP records to update blocks, if the generation number matches. 227 */ 228 static void 229 pass6harvest(ufs_daddr_t daddr, FINFO *fip) 230 { 231 struct uvnode *vp; 232 int i; 233 size_t size; 234 235 vp = vget(fs, fip->fi_ino); 236 if (vp && vp != fs->lfs_ivnode && 237 VTOI(vp)->i_ffs1_gen == fip->fi_version) { 238 for (i = 0; i < fip->fi_nblocks; i++) { 239 size = (i == fip->fi_nblocks - 1 ? 240 fip->fi_lastlength : fs->lfs_bsize); 241 rfw_update_single(vp, fip->fi_blocks[i], daddr, size); 242 daddr += btofsb(fs, size); 243 } 244 } 245 } 246 247 /* 248 * Check validity of blocks on roll-forward inodes. 249 */ 250 int 251 pass6check(struct inodesc * idesc) 252 { 253 int i, sn, anyout, anynew; 254 255 /* Check that the blocks do not lie within clean segments. */ 256 anyout = anynew = 0; 257 for (i = 0; i < fragstofsb(fs, idesc->id_numfrags); i++) { 258 sn = dtosn(fs, idesc->id_blkno + i); 259 if (sn < 0 || sn >= fs->lfs_nseg || 260 (seg_table[sn].su_flags & SEGUSE_DIRTY) == 0) { 261 anyout = 1; 262 break; 263 } 264 if (seg_table[sn].su_flags & SEGUSE_ACTIVE) { 265 if (sn != dtosn(fs, fs->lfs_offset) || 266 idesc->id_blkno > fs->lfs_offset) { 267 ++anynew; 268 } 269 } 270 if (!anynew) { 271 /* Clear so pass1check won't be surprised */ 272 clrbmap(idesc->id_blkno + i); 273 seg_table[sn].su_nbytes -= fsbtob(fs, 1); 274 } 275 } 276 if (anyout) { 277 blkerror(idesc->id_number, "BAD", idesc->id_blkno); 278 if (badblk++ >= MAXBAD) { 279 pwarn("EXCESSIVE BAD BLKS I=%llu", 280 (unsigned long long)idesc->id_number); 281 if (preen) 282 pwarn(" (SKIPPING)\n"); 283 else if (reply("CONTINUE") == 0) 284 err(8, "%s", ""); 285 return (STOP); 286 } 287 } 288 289 return pass1check(idesc); 290 } 291 292 /* 293 * Give a previously allocated inode a new address; do segment 294 * accounting if necessary. 295 * 296 * Caller has ensured that this inode is not on the free list, so no 297 * free list accounting is done. 298 */ 299 static void 300 readdress_inode(ino_t thisino, ufs_daddr_t daddr) 301 { 302 IFILE *ifp; 303 SEGUSE *sup; 304 struct ubuf *bp; 305 int sn; 306 ufs_daddr_t odaddr; 307 308 LFS_IENTRY(ifp, fs, thisino, bp); 309 odaddr = ifp->if_daddr; 310 ifp->if_daddr = daddr; 311 VOP_BWRITE(bp); 312 313 sn = dtosn(fs, odaddr); 314 LFS_SEGENTRY(sup, fs, sn, bp); 315 sup->su_nbytes -= DINODE1_SIZE; 316 VOP_BWRITE(bp); 317 seg_table[sn].su_nbytes -= DINODE1_SIZE; 318 319 sn = dtosn(fs, daddr); 320 LFS_SEGENTRY(sup, fs, sn, bp); 321 sup->su_nbytes += DINODE1_SIZE; 322 VOP_BWRITE(bp); 323 seg_table[sn].su_nbytes += DINODE1_SIZE; 324 } 325 326 /* 327 * Allocate the given inode from the free list. 328 */ 329 static void 330 alloc_inode(ino_t thisino, ufs_daddr_t daddr) 331 { 332 ino_t ino, nextfree; 333 IFILE *ifp; 334 SEGUSE *sup; 335 struct ubuf *bp; 336 337 while (thisino >= maxino) { 338 extend_ifile(fs); 339 reset_maxino(((VTOI(fs->lfs_ivnode)->i_ffs1_size >> 340 fs->lfs_bsize) - fs->lfs_segtabsz - 341 fs->lfs_cleansz) * fs->lfs_ifpb); 342 } 343 344 LFS_IENTRY(ifp, fs, thisino, bp); 345 nextfree = ifp->if_nextfree; 346 ifp->if_nextfree = 0; 347 ifp->if_daddr = daddr; 348 VOP_BWRITE(bp); 349 350 if (fs->lfs_freehd == thisino) { 351 fs->lfs_freehd = nextfree; 352 sbdirty(); 353 if (nextfree == 0) { 354 extend_ifile(fs); 355 reset_maxino(((VTOI(fs->lfs_ivnode)->i_ffs1_size >> 356 fs->lfs_bsize) - fs->lfs_segtabsz - 357 fs->lfs_cleansz) * fs->lfs_ifpb); 358 } 359 } else { 360 /* Search the free list for this inode */ 361 ino = fs->lfs_freehd; 362 while (ino) { 363 LFS_IENTRY(ifp, fs, ino, bp); 364 assert(ifp->if_nextfree != ino); 365 if (ifp->if_nextfree == thisino) { 366 ifp->if_nextfree = nextfree; 367 VOP_BWRITE(bp); 368 break; 369 } else 370 ino = ifp->if_nextfree; 371 brelse(bp); 372 } 373 } 374 375 /* Account for new location */ 376 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), bp); 377 sup->su_nbytes += DINODE1_SIZE; 378 VOP_BWRITE(bp); 379 seg_table[dtosn(fs, daddr)].su_nbytes += DINODE1_SIZE; 380 } 381 382 /* 383 * Roll forward from the last verified checkpoint. 384 * 385 * Basic strategy: 386 * 387 * Run through the summaries finding the last valid partial segment. 388 * Note segment numbers as we go. For each inode that we find, compare 389 * its generation number; if newer than old inode's (or if old inode is 390 * USTATE), change to that inode. Recursively look at inode blocks that 391 * do not have their old disk addresses. These addresses must lie in 392 * segments we have seen already in our roll forward. 393 * 394 * A second pass through the past-checkpoint area verifies the validity 395 * of these new blocks, as well as updating other blocks that do not 396 * have corresponding new inodes (but their generation number must match 397 * the old generation number). 398 */ 399 void 400 pass6(void) 401 { 402 ufs_daddr_t daddr, ibdaddr, odaddr, lastgood, nextseg, *idaddrp; 403 struct uvnode *vp, *devvp; 404 CLEANERINFO *cip; 405 SEGUSE *sup; 406 SEGSUM *sp; 407 struct ubuf *bp, *ibp, *sbp, *cbp; 408 struct ufs1_dinode *dp; 409 struct inodesc idesc; 410 int i, j, bc; 411 ufs_daddr_t hassuper; 412 413 devvp = fs->lfs_devvp; 414 415 /* Find last valid partial segment */ 416 lastgood = try_verify(fs, devvp, 0, debug); 417 if (lastgood == fs->lfs_offset) { 418 if (debug) 419 pwarn("not rolling forward, nothing to recover\n"); 420 return; 421 } 422 423 if (debug) 424 pwarn("could roll forward from %" PRIx32 " to %" PRIx32 "\n", 425 fs->lfs_offset, lastgood); 426 427 if (!preen && reply("roll forward") == 0) 428 return; 429 /* 430 * Pass 1: find inode blocks. We ignore the Ifile inode but accept 431 * changes to any other inode. 432 */ 433 434 daddr = fs->lfs_offset; 435 nextseg = fs->lfs_nextseg; 436 while (daddr != lastgood) { 437 seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE; 438 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 439 sup->su_flags |= SEGUSE_DIRTY; 440 VOP_BWRITE(sbp); 441 hassuper = 0; 442 oncemore: 443 /* Read in summary block */ 444 bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp); 445 sp = (SEGSUM *)bp->b_data; 446 447 /* Could be a superblock instead of a segment summary. */ 448 if (sntod(fs, dtosn(fs, daddr)) == daddr && 449 (sp->ss_magic != SS_MAGIC || 450 sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize - 451 sizeof(sp->ss_sumsum)))) { 452 brelse(bp); 453 daddr += btofsb(fs, LFS_SBPAD); 454 hassuper = 1; 455 goto oncemore; 456 } 457 458 /* We have verified that this is a good summary. */ 459 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 460 ++sup->su_nsums; 461 VOP_BWRITE(sbp); 462 fs->lfs_bfree -= btofsb(fs, fs->lfs_sumsize); 463 fs->lfs_dmeta += btofsb(fs, fs->lfs_sumsize); 464 sbdirty(); 465 nextseg = sp->ss_next; 466 if (sntod(fs, dtosn(fs, daddr)) == daddr + 467 hassuper * btofsb(fs, LFS_SBPAD) && 468 dtosn(fs, daddr) != dtosn(fs, fs->lfs_offset)) { 469 --fs->lfs_nclean; 470 sbdirty(); 471 } 472 473 /* Find inodes, look at generation number. */ 474 if (sp->ss_ninos) { 475 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 476 sup->su_ninos += howmany(sp->ss_ninos, INOPB(fs)); 477 VOP_BWRITE(sbp); 478 fs->lfs_dmeta += btofsb(fs, howmany(sp->ss_ninos, 479 INOPB(fs)) * 480 fs->lfs_ibsize); 481 } 482 idaddrp = ((ufs_daddr_t *)((char *)bp->b_data + fs->lfs_sumsize)); 483 for (i = 0; i < howmany(sp->ss_ninos, INOPB(fs)); i++) { 484 ino_t inums[INOPB(fs) + 1]; 485 486 for (j = 0; j < INOPB(fs) + 1; j++) 487 inums[j] = 0; 488 ibdaddr = *--idaddrp; 489 fs->lfs_bfree -= btofsb(fs, fs->lfs_ibsize); 490 sbdirty(); 491 bread(devvp, fsbtodb(fs, ibdaddr), fs->lfs_ibsize, 492 NOCRED, &ibp); 493 j = 0; 494 for (dp = (struct ufs1_dinode *)ibp->b_data; 495 dp < (struct ufs1_dinode *)ibp->b_data + INOPB(fs); 496 ++dp) { 497 if (dp->di_u.inumber == 0 || 498 dp->di_u.inumber == fs->lfs_ifile) 499 continue; 500 /* Basic sanity checks */ 501 if (dp->di_nlink < 0 || 502 dp->di_u.inumber < 0 || 503 dp->di_size < 0) { 504 pwarn("bad inode at %" PRIx32 "\n", 505 ibdaddr); 506 brelse(ibp); 507 brelse(bp); 508 goto out; 509 } 510 511 vp = vget(fs, dp->di_u.inumber); 512 513 /* 514 * Four cases: 515 * (1) Invalid inode (nlink == 0). 516 * If currently allocated, remove. 517 */ 518 if (dp->di_nlink == 0) { 519 remove_ino(vp, dp->di_u.inumber); 520 continue; 521 } 522 /* 523 * (2) New valid inode, previously free. 524 * Nothing to do except account 525 * the inode itself, done after the 526 * loop. 527 */ 528 if (vp == NULL) { 529 inums[j++] = dp->di_u.inumber; 530 continue; 531 } 532 /* 533 * (3) Valid new version of previously 534 * allocated inode. Delete old file 535 * and proceed as in (2). 536 */ 537 if (vp && VTOI(vp)->i_ffs1_gen < dp->di_gen) { 538 remove_ino(vp, dp->di_u.inumber); 539 inums[j++] = dp->di_u.inumber; 540 continue; 541 } 542 /* 543 * (4) Same version of previously 544 * allocated inode. Move inode to 545 * this location, account inode change 546 * only. We'll pick up any new 547 * blocks when we do the block pass. 548 */ 549 if (vp && VTOI(vp)->i_ffs1_gen == dp->di_gen) { 550 readdress_inode(dp->di_u.inumber, ibdaddr); 551 552 /* Update with new info */ 553 VTOD(vp)->di_mode = dp->di_mode; 554 VTOD(vp)->di_nlink = dp->di_nlink; 555 /* XXX size is important */ 556 VTOD(vp)->di_size = dp->di_size; 557 VTOD(vp)->di_atime = dp->di_atime; 558 VTOD(vp)->di_atimensec = dp->di_atimensec; 559 VTOD(vp)->di_mtime = dp->di_mtime; 560 VTOD(vp)->di_mtimensec = dp->di_mtimensec; 561 VTOD(vp)->di_ctime = dp->di_ctime; 562 VTOD(vp)->di_ctimensec = dp->di_ctimensec; 563 VTOD(vp)->di_flags = dp->di_flags; 564 VTOD(vp)->di_uid = dp->di_uid; 565 VTOD(vp)->di_gid = dp->di_gid; 566 inodirty(VTOI(vp)); 567 } 568 } 569 brelse(ibp); 570 for (j = 0; inums[j]; j++) { 571 alloc_inode(inums[j], ibdaddr); 572 vp = lfs_raw_vget(fs, inums[j], 573 devvp->v_fd, ibdaddr); 574 /* We'll get the blocks later */ 575 memset(VTOD(vp)->di_db, 0, (NDADDR + NIADDR) * 576 sizeof(ufs_daddr_t)); 577 VTOD(vp)->di_blocks = 0; 578 579 vp->v_flag |= VDIROP; 580 inodirty(VTOI(vp)); 581 } 582 } 583 584 bc = check_summary(fs, sp, daddr, debug, devvp, NULL); 585 if (bc == 0) { 586 brelse(bp); 587 break; 588 } 589 odaddr = daddr; 590 daddr += btofsb(fs, fs->lfs_sumsize + bc); 591 if (dtosn(fs, odaddr) != dtosn(fs, daddr) || 592 dtosn(fs, daddr) != dtosn(fs, daddr + 593 btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize))) { 594 daddr = ((SEGSUM *)bp->b_data)->ss_next; 595 } 596 brelse(bp); 597 } 598 out: 599 600 /* 601 * Check our new vnodes. Any blocks must lie in segments that 602 * we've seen before (SEGUSE_DIRTY or SEGUSE_RFW); and the rest 603 * of the pass 1 checks as well. 604 */ 605 memset(&idesc, 0, sizeof(struct inodesc)); 606 idesc.id_type = ADDR; 607 idesc.id_func = pass6check; 608 idesc.id_lblkno = 0; 609 LIST_FOREACH(vp, &vnodelist, v_mntvnodes) { 610 if ((vp->v_flag & VDIROP) == 0) 611 --n_files; /* Don't double count */ 612 checkinode(VTOI(vp)->i_number, &idesc); 613 } 614 615 /* 616 * Second pass. Run through FINFO entries looking for blocks 617 * with the same generation number as files we've seen before. 618 * If they have it, pretend like we just wrote them. We don't 619 * do the pretend-write, though, if we've already seen them 620 * (the accounting would have been done for us already). 621 */ 622 daddr = fs->lfs_offset; 623 while (daddr != lastgood) { 624 if (!(seg_table[dtosn(fs, daddr)].su_flags & SEGUSE_DIRTY)) { 625 seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY; 626 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 627 sup->su_flags |= SEGUSE_DIRTY; 628 VOP_BWRITE(sbp); 629 } 630 oncemore2: 631 /* Read in summary block */ 632 bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp); 633 sp = (SEGSUM *)bp->b_data; 634 635 /* Could be a superblock instead of a segment summary. */ 636 if (sntod(fs, dtosn(fs, daddr)) == daddr && 637 (sp->ss_magic != SS_MAGIC || 638 sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize - 639 sizeof(sp->ss_sumsum)))) { 640 brelse(bp); 641 daddr += btofsb(fs, LFS_SBPAD); 642 goto oncemore2; 643 } 644 645 bc = check_summary(fs, sp, daddr, debug, devvp, pass6harvest); 646 if (bc == 0) { 647 brelse(bp); 648 break; 649 } 650 odaddr = daddr; 651 daddr += btofsb(fs, fs->lfs_sumsize + bc); 652 fs->lfs_avail -= btofsb(fs, fs->lfs_sumsize + bc); 653 if (dtosn(fs, odaddr) != dtosn(fs, daddr) || 654 dtosn(fs, daddr) != dtosn(fs, daddr + 655 btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize))) { 656 fs->lfs_avail -= sntod(fs, dtosn(fs, daddr) + 1) - daddr; 657 daddr = ((SEGSUM *)bp->b_data)->ss_next; 658 } 659 LFS_CLEANERINFO(cip, fs, cbp); 660 LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0); 661 bp->b_flags |= B_AGE; 662 brelse(bp); 663 } 664 665 /* Update offset to point at correct location */ 666 fs->lfs_offset = lastgood; 667 fs->lfs_curseg = sntod(fs, dtosn(fs, lastgood)); 668 fs->lfs_nextseg = nextseg; 669 670 if (!preen) { 671 /* Run pass 5 again (it's quick anyway). */ 672 pwarn("** Phase 6b - Recheck Segment Block Accounting\n"); 673 pass5(); 674 } 675 676 /* Likewise for pass 0 */ 677 if (!preen) 678 pwarn("** Phase 6c - Recheck Inode Free List\n"); 679 pass0(); 680 } 681