btrfs-progs: tune: recover from failed btrfstune -m|M
Currently, to fix device following the write failure of one or more devices during btrfstune -m|M, we rely on the kernel's ability to reassemble devices, even when they possess distinct fsids. Kernel hinges combinations of metadata_uuid and generation number, with additional cues taken from the fsid and the BTRFS_SUPER_FLAG_CHANGING_FSID_V2 flag. This patch adds this logic to btrfs-progs. In complex scenarios (such as multiple fsids with the same metadata_uuid and matching generation), user intervention becomes necessary to resolve the situations which btrfs-progs can do better. Signed-off-by: Anand Jain <anand.jain@oracle.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
e75658fe57
commit
cabf70c7b8
|
@ -21,9 +21,31 @@
|
|||
#include "kernel-shared/uapi/btrfs.h"
|
||||
#include "kernel-shared/ctree.h"
|
||||
#include "kernel-shared/transaction.h"
|
||||
#include "kernel-shared/volumes.h"
|
||||
#include "common/messages.h"
|
||||
#include "tune/tune.h"
|
||||
|
||||
/*
|
||||
* Return 0 for no unfinished metadata_uuid change.
|
||||
* Return >0 for unfinished metadata_uuid change, and restore unfinished
|
||||
* fsid/metadata_uuid into fsid_ret/metadata_uuid_ret.
|
||||
*/
|
||||
static int check_unfinished_metadata_uuid(struct btrfs_fs_info *fs_info,
|
||||
uuid_t fsid_ret,
|
||||
uuid_t metadata_uuid_ret)
|
||||
{
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
|
||||
if (fs_info->fs_devices->inconsistent_super) {
|
||||
memcpy(fsid_ret, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
|
||||
read_extent_buffer(tree_root->node, metadata_uuid_ret,
|
||||
btrfs_header_chunk_tree_uuid(tree_root->node),
|
||||
BTRFS_UUID_SIZE);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_metadata_uuid(struct btrfs_root *root, const char *new_fsid_string)
|
||||
{
|
||||
struct btrfs_super_block *disk_super;
|
||||
|
@ -45,15 +67,24 @@ int set_metadata_uuid(struct btrfs_root *root, const char *new_fsid_string)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (check_unfinished_fsid_change(root->fs_info, fsid, metadata_uuid)) {
|
||||
error("UUID rewrite in progress, cannot change metadata_uuid");
|
||||
return 1;
|
||||
}
|
||||
if (check_unfinished_metadata_uuid(root->fs_info, fsid, metadata_uuid)) {
|
||||
if (new_fsid_string) {
|
||||
uuid_t tmp;
|
||||
|
||||
if (new_fsid_string)
|
||||
uuid_parse(new_fsid_string, fsid);
|
||||
else
|
||||
uuid_generate(fsid);
|
||||
uuid_parse(new_fsid_string, tmp);
|
||||
if (memcmp(tmp, fsid, BTRFS_FSID_SIZE) != 0) {
|
||||
error(
|
||||
"new fsid %s is not the same with unfinished fsid change",
|
||||
new_fsid_string);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (new_fsid_string)
|
||||
uuid_parse(new_fsid_string, fsid);
|
||||
else
|
||||
uuid_generate(fsid);
|
||||
}
|
||||
|
||||
new_fsid = (memcmp(fsid, disk_super->fsid, BTRFS_FSID_SIZE) != 0);
|
||||
|
||||
|
|
|
@ -210,8 +210,8 @@ static int change_fsid_done(struct btrfs_fs_info *fs_info)
|
|||
* Return >0 for unfinished fsid change, and restore unfinished fsid/
|
||||
* chunk_tree_id into fsid_ret/chunk_id_ret.
|
||||
*/
|
||||
int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
|
||||
uuid_t fsid_ret, uuid_t chunk_id_ret)
|
||||
static int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
|
||||
uuid_t fsid_ret, uuid_t chunk_id_ret)
|
||||
{
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ struct btrfs_fs_info;
|
|||
|
||||
int update_seeding_flag(struct btrfs_root *root, const char *device, int set_flag, int force);
|
||||
|
||||
int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
|
||||
uuid_t fsid_ret, uuid_t chunk_id_ret);
|
||||
int change_uuid(struct btrfs_fs_info *fs_info, const char *new_fsid_str);
|
||||
int set_metadata_uuid(struct btrfs_root *root, const char *uuid_string);
|
||||
|
||||
|
|
Loading…
Reference in New Issue