> On Feb 12, 2020, at 8:43 AM, Chuck Lever <chuck.le...@oracle.com> wrote:
> 
> The @nents value that was passed to ib_dma_map_sg() has to be passed
> to the matching ib_dma_unmap_sg() call. If ib_dma_map_sg() choses to
> concatenate sg entries, it will return a different nents value than
> it was passed.
> 
> The bug was exposed by recent changes to the AMD IOMMU driver, which
> enabled sg entry concatenation.
> 
> Looking all the way back to 4143f34e01e9 ("xprtrdma: Port to new
> memory registration API") and reviewing other kernel ULPs, it's not
> clear that the frwr_map() logic was ever correct for this case.
> 
> Reported-by: Andre Tomt <an...@tomt.net>
> Suggested-by: Robin Murphy <robin.mur...@arm.com>
> Signed-off-by: Chuck Lever <chuck.le...@oracle.com>
> ---
> include/trace/events/rpcrdma.h |    6 ++++--
> net/sunrpc/xprtrdma/frwr_ops.c |   13 +++++++------
> 2 files changed, 11 insertions(+), 8 deletions(-)
> 
> Hi Andre, here's take 2, based on the trace data you sent me.
> Please let me know if this one fares any better.
> 
> Changes since v1:
> - Ensure the correct nents value is passed to ib_map_mr_sg
> - Record the mr_nents value in the MR trace points
> 
> diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h
> index c0e4c93324f5..023c5da45999 100644
> --- a/include/trace/events/rpcrdma.h
> +++ b/include/trace/events/rpcrdma.h
> @@ -275,6 +275,7 @@ DECLARE_EVENT_CLASS(xprtrdma_mr,
> 
>       TP_STRUCT__entry(
>               __field(const void *, mr)
> +             __field(unsigned int, nents)
>               __field(u32, handle)
>               __field(u32, length)
>               __field(u64, offset)
> @@ -283,14 +284,15 @@ DECLARE_EVENT_CLASS(xprtrdma_mr,
> 
>       TP_fast_assign(
>               __entry->mr = mr;
> +             __entry->nents = mr->mr_nents;
>               __entry->handle = mr->mr_handle;
>               __entry->length = mr->mr_length;
>               __entry->offset = mr->mr_offset;
>               __entry->dir    = mr->mr_dir;
>       ),
> 
> -     TP_printk("mr=%p %u@0x%016llx:0x%08x (%s)",
> -             __entry->mr, __entry->length,
> +     TP_printk("mr=%p %d %u@0x%016llx:0x%08x (%s)",
> +             __entry->mr, __entry->mr_nents, __entry->length,

This should be:
                __entry->mr, __entry->nents, __entry->length,

Sorry about that.


>               (unsigned long long)__entry->offset, __entry->handle,
>               xprtrdma_show_direction(__entry->dir)
>       )
> diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c
> index 095be887753e..75617646702b 100644
> --- a/net/sunrpc/xprtrdma/frwr_ops.c
> +++ b/net/sunrpc/xprtrdma/frwr_ops.c
> @@ -288,8 +288,8 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt 
> *r_xprt,
> {
>       struct rpcrdma_ia *ia = &r_xprt->rx_ia;
>       struct ib_reg_wr *reg_wr;
> +     int i, n, dma_nents;
>       struct ib_mr *ibmr;
> -     int i, n;
>       u8 key;
> 
>       if (nsegs > ia->ri_max_frwr_depth)
> @@ -313,15 +313,16 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt 
> *r_xprt,
>                       break;
>       }
>       mr->mr_dir = rpcrdma_data_dir(writing);
> +     mr->mr_nents = i;
> 
> -     mr->mr_nents =
> -             ib_dma_map_sg(ia->ri_id->device, mr->mr_sg, i, mr->mr_dir);
> -     if (!mr->mr_nents)
> +     dma_nents = ib_dma_map_sg(ia->ri_id->device, mr->mr_sg,
> +                               mr->mr_nents, mr->mr_dir);
> +     if (!dma_nents)
>               goto out_dmamap_err;
> 
>       ibmr = mr->frwr.fr_mr;
> -     n = ib_map_mr_sg(ibmr, mr->mr_sg, mr->mr_nents, NULL, PAGE_SIZE);
> -     if (unlikely(n != mr->mr_nents))
> +     n = ib_map_mr_sg(ibmr, mr->mr_sg, dma_nents, NULL, PAGE_SIZE);
> +     if (n != dma_nents)
>               goto out_mapmr_err;
> 
>       ibmr->iova &= 0x00000000ffffffff;
> 
> 

--
Chuck Lever



_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to