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
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to