btrfs: Fix a regression which we can't convert to SINGLE profile
authorQu Wenruo <wqu@suse.com>
Wed, 25 Sep 2019 02:13:27 +0000 (10:13 +0800)
committerDavid Sterba <dsterba@suse.com>
Wed, 25 Sep 2019 14:00:37 +0000 (16:00 +0200)
[BUG]
With v5.3 kernel, we can't convert to SINGLE profile:

  # btrfs balance start -f -dconvert=single $mnt
  ERROR: error during balancing '/mnt/btrfs': Invalid argument
  # dmesg -t | tail
  validate_convert_profile: data profile=0x1000000000000 allowed=0x20 is_valid=1 final=0x1000000000000 ret=1
  BTRFS error (device dm-3): balance: invalid convert data profile single

[CAUSE]
With the extra debug output added, it shows that the @allowed bit is
lacking the special in-memory only SINGLE profile bit.

Thus we fail at that (profile & ~allowed) check.

This regression is caused by commit 081db89b13cb ("btrfs: use raid_attr
to get allowed profiles for balance conversion") and the fact that we
don't use any bit to indicate SINGLE profile on-disk, but uses special
in-memory only bit to help distinguish different profiles.

[FIX]
Add that BTRFS_AVAIL_ALLOC_BIT_SINGLE to @allowed, so the code should be
the same as it was and fix the regression.

Reported-by: Chris Murphy <lists@colorremedies.com>
Fixes: 081db89b13cb ("btrfs: use raid_attr to get allowed profiles for balance conversion")
CC: stable@vger.kernel.org # 5.3+
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/volumes.c

index a324480bc88b9827f13f72d94beb76a9d7b3fb61..cdd7af424033c22bbc3932d49674c2d907c4def0 100644 (file)
@@ -4063,7 +4063,13 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
        }
 
        num_devices = btrfs_num_devices(fs_info);
-       allowed = 0;
+
+       /*
+        * SINGLE profile on-disk has no profile bit, but in-memory we have a
+        * special bit for it, to make it easier to distinguish.  Thus we need
+        * to set it manually, or balance would refuse the profile.
+        */
+       allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
        for (i = 0; i < ARRAY_SIZE(btrfs_raid_array); i++)
                if (num_devices >= btrfs_raid_array[i].devs_min)
                        allowed |= btrfs_raid_array[i].bg_flag;