summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.com>2019-06-11 14:31:01 +0200
committerDavid Sterba <dsterba@suse.com>2019-07-02 12:30:48 +0200
commit6d58a55a894e8632a6153e5b98792e7bdda13be8 (patch)
tree26def269ba0b6c73bd1233d09394d7e85db641d7
parentbtrfs: switch extent_buffer write_locks from atomic to int (diff)
downloadlinux-6d58a55a894e8632a6153e5b98792e7bdda13be8.tar.xz
linux-6d58a55a894e8632a6153e5b98792e7bdda13be8.zip
btrfs: raid56: clear incompat block group flags after removing the last one
The incompat bit for RAID56 is set either at mount time or automatically when the profile is used by balance. The part where the bit is removed is missing and can be unexpected or undesired when an older kernel is needed. This patch will drop the incompat bit after this command, assuming that RAID5 profile is not used by system or metadata: $ btrfs balance start -dconvert=raid5 /mnt $ btrfs balance start -dconvert=raid1 /mnt This will print "clearing 128 feature flag" to the system log. The patch is safe for backporting to older kernels. Reported-by: Hugo Mills <hugo@carfax.org.uk> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/extent-tree.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 862df2066e7a..f24ef9020323 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -10606,6 +10606,35 @@ static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
write_sequnlock(&fs_info->profiles_lock);
}
+/*
+ * Clear incompat bits for the following feature(s):
+ *
+ * - RAID56 - in case there's neither RAID5 nor RAID6 profile block group
+ * in the whole filesystem
+ */
+static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
+{
+ if (flags & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+ struct list_head *head = &fs_info->space_info;
+ struct btrfs_space_info *sinfo;
+
+ list_for_each_entry_rcu(sinfo, head, list) {
+ bool found = false;
+
+ down_read(&sinfo->groups_sem);
+ if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID5]))
+ found = true;
+ if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID6]))
+ found = true;
+ up_read(&sinfo->groups_sem);
+
+ if (found)
+ return;
+ }
+ btrfs_clear_fs_incompat(fs_info, RAID56);
+ }
+}
+
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
u64 group_start, struct extent_map *em)
{
@@ -10752,6 +10781,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
clear_avail_alloc_bits(fs_info, block_group->flags);
}
up_write(&block_group->space_info->groups_sem);
+ clear_incompat_bg_bits(fs_info, block_group->flags);
if (kobj) {
kobject_del(kobj);
kobject_put(kobj);