OSDN Git Service

btrfs: zoned: bail out if we can't read a reliable write pointer
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>
Fri, 30 Apr 2021 13:34:18 +0000 (15:34 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 21 Jun 2021 13:19:04 +0000 (15:19 +0200)
If we can't read a reliable write pointer from a sequential zone fail
creating the block group with an I/O error.

Also if the read write pointer is beyond the end of the respective zone,
fail the creation of the block group on this zone with an I/O error.

While this could also happen in real world scenarios with misbehaving
drives, this issue addresses a problem uncovered by fstests' test case
generic/475.

CC: stable@vger.kernel.org # 5.12+
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/zoned.c

index 4f3bbba..c7243d3 100644 (file)
@@ -1204,6 +1204,13 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
 
        switch (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
        case 0: /* single */
+               if (alloc_offsets[0] == WP_MISSING_DEV) {
+                       btrfs_err(fs_info,
+                       "zoned: cannot recover write pointer for zone %llu",
+                               physical);
+                       ret = -EIO;
+                       goto out;
+               }
                cache->alloc_offset = alloc_offsets[0];
                break;
        case BTRFS_BLOCK_GROUP_DUP:
@@ -1221,6 +1228,13 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
        }
 
 out:
+       if (cache->alloc_offset > fs_info->zone_size) {
+               btrfs_err(fs_info,
+                       "zoned: invalid write pointer %llu in block group %llu",
+                       cache->alloc_offset, cache->start);
+               ret = -EIO;
+       }
+
        /* An extent is allocated after the write pointer */
        if (!ret && num_conventional && last_alloc > cache->alloc_offset) {
                btrfs_err(fs_info,