Skip to content

Commit fbc6fea

Browse files
lorddoskiaskdave
authored andcommitted
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>
1 parent de37aa5 commit fbc6fea

File tree

1 file changed

+12
-3
lines changed

1 file changed

+12
-3
lines changed

fs/btrfs/disk-io.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,10 +2799,10 @@ int open_ctree(struct super_block *sb,
27992799
* the whole block of INFO_SIZE
28002800
*/
28012801
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));
28042802
brelse(bh);
28052803

2804+
disk_super = fs_info->super_copy;
2805+
28062806
ASSERT(!memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid,
28072807
BTRFS_FSID_SIZE));
28082808

@@ -2812,6 +2812,16 @@ int open_ctree(struct super_block *sb,
28122812
BTRFS_FSID_SIZE));
28132813
}
28142814

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));
28152825

28162826
ret = btrfs_validate_mount_super(fs_info);
28172827
if (ret) {
@@ -2820,7 +2830,6 @@ int open_ctree(struct super_block *sb,
28202830
goto fail_alloc;
28212831
}
28222832

2823-
disk_super = fs_info->super_copy;
28242833
if (!btrfs_super_root(disk_super))
28252834
goto fail_alloc;
28262835

0 commit comments

Comments
 (0)