]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
btrfs: drop never met disk total bytes check in verify_one_dev_extent
authorAnand Jain <anand.jain@oracle.com>
Tue, 3 Nov 2020 05:49:42 +0000 (13:49 +0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 8 Dec 2020 14:54:08 +0000 (15:54 +0100)
Drop the condition in verify_one_dev_extent,
btrfs_device::disk_total_bytes is set even for a seed device. The
comment is wrong, the size is properly set when cloning the device.

Commit 1b3922a8bc74 ("btrfs: Use real device structure to verify
dev extent") introduced it but it's unclear why the total_disk_bytes
was 0.

Theoretically, all devices (including missing and seed) marked with the
BTRFS_DEV_STATE_IN_FS_METADATA flag gets the total_disk_bytes updated at
fill_device_from_item():

  open_ctree()
    btrfs_read_chunk_tree()
      read_one_dev()
        open_seed_device()
        fill_device_from_item()

Even if verify_one_dev_extent() reports total_disk_bytes == 0, then its
a bug to be fixed somewhere else and not in verify_one_dev_extent() as
it's just a messenger. It is never expected that a total_disk_bytes
shall be zero.

The function fill_device_from_item() does the job of reading it from the
item and updating btrfs_device::disk_total_bytes. So both the missing
device and the seed devices do have their disk_total_bytes updated.
btrfs_find_device can also return a device from fs_info->seed_list
because it searches it as well.

Furthermore, while removing the device if there is a power loss, we
could have a device with its total_bytes = 0, that's still valid.

Instead, introduce a check against maximum block device size in
read_one_dev().

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/volumes.c

index d7cc74f59293e794dc2518a38493af927789baf0..cd72bdc7455ef166132ab05e78a8494b37db12d3 100644 (file)
@@ -6869,6 +6869,16 @@ static int read_one_dev(struct extent_buffer *leaf,
        }
 
        fill_device_from_item(leaf, dev_item, device);
+       if (device->bdev) {
+               u64 max_total_bytes = i_size_read(device->bdev->bd_inode);
+
+               if (device->total_bytes > max_total_bytes) {
+                       btrfs_err(fs_info,
+                       "device total_bytes should be at most %llu but found %llu",
+                                 max_total_bytes, device->total_bytes);
+                       return -EINVAL;
+               }
+       }
        set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
        if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
           !test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
@@ -7598,21 +7608,6 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
                goto out;
        }
 
-       /* It's possible this device is a dummy for seed device */
-       if (dev->disk_total_bytes == 0) {
-               struct btrfs_fs_devices *devs;
-
-               devs = list_first_entry(&fs_info->fs_devices->seed_list,
-                                       struct btrfs_fs_devices, seed_list);
-               dev = btrfs_find_device(devs, devid, NULL, NULL, false);
-               if (!dev) {
-                       btrfs_err(fs_info, "failed to find seed devid %llu",
-                                 devid);
-                       ret = -EUCLEAN;
-                       goto out;
-               }
-       }
-
        if (physical_offset + physical_len > dev->disk_total_bytes) {
                btrfs_err(fs_info,
 "dev extent devid %llu physical offset %llu len %llu is beyond device boundary %llu",