[PATCH 08/10] ufs: refuse read-write mount when fsck or journal replay is needed

Ali Ahmet Memis <[email protected]>
Newsgroups gmane.linux.file-systems,gmane.linux.kernel
Message-ID <[email protected]>
FS_NEEDSFSCK, FS_SUJ and FS_GJOURNAL live in the 32 bit fs_flags of the
modern superblock, which Linux has never read. A UFS2 filesystem that
FreeBSD marked as needing a foreground fsck, or that carries soft
updates journalling or a GEOM journal, therefore mounts read-write here
and is written to with the pending recovery work still outstanding.

FreeBSD itself will not do this. ffs_mountfs() only accepts an unclean
filesystem when neither flag is set:

	(fs->fs_flags & (FS_SUJ | FS_NEEDSFSCK)) == 0 &&
	    (fs->fs_flags & FS_DOSOFTDEP)

and otherwise refuses with "Filesystem is not clean - run fsck".

Linux has no journal replay for either journal and no way to run the
recovery, so the only safe thing it can do is stay read-only. Check the
flags on mount and on remount read-write.

Only UFS2 is examined. On older layouts the same offset is scratch space
that may hold anything, and misreading it would wrongly refuse
filesystems that are perfectly fine.

Signed-off-by: Ali Ahmet Memis <[email protected]>
---
 fs/ufs/super.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 4b0e9196fa41..df95502e039e 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -767,6 +767,34 @@ static bool ufs_state_allows_write(struct super_block *sb)
 	}
 }
 
+/*
+ * Refuse to write to a filesystem using features we do not implement.
+ * Only UFS2 is examined: the 32 bit fs_flags lives in the modern part of
+ * the superblock, which older layouts leave as scratch space.
+ */
+static bool ufs_features_allow_write(struct super_block *sb)
+{
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+	struct ufs_super_block_third *usb3 = ubh_get_usb_third(uspi);
+	u32 fsflags;
+
+	if (uspi->fs_magic != UFS2_MAGIC)
+		return true;
+
+	fsflags = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_flags);
+
+	if (fsflags & UFS_FS_NEEDSFSCK) {
+		pr_err("%s(): fs is marked as needing fsck\n", __func__);
+		return false;
+	}
+	if (fsflags & (UFS_FS_SUJ | UFS_FS_GJOURNAL)) {
+		pr_err("%s(): journalled fs, journal replay is not supported\n",
+		       __func__);
+		return false;
+	}
+	return true;
+}
+
 static int ufs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
 	struct ufs_fs_context *ctx = fc->fs_private;
@@ -1103,7 +1131,7 @@ static int ufs_fill_super(struct super_block *sb, struct fs_context *fc)
 	 * Check, if file system was correctly unmounted.
 	 * If not, make it read only.
 	 */
-	if (!ufs_state_allows_write(sb))
+	if (!ufs_state_allows_write(sb) || !ufs_features_allow_write(sb))
 		sb->s_flags |= SB_RDONLY;
 
 	/*
@@ -1310,7 +1338,8 @@ static int ufs_reconfigure(struct fs_context *fc)
 			mutex_unlock(&UFS_SB(sb)->s_lock);
 			return -EINVAL;
 		}
-		if (!ufs_state_allows_write(sb)) {
+		if (!ufs_state_allows_write(sb) ||
+		    !ufs_features_allow_write(sb)) {
 			mutex_unlock(&UFS_SB(sb)->s_lock);
 			return -EROFS;
 		}
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.