summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/fsck_ffs/fsck.h6
-rw-r--r--sbin/fsck_ffs/fsck_ffs.827
-rw-r--r--sbin/fsck_ffs/fsutil.c96
-rw-r--r--sbin/fsck_ffs/inode.c57
-rw-r--r--sbin/fsck_ffs/main.c14
-rw-r--r--sbin/fsck_ffs/pass1.c81
6 files changed, 205 insertions, 76 deletions
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 76cf23c..887b94e 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -270,7 +270,7 @@ char yflag; /* assume a yes response */
int bkgrdflag; /* use a snapshot to run on an active system */
int bflag; /* location of alternate super block */
int debug; /* output debugging info */
-char damagedflag; /* run in damaged mode */
+int inoopt; /* trim out unused inodes */
char ckclean; /* only do work if not cleanly unmounted */
int cvtlevel; /* convert to newer file system format */
int bkgrdcheck; /* determine if background check is possible */
@@ -337,7 +337,7 @@ void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
int changeino(ino_t dir, const char *name, ino_t newnum);
-void check_cgmagic(int cg, struct cg *cgp);
+int check_cgmagic(int cg, struct cg *cgp);
int chkrange(ufs2_daddr_t blk, int cnt);
void ckfini(int markclean);
int ckinode(union dinode *dp, struct inodesc *);
@@ -362,7 +362,7 @@ int ftypeok(union dinode *dp);
void getblk(struct bufarea *bp, ufs2_daddr_t blk, long size);
struct bufarea *getdatablk(ufs2_daddr_t blkno, long size);
struct inoinfo *getinoinfo(ino_t inumber);
-union dinode *getnextinode(ino_t inumber);
+union dinode *getnextinode(ino_t inumber, int rebuildcg);
void getpathname(char *namebuf, ino_t curdir, ino_t ino);
union dinode *ginode(ino_t inumber);
void infohandler(int sig);
diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8
index b27269a..8b02e2d 100644
--- a/sbin/fsck_ffs/fsck_ffs.8
+++ b/sbin/fsck_ffs/fsck_ffs.8
@@ -38,7 +38,7 @@
.Nd file system consistency check and interactive repair
.Sh SYNOPSIS
.Nm
-.Op Fl BDFpfny
+.Op Fl BFprfny
.Op Fl b Ar block
.Op Fl c Ar level
.Op Fl m Ar mode
@@ -216,22 +216,6 @@ are being converted at once.
The format of a file system can be determined from the
first line of output from
.Xr dumpfs 8 .
-.It Fl D
-Run
-.Nm
-in 'damaged recovery' mode, which will enable certain aggressive
-operations that can make
-.Nm
-to survive with file systems that has very serious data damage, which
-is an useful last resort when on disk data damage is very serious
-and causes
-.Nm
-to crash otherwise. Be
-.Em very careful
-using this flag, it is dangerous if there are data transmission hazards
-because a false positive cylinder group magic number mismatch could
-cause
-.Em irrevertible data loss!
.Pp
This option implies the
.Fl f
@@ -259,6 +243,15 @@ which is assumed to be affirmative;
do not open the file system for writing.
.It Fl p
Preen file systems (see above).
+.It Fl r
+Free up excess unused inodes.
+Decreasing the number of preallocated inodes reduces the
+running time of future runs of
+.Nm
+and frees up space that can allocated to files.
+The
+.Fl r
+option is ignored when running in preen mode.
.It Fl y
Assume a yes response to all questions asked by
.Nm ;
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 91628ea..4ce2ef2 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -333,9 +333,13 @@ ckfini(int markclean)
if (!markclean)
rerun = 1;
}
- } else if (!preen && !markclean) {
- printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
- rerun = 1;
+ } else if (!preen) {
+ if (markclean) {
+ printf("\n***** FILE SYSTEM IS CLEAN *****\n");
+ } else {
+ printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
+ rerun = 1;
+ }
}
if (debug && totalreads > 0)
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
@@ -418,32 +422,73 @@ blwrite(int fd, char *buf, ufs2_daddr_t blk, long size)
}
/*
- * Check cg's magic number. If catastrophic mode is enabled and the cg's
- * magic number is bad, offer an option to clear the whole cg.
+ * Verify cylinder group's magic number and other parameters. If the
+ * test fails, offer an option to rebuild the whole cylinder group.
*/
-void
+int
check_cgmagic(int cg, struct cg *cgp)
{
- if (!cg_chkmagic(cgp)) {
- pwarn("CG %d: BAD MAGIC NUMBER\n", cg);
- if (damagedflag) {
- if (reply("CLEAR CG")) {
- memset(cgp, 0, (size_t)sblock.fs_cgsize);
- cgp->cg_initediblk = sblock.fs_ipg;
- cgp->cg_old_niblk = sblock.fs_ipg;
- cgp->cg_old_ncyl = sblock.fs_old_cpg;
- cgp->cg_cgx = cg;
- cgp->cg_niblk = sblock.fs_ipg;
- cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
- cgp->cg_magic = CG_MAGIC;
- cgdirty();
- printf("PLEASE RERUN FSCK.\n");
- rerun = 1;
- }
- } else
- printf("YOU MAY NEED TO RERUN FSCK WITH -D IF IT CRASHED.\n");
+ /*
+ * Extended cylinder group checks.
+ */
+ if (cg_chkmagic(cgp) &&
+ ((sblock.fs_magic == FS_UFS1_MAGIC &&
+ cgp->cg_old_niblk == sblock.fs_ipg &&
+ cgp->cg_ndblk <= sblock.fs_fpg &&
+ cgp->cg_old_ncyl == sblock.fs_old_cpg) ||
+ (sblock.fs_magic == FS_UFS2_MAGIC &&
+ cgp->cg_niblk == sblock.fs_ipg &&
+ cgp->cg_ndblk <= sblock.fs_fpg &&
+ cgp->cg_initediblk <= sblock.fs_ipg))) {
+ return (1);
+ }
+ pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg);
+ if (!reply("REBUILD CYLINDER GROUP")) {
+ printf("YOU WILL NEED TO RERUN FSCK.\n");
+ rerun = 1;
+ return (1);
+ }
+ /*
+ * Zero out the cylinder group and then initialize critical fields.
+ * Bit maps and summaries will be recalculated by later passes.
+ */
+ memset(cgp, 0, (size_t)sblock.fs_cgsize);
+ cgp->cg_magic = CG_MAGIC;
+ cgp->cg_cgx = cg;
+ cgp->cg_niblk = sblock.fs_ipg;
+ cgp->cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
+ sblock.fs_ipg : 2 * INOPB(&sblock);
+ if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size)
+ cgp->cg_ndblk = sblock.fs_fpg;
+ else
+ cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
+ cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield);
+ if (sblock.fs_magic == FS_UFS1_MAGIC) {
+ cgp->cg_niblk = 0;
+ cgp->cg_initediblk = 0;
+ cgp->cg_old_ncyl = sblock.fs_old_cpg;
+ cgp->cg_old_niblk = sblock.fs_ipg;
+ cgp->cg_old_btotoff = cgp->cg_iusedoff;
+ cgp->cg_old_boff = cgp->cg_old_btotoff +
+ sblock.fs_old_cpg * sizeof(int32_t);
+ cgp->cg_iusedoff = cgp->cg_old_boff +
+ sblock.fs_old_cpg * sizeof(u_int16_t);
+ }
+ cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
+ cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT);
+ if (sblock.fs_contigsumsize > 0) {
+ cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag;
+ cgp->cg_clustersumoff =
+ roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t));
+ cgp->cg_clustersumoff -= sizeof(u_int32_t);
+ cgp->cg_clusteroff = cgp->cg_clustersumoff +
+ (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t);
+ cgp->cg_nextfreeoff = cgp->cg_clusteroff +
+ howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
}
+ cgdirty();
+ return (0);
}
/*
@@ -470,7 +515,8 @@ allocblk(long frags)
}
cg = dtog(&sblock, i + j);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
- check_cgmagic(cg, cgp);
+ if (!check_cgmagic(cg, cgp))
+ return (0);
baseblk = dtogd(&sblock, i + j);
for (k = 0; k < frags; k++) {
setbmap(i + j + k);
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 94c637e..5feead0 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -309,10 +309,12 @@ static long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
static caddr_t inodebuf;
union dinode *
-getnextinode(ino_t inumber)
+getnextinode(ino_t inumber, int rebuildcg)
{
+ int j;
long size;
- ufs2_daddr_t dblk;
+ mode_t mode;
+ ufs2_daddr_t ndb, dblk;
union dinode *dp;
static caddr_t nextinop;
@@ -336,6 +338,54 @@ getnextinode(ino_t inumber)
nextinop = inodebuf;
}
dp = (union dinode *)nextinop;
+ if (rebuildcg && nextinop == inodebuf) {
+ /*
+ * Try to determine if we have reached the end of the
+ * allocated inodes.
+ */
+ mode = DIP(dp, di_mode) & IFMT;
+ if (mode == 0) {
+ if (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
+ NDADDR * sizeof(ufs2_daddr_t)) ||
+ memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
+ NIADDR * sizeof(ufs2_daddr_t)) ||
+ dp->dp2.di_mode || dp->dp2.di_size)
+ return (NULL);
+ goto inodegood;
+ }
+ if (!ftypeok(dp))
+ return (NULL);
+ ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
+ if (ndb < 0)
+ return (NULL);
+ if (mode == IFBLK || mode == IFCHR)
+ ndb++;
+ if (mode == IFLNK) {
+ /*
+ * Fake ndb value so direct/indirect block checks below
+ * will detect any garbage after symlink string.
+ */
+ if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) {
+ ndb = howmany(DIP(dp, di_size),
+ sizeof(ufs2_daddr_t));
+ if (ndb > NDADDR) {
+ j = ndb - NDADDR;
+ for (ndb = 1; j > 1; j--)
+ ndb *= NINDIR(&sblock);
+ ndb += NDADDR;
+ }
+ }
+ }
+ for (j = ndb; ndb < NDADDR && j < NDADDR; j++)
+ if (DIP(dp, di_db[j]) != 0)
+ return (NULL);
+ for (j = 0, ndb -= NDADDR; ndb > 0; j++)
+ ndb /= NINDIR(&sblock);
+ for (; j < NIADDR; j++)
+ if (DIP(dp, di_ib[j]) != 0)
+ return (NULL);
+ }
+inodegood:
if (sblock.fs_magic == FS_UFS1_MAGIC)
nextinop += sizeof(struct ufs1_dinode);
else
@@ -617,7 +667,8 @@ allocino(ino_t request, int type)
return (0);
cg = ino_to_cg(&sblock, ino);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
- check_cgmagic(cg, cgp);
+ if (!check_cgmagic(cg, cgp))
+ return (0);
setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
cgp->cg_cs.cs_nifree--;
switch (type & IFMT) {
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 2fdd248..0366e45 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -81,8 +81,8 @@ main(int argc, char *argv[])
sync();
skipclean = 1;
- damagedflag = 0;
- while ((ch = getopt(argc, argv, "b:Bc:CdDfFm:npy")) != -1) {
+ inoopt = 0;
+ while ((ch = getopt(argc, argv, "b:Bc:CdfFm:npry")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
@@ -106,10 +106,6 @@ main(int argc, char *argv[])
debug++;
break;
- case 'D':
- damagedflag = 1;
- /* FALLTHROUGH */
-
case 'f':
skipclean = 0;
break;
@@ -138,6 +134,10 @@ main(int argc, char *argv[])
ckclean++;
break;
+ case 'r':
+ inoopt++;
+ break;
+
case 'y':
yflag++;
nflag = 0;
@@ -606,7 +606,7 @@ static void
usage(void)
{
(void) fprintf(stderr,
- "usage: %s [-BCFpfny] [-b block] [-c level] [-m mode] "
+ "usage: %s [-BFprfny] [-b block] [-c level] [-m mode] "
"filesystem ...\n",
getprogname());
exit(1);
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index 9bfc95d..73b6419 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -54,17 +54,17 @@ static ufs2_daddr_t badblk;
static ufs2_daddr_t dupblk;
static ino_t lastino; /* last inode in use */
-static void checkinode(ino_t inumber, struct inodesc *);
+static int checkinode(ino_t inumber, struct inodesc *, int rebuildcg);
void
pass1(void)
{
struct inostat *info;
struct inodesc idesc;
- ino_t inumber, inosused;
+ ino_t inumber, inosused, mininos;
ufs2_daddr_t i, cgd;
u_int8_t *cp;
- int c;
+ int c, rebuildcg;
/*
* Set file system reserved blocks in used block map.
@@ -93,7 +93,10 @@ pass1(void)
inumber = c * sblock.fs_ipg;
setinodebuf(inumber);
getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
- if (sblock.fs_magic == FS_UFS2_MAGIC) {
+ rebuildcg = 0;
+ if (!check_cgmagic(c, &cgrp))
+ rebuildcg = 1;
+ if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) {
inosused = cgrp.cg_initediblk;
if (inosused > sblock.fs_ipg)
inosused = sblock.fs_ipg;
@@ -117,9 +120,7 @@ pass1(void)
* to find the inodes that are really in use, and then
* read only those inodes in from disk.
*/
- if (preen && usedsoftdep) {
- if (!cg_chkmagic(&cgrp))
- pfatal("CG %d: BAD MAGIC NUMBER\n", c);
+ if ((preen || inoopt) && usedsoftdep && !rebuildcg) {
cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT];
for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
if (*cp == 0)
@@ -152,24 +153,60 @@ pass1(void)
*/
for (i = 0; i < inosused; i++, inumber++) {
if (inumber < ROOTINO) {
- (void)getnextinode(inumber);
+ (void)getnextinode(inumber, rebuildcg);
continue;
}
- checkinode(inumber, &idesc);
+ /*
+ * NULL return indicates probable end of allocated
+ * inodes during cylinder group rebuild attempt.
+ * We always keep trying until we get to the minimum
+ * valid number for this cylinder group.
+ */
+ if (checkinode(inumber, &idesc, rebuildcg) == 0 &&
+ i > cgrp.cg_initediblk)
+ break;
}
- lastino += 1;
- if (inosused < sblock.fs_ipg || inumber == lastino)
+ /*
+ * This optimization speeds up future runs of fsck
+ * by trimming down the number of inodes in cylinder
+ * groups that formerly had many inodes but now have
+ * fewer in use.
+ */
+ mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock));
+ if (inoopt && !preen && !rebuildcg &&
+ sblock.fs_magic == FS_UFS2_MAGIC &&
+ cgrp.cg_initediblk > 2 * INOPB(&sblock) &&
+ mininos < cgrp.cg_initediblk) {
+ i = cgrp.cg_initediblk;
+ if (mininos < 2 * INOPB(&sblock))
+ cgrp.cg_initediblk = 2 * INOPB(&sblock);
+ else
+ cgrp.cg_initediblk = mininos;
+ pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n",
+ c, i, cgrp.cg_initediblk, "VALID INODES");
+ cgdirty();
+ }
+ if (inosused < sblock.fs_ipg)
continue;
+ lastino += 1;
+ if (lastino < (c * sblock.fs_ipg))
+ inosused = 0;
+ else
+ inosused = lastino - (c * sblock.fs_ipg);
+ if (rebuildcg && inosused > cgrp.cg_initediblk &&
+ sblock.fs_magic == FS_UFS2_MAGIC) {
+ cgrp.cg_initediblk = roundup(inosused, INOPB(&sblock));
+ pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c,
+ cgrp.cg_initediblk);
+ }
/*
* If we were not able to determine in advance which inodes
* were in use, then reduce the size of the inoinfo structure
* to the size necessary to describe the inodes that we
* really found.
*/
- if (lastino < (c * sblock.fs_ipg))
- inosused = 0;
- else
- inosused = lastino - (c * sblock.fs_ipg);
+ if (inumber == lastino)
+ continue;
inostathead[c].il_numalloced = inosused;
if (inosused == 0) {
free(inostathead[c].il_stat);
@@ -187,8 +224,8 @@ pass1(void)
freeinodebuf();
}
-static void
-checkinode(ino_t inumber, struct inodesc *idesc)
+static int
+checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
{
union dinode *dp;
off_t kernmaxfilesize;
@@ -196,7 +233,8 @@ checkinode(ino_t inumber, struct inodesc *idesc)
mode_t mode;
int j, ret, offset;
- dp = getnextinode(inumber);
+ if ((dp = getnextinode(inumber, rebuildcg)) == NULL)
+ return (0);
mode = DIP(dp, di_mode) & IFMT;
if (mode == 0) {
if ((sblock.fs_magic == FS_UFS1_MAGIC &&
@@ -220,7 +258,7 @@ checkinode(ino_t inumber, struct inodesc *idesc)
}
}
inoinfo(inumber)->ino_state = USTATE;
- return;
+ return (1);
}
lastino = inumber;
/* This should match the file size limit in ffs_mountfs(). */
@@ -352,7 +390,7 @@ checkinode(ino_t inumber, struct inodesc *idesc)
if (preen)
printf(" (CORRECTED)\n");
else if (reply("CORRECT") == 0)
- return;
+ return (1);
if (bkgrdflag == 0) {
dp = ginode(inumber);
DIP_SET(dp, di_blocks, idesc->id_entryno);
@@ -368,7 +406,7 @@ checkinode(ino_t inumber, struct inodesc *idesc)
rwerror("ADJUST INODE BLOCK COUNT", cmd.value);
}
}
- return;
+ return (1);
unknown:
pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber);
inoinfo(inumber)->ino_state = FCLEAR;
@@ -378,6 +416,7 @@ unknown:
clearinode(dp);
inodirty();
}
+ return (1);
}
int
OpenPOWER on IntegriCloud