1 /* $NetBSD: pass6.c,v 1.20 2007/10/10 20:42:20 ad 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 <signal.h> 55 #include <string.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <util.h> 59 60 #include "bufcache.h" 61 #include "vnode.h" 62 #include "lfs_user.h" 63 #include "segwrite.h" 64 65 #include "fsck.h" 66 #include "extern.h" 67 #include "fsutil.h" 68 69 extern u_int32_t cksum(void *, size_t); 70 extern u_int32_t lfs_sb_cksum(struct dlfs *); 71 72 extern ufs_daddr_t badblk; 73 extern SEGUSE *seg_table; 74 75 static int nnewblocks; 76 77 /* 78 * Our own copy of lfs_update_single so we can account in seg_table 79 * as well as the Ifile; and so we can add the blocks to their new 80 * segment. 81 * 82 * Change the given block's address to ndaddr, finding its previous 83 * location using ufs_bmaparray(). 84 * 85 * Account for this change in the segment table. 86 */ 87 static void 88 rfw_update_single(struct uvnode *vp, daddr_t lbn, ufs_daddr_t ndaddr, int size) 89 { 90 SEGUSE *sup; 91 struct ubuf *bp; 92 struct indir a[NIADDR + 2], *ap; 93 struct inode *ip; 94 daddr_t daddr, ooff; 95 int num, error; 96 int i, bb, osize = 0, obb = 0; 97 u_int32_t oldsn, sn; 98 99 ip = VTOI(vp); 100 ip->i_flag |= IN_MODIFIED; 101 102 error = ufs_bmaparray(fs, vp, lbn, &daddr, a, &num); 103 if (error) 104 errx(1, "lfs_updatemeta: ufs_bmaparray returned %d" 105 " looking up lbn %" PRId64 "\n", error, lbn); 106 if (daddr > 0) 107 daddr = dbtofsb(fs, daddr); 108 109 bb = fragstofsb(fs, numfrags(fs, size)); 110 switch (num) { 111 case 0: 112 ooff = ip->i_ffs1_db[lbn]; 113 if (ooff <= 0) 114 ip->i_ffs1_blocks += bb; 115 else { 116 /* possible fragment truncation or extension */ 117 obb = btofsb(fs, ip->i_lfs_fragsize[lbn]); 118 ip->i_ffs1_blocks += (bb - obb); 119 } 120 ip->i_ffs1_db[lbn] = ndaddr; 121 break; 122 case 1: 123 ooff = ip->i_ffs1_ib[a[0].in_off]; 124 if (ooff <= 0) 125 ip->i_ffs1_blocks += bb; 126 ip->i_ffs1_ib[a[0].in_off] = ndaddr; 127 break; 128 default: 129 ap = &a[num - 1]; 130 if (bread(vp, ap->in_lbn, fs->lfs_bsize, NULL, &bp)) 131 errx(1, "lfs_updatemeta: bread bno %" PRId64, 132 ap->in_lbn); 133 134 ooff = ((ufs_daddr_t *) bp->b_data)[ap->in_off]; 135 if (ooff <= 0) 136 ip->i_ffs1_blocks += bb; 137 ((ufs_daddr_t *) bp->b_data)[ap->in_off] = ndaddr; 138 (void) VOP_BWRITE(bp); 139 } 140 141 /* 142 * Update segment usage information, based on old size 143 * and location. 144 */ 145 if (daddr > 0) { 146 oldsn = dtosn(fs, daddr); 147 if (lbn >= 0 && lbn < NDADDR) 148 osize = ip->i_lfs_fragsize[lbn]; 149 else 150 osize = fs->lfs_bsize; 151 LFS_SEGENTRY(sup, fs, oldsn, bp); 152 seg_table[oldsn].su_nbytes -= osize; 153 sup->su_nbytes -= osize; 154 if (!(bp->b_flags & B_GATHERED)) 155 fs->lfs_flags |= LFS_IFDIRTY; 156 LFS_WRITESEGENTRY(sup, fs, oldsn, bp); 157 for (i = 0; i < btofsb(fs, osize); i++) 158 clrbmap(daddr + i); 159 } 160 161 /* If block is beyond EOF, update size */ 162 if (lbn >= 0 && ip->i_ffs1_size <= (lbn << fs->lfs_bshift)) { 163 ip->i_ffs1_size = (lbn << fs->lfs_bshift) + 1; 164 } 165 166 /* If block frag size is too large for old EOF, update size */ 167 if (lbn < NDADDR) { 168 off_t minsize; 169 170 minsize = (lbn << fs->lfs_bshift); 171 minsize += (size - fs->lfs_fsize) + 1; 172 if (ip->i_ffs1_size < minsize) 173 ip->i_ffs1_size = minsize; 174 } 175 176 /* Count for the user */ 177 ++nnewblocks; 178 179 /* Add block to its new segment */ 180 sn = dtosn(fs, ndaddr); 181 LFS_SEGENTRY(sup, fs, sn, bp); 182 seg_table[sn].su_nbytes += size; 183 sup->su_nbytes += size; 184 if (!(bp->b_flags & B_GATHERED)) 185 fs->lfs_flags |= LFS_IFDIRTY; 186 LFS_WRITESEGENTRY(sup, fs, sn, bp); 187 for (i = 0; i < btofsb(fs, size); i++) 188 #ifndef VERBOSE_BLOCKMAP 189 setbmap(daddr + i); 190 #else 191 setbmap(daddr + i, ip->i_number); 192 #endif 193 194 /* Check bfree accounting as well */ 195 if (daddr <= 0) { 196 fs->lfs_bfree -= btofsb(fs, size); 197 } else if (size != osize) { 198 fs->lfs_bfree -= (bb - obb); 199 } 200 201 /* 202 * Now that this block has a new address, and its old 203 * segment no longer owns it, we can forget about its 204 * old size. 205 */ 206 if (lbn >= 0 && lbn < NDADDR) 207 ip->i_lfs_fragsize[lbn] = size; 208 } 209 210 /* 211 * Remove the vnode from the cache, including any blocks it 212 * may hold. Account the blocks. Finally account the removal 213 * of the inode from its segment. 214 */ 215 static void 216 remove_ino(struct uvnode *vp, ino_t ino) 217 { 218 IFILE *ifp; 219 SEGUSE *sup; 220 CLEANERINFO *cip; 221 struct ubuf *bp, *sbp, *cbp; 222 struct inodesc idesc; 223 ufs_daddr_t daddr; 224 int obfree; 225 226 if (debug) 227 pwarn("remove ino %d\n", (int)ino); 228 229 obfree = fs->lfs_bfree; 230 LFS_IENTRY(ifp, fs, ino, bp); 231 daddr = ifp->if_daddr; 232 if (daddr > 0) { 233 ifp->if_daddr = 0x0; 234 235 LFS_GET_HEADFREE(fs, cip, cbp, &(ifp->if_nextfree)); 236 VOP_BWRITE(bp); 237 LFS_PUT_HEADFREE(fs, cip, cbp, ino); 238 sbdirty(); 239 240 if (vp == NULL) 241 vp = lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr); 242 243 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 244 sup->su_nbytes -= DINODE1_SIZE; 245 VOP_BWRITE(sbp); 246 seg_table[dtosn(fs, daddr)].su_nbytes -= DINODE1_SIZE; 247 } else 248 brelse(bp, 0); 249 250 /* Do on-disk accounting */ 251 if (vp) { 252 idesc.id_number = ino; 253 idesc.id_func = pass4check; /* Delete dinode and blocks */ 254 idesc.id_type = ADDR; 255 idesc.id_lblkno = 0; 256 clri(&idesc, "unknown", 2); /* XXX magic number 2 */ 257 /* vp has been destroyed */ 258 } 259 } 260 261 /* 262 * Use FIP records to update blocks, if the generation number matches. 263 */ 264 static void 265 pass6harvest(ufs_daddr_t daddr, FINFO *fip) 266 { 267 struct uvnode *vp; 268 int i; 269 size_t size; 270 271 vp = vget(fs, fip->fi_ino); 272 if (vp && vp != fs->lfs_ivnode && 273 VTOI(vp)->i_ffs1_gen == fip->fi_version) { 274 for (i = 0; i < fip->fi_nblocks; i++) { 275 size = (i == fip->fi_nblocks - 1 ? 276 fip->fi_lastlength : fs->lfs_bsize); 277 if (debug) 278 pwarn("ino %lld lbn %lld -> 0x%lx\n", 279 (long long)fip->fi_ino, 280 (long long)fip->fi_blocks[i], 281 (long)daddr); 282 rfw_update_single(vp, fip->fi_blocks[i], daddr, size); 283 daddr += btofsb(fs, size); 284 } 285 } 286 } 287 288 /* 289 * Check validity of blocks on roll-forward inodes. 290 */ 291 int 292 pass6check(struct inodesc * idesc) 293 { 294 int i, sn, anyout, anynew; 295 296 /* Brand new blocks are always OK */ 297 if (idesc->id_blkno == UNWRITTEN) 298 return KEEPON; 299 300 /* Check that the blocks do not lie within clean segments. */ 301 anyout = anynew = 0; 302 for (i = 0; i < fragstofsb(fs, idesc->id_numfrags); i++) { 303 sn = dtosn(fs, idesc->id_blkno + i); 304 if (sn < 0 || sn >= fs->lfs_nseg || 305 (seg_table[sn].su_flags & SEGUSE_DIRTY) == 0) { 306 anyout = 1; 307 break; 308 } 309 if (seg_table[sn].su_flags & SEGUSE_ACTIVE) { 310 if (sn != dtosn(fs, fs->lfs_offset) || 311 idesc->id_blkno > fs->lfs_offset) { 312 ++anynew; 313 } 314 } 315 if (!anynew) { 316 /* Clear so pass1check won't be surprised */ 317 clrbmap(idesc->id_blkno + i); 318 seg_table[sn].su_nbytes -= fsbtob(fs, 1); 319 } 320 } 321 if (anyout) { 322 blkerror(idesc->id_number, "BAD", idesc->id_blkno); 323 if (badblk++ >= MAXBAD) { 324 pwarn("EXCESSIVE BAD BLKS I=%llu", 325 (unsigned long long)idesc->id_number); 326 if (preen) 327 pwarn(" (SKIPPING)\n"); 328 else if (reply("CONTINUE") == 0) 329 err(EEXIT, "%s", ""); 330 return (STOP); 331 } 332 } 333 334 return pass1check(idesc); 335 } 336 337 static void 338 account_indir(struct uvnode *vp, struct ufs1_dinode *dp, daddr_t ilbn, daddr_t daddr, int lvl) 339 { 340 struct ubuf *bp; 341 int32_t *dap, *odap, *buf, *obuf; 342 daddr_t lbn; 343 344 if (lvl == 0) 345 lbn = -ilbn; 346 else 347 lbn = ilbn + 1; 348 bread(fs->lfs_devvp, fsbtodb(fs, daddr), fs->lfs_bsize, NULL, &bp); 349 buf = emalloc(fs->lfs_bsize); 350 memcpy(buf, bp->b_data, fs->lfs_bsize); 351 brelse(bp, 0); 352 353 obuf = emalloc(fs->lfs_bsize); 354 if (vp) { 355 bread(vp, ilbn, fs->lfs_bsize, NULL, &bp); 356 memcpy(obuf, bp->b_data, fs->lfs_bsize); 357 brelse(bp, 0); 358 } else 359 memset(obuf, 0, fs->lfs_bsize); 360 361 for (dap = buf, odap = obuf; 362 dap < (int32_t *)((char *)buf + fs->lfs_bsize); 363 ++dap, ++odap) { 364 if (*dap > 0 && *dap != *odap) { 365 rfw_update_single(vp, lbn, *dap, dblksize(fs, dp, lbn)); 366 if (lvl > 0) 367 account_indir(vp, dp, lbn, *dap, lvl - 1); 368 } 369 if (lvl == 0) 370 ++lbn; 371 else if (lvl == 1) 372 lbn -= NINDIR(fs); 373 else if (lvl == 2) 374 lbn -= NINDIR(fs) * NINDIR(fs); 375 } 376 377 free(obuf); 378 free(buf); 379 } 380 381 /* 382 * Account block changes between new found inode and existing inode. 383 */ 384 static void 385 account_block_changes(struct ufs1_dinode *dp) 386 { 387 int i; 388 daddr_t lbn, off, odaddr; 389 struct uvnode *vp; 390 struct inode *ip; 391 392 vp = vget(fs, dp->di_inumber); 393 ip = (vp ? VTOI(vp) : NULL); 394 395 /* Check direct block holdings between existing and new */ 396 for (i = 0; i < NDADDR; i++) { 397 odaddr = (ip ? ip->i_ffs1_db[i] : 0x0); 398 if (dp->di_db[i] > 0 && dp->di_db[i] != odaddr) 399 rfw_update_single(vp, i, dp->di_db[i], 400 dblksize(fs, dp, i)); 401 } 402 403 /* Check indirect block holdings between existing and new */ 404 off = 0; 405 for (i = 0; i < NIADDR; i++) { 406 odaddr = (ip ? ip->i_ffs1_ib[i] : 0x0); 407 if (dp->di_ib[i] > 0 && dp->di_ib[i] != odaddr) { 408 lbn = -(NDADDR + off + i); 409 rfw_update_single(vp, i, dp->di_ib[i], fs->lfs_bsize); 410 account_indir(vp, dp, lbn, dp->di_ib[i], i); 411 } 412 if (off == 0) 413 off = NINDIR(fs); 414 else 415 off *= NINDIR(fs); 416 } 417 } 418 419 /* 420 * Give a previously allocated inode a new address; do segment 421 * accounting if necessary. 422 * 423 * Caller has ensured that this inode is not on the free list, so no 424 * free list accounting is done. 425 */ 426 static void 427 readdress_inode(struct ufs1_dinode *dp, ufs_daddr_t daddr) 428 { 429 IFILE *ifp; 430 SEGUSE *sup; 431 struct ubuf *bp; 432 int sn; 433 ufs_daddr_t odaddr; 434 ino_t thisino = dp->di_inumber; 435 struct uvnode *vp; 436 437 /* Recursively check all block holdings, account changes */ 438 account_block_changes(dp); 439 440 /* Move ifile pointer to this location */ 441 LFS_IENTRY(ifp, fs, thisino, bp); 442 odaddr = ifp->if_daddr; 443 assert(odaddr != 0); 444 ifp->if_daddr = daddr; 445 VOP_BWRITE(bp); 446 447 if (debug) 448 pwarn("readdress ino %d from 0x%x to 0x%x mode %o nlink %d\n", 449 (int)dp->di_inumber, 450 (unsigned)odaddr, 451 (unsigned)daddr, 452 (int)dp->di_mode, (int)dp->di_nlink); 453 454 /* Copy over preexisting in-core inode, if any */ 455 vp = vget(fs, thisino); 456 memcpy(VTOI(vp)->i_din.ffs1_din, dp, sizeof(*dp)); 457 458 /* Finally account the inode itself */ 459 sn = dtosn(fs, odaddr); 460 LFS_SEGENTRY(sup, fs, sn, bp); 461 sup->su_nbytes -= DINODE1_SIZE; 462 VOP_BWRITE(bp); 463 seg_table[sn].su_nbytes -= DINODE1_SIZE; 464 465 sn = dtosn(fs, daddr); 466 LFS_SEGENTRY(sup, fs, sn, bp); 467 sup->su_nbytes += DINODE1_SIZE; 468 VOP_BWRITE(bp); 469 seg_table[sn].su_nbytes += DINODE1_SIZE; 470 } 471 472 /* 473 * Allocate the given inode from the free list. 474 */ 475 static void 476 alloc_inode(ino_t thisino, ufs_daddr_t daddr) 477 { 478 ino_t ino, nextfree, oldhead; 479 IFILE *ifp; 480 SEGUSE *sup; 481 struct ubuf *bp, *cbp; 482 CLEANERINFO *cip; 483 484 if (debug) 485 pwarn("allocating ino %d at 0x%x\n", (int)thisino, 486 (unsigned)daddr); 487 while (thisino >= maxino) { 488 extend_ifile(fs); 489 } 490 491 LFS_IENTRY(ifp, fs, thisino, bp); 492 if (ifp->if_daddr != 0) { 493 pwarn("allocated inode %lld already allocated\n", 494 (long long)thisino); 495 } 496 nextfree = ifp->if_nextfree; 497 ifp->if_nextfree = 0; 498 ifp->if_daddr = daddr; 499 VOP_BWRITE(bp); 500 501 LFS_GET_HEADFREE(fs, cip, cbp, &oldhead); 502 if (oldhead == thisino) { 503 LFS_PUT_HEADFREE(fs, cip, cbp, nextfree); 504 sbdirty(); 505 if (nextfree == 0) { 506 extend_ifile(fs); 507 } 508 } else { 509 /* Search the free list for this inode */ 510 ino = oldhead; 511 while (ino) { 512 LFS_IENTRY(ifp, fs, ino, bp); 513 assert(ifp->if_nextfree != ino); 514 if (ifp->if_nextfree == thisino) { 515 ifp->if_nextfree = nextfree; 516 VOP_BWRITE(bp); 517 if (nextfree == 0) 518 LFS_PUT_TAILFREE(fs, cip, cbp, ino); 519 break; 520 } else 521 ino = ifp->if_nextfree; 522 brelse(bp, 0); 523 } 524 } 525 526 /* Account for new location */ 527 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), bp); 528 sup->su_nbytes += DINODE1_SIZE; 529 VOP_BWRITE(bp); 530 seg_table[dtosn(fs, daddr)].su_nbytes += DINODE1_SIZE; 531 } 532 533 /* 534 * Roll forward from the last verified checkpoint. 535 * 536 * Basic strategy: 537 * 538 * Run through the summaries finding the last valid partial segment. 539 * Note segment numbers as we go. For each inode that we find, compare 540 * its generation number; if newer than old inode's (or if old inode is 541 * USTATE), change to that inode. Recursively look at inode blocks that 542 * do not have their old disk addresses. These addresses must lie in 543 * segments we have seen already in our roll forward. 544 * 545 * A second pass through the past-checkpoint area verifies the validity 546 * of these new blocks, as well as updating other blocks that do not 547 * have corresponding new inodes (but their generation number must match 548 * the old generation number). 549 */ 550 void 551 pass6(void) 552 { 553 ufs_daddr_t daddr, ibdaddr, odaddr, lastgood, nextseg, *idaddrp; 554 struct uvnode *vp, *devvp; 555 CLEANERINFO *cip; 556 SEGUSE *sup; 557 SEGSUM *sp; 558 struct ubuf *bp, *ibp, *sbp, *cbp; 559 struct ufs1_dinode *dp; 560 struct inodesc idesc; 561 int i, j, bc, hassuper; 562 int nnewfiles, ndelfiles, nmvfiles; 563 int sn, curseg; 564 char *ibbuf; 565 long lastserial; 566 567 devvp = fs->lfs_devvp; 568 569 /* If we can't roll forward because of created files, don't try */ 570 if (no_roll_forward) { 571 if (debug) 572 pwarn("not rolling forward due to possible allocation conflict\n"); 573 return; 574 } 575 576 /* Find last valid partial segment */ 577 lastgood = try_verify(fs, devvp, 0, debug); 578 if (lastgood == fs->lfs_offset) { 579 if (debug) 580 pwarn("not rolling forward, nothing to recover\n"); 581 return; 582 } 583 584 if (debug) 585 pwarn("could roll forward from 0x%" PRIx32 " to 0x%" PRIx32 "\n", 586 fs->lfs_offset, lastgood); 587 588 if (!preen && reply("ROLL FORWARD") == 0) 589 return; 590 /* 591 * Pass 1: find inode blocks. We ignore the Ifile inode but accept 592 * changes to any other inode. 593 */ 594 595 ibbuf = emalloc(fs->lfs_ibsize); 596 nnewfiles = ndelfiles = nmvfiles = nnewblocks = 0; 597 daddr = fs->lfs_offset; 598 nextseg = fs->lfs_nextseg; 599 hassuper = 0; 600 lastserial = 0; 601 while (daddr != lastgood) { 602 seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE; 603 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 604 sup->su_flags |= SEGUSE_DIRTY; 605 VOP_BWRITE(sbp); 606 607 /* Could be a superblock */ 608 if (sntod(fs, dtosn(fs, daddr)) == daddr) { 609 if (daddr == fs->lfs_start) { 610 ++hassuper; 611 daddr += btofsb(fs, LFS_LABELPAD); 612 } 613 for (i = 0; i < LFS_MAXNUMSB; i++) { 614 if (daddr == fs->lfs_sboffs[i]) { 615 ++hassuper; 616 daddr += btofsb(fs, LFS_SBPAD); 617 } 618 if (daddr < fs->lfs_sboffs[i]) 619 break; 620 } 621 } 622 623 /* Read in summary block */ 624 bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp); 625 sp = (SEGSUM *)bp->b_data; 626 if (debug) 627 pwarn("sum at 0x%x: ninos=%d nfinfo=%d\n", 628 (unsigned)daddr, (int)sp->ss_ninos, 629 (int)sp->ss_nfinfo); 630 631 /* We have verified that this is a good summary. */ 632 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 633 ++sup->su_nsums; 634 VOP_BWRITE(sbp); 635 fs->lfs_bfree -= btofsb(fs, fs->lfs_sumsize); 636 fs->lfs_dmeta += btofsb(fs, fs->lfs_sumsize); 637 sbdirty(); 638 nextseg = sp->ss_next; 639 if (sntod(fs, dtosn(fs, daddr)) == daddr + 640 hassuper * btofsb(fs, LFS_SBPAD) && 641 dtosn(fs, daddr) != dtosn(fs, fs->lfs_offset)) { 642 --fs->lfs_nclean; 643 sbdirty(); 644 } 645 646 /* Find inodes, look at generation number. */ 647 if (sp->ss_ninos) { 648 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 649 sup->su_ninos += howmany(sp->ss_ninos, INOPB(fs)); 650 VOP_BWRITE(sbp); 651 fs->lfs_dmeta += btofsb(fs, howmany(sp->ss_ninos, 652 INOPB(fs)) * 653 fs->lfs_ibsize); 654 } 655 idaddrp = ((ufs_daddr_t *)((char *)bp->b_data + fs->lfs_sumsize)); 656 for (i = 0; i < howmany(sp->ss_ninos, INOPB(fs)); i++) { 657 ino_t *inums; 658 659 inums = ecalloc(INOPB(fs) + 1, sizeof(*inums)); 660 ibdaddr = *--idaddrp; 661 fs->lfs_bfree -= btofsb(fs, fs->lfs_ibsize); 662 sbdirty(); 663 bread(devvp, fsbtodb(fs, ibdaddr), fs->lfs_ibsize, 664 NOCRED, &ibp); 665 memcpy(ibbuf, ibp->b_data, fs->lfs_ibsize); 666 brelse(ibp, 0); 667 668 j = 0; 669 for (dp = (struct ufs1_dinode *)ibbuf; 670 dp < (struct ufs1_dinode *)ibbuf + INOPB(fs); 671 ++dp) { 672 if (dp->di_u.inumber == 0 || 673 dp->di_u.inumber == fs->lfs_ifile) 674 continue; 675 /* Basic sanity checks */ 676 if (dp->di_nlink < 0 677 #if 0 678 || dp->di_u.inumber < 0 679 || dp->di_size < 0 680 #endif 681 ) { 682 pwarn("BAD INODE AT 0x%" PRIx32 "\n", 683 ibdaddr); 684 brelse(bp, 0); 685 free(inums); 686 goto out; 687 } 688 689 vp = vget(fs, dp->di_u.inumber); 690 691 /* 692 * Four cases: 693 * (1) Invalid inode (nlink == 0). 694 * If currently allocated, remove. 695 */ 696 if (dp->di_nlink == 0) { 697 remove_ino(vp, dp->di_u.inumber); 698 ++ndelfiles; 699 continue; 700 } 701 /* 702 * (2) New valid inode, previously free. 703 * Nothing to do except account 704 * the inode itself, done after the 705 * loop. 706 */ 707 if (vp == NULL) { 708 if (!(sp->ss_flags & SS_DIROP)) 709 pfatal("NEW FILE IN NON-DIROP PARTIAL SEGMENT"); 710 else { 711 inums[j++] = dp->di_u.inumber; 712 nnewfiles++; 713 } 714 continue; 715 } 716 /* 717 * (3) Valid new version of previously 718 * allocated inode. Delete old file 719 * and proceed as in (2). 720 */ 721 if (vp && VTOI(vp)->i_ffs1_gen < dp->di_gen) { 722 remove_ino(vp, dp->di_u.inumber); 723 if (!(sp->ss_flags & SS_DIROP)) 724 pfatal("NEW FILE VERSION IN NON-DIROP PARTIAL SEGMENT"); 725 else { 726 inums[j++] = dp->di_u.inumber; 727 ndelfiles++; 728 nnewfiles++; 729 } 730 continue; 731 } 732 /* 733 * (4) Same version of previously 734 * allocated inode. Move inode to 735 * this location, account inode change 736 * only. We'll pick up any new 737 * blocks when we do the block pass. 738 */ 739 if (vp && VTOI(vp)->i_ffs1_gen == dp->di_gen) { 740 nmvfiles++; 741 readdress_inode(dp, ibdaddr); 742 743 /* Update with new info */ 744 VTOD(vp)->di_mode = dp->di_mode; 745 VTOD(vp)->di_nlink = dp->di_nlink; 746 /* XXX size is important */ 747 VTOD(vp)->di_size = dp->di_size; 748 VTOD(vp)->di_atime = dp->di_atime; 749 VTOD(vp)->di_atimensec = dp->di_atimensec; 750 VTOD(vp)->di_mtime = dp->di_mtime; 751 VTOD(vp)->di_mtimensec = dp->di_mtimensec; 752 VTOD(vp)->di_ctime = dp->di_ctime; 753 VTOD(vp)->di_ctimensec = dp->di_ctimensec; 754 VTOD(vp)->di_flags = dp->di_flags; 755 VTOD(vp)->di_uid = dp->di_uid; 756 VTOD(vp)->di_gid = dp->di_gid; 757 inodirty(VTOI(vp)); 758 } 759 } 760 for (j = 0; inums[j]; j++) { 761 alloc_inode(inums[j], ibdaddr); 762 vp = lfs_raw_vget(fs, inums[j], 763 devvp->v_fd, ibdaddr); 764 /* We'll get the blocks later */ 765 if (debug) 766 pwarn("alloc ino %d nlink %d\n", 767 (int)inums[j], VTOD(vp)->di_nlink); 768 memset(VTOD(vp)->di_db, 0, (NDADDR + NIADDR) * 769 sizeof(ufs_daddr_t)); 770 VTOD(vp)->di_blocks = 0; 771 772 vp->v_uflag |= VU_DIROP; 773 inodirty(VTOI(vp)); 774 } 775 free(inums); 776 } 777 778 bc = check_summary(fs, sp, daddr, debug, devvp, NULL); 779 if (bc == 0) { 780 pwarn("unexpected bad seg ptr at 0x%x with serial=%d\n", 781 (int)daddr, (int)sp->ss_serial); 782 brelse(bp, 0); 783 break; 784 } else { 785 if (debug) 786 pwarn("good seg ptr at 0x%x with serial=%d\n", 787 (int)daddr, (int)sp->ss_serial); 788 lastserial = sp->ss_serial; 789 } 790 odaddr = daddr; 791 daddr += btofsb(fs, fs->lfs_sumsize + bc); 792 if (dtosn(fs, odaddr) != dtosn(fs, daddr) || 793 dtosn(fs, daddr) != dtosn(fs, daddr + 794 btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize) - 1)) { 795 daddr = ((SEGSUM *)bp->b_data)->ss_next; 796 } 797 brelse(bp, 0); 798 } 799 800 out: 801 free(ibbuf); 802 803 /* Set serial here, just to be sure (XXX should be right already) */ 804 fs->lfs_serial = lastserial + 1; 805 806 /* 807 * Check our new vnodes. Any blocks must lie in segments that 808 * we've seen before (SEGUSE_DIRTY or SEGUSE_RFW); and the rest 809 * of the pass 1 checks as well. 810 */ 811 memset(&idesc, 0, sizeof(struct inodesc)); 812 idesc.id_type = ADDR; 813 idesc.id_func = pass6check; 814 idesc.id_lblkno = 0; 815 LIST_FOREACH(vp, &vnodelist, v_mntvnodes) { 816 if ((vp->v_uflag & VU_DIROP) == 0) 817 --n_files; /* Don't double count */ 818 checkinode(VTOI(vp)->i_number, &idesc); 819 } 820 821 /* 822 * Second pass. Run through FINFO entries looking for blocks 823 * with the same generation number as files we've seen before. 824 * If they have it, pretend like we just wrote them. We don't 825 * do the pretend-write, though, if we've already seen them 826 * (the accounting would have been done for us already). 827 */ 828 daddr = fs->lfs_offset; 829 while (daddr != lastgood) { 830 if (!(seg_table[dtosn(fs, daddr)].su_flags & SEGUSE_DIRTY)) { 831 seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY; 832 LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); 833 sup->su_flags |= SEGUSE_DIRTY; 834 VOP_BWRITE(sbp); 835 } 836 837 /* Could be a superblock */ 838 if (sntod(fs, dtosn(fs, daddr)) == daddr) { 839 if (daddr == fs->lfs_start) 840 daddr += btofsb(fs, LFS_LABELPAD); 841 for (i = 0; i < LFS_MAXNUMSB; i++) { 842 if (daddr == fs->lfs_sboffs[i]) { 843 daddr += btofsb(fs, LFS_SBPAD); 844 } 845 if (daddr < fs->lfs_sboffs[i]) 846 break; 847 } 848 } 849 850 /* Read in summary block */ 851 bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp); 852 sp = (SEGSUM *)bp->b_data; 853 bc = check_summary(fs, sp, daddr, debug, devvp, pass6harvest); 854 if (bc == 0) { 855 pwarn("unexpected bad seg ptr [2] at 0x%x with serial=%d\n", 856 (int)daddr, (int)sp->ss_serial); 857 brelse(bp, 0); 858 break; 859 } 860 odaddr = daddr; 861 daddr += btofsb(fs, fs->lfs_sumsize + bc); 862 fs->lfs_avail -= btofsb(fs, fs->lfs_sumsize + bc); 863 if (dtosn(fs, odaddr) != dtosn(fs, daddr) || 864 dtosn(fs, daddr) != dtosn(fs, daddr + 865 btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize) - 1)) { 866 fs->lfs_avail -= sntod(fs, dtosn(fs, daddr) + 1) - daddr; 867 daddr = ((SEGSUM *)bp->b_data)->ss_next; 868 } 869 LFS_CLEANERINFO(cip, fs, cbp); 870 LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0); 871 bp->b_flags |= B_AGE; 872 brelse(bp, 0); 873 } 874 875 /* Final address could also be a superblock */ 876 if (sntod(fs, dtosn(fs, lastgood)) == lastgood) { 877 if (lastgood == fs->lfs_start) 878 lastgood += btofsb(fs, LFS_LABELPAD); 879 for (i = 0; i < LFS_MAXNUMSB; i++) { 880 if (lastgood == fs->lfs_sboffs[i]) 881 lastgood += btofsb(fs, LFS_SBPAD); 882 if (lastgood < fs->lfs_sboffs[i]) 883 break; 884 } 885 } 886 887 /* Update offset to point at correct location */ 888 fs->lfs_offset = lastgood; 889 fs->lfs_curseg = sntod(fs, dtosn(fs, lastgood)); 890 for (sn = curseg = dtosn(fs, fs->lfs_curseg);;) { 891 sn = (sn + 1) % fs->lfs_nseg; 892 if (sn == curseg) 893 errx(1, "no clean segments"); 894 LFS_SEGENTRY(sup, fs, sn, bp); 895 if ((sup->su_flags & SEGUSE_DIRTY) == 0) { 896 sup->su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE; 897 VOP_BWRITE(bp); 898 break; 899 } 900 brelse(bp, 0); 901 } 902 fs->lfs_nextseg = sntod(fs, sn); 903 904 if (preen) { 905 if (ndelfiles) 906 pwarn("roll forward deleted %d file%s\n", ndelfiles, 907 (ndelfiles > 1 ? "s" : "")); 908 if (nnewfiles) 909 pwarn("roll forward added %d file%s\n", nnewfiles, 910 (nnewfiles > 1 ? "s" : "")); 911 if (nmvfiles) 912 pwarn("roll forward relocated %d inode%s\n", nmvfiles, 913 (nmvfiles > 1 ? "s" : "")); 914 if (nnewblocks) 915 pwarn("roll forward verified %d data block%s\n", nnewblocks, 916 (nnewblocks > 1 ? "s" : "")); 917 if (ndelfiles == 0 && nnewfiles == 0 && nmvfiles == 0 && 918 nnewblocks == 0) 919 pwarn("roll forward produced nothing new\n"); 920 } 921 922 if (!preen) { 923 /* Run pass 5 again (it's quick anyway). */ 924 pwarn("** Phase 6b - Recheck Segment Block Accounting\n"); 925 pass5(); 926 } 927 928 /* Likewise for pass 0 */ 929 if (!preen) 930 pwarn("** Phase 6c - Recheck Inode Free List\n"); 931 pass0(); 932 } 933