btrfs: introduce new "rescue=ignoremetacsums" mount option
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>
This commit is contained in:
parent
cf31b271e0
commit
169aaaf2e0
@ -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.
|
* point, so they are handled as part of the no-checksum case.
|
||||||
*/
|
*/
|
||||||
if (inode && !(inode->flags & BTRFS_INODE_NODATASUM) &&
|
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)) {
|
!btrfs_is_data_reloc_root(inode->root)) {
|
||||||
if (should_async_write(bbio) &&
|
if (should_async_write(bbio) &&
|
||||||
btrfs_wq_submit_bio(bbio, bioc, &smap, mirror_num))
|
btrfs_wq_submit_bio(bbio, bioc, &smap, mirror_num))
|
||||||
|
@ -367,6 +367,7 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
|
|||||||
u8 result[BTRFS_CSUM_SIZE];
|
u8 result[BTRFS_CSUM_SIZE];
|
||||||
const u8 *header_csum;
|
const u8 *header_csum;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
const bool ignore_csum = btrfs_test_opt(fs_info, IGNOREMETACSUMS);
|
||||||
|
|
||||||
ASSERT(check);
|
ASSERT(check);
|
||||||
|
|
||||||
@ -399,13 +400,16 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
|
|||||||
|
|
||||||
if (memcmp(result, header_csum, csum_size) != 0) {
|
if (memcmp(result, header_csum, csum_size) != 0) {
|
||||||
btrfs_warn_rl(fs_info,
|
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,
|
eb->start, eb->read_mirror,
|
||||||
CSUM_FMT_VALUE(csum_size, header_csum),
|
CSUM_FMT_VALUE(csum_size, header_csum),
|
||||||
CSUM_FMT_VALUE(csum_size, result),
|
CSUM_FMT_VALUE(csum_size, result),
|
||||||
btrfs_header_level(eb));
|
btrfs_header_level(eb),
|
||||||
ret = -EUCLEAN;
|
ignore_csum ? ", ignored" : "");
|
||||||
goto out;
|
if (!ignore_csum) {
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_level != check->level) {
|
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 we have IGNOREDATACSUMS skip loading these roots. */
|
||||||
if (objectid == BTRFS_CSUM_TREE_OBJECTID &&
|
if (objectid == BTRFS_CSUM_TREE_OBJECTID &&
|
||||||
btrfs_test_opt(fs_info, IGNOREDATACSUMS)) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2184,7 +2188,7 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,
|
|||||||
|
|
||||||
if (!found || ret) {
|
if (!found || ret) {
|
||||||
if (objectid == BTRFS_CSUM_TREE_OBJECTID)
|
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))
|
if (!btrfs_test_opt(fs_info, IGNOREBADROOTS))
|
||||||
ret = ret ? ret : -ENOENT;
|
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))
|
if (sb_rdonly(sb))
|
||||||
set_bit(BTRFS_FS_STATE_RO, &fs_info->fs_state);
|
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);
|
return btrfs_alloc_stripe_hash_table(fs_info);
|
||||||
}
|
}
|
||||||
|
@ -353,7 +353,7 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
|||||||
u32 bio_offset = 0;
|
u32 bio_offset = 0;
|
||||||
|
|
||||||
if ((inode->flags & BTRFS_INODE_NODATASUM) ||
|
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;
|
return BLK_STS_OK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -98,7 +98,9 @@ enum {
|
|||||||
/* The btrfs_fs_info created for self-tests */
|
/* The btrfs_fs_info created for self-tests */
|
||||||
BTRFS_FS_STATE_DUMMY_FS_INFO,
|
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. */
|
/* Indicates there was an error cleaning up a log tree. */
|
||||||
BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
|
BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
|
||||||
@ -224,6 +226,7 @@ enum {
|
|||||||
BTRFS_MOUNT_IGNOREDATACSUMS = (1UL << 28),
|
BTRFS_MOUNT_IGNOREDATACSUMS = (1UL << 28),
|
||||||
BTRFS_MOUNT_NODISCARD = (1UL << 29),
|
BTRFS_MOUNT_NODISCARD = (1UL << 29),
|
||||||
BTRFS_MOUNT_NOSPACECACHE = (1UL << 30),
|
BTRFS_MOUNT_NOSPACECACHE = (1UL << 30),
|
||||||
|
BTRFS_MOUNT_IGNOREMETACSUMS = (1UL << 31),
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -20,7 +20,8 @@ static const char fs_state_chars[] = {
|
|||||||
[BTRFS_FS_STATE_TRANS_ABORTED] = 'A',
|
[BTRFS_FS_STATE_TRANS_ABORTED] = 'A',
|
||||||
[BTRFS_FS_STATE_DEV_REPLACING] = 'R',
|
[BTRFS_FS_STATE_DEV_REPLACING] = 'R',
|
||||||
[BTRFS_FS_STATE_DUMMY_FS_INFO] = 0,
|
[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',
|
[BTRFS_FS_STATE_LOG_CLEANUP_ERROR] = 'L',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ enum {
|
|||||||
Opt_rescue_nologreplay,
|
Opt_rescue_nologreplay,
|
||||||
Opt_rescue_ignorebadroots,
|
Opt_rescue_ignorebadroots,
|
||||||
Opt_rescue_ignoredatacsums,
|
Opt_rescue_ignoredatacsums,
|
||||||
|
Opt_rescue_ignoremetacsums,
|
||||||
Opt_rescue_parameter_all,
|
Opt_rescue_parameter_all,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -185,7 +186,9 @@ static const struct constant_table btrfs_parameter_rescue[] = {
|
|||||||
{ "ignorebadroots", Opt_rescue_ignorebadroots },
|
{ "ignorebadroots", Opt_rescue_ignorebadroots },
|
||||||
{ "ibadroots", Opt_rescue_ignorebadroots },
|
{ "ibadroots", Opt_rescue_ignorebadroots },
|
||||||
{ "ignoredatacsums", Opt_rescue_ignoredatacsums },
|
{ "ignoredatacsums", Opt_rescue_ignoredatacsums },
|
||||||
|
{ "ignoremetacsums", Opt_rescue_ignoremetacsums},
|
||||||
{ "idatacsums", Opt_rescue_ignoredatacsums },
|
{ "idatacsums", Opt_rescue_ignoredatacsums },
|
||||||
|
{ "imetacsums", Opt_rescue_ignoremetacsums},
|
||||||
{ "all", Opt_rescue_parameter_all },
|
{ "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:
|
case Opt_rescue_ignoredatacsums:
|
||||||
btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
|
btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
|
||||||
break;
|
break;
|
||||||
|
case Opt_rescue_ignoremetacsums:
|
||||||
|
btrfs_set_opt(ctx->mount_opt, IGNOREMETACSUMS);
|
||||||
|
break;
|
||||||
case Opt_rescue_parameter_all:
|
case Opt_rescue_parameter_all:
|
||||||
btrfs_set_opt(ctx->mount_opt, IGNOREDATACSUMS);
|
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, IGNOREBADROOTS);
|
||||||
btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
|
btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
|
||||||
break;
|
break;
|
||||||
@ -647,7 +654,8 @@ bool btrfs_check_options(const struct btrfs_fs_info *info, unsigned long *mount_
|
|||||||
if (!(flags & SB_RDONLY) &&
|
if (!(flags & SB_RDONLY) &&
|
||||||
(check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") ||
|
(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_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;
|
ret = false;
|
||||||
|
|
||||||
if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE) &&
|
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);
|
print_rescue_option(seq, "ignorebadroots", &printed);
|
||||||
if (btrfs_test_opt(info, IGNOREDATACSUMS))
|
if (btrfs_test_opt(info, IGNOREDATACSUMS))
|
||||||
print_rescue_option(seq, "ignoredatacsums", &printed);
|
print_rescue_option(seq, "ignoredatacsums", &printed);
|
||||||
|
if (btrfs_test_opt(info, IGNOREMETACSUMS))
|
||||||
|
print_rescue_option(seq, "ignoremetacsums", &printed);
|
||||||
if (btrfs_test_opt(info, FLUSHONCOMMIT))
|
if (btrfs_test_opt(info, FLUSHONCOMMIT))
|
||||||
seq_puts(seq, ",flushoncommit");
|
seq_puts(seq, ",flushoncommit");
|
||||||
if (btrfs_test_opt(info, DISCARD_SYNC))
|
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, 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, IGNOREBADROOTS, "ignoring bad roots");
|
||||||
btrfs_info_if_set(info, old, IGNOREDATACSUMS, "ignoring data csums");
|
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, NODATACOW, "setting datacow");
|
||||||
btrfs_info_if_unset(info, old, SSD, "not using ssd optimizations");
|
btrfs_info_if_unset(info, old, SSD, "not using ssd optimizations");
|
||||||
|
@ -385,6 +385,7 @@ static const char *rescue_opts[] = {
|
|||||||
"nologreplay",
|
"nologreplay",
|
||||||
"ignorebadroots",
|
"ignorebadroots",
|
||||||
"ignoredatacsums",
|
"ignoredatacsums",
|
||||||
|
"ignoremetacsums",
|
||||||
"all",
|
"all",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1844,7 +1844,7 @@ out:
|
|||||||
* here so that we don't attempt to log the csums later.
|
* here so that we don't attempt to log the csums later.
|
||||||
*/
|
*/
|
||||||
if ((inode->flags & BTRFS_INODE_NODATASUM) ||
|
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,
|
while ((sum = list_first_entry_or_null(&ordered->list,
|
||||||
typeof(*sum), list))) {
|
typeof(*sum), list))) {
|
||||||
list_del(&sum->list);
|
list_del(&sum->list);
|
||||||
|
Loading…
Reference in New Issue
Block a user