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