Re: [PATCH v5 07/16] block: introduce dma map backed bio type

Christoph Hellwig <[email protected]> Tue, 4 Aug 2026 18:24:40 +0200
Newsgroups gmane.linux.kernel.io-uring,gmane.linux.block,gmane.linux.kernel,gmane.linux.file-systems,gmane.linux.drivers.video-input-infrastructure,gmane.comp.video.dri.devel,gmane.comp.file-systems.btrfs,gmane.comp.file-systems.ceph.devel
Message-ID <[email protected]>
On Sat, Aug 01, 2026 at 04:46:19PM +0100, Pavel Begunkov wrote:
> Premapped buffers don't require a generic bio_vec since these have
> already been dma mapped. Repurpose the bi_io_vec space to strore dmabuf
> maps as they are mutually exclusive.
> 
> Suggested-by: Keith Busch <[email protected]>
> Signed-off-by: Pavel Begunkov <[email protected]>
> ---
>  block/bio.c               | 15 +++++++++++++--
>  block/blk-merge.c         | 37 +++++++++++++++++++++++++++++++++++++
>  block/fops.c              |  2 +-
>  include/linux/bio.h       |  9 +++++----
>  include/linux/blk-mq.h    |  7 +++++++
>  include/linux/blk_types.h | 14 +++++++++++++-
>  include/linux/bvec.h      |  3 ++-
>  7 files changed, 78 insertions(+), 9 deletions(-)
> 
> diff --git a/block/bio.c b/block/bio.c
> index 898b2f5ef8c8..1602eab05761 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -860,7 +860,11 @@ static int __bio_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp)
>  	bio->bi_write_hint = bio_src->bi_write_hint;
>  	bio->bi_write_stream = bio_src->bi_write_stream;
>  	bio->bi_iter = bio_src->bi_iter;
> -	bio->bi_io_vec = bio_src->bi_io_vec;
> +
> +	if (op_is_dmabuf(bio->bi_opf))
> +		bio->bi_dmabuf_map = bio_src->bi_dmabuf_map;
> +	else
> +		bio->bi_io_vec = bio_src->bi_io_vec;
>  
>  	if (bio->bi_bdev) {
>  		if (bio->bi_bdev == bio_src->bi_bdev &&
> @@ -1183,16 +1187,23 @@ EXPORT_SYMBOL_GPL(__bio_release_pages);
>  
>  bool bio_iov_iter_set(struct bio *bio, const struct iov_iter *iter)
>  {
> -	if (!iov_iter_is_bvec(iter))
> +	if (!iov_iter_is_bvec(iter) && !iov_iter_is_dmabuf_map(iter))
>  		return false;
>  
>  	WARN_ON_ONCE(bio->bi_max_vecs);
>  
> +	static_assert(offsetof(struct bio, bi_io_vec) ==
> +		      offsetof(struct bio, bi_dmabuf_map));
> +	static_assert(offsetof(struct iov_iter, bvec) ==
> +		      offsetof(struct iov_iter, dmabuf_map));
> +
>  	bio->bi_io_vec = (struct bio_vec *)iter->bvec;
>  	bio->bi_iter.bi_idx = 0;
>  	bio->bi_iter.bi_offset = iter->iov_offset;
>  	bio->bi_iter.bi_size = iov_iter_count(iter);
>  	bio_set_flag(bio, BIO_CLONED);
> +	if (iov_iter_is_dmabuf_map(iter))
> +		bio->bi_opf |= REQ_NOMERGE | REQ_DMABUF;
>  	return true;
>  }
>  
> diff --git a/block/blk-merge.c b/block/blk-merge.c
> index 258a726071d1..1beedc42a85d 100644
> --- a/block/blk-merge.c
> +++ b/block/blk-merge.c
> @@ -9,6 +9,7 @@
>  #include <linux/blk-integrity.h>
>  #include <linux/part_stat.h>
>  #include <linux/blk-cgroup.h>
> +#include <linux/dma-buf-io.h>
>  
>  #include <trace/events/block.h>
>  
> @@ -319,6 +320,28 @@ static inline unsigned int bvec_seg_gap(struct bio_vec *bvprv,
>  	return bv->bv_offset | (bvprv->bv_offset + bvprv->bv_len);
>  }
>  
> +static inline int bio_split_io_at_dmabuf(struct bio *bio,
> +		const struct queue_limits *lim, unsigned *segs,
> +		unsigned max_bytes, unsigned len_align_mask,
> +		unsigned start_align_mask)
> +{
> +	unsigned bytes = min(bio->bi_iter.bi_size, max_bytes);
> +	unsigned seg_shift = bio->bi_dmabuf_map->seg_shift;
> +	unsigned offset = bio->bi_iter.bi_offset & ((1U << seg_shift) - 1);
> +
> +	if ((bio->bi_iter.bi_offset & start_align_mask) ||
> +	    (bio->bi_iter.bi_size & len_align_mask))
> +		return -EINVAL;
> +
> +	/* single contiguous range into the dma-buf */
> +	*segs = 1;
> +
> +	bytes = min(bytes, ((unsigned)lim->max_segments << seg_shift) - offset);

I guess ->seg_shift is some sort of encoding of a max
segment size?

Comments please.