]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
bcachefs: Don't set BCH_FEATURE_incompat_version_field unless requested
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 28 Feb 2025 20:58:30 +0000 (15:58 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 1 Mar 2025 00:07:33 +0000 (19:07 -0500)
We shouldn't be setting incompatible bits or the incompatible version
field unless explicitly request or allowed - otherwise we break mounting
with old kernels or userspace.

Reported-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/super-io.c
fs/bcachefs/super-io.h

index 8037ccbacf6afe99b987e5fa85ecb0e06ad29676..a81a7b6c09897bc12f65172129f6fb0006a25106 100644 (file)
@@ -69,14 +69,20 @@ enum bcachefs_metadata_version bch2_latest_compatible_version(enum bcachefs_meta
        return v;
 }
 
-void bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version version)
+bool bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version version)
 {
-       mutex_lock(&c->sb_lock);
-       SET_BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb,
-               max(BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb), version));
-       c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_FEATURE_incompat_version_field);
-       bch2_write_super(c);
-       mutex_unlock(&c->sb_lock);
+       bool ret = (c->sb.features & BIT_ULL(BCH_FEATURE_incompat_version_field)) &&
+                  version <= c->sb.version_incompat_allowed;
+
+       if (ret) {
+               mutex_lock(&c->sb_lock);
+               SET_BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb,
+                       max(BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb), version));
+               bch2_write_super(c);
+               mutex_unlock(&c->sb_lock);
+       }
+
+       return ret;
 }
 
 const char * const bch2_sb_fields[] = {
@@ -1219,9 +1225,11 @@ void bch2_sb_upgrade(struct bch_fs *c, unsigned new_version, bool incompat)
        c->disk_sb.sb->version = cpu_to_le16(new_version);
        c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALL);
 
-       if (incompat)
+       if (incompat) {
                SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(c->disk_sb.sb,
                        max(BCH_SB_VERSION_INCOMPAT_ALLOWED(c->disk_sb.sb), new_version));
+               c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_FEATURE_incompat_version_field);
+       }
 }
 
 static int bch2_sb_ext_validate(struct bch_sb *sb, struct bch_sb_field *f,
index f1ab4f943720367ffc84d3bd7f626a97de902c84..b4cff9ebdebbf03d2d25c834b3b5ef7b06818fb0 100644 (file)
@@ -21,17 +21,14 @@ static inline bool bch2_version_compatible(u16 version)
 void bch2_version_to_text(struct printbuf *, enum bcachefs_metadata_version);
 enum bcachefs_metadata_version bch2_latest_compatible_version(enum bcachefs_metadata_version);
 
-void bch2_set_version_incompat(struct bch_fs *, enum bcachefs_metadata_version);
+bool bch2_set_version_incompat(struct bch_fs *, enum bcachefs_metadata_version);
 
 static inline bool bch2_request_incompat_feature(struct bch_fs *c,
                                                 enum bcachefs_metadata_version version)
 {
-       if (unlikely(version > c->sb.version_incompat)) {
-               if (version > c->sb.version_incompat_allowed)
-                       return false;
-               bch2_set_version_incompat(c, version);
-       }
-       return true;
+       return likely(version <= c->sb.version_incompat)
+               ? true
+               : bch2_set_version_incompat(c, version);
 }
 
 static inline size_t bch2_sb_field_bytes(struct bch_sb_field *f)