[06/11] btrfs-progs: handle split-brain scenario for scanned changed/unchanged device with INCOMPAT_METADATA_UUID
diff mbox series

Message ID 20191212110204.11128-7-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 the unchanged/changed device, just need to fs_devices in changing
state, or devices with same status:

a) The scanned device succeeded to sync into disk. The fs_devices
can be with INCOMPAT_METADATA_UUID. So their fsid and metadata_uuid
differs, and metadata_uuid is same as its metada_uuid.

b) The scanned device succeeded to sync into disk. The fs_devices
can be without INCOMPAT_METADATA_UUID. So their fsid and metadata_uuid
be same, and fsid is same as its metadata_uuid.

c) The scanned device failed to be into changing state. There
are some devices whose fsids and metadata_uuids are same as the
device's.

d) The above cases all are missed, only unchanged devices are same
as the device.

Case c and d can be merged into one that both fsid and metadata
requirements are meet.

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

Patch
diff mbox series

diff --git a/volumes.c b/volumes.c
index 0fd41186c54a..d094f85999d4 100644
--- a/volumes.c
+++ b/volumes.c
@@ -275,6 +275,50 @@  static struct btrfs_fs_devices *find_fsid_changed(
 	return find_fsid(disk_super->fsid, disk_super->metadata_uuid);
 }
 
+static struct btrfs_fs_devices *find_fsid_changing_metadata_uuid(
+					struct btrfs_super_block *disk_super)
+{
+	struct btrfs_fs_devices *fs_devices;
+
+	/*
+	 * Handle scanned device having completed its fsid change but
+	 * belonging to a fs_devices that was created by first scanning
+	 * a device which didn't have its fsid/metadata_uuid changed
+	 * at all and the CHANGING_FSID_V2 flag set.
+	 */
+	list_for_each_entry(fs_devices, &fs_uuids, list) {
+		if (fs_devices->fsid_change &&
+		    memcmp(disk_super->metadata_uuid, fs_devices->fsid,
+			   BTRFS_FSID_SIZE) == 0 &&
+		    memcmp(fs_devices->fsid, fs_devices->metadata_uuid,
+			   BTRFS_FSID_SIZE) == 0) {
+			return fs_devices;
+		}
+	}
+	/*
+	 * Handle scanned device having completed its fsid change but
+	 * belonging to a fs_devices that was created by a device that
+	 * has an outdated pair of fsid/metadata_uuid and
+	 * CHANGING_FSID_V2 flag set.
+	 */
+	list_for_each_entry(fs_devices, &fs_uuids, list) {
+		if (fs_devices->fsid_change &&
+		    memcmp(fs_devices->metadata_uuid,
+			   fs_devices->fsid, BTRFS_FSID_SIZE) != 0 &&
+		    memcmp(disk_super->metadata_uuid,
+			   fs_devices->metadata_uuid, BTRFS_FSID_SIZE) == 0) {
+			return fs_devices;
+		}
+	}
+
+	/*
+	 * The scanned device is unchanged. Try to find devices which are
+	 * successful in changing stage. Or old devices failed to be
+	 * changeing liked current device.
+	 */
+	return find_fsid(disk_super->fsid, disk_super->metadata_uuid);
+}
+
 static int device_list_add(const char *path,
 			   struct btrfs_super_block *disk_super,
 			   u64 devid, struct btrfs_fs_devices **fs_devices_ret)
@@ -292,6 +336,8 @@  static int device_list_add(const char *path,
 			fs_devices = find_fsid_inprogress(disk_super);
 		else
 			fs_devices = find_fsid_changed(disk_super);
+	} else if (metadata_uuid) {
+		fs_devices = find_fsid_changing_metadata_uuid(disk_super);
 	}
 
 	if (metadata_uuid && !fs_devices)