mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
btrfs: always use the second newest slot for rescue=usebackuproot
[RESCUE FAILURE] There is a bug report that "rescue=usebackuproot" failed to properly mount the fs, but if using btrfs-mod-sb to use the second newest slot, then the fs can even pass the full "btrfs check" and be mounted RW. [CAUSE] During init_tree_roots(), "rescue=usebackuproot" only makes a difference if the tree and chunk roots failed to be load. The loading only requires the root node/leaf to be properly loaded: - tree root - extent tree - block group tree - device tree - data reloc tree - quota tree (optional) - uuid tree - raid stripe tree (for RST feature) And it doesn't really check any child tree blocks, thus for a lot of cases, "rescue=usebackuproot" won't make a difference. [ENHANCEMENT] Instead of trying every slot and settling down on the first passing backup slot, always use the second newest slot. The newest slot should always match the root info in the super block, and if it worked the end user should not even need to bother to use backup root. Older backup slots normally have a very low chance to work. Link: https://github.com/kdave/btrfs-progs/issues/1162#issuecomment-5475477108 Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
d00b85308a
commit
c73eb6f727
|
|
@ -2711,73 +2711,55 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
|
|||
int backup_index = find_newest_super_backup(fs_info);
|
||||
struct btrfs_super_block *sb = fs_info->super_copy;
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
bool handle_error = false;
|
||||
bool use_backup = btrfs_test_opt(fs_info, USEBACKUPROOT);
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
|
||||
if (handle_error) {
|
||||
if (!IS_ERR(tree_root->node))
|
||||
free_extent_buffer(tree_root->node);
|
||||
tree_root->node = NULL;
|
||||
|
||||
if (!btrfs_test_opt(fs_info, USEBACKUPROOT))
|
||||
break;
|
||||
|
||||
free_root_pointers(fs_info, 0);
|
||||
|
||||
/*
|
||||
* Don't use the log in recovery mode, it won't be
|
||||
* valid
|
||||
*/
|
||||
btrfs_set_super_log_root(sb, 0);
|
||||
|
||||
btrfs_warn(fs_info, "try to load backup roots slot %d", i);
|
||||
ret = read_backup_root(fs_info, i);
|
||||
backup_index = ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (use_backup) {
|
||||
ret = read_backup_root(fs_info, 1);
|
||||
if (ret < 0) {
|
||||
btrfs_err(fs_info,
|
||||
"failed to load backup roots at slot %d", 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = load_important_roots(fs_info);
|
||||
if (ret) {
|
||||
handle_error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to hold btrfs_root::objectid_mutex since the fs
|
||||
* hasn't been fully initialised and we are the only user
|
||||
* Don't use the log in recovery mode, it won't be
|
||||
* valid
|
||||
*/
|
||||
ret = btrfs_init_root_free_objectid(tree_root);
|
||||
if (ret < 0) {
|
||||
handle_error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(tree_root->free_objectid <= BTRFS_LAST_FREE_OBJECTID);
|
||||
|
||||
ret = btrfs_read_roots(fs_info);
|
||||
if (ret < 0) {
|
||||
handle_error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* All successful */
|
||||
fs_info->generation = btrfs_header_generation(tree_root->node);
|
||||
btrfs_set_last_trans_committed(fs_info, fs_info->generation);
|
||||
fs_info->last_reloc_trans = 0;
|
||||
|
||||
/* Always begin writing backup roots after the one being used */
|
||||
if (backup_index < 0) {
|
||||
fs_info->backup_root_index = 0;
|
||||
} else {
|
||||
fs_info->backup_root_index = backup_index + 1;
|
||||
fs_info->backup_root_index %= BTRFS_NUM_BACKUP_ROOTS;
|
||||
}
|
||||
break;
|
||||
btrfs_set_super_log_root(sb, 0);
|
||||
backup_index = ret;
|
||||
btrfs_warn(fs_info, "loaded backup roots at slot %d", 1);
|
||||
}
|
||||
|
||||
ret = load_important_roots(fs_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* No need to hold btrfs_root::objectid_mutex since the fs
|
||||
* hasn't been fully initialised and we are the only user
|
||||
*/
|
||||
ret = btrfs_init_root_free_objectid(tree_root);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ASSERT(tree_root->free_objectid <= BTRFS_LAST_FREE_OBJECTID);
|
||||
|
||||
ret = btrfs_read_roots(fs_info);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* All successful */
|
||||
fs_info->generation = btrfs_header_generation(tree_root->node);
|
||||
btrfs_set_last_trans_committed(fs_info, fs_info->generation);
|
||||
fs_info->last_reloc_trans = 0;
|
||||
|
||||
/* Always begin writing backup roots after the one being used */
|
||||
if (backup_index < 0) {
|
||||
fs_info->backup_root_index = 0;
|
||||
} else {
|
||||
fs_info->backup_root_index = backup_index + 1;
|
||||
fs_info->backup_root_index %= BTRFS_NUM_BACKUP_ROOTS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user