diff options
| author | Qu Wenruo <wqu@suse.com> | 2026-09-06 16:33:38 +0930 |
|---|---|---|
| committer | David Sterba <dsterba@suse.com> | 2026-10-12 19:16:24 +0200 |
| commit | 9421d1897ba2185cd2c3cf7bf517fd99d4f58516 (patch) | |
| tree | 9688029ae4a5abe8deb1019a4bdc35419e1b7518 /fs/btrfs | |
| parent | c73eb6f727414a0a78ee993eccd6c2d2065e9571 (diff) | |
btrfs: introduce more accurate usebackuproot options
Previously we had no way to tell btrfs to use which backup slot, but
always use the newest backup, and retry until all backup roots are
exhausted.
This doesn't give any control to the end user, even if the end user
wants to use a specific backup slot.
To address this problem, allow more fine-control on usebackuproot rescue
option by introducing the following 4 rescue mount options:
- rescue=usebackuproot_0
- rescue=usebackuproot_1
- rescue=usebackuproot_2
- rescue=usebackuproot_3
The number 0 means the newest slot, which should be the same as the one
recorded in the super block and no need to load any backup root.
1/2/3 means the second/third/fourth(oldest) backup slot to use.
The existing "rescue=usebackuproot" is just an alias of
"rescue=usebackuproot_1".
This will allow users to choose which backup root to use, thus can have
a better control than blindly choose any slot that can pass the very
basic root node checks.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
| -rw-r--r-- | fs/btrfs/disk-io.c | 12 | ||||
| -rw-r--r-- | fs/btrfs/fs.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 28 |
3 files changed, 36 insertions, 5 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d3d3d67ced3e..66b054eb98c6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2715,10 +2715,14 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info) int ret = 0; if (use_backup) { - ret = read_backup_root(fs_info, 1); + ASSERT(fs_info->use_backup_slot >= 0 && + fs_info->use_backup_slot < BTRFS_NUM_BACKUP_ROOTS); + + ret = read_backup_root(fs_info, fs_info->use_backup_slot); if (ret < 0) { btrfs_err(fs_info, - "failed to load backup roots at slot %d", 1); + "failed to load backup roots at slot %d", + fs_info->use_backup_slot); return ret; } /* @@ -2727,7 +2731,8 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info) */ btrfs_set_super_log_root(sb, 0); backup_index = ret; - btrfs_warn(fs_info, "loaded backup roots at slot %d", 1); + btrfs_warn(fs_info, "loaded backup roots at slot %d", + fs_info->use_backup_slot); } ret = load_important_roots(fs_info); @@ -2898,6 +2903,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) init_waitqueue_head(&fs_info->async_submit_wait); init_waitqueue_head(&fs_info->delayed_iputs_wait); + fs_info->use_backup_slot = -1; /* Usable values until the real ones are cached from the superblock */ fs_info->nodesize = 4096; fs_info->sectorsize = 4096; diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h index 3eba8438593c..649623c603e8 100644 --- a/fs/btrfs/fs.h +++ b/fs/btrfs/fs.h @@ -857,6 +857,7 @@ struct btrfs_fs_info { /* Next backup root to be overwritten */ int backup_root_index; + int use_backup_slot; /* Device replace state */ struct btrfs_dev_replace dev_replace; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ddb620ac241b..8d01409ed382 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -87,6 +87,7 @@ struct btrfs_fs_context { unsigned long long mount_opt; unsigned long compress_type:4; int compress_level; + int use_backup_slot; refcount_t refs; }; @@ -175,6 +176,10 @@ static const struct constant_table btrfs_parameter_space_cache[] = { enum { Opt_rescue_usebackuproot, + Opt_rescue_usebackup_slot_0, + Opt_rescue_usebackup_slot_1, + Opt_rescue_usebackup_slot_2, + Opt_rescue_usebackup_slot_3, Opt_rescue_nologreplay, Opt_rescue_ignorebadroots, Opt_rescue_ignoredatacsums, @@ -185,6 +190,10 @@ enum { static const struct constant_table btrfs_parameter_rescue[] = { { "usebackuproot", Opt_rescue_usebackuproot }, + { "usebackuproot_0", Opt_rescue_usebackup_slot_0}, + { "usebackuproot_1", Opt_rescue_usebackup_slot_1}, + { "usebackuproot_2", Opt_rescue_usebackup_slot_2}, + { "usebackuproot_3", Opt_rescue_usebackup_slot_3}, { "nologreplay", Opt_rescue_nologreplay }, { "ignorebadroots", Opt_rescue_ignorebadroots }, { "ibadroots", Opt_rescue_ignorebadroots }, @@ -588,6 +597,14 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param) switch (result.uint_32) { case Opt_rescue_usebackuproot: btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT); + ctx->use_backup_slot = 1; + break; + case Opt_rescue_usebackup_slot_0: + case Opt_rescue_usebackup_slot_1: + case Opt_rescue_usebackup_slot_2: + case Opt_rescue_usebackup_slot_3: + btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT); + ctx->use_backup_slot = result.uint_32 - Opt_rescue_usebackup_slot_0; break; case Opt_rescue_nologreplay: btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY); @@ -611,6 +628,7 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param) btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS); btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY); btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT); + ctx->use_backup_slot = 1; break; default: btrfs_info(NULL, "unrecognized rescue option '%s'", @@ -1089,8 +1107,11 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) seq_puts(seq, ",notreelog"); if (btrfs_test_opt(info, NOLOGREPLAY)) print_rescue_option(seq, "nologreplay", &printed); - if (btrfs_test_opt(info, USEBACKUPROOT)) - print_rescue_option(seq, "usebackuproot", &printed); + if (btrfs_test_opt(info, USEBACKUPROOT)) { + seq_printf(seq, "%susebackuproot_%d", printed ? ":" : ",rescue=", + info->use_backup_slot); + printed = true; + } if (btrfs_test_opt(info, IGNOREBADROOTS)) print_rescue_option(seq, "ignorebadroots", &printed); if (btrfs_test_opt(info, IGNOREDATACSUMS)) @@ -1406,6 +1427,7 @@ static void btrfs_ctx_to_info(struct btrfs_fs_info *fs_info, struct btrfs_fs_con fs_info->mount_opt = ctx->mount_opt; fs_info->compress_type = ctx->compress_type; fs_info->compress_level = ctx->compress_level; + fs_info->use_backup_slot = ctx->use_backup_slot; } static void btrfs_info_to_ctx(struct btrfs_fs_info *fs_info, struct btrfs_fs_context *ctx) @@ -1417,6 +1439,7 @@ static void btrfs_info_to_ctx(struct btrfs_fs_info *fs_info, struct btrfs_fs_con ctx->mount_opt = fs_info->mount_opt; ctx->compress_type = fs_info->compress_type; ctx->compress_level = fs_info->compress_level; + ctx->use_backup_slot = fs_info->use_backup_slot; } #define btrfs_info_if_set(fs_info, old_ctx, opt, fmt, args...) \ @@ -2209,6 +2232,7 @@ static int btrfs_init_fs_context(struct fs_context *fc) if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) { btrfs_info_to_ctx(btrfs_sb(fc->root->d_sb), ctx); } else { + ctx->use_backup_slot = -1; ctx->thread_pool_size = min_t(unsigned long, num_online_cpus() + 2, 8); ctx->max_inline = BTRFS_DEFAULT_MAX_INLINE; |
