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

btrfs: Add handling for disk split-brain scenario during fsid change

Even though fsid change without rewrite is a very quick operation it's
still possible to experience a split-brain scenario if power loss occurs
at the most inconvenient time. This patch handles the case where power
failure occurs while the first transaction (the one setting
CHANGING_FSID_V2) flag is being persisted on disk. This can cause the
btrfs_fs_devices of this filesystem to be created by a device which:

 a) has the CHANGING_FSID_V2 flag set but its fsid value is intact

 b) or a device which doesn't have CHANGING_FSID_V2 flag set and its
    fsid value is intact

This situation is trivially handled by the current find_fsid code since
in both cases the devices are going to be treated like ordinary devices.
Since btrfs is always mounted using the superblock of the latest
device (the one with highest generation number), meaning it will have
the CHANGING_FSID_V2 flag set, ensure it's being cleared on mount. On
the first transaction commit following mount all disks will have it
cleared.
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 de37aa51
...@@ -2799,10 +2799,10 @@ int open_ctree(struct super_block *sb, ...@@ -2799,10 +2799,10 @@ int open_ctree(struct super_block *sb,
* the whole block of INFO_SIZE * the whole block of INFO_SIZE
*/ */
memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy)); memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy));
memcpy(fs_info->super_for_commit, fs_info->super_copy,
sizeof(*fs_info->super_for_commit));
brelse(bh); brelse(bh);
disk_super = fs_info->super_copy;
ASSERT(!memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid, ASSERT(!memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid,
BTRFS_FSID_SIZE)); BTRFS_FSID_SIZE));
...@@ -2812,6 +2812,16 @@ int open_ctree(struct super_block *sb, ...@@ -2812,6 +2812,16 @@ int open_ctree(struct super_block *sb,
BTRFS_FSID_SIZE)); BTRFS_FSID_SIZE));
} }
features = btrfs_super_flags(disk_super);
if (features & BTRFS_SUPER_FLAG_CHANGING_FSID_V2) {
features &= ~BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
btrfs_set_super_flags(disk_super, features);
btrfs_info(fs_info,
"found metadata UUID change in progress flag, clearing");
}
memcpy(fs_info->super_for_commit, fs_info->super_copy,
sizeof(*fs_info->super_for_commit));
ret = btrfs_validate_mount_super(fs_info); ret = btrfs_validate_mount_super(fs_info);
if (ret) { if (ret) {
...@@ -2820,7 +2830,6 @@ int open_ctree(struct super_block *sb, ...@@ -2820,7 +2830,6 @@ int open_ctree(struct super_block *sb,
goto fail_alloc; goto fail_alloc;
} }
disk_super = fs_info->super_copy;
if (!btrfs_super_root(disk_super)) if (!btrfs_super_root(disk_super))
goto fail_alloc; goto fail_alloc;
......
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