static int pass1bcheck(struct inodesc *idesc) { struct dups *dlp; int nfrags, res = KEEPON; daddr_t blkno = idesc->id_blkno; for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { if (chkrange(blkno, 1)) res = SKIP; for (dlp = duphead; dlp; dlp = dlp->next) { if (dlp->dup == blkno) { blkerror(idesc->id_number, "DUP", blkno); dlp->dup = duphead->dup; duphead->dup = blkno; duphead = duphead->next; } if (dlp == muldup) break; } if (muldup == 0 || duphead == muldup->next) return (STOP); } return (res); }
int pass1check(struct inodesc *idesc) { int res = KEEPON; int anyout; int nfrags; daddr32_t lbn; daddr32_t fragno = idesc->id_blkno; struct dinode *dp; /* * If this is a fallocate'd file, block numbers may be stored * as negative. In that case negate the negative numbers. */ dp = ginode(idesc->id_number); if (dp->di_cflags & IFALLOCATE && fragno < 0) fragno = -fragno; if ((anyout = chkrange(fragno, idesc->id_numfrags)) != 0) { /* * Note that blkerror() exits when preening. */ blkerror(idesc->id_number, "OUT OF RANGE", fragno, idesc->id_lbn * sblock.fs_frag); dp = ginode(idesc->id_number); if ((((dp->di_mode & IFMT) == IFDIR) || ((dp->di_mode & IFMT) == IFATTRDIR)) && (idesc->id_firsthole < 0)) { idesc->id_firsthole = idesc->id_lbn; } if (++badblk >= MAXBAD) { pwarn("EXCESSIVE BAD FRAGMENTS I=%u", idesc->id_number); if (reply("CONTINUE") == 0) errexit("Program terminated."); /* * See discussion below as to why we don't * want to short-circuit the processing of * this inode. However, we know that this * particular block is bad, so we don't need * to go through the dup check loop. */ return (SKIP | STOP); } } /* * For each fragment, verify that it is a legal one (either * by having already found the entire run to be legal, or by * individual inspection), and if it is legal, see if we've * seen it before or not. If we haven't, note that we've seen * it and continue on. If we have (our in-core bitmap shows * it as already being busy), then this must be a duplicate * allocation. Whine and moan accordingly. * * Note that for full-block allocations, this will produce * a complaint for each fragment making up the block (i.e., * fs_frags' worth). Among other things, this could be * considered artificially inflating the dup-block count. * However, since it is possible that one file has a full * fs block allocated, but another is only claiming a frag * or two out of the middle, we'll just live it. */ for (nfrags = 0; nfrags < idesc->id_numfrags; fragno++, nfrags++) { if (anyout && chkrange(fragno, 1)) { /* bad fragment number */ res = SKIP; } else if (!testbmap(fragno)) { /* no other claims seen as yet */ note_used(fragno); } else { /* * We have a duplicate claim for the same fragment. * * blkerror() exits when preening. * * We want to report all the dups up until * hitting MAXDUP. Fortunately, blkerror()'s * side-effects on statemap[] are idempotent, * so the ``extra'' calls are harmless. */ lbn = idesc->id_lbn * sblock.fs_frag + nfrags; if (dupblk < MAXDUP) blkerror(idesc->id_number, "DUP", fragno, lbn); /* * Use ==, so we only complain once, no matter * how far over the limit we end up going. */ if (++dupblk == MAXDUP) { pwarn("EXCESSIVE DUPLICATE FRAGMENTS I=%u", idesc->id_number); if (reply("CONTINUE") == 0) errexit("Program terminated."); /* * If we stop the traversal here, then * there may be more dups in the * inode's block list that don't get * flagged. Later, if we're told to * clear one of the files claiming * these blocks, but not the other, we * will release blocks that are * actually still in use. An additional * fsck run would be necessary to undo * the damage. So, instead of the * traditional return (STOP) when told * to continue, we really do just continue. */ } (void) find_dup_ref(fragno, idesc->id_number, lbn, DB_CREATE | DB_INCR); } /* * id_entryno counts the number of disk blocks found. */ idesc->id_entryno += btodb(sblock.fs_fsize); } return (res); }