Re: [PATCH 6/6] ublk: lift need_map check out of ublk_{,un}map_io()

Caleb Sander Mateos <[email protected]> Thu, 30 Jul 2026 08:54:07 -0700
Newsgroups org.kernel.vger.linux-block,org.kernel.vger.linux-kernel
Message-ID <CADUfDZr2uZi775agBb5TszOrL3q6QH199bZNtqSUN9KzHBEjEw@mail.gmail.com>
On Tue, Jul 28, 2026 at 6:30 PM Caleb Sander Mateos
<[email protected]> wrote:
>
> ublk_map_io() and ublk_unmap_io() are no-ops for ublk devices that
> enable user copy or zero copy. However, the implementation is a bit
> convoluted, returning the full request data length and relying on the
> caller to check the return value against the request length.
> UBLK_F_SHMEM_ZC recently added branches to skip the ublk_{,un}map_io()
> call for I/Os using a shared-memory buffer. This is a more logical place
> for the need_map check, so move it there from ublk_{,un}map_io().
>
> Checking need_map early also avoids the expensive pointer-chasing for
> the ublk_iod_is_shmem_zc() check in __ublk_complete_rq() in the common
> case of a ublk device using user copy or zero copy.
>
> Signed-off-by: Caleb Sander Mateos <[email protected]>
> ---
>  drivers/block/ublk_drv.c | 21 +++++++--------------
>  1 file changed, 7 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 1da45e382253..d4443a43229e 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -1464,19 +1464,15 @@ static inline bool ublk_need_unmap_req(const struct request *req)
>  {
>         return blk_rq_has_data(req) &&
>                (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_DRV_IN);
>  }
>
> -static unsigned int ublk_map_io(const struct ublk_queue *ubq,
> -                               const struct request *req,
> +static unsigned int ublk_map_io(const struct request *req,
>                                 const struct ublk_io *io)
>  {
>         const unsigned int rq_bytes = blk_rq_bytes(req);
>
> -       if (!ublk_need_map_io(ubq))
> -               return rq_bytes;
> -
>         /*
>          * no zero copy, we delay copy WRITE request data into ublksrv
>          * context and the big benefit is that pinning pages in current
>          * context is pretty fast, see ublk_pin_user_pages
>          */
> @@ -1488,19 +1484,15 @@ static unsigned int ublk_map_io(const struct ublk_queue *ubq,
>                 return ublk_copy_user_pages(req, 0, &iter, dir);
>         }
>         return rq_bytes;
>  }
>
> -static unsigned int ublk_unmap_io(bool need_map,
> -               const struct request *req,
> +static unsigned int ublk_unmap_io(const struct request *req,
>                 const struct ublk_io *io)
>  {
>         const unsigned int rq_bytes = blk_rq_bytes(req);
>
> -       if (!need_map)
> -               return rq_bytes;
> -
>         if (ublk_need_unmap_req(req)) {
>                 struct iov_iter iter;
>                 const int dir = ITER_SOURCE;
>
>                 import_ubuf(dir, u64_to_user_ptr(io->buf.addr), io->res, &iter);
> @@ -1591,15 +1583,16 @@ static inline void __ublk_complete_rq(struct request *req, struct ublk_io *io,
>         if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE &&
>             req_op(req) != REQ_OP_DRV_IN)
>                 goto exit;
>
>         /* shmem zero copy: no data to unmap, pages already shared */
> -       if (ublk_iod_is_shmem_zc(req->mq_hctx->driver_data, req->tag))
> +       if (!need_map ||
> +           ublk_iod_is_shmem_zc(req->mq_hctx->driver_data, req->tag))

Realized the ublk_need_unmap_req() check in ublk_unmap_io() can also
be combined with the req_op(req) check above. Will update in v2.

Best,
Caleb

>                 goto exit;
>
>         /* for READ request, writing data in iod->addr to rq buffers */
> -       unmapped_bytes = ublk_unmap_io(need_map, req, io);
> +       unmapped_bytes = ublk_unmap_io(req, io);
>
>         /*
>          * Extremely impossible since we got data filled in just before
>          *
>          * Re-read simply for this unlikely case.
> @@ -1755,14 +1748,14 @@ static bool ublk_start_io(const struct ublk_queue *ubq, struct request *req,
>                           struct ublk_io *io)
>  {
>         unsigned mapped_bytes;
>
>         /* shmem zero copy: skip data copy, pages already shared */
> -       if (ublk_iod_is_shmem_zc(ubq, req->tag))
> +       if (!ublk_need_map_io(ubq) || ublk_iod_is_shmem_zc(ubq, req->tag))
>                 return true;
>
> -       mapped_bytes = ublk_map_io(ubq, req, io);
> +       mapped_bytes = ublk_map_io(req, io);
>
>         /* partially mapped, update io descriptor */
>         if (unlikely(mapped_bytes != blk_rq_bytes(req))) {
>                 /*
>                  * Nothing mapped, retry until we succeed.
> --
> 2.54.0
>