diff options
-rw-r--r-- | sbin/fsck_ffs/Makefile | 3 | ||||
-rw-r--r-- | sbin/fsck_ffs/dir.c | 11 | ||||
-rw-r--r-- | sbin/fsck_ffs/fsck.h | 136 | ||||
-rw-r--r-- | sbin/fsck_ffs/fsck_ffs.8 | 7 | ||||
-rw-r--r-- | sbin/fsck_ffs/fsutil.c | 19 | ||||
-rw-r--r-- | sbin/fsck_ffs/main.c | 35 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass1.c | 5 | ||||
-rw-r--r-- | sbin/fsck_ffs/pass1b.c | 8 | ||||
-rw-r--r-- | sbin/fsck_ffs/suj.c | 56 | ||||
-rw-r--r-- | sbin/fsck_ffs/utilities.c | 11 |
10 files changed, 183 insertions, 108 deletions
diff --git a/sbin/fsck_ffs/Makefile b/sbin/fsck_ffs/Makefile index db2930b..028a486 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 965e3e3..7640f70 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 632d454..a7b5961 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 adf08d7..828df27 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 16ef819..4b44fd4 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 1a1c03b..08c7745 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 3199541..67fba6e 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 e635935..69a23c2 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 5fca0f5..9d6a2ec 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 5e7d69c..4e82c31 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; -} |