pass1.c revision ce37393aa5dacd7677a7e930e35a5dead0b3d507
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by the University of California, Berkeley and its contributors''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define _KERNEL
#include "fsck.h"
/*
* for each large file (size > MAXOFF_T), the global largefile_count
* gets incremented during this pass.
*/
void
pass1(void)
{
uint_t c, i;
/*
* Set file system reserved blocks in used block map.
*/
if (c == 0) {
/*
* Doing the first cylinder group, account for
* the cg summaries as well.
*/
} else {
}
for (; i < cgd; i++) {
note_used(i);
}
}
/*
* Note blocks being used by the log, so we don't declare
* them as available and some time in the future we get a
* freeing free block panic.
*/
/*
* Find all allocated blocks. This must be completed before
* we read the contents of any directories, as dirscan() et al
* don't want to know about block allocation holes. So, part
* of this pass is to truncate any directories with holes to
* just before those holes, so dirscan() can remain blissfully
* ignorant.
*/
inumber = 0;
if (inumber < UFSROOTINO)
continue;
}
}
freeinodebuf();
}
/*
* in maps (statemap[], lncntp[]) for future reference and validation.
* Initiate the calls to ckinode and in turn pass1check() to handle
* further validation.
*/
static void
{
int isdir;
char *err;
/* mode and type of file is not set */
clearinode(dp);
inodirty();
} else {
iscorrupt = 1;
}
}
return;
}
pfatal("NEGATIVE SIZE %lld I=%d",
goto bogus;
}
/*
* A more precise test of the type is done later on. Just get
* rid of the blatantly-wrong ones before we do any
* significant work.
*/
pfatal("BAD MODE 0%o I=%d",
inodirty();
dp = getnextrefresh();
} else {
iscorrupt = 1;
}
}
if (ndb < 0) {
/* extra space to distinguish from previous pfatal() */
pfatal("NEGATIVE SIZE %lld I=%d",
goto bogus;
}
pfatal("SPECIAL FILE WITH NON-ZERO LENGTH %lld I=%d",
goto bogus;
}
for (j = 0; j < NDADDR; j++) {
/*
* It's a device, so all the block pointers
* should be zero except for di_ordev.
* di_ordev is overlayed on the block array,
* but where varies between big and little
* endian, so make sure that the only non-zero
* element is the correct one. There can be
* a device whose ordev is zero, so we can't
* check for the reverse.
*/
if (debug) {
(void) printf(
"spec file di_db[%d] has %d\n",
}
"SPECIAL FILE WITH NON-ZERO FRAGMENT LIST I=%d",
inumber);
goto bogus;
}
}
for (j = 0; j < NIADDR; j++) {
if (debug)
(void) printf(
"special has %d at ib[%d]\n",
"SPECIAL FILE WITH NON-ZERO FRAGMENT LIST I=%d",
inumber);
goto bogus;
}
}
} else {
/*
* This assignment is mostly here to appease lint, but
* doesn't hurt.
*/
err = "Internal error: unexpected variant of having "
"blocks past end of file I=%d";
clear = 0;
/*
* If it's not a device, it has to follow the
* rules for files. In particular, no blocks after
* the last one that di_size says is in use.
*/
if (debug) {
(void) printf("bad file direct "
"addr[%d]: block 0x%x "
"format: 0%o\n",
}
err = "FILE WITH FRAGMENTS PAST END I=%d";
clear = 1;
break;
}
}
/*
* Find last indirect pointer that should be in use,
* and make sure any after it are clear.
*/
if (!clear) {
}
for (; j < NIADDR; j++) {
if (debug) {
(void) printf("bad file "
"indirect addr: block %d\n",
}
err =
"FILE WITH FRAGMENTS PAST END I=%d";
clear = 2;
break;
}
}
}
if (clear) {
/*
* The discarded blocks will be garbage-
* collected in pass5. If we're told not to
* discard them, it's just lost blocks, which
* isn't worth setting iscorrupt for.
*/
if (clear == 1) {
for (; j < NDADDR; j++)
j = 0;
}
for (; j < NIADDR; j++)
inodirty();
dp = getnextrefresh();
if (preen)
(void) printf(" (TRUNCATED)");
}
}
}
goto bogus;
}
n_files++;
/*
* We can't do anything about it right now, so note that its
* processing is being delayed. Otherwise, we'd be changing
* the block allocations out from under ourselves, which causes
* no end of confusion.
*/
/*
* if errorlocked or logging, then open deleted files will
* manifest as di_nlink <= 0 and di_mode != 0
* so skip them; they're ok.
* Also skip anything already marked to be cleared.
*/
if (debug)
(void) printf(
"marking i=%d INZLINK; nlink %d, mode 0%o, islog %d\n",
}
case IFDIR:
case IFATTRDIR:
/*
* INCLEAR means it will be ignored by passes 2 & 3.
*/
(void) printf("ZERO-LENGTH DIR I=%d\n",
inumber);
else
(void) printf("ZERO-LENGTH ATTRDIR I=%d\n",
inumber);
}
countdirs++;
break;
case IFSHAD:
}
break;
default:
}
badblk = 0;
dupblk = 0;
}
/*
* The kernel releases any blocks it finds in the lists,
* ignoring the block count itself. So, a bad count is
* not grounds for setting iscorrupt.
*/
pwarn("INCORRECT DISK BLOCK COUNT I=%u (%d should be %d)",
return;
inodirty();
if (preen)
(void) printf(" (CORRECTED)\n");
}
/*
* INCLEAR will cause passes 2 and 3 to skip it.
*/
}
/*
* Check that the ACL is on a valid file type
*/
if (shadow != 0) {
"NON-ZERO ACL REFERENCE, I=%d\n");
} else if ((shadow <= UFSROOTINO) ||
(shadow > maxinumber)) {
"BAD ACL REFERENCE I=%d\n");
} else {
}
}
if (attrinode != 0) {
if ((attrinode <= UFSROOTINO) ||
(attrinode > maxinumber)) {
"BAD ATTRIBUTE REFERENCE TO I=%d FROM I=%d\n");
} else {
"BAD ATTRIBUTE DIR REF TO I=%d FROM I=%d\n");
"REFERENCE TO ZERO-LENGTH ATTRIBUTE DIR I=%d from I=%d\n");
} else {
}
}
}
return;
/*
* If we got here, we've not had the chance to see if a
* directory has holes, but we know the directory's bad,
* so it's safe to always return false (no holes found).
*
* Also, a pfatal() is always done before jumping here, so
* we know we're not in preen mode.
*/
if (isdir) {
/*
* INCLEAR makes passes 2 & 3 skip it.
*/
} else {
}
inodirty();
} else {
iscorrupt = 1;
}
}
/*
* we assume we're working on a shadow, otherwise an extended attribute.
* FMT must be a printf format string, with one %d directive for
* the inode number.
*/
static void
{
if (parent != -1)
if (parent == -1)
else
}
if (debug)
iscorrupt = 1;
return;
}
if (parent == -1) {
/*
* until someone can protect it the way they need it
* to be (i.e., be conservatively paranoid).
*/
} else {
dp->di_oeftflag = 0;
}
inodirty();
if (preen)
(void) printf(" (CORRECTED)\n");
}
/*
* Check if we have holes in the directory's indirect
* blocks. If there are, get rid of everything after
* the first hole.
*/
static void
{
pfatal("I=%d DIRECTORY %s: CONTAINS EMPTY BLOCKS",
/*
* We found a hole, so get rid of it.
*/
if (preen)
(void) printf(" (TRUNCATED)\n");
} else {
iscorrupt = 1;
}
}
/*
* Truncate a directory to its first hole. If there are non-holes
* in the direct blocks after the problem block, move them down so
* that there's somewhat less lossage. Doing this for indirect blocks
* is left as an exercise for the reader.
*/
static void
{
int blocks;
if (idesc->id_firsthole < 0) {
return;
}
/*
* Since truncino() adjusts the size, we don't need to do that here,
* but we have to tell it what final size we want.
*
* We need to count from block zero up through the last block
* before the hole. If the hole is in the indirect blocks, chop at
* the start of the nearest level of indirection. Orphans will
* get reconnected, so we're not actually losing anything by doing
* it this way, and we're simplifying truncation significantly.
*/
else
if (debug)
(void) printf("to %lld (blocks %d)\n",
}
/*
* Technically, there are still the original number of fragments
* associated with the object. However, that number is not used
* to control anything, so we can do the in-memory truncation of
* it without bad things happening.
*/
}
int
{
int anyout;
int nfrags;
/*
* If this is a fallocate'd file, block numbers may be stored
* as negative. In that case negate the negative numbers.
*/
/*
* Note that blkerror() exits when preening.
*/
(idesc->id_firsthole < 0)) {
}
pwarn("EXCESSIVE BAD FRAGMENTS I=%u",
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.
*/
}
}
/*
* 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.
*/
/* bad fragment number */
/* no other claims seen as yet */
} 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.
*/
/*
* Use ==, so we only complain once, no matter
* how far over the limit we end up going.
*/
pwarn("EXCESSIVE DUPLICATE FRAGMENTS I=%u",
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.
*/
}
}
/*
* id_entryno counts the number of disk blocks found.
*/
}
return (res);
}
static void
{
n_blks++;
}