diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index f7d16097a0cd..830460a40e86 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -2630,7 +2630,7 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info) /* Fill dummy cache as FULL */ bg->length = map->chunk_len; - bg->flags = map->type; + bg->flags = map->on_disk_type; bg->cached = BTRFS_CACHE_FINISHED; bg->used = map->chunk_len; bg->space_info = btrfs_find_space_info(fs_info, bg->flags); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b68ede97e8c8..a8e27db8e4bc 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6014,6 +6014,19 @@ struct btrfs_chunk_map *btrfs_alloc_chunk_map(int num_stripes, gfp_t gfp) return map; } +static void set_real_chunk_type(struct btrfs_chunk_map *map) +{ + map->type = map->on_disk_type; + if (likely((map->on_disk_type & BTRFS_BLOCK_GROUP_RAID56_MASK) == 0 || + nr_data_stripes(map) > 1)) + return; + if (map->on_disk_type & BTRFS_BLOCK_GROUP_RAID5) + map->type |= BTRFS_BLOCK_GROUP_RAID1; + else + map->type |= BTRFS_BLOCK_GROUP_RAID1C3; + map->type &= ~BTRFS_BLOCK_GROUP_RAID56_MASK; +} + static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans, struct alloc_chunk_ctl *ctl, struct btrfs_device_info *devices_info) @@ -6032,9 +6045,10 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans, map->start = start; map->chunk_len = ctl->chunk_size; map->stripe_size = ctl->stripe_size; - map->type = type; + map->on_disk_type = type; map->sub_stripes = ctl->sub_stripes; map->num_stripes = ctl->num_stripes; + set_real_chunk_type(map); for (int i = 0; i < ctl->ndevs; i++) { for (int j = 0; j < ctl->dev_stripes; j++) { @@ -6213,7 +6227,7 @@ int btrfs_chunk_alloc_add_chunk_item(struct btrfs_trans_handle *trans, btrfs_set_stack_chunk_length(chunk, bg->length); btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_stack_chunk_stripe_len(chunk, BTRFS_STRIPE_LEN); - btrfs_set_stack_chunk_type(chunk, map->type); + btrfs_set_stack_chunk_type(chunk, map->on_disk_type); btrfs_set_stack_chunk_num_stripes(chunk, map->num_stripes); btrfs_set_stack_chunk_io_align(chunk, BTRFS_STRIPE_LEN); btrfs_set_stack_chunk_io_width(chunk, BTRFS_STRIPE_LEN); @@ -7595,7 +7609,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, map->start = logical; map->chunk_len = length; map->num_stripes = num_stripes; - map->type = type; + map->on_disk_type = type; /* * We can't use the sub_stripes value, as for profiles other than * RAID10, they may have 0 as sub_stripes for filesystems created by @@ -7606,6 +7620,7 @@ 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; + set_real_chunk_type(map); if (num_stripes > 0) map->stripe_size = btrfs_calc_stripe_length(map); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 30597e1fd240..eaf23c0dcbf6 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -632,7 +632,15 @@ struct btrfs_chunk_map { u64 start; u64 chunk_len; u64 stripe_size; + /* + * The real type that is utilized during logical address mapping. + * + * For most profiles it matches @on_disk_type, but for single-data-RAID56, + * the real type will be set to RAID1/RAID1C3, to avoid unsupported + * operations from raid56 lib. + */ u64 type; + u64 on_disk_type; int num_stripes; int sub_stripes; struct btrfs_io_stripe stripes[];