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
pass1(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
verify_inode(fsck_ino_t inumber,struct inodesc * idesc,fsck_ino_t maxinumber)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
clear_attr_acl(fsck_ino_t inumber,fsck_ino_t parent,char * fmt)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
check_dirholes(fsck_ino_t inumber,struct inodesc * idesc)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
collapse_dirhole(fsck_ino_t inumber,struct inodesc * idesc)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
pass1check(struct inodesc * idesc)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
note_used(daddr32_t frag)744 note_used(daddr32_t frag)
745 {
746 n_blks++;
747 setbmap(frag);
748 }
749