Commit 7c39f7f6 authored by Josh Collier's avatar Josh Collier Committed by Jason Gunthorpe

IB/rdmavt: Fix frwr memory registration

Current implementation was not properly handling frwr memory
registrations. This was uncovered by commit 27f26cec761das ("xprtrdma:
Plant XID in on-the-wire RDMA offset (FRWR)") in which xprtrdma, which is
used for NFS over RDMA, started failing as it was the first ULP to modify
the ib_mr iova resulting in the NFS server getting REMOTE ACCESS ERROR
when attempting to perform RDMA Writes to the client.

The fix is to properly capture the true iova, offset, and length in the
call to ib_map_mr_sg, and then update the iova when processing the
IB_WR_REG_MEM on the send queue.

Fixes: a41081aa ("IB/rdmavt: Add support for ib_map_mr_sg")
Cc: stable@vger.kernel.org
Reviewed-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Reviewed-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Reviewed-by: default avatarMichael J. Ruhl <michael.j.ruhl@intel.com>
Signed-off-by: default avatarJosh Collier <josh.d.collier@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent dc4060a5
...@@ -608,11 +608,6 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr) ...@@ -608,11 +608,6 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr)
if (unlikely(mapped_segs == mr->mr.max_segs)) if (unlikely(mapped_segs == mr->mr.max_segs))
return -ENOMEM; return -ENOMEM;
if (mr->mr.length == 0) {
mr->mr.user_base = addr;
mr->mr.iova = addr;
}
m = mapped_segs / RVT_SEGSZ; m = mapped_segs / RVT_SEGSZ;
n = mapped_segs % RVT_SEGSZ; n = mapped_segs % RVT_SEGSZ;
mr->mr.map[m]->segs[n].vaddr = (void *)addr; mr->mr.map[m]->segs[n].vaddr = (void *)addr;
...@@ -630,17 +625,24 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr) ...@@ -630,17 +625,24 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr)
* @sg_nents: number of entries in sg * @sg_nents: number of entries in sg
* @sg_offset: offset in bytes into sg * @sg_offset: offset in bytes into sg
* *
* Overwrite rvt_mr length with mr length calculated by ib_sg_to_pages.
*
* Return: number of sg elements mapped to the memory region * Return: number of sg elements mapped to the memory region
*/ */
int rvt_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int rvt_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
int sg_nents, unsigned int *sg_offset) int sg_nents, unsigned int *sg_offset)
{ {
struct rvt_mr *mr = to_imr(ibmr); struct rvt_mr *mr = to_imr(ibmr);
int ret;
mr->mr.length = 0; mr->mr.length = 0;
mr->mr.page_shift = PAGE_SHIFT; mr->mr.page_shift = PAGE_SHIFT;
return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, rvt_set_page);
rvt_set_page); mr->mr.user_base = ibmr->iova;
mr->mr.iova = ibmr->iova;
mr->mr.offset = ibmr->iova - (u64)mr->mr.map[0]->segs[0].vaddr;
mr->mr.length = (size_t)ibmr->length;
return ret;
} }
/** /**
...@@ -671,6 +673,7 @@ int rvt_fast_reg_mr(struct rvt_qp *qp, struct ib_mr *ibmr, u32 key, ...@@ -671,6 +673,7 @@ int rvt_fast_reg_mr(struct rvt_qp *qp, struct ib_mr *ibmr, u32 key,
ibmr->rkey = key; ibmr->rkey = key;
mr->mr.lkey = key; mr->mr.lkey = key;
mr->mr.access_flags = access; mr->mr.access_flags = access;
mr->mr.iova = ibmr->iova;
atomic_set(&mr->mr.lkey_invalid, 0); atomic_set(&mr->mr.lkey_invalid, 0);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment