> 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