@@ -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,25 @@ 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)) {
+ 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);
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-prog can do better. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- tune/change-metadata-uuid.c | 48 ++++++++++++++++++++++++++++++------- tune/change-uuid.c | 4 ++-- tune/tune.h | 2 -- 3 files changed, 42 insertions(+), 12 deletions(-)