With the new btrfs_bio_split() helper, we are able to split bio according to chunk stripe boundaries at btrfs_map_bio() time. Although currently due bio split at buffered/compressed/direct IO time, this ability is not yet utilized. Signed-off-by: Qu Wenruo <wqu@xxxxxxxx> --- fs/btrfs/volumes.c | 48 ++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 365e43bbfd14..35ba1ea95295 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6893,29 +6893,43 @@ static int submit_one_mapped_range(struct btrfs_fs_info *fs_info, struct bio *bi blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num) { - u64 logical = bio->bi_iter.bi_sector << 9; - u64 length = 0; - u64 map_length; + const u64 orig_logical = bio->bi_iter.bi_sector << SECTOR_SHIFT; + const unsigned int orig_length = bio->bi_iter.bi_size; + const enum btrfs_map_op op = btrfs_op(bio); + u64 cur_logical = orig_logical; int ret; - struct btrfs_io_context *bioc = NULL; - length = bio->bi_iter.bi_size; - map_length = length; + while (cur_logical < orig_logical + orig_length) { + u64 map_length = orig_logical + orig_length - cur_logical; + struct btrfs_io_context *bioc = NULL; + struct bio *cur_bio; - btrfs_bio_counter_inc_blocked(fs_info); - ret = __btrfs_map_block(fs_info, btrfs_op(bio), logical, - &map_length, &bioc, mirror_num, 1); - if (ret) { - btrfs_bio_counter_dec(fs_info); - return errno_to_blk_status(ret); - } + ret = __btrfs_map_block(fs_info, op, cur_logical, &map_length, + &bioc, mirror_num, 1); + if (ret) + return errno_to_blk_status(ret); - ret = submit_one_mapped_range(fs_info, bio, bioc, map_length, mirror_num); - if (ret < 0) { + if (cur_logical + map_length < orig_logical + orig_length) { + /* + * For now zoned write should never cross stripe + * boundary + */ + ASSERT(bio_op(bio) != REQ_OP_ZONE_APPEND); + + /* Split the bio */ + cur_bio = btrfs_bio_split(fs_info, bio, map_length); + } else { + /* Use the existing bio directly */ + cur_bio = bio; + } + btrfs_bio_counter_inc_blocked(fs_info); + ret = submit_one_mapped_range(fs_info, cur_bio, bioc, + map_length, mirror_num); btrfs_bio_counter_dec(fs_info); - return errno_to_blk_status(ret); + if (ret < 0) + return errno_to_blk_status(ret); + cur_logical += map_length; } - btrfs_bio_counter_dec(fs_info); return BLK_STS_OK; } -- 2.34.1