Commit cc6cf827 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.13-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "A few more fixes that people hit during testing.

  Zoned mode fix:

   - fix 32bit value wrapping when calculating superblock offsets

  Error handling fixes:

   - properly check filesystema and device uuids

   - properly return errors when marking extents as written

   - do not write supers if we have an fs error"

* tag 'for-5.13-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: promote debugging asserts to full-fledged checks in validate_super
  btrfs: return value from btrfs_mark_extent_written() in case of error
  btrfs: zoned: fix zone number to sector/physical calculation
  btrfs: do not write supers if we have an fs error
parents 2f673816 aefd7f70
...@@ -2648,6 +2648,24 @@ static int validate_super(struct btrfs_fs_info *fs_info, ...@@ -2648,6 +2648,24 @@ static int validate_super(struct btrfs_fs_info *fs_info,
ret = -EINVAL; ret = -EINVAL;
} }
if (memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid,
BTRFS_FSID_SIZE)) {
btrfs_err(fs_info,
"superblock fsid doesn't match fsid of fs_devices: %pU != %pU",
fs_info->super_copy->fsid, fs_info->fs_devices->fsid);
ret = -EINVAL;
}
if (btrfs_fs_incompat(fs_info, METADATA_UUID) &&
memcmp(fs_info->fs_devices->metadata_uuid,
fs_info->super_copy->metadata_uuid, BTRFS_FSID_SIZE)) {
btrfs_err(fs_info,
"superblock metadata_uuid doesn't match metadata uuid of fs_devices: %pU != %pU",
fs_info->super_copy->metadata_uuid,
fs_info->fs_devices->metadata_uuid);
ret = -EINVAL;
}
if (memcmp(fs_info->fs_devices->metadata_uuid, sb->dev_item.fsid, if (memcmp(fs_info->fs_devices->metadata_uuid, sb->dev_item.fsid,
BTRFS_FSID_SIZE) != 0) { BTRFS_FSID_SIZE) != 0) {
btrfs_err(fs_info, btrfs_err(fs_info,
...@@ -3279,14 +3297,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device ...@@ -3279,14 +3297,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
disk_super = fs_info->super_copy; disk_super = fs_info->super_copy;
ASSERT(!memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid,
BTRFS_FSID_SIZE));
if (btrfs_fs_incompat(fs_info, METADATA_UUID)) {
ASSERT(!memcmp(fs_info->fs_devices->metadata_uuid,
fs_info->super_copy->metadata_uuid,
BTRFS_FSID_SIZE));
}
features = btrfs_super_flags(disk_super); features = btrfs_super_flags(disk_super);
if (features & BTRFS_SUPER_FLAG_CHANGING_FSID_V2) { if (features & BTRFS_SUPER_FLAG_CHANGING_FSID_V2) {
......
...@@ -1094,7 +1094,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -1094,7 +1094,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
int del_nr = 0; int del_nr = 0;
int del_slot = 0; int del_slot = 0;
int recow; int recow;
int ret; int ret = 0;
u64 ino = btrfs_ino(inode); u64 ino = btrfs_ino(inode);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
...@@ -1315,7 +1315,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -1315,7 +1315,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
} }
out: out:
btrfs_free_path(path); btrfs_free_path(path);
return 0; return ret;
} }
/* /*
......
...@@ -3302,6 +3302,22 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -3302,6 +3302,22 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
* begins and releases it only after writing its superblock. * begins and releases it only after writing its superblock.
*/ */
mutex_lock(&fs_info->tree_log_mutex); mutex_lock(&fs_info->tree_log_mutex);
/*
* The previous transaction writeout phase could have failed, and thus
* marked the fs in an error state. We must not commit here, as we
* could have updated our generation in the super_for_commit and
* writing the super here would result in transid mismatches. If there
* is an error here just bail.
*/
if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
ret = -EIO;
btrfs_set_log_full_commit(trans);
btrfs_abort_transaction(trans, ret);
mutex_unlock(&fs_info->tree_log_mutex);
goto out_wake_log_root;
}
btrfs_set_super_log_root(fs_info->super_for_commit, log_root_start); btrfs_set_super_log_root(fs_info->super_for_commit, log_root_start);
btrfs_set_super_log_root_level(fs_info->super_for_commit, log_root_level); btrfs_set_super_log_root_level(fs_info->super_for_commit, log_root_level);
ret = write_all_supers(fs_info, 1); ret = write_all_supers(fs_info, 1);
......
...@@ -150,6 +150,18 @@ static inline u32 sb_zone_number(int shift, int mirror) ...@@ -150,6 +150,18 @@ static inline u32 sb_zone_number(int shift, int mirror)
return (u32)zone; return (u32)zone;
} }
static inline sector_t zone_start_sector(u32 zone_number,
struct block_device *bdev)
{
return (sector_t)zone_number << ilog2(bdev_zone_sectors(bdev));
}
static inline u64 zone_start_physical(u32 zone_number,
struct btrfs_zoned_device_info *zone_info)
{
return (u64)zone_number << zone_info->zone_size_shift;
}
/* /*
* Emulate blkdev_report_zones() for a non-zoned device. It slices up the block * Emulate blkdev_report_zones() for a non-zoned device. It slices up the block
* device into static sized chunks and fake a conventional zone on each of * device into static sized chunks and fake a conventional zone on each of
...@@ -405,8 +417,8 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device) ...@@ -405,8 +417,8 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
if (sb_zone + 1 >= zone_info->nr_zones) if (sb_zone + 1 >= zone_info->nr_zones)
continue; continue;
sector = sb_zone << (zone_info->zone_size_shift - SECTOR_SHIFT); ret = btrfs_get_dev_zones(device,
ret = btrfs_get_dev_zones(device, sector << SECTOR_SHIFT, zone_start_physical(sb_zone, zone_info),
&zone_info->sb_zones[sb_pos], &zone_info->sb_zones[sb_pos],
&nr_zones); &nr_zones);
if (ret) if (ret)
...@@ -721,7 +733,7 @@ int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw, ...@@ -721,7 +733,7 @@ int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw,
if (sb_zone + 1 >= nr_zones) if (sb_zone + 1 >= nr_zones)
return -ENOENT; return -ENOENT;
ret = blkdev_report_zones(bdev, sb_zone << zone_sectors_shift, ret = blkdev_report_zones(bdev, zone_start_sector(sb_zone, bdev),
BTRFS_NR_SB_LOG_ZONES, copy_zone_info_cb, BTRFS_NR_SB_LOG_ZONES, copy_zone_info_cb,
zones); zones);
if (ret < 0) if (ret < 0)
...@@ -826,7 +838,7 @@ int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror) ...@@ -826,7 +838,7 @@ int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror)
return -ENOENT; return -ENOENT;
return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET, return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
sb_zone << zone_sectors_shift, zone_start_sector(sb_zone, bdev),
zone_sectors * BTRFS_NR_SB_LOG_ZONES, GFP_NOFS); zone_sectors * BTRFS_NR_SB_LOG_ZONES, GFP_NOFS);
} }
...@@ -878,7 +890,8 @@ u64 btrfs_find_allocatable_zones(struct btrfs_device *device, u64 hole_start, ...@@ -878,7 +890,8 @@ u64 btrfs_find_allocatable_zones(struct btrfs_device *device, u64 hole_start,
if (!(end <= sb_zone || if (!(end <= sb_zone ||
sb_zone + BTRFS_NR_SB_LOG_ZONES <= begin)) { sb_zone + BTRFS_NR_SB_LOG_ZONES <= begin)) {
have_sb = true; have_sb = true;
pos = ((u64)sb_zone + BTRFS_NR_SB_LOG_ZONES) << shift; pos = zone_start_physical(
sb_zone + BTRFS_NR_SB_LOG_ZONES, zinfo);
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment