summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c13
-rw-r--r--fs/btrfs/fs.h8
2 files changed, 21 insertions, 0 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index d8ca5b6e88e0..fbd498aa9b99 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3255,6 +3255,15 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
return 0;
}
+static bool fs_is_full_ro(const struct btrfs_fs_info *fs_info)
+{
+ if (!sb_rdonly(fs_info->sb))
+ return false;
+ if (unlikely(fs_info->mount_opt & BTRFS_MOUNT_FULL_RO_MASK))
+ return true;
+ return false;
+}
+
int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices)
{
u32 sectorsize;
@@ -3363,6 +3372,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
WRITE_ONCE(fs_info->fs_error, -EUCLEAN);
+ /* If the fs has any rescue options, no transaction is allowed. */
+ if (fs_is_full_ro(fs_info))
+ WRITE_ONCE(fs_info->fs_error, -EROFS);
+
/* Set up fs_info before parsing mount options */
nodesize = btrfs_super_nodesize(disk_super);
sectorsize = btrfs_super_sectorsize(disk_super);
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
index 0f7e1ef27891..8ffbc40ebe45 100644
--- a/fs/btrfs/fs.h
+++ b/fs/btrfs/fs.h
@@ -264,6 +264,14 @@ enum {
BTRFS_MOUNT_REF_TRACKER = (1ULL << 33),
};
+/* These mount options require a full read-only fs, no new transaction is allowed. */
+#define BTRFS_MOUNT_FULL_RO_MASK \
+ (BTRFS_MOUNT_NOLOGREPLAY | \
+ BTRFS_MOUNT_IGNOREBADROOTS | \
+ BTRFS_MOUNT_IGNOREDATACSUMS | \
+ BTRFS_MOUNT_IGNOREMETACSUMS | \
+ BTRFS_MOUNT_IGNORESUPERFLAGS)
+
/*
* Compat flags that we support. If any incompat flags are set other than the
* ones specified below then we will fail to mount