aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/fsck_ffs/Makefile3
-rw-r--r--sbin/fsck_ffs/dir.c11
-rw-r--r--sbin/fsck_ffs/fsck.h136
-rw-r--r--sbin/fsck_ffs/fsck_ffs.87
-rw-r--r--sbin/fsck_ffs/fsutil.c19
-rw-r--r--sbin/fsck_ffs/main.c35
-rw-r--r--sbin/fsck_ffs/pass1.c5
-rw-r--r--sbin/fsck_ffs/pass1b.c8
-rw-r--r--sbin/fsck_ffs/suj.c56
-rw-r--r--sbin/fsck_ffs/utilities.c11
10 files changed, 183 insertions, 108 deletions
diff --git a/sbin/fsck_ffs/Makefile b/sbin/fsck_ffs/Makefile
index db2930bea627..028a4867c85d 100644
--- a/sbin/fsck_ffs/Makefile
+++ b/sbin/fsck_ffs/Makefile
@@ -7,7 +7,8 @@ LINKS+= ${BINDIR}/fsck_ffs ${BINDIR}/fsck_4.2bsd
MAN= fsck_ffs.8
MLINKS= fsck_ffs.8 fsck_ufs.8 fsck_ffs.8 fsck_4.2bsd.8
SRCS= dir.c ea.c fsutil.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c \
- pass4.c pass5.c setup.c suj.c utilities.c gjournal.c getmntopts.c
+ pass4.c pass5.c setup.c suj.c utilities.c gjournal.c getmntopts.c \
+ globs.c
DPADD= ${LIBUFS}
LDADD= -lufs
WARNS?= 2
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index 965e3e398215..7640f704b76a 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -48,20 +48,14 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
-const char *lfname = "lost+found";
-int lfmode = 0700;
-struct dirtemplate emptydir = {
+static struct dirtemplate emptydir = {
0, DIRBLKSIZ, DT_UNKNOWN, 0, "",
0, 0, DT_UNKNOWN, 0, ""
};
-struct dirtemplate dirhead = {
+static struct dirtemplate dirhead = {
0, 12, DT_DIR, 1, ".",
0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
};
-struct odirtemplate odirhead = {
- 0, 12, 1, ".",
- 0, DIRBLKSIZ - 12, 2, ".."
-};
static int chgino(struct inodesc *);
static int dircheck(struct inodesc *, struct direct *);
@@ -133,6 +127,7 @@ dirscan(struct inodesc *idesc)
(size_t)dsize);
dirty(bp);
sbdirty();
+ rerun = 1;
}
if (n & STOP)
return (n);
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 632d45433da2..a7b5961a574d 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -192,15 +192,15 @@ struct bufarea {
"Inode Block", \
"Directory Contents", \
"User Data" }
-long readcnt[BT_NUMBUFTYPES];
-long totalreadcnt[BT_NUMBUFTYPES];
-struct timespec readtime[BT_NUMBUFTYPES];
-struct timespec totalreadtime[BT_NUMBUFTYPES];
-struct timespec startprog;
+extern long readcnt[BT_NUMBUFTYPES];
+extern long totalreadcnt[BT_NUMBUFTYPES];
+extern struct timespec readtime[BT_NUMBUFTYPES];
+extern struct timespec totalreadtime[BT_NUMBUFTYPES];
+extern struct timespec startprog;
-struct bufarea sblk; /* file system superblock */
-struct bufarea *pdirbp; /* current directory contents */
-struct bufarea *pbp; /* current inode block */
+extern struct bufarea sblk; /* file system superblock */
+extern struct bufarea *pdirbp; /* current directory contents */
+extern struct bufarea *pbp; /* current inode block */
#define dirty(bp) do { \
if (fswritefd < 0) \
@@ -219,7 +219,7 @@ struct bufarea *pbp; /* current inode block */
#define sblock (*sblk.b_un.b_fs)
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
-ino_t cursnapshot;
+extern ino_t cursnapshot;
struct inodesc {
enum fixstate id_fix; /* policy on fixing errors */
@@ -282,63 +282,64 @@ struct inoinfo {
u_int i_numblks; /* size of block array in bytes */
ufs2_daddr_t i_blks[1]; /* actually longer */
} **inphead, **inpsort;
-long numdirs, dirhash, listmax, inplast;
-long countdirs; /* number of directories we actually found */
+extern long numdirs, dirhash, listmax, inplast;
+extern long countdirs; /* number of directories we actually found */
#define MIBSIZE 3 /* size of fsck sysctl MIBs */
-int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
-int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
-int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
-int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
-int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
-int adjnffree[MIBSIZE]; /* MIB command to adjust number of free frags */
-int adjnumclusters[MIBSIZE]; /* MIB command to adjust number of free clusters */
-int freefiles[MIBSIZE]; /* MIB command to free a set of files */
-int freedirs[MIBSIZE]; /* MIB command to free a set of directories */
-int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */
-struct fsck_cmd cmd; /* sysctl file system update commands */
-char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
-char *cdevname; /* name of device being checked */
-long dev_bsize; /* computed value of DEV_BSIZE */
-long secsize; /* actual disk sector size */
-u_int real_dev_bsize; /* actual disk sector size, not overriden */
-char nflag; /* assume a no response */
-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 */
-int Eflag; /* delete empty data blocks */
-int Zflag; /* zero empty data blocks */
-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 */
-int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */
-char usedsoftdep; /* just fix soft dependency inconsistencies */
-char preen; /* just fix normal inconsistencies */
-char rerun; /* rerun fsck. Only used in non-preen mode */
-int returntosingle; /* 1 => return to single user mode on exit */
-char resolved; /* cleared if unresolved changes => not clean */
-char havesb; /* superblock has been read */
-char skipclean; /* skip clean file systems if preening */
-int fsmodified; /* 1 => write done to file system */
-int fsreadfd; /* file descriptor for reading file system */
-int fswritefd; /* file descriptor for writing file system */
-int surrender; /* Give up if reads fail */
-
-ufs2_daddr_t maxfsblock; /* number of blocks in the file system */
-char *blockmap; /* ptr to primary blk allocation map */
-ino_t maxino; /* number of inodes in file system */
-
-ino_t lfdir; /* lost & found directory inode number */
-const char *lfname; /* lost & found directory name */
-int lfmode; /* lost & found directory creation mode */
-
-ufs2_daddr_t n_blks; /* number of blocks in use */
-ino_t n_files; /* number of files in use */
-
-volatile sig_atomic_t got_siginfo; /* received a SIGINFO */
-volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
+extern int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
+extern int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
+extern int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
+extern int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
+extern int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
+extern int adjnffree[MIBSIZE]; /* MIB command to adjust number of free frags */
+extern int adjnumclusters[MIBSIZE]; /* MIB command to adjust number of free clusters */
+extern int freefiles[MIBSIZE]; /* MIB command to free a set of files */
+extern int freedirs[MIBSIZE]; /* MIB command to free a set of directories */
+extern int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */
+extern struct fsck_cmd cmd; /* sysctl file system update commands */
+extern char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
+extern char *cdevname; /* name of device being checked */
+extern long dev_bsize; /* computed value of DEV_BSIZE */
+extern long secsize; /* actual disk sector size */
+extern u_int real_dev_bsize; /* actual disk sector size, not overriden */
+extern char nflag; /* assume a no response */
+extern char yflag; /* assume a yes response */
+extern int bkgrdflag; /* use a snapshot to run on an active system */
+extern int bflag; /* location of alternate super block */
+extern int debug; /* output debugging info */
+extern int Eflag; /* delete empty data blocks */
+extern int Zflag; /* zero empty data blocks */
+extern int inoopt; /* trim out unused inodes */
+extern char ckclean; /* only do work if not cleanly unmounted */
+extern int cvtlevel; /* convert to newer file system format */
+extern int bkgrdcheck; /* determine if background check is possible */
+extern int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */
+extern char usedsoftdep; /* just fix soft dependency inconsistencies */
+extern char preen; /* just fix normal inconsistencies */
+extern char rerun; /* rerun fsck. Only used in non-preen mode */
+extern int returntosingle; /* 1 => return to single user mode on exit */
+extern char resolved; /* cleared if unresolved changes => not clean */
+extern char havesb; /* superblock has been read */
+extern char skipclean; /* skip clean file systems if preening */
+extern int fsmodified; /* 1 => write done to file system */
+extern int fsreadfd; /* file descriptor for reading file system */
+extern int fswritefd; /* file descriptor for writing file system */
+extern int surrender; /* Give up if reads fail */
+extern int wantrestart; /* Restart fsck on early termination */
+
+extern ufs2_daddr_t maxfsblock; /* number of blocks in the file system */
+extern char *blockmap; /* ptr to primary blk allocation map */
+extern ino_t maxino; /* number of inodes in file system */
+
+extern ino_t lfdir; /* lost & found directory inode number */
+extern const char *lfname; /* lost & found directory name */
+extern int lfmode; /* lost & found directory creation mode */
+
+extern ufs2_daddr_t n_blks; /* number of blocks in use */
+extern ino_t n_files; /* number of files in use */
+
+extern volatile sig_atomic_t got_siginfo; /* received a SIGINFO */
+extern volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
#define clearinode(dp) \
if (sblock.fs_magic == FS_UFS1_MAGIC) { \
@@ -346,8 +347,8 @@ volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
} else { \
(dp)->dp2 = ufs2_zino; \
}
-struct ufs1_dinode ufs1_zino;
-struct ufs2_dinode ufs2_zino;
+extern struct ufs1_dinode ufs1_zino;
+extern struct ufs2_dinode ufs2_zino;
#define setbmap(blkno) setbit(blockmap, blkno)
#define testbmap(blkno) isset(blockmap, blkno)
@@ -360,6 +361,7 @@ struct ufs2_dinode ufs2_zino;
#define FOUND 0x10
#define EEXIT 8 /* Standard error exit. */
+#define ERESTART -1
int flushentry(void);
/*
@@ -428,6 +430,7 @@ void flush(int fd, struct bufarea *bp);
void freeblk(ufs2_daddr_t blkno, long frags);
void freeino(ino_t ino);
void freeinodebuf(void);
+void fsutilinit(void);
int ftypeok(union dinode *dp);
void getblk(struct bufarea *bp, ufs2_daddr_t blk, long size);
struct bufarea *cgget(int cg);
@@ -466,5 +469,6 @@ int setup(char *dev);
void gjournal_check(const char *filesys);
int suj_check(const char *filesys);
void update_maps(struct cg *, struct cg*, int);
+void fsckinit(void);
#endif /* !_FSCK_H_ */
diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8
index adf08d7bb434..828df2756997 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 BEFfnpryZ
+.Op Fl BEFfnpRryZ
.Op Fl b Ar block
.Op Fl c Ar level
.Op Fl m Ar mode
@@ -266,6 +266,11 @@ 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
+Instruct fsck_ffs to restart itself if it encounters certain errors that
+warrant another run. It will limit itself to a maximum of 10 restarts
+in a given run in order to avoid an endless loop with extremely corrupted
+filesystems.
.It Fl r
Free up excess unused inodes.
Decreasing the number of preallocated inodes reduces the
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 16ef8193fd89..4b44fd4ec856 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -74,6 +74,25 @@ static struct bufarea cgblk; /* backup buffer for cylinder group blocks */
static TAILQ_HEAD(buflist, bufarea) bufhead; /* head of buffer cache list */
static int numbufs; /* size of buffer cache */
static char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
+static struct bufarea *cgbufs; /* header for cylinder group cache */
+static int flushtries; /* number of tries to reclaim memory */
+
+void
+fsutilinit(void)
+{
+ diskreads = totaldiskreads = totalreads = 0;
+ bzero(&startpass, sizeof(struct timespec));
+ bzero(&finishpass, sizeof(struct timespec));
+ bzero(&slowio_starttime, sizeof(struct timeval));
+ slowio_delay_usec = 10000;
+ slowio_pollcnt = 0;
+ bzero(&cgblk, sizeof(struct bufarea));
+ TAILQ_INIT(&bufhead);
+ numbufs = 0;
+ /* buftype ? */
+ cgbufs = NULL;
+ flushtries = 0;
+}
int
ftypeok(union dinode *dp)
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 1a1c03bc7d85..08c7745727e4 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
+int restarts;
+
static void usage(void) __dead2;
static int argtoi(int flag, const char *req, const char *str, int base);
static int checkfilesys(char *filesys);
@@ -82,7 +84,7 @@ main(int argc, char *argv[])
sync();
skipclean = 1;
inoopt = 0;
- while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:nprSyZ")) != -1) {
+ while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZ")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
@@ -138,6 +140,9 @@ main(int argc, char *argv[])
ckclean++;
break;
+ case 'R':
+ wantrestart = 1;
+ break;
case 'r':
inoopt++;
break;
@@ -186,8 +191,12 @@ main(int argc, char *argv[])
rlimit.rlim_cur = rlimit.rlim_max;
(void)setrlimit(RLIMIT_DATA, &rlimit);
}
- while (argc-- > 0)
- (void)checkfilesys(*argv++);
+ while (argc > 0) {
+ if (checkfilesys(*argv) == ERESTART)
+ continue;
+ argc--;
+ argv++;
+ }
if (returntosingle)
ret = 2;
@@ -228,6 +237,8 @@ checkfilesys(char *filesys)
iov = NULL;
iovlen = 0;
errmsg[0] = '\0';
+ fsutilinit();
+ fsckinit();
cdevname = filesys;
if (debug && ckclean)
@@ -550,8 +561,12 @@ checkfilesys(char *filesys)
inostathead = NULL;
if (fsmodified && !preen)
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
- if (rerun)
+ if (rerun) {
+ if (wantrestart && (restarts++ < 10) &&
+ (preen || reply("RESTART")))
+ return (ERESTART);
printf("\n***** PLEASE RERUN FSCK *****\n");
+ }
if (chkdoreload(mntp) != 0) {
if (!fsmodified)
return (0);
@@ -654,3 +669,15 @@ usage(void)
getprogname());
exit(1);
}
+
+void
+infohandler(int sig __unused)
+{
+ got_siginfo = 1;
+}
+
+void
+alarmhandler(int sig __unused)
+{
+ got_sigalarm = 1;
+}
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index 319954122863..67fba6eaa35c 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -68,6 +68,8 @@ pass1(void)
u_int8_t *cp;
int c, rebuildcg;
+ badblk = dupblk = lastino = 0;
+
/*
* Set file system reserved blocks in used block map.
*/
@@ -463,6 +465,7 @@ pass1check(struct inodesc *idesc)
ckfini(0);
exit(EEXIT);
}
+ rerun = 1;
return (STOP);
}
}
@@ -483,6 +486,7 @@ pass1check(struct inodesc *idesc)
ckfini(0);
exit(EEXIT);
}
+ rerun = 1;
return (STOP);
}
new = (struct dups *)Malloc(sizeof(struct dups));
@@ -492,6 +496,7 @@ pass1check(struct inodesc *idesc)
ckfini(0);
exit(EEXIT);
}
+ rerun = 1;
return (STOP);
}
new->dup = blkno;
diff --git a/sbin/fsck_ffs/pass1b.c b/sbin/fsck_ffs/pass1b.c
index e635935fca00..69a23c207ecd 100644
--- a/sbin/fsck_ffs/pass1b.c
+++ b/sbin/fsck_ffs/pass1b.c
@@ -80,8 +80,10 @@ pass1b(void)
continue;
idesc.id_number = inumber;
if (inoinfo(inumber)->ino_state != USTATE &&
- (ckinode(dp, &idesc) & STOP))
+ (ckinode(dp, &idesc) & STOP)) {
+ rerun = 1;
return;
+ }
}
}
}
@@ -106,8 +108,10 @@ pass1bcheck(struct inodesc *idesc)
if (dlp == muldup)
break;
}
- if (muldup == 0 || duphead == muldup->next)
+ if (muldup == 0 || duphead == muldup->next) {
+ rerun = 1;
return (STOP);
+ }
}
return (res);
}
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index 5fca0f5fbfdf..9d6a2eccdc97 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -125,26 +125,26 @@ struct suj_cg {
int sc_cgx;
};
-LIST_HEAD(cghd, suj_cg) cghash[SUJ_HASHSIZE];
-LIST_HEAD(dblkhd, data_blk) dbhash[SUJ_HASHSIZE];
-struct suj_cg *lastcg;
-struct data_blk *lastblk;
+static LIST_HEAD(cghd, suj_cg) cghash[SUJ_HASHSIZE];
+static LIST_HEAD(dblkhd, data_blk) dbhash[SUJ_HASHSIZE];
+static struct suj_cg *lastcg;
+static struct data_blk *lastblk;
-TAILQ_HEAD(seghd, suj_seg) allsegs;
-uint64_t oldseq;
+static TAILQ_HEAD(seghd, suj_seg) allsegs;
+static uint64_t oldseq;
static struct uufsd *disk = NULL;
static struct fs *fs = NULL;
-ino_t sujino;
+static ino_t sujino;
/*
* Summary statistics.
*/
-uint64_t freefrags;
-uint64_t freeblocks;
-uint64_t freeinos;
-uint64_t freedir;
-uint64_t jbytes;
-uint64_t jrecs;
+static uint64_t freefrags;
+static uint64_t freeblocks;
+static uint64_t freeinos;
+static uint64_t freedir;
+static uint64_t jbytes;
+static uint64_t jrecs;
static jmp_buf jmpbuf;
@@ -155,6 +155,7 @@ static void ino_decr(ino_t);
static void ino_adjust(struct suj_ino *);
static void ino_build(struct suj_ino *);
static int blk_isfree(ufs2_daddr_t);
+static void initsuj(void);
static void *
errmalloc(size_t n)
@@ -2413,7 +2414,7 @@ struct jextent {
int je_blocks; /* Disk block count. */
};
-struct jblocks *suj_jblocks;
+static struct jblocks *suj_jblocks;
static struct jblocks *
jblocks_create(void)
@@ -2673,8 +2674,8 @@ suj_check(const char *filesys)
struct suj_seg *seg;
struct suj_seg *segn;
+ initsuj();
opendisk(filesys);
- TAILQ_INIT(&allsegs);
/*
* Set an exit point when SUJ check failed
@@ -2763,3 +2764,28 @@ suj_check(const char *filesys)
return (0);
}
+
+static void
+initsuj(void)
+{
+ int i;
+
+ for (i = 0; i < SUJ_HASHSIZE; i++) {
+ LIST_INIT(&cghash[i]);
+ LIST_INIT(&dbhash[i]);
+ }
+ lastcg = NULL;
+ lastblk = NULL;
+ TAILQ_INIT(&allsegs);
+ oldseq = 0;
+ disk = NULL;
+ fs = NULL;
+ sujino = 0;
+ freefrags = 0;
+ freeblocks = 0;
+ freeinos = 0;
+ freedir = 0;
+ jbytes = 0;
+ jrecs = 0;
+ suj_jblocks = NULL;
+}
diff --git a/sbin/fsck_ffs/utilities.c b/sbin/fsck_ffs/utilities.c
index 5e7d69c1ff6a..4e82c31640da 100644
--- a/sbin/fsck_ffs/utilities.c
+++ b/sbin/fsck_ffs/utilities.c
@@ -108,14 +108,3 @@ retry:
return (origname);
}
-void
-infohandler(int sig __unused)
-{
- got_siginfo = 1;
-}
-
-void
-alarmhandler(int sig __unused)
-{
- got_sigalarm = 1;
-}