1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/mntent.h> 35 #include <sys/fs/ufs_fs.h> 36 #include <sys/vnode.h> 37 #define _KERNEL 38 #include <sys/fs/ufs_fsdir.h> 39 #undef _KERNEL 40 #include <sys/fs/ufs_inode.h> 41 #include "fsck.h" 42 43 /* 44 * for each large file (size > MAXOFF_T), the global largefile_count 45 * gets incremented during this pass. 46 */ 47 48 static uint32_t badblk; /* number seen for the current inode */ 49 static uint32_t dupblk; /* number seen for the current inode */ 50 51 static void clear_attr_acl(fsck_ino_t, fsck_ino_t, char *); 52 static void verify_inode(fsck_ino_t, struct inodesc *, fsck_ino_t); 53 static void check_dirholes(fsck_ino_t, struct inodesc *); 54 static void collapse_dirhole(fsck_ino_t, struct inodesc *); 55 static void note_used(daddr32_t); 56 57 void 58 pass1(void) 59 { 60 uint_t c, i; 61 daddr32_t cgd; 62 struct inodesc idesc; 63 fsck_ino_t inumber; 64 fsck_ino_t maxinumber; 65 66 /* 67 * Set file system reserved blocks in used block map. 68 */ 69 for (c = 0; c < sblock.fs_ncg; c++) { 70 cgd = cgdmin(&sblock, c); 71 if (c == 0) { 72 /* 73 * Doing the first cylinder group, account for 74 * the cg summaries as well. 75 */ 76 i = cgbase(&sblock, c); 77 cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); 78 } else { 79 i = cgsblock(&sblock, c); 80 } 81 for (; i < cgd; i++) { 82 note_used(i); 83 } 84 } 85 /* 86 * Note blocks being used by the log, so we don't declare 87 * them as available and some time in the future we get a 88 * freeing free block panic. 89 */ 90 if (islog && islogok && sblock.fs_logbno) 91 examinelog(¬e_used); 92 93 /* 94 * Find all allocated blocks. This must be completed before 95 * we read the contents of any directories, as dirscan() et al 96 * don't want to know about block allocation holes. So, part 97 * of this pass is to truncate any directories with holes to 98 * just before those holes, so dirscan() can remain blissfully 99 * ignorant. 100 */ 101 inumber = 0; 102 n_files = n_blks = 0; 103 resetinodebuf(); 104 maxinumber = sblock.fs_ncg * sblock.fs_ipg; 105 for (c = 0; c < sblock.fs_ncg; c++) { 106 for (i = 0; i < sblock.fs_ipg; i++, inumber++) { 107 if (inumber < UFSROOTINO) 108 continue; 109 init_inodesc(&idesc); 110 idesc.id_type = ADDR; 111 idesc.id_func = pass1check; 112 verify_inode(inumber, &idesc, maxinumber); 113 } 114 } 115 freeinodebuf(); 116 } 117 118 /* 119 * Perform checks on an inode and setup/track the state of the inode 120 * in maps (statemap[], lncntp[]) for future reference and validation. 121 * Initiate the calls to ckinode and in turn pass1check() to handle 122 * further validation. 123 */ 124 static void 125 verify_inode(fsck_ino_t inumber, struct inodesc *idesc, fsck_ino_t maxinumber) 126 { 127 int j, clear, flags; 128 int isdir; 129 char *err; 130 fsck_ino_t shadow, attrinode; 131 daddr32_t ndb; 132 struct dinode *dp; 133 struct inoinfo *iip; 134 135 dp = getnextinode(inumber); 136 if ((dp->di_mode & IFMT) == 0) { 137 /* mode and type of file is not set */ 138 if ((memcmp((void *)dp->di_db, (void *)zino.di_db, 139 NDADDR * sizeof (daddr32_t)) != 0) || 140 (memcmp((void *)dp->di_ib, (void *)zino.di_ib, 141 NIADDR * sizeof (daddr32_t)) != 0) || 142 (dp->di_mode != 0) || (dp->di_size != 0)) { 143 pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber); 144 if (reply("CLEAR") == 1) { 145 dp = ginode(inumber); 146 clearinode(dp); 147 inodirty(); 148 } else { 149 iscorrupt = 1; 150 } 151 } 152 statemap[inumber] = USTATE; 153 return; 154 } 155 156 isdir = ((dp->di_mode & IFMT) == IFDIR) || 157 ((dp->di_mode & IFMT) == IFATTRDIR); 158 159 lastino = inumber; 160 if (dp->di_size > (u_offset_t)UFS_MAXOFFSET_T) { 161 pfatal("NEGATIVE SIZE %lld I=%d", 162 (longlong_t)dp->di_size, inumber); 163 goto bogus; 164 } 165 166 /* 167 * A more precise test of the type is done later on. Just get 168 * rid of the blatantly-wrong ones before we do any 169 * significant work. 170 */ 171 if ((dp->di_mode & IFMT) == IFMT) { 172 pfatal("BAD MODE 0%o I=%d", 173 dp->di_mode & IFMT, inumber); 174 if (reply("BAD MODE: MAKE IT A FILE") == 1) { 175 statemap[inumber] = FSTATE; 176 dp = ginode(inumber); 177 dp->di_mode = IFREG | 0600; 178 inodirty(); 179 truncino(inumber, sblock.fs_fsize, TI_NOPARENT); 180 dp = getnextrefresh(); 181 } else { 182 iscorrupt = 1; 183 } 184 } 185 186 ndb = howmany(dp->di_size, (u_offset_t)sblock.fs_bsize); 187 if (ndb < 0) { 188 /* extra space to distinguish from previous pfatal() */ 189 pfatal("NEGATIVE SIZE %lld I=%d", 190 (longlong_t)dp->di_size, inumber); 191 goto bogus; 192 } 193 194 if ((dp->di_mode & IFMT) == IFBLK || 195 (dp->di_mode & IFMT) == IFCHR) { 196 if (dp->di_size != 0) { 197 pfatal("SPECIAL FILE WITH NON-ZERO LENGTH %lld I=%d", 198 (longlong_t)dp->di_size, inumber); 199 goto bogus; 200 } 201 202 for (j = 0; j < NDADDR; j++) { 203 /* 204 * It's a device, so all the block pointers 205 * should be zero except for di_ordev. 206 * di_ordev is overlayed on the block array, 207 * but where varies between big and little 208 * endian, so make sure that the only non-zero 209 * element is the correct one. There can be 210 * a device whose ordev is zero, so we can't 211 * check for the reverse. 212 */ 213 if (dp->di_db[j] != 0 && 214 &dp->di_db[j] != &dp->di_ordev) { 215 if (debug) { 216 (void) printf( 217 "spec file di_db[%d] has %d\n", 218 j, dp->di_db[j]); 219 } 220 pfatal( 221 "SPECIAL FILE WITH NON-ZERO FRAGMENT LIST I=%d", 222 inumber); 223 goto bogus; 224 } 225 } 226 227 for (j = 0; j < NIADDR; j++) { 228 if (dp->di_ib[j] != 0) { 229 if (debug) 230 (void) printf( 231 "special has %d at ib[%d]\n", 232 dp->di_ib[j], j); 233 pfatal( 234 "SPECIAL FILE WITH NON-ZERO FRAGMENT LIST I=%d", 235 inumber); 236 goto bogus; 237 } 238 } 239 } else { 240 /* 241 * This assignment is mostly here to appease lint, but 242 * doesn't hurt. 243 */ 244 err = "Internal error: unexpected variant of having " 245 "blocks past end of file I=%d"; 246 247 clear = 0; 248 249 /* 250 * If it's not a device, it has to follow the 251 * rules for files. In particular, no blocks after 252 * the last one that di_size says is in use. 253 */ 254 for (j = ndb; j < NDADDR; j++) { 255 if (dp->di_db[j] != 0) { 256 if (debug) { 257 (void) printf("bad file direct " 258 "addr[%d]: block 0x%x " 259 "format: 0%o\n", 260 j, dp->di_db[j], 261 dp->di_mode & IFMT); 262 } 263 err = "FILE WITH FRAGMENTS PAST END I=%d"; 264 clear = 1; 265 break; 266 } 267 } 268 269 /* 270 * Find last indirect pointer that should be in use, 271 * and make sure any after it are clear. 272 */ 273 if (!clear) { 274 for (j = 0, ndb -= NDADDR; ndb > 0; j++) { 275 ndb /= NINDIR(&sblock); 276 } 277 for (; j < NIADDR; j++) { 278 if (dp->di_ib[j] != 0) { 279 if (debug) { 280 (void) printf("bad file " 281 "indirect addr: block %d\n", 282 dp->di_ib[j]); 283 } 284 err = 285 "FILE WITH FRAGMENTS PAST END I=%d"; 286 clear = 2; 287 break; 288 } 289 } 290 } 291 292 if (clear) { 293 /* 294 * The discarded blocks will be garbage- 295 * collected in pass5. If we're told not to 296 * discard them, it's just lost blocks, which 297 * isn't worth setting iscorrupt for. 298 */ 299 pwarn(err, inumber); 300 if (preen || reply("DISCARD EXCESS FRAGMENTS") == 1) { 301 dp = ginode(inumber); 302 if (clear == 1) { 303 for (; j < NDADDR; j++) 304 dp->di_db[j] = 0; 305 j = 0; 306 } 307 for (; j < NIADDR; j++) 308 dp->di_ib[j] = 0; 309 inodirty(); 310 dp = getnextrefresh(); 311 if (preen) 312 (void) printf(" (TRUNCATED)"); 313 } 314 } 315 } 316 317 if (ftypeok(dp) == 0) { 318 pfatal("UNKNOWN FILE TYPE 0%o I=%d", dp->di_mode, inumber); 319 goto bogus; 320 } 321 n_files++; 322 TRACK_LNCNTP(inumber, lncntp[inumber] = dp->di_nlink); 323 324 /* 325 * We can't do anything about it right now, so note that its 326 * processing is being delayed. Otherwise, we'd be changing 327 * the block allocations out from under ourselves, which causes 328 * no end of confusion. 329 */ 330 flags = statemap[inumber] & INDELAYD; 331 332 /* 333 * if errorlocked or logging, then open deleted files will 334 * manifest as di_nlink <= 0 and di_mode != 0 335 * so skip them; they're ok. 336 * Also skip anything already marked to be cleared. 337 */ 338 if (dp->di_nlink <= 0 && 339 !((errorlocked || islog) && dp->di_mode == 0) && 340 !(flags & INCLEAR)) { 341 flags |= INZLINK; 342 if (debug) 343 (void) printf( 344 "marking i=%d INZLINK; nlink %d, mode 0%o, islog %d\n", 345 inumber, dp->di_nlink, dp->di_mode, islog); 346 } 347 348 switch (dp->di_mode & IFMT) { 349 case IFDIR: 350 case IFATTRDIR: 351 if (dp->di_size == 0) { 352 /* 353 * INCLEAR means it will be ignored by passes 2 & 3. 354 */ 355 if ((dp->di_mode & IFMT) == IFDIR) 356 (void) printf("ZERO-LENGTH DIR I=%d\n", 357 inumber); 358 else 359 (void) printf("ZERO-LENGTH ATTRDIR I=%d\n", 360 inumber); 361 add_orphan_dir(inumber); 362 flags |= INCLEAR; 363 flags &= ~INZLINK; /* It will be cleared anyway */ 364 } 365 statemap[inumber] = DSTATE | flags; 366 cacheino(dp, inumber); 367 countdirs++; 368 break; 369 370 case IFSHAD: 371 if (dp->di_size == 0) { 372 (void) printf("ZERO-LENGTH SHADOW I=%d\n", inumber); 373 flags |= INCLEAR; 374 flags &= ~INZLINK; /* It will be cleared anyway */ 375 } 376 statemap[inumber] = SSTATE | flags; 377 cacheacl(dp, inumber); 378 break; 379 380 default: 381 statemap[inumber] = FSTATE | flags; 382 } 383 384 badblk = 0; 385 dupblk = 0; 386 idesc->id_number = inumber; 387 idesc->id_fix = DONTKNOW; 388 if (dp->di_size > (u_offset_t)MAXOFF_T) { 389 largefile_count++; 390 } 391 392 (void) ckinode(dp, idesc, CKI_TRAVERSE); 393 if (isdir && (idesc->id_firsthole >= 0)) 394 check_dirholes(inumber, idesc); 395 396 if (dp->di_blocks != idesc->id_entryno) { 397 /* 398 * The kernel releases any blocks it finds in the lists, 399 * ignoring the block count itself. So, a bad count is 400 * not grounds for setting iscorrupt. 401 */ 402 pwarn("INCORRECT DISK BLOCK COUNT I=%u (%d should be %d)", 403 inumber, (uint32_t)dp->di_blocks, idesc->id_entryno); 404 if (!preen && (reply("CORRECT") == 0)) 405 return; 406 dp = ginode(inumber); 407 dp->di_blocks = idesc->id_entryno; 408 iip = getinoinfo(inumber); 409 if (iip != NULL) 410 iip->i_isize = dp->di_size; 411 inodirty(); 412 if (preen) 413 (void) printf(" (CORRECTED)\n"); 414 } 415 if (isdir && (dp->di_blocks == 0)) { 416 /* 417 * INCLEAR will cause passes 2 and 3 to skip it. 418 */ 419 (void) printf("DIR WITH ZERO BLOCKS I=%d\n", inumber); 420 statemap[inumber] = DCLEAR; 421 add_orphan_dir(inumber); 422 } 423 424 /* 425 * Check that the ACL is on a valid file type 426 */ 427 shadow = dp->di_shadow; 428 if (shadow != 0) { 429 if (acltypeok(dp) == 0) { 430 clear_attr_acl(inumber, -1, 431 "NON-ZERO ACL REFERENCE, I=%d\n"); 432 } else if ((shadow <= UFSROOTINO) || 433 (shadow > maxinumber)) { 434 clear_attr_acl(inumber, -1, 435 "BAD ACL REFERENCE I=%d\n"); 436 } else { 437 registershadowclient(shadow, 438 inumber, &shadowclientinfo); 439 } 440 } 441 442 attrinode = dp->di_oeftflag; 443 if (attrinode != 0) { 444 if ((attrinode <= UFSROOTINO) || 445 (attrinode > maxinumber)) { 446 clear_attr_acl(attrinode, inumber, 447 "BAD ATTRIBUTE REFERENCE TO I=%d FROM I=%d\n"); 448 } else { 449 dp = ginode(attrinode); 450 if ((dp->di_mode & IFMT) != IFATTRDIR) { 451 clear_attr_acl(attrinode, inumber, 452 "BAD ATTRIBUTE DIR REF TO I=%d FROM I=%d\n"); 453 } else if (dp->di_size == 0) { 454 clear_attr_acl(attrinode, inumber, 455 "REFERENCE TO ZERO-LENGTH ATTRIBUTE DIR I=%d from I=%d\n"); 456 } else { 457 registershadowclient(attrinode, inumber, 458 &attrclientinfo); 459 } 460 } 461 } 462 return; 463 464 /* 465 * If we got here, we've not had the chance to see if a 466 * directory has holes, but we know the directory's bad, 467 * so it's safe to always return false (no holes found). 468 * 469 * Also, a pfatal() is always done before jumping here, so 470 * we know we're not in preen mode. 471 */ 472 bogus: 473 if (isdir) { 474 /* 475 * INCLEAR makes passes 2 & 3 skip it. 476 */ 477 statemap[inumber] = DCLEAR; 478 add_orphan_dir(inumber); 479 cacheino(dp, inumber); 480 } else { 481 statemap[inumber] = FCLEAR; 482 } 483 if (reply("CLEAR") == 1) { 484 (void) tdelete((void *)inumber, &limbo_dirs, ino_t_cmp); 485 freeino(inumber, TI_PARENT); 486 inodirty(); 487 } else { 488 iscorrupt = 1; 489 } 490 } 491 492 /* 493 * Do fixup for bad acl/attr references. If PARENT is -1, then 494 * we assume we're working on a shadow, otherwise an extended attribute. 495 * FMT must be a printf format string, with one %d directive for 496 * the inode number. 497 */ 498 static void 499 clear_attr_acl(fsck_ino_t inumber, fsck_ino_t parent, char *fmt) 500 { 501 fsck_ino_t victim = inumber; 502 struct dinode *dp; 503 504 if (parent != -1) 505 victim = parent; 506 507 if (fmt != NULL) { 508 if (parent == -1) 509 pwarn(fmt, (int)inumber); 510 else 511 pwarn(fmt, (int)inumber, (int)parent); 512 } 513 514 if (debug) 515 (void) printf("parent file/dir I=%d\nvictim I=%d", 516 (int)parent, (int)victim); 517 518 if (!preen && (reply("REMOVE REFERENCE") == 0)) { 519 iscorrupt = 1; 520 return; 521 } 522 523 dp = ginode(victim); 524 if (parent == -1) { 525 /* 526 * The file had a bad shadow/acl, so lock it down 527 * until someone can protect it the way they need it 528 * to be (i.e., be conservatively paranoid). 529 */ 530 dp->di_shadow = 0; 531 dp->di_mode &= IFMT; 532 } else { 533 dp->di_oeftflag = 0; 534 } 535 536 inodirty(); 537 if (preen) 538 (void) printf(" (CORRECTED)\n"); 539 } 540 541 /* 542 * Check if we have holes in the directory's indirect 543 * blocks. If there are, get rid of everything after 544 * the first hole. 545 */ 546 static void 547 check_dirholes(fsck_ino_t inumber, struct inodesc *idesc) 548 { 549 char pathbuf[MAXPATHLEN + 1]; 550 551 getpathname(pathbuf, idesc->id_number, idesc->id_number); 552 pfatal("I=%d DIRECTORY %s: CONTAINS EMPTY BLOCKS", 553 idesc->id_number, pathbuf); 554 if (reply("TRUNCATE AT FIRST EMPTY BLOCK") == 1) { 555 /* 556 * We found a hole, so get rid of it. 557 */ 558 collapse_dirhole(inumber, idesc); 559 560 if (preen) 561 (void) printf(" (TRUNCATED)\n"); 562 } else { 563 iscorrupt = 1; 564 } 565 } 566 567 /* 568 * Truncate a directory to its first hole. If there are non-holes 569 * in the direct blocks after the problem block, move them down so 570 * that there's somewhat less lossage. Doing this for indirect blocks 571 * is left as an exercise for the reader. 572 */ 573 static void 574 collapse_dirhole(fsck_ino_t inumber, struct inodesc *idesc) 575 { 576 offset_t new_size; 577 int blocks; 578 579 if (idesc->id_firsthole < 0) { 580 return; 581 } 582 583 /* 584 * Since truncino() adjusts the size, we don't need to do that here, 585 * but we have to tell it what final size we want. 586 * 587 * We need to count from block zero up through the last block 588 * before the hole. If the hole is in the indirect blocks, chop at 589 * the start of the nearest level of indirection. Orphans will 590 * get reconnected, so we're not actually losing anything by doing 591 * it this way, and we're simplifying truncation significantly. 592 */ 593 new_size = idesc->id_firsthole * (offset_t)sblock.fs_bsize; 594 blocks = howmany(new_size, sblock.fs_bsize); 595 if (blocks > NDADDR) { 596 if (blocks < (NDADDR + NINDIR(&sblock))) 597 blocks = NDADDR; 598 else if (blocks < (NDADDR + NINDIR(&sblock) + 599 (NINDIR(&sblock) * NINDIR(&sblock)))) 600 blocks = NDADDR + NINDIR(&sblock); 601 else 602 blocks = NDADDR + NINDIR(&sblock) + 603 (NINDIR(&sblock) * NINDIR(&sblock)); 604 new_size = blocks * sblock.fs_bsize; 605 if (debug) 606 (void) printf("to %lld (blocks %d)\n", 607 (longlong_t)new_size, blocks); 608 } 609 truncino(inumber, new_size, TI_NOPARENT); 610 611 /* 612 * Technically, there are still the original number of fragments 613 * associated with the object. However, that number is not used 614 * to control anything, so we can do the in-memory truncation of 615 * it without bad things happening. 616 */ 617 idesc->id_entryno = btodb(new_size); 618 } 619 620 int 621 pass1check(struct inodesc *idesc) 622 { 623 int res = KEEPON; 624 int anyout; 625 int nfrags; 626 daddr32_t lbn; 627 daddr32_t fragno = idesc->id_blkno; 628 struct dinode *dp; 629 630 /* 631 * If this is a fallocate'd file, block numbers may be stored 632 * as negative. In that case negate the negative numbers. 633 */ 634 dp = ginode(idesc->id_number); 635 if (dp->di_cflags & IFALLOCATE && fragno < 0) 636 fragno = -fragno; 637 638 if ((anyout = chkrange(fragno, idesc->id_numfrags)) != 0) { 639 /* 640 * Note that blkerror() exits when preening. 641 */ 642 blkerror(idesc->id_number, "OUT OF RANGE", 643 fragno, idesc->id_lbn * sblock.fs_frag); 644 645 dp = ginode(idesc->id_number); 646 if ((((dp->di_mode & IFMT) == IFDIR) || 647 ((dp->di_mode & IFMT) == IFATTRDIR)) && 648 (idesc->id_firsthole < 0)) { 649 idesc->id_firsthole = idesc->id_lbn; 650 } 651 652 if (++badblk >= MAXBAD) { 653 pwarn("EXCESSIVE BAD FRAGMENTS I=%u", 654 idesc->id_number); 655 if (reply("CONTINUE") == 0) 656 errexit("Program terminated."); 657 /* 658 * See discussion below as to why we don't 659 * want to short-circuit the processing of 660 * this inode. However, we know that this 661 * particular block is bad, so we don't need 662 * to go through the dup check loop. 663 */ 664 return (SKIP | STOP); 665 } 666 } 667 668 /* 669 * For each fragment, verify that it is a legal one (either 670 * by having already found the entire run to be legal, or by 671 * individual inspection), and if it is legal, see if we've 672 * seen it before or not. If we haven't, note that we've seen 673 * it and continue on. If we have (our in-core bitmap shows 674 * it as already being busy), then this must be a duplicate 675 * allocation. Whine and moan accordingly. 676 * 677 * Note that for full-block allocations, this will produce 678 * a complaint for each fragment making up the block (i.e., 679 * fs_frags' worth). Among other things, this could be 680 * considered artificially inflating the dup-block count. 681 * However, since it is possible that one file has a full 682 * fs block allocated, but another is only claiming a frag 683 * or two out of the middle, we'll just live it. 684 */ 685 for (nfrags = 0; nfrags < idesc->id_numfrags; fragno++, nfrags++) { 686 if (anyout && chkrange(fragno, 1)) { 687 /* bad fragment number */ 688 res = SKIP; 689 } else if (!testbmap(fragno)) { 690 /* no other claims seen as yet */ 691 note_used(fragno); 692 } else { 693 /* 694 * We have a duplicate claim for the same fragment. 695 * 696 * blkerror() exits when preening. 697 * 698 * We want to report all the dups up until 699 * hitting MAXDUP. Fortunately, blkerror()'s 700 * side-effects on statemap[] are idempotent, 701 * so the ``extra'' calls are harmless. 702 */ 703 lbn = idesc->id_lbn * sblock.fs_frag + nfrags; 704 if (dupblk < MAXDUP) 705 blkerror(idesc->id_number, "DUP", fragno, lbn); 706 707 /* 708 * Use ==, so we only complain once, no matter 709 * how far over the limit we end up going. 710 */ 711 if (++dupblk == MAXDUP) { 712 pwarn("EXCESSIVE DUPLICATE FRAGMENTS I=%u", 713 idesc->id_number); 714 if (reply("CONTINUE") == 0) 715 errexit("Program terminated."); 716 717 /* 718 * If we stop the traversal here, then 719 * there may be more dups in the 720 * inode's block list that don't get 721 * flagged. Later, if we're told to 722 * clear one of the files claiming 723 * these blocks, but not the other, we 724 * will release blocks that are 725 * actually still in use. An additional 726 * fsck run would be necessary to undo 727 * the damage. So, instead of the 728 * traditional return (STOP) when told 729 * to continue, we really do just continue. 730 */ 731 } 732 (void) find_dup_ref(fragno, idesc->id_number, lbn, 733 DB_CREATE | DB_INCR); 734 } 735 /* 736 * id_entryno counts the number of disk blocks found. 737 */ 738 idesc->id_entryno += btodb(sblock.fs_fsize); 739 } 740 return (res); 741 } 742 743 static void 744 note_used(daddr32_t frag) 745 { 746 n_blks++; 747 setbmap(frag); 748 } 749