btrfs-progs: check: fix wrong total bytes check for seed device

[BUG]
The following script can lead to false positive from btrfs check:

  mkfs.btrfs -f $dev1
  mount $dev1 $mnt
  btrfstune -S1 $dev1
  mount $dev1 $mnt
  btrfs dev add -f $dev2 $mnt
  umount $mnt

  # Now dev1 is seed, and dev2 is the rw fs.
  btrfs check $dev2
  ...
  [2/7] checking extents
  WARNING: minor unaligned/mismatch device size detected
  WARNING: recommended to use 'btrfs rescue fix-device-size' to fix it
  ...

This false positive only happens on $dev2, $dev1 is completely fine.

[CAUSE]
The warning is from is_super_size_valid(), in that function we verify
the super block total bytes (@super_bytes) is correct against the total
device bytes (@total_bytes).

However the when calculating @total_bytes, we only use devices in
current fs_devices, which only contains RW devices.

Thus all bytes from seed device are not taken into consideration, and
trigger the false positive.

[FIX]
Fix it by also iterating seed devices.

Since we're here, also output @total_bytes and @super_bytes when
outputting the warning message, to allow end users have a better idea on
what's going wrong.

Reviewed-by: Su Yue <l@damenly.su>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2022-04-17 15:30:35 +08:00 committed by David Sterba
parent ef194732d5
commit 0dc8b8b6a4

View File

@ -8599,13 +8599,17 @@ static int check_device_used(struct device_record *dev_rec,
*/
static bool is_super_size_valid(void)
{
struct btrfs_device *dev;
struct list_head *dev_list = &gfs_info->fs_devices->devices;
struct btrfs_fs_devices *fs_devices = gfs_info->fs_devices;
const u64 super_bytes = btrfs_super_total_bytes(gfs_info->super_copy);
u64 total_bytes = 0;
u64 super_bytes = btrfs_super_total_bytes(gfs_info->super_copy);
list_for_each_entry(dev, dev_list, dev_list)
total_bytes += dev->total_bytes;
while (fs_devices) {
struct btrfs_device *dev;
list_for_each_entry(dev, &fs_devices->devices, dev_list)
total_bytes += dev->total_bytes;
fs_devices = fs_devices->seed;
}
/* Important check, which can cause unmountable fs */
if (super_bytes < total_bytes) {
@ -8628,7 +8632,9 @@ static bool is_super_size_valid(void)
if (!IS_ALIGNED(super_bytes, gfs_info->sectorsize) ||
!IS_ALIGNED(total_bytes, gfs_info->sectorsize) ||
super_bytes != total_bytes) {
warning("minor unaligned/mismatch device size detected");
warning("minor unaligned/mismatch device size detected:"
"\tsuper block total bytes=%llu found total bytes=%llu",
super_bytes, total_bytes);
warning(
"recommended to use 'btrfs rescue fix-device-size' to fix it");
}