Skip to content

Commit

Permalink
Various new check-hash checks have been added to the UFS filesystem
Browse files Browse the repository at this point in the history
over various major releases. Superblock check hashes were added for
the 12 release and cylinder-group and inode check hashes will appear
in the 13 release.

When a disk with a UFS filesystem is writably mounted, the kernel
clears the feature flags for anything that it does not support. For
example, if a UFS disk from a 12-stable kernel is mounted on an
11-stable system, the 11-stable kernel will clear the flag in the
filesystem superblock that indicates that superblock check-hashs
are being maintained. Thus if the disk is later moved back to a
12-stable system, the 12-stable system will know to ignore its
incorrect check-hash.

If the only filesystem modification done on the earlier kernel is
to run a utility such as growfs(8) that modifies the superblock but
neither updates the check-hash nor clears the feature flag indicating
that it does not support the check-hash, the disk will fail to mount
if it is moved back to its original newer kernel.

This patch moves the code that clears the filesystem feature flags
from the mount code (ffs_mountfs()) to the code that reads the
superblock (ffs_sbget()). As ffs_sbget() is used by the kernel mount
code and is imported into libufs(3), all the filesystem utilities
will now also clear these flags when they make modifications to the
filesystem.

As suggested by John Baldwin, fsck_ffs(8) has been changed to accept
and repair bad superblock check-hashes rather than refusing to run.
This change allows fsck to recover filesystems that have been impacted
by utilities older than those created after this change and is a
sensible thing to do in any event.

Reported by:  John Baldwin (jhb@)
MFC after:    2 weeks
Sponsored by: Netflix
  • Loading branch information
Kirk McKusick authored and Kirk McKusick committed Oct 25, 2020
1 parent 6cb13a3 commit 996d40f
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 7 deletions.
2 changes: 1 addition & 1 deletion sbin/fsck_ffs/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ readsb(int listerr)
int bad, ret;
struct fs *fs;

super = bflag ? bflag * dev_bsize : STDSB;
super = bflag ? bflag * dev_bsize : STDSB_NOHASHFAIL;
readcnt[sblk.b_type]++;
if ((ret = sbget(fsreadfd, &fs, super)) != 0) {
switch (ret) {
Expand Down
10 changes: 8 additions & 2 deletions sys/ufs/ffs/ffs_subr.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,15 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,

fs = NULL;
*fsp = NULL;
chkhash = 1;
if (altsblock >= 0) {
if ((error = readsuper(devfd, &fs, altsblock, 1, chkhash,
if ((error = readsuper(devfd, &fs, altsblock, 1, 0,
readfunc)) != 0) {
if (fs != NULL)
UFS_FREE(fs, filltype);
return (error);
}
} else {
chkhash = 1;
if (altsblock == STDSB_NOHASHFAIL)
chkhash = 0;
for (i = 0; sblock_try[i] != -1; i++) {
Expand Down Expand Up @@ -277,6 +277,12 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
*/
if ((fs->fs_flags & FS_METACKHASH) == 0)
fs->fs_metackhash = 0;
/*
* Clear any check-hashes that are not maintained
* by this kernel. Also clear any unsupported flags.
*/
fs->fs_metackhash &= CK_SUPPORTED;
fs->fs_flags &= FS_SUPPORTED;
if (fs->fs_ckhash != (ckhash = ffs_calc_sbhash(fs))) {
#ifdef _KERNEL
res = uprintf("Superblock check-hash failed: recorded "
Expand Down
4 changes: 0 additions & 4 deletions sys/ufs/ffs/ffs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1070,10 +1070,6 @@ ffs_mountfs(odevvp, mp, td)
loc = STDSB_NOHASHFAIL;
if ((error = ffs_sbget(devvp, &fs, loc, M_UFSMNT, ffs_use_bread)) != 0)
goto out;
/* none of these types of check-hashes are maintained by this kernel */
fs->fs_metackhash &= ~(CK_INDIR | CK_DIR);
/* no support for any undefined flags */
fs->fs_flags &= FS_SUPPORTED;
fs->fs_flags &= ~FS_UNCLEAN;
if (fs->fs_clean == 0) {
fs->fs_flags |= FS_UNCLEAN;
Expand Down
1 change: 1 addition & 0 deletions sys/ufs/ffs/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ CTASSERT(sizeof(struct fs) == 1376);
#define CK_INODE 0x0004 /* inodes */
#define CK_INDIR 0x0008 /* indirect blocks */
#define CK_DIR 0x0010 /* directory contents */
#define CK_SUPPORTED 0x0007 /* supported flags, others cleared at mount */
/*
* The BX_FSPRIV buffer b_xflags are used to track types of data in buffers.
*/
Expand Down

0 comments on commit 996d40f

Please sign in to comment.