btrfs: re-introduce struct btrfs_io_geometry

Re-introduce struct btrfs_io_geometry, holding the necessary bits and
pieces needed in btrfs_map_block() to decide the I/O geometry of a specific
block mapping.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Johannes Thumshirn 2023-12-13 06:42:57 -08:00 committed by David Sterba
parent 02d05b6416
commit fd747f2d5f

View File

@ -41,6 +41,17 @@
BTRFS_BLOCK_GROUP_RAID10 | \
BTRFS_BLOCK_GROUP_RAID56_MASK)
struct btrfs_io_geometry {
u32 stripe_index;
u32 stripe_nr;
int mirror_num;
int num_stripes;
u64 stripe_offset;
u64 raid56_full_stripe_start;
int max_errors;
enum btrfs_map_op op;
};
const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
[BTRFS_RAID_RAID10] = {
.sub_stripes = 2,
@ -6392,28 +6403,27 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
struct btrfs_io_stripe *smap, int *mirror_num_ret)
{
struct btrfs_chunk_map *map;
struct btrfs_io_geometry io_geom = { 0 };
u64 map_offset;
u64 stripe_offset;
u32 stripe_nr;
u32 stripe_index;
int data_stripes;
int i;
int ret = 0;
int mirror_num = (mirror_num_ret ? *mirror_num_ret : 0);
int num_stripes;
int num_copies;
int max_errors = 0;
struct btrfs_io_context *bioc = NULL;
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
int dev_replace_is_ongoing = 0;
u16 num_alloc_stripes;
u64 raid56_full_stripe_start = (u64)-1;
u64 max_len;
ASSERT(bioc_ret);
io_geom.mirror_num = (mirror_num_ret ? *mirror_num_ret : 0);
io_geom.num_stripes = 1;
io_geom.stripe_index = 0;
io_geom.op = op;
num_copies = btrfs_num_copies(fs_info, logical, fs_info->sectorsize);
if (mirror_num > num_copies)
if (io_geom.mirror_num > num_copies)
return -EINVAL;
map = btrfs_get_chunk_map(fs_info, logical, *length);
@ -6423,8 +6433,10 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
data_stripes = nr_data_stripes(map);
map_offset = logical - map->start;
max_len = btrfs_max_io_len(map, op, map_offset, &stripe_nr,
&stripe_offset, &raid56_full_stripe_start);
io_geom.raid56_full_stripe_start = (u64)-1;
max_len = btrfs_max_io_len(map, io_geom.op, map_offset, &io_geom.stripe_nr,
&io_geom.stripe_offset,
&io_geom.raid56_full_stripe_start);
*length = min_t(u64, map->chunk_len - map_offset, max_len);
down_read(&dev_replace->rwsem);
@ -6436,53 +6448,51 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
if (!dev_replace_is_ongoing)
up_read(&dev_replace->rwsem);
num_stripes = 1;
stripe_index = 0;
if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
stripe_index = stripe_nr % map->num_stripes;
stripe_nr /= map->num_stripes;
io_geom.stripe_index = io_geom.stripe_nr % map->num_stripes;
io_geom.stripe_nr /= map->num_stripes;
if (op == BTRFS_MAP_READ)
mirror_num = 1;
io_geom.mirror_num = 1;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID1_MASK) {
if (op != BTRFS_MAP_READ) {
num_stripes = map->num_stripes;
} else if (mirror_num) {
stripe_index = mirror_num - 1;
io_geom.num_stripes = map->num_stripes;
} else if (io_geom.mirror_num) {
io_geom.stripe_index = io_geom.mirror_num - 1;
} else {
stripe_index = find_live_mirror(fs_info, map, 0,
io_geom.stripe_index = find_live_mirror(fs_info, map, 0,
dev_replace_is_ongoing);
mirror_num = stripe_index + 1;
io_geom.mirror_num = io_geom.stripe_index + 1;
}
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
if (op != BTRFS_MAP_READ) {
num_stripes = map->num_stripes;
} else if (mirror_num) {
stripe_index = mirror_num - 1;
io_geom.num_stripes = map->num_stripes;
} else if (io_geom.mirror_num) {
io_geom.stripe_index = io_geom.mirror_num - 1;
} else {
mirror_num = 1;
io_geom.mirror_num = 1;
}
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
u32 factor = map->num_stripes / map->sub_stripes;
stripe_index = (stripe_nr % factor) * map->sub_stripes;
stripe_nr /= factor;
io_geom.stripe_index = (io_geom.stripe_nr % factor) * map->sub_stripes;
io_geom.stripe_nr /= factor;
if (op != BTRFS_MAP_READ)
num_stripes = map->sub_stripes;
else if (mirror_num)
stripe_index += mirror_num - 1;
io_geom.num_stripes = map->sub_stripes;
else if (io_geom.mirror_num)
io_geom.stripe_index += io_geom.mirror_num - 1;
else {
int old_stripe_index = stripe_index;
stripe_index = find_live_mirror(fs_info, map,
stripe_index,
int old_stripe_index = io_geom.stripe_index;
io_geom.stripe_index = find_live_mirror(fs_info, map,
io_geom.stripe_index,
dev_replace_is_ongoing);
mirror_num = stripe_index - old_stripe_index + 1;
io_geom.mirror_num = io_geom.stripe_index - old_stripe_index + 1;
}
} else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
if (op != BTRFS_MAP_READ || mirror_num > 1) {
if (op != BTRFS_MAP_READ || io_geom.mirror_num > 1) {
/*
* Needs full stripe mapping.
*
@ -6494,29 +6504,33 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
* but that can be expensive. Here we just divide
* @stripe_nr with @data_stripes.
*/
stripe_nr /= data_stripes;
io_geom.stripe_nr /= data_stripes;
/* RAID[56] write or recovery. Return all stripes */
num_stripes = map->num_stripes;
max_errors = btrfs_chunk_max_errors(map);
io_geom.num_stripes = map->num_stripes;
io_geom.max_errors = btrfs_chunk_max_errors(map);
/* Return the length to the full stripe end */
*length = min(logical + *length,
raid56_full_stripe_start + map->start +
btrfs_stripe_nr_to_offset(data_stripes)) -
io_geom.raid56_full_stripe_start +
map->start +
btrfs_stripe_nr_to_offset(
data_stripes)) -
logical;
stripe_index = 0;
stripe_offset = 0;
io_geom.stripe_index = 0;
io_geom.stripe_offset = 0;
} else {
ASSERT(mirror_num <= 1);
ASSERT(io_geom.mirror_num <= 1);
/* Just grab the data stripe directly. */
stripe_index = stripe_nr % data_stripes;
stripe_nr /= data_stripes;
io_geom.stripe_index = io_geom.stripe_nr % data_stripes;
io_geom.stripe_nr /= data_stripes;
/* We distribute the parity blocks across stripes */
stripe_index = (stripe_nr + stripe_index) % map->num_stripes;
if (op == BTRFS_MAP_READ && mirror_num < 1)
mirror_num = 1;
io_geom.stripe_index =
(io_geom.stripe_nr + io_geom.stripe_index) %
map->num_stripes;
if (op == BTRFS_MAP_READ && io_geom.mirror_num < 1)
io_geom.mirror_num = 1;
}
} else {
/*
@ -6524,19 +6538,19 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
* device we have to walk to find the data, and stripe_index is
* the number of our device in the stripe array
*/
stripe_index = stripe_nr % map->num_stripes;
stripe_nr /= map->num_stripes;
mirror_num = stripe_index + 1;
io_geom.stripe_index = io_geom.stripe_nr % map->num_stripes;
io_geom.stripe_nr /= map->num_stripes;
io_geom.mirror_num = io_geom.stripe_index + 1;
}
if (stripe_index >= map->num_stripes) {
if (io_geom.stripe_index >= map->num_stripes) {
btrfs_crit(fs_info,
"stripe index math went horribly wrong, got stripe_index=%u, num_stripes=%u",
stripe_index, map->num_stripes);
io_geom.stripe_index, map->num_stripes);
ret = -EINVAL;
goto out;
}
num_alloc_stripes = num_stripes;
num_alloc_stripes = io_geom.num_stripes;
if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL &&
op != BTRFS_MAP_READ)
/*
@ -6554,11 +6568,12 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
* I/O context structure.
*/
if (is_single_device_io(fs_info, smap, map, num_alloc_stripes, op,
mirror_num)) {
io_geom.mirror_num)) {
ret = set_io_stripe(fs_info, op, logical, length, smap, map,
stripe_index, stripe_offset, stripe_nr);
io_geom.stripe_index, io_geom.stripe_offset,
io_geom.stripe_nr);
if (mirror_num_ret)
*mirror_num_ret = mirror_num;
*mirror_num_ret = io_geom.mirror_num;
*bioc_ret = NULL;
goto out;
}
@ -6578,7 +6593,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
* It's still mostly the same as other profiles, just with extra rotation.
*/
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK &&
(op != BTRFS_MAP_READ || mirror_num > 1)) {
(op != BTRFS_MAP_READ || io_geom.mirror_num > 1)) {
/*
* For RAID56 @stripe_nr is already the number of full stripes
* before us, which is also the rotation value (needs to modulo
@ -6588,12 +6603,13 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
* modulo, to reduce one modulo call.
*/
bioc->full_stripe_logical = map->start +
btrfs_stripe_nr_to_offset(stripe_nr * data_stripes);
for (int i = 0; i < num_stripes; i++) {
btrfs_stripe_nr_to_offset(io_geom.stripe_nr * data_stripes);
for (int i = 0; i < io_geom.num_stripes; i++) {
ret = set_io_stripe(fs_info, op, logical, length,
&bioc->stripes[i], map,
(i + stripe_nr) % num_stripes,
stripe_offset, stripe_nr);
(i + io_geom.stripe_nr) % io_geom.num_stripes,
io_geom.stripe_offset,
io_geom.stripe_nr);
if (ret < 0)
break;
}
@ -6602,13 +6618,15 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
* For all other non-RAID56 profiles, just copy the target
* stripe into the bioc.
*/
for (i = 0; i < num_stripes; i++) {
for (i = 0; i < io_geom.num_stripes; i++) {
ret = set_io_stripe(fs_info, op, logical, length,
&bioc->stripes[i], map, stripe_index,
stripe_offset, stripe_nr);
&bioc->stripes[i], map,
io_geom.stripe_index,
io_geom.stripe_offset,
io_geom.stripe_nr);
if (ret < 0)
break;
stripe_index++;
io_geom.stripe_index++;
}
}
@ -6619,18 +6637,18 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
}
if (op != BTRFS_MAP_READ)
max_errors = btrfs_chunk_max_errors(map);
io_geom.max_errors = btrfs_chunk_max_errors(map);
if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL &&
op != BTRFS_MAP_READ) {
handle_ops_on_dev_replace(op, bioc, dev_replace, logical,
&num_stripes, &max_errors);
&io_geom.num_stripes, &io_geom.max_errors);
}
*bioc_ret = bioc;
bioc->num_stripes = num_stripes;
bioc->max_errors = max_errors;
bioc->mirror_num = mirror_num;
bioc->num_stripes = io_geom.num_stripes;
bioc->max_errors = io_geom.max_errors;
bioc->mirror_num = io_geom.mirror_num;
out:
if (dev_replace_is_ongoing) {