From owner-freebsd-current@FreeBSD.ORG Fri Feb 22 01:00:34 2008 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A77C816A405; Fri, 22 Feb 2008 01:00:34 +0000 (UTC) (envelope-from delphij@delphij.net) Received: from tarsier.delphij.net (delphij-pt.tunnel.tserv2.fmt.ipv6.he.net [IPv6:2001:470:1f03:2c9::2]) by mx1.freebsd.org (Postfix) with ESMTP id 1BD8713C4D9; Fri, 22 Feb 2008 01:00:33 +0000 (UTC) (envelope-from delphij@delphij.net) Received: from tarsier.geekcn.org (tarsier.geekcn.org [202.108.54.204]) (using TLSv1 with cipher ADH-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by tarsier.delphij.net (Postfix) with ESMTP id 0AE7A2844E; Fri, 22 Feb 2008 09:00:32 +0800 (CST) Received: from localhost (tarsier.geekcn.org [202.108.54.204]) by tarsier.geekcn.org (Postfix) with ESMTP id B2F6AEC47B6; Fri, 22 Feb 2008 09:00:31 +0800 (CST) X-Virus-Scanned: amavisd-new at geekcn.org Received: from tarsier.geekcn.org ([202.108.54.204]) by localhost (mail.geekcn.org [202.108.54.204]) (amavisd-new, port 10024) with ESMTP id O6Ga7sVKDYkP; Fri, 22 Feb 2008 09:00:25 +0800 (CST) Received: from charlie.delphij.net (71.5.7.139.ptr.us.xo.net [71.5.7.139]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by tarsier.geekcn.org (Postfix) with ESMTP id 5E24CEC4781; Fri, 22 Feb 2008 09:00:24 +0800 (CST) DomainKey-Signature: a=rsa-sha1; s=default; d=delphij.net; c=nofws; q=dns; h=message-id:date:from:reply-to:organization:user-agent: mime-version:to:cc:subject:references:in-reply-to: x-enigmail-version:openpgp:content-type; b=btvnXK0h/u2NC1GrK6ItXnVwEUEdEzeGt1Kb+rZTiRCSFo4xR3HIznxQKlZozv8x2 4m5RQLGnnpUf0t8hwS2OA== Message-ID: <47BE1EA3.7030105@delphij.net> Date: Thu, 21 Feb 2008 17:00:19 -0800 From: Xin LI Organization: The FreeBSD Project User-Agent: Thunderbird 2.0.0.9 (X11/20080122) MIME-Version: 1.0 To: d@delphij.net References: <47BBD864.3070905@delphij.net> <47BE0096.3010109@delphij.net> In-Reply-To: <47BE0096.3010109@delphij.net> X-Enigmail-Version: 0.95.5 OpenPGP: id=18EDEBA0; url=http://www.delphij.net/delphij.asc Content-Type: multipart/mixed; boundary="------------060303000807050602000802" Cc: freebsd-fs@freebsd.org, FreeBSD Current Subject: Re: [PATCH FOR REVIEW] fsck_ffs: Recover from catastrophic damage X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: d@delphij.net List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Feb 2008 01:00:34 -0000 This is a multi-part message in MIME format. --------------060303000807050602000802 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Xin LI wrote: > Here is a revised version of patch. Sorry for replying myself. I found a nit - the clear of cg is beyond the reach of later phases, so set rerun = 1 to advise the user that a rerun of fsck is necessary to make a full recover. No other functional chnages. Cheers, - -- Xin LI http://www.delphij.net/ FreeBSD - The Power to Serve! -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.4 (FreeBSD) iD8DBQFHvh6ii+vbBBjt66ARApvIAKDCTQ13lZCTnP3mHLrJtIs+dsvF2gCeIy3j lrJcQw30LubvVfiVm8y6cvs= =Wh3/ -----END PGP SIGNATURE----- --------------060303000807050602000802 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 22 Feb 2008 00:50:43 -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,35 @@ 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; + cgdirty(); + printf("PLEASE RERUN FSCK.\n"); + rerun = 1; + } + } 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 +470,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) { --------------060303000807050602000802--