Date: Thu, 21 Feb 2008 14:52:06 -0800 From: Xin LI <delphij@delphij.net> To: d@delphij.net Cc: freebsd-fs@freebsd.org, FreeBSD Current <freebsd-current@freebsd.org> Subject: Re: [PATCH FOR REVIEW] fsck_ffs: Recover from catastrophic damage Message-ID: <47BE0096.3010109@delphij.net> In-Reply-To: <47BBD864.3070905@delphij.net> References: <47BBD864.3070905@delphij.net>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------090507070102080306020007 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Here is a revised version of patch. It adds a new '-C' flag to fsck_ffs(8), which causes fsck_ffs(8) to run in a new 'catastrophic recovery' mode, where more aggressive operations are done. All cg clearing operations are now hidden in '-C' mode, and a prompt is provided so that sysadmin can choose whether to clear the cg. Other changes: - Be more careful while resetting a cg. Set more fields; - Sanity check d_ino in pass2check(). Give fsck_ffs(8) an opportunity to recover from insane inode number provided by damaged directory entry. Cheers, - -- Xin LI <delphij@delphij.net> http://www.delphij.net/ FreeBSD - The Power to Serve! -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.4 (FreeBSD) iD8DBQFHvgCWi+vbBBjt66ARAjrmAKCvDR/4wWiNp/k+9Jhz6YEhp9fFpgCeLyus /1BXVmFBI9S0fBdc3YOXmMw= =sE9G -----END PGP SIGNATURE----- --------------090507070102080306020007 Content-Type: text/plain; name="fsck.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="fsck.diff" Index: fsck.h =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/fsck.h,v retrieving revision 1.37 diff -u -p -r1.37 fsck.h --- fsck.h 31 Oct 2006 22:06:56 -0000 1.37 +++ fsck.h 21 Feb 2008 22:01:44 -0000 @@ -270,6 +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 catastrophicflag; /* run in catastrophic mode */ 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 */ @@ -335,6 +336,7 @@ void cacheino(union dinode *dp, ino_t i 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 chkrange(ufs2_daddr_t blk, int cnt); void ckfini(int markclean); int ckinode(union dinode *dp, struct inodesc *); Index: fsck_ffs.8 =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/fsck_ffs.8,v retrieving revision 1.34 diff -u -p -r1.34 fsck_ffs.8 --- fsck_ffs.8 20 Sep 2005 08:02:38 -0000 1.34 +++ fsck_ffs.8 21 Feb 2008 22:26:08 -0000 @@ -38,7 +38,7 @@ .Nd file system consistency check and interactive repair .Sh SYNOPSIS .Nm -.Op Fl BFpfny +.Op Fl BCFpfny .Op Fl b Ar block .Op Fl c Ar level .Op Fl m Ar mode @@ -175,6 +175,26 @@ Use the block specified immediately afte the super block for the file system. An alternate super block is usually located at block 32 for UFS1, and block 160 for UFS2. +.It Fl C +Run +.Nm +in 'catastrophic 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, 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 +flag. .It Fl c Convert the file system to the specified level. Note that the level of a file system can only be raised. Index: fsutil.c =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/fsutil.c,v retrieving revision 1.26 diff -u -p -r1.26 fsutil.c --- fsutil.c 31 Oct 2006 22:06:56 -0000 1.26 +++ fsutil.c 21 Feb 2008 22:47:08 -0000 @@ -301,7 +301,7 @@ ckfini(int markclean) if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && sblk.b_bno != sblock.fs_sblockloc / dev_bsize && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { - sblk.b_bno = sblock.fs_sblockloc / dev_bsize; + sblk.b_bno = SBLOCK_UFS2 / dev_bsize; sbdirty(); flush(fswritefd, &sblk); } @@ -418,6 +418,32 @@ blwrite(int fd, char *buf, ufs2_daddr_t } /* + * 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. + */ +void +check_cgmagic(int cg, struct cg *cgp) +{ + + if (!cg_chkmagic(cgp)) { + pwarn("CG %d: BAD MAGIC NUMBER\n", cg); + if (catastrophicflag) { + 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; + } + } else + printf("YOU MAY NEED TO RERUN FSCK WITH -C IF IT CRASHED.\n"); + } +} + +/* * allocate a data block with the specified number of fragments */ ufs2_daddr_t @@ -441,8 +467,7 @@ allocblk(long frags) } cg = dtog(&sblock, i + j); getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); - if (!cg_chkmagic(cgp)) - pfatal("CG %d: BAD MAGIC NUMBER\n", cg); + check_cgmagic(cg, cgp); baseblk = dtogd(&sblock, i + j); for (k = 0; k < frags; k++) { setbmap(i + j + k); Index: inode.c =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/inode.c,v retrieving revision 1.38 diff -u -p -r1.38 inode.c --- inode.c 31 Oct 2006 22:06:56 -0000 1.38 +++ inode.c 21 Feb 2008 21:56:27 -0000 @@ -617,8 +617,7 @@ allocino(ino_t request, int type) return (0); cg = ino_to_cg(&sblock, ino); getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); - if (!cg_chkmagic(cgp)) - pfatal("CG %d: BAD MAGIC NUMBER\n", cg); + check_cgmagic(cg, cgp); setbit(cg_inosused(cgp), ino % sblock.fs_ipg); cgp->cg_cs.cs_nifree--; switch (type & IFMT) { Index: main.c =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/main.c,v retrieving revision 1.47 diff -u -p -r1.47 main.c --- main.c 19 Sep 2007 01:24:19 -0000 1.47 +++ main.c 21 Feb 2008 22:02:42 -0000 @@ -81,7 +81,8 @@ main(int argc, char *argv[]) sync(); skipclean = 1; - while ((ch = getopt(argc, argv, "b:Bc:dfFm:npy")) != -1) { + catastrophicflag = 0; + while ((ch = getopt(argc, argv, "b:Bc:CdfFm:npy")) != -1) { switch (ch) { case 'b': skipclean = 0; @@ -105,6 +106,10 @@ main(int argc, char *argv[]) debug++; break; + case 'C': + catastrophicflag = 1; + /* FALLTHROUGH */ + case 'f': skipclean = 0; break; Index: pass1.c =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/pass1.c,v retrieving revision 1.43 diff -u -p -r1.43 pass1.c --- pass1.c 8 Oct 2004 20:44:47 -0000 1.43 +++ pass1.c 20 Feb 2008 07:13:53 -0000 @@ -93,9 +93,11 @@ pass1(void) inumber = c * sblock.fs_ipg; setinodebuf(inumber); getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); - if (sblock.fs_magic == FS_UFS2_MAGIC) + if (sblock.fs_magic == FS_UFS2_MAGIC) { inosused = cgrp.cg_initediblk; - else + if (inosused > sblock.fs_ipg) + inosused = sblock.fs_ipg; + } else inosused = sblock.fs_ipg; if (got_siginfo) { printf("%s: phase 1: cyl group %d of %d (%d%%)\n", Index: pass2.c =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/pass2.c,v retrieving revision 1.26 diff -u -p -r1.26 pass2.c --- pass2.c 8 Oct 2004 20:44:47 -0000 1.26 +++ pass2.c 21 Feb 2008 22:31:03 -0000 @@ -242,6 +242,8 @@ pass2check(struct inodesc *idesc) /* * check for "." */ + if (dirp->d_ino > maxino) + goto chk2; if (idesc->id_entryno != 0) goto chk1; if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { Index: setup.c =================================================================== RCS file: /home/ncvs/src/sbin/fsck_ffs/setup.c,v retrieving revision 1.50 diff -u -p -r1.50 setup.c --- setup.c 31 Oct 2006 22:06:56 -0000 1.50 +++ setup.c 20 Feb 2008 07:13:27 -0000 @@ -349,7 +349,7 @@ readsb(int listerr) sblock.fs_sblockloc == sblock_try[i])) && sblock.fs_ncg >= 1 && sblock.fs_bsize >= MINBSIZE && - sblock.fs_bsize >= sizeof(struct fs)) + sblock.fs_sbsize >= roundup(sizeof(struct fs), dev_bsize)) break; } if (sblock_try[i] == -1) { --------------090507070102080306020007--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?47BE0096.3010109>