diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 682dd60ebd4460..496de9913eda41 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -717,7 +717,19 @@ validate_sblock(struct fs *fs, int flags) howmany(fs->fs_cssize, fs->fs_fsize), %jd); #endif WCHK(fs->fs_metaspace, <, 0, %jd); - WCHK(fs->fs_metaspace, >, fs->fs_fpg / 2, %jd); + /* + * FreeBSD and NetBSD FFSv2 layouts diverge in the superblock region + * following fs_maxbsize. NetBSD's WAPBL journal metadata occupies + * the same bytes as FreeBSD's fs_metaspace and other fields. + * fs_flags cannot serve as a discriminator: ffs_oldfscompat_read() + * may overwrite it from the 8-bit fs_old_flags before this check runs. + * Skip the upper-bound check for UFS2; ffs_mountfs() detects the + * condition and enforces read-only access without modifying the + * on-disk superblock. The check is preserved for UFS1 where no such + * layout divergence exists. + */ + if (fs->fs_magic != FS_UFS2_MAGIC) + WCHK(fs->fs_metaspace, >, fs->fs_fpg / 2, %jd); WCHK(fs->fs_minfree, >, 99, %jd%%); maxfilesize = fs->fs_bsize * UFS_NDADDR - 1; for (sizepb = fs->fs_bsize, i = 0; i < UFS_NIADDR; i++) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 11afa99bea7653..633a8fed90e64f 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -604,6 +604,16 @@ ffs_mount(struct mount *mp) if (error) { return (error); } + /* + * Refuse upgrade of NetBSD WAPBL filesystem to + * read-write; see validate_sblock() for details. + */ + if (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_metaspace > fs->fs_fpg / 2) { + vfs_mount_error(mp, "NetBSD WAPBL filesystem " + "must be mounted read-only"); + return (EROFS); + } fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN; @@ -926,6 +936,23 @@ ffs_mountfs(struct vnode *odevvp, struct mount *mp, struct thread *td) ffs_use_bread); if (error != 0) goto out; + /* + * Per NetBSD's wapbl(4), systems without WAPBL support should mount it + * read-only; see validate_sblock() for details. + */ + if (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_metaspace > fs->fs_fpg / 2) { + if ((mp->mnt_flag & MNT_RDONLY) == 0) { + vfs_mount_error(mp, "NetBSD WAPBL filesystem must be " + "mounted read-only"); + error = EROFS; + goto out; + } + printf("WARNING: %s: NetBSD WAPBL filesystem mounted " + "read-only (fs_metaspace %jd, fs_fpg/2 %jd)\n", + mp->mnt_stat.f_mntonname, (intmax_t)fs->fs_metaspace, + (intmax_t)fs->fs_fpg / 2); + } fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN;