Page MenuHomeFreeBSD
Authored By
mckusick
Aug 9 2017, 4:50 AM
Size
6 KB
Referenced Files
None
Subscribers

diffs.txt

Index: sys/ufs/ffs/fs.h
===================================================================
--- sys/ufs/ffs/fs.h (revision 322251)
+++ sys/ufs/ffs/fs.h (working copy)
@@ -234,6 +234,20 @@
};
/*
+ * 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
Index: sbin/fsck_ffs/setup.c
===================================================================
--- sbin/fsck_ffs/setup.c (revision 322296)
+++ sbin/fsck_ffs/setup.c (working copy)
@@ -58,6 +58,10 @@
#define altsblock (*asblk.b_un.b_fs)
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
+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.
* Return 1 if successful, 0 if unsuccessful, -1 if file system
@@ -66,9 +70,10 @@
int
setup(char *dev)
{
- long asked, i, j;
+ long cg, asked, i, j;
long bmapsize;
struct stat statb;
+ struct fs proto;
size_t size;
havesb = 0;
@@ -173,10 +178,28 @@
*/
if (readsb(1) == 0) {
skipclean = 0;
- if (bflag || preen)
+ if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
return(0);
- /* Looking for alternates is hard punt for now but retain structure */
- return (0);
+ if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
+ return (0);
+ for (cg = 0; cg < proto.fs_ncg; cg++) {
+ bflag = fsbtodb(&proto, cgsblock(&proto, cg));
+ if (readsb(0) != 0)
+ break;
+ }
+ if (cg >= proto.fs_ncg) {
+ printf("%s %s\n%s %s\n%s %s\n",
+ "SEARCH FOR ALTERNATE SUPER-BLOCK",
+ "FAILED. YOU MUST USE THE",
+ "-b OPTION TO FSCK TO SPECIFY THE",
+ "LOCATION OF AN ALTERNATE",
+ "SUPER-BLOCK TO SUPPLY NEEDED",
+ "INFORMATION; SEE fsck_ffs(8).");
+ bflag = 0;
+ return(0);
+ }
+ pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
+ bflag = 0;
}
if (skipclean && ckclean && sblock.fs_clean) {
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
@@ -213,6 +236,10 @@
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.
*/
@@ -428,3 +455,73 @@
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));
+}
Index: sbin/newfs/mkfs.c
===================================================================
--- sbin/newfs/mkfs.c (revision 322251)
+++ sbin/newfs/mkfs.c (working copy)
@@ -121,6 +121,7 @@
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];
@@ -617,6 +618,25 @@
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.
*/

File Metadata

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1010948
Default Alt Text
diffs.txt (6 KB)

Event Timeline

This is fine. > 8k on these boot blocks effectively never ever was used, so putting it here is fine.

Though I like the idea of just storing a few extra copies of the super blocks better.