[PATCH FOR REVIEW] fsck_ffs: Recover from catastrophic damage

Xin LI delphij at delphij.net
Wed Feb 20 07:37:10 UTC 2008


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

Here is a patch that will help fsck_ffs(8) to recover from certain types
of damages which is caused by some catastrophic damage seen in some disk
arrays that does not detect data errors in time.

Change summary:

fsutil.c:
 - Really update standard superblock.  fsck_ffs -b used to update the
backup superblock which does not recover file systems which have bad
master superblocks.
 - Instead of coredump, zero out whole cg if its signature is bad.

inode.c:
 - Instead of coredump, zero out whole cg if its signature is bad.

pass1.c:
 - If cg gives insane initediblk, use a fallback one which will not
cause allocation failure.

setup.c:
 - Really sanity check the superblock's fs_sbsize.

With these changes, fsck_ffs will be able to check file systems with
heavily damaged cylinder group information, and have a better chance
surviving.

Comments?

Cheers,
- --
Xin LI <delphij at delphij.net>	http://www.delphij.net/
FreeBSD - The Power to Serve!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4 (FreeBSD)

iD8DBQFHu9hji+vbBBjt66ARAqSyAJ49q4uEIANxr4/ccaVKeLTDomiFVQCfVB0i
kLZsrSPTifwvItwC3WMq40E=
=vvkQ
-----END PGP SIGNATURE-----
-------------- next part --------------
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	20 Feb 2008 07:15:56 -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);
 	}
@@ -441,8 +441,13 @@ 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);
+			if (!cg_chkmagic(cgp)) {
+				pwarn("CG %d: BAD MAGIC NUMBER\n", cg);
+				memset(cgp, 0, (size_t)sblock.fs_cgsize);
+				cgp->cg_niblk = sblock.fs_ipg;
+				cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
+				cgp->cg_magic = CG_MAGIC;
+			}
 			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	20 Feb 2008 07:15:22 -0000
@@ -617,8 +617,13 @@ 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);
+	if (!cg_chkmagic(cgp)) {
+		pwarn("CG %d: BAD MAGIC NUMBER\n", cg);
+		memset(cgp, 0, (size_t)sblock.fs_cgsize);
+		cgp->cg_niblk = sblock.fs_ipg;
+		cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
+		cgp->cg_magic = CG_MAGIC;
+	}
 	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
 	cgp->cg_cs.cs_nifree--;
 	switch (type & IFMT) {
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: 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) {


More information about the freebsd-current mailing list