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.

Reply via email to