Commit 05840710 authored by Nikolay Borisov's avatar Nikolay Borisov Committed by David Sterba

btrfs: Handle another split brain scenario with metadata uuid feature

There is one more cases which isn't handled by the original metadata
uuid work. Namely, when a filesystem has METADATA_UUID incompat bit and
the user decides to change the FSID to the original one e.g. have
metadata_uuid and fsid match. In case of power failure while this
operation is in progress we could end up in a situation where some of
the disks have the incompat bit removed and the other half have both
METADATA_UUID_INCOMPAT and FSID_CHANGING_IN_PROGRESS flags.

This patch handles the case where a disk that has successfully changed
its FSID such that it equals METADATA_UUID is scanned first.
Subsequently when a disk with both
METADATA_UUID_INCOMPAT/FSID_CHANGING_IN_PROGRESS flags is scanned
find_fsid_changed won't be able to find an appropriate btrfs_fs_devices.
This is done by extending find_fsid_changed to correctly find
btrfs_fs_devices whose metadata_uuid/fsid are the same and they match
the metadata_uuid of the currently scanned device.

Fixes: cc5de4e7 ("btrfs: Handle final split-brain possibility during fsid change")
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Reported-by: default avatarSu Yue <Damenly_Su@gmx.com>
Signed-off-by: default avatarNikolay Borisov <nborisov@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent c6730a0e
...@@ -710,17 +710,28 @@ static struct btrfs_fs_devices *find_fsid_changed( ...@@ -710,17 +710,28 @@ static struct btrfs_fs_devices *find_fsid_changed(
/* /*
* Handles the case where scanned device is part of an fs that had * Handles the case where scanned device is part of an fs that had
* multiple successful changes of FSID but curently device didn't * multiple successful changes of FSID but curently device didn't
* observe it. Meaning our fsid will be different than theirs. * observe it. Meaning our fsid will be different than theirs. We need
* to handle two subcases :
* 1 - The fs still continues to have different METADATA/FSID uuids.
* 2 - The fs is switched back to its original FSID (METADATA/FSID
* are equal).
*/ */
list_for_each_entry(fs_devices, &fs_uuids, fs_list) { list_for_each_entry(fs_devices, &fs_uuids, fs_list) {
/* Changed UUIDs */
if (memcmp(fs_devices->metadata_uuid, fs_devices->fsid, if (memcmp(fs_devices->metadata_uuid, fs_devices->fsid,
BTRFS_FSID_SIZE) != 0 && BTRFS_FSID_SIZE) != 0 &&
memcmp(fs_devices->metadata_uuid, disk_super->metadata_uuid, memcmp(fs_devices->metadata_uuid, disk_super->metadata_uuid,
BTRFS_FSID_SIZE) == 0 && BTRFS_FSID_SIZE) == 0 &&
memcmp(fs_devices->fsid, disk_super->fsid, memcmp(fs_devices->fsid, disk_super->fsid,
BTRFS_FSID_SIZE) != 0) { BTRFS_FSID_SIZE) != 0)
return fs_devices;
/* Unchanged UUIDs */
if (memcmp(fs_devices->metadata_uuid, fs_devices->fsid,
BTRFS_FSID_SIZE) == 0 &&
memcmp(fs_devices->fsid, disk_super->metadata_uuid,
BTRFS_FSID_SIZE) == 0)
return fs_devices; return fs_devices;
}
} }
return NULL; return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment