aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2018-10-23 21:10:06 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2018-10-23 21:10:06 +0000
commitec888383cff48d90ac65cdbcad1e3f8e152ff8ca (patch)
tree0f51492bb043f6e2c716b9eba95af4631be6c024
parent8c6d2039230c7c4039c8fa42bf95dbec842783f4 (diff)
Notes
-rw-r--r--sbin/fsck_ffs/main.c8
-rw-r--r--sbin/newfs/mkfs.c4
-rw-r--r--sys/sys/param.h1
-rw-r--r--sys/ufs/ffs/ffs_subr.c63
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c2
-rw-r--r--sys/ufs/ffs/fs.h3
6 files changed, 73 insertions, 8 deletions
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index c160295d2702..e5118619475b 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -460,11 +460,13 @@ checkfilesys(char *filesys)
if ((sblock.fs_metackhash & CK_CYLGRP) == 0 &&
reply("ADD CYLINDER GROUP CHECK-HASH PROTECTION") != 0)
ckhashadd |= CK_CYLGRP;
-#ifdef notyet
if ((sblock.fs_metackhash & CK_SUPERBLOCK) == 0 &&
getosreldate() >= P_OSREL_CK_SUPERBLOCK &&
- reply("ADD SUPERBLOCK CHECK-HASH PROTECTION") != 0)
- ckhashadd |= CK_SUPERBLOCK;
+ reply("ADD SUPERBLOCK CHECK-HASH PROTECTION") != 0) {
+ sblock.fs_metackhash |= CK_SUPERBLOCK;
+ sbdirty();
+ }
+#ifdef notyet
if ((sblock.fs_metackhash & CK_INODE) == 0 &&
getosreldate() >= P_OSREL_CK_INODE &&
reply("ADD INODE CHECK-HASH PROTECTION") != 0)
diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c
index 79fc627e5f7a..74a0f9511a85 100644
--- a/sbin/newfs/mkfs.c
+++ b/sbin/newfs/mkfs.c
@@ -496,7 +496,9 @@ restart:
if (Oflag > 1) {
sblock.fs_flags |= FS_METACKHASH;
if (getosreldate() >= P_OSREL_CK_CYLGRP)
- sblock.fs_metackhash = CK_CYLGRP;
+ sblock.fs_metackhash |= CK_CYLGRP;
+ if (getosreldate() >= P_OSREL_CK_SUPERBLOCK)
+ sblock.fs_metackhash |= CK_SUPERBLOCK;
}
/*
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 3d77aa945c10..2186dd37f428 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -88,6 +88,7 @@
#define P_OSREL_WRFSBASE 1200041
#define P_OSREL_CK_CYLGRP 1200046
#define P_OSREL_VMTOTAL64 1200054
+#define P_OSREL_CK_SUPERBLOCK 1300000
#define P_OSREL_MAJOR(x) ((x) / 100000)
#endif
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
index c7490568a764..de70a3f84283 100644
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
+uint32_t calculate_crc32c(uint32_t, const void *, size_t);
struct malloc_type;
#define UFS_MALLOC(size, type, flags) malloc(size)
#define UFS_FREE(ptr, type) free(ptr)
@@ -142,6 +143,7 @@ ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
static off_t sblock_try[] = SBLOCKSEARCH;
static int readsuper(void *, struct fs **, off_t, int,
int (*)(void *, off_t, void **, int));
+static uint32_t calc_sbhash(struct fs *);
/*
* Read a superblock from the devfd device.
@@ -252,7 +254,8 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
{
struct fs *fs;
- int error;
+ int error, res;
+ uint32_t ckhash;
error = (*readfunc)(devfd, sblockloc, (void **)fsp, SBLOCKSIZE);
if (error != 0)
@@ -267,7 +270,26 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
fs->fs_ncg >= 1 &&
fs->fs_bsize >= MINBSIZE &&
fs->fs_bsize <= MAXBSIZE &&
- fs->fs_bsize >= roundup(sizeof(struct fs), DEV_BSIZE)) {
+ fs->fs_bsize >= roundup(sizeof(struct fs), DEV_BSIZE) &&
+ fs->fs_sbsize <= SBLOCKSIZE) {
+ if (fs->fs_ckhash != (ckhash = calc_sbhash(fs))) {
+#ifdef _KERNEL
+ res = uprintf("Superblock check-hash failed: recorded "
+ "check-hash 0x%x != computed check-hash 0x%x\n",
+ fs->fs_ckhash, ckhash);
+#else
+ res = 0;
+#endif
+ /*
+ * Print check-hash failure if no controlling terminal
+ * in kernel or always if in user-mode (libufs).
+ */
+ if (res == 0)
+ printf("Superblock check-hash failed: recorded "
+ "check-hash 0x%x != computed check-hash "
+ "0x%x\n", fs->fs_ckhash, ckhash);
+ return (EINVAL);
+ }
/* Have to set for old filesystems that predate this field */
fs->fs_sblockactualloc = sblockloc;
/* Not yet any summary information */
@@ -313,12 +335,49 @@ ffs_sbput(void *devfd, struct fs *fs, off_t loc,
}
fs->fs_fmod = 0;
fs->fs_time = UFS_TIME;
+ fs->fs_ckhash = calc_sbhash(fs);
if ((error = (*writefunc)(devfd, loc, fs, fs->fs_sbsize)) != 0)
return (error);
return (0);
}
/*
+ * Calculate the check-hash for a superblock.
+ */
+static uint32_t
+calc_sbhash(struct fs *fs)
+{
+ uint32_t ckhash, save_ckhash;
+
+ /*
+ * A filesystem that was using a superblock ckhash may be moved
+ * to an older kernel that does not support ckhashes. The
+ * older kernel will clear the FS_METACKHASH flag indicating
+ * that it does not update hashes. When the disk is moved back
+ * to a kernel capable of ckhashes it disables them on mount:
+ *
+ * if ((fs->fs_flags & FS_METACKHASH) == 0)
+ * fs->fs_metackhash = 0;
+ *
+ * This leaves (fs->fs_metackhash & CK_SUPERBLOCK) == 0) with an
+ * old stale value in the fs->fs_ckhash field. Thus the need to
+ * just accept what is there.
+ */
+ if ((fs->fs_metackhash & CK_SUPERBLOCK) == 0)
+ return (fs->fs_ckhash);
+
+ save_ckhash = fs->fs_ckhash;
+ fs->fs_ckhash = 0;
+ /*
+ * If newly read from disk, the caller is responsible for
+ * verifying that fs->fs_sbsize <= SBLOCKSIZE.
+ */
+ ckhash = calculate_crc32c(~0L, (void *)fs, fs->fs_sbsize);
+ fs->fs_ckhash = save_ckhash;
+ return (ckhash);
+}
+
+/*
* Update the frsum fields to reflect addition or deletion
* of some frags.
*/
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index e3927327c79c..b69dd20da113 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -814,7 +814,7 @@ ffs_mountfs(devvp, mp, td)
if ((fs->fs_flags & FS_METACKHASH) == 0)
fs->fs_metackhash = 0;
/* none of these types of check-hashes are maintained by this kernel */
- fs->fs_metackhash &= ~(CK_SUPERBLOCK | CK_INODE | CK_INDIR | CK_DIR);
+ fs->fs_metackhash &= ~(CK_INODE | CK_INDIR | CK_DIR);
/* no support for any undefined flags */
fs->fs_flags &= FS_SUPPORTED;
fs->fs_flags &= ~FS_UNCLEAN;
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
index 30925d72165c..0560bc693afa 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -364,7 +364,8 @@ struct fs {
int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
ufs_time_t fs_mtime; /* Last mount or fsck time. */
int32_t fs_sujfree; /* SUJ free list */
- int32_t fs_sparecon32[22]; /* reserved for future constants */
+ int32_t fs_sparecon32[21]; /* reserved for future constants */
+ u_int32_t fs_ckhash; /* if CK_SUPERBLOCK, its check-hash */
u_int32_t fs_metackhash; /* metadata check-hash, see CK_ below */
int32_t fs_flags; /* see FS_ flags below */
int32_t fs_contigsumsize; /* size of cluster summary array */