]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: introduce new "rescue=ignoremetacsums" mount option
authorQu Wenruo <wqu@suse.com>
Fri, 14 Jun 2024 04:22:30 +0000 (13:52 +0930)
committerDavid Sterba <dsterba@suse.com>
Thu, 11 Jul 2024 13:33:29 +0000 (15:33 +0200)
Introduce "rescue=ignoremetacsums" to ignore metadata csums, all the
other metadata sanity checks are still kept as is.

This new mount option is mostly to allow the kernel to mount an
interrupted checksum conversion (at the metadata csum overwrite stage).

And since the main part of metadata sanity checks is inside
tree-checker, we shouldn't lose much safety, and the new mount option is
rescue mount option it requires full read-only mount.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/bio.c
fs/btrfs/disk-io.c
fs/btrfs/file-item.c
fs/btrfs/fs.h
fs/btrfs/messages.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/zoned.c

index f59b00be26f33c3aa097e7cb40d77817182ca72d..f04d931099601a786f47d0b2a0c0c0f6a0d5ddcd 100644 (file)
@@ -732,7 +732,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
                 * point, so they are handled as part of the no-checksum case.
                 */
                if (inode && !(inode->flags & BTRFS_INODE_NODATASUM) &&
-                   !test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state) &&
+                   !test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state) &&
                    !btrfs_is_data_reloc_root(inode->root)) {
                        if (should_async_write(bbio) &&
                            btrfs_wq_submit_bio(bbio, bioc, &smap, mirror_num))
index 686eec119eb4cf5f25d1224b29cbbc2d26ec7fa1..2cfb7ab24aa9e3ffe078e526da9e57650c84022a 100644 (file)
@@ -367,6 +367,7 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
        u8 result[BTRFS_CSUM_SIZE];
        const u8 *header_csum;
        int ret = 0;
+       const bool ignore_csum = btrfs_test_opt(fs_info, IGNOREMETACSUMS);
 
        ASSERT(check);
 
@@ -399,13 +400,16 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
 
        if (memcmp(result, header_csum, csum_size) != 0) {
                btrfs_warn_rl(fs_info,
-"checksum verify failed on logical %llu mirror %u wanted " CSUM_FMT " found " CSUM_FMT " level %d",
+"checksum verify failed on logical %llu mirror %u wanted " CSUM_FMT " found " CSUM_FMT " level %d%s",
                              eb->start, eb->read_mirror,
                              CSUM_FMT_VALUE(csum_size, header_csum),
                              CSUM_FMT_VALUE(csum_size, result),
-                             btrfs_header_level(eb));
-               ret = -EUCLEAN;
-               goto out;
+                             btrfs_header_level(eb),
+                             ignore_csum ? ", ignored" : "");
+               if (!ignore_csum) {
+                       ret = -EUCLEAN;
+                       goto out;
+               }
        }
 
        if (found_level != check->level) {
@@ -2131,7 +2135,7 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,
        /* If we have IGNOREDATACSUMS skip loading these roots. */
        if (objectid == BTRFS_CSUM_TREE_OBJECTID &&
            btrfs_test_opt(fs_info, IGNOREDATACSUMS)) {
-               set_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state);
+               set_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state);
                return 0;
        }
 
@@ -2184,7 +2188,7 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,
 
        if (!found || ret) {
                if (objectid == BTRFS_CSUM_TREE_OBJECTID)
-                       set_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state);
+                       set_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state);
 
                if (!btrfs_test_opt(fs_info, IGNOREBADROOTS))
                        ret = ret ? ret : -ENOENT;
@@ -2865,6 +2869,8 @@ static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block
 
        if (sb_rdonly(sb))
                set_bit(BTRFS_FS_STATE_RO, &fs_info->fs_state);
+       if (btrfs_test_opt(fs_info, IGNOREMETACSUMS))
+               set_bit(BTRFS_FS_STATE_SKIP_META_CSUMS, &fs_info->fs_state);
 
        return btrfs_alloc_stripe_hash_table(fs_info);
 }
index e815fefaffe1719e0f007a56bc49b127fc01c5a0..5c342fe1af619215fd02e8e5682e38dcb574e3ea 100644 (file)
@@ -353,7 +353,7 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
        u32 bio_offset = 0;
 
        if ((inode->flags & BTRFS_INODE_NODATASUM) ||
-           test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state))
+           test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state))
                return BLK_STS_OK;
 
        /*
index 18e0d3539496724e85f8bf4e5ef0283e70247f99..d5d473aafe984da30b64bd53139ff8bd544fd1fb 100644 (file)
@@ -98,7 +98,9 @@ enum {
        /* The btrfs_fs_info created for self-tests */
        BTRFS_FS_STATE_DUMMY_FS_INFO,
 
-       BTRFS_FS_STATE_NO_CSUMS,
+       /* Checksum errors are ignored. */
+       BTRFS_FS_STATE_NO_DATA_CSUMS,
+       BTRFS_FS_STATE_SKIP_META_CSUMS,
 
        /* Indicates there was an error cleaning up a log tree. */
        BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
@@ -224,6 +226,7 @@ enum {
        BTRFS_MOUNT_IGNOREDATACSUMS             = (1UL << 28),
        BTRFS_MOUNT_NODISCARD                   = (1UL << 29),
        BTRFS_MOUNT_NOSPACECACHE                = (1UL << 30),
+       BTRFS_MOUNT_IGNOREMETACSUMS             = (1UL << 31),
 };
 
 /*
index 210d9c82e2ae05976fc75325562f25cd7f9dc0b2..77752eec125d939afd3b61a584499b32e75b0347 100644 (file)
@@ -20,7 +20,8 @@ static const char fs_state_chars[] = {
        [BTRFS_FS_STATE_TRANS_ABORTED]          = 'A',
        [BTRFS_FS_STATE_DEV_REPLACING]          = 'R',
        [BTRFS_FS_STATE_DUMMY_FS_INFO]          = 0,
-       [BTRFS_FS_STATE_NO_CSUMS]               = 'C',
+       [BTRFS_FS_STATE_NO_DATA_CSUMS]          = 'C',
+       [BTRFS_FS_STATE_SKIP_META_CSUMS]        = 'S',
        [BTRFS_FS_STATE_LOG_CLEANUP_ERROR]      = 'L',
 };
 
index 12cc1805af39a72da42203c657ea2a8b325768d9..65d2abdc9975e57dc9cca25b8fcb217ae0f20f46 100644 (file)
@@ -176,6 +176,7 @@ enum {
        Opt_rescue_nologreplay,
        Opt_rescue_ignorebadroots,
        Opt_rescue_ignoredatacsums,
+       Opt_rescue_ignoremetacsums,
        Opt_rescue_parameter_all,
 };
 
@@ -185,7 +186,9 @@ static const struct constant_table btrfs_parameter_rescue[] = {
        { "ignorebadroots", Opt_rescue_ignorebadroots },
        { "ibadroots", Opt_rescue_ignorebadroots },
        { "ignoredatacsums", Opt_rescue_ignoredatacsums },
+       { "ignoremetacsums", Opt_rescue_ignoremetacsums},
        { "idatacsums", Opt_rescue_ignoredatacsums },
+       { "imetacsums", Opt_rescue_ignoremetacsums},
        { "all", Opt_rescue_parameter_all },
        {}
 };
@@ -571,8 +574,12 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
                case Opt_rescue_ignoredatacsums:
                        btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
                        break;
+               case Opt_rescue_ignoremetacsums:
+                       btrfs_set_opt(ctx->mount_opt, IGNOREMETACSUMS);
+                       break;
                case Opt_rescue_parameter_all:
                        btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
+                       btrfs_set_opt(ctx->mount_opt, IGNOREMETACSUMS);
                        btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS);
                        btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
                        break;
@@ -647,7 +654,8 @@ bool btrfs_check_options(const struct btrfs_fs_info *info, unsigned long *mount_
        if (!(flags & SB_RDONLY) &&
            (check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
             check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") ||
-            check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums")))
+            check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums") ||
+            check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREMETACSUMS, "ignoremetacsums")))
                ret = false;
 
        if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE) &&
@@ -1063,6 +1071,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                print_rescue_option(seq, "ignorebadroots", &printed);
        if (btrfs_test_opt(info, IGNOREDATACSUMS))
                print_rescue_option(seq, "ignoredatacsums", &printed);
+       if (btrfs_test_opt(info, IGNOREMETACSUMS))
+               print_rescue_option(seq, "ignoremetacsums", &printed);
        if (btrfs_test_opt(info, FLUSHONCOMMIT))
                seq_puts(seq, ",flushoncommit");
        if (btrfs_test_opt(info, DISCARD_SYNC))
@@ -1420,6 +1430,7 @@ static void btrfs_emit_options(struct btrfs_fs_info *info,
        btrfs_info_if_set(info, old, USEBACKUPROOT, "trying to use backup root at mount time");
        btrfs_info_if_set(info, old, IGNOREBADROOTS, "ignoring bad roots");
        btrfs_info_if_set(info, old, IGNOREDATACSUMS, "ignoring data csums");
+       btrfs_info_if_set(info, old, IGNOREMETACSUMS, "ignoring meta csums");
 
        btrfs_info_if_unset(info, old, NODATACOW, "setting datacow");
        btrfs_info_if_unset(info, old, SSD, "not using ssd optimizations");
index c58cea0da597ef296232fa2335abf0813ea77b0a..0e0e8eb84ca2dbe3a7b33913058e5fac1f9affa5 100644 (file)
@@ -385,6 +385,7 @@ static const char *rescue_opts[] = {
        "nologreplay",
        "ignorebadroots",
        "ignoredatacsums",
+       "ignoremetacsums",
        "all",
 };
 
index 58e724c80a0634d8e88ad3c5400e5c436d578b6d..df7733044f7ecea3b9bf96b8612cb9293630d383 100644 (file)
@@ -1844,7 +1844,7 @@ out:
         * here so that we don't attempt to log the csums later.
         */
        if ((inode->flags & BTRFS_INODE_NODATASUM) ||
-           test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state)) {
+           test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state)) {
                while ((sum = list_first_entry_or_null(&ordered->list,
                                                       typeof(*sum), list))) {
                        list_del(&sum->list);