]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: Handle another split brain scenario with metadata uuid feature
authorNikolay Borisov <nborisov@suse.com>
Fri, 10 Jan 2020 12:11:34 +0000 (14:11 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Feb 2020 12:36:58 +0000 (04:36 -0800)
commit 05840710149c7d1a78ea85a2db5723f706e97d8f upstream.

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: cc5de4e70256 ("btrfs: Handle final split-brain possibility during fsid change")
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Reported-by: Su Yue <Damenly_Su@gmx.com>
Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/btrfs/volumes.c

index 9b78e720c6973c6e141fff069e212cd388fd58f8..72ff80f7f24caf06a80d797096d6c7e273d522e5 100644 (file)
@@ -697,17 +697,28 @@ static struct btrfs_fs_devices *find_fsid_changed(
        /*
         * Handles the case where scanned device is part of an fs that had
         * 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) {
+               /* Changed UUIDs */
                if (memcmp(fs_devices->metadata_uuid, fs_devices->fsid,
                           BTRFS_FSID_SIZE) != 0 &&
                    memcmp(fs_devices->metadata_uuid, disk_super->metadata_uuid,
                           BTRFS_FSID_SIZE) == 0 &&
                    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 NULL;