summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorNikolay Borisov <nborisov@suse.com>2018-10-30 10:43:25 -0400
committerDavid Sterba <dsterba@suse.com>2018-12-17 08:51:38 -0500
commitfbc6feaec98ac0c6a615bbe9e17c5689a1a84650 (patch)
tree0967900f3d1d6b94d5550743db9de0b83a2a5c69 /fs/btrfs/disk-io.c
parentde37aa513105f864d3c21105bf5542d498f21ca2 (diff)
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: Nikolay Borisov <nborisov@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index ed6d4c83c1e7..feb67dfd663d 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2799,10 +2799,10 @@ int open_ctree(struct super_block *sb,
2799 * the whole block of INFO_SIZE 2799 * the whole block of INFO_SIZE
2800 */ 2800 */
2801 memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy)); 2801 memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy));
2802 memcpy(fs_info->super_for_commit, fs_info->super_copy,
2803 sizeof(*fs_info->super_for_commit));
2804 brelse(bh); 2802 brelse(bh);
2805 2803
2804 disk_super = fs_info->super_copy;
2805
2806 ASSERT(!memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid, 2806 ASSERT(!memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid,
2807 BTRFS_FSID_SIZE)); 2807 BTRFS_FSID_SIZE));
2808 2808
@@ -2812,6 +2812,16 @@ int open_ctree(struct super_block *sb,
2812 BTRFS_FSID_SIZE)); 2812 BTRFS_FSID_SIZE));
2813 } 2813 }
2814 2814
2815 features = btrfs_super_flags(disk_super);
2816 if (features & BTRFS_SUPER_FLAG_CHANGING_FSID_V2) {
2817 features &= ~BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
2818 btrfs_set_super_flags(disk_super, features);
2819 btrfs_info(fs_info,
2820 "found metadata UUID change in progress flag, clearing");
2821 }
2822
2823 memcpy(fs_info->super_for_commit, fs_info->super_copy,
2824 sizeof(*fs_info->super_for_commit));
2815 2825
2816 ret = btrfs_validate_mount_super(fs_info); 2826 ret = btrfs_validate_mount_super(fs_info);
2817 if (ret) { 2827 if (ret) {
@@ -2820,7 +2830,6 @@ int open_ctree(struct super_block *sb,
2820 goto fail_alloc; 2830 goto fail_alloc;
2821 } 2831 }
2822 2832
2823 disk_super = fs_info->super_copy;
2824 if (!btrfs_super_root(disk_super)) 2833 if (!btrfs_super_root(disk_super))
2825 goto fail_alloc; 2834 goto fail_alloc;
2826 2835