Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 Aug 2017 04:35:04 +0000 (UTC)
From:      Kirk McKusick <mckusick@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r322806 - in stable/11: sbin/fsck_ffs sbin/newfs sys/ufs/ffs
Message-ID:  <201708230435.v7N4Z4l4086383@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mckusick
Date: Wed Aug 23 04:35:03 2017
New Revision: 322806
URL: https://svnweb.freebsd.org/changeset/base/322806

Log:
  MFC of 322200, 322201, 322271, and 322297
  
  322200: Remove (broken) search for alternate superblocks
  322201: Show differences when alternate superblock fails to match
  322271: Cleanup for 322200.
  322297: Restore fsck_ffs ability to find alternate superblocks
  
  Discussed with: kib, imp
  Differential Revision: https://reviews.freebsd.org/D11589

Modified:
  stable/11/sbin/fsck_ffs/setup.c
  stable/11/sbin/newfs/mkfs.c
  stable/11/sys/ufs/ffs/fs.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sbin/fsck_ffs/setup.c
==============================================================================
--- stable/11/sbin/fsck_ffs/setup.c	Wed Aug 23 03:54:34 2017	(r322805)
+++ stable/11/sbin/fsck_ffs/setup.c	Wed Aug 23 04:35:03 2017	(r322806)
@@ -58,7 +58,9 @@ struct bufarea asblk;
 #define altsblock (*asblk.b_un.b_fs)
 #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
 
-static void badsb(int listerr, const char *s);
+static int calcsb(char *dev, int devfd, struct fs *fs);
+static void saverecovery(int readfd, int writefd);
+static int chkrecovery(int devfd);
 
 /*
  * Read in a superblock finding an alternate if necessary.
@@ -176,7 +178,7 @@ setup(char *dev)
 	 */
 	if (readsb(1) == 0) {
 		skipclean = 0;
-		if (bflag || preen)
+		if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
 			return(0);
 		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
 			return (0);
@@ -234,6 +236,10 @@ setup(char *dev)
 		memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
 		flush(fswritefd, &asblk);
 	}
+	if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC &&
+	    fswritefd != -1 && chkrecovery(fsreadfd) == 0 &&
+	    reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0)
+		saverecovery(fsreadfd, fswritefd);
 	/*
 	 * read in the summary info.
 	 */
@@ -313,7 +319,7 @@ int
 readsb(int listerr)
 {
 	ufs2_daddr_t super;
-	int i;
+	int i, bad;
 
 	if (bflag) {
 		super = bflag;
@@ -363,40 +369,57 @@ readsb(int listerr)
 	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
 	sblk.b_bno = super / dev_bsize;
 	sblk.b_size = SBLOCKSIZE;
-	if (bflag)
-		goto out;
 	/*
 	 * Compare all fields that should not differ in alternate super block.
 	 * When an alternate super-block is specified this check is skipped.
 	 */
+	if (bflag)
+		goto out;
 	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
 	if (asblk.b_errs)
 		return (0);
-	if (altsblock.fs_sblkno != sblock.fs_sblkno ||
-	    altsblock.fs_cblkno != sblock.fs_cblkno ||
-	    altsblock.fs_iblkno != sblock.fs_iblkno ||
-	    altsblock.fs_dblkno != sblock.fs_dblkno ||
-	    altsblock.fs_ncg != sblock.fs_ncg ||
-	    altsblock.fs_bsize != sblock.fs_bsize ||
-	    altsblock.fs_fsize != sblock.fs_fsize ||
-	    altsblock.fs_frag != sblock.fs_frag ||
-	    altsblock.fs_bmask != sblock.fs_bmask ||
-	    altsblock.fs_fmask != sblock.fs_fmask ||
-	    altsblock.fs_bshift != sblock.fs_bshift ||
-	    altsblock.fs_fshift != sblock.fs_fshift ||
-	    altsblock.fs_fragshift != sblock.fs_fragshift ||
-	    altsblock.fs_fsbtodb != sblock.fs_fsbtodb ||
-	    altsblock.fs_sbsize != sblock.fs_sbsize ||
-	    altsblock.fs_nindir != sblock.fs_nindir ||
-	    altsblock.fs_inopb != sblock.fs_inopb ||
-	    altsblock.fs_cssize != sblock.fs_cssize ||
-	    altsblock.fs_ipg != sblock.fs_ipg ||
-	    altsblock.fs_fpg != sblock.fs_fpg ||
-	    altsblock.fs_magic != sblock.fs_magic) {
-		badsb(listerr,
-		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
-		return (0);
+	bad = 0;
+#define CHK(x, y)				\
+	if (altsblock.x != sblock.x) {		\
+		bad++;				\
+		if (listerr && debug)		\
+			printf("SUPER BLOCK VS ALTERNATE MISMATCH %s: " y " vs " y "\n", \
+			    #x, (intmax_t)sblock.x, (intmax_t)altsblock.x); \
 	}
+	CHK(fs_sblkno, "%jd");
+	CHK(fs_cblkno, "%jd");
+	CHK(fs_iblkno, "%jd");
+	CHK(fs_dblkno, "%jd");
+	CHK(fs_ncg, "%jd");
+	CHK(fs_bsize, "%jd");
+	CHK(fs_fsize, "%jd");
+	CHK(fs_frag, "%jd");
+	CHK(fs_bmask, "%#jx");
+	CHK(fs_fmask, "%#jx");
+	CHK(fs_bshift, "%jd");
+	CHK(fs_fshift, "%jd");
+	CHK(fs_fragshift, "%jd");
+	CHK(fs_fsbtodb, "%jd");
+	CHK(fs_sbsize, "%jd");
+	CHK(fs_nindir, "%jd");
+	CHK(fs_inopb, "%jd");
+	CHK(fs_cssize, "%jd");
+	CHK(fs_ipg, "%jd");
+	CHK(fs_fpg, "%jd");
+	CHK(fs_magic, "%#jx");
+#undef CHK
+	if (bad) {
+		if (listerr == 0)
+			return (0);
+		if (preen)
+			printf("%s: ", cdevname);
+		printf(
+		    "VALUES IN SUPER BLOCK LSB=%jd DISAGREE WITH THOSE IN\n"
+		    "LAST ALTERNATE LSB=%jd\n",
+		    sblk.b_bno, asblk.b_bno);
+		if (reply("IGNORE ALTERNATE SUPER BLOCK") == 0)
+			return (0);
+	}
 out:
 	/*
 	 * If not yet done, update UFS1 superblock with new wider fields.
@@ -417,17 +440,6 @@ out:
 	return (1);
 }
 
-static void
-badsb(int listerr, const char *s)
-{
-
-	if (!listerr)
-		return;
-	if (preen)
-		printf("%s: ", cdevname);
-	pfatal("BAD SUPER BLOCK: %s\n", s);
-}
-
 void
 sblock_init(void)
 {
@@ -442,4 +454,74 @@ sblock_init(void)
 	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
 		errx(EEXIT, "cannot allocate space for superblock");
 	dev_bsize = secsize = DEV_BSIZE;
+}
+
+/*
+ * Calculate a prototype superblock based on information in the boot area.
+ * When done the cgsblock macro can be calculated and the fs_ncg field
+ * can be used. Do NOT attempt to use other macros without verifying that
+ * their needed information is available!
+ */
+static int
+calcsb(char *dev, int devfd, struct fs *fs)
+{
+	struct fsrecovery fsr;
+
+	/*
+	 * We need fragments-per-group and the partition-size.
+	 *
+	 * Newfs stores these details at the end of the boot block area
+	 * at the start of the filesystem partition. If they have been
+	 * overwritten by a boot block, we fail. But usually they are
+	 * there and we can use them.
+	 */
+	if (blread(devfd, (char *)&fsr,
+	    (SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize, sizeof(fsr)) ||
+	    fsr.fsr_magic != FS_UFS2_MAGIC)
+		return (0);
+	memset(fs, 0, sizeof(struct fs));
+	fs->fs_fpg = fsr.fsr_fpg;
+	fs->fs_fsbtodb = fsr.fsr_fsbtodb;
+	fs->fs_sblkno = fsr.fsr_sblkno;
+	fs->fs_magic = fsr.fsr_magic;
+	fs->fs_ncg = fsr.fsr_ncg;
+	return (1);
+}
+
+/*
+ * Check to see if recovery information exists.
+ */
+static int
+chkrecovery(int devfd)
+{
+	struct fsrecovery fsr;
+
+	if (blread(devfd, (char *)&fsr,
+	    (SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize, sizeof(fsr)) ||
+	    fsr.fsr_magic != FS_UFS2_MAGIC)
+		return (0);
+	return (1);
+}
+
+/*
+ * Read the last sector of the boot block, replace the last
+ * 20 bytes with the recovery information, then write it back.
+ * The recovery information only works for UFS2 filesystems.
+ */
+static void
+saverecovery(int readfd, int writefd)
+{
+	struct fsrecovery fsr;
+
+	if (sblock.fs_magic != FS_UFS2_MAGIC ||
+	    blread(readfd, (char *)&fsr,
+	    (SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize, sizeof(fsr)))
+		return;
+	fsr.fsr_magic = sblock.fs_magic;
+	fsr.fsr_fpg = sblock.fs_fpg;
+	fsr.fsr_fsbtodb = sblock.fs_fsbtodb;
+	fsr.fsr_sblkno = sblock.fs_sblkno;
+	fsr.fsr_ncg = sblock.fs_ncg;
+	blwrite(writefd, (char *)&fsr, (SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize,
+	    sizeof(fsr));
 }

Modified: stable/11/sbin/newfs/mkfs.c
==============================================================================
--- stable/11/sbin/newfs/mkfs.c	Wed Aug 23 03:54:34 2017	(r322805)
+++ stable/11/sbin/newfs/mkfs.c	Wed Aug 23 04:35:03 2017	(r322806)
@@ -121,6 +121,7 @@ mkfs(struct partition *pp, char *fsys)
 	ino_t maxinum;
 	int minfragsperinode;	/* minimum ratio of frags to inodes */
 	char tmpbuf[100];	/* XXX this will break in about 2,500 years */
+	struct fsrecovery fsr;
 	union {
 		struct fs fdummy;
 		char cdummy[SBLOCKSIZE];
@@ -615,6 +616,25 @@ restart:
 		wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
 			MIN(sblock.fs_cssize - i, sblock.fs_bsize),
 			((char *)fscs) + i);
+	/*
+	 * Read the last sector of the boot block, replace the last
+	 * 20 bytes with the recovery information, then write it back.
+	 * The recovery information only works for UFS2 filesystems.
+	 */
+	if (sblock.fs_magic == FS_UFS2_MAGIC) {
+		i = bread(&disk,
+		    part_ofs + (SBLOCK_UFS2 - sizeof(fsr)) / disk.d_bsize,
+		    (char *)&fsr, sizeof(fsr));
+		if (i == -1)
+			err(1, "can't read recovery area: %s", disk.d_error);
+		fsr.fsr_magic = sblock.fs_magic;
+		fsr.fsr_fpg = sblock.fs_fpg;
+		fsr.fsr_fsbtodb = sblock.fs_fsbtodb;
+		fsr.fsr_sblkno = sblock.fs_sblkno;
+		fsr.fsr_ncg = sblock.fs_ncg;
+		wtfs((SBLOCK_UFS2 - sizeof(fsr)) / disk.d_bsize, sizeof(fsr),
+		    (char *)&fsr);
+	}
 	/*
 	 * Update information about this partition in pack
 	 * label, to that it may be updated on disk.

Modified: stable/11/sys/ufs/ffs/fs.h
==============================================================================
--- stable/11/sys/ufs/ffs/fs.h	Wed Aug 23 03:54:34 2017	(r322805)
+++ stable/11/sys/ufs/ffs/fs.h	Wed Aug 23 04:35:03 2017	(r322806)
@@ -234,6 +234,20 @@ struct fsck_cmd {
 };
 
 /*
+ * A recovery structure placed at the end of the boot block area by newfs
+ * that can be used by fsck to search for alternate superblocks.
+ */
+#define RESID	(4096 - 20)	/* disk sector size minus recovery area size */
+struct fsrecovery {
+	char	block[RESID];	/* unused part of sector */
+	int32_t	fsr_magic;	/* magic number */
+	int32_t	fsr_fsbtodb;	/* fsbtodb and dbtofsb shift constant */
+	int32_t	fsr_sblkno;	/* offset of super-block in filesys */
+	int32_t	fsr_fpg;	/* blocks per group * fs_frag */
+	u_int32_t fsr_ncg;	/* number of cylinder groups */
+};
+
+/*
  * Per cylinder group information; summarized in blocks allocated
  * from first cylinder group data blocks.  These blocks have to be
  * read in from fs_csaddr (size fs_cssize) in addition to the



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201708230435.v7N4Z4l4086383>