xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass1.c (revision 2a8bcb4e)
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(&note_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