diff mbox series

[07/11] btrfs-progs: handle split-brain scenario for scanned changed/unchanged device without INCOMPAT_METADATA_UUID

Message ID 20191212110204.11128-8-Damenly_Su@gmx.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: metadata_uuid feature fixes and portation | expand

Commit Message

Su Yue Dec. 12, 2019, 11:02 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
must be with INCOMPAT_METADATA_UUID. So their fsid and metadata_uuid
differs, and metadata_uuid is same as its fsid.

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

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

Case b and c can be merged into one that only same fsid requirement is
meet.

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

Patch

diff --git a/volumes.c b/volumes.c
index d094f85999d4..94940dd82d0f 100644
--- a/volumes.c
+++ b/volumes.c
@@ -319,6 +319,35 @@  static struct btrfs_fs_devices *find_fsid_changing_metadata_uuid(
 	return find_fsid(disk_super->fsid, disk_super->metadata_uuid);
 }
 
+static struct btrfs_fs_devices *find_fsid_changing(
+					struct btrfs_super_block *disk_super)
+{
+	struct btrfs_fs_devices *fs_devices;
+
+	/*
+	 * Handles the case where scanned device is part of an fs that had
+	 * multiple successful changes of FSID but currently device didn't
+	 * observe it.
+	 * Since the scanned devices does not own the metadata_uuid feature,
+	 * fsid and metadata_uuid of the changing devices must differ, and
+	 * their metadata_uuid must be same as disk_super->fsid.
+	 */
+	list_for_each_entry(fs_devices, &fs_uuids, list) {
+		if (!fs_devices->fsid_change)
+			continue;
+		if (memcmp(fs_devices->fsid, fs_devices->metadata_uuid,
+			   BTRFS_FSID_SIZE) != 0 &&
+		    memcmp(fs_devices->metadata_uuid, disk_super->fsid,
+			   BTRFS_FSID_SIZE) == 0)
+			return fs_devices;
+	}
+
+	/*
+	 * Back to find newer fs_devices is changeing or some in same stage.
+	 */
+	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)
@@ -338,6 +367,8 @@  static int device_list_add(const char *path,
 			fs_devices = find_fsid_changed(disk_super);
 	} else if (metadata_uuid) {
 		fs_devices = find_fsid_changing_metadata_uuid(disk_super);
+	} else {
+		fs_devices = find_fsid_changing(disk_super);
 	}
 
 	if (metadata_uuid && !fs_devices)