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>