mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 17:12:50 -04:00
btrfs: allow remapped chunks to have zero stripes
When a chunk has been fully remapped, we are going to set its num_stripes to 0, as it will no longer represent a physical location on disk. Change tree-checker to allow for this, and fix read_one_chunk() to avoid a divide by zero. Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Mark Harmstone <mark@harmstone.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
committed by
David Sterba
parent
0b4d29fa98
commit
c3d6dda60c
@@ -816,6 +816,32 @@ static void chunk_err(const struct btrfs_fs_info *fs_info,
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static bool valid_stripe_count(u64 profile, u16 num_stripes, u16 sub_stripes)
|
||||
{
|
||||
switch (profile) {
|
||||
case BTRFS_BLOCK_GROUP_RAID0:
|
||||
return true;
|
||||
case BTRFS_BLOCK_GROUP_RAID10:
|
||||
return sub_stripes == btrfs_raid_array[BTRFS_RAID_RAID10].sub_stripes;
|
||||
case BTRFS_BLOCK_GROUP_RAID1:
|
||||
return num_stripes == btrfs_raid_array[BTRFS_RAID_RAID1].devs_min;
|
||||
case BTRFS_BLOCK_GROUP_RAID1C3:
|
||||
return num_stripes == btrfs_raid_array[BTRFS_RAID_RAID1C3].devs_min;
|
||||
case BTRFS_BLOCK_GROUP_RAID1C4:
|
||||
return num_stripes == btrfs_raid_array[BTRFS_RAID_RAID1C4].devs_min;
|
||||
case BTRFS_BLOCK_GROUP_RAID5:
|
||||
return num_stripes >= btrfs_raid_array[BTRFS_RAID_RAID5].devs_min;
|
||||
case BTRFS_BLOCK_GROUP_RAID6:
|
||||
return num_stripes >= btrfs_raid_array[BTRFS_RAID_RAID6].devs_min;
|
||||
case BTRFS_BLOCK_GROUP_DUP:
|
||||
return num_stripes == btrfs_raid_array[BTRFS_RAID_DUP].dev_stripes;
|
||||
case 0: /* SINGLE */
|
||||
return num_stripes == btrfs_raid_array[BTRFS_RAID_SINGLE].dev_stripes;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The common chunk check which could also work on super block sys chunk array.
|
||||
*
|
||||
@@ -839,6 +865,7 @@ int btrfs_check_chunk_valid(const struct btrfs_fs_info *fs_info,
|
||||
u64 features;
|
||||
u32 chunk_sector_size;
|
||||
bool mixed = false;
|
||||
bool remapped;
|
||||
int raid_index;
|
||||
int nparity;
|
||||
int ncopies;
|
||||
@@ -861,13 +888,14 @@ int btrfs_check_chunk_valid(const struct btrfs_fs_info *fs_info,
|
||||
raid_index = btrfs_bg_flags_to_raid_index(type);
|
||||
ncopies = btrfs_raid_array[raid_index].ncopies;
|
||||
nparity = btrfs_raid_array[raid_index].nparity;
|
||||
remapped = (type & BTRFS_BLOCK_GROUP_REMAPPED);
|
||||
|
||||
if (unlikely(!num_stripes)) {
|
||||
if (unlikely(!remapped && !num_stripes)) {
|
||||
chunk_err(fs_info, leaf, chunk, logical,
|
||||
"invalid chunk num_stripes, have %u", num_stripes);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (unlikely(num_stripes < ncopies)) {
|
||||
if (unlikely(num_stripes != 0 && num_stripes < ncopies)) {
|
||||
chunk_err(fs_info, leaf, chunk, logical,
|
||||
"invalid chunk num_stripes < ncopies, have %u < %d",
|
||||
num_stripes, ncopies);
|
||||
@@ -965,22 +993,9 @@ int btrfs_check_chunk_valid(const struct btrfs_fs_info *fs_info,
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely((type & BTRFS_BLOCK_GROUP_RAID10 &&
|
||||
sub_stripes != btrfs_raid_array[BTRFS_RAID_RAID10].sub_stripes) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID1 &&
|
||||
num_stripes != btrfs_raid_array[BTRFS_RAID_RAID1].devs_min) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID1C3 &&
|
||||
num_stripes != btrfs_raid_array[BTRFS_RAID_RAID1C3].devs_min) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID1C4 &&
|
||||
num_stripes != btrfs_raid_array[BTRFS_RAID_RAID1C4].devs_min) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID5 &&
|
||||
num_stripes < btrfs_raid_array[BTRFS_RAID_RAID5].devs_min) ||
|
||||
(type & BTRFS_BLOCK_GROUP_RAID6 &&
|
||||
num_stripes < btrfs_raid_array[BTRFS_RAID_RAID6].devs_min) ||
|
||||
(type & BTRFS_BLOCK_GROUP_DUP &&
|
||||
num_stripes != btrfs_raid_array[BTRFS_RAID_DUP].dev_stripes) ||
|
||||
((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 &&
|
||||
num_stripes != btrfs_raid_array[BTRFS_RAID_SINGLE].dev_stripes))) {
|
||||
if (!remapped &&
|
||||
!valid_stripe_count(type & BTRFS_BLOCK_GROUP_PROFILE_MASK,
|
||||
num_stripes, sub_stripes)) {
|
||||
chunk_err(fs_info, leaf, chunk, logical,
|
||||
"invalid num_stripes:sub_stripes %u:%u for profile %llu",
|
||||
num_stripes, sub_stripes,
|
||||
@@ -1004,11 +1019,11 @@ static int check_leaf_chunk_item(struct extent_buffer *leaf,
|
||||
struct btrfs_fs_info *fs_info = leaf->fs_info;
|
||||
int num_stripes;
|
||||
|
||||
if (unlikely(btrfs_item_size(leaf, slot) < sizeof(struct btrfs_chunk))) {
|
||||
if (unlikely(btrfs_item_size(leaf, slot) < offsetof(struct btrfs_chunk, stripe))) {
|
||||
chunk_err(fs_info, leaf, chunk, key->offset,
|
||||
"invalid chunk item size: have %u expect [%zu, %u)",
|
||||
btrfs_item_size(leaf, slot),
|
||||
sizeof(struct btrfs_chunk),
|
||||
offsetof(struct btrfs_chunk, stripe),
|
||||
BTRFS_LEAF_DATA_SIZE(fs_info));
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
@@ -7047,7 +7047,12 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
|
||||
*/
|
||||
map->sub_stripes = btrfs_raid_array[index].sub_stripes;
|
||||
map->verified_stripes = 0;
|
||||
map->stripe_size = btrfs_calc_stripe_length(map);
|
||||
|
||||
if (num_stripes > 0)
|
||||
map->stripe_size = btrfs_calc_stripe_length(map);
|
||||
else
|
||||
map->stripe_size = 0;
|
||||
|
||||
for (i = 0; i < num_stripes; i++) {
|
||||
map->stripes[i].physical =
|
||||
btrfs_stripe_offset_nr(leaf, chunk, i);
|
||||
|
||||
Reference in New Issue
Block a user