From: Jan Kara <jack@suse.cz>
Subject: ext4: add allow_unsupported module parameter
Patch-mainline: never, SUSE-specific
References: fate#317919
Disallow access to filesystem with unsupported features by default but
leave a chance to access the filesystem via module parameter override
(taints kernel).
The status can be toggled during runtime by changing the exported module
parameter in /sys.
Currently we make bigalloc and metadata checksum features unsupported
because they aren't quite mature.
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/ext4/ext4.h | 3 ++
fs/ext4/super.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 59 insertions(+), 2 deletions(-)
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -43,6 +43,8 @@
#ifdef __KERNEL__
#include <linux/compat.h>
#endif
+#include <linux/module.h>
+#include <linux/unsupported-feature.h>
/*
* The fourth extended filesystem constants/structures
@@ -3248,4 +3250,5 @@ extern const struct iomap_ops ext4_iomap
#define EFSBADCRC EBADMSG /* Bad CRC detected */
#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
+DECLARE_SUSE_UNSUPPORTED_FEATURE(ext4);
#endif /* _EXT4_H */
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -52,6 +52,8 @@
#include "mballoc.h"
#include "fsmap.h"
+DEFINE_SUSE_UNSUPPORTED_FEATURE(ext4)
+
#define CREATE_TRACE_POINTS
#include <trace/events/ext4.h>
@@ -2674,6 +2676,28 @@ static unsigned long ext4_get_stripe_siz
return ret;
}
+static int
+ext4_check_unsupported_ro(struct super_block *sb, bool allow_ro, bool readonly,
+ const char *description)
+{
+ if (allow_ro && readonly)
+ return 0;
+
+ if (ext4_allow_unsupported())
+ return 0;
+
+ ext4_msg(sb, KERN_ERR, "Couldn't mount %sbecause of SUSE-unsupported optional feature %s. Load module with allow_unsupported=1.",
+ allow_ro ? "RDWR " : "", description);
+ return -EINVAL;
+}
+
+static int
+ext4_check_unsupported(struct super_block *sb, const char *description)
+{
+ /* The readonly argument doesn't matter if allow_ro is false */
+ return ext4_check_unsupported_ro(sb, false, false, description);
+}
+
/*
* Check whether this filesystem can be mounted based on
* the features present and the RDONLY/RDWR mount requested.
@@ -2708,6 +2732,16 @@ static int ext4_feature_set_ok(struct su
~EXT4_FEATURE_RO_COMPAT_SUPP));
return 0;
}
+
+
+ if (ext4_has_feature_bigalloc(sb) &&
+ ext4_check_unsupported_ro(sb, true, readonly, "BIGALLOC"))
+ return 0;
+
+ if (ext4_has_feature_metadata_csum(sb) &&
+ ext4_check_unsupported_ro(sb, true, readonly, "METADATA_CSUM"))
+ return 0;
+
/*
* Large file size enabled file system can only be mounted
* read-write on 32-bit systems if kernel is built with CONFIG_LBDAF
@@ -4516,6 +4550,7 @@ static int ext4_load_journal(struct supe
dev_t journal_dev;
int err = 0;
int really_read_only;
+ int csum_v1, csum_v2;
BUG_ON(!ext4_has_feature_journal(sb));
@@ -4581,8 +4616,23 @@ static int ext4_load_journal(struct supe
if (err) {
ext4_msg(sb, KERN_ERR, "error loading journal");
- jbd2_journal_destroy(journal);
- return err;
+ goto out_destroy_journal;
+ }
+
+ csum_v1 = jbd2_journal_check_used_features(journal,
+ JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0);
+ if (csum_v1) {
+ err = ext4_check_unsupported(sb, "CHECKSUM");
+ if (err)
+ goto out_destroy_journal;
+ }
+
+ csum_v2 = jbd2_journal_check_used_features(journal, 0, 0,
+ JBD2_FEATURE_INCOMPAT_CSUM_V2);
+ if (csum_v2) {
+ err = ext4_check_unsupported(sb, "CSUM_V1");
+ if (err)
+ goto out_destroy_journal;
}
EXT4_SB(sb)->s_journal = journal;
@@ -4597,6 +4647,10 @@ static int ext4_load_journal(struct supe
}
return 0;
+
+out_destroy_journal:
+ jbd2_journal_destroy(journal);
+ return err;
}
static int ext4_commit_super(struct super_block *sb, int sync)