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/uapi/btrfs.h"
|
||||||
#include "kernel-shared/ctree.h"
|
#include "kernel-shared/ctree.h"
|
||||||
#include "kernel-shared/transaction.h"
|
#include "kernel-shared/transaction.h"
|
||||||
|
#include "kernel-shared/volumes.h"
|
||||||
#include "common/messages.h"
|
#include "common/messages.h"
|
||||||
#include "tune/tune.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)
|
int set_metadata_uuid(struct btrfs_root *root, const char *new_fsid_string)
|
||||||
{
|
{
|
||||||
struct btrfs_super_block *disk_super;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_unfinished_fsid_change(root->fs_info, fsid, metadata_uuid)) {
|
if (check_unfinished_metadata_uuid(root->fs_info, fsid, metadata_uuid)) {
|
||||||
error("UUID rewrite in progress, cannot change metadata_uuid");
|
if (new_fsid_string) {
|
||||||
return 1;
|
uuid_t tmp;
|
||||||
}
|
|
||||||
|
|
||||||
if (new_fsid_string)
|
uuid_parse(new_fsid_string, tmp);
|
||||||
uuid_parse(new_fsid_string, fsid);
|
if (memcmp(tmp, fsid, BTRFS_FSID_SIZE) != 0) {
|
||||||
else
|
error(
|
||||||
uuid_generate(fsid);
|
"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);
|
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/
|
* Return >0 for unfinished fsid change, and restore unfinished fsid/
|
||||||
* chunk_tree_id into fsid_ret/chunk_id_ret.
|
* chunk_tree_id into fsid_ret/chunk_id_ret.
|
||||||
*/
|
*/
|
||||||
int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
|
static int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
|
||||||
uuid_t fsid_ret, uuid_t chunk_id_ret)
|
uuid_t fsid_ret, uuid_t chunk_id_ret)
|
||||||
{
|
{
|
||||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
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 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 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);
|
int set_metadata_uuid(struct btrfs_root *root, const char *uuid_string);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue