[04/11] btrfs-progs: handle split-brain scenario for scanned changing device without INCOMPAT_METADATA_UUID
diff mbox series

Message ID 20191212110204.11128-5-Damenly_Su@gmx.com
State New
Headers show
Series
  • btrfs-progs: metadata_uuid feature fixes and portation
Related show

Commit Message

Damenly Su Dec. 12, 2019, 11:01 a.m. UTC
From: Su Yue <Damenly_Su@gmx.com>

For a scanned changing device without INCOMPAT_METADATA_UUID, the
situation may be
a) The scanned failed to be pull into disk, and there are successful
synced devices which is already in fs_devices->devices. So their
fsid and metadata_uuid must differ. Also since the scanned device is
without INCOMPAT_METADATA_UUID, so fs_device->metadata_uuid must equals
disk_super->fs_id.

b) The scanned device is in the newest state. There are some old
devices failed to be with CHANGING_FSID_V2 or some devices just like
the device.

Signed-off-by: Su Yue <Damenly_Su@gmx.com>
---
 volumes.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

Patch
diff mbox series

diff --git a/volumes.c b/volumes.c
index 88e926e98d5b..bc1726975ce4 100644
--- a/volumes.c
+++ b/volumes.c
@@ -205,18 +205,46 @@  static struct btrfs_fs_devices *find_fsid(u8 *fsid, u8 *metadata_uuid)
 	return NULL;
 }
 
+/*
+ * Handle scanned device which has CHANGING_FSID_V2 set, it might belong to
+ * either a filesystem which has disks with completed fsid change or it might
+ * belong to fs with no UUID changes in effect, handle both.
+ */
+static struct btrfs_fs_devices *find_fsid_inprogress(
+					struct btrfs_super_block *disk_super)
+{
+	struct btrfs_fs_devices *fs_devices;
+
+	list_for_each_entry(fs_devices, &fs_uuids, list) {
+		if (memcmp(fs_devices->metadata_uuid, fs_devices->fsid,
+			   BTRFS_FSID_SIZE) != 0 &&
+		    memcmp(fs_devices->metadata_uuid, disk_super->fsid,
+			   BTRFS_FSID_SIZE) == 0 && !fs_devices->fsid_change) {
+			return fs_devices;
+		}
+	}
+
+	return find_fsid(disk_super->fsid, NULL);
+}
+
 static int device_list_add(const char *path,
 			   struct btrfs_super_block *disk_super,
 			   u64 devid, struct btrfs_fs_devices **fs_devices_ret)
 {
 	struct btrfs_device *device;
-	struct btrfs_fs_devices *fs_devices;
+	struct btrfs_fs_devices *fs_devices = NULL;
 	u64 found_transid = btrfs_super_generation(disk_super);
 	bool metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
 		BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
 	bool fsid_change_in_progress = (btrfs_super_flags(disk_super) &
 					BTRFS_SUPER_FLAG_CHANGING_FSID_V2);
-	if (metadata_uuid)
+
+	if (fsid_change_in_progress) {
+		if (!metadata_uuid)
+			fs_devices = find_fsid_inprogress(disk_super);
+	}
+
+	if (metadata_uuid && !fs_devices)
 		fs_devices = find_fsid(disk_super->fsid,
 				       disk_super->metadata_uuid);
 	else