return ret;
 }
 
+/*
+ * Do various sanity and dependency checks of different features.
+ *
+ * This is the place for less strict checks (like for subpage or artificial
+ * feature dependencies).
+ *
+ * For strict checks or possible corruption detection, see
+ * btrfs_validate_super().
+ *
+ * This should be called after btrfs_parse_options(), as some mount options
+ * (space cache related) can modify on-disk format like free space tree and
+ * screw up certain feature dependencies.
+ */
+int btrfs_check_features(struct btrfs_fs_info *fs_info, struct super_block *sb)
+{
+       struct btrfs_super_block *disk_super = fs_info->super_copy;
+       u64 incompat = btrfs_super_incompat_flags(disk_super);
+       const u64 compat_ro = btrfs_super_compat_ro_flags(disk_super);
+       const u64 compat_ro_unsupp = (compat_ro & ~BTRFS_FEATURE_COMPAT_RO_SUPP);
+
+       if (incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP) {
+               btrfs_err(fs_info,
+               "cannot mount because of unknown incompat features (0x%llx)",
+                   incompat);
+               return -EINVAL;
+       }
+
+       /* Runtime limitation for mixed block groups. */
+       if ((incompat & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
+           (fs_info->sectorsize != fs_info->nodesize)) {
+               btrfs_err(fs_info,
+"unequal nodesize/sectorsize (%u != %u) are not allowed for mixed block groups",
+                       fs_info->nodesize, fs_info->sectorsize);
+               return -EINVAL;
+       }
+
+       /* Mixed backref is an always-enabled feature. */
+       incompat |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
+
+       /* Set compression related flags just in case. */
+       if (fs_info->compress_type == BTRFS_COMPRESS_LZO)
+               incompat |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
+       else if (fs_info->compress_type == BTRFS_COMPRESS_ZSTD)
+               incompat |= BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD;
+
+       /*
+        * An ancient flag, which should really be marked deprecated.
+        * Such runtime limitation doesn't really need a incompat flag.
+        */
+       if (btrfs_super_nodesize(disk_super) > PAGE_SIZE)
+               incompat |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
+
+       if (compat_ro_unsupp && !sb_rdonly(sb)) {
+               btrfs_err(fs_info,
+       "cannot mount read-write because of unknown compat_ro features (0x%llx)",
+                      compat_ro);
+               return -EINVAL;
+       }
+
+       /*
+        * We have unsupported RO compat features, although RO mounted, we
+        * should not cause any metadata writes, including log replay.
+        * Or we could screw up whatever the new feature requires.
+        */
+       if (compat_ro_unsupp && btrfs_super_log_root(disk_super) &&
+           !btrfs_test_opt(fs_info, NOLOGREPLAY)) {
+               btrfs_err(fs_info,
+"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
+                         compat_ro);
+               return -EINVAL;
+       }
+
+       /*
+        * Artificial limitations for block group tree, to force
+        * block-group-tree to rely on no-holes and free-space-tree.
+        */
+       if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE) &&
+           (!btrfs_fs_incompat(fs_info, NO_HOLES) ||
+            !btrfs_test_opt(fs_info, FREE_SPACE_TREE))) {
+               btrfs_err(fs_info,
+"block-group-tree feature requires no-holes and free-space-tree features");
+               return -EINVAL;
+       }
+
+       /*
+        * Subpage runtime limitation on v1 cache.
+        *
+        * V1 space cache still has some hard codeed PAGE_SIZE usage, while
+        * we're already defaulting to v2 cache, no need to bother v1 as it's
+        * going to be deprecated anyway.
+        */
+       if (fs_info->sectorsize < PAGE_SIZE && btrfs_test_opt(fs_info, SPACE_CACHE)) {
+               btrfs_warn(fs_info,
+       "v1 space cache is not supported for page size %lu with sectorsize %u",
+                          PAGE_SIZE, fs_info->sectorsize);
+               return -EINVAL;
+       }
+
+       /* This can be called by remount, we need to protect the super block. */
+       spin_lock(&fs_info->super_lock);
+       btrfs_set_super_incompat_flags(disk_super, incompat);
+       spin_unlock(&fs_info->super_lock);
+
+       return 0;
+}
+
 int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices,
                      char *options)
 {
                goto fail_alloc;
        }
 
-       features = btrfs_super_incompat_flags(disk_super) &
-               ~BTRFS_FEATURE_INCOMPAT_SUPP;
-       if (features) {
-               btrfs_err(fs_info,
-                   "cannot mount because of unsupported optional features (0x%llx)",
-                   features);
-               err = -EINVAL;
-               goto fail_alloc;
-       }
-
-       features = btrfs_super_incompat_flags(disk_super);
-       features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
-       if (fs_info->compress_type == BTRFS_COMPRESS_LZO)
-               features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
-       else if (fs_info->compress_type == BTRFS_COMPRESS_ZSTD)
-               features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD;
-
-       /*
-        * Flag our filesystem as having big metadata blocks if they are bigger
-        * than the page size.
-        */
-       if (btrfs_super_nodesize(disk_super) > PAGE_SIZE)
-               features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
-
-       /*
-        * mixed block groups end up with duplicate but slightly offset
-        * extent buffers for the same range.  It leads to corruptions
-        */
-       if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
-           (sectorsize != nodesize)) {
-               btrfs_err(fs_info,
-"unequal nodesize/sectorsize (%u != %u) are not allowed for mixed block groups",
-                       nodesize, sectorsize);
-               goto fail_alloc;
-       }
-
-       /*
-        * Needn't use the lock because there is no other task which will
-        * update the flag.
-        */
-       btrfs_set_super_incompat_flags(disk_super, features);
-
-       features = btrfs_super_compat_ro_flags(disk_super) &
-               ~BTRFS_FEATURE_COMPAT_RO_SUPP;
-       if (!sb_rdonly(sb) && features) {
-               btrfs_err(fs_info,
-       "cannot mount read-write because of unsupported optional features (0x%llx)",
-                      features);
-               err = -EINVAL;
-               goto fail_alloc;
-       }
-       /*
-        * We have unsupported RO compat features, although RO mounted, we
-        * should not cause any metadata write, including log replay.
-        * Or we could screw up whatever the new feature requires.
-        */
-       if (unlikely(features && btrfs_super_log_root(disk_super) &&
-                    !btrfs_test_opt(fs_info, NOLOGREPLAY))) {
-               btrfs_err(fs_info,
-"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
-                         features);
-               err = -EINVAL;
+       ret = btrfs_check_features(fs_info, sb);
+       if (ret < 0) {
+               err = ret;
                goto fail_alloc;
        }
 
-
        if (sectorsize < PAGE_SIZE) {
                struct btrfs_subpage_info *subpage_info;