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