|
@@ -101,7 +101,7 @@ frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mw *r)
|
|
struct rpcrdma_frmr *f = &r->frmr;
|
|
struct rpcrdma_frmr *f = &r->frmr;
|
|
int rc;
|
|
int rc;
|
|
|
|
|
|
- f->fr_mr = ib_alloc_mr(ia->ri_pd, IB_MR_TYPE_MEM_REG, depth);
|
|
|
|
|
|
+ f->fr_mr = ib_alloc_mr(ia->ri_pd, ia->ri_mrtype, depth);
|
|
if (IS_ERR(f->fr_mr))
|
|
if (IS_ERR(f->fr_mr))
|
|
goto out_mr_err;
|
|
goto out_mr_err;
|
|
|
|
|
|
@@ -157,7 +157,7 @@ __frwr_reset_mr(struct rpcrdma_ia *ia, struct rpcrdma_mw *r)
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
- f->fr_mr = ib_alloc_mr(ia->ri_pd, IB_MR_TYPE_MEM_REG,
|
|
|
|
|
|
+ f->fr_mr = ib_alloc_mr(ia->ri_pd, ia->ri_mrtype,
|
|
ia->ri_max_frmr_depth);
|
|
ia->ri_max_frmr_depth);
|
|
if (IS_ERR(f->fr_mr)) {
|
|
if (IS_ERR(f->fr_mr)) {
|
|
pr_warn("rpcrdma: ib_alloc_mr status %ld, frwr %p orphaned\n",
|
|
pr_warn("rpcrdma: ib_alloc_mr status %ld, frwr %p orphaned\n",
|
|
@@ -171,10 +171,6 @@ __frwr_reset_mr(struct rpcrdma_ia *ia, struct rpcrdma_mw *r)
|
|
}
|
|
}
|
|
|
|
|
|
/* Reset of a single FRMR. Generate a fresh rkey by replacing the MR.
|
|
/* Reset of a single FRMR. Generate a fresh rkey by replacing the MR.
|
|
- *
|
|
|
|
- * There's no recovery if this fails. The FRMR is abandoned, but
|
|
|
|
- * remains in rb_all. It will be cleaned up when the transport is
|
|
|
|
- * destroyed.
|
|
|
|
*/
|
|
*/
|
|
static void
|
|
static void
|
|
frwr_op_recover_mr(struct rpcrdma_mw *mw)
|
|
frwr_op_recover_mr(struct rpcrdma_mw *mw)
|
|
@@ -210,11 +206,16 @@ static int
|
|
frwr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep,
|
|
frwr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep,
|
|
struct rpcrdma_create_data_internal *cdata)
|
|
struct rpcrdma_create_data_internal *cdata)
|
|
{
|
|
{
|
|
|
|
+ struct ib_device_attr *attrs = &ia->ri_device->attrs;
|
|
int depth, delta;
|
|
int depth, delta;
|
|
|
|
|
|
|
|
+ ia->ri_mrtype = IB_MR_TYPE_MEM_REG;
|
|
|
|
+ if (attrs->device_cap_flags & IB_DEVICE_SG_GAPS_REG)
|
|
|
|
+ ia->ri_mrtype = IB_MR_TYPE_SG_GAPS;
|
|
|
|
+
|
|
ia->ri_max_frmr_depth =
|
|
ia->ri_max_frmr_depth =
|
|
min_t(unsigned int, RPCRDMA_MAX_DATA_SEGS,
|
|
min_t(unsigned int, RPCRDMA_MAX_DATA_SEGS,
|
|
- ia->ri_device->attrs.max_fast_reg_page_list_len);
|
|
|
|
|
|
+ attrs->max_fast_reg_page_list_len);
|
|
dprintk("RPC: %s: device's max FR page list len = %u\n",
|
|
dprintk("RPC: %s: device's max FR page list len = %u\n",
|
|
__func__, ia->ri_max_frmr_depth);
|
|
__func__, ia->ri_max_frmr_depth);
|
|
|
|
|
|
@@ -241,8 +242,8 @@ frwr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep,
|
|
}
|
|
}
|
|
|
|
|
|
ep->rep_attr.cap.max_send_wr *= depth;
|
|
ep->rep_attr.cap.max_send_wr *= depth;
|
|
- if (ep->rep_attr.cap.max_send_wr > ia->ri_device->attrs.max_qp_wr) {
|
|
|
|
- cdata->max_requests = ia->ri_device->attrs.max_qp_wr / depth;
|
|
|
|
|
|
+ if (ep->rep_attr.cap.max_send_wr > attrs->max_qp_wr) {
|
|
|
|
+ cdata->max_requests = attrs->max_qp_wr / depth;
|
|
if (!cdata->max_requests)
|
|
if (!cdata->max_requests)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
ep->rep_attr.cap.max_send_wr = cdata->max_requests *
|
|
ep->rep_attr.cap.max_send_wr = cdata->max_requests *
|
|
@@ -348,6 +349,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
|
|
int nsegs, bool writing, struct rpcrdma_mw **out)
|
|
int nsegs, bool writing, struct rpcrdma_mw **out)
|
|
{
|
|
{
|
|
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
|
|
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
|
|
|
|
+ bool holes_ok = ia->ri_mrtype == IB_MR_TYPE_SG_GAPS;
|
|
struct rpcrdma_mw *mw;
|
|
struct rpcrdma_mw *mw;
|
|
struct rpcrdma_frmr *frmr;
|
|
struct rpcrdma_frmr *frmr;
|
|
struct ib_mr *mr;
|
|
struct ib_mr *mr;
|
|
@@ -383,8 +385,8 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
|
|
|
|
|
|
++seg;
|
|
++seg;
|
|
++i;
|
|
++i;
|
|
-
|
|
|
|
- /* Check for holes */
|
|
|
|
|
|
+ if (holes_ok)
|
|
|
|
+ continue;
|
|
if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
|
|
if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
|
|
offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
|
|
offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
|
|
break;
|
|
break;
|
|
@@ -421,7 +423,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
|
|
IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
|
|
IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
|
|
IB_ACCESS_REMOTE_READ;
|
|
IB_ACCESS_REMOTE_READ;
|
|
|
|
|
|
- DECR_CQCOUNT(&r_xprt->rx_ep);
|
|
|
|
|
|
+ rpcrdma_set_signaled(&r_xprt->rx_ep, ®_wr->wr);
|
|
rc = ib_post_send(ia->ri_id->qp, ®_wr->wr, &bad_wr);
|
|
rc = ib_post_send(ia->ri_id->qp, ®_wr->wr, &bad_wr);
|
|
if (rc)
|
|
if (rc)
|
|
goto out_senderr;
|
|
goto out_senderr;
|
|
@@ -451,26 +453,6 @@ out_senderr:
|
|
return -ENOTCONN;
|
|
return -ENOTCONN;
|
|
}
|
|
}
|
|
|
|
|
|
-static struct ib_send_wr *
|
|
|
|
-__frwr_prepare_linv_wr(struct rpcrdma_mw *mw)
|
|
|
|
-{
|
|
|
|
- struct rpcrdma_frmr *f = &mw->frmr;
|
|
|
|
- struct ib_send_wr *invalidate_wr;
|
|
|
|
-
|
|
|
|
- dprintk("RPC: %s: invalidating frmr %p\n", __func__, f);
|
|
|
|
-
|
|
|
|
- f->fr_state = FRMR_IS_INVALID;
|
|
|
|
- invalidate_wr = &f->fr_invwr;
|
|
|
|
-
|
|
|
|
- memset(invalidate_wr, 0, sizeof(*invalidate_wr));
|
|
|
|
- f->fr_cqe.done = frwr_wc_localinv;
|
|
|
|
- invalidate_wr->wr_cqe = &f->fr_cqe;
|
|
|
|
- invalidate_wr->opcode = IB_WR_LOCAL_INV;
|
|
|
|
- invalidate_wr->ex.invalidate_rkey = f->fr_mr->rkey;
|
|
|
|
-
|
|
|
|
- return invalidate_wr;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* Invalidate all memory regions that were registered for "req".
|
|
/* Invalidate all memory regions that were registered for "req".
|
|
*
|
|
*
|
|
* Sleeps until it is safe for the host CPU to access the
|
|
* Sleeps until it is safe for the host CPU to access the
|
|
@@ -481,12 +463,12 @@ __frwr_prepare_linv_wr(struct rpcrdma_mw *mw)
|
|
static void
|
|
static void
|
|
frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
|
|
frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
|
|
{
|
|
{
|
|
- struct ib_send_wr *invalidate_wrs, *pos, *prev, *bad_wr;
|
|
|
|
|
|
+ struct ib_send_wr *first, **prev, *last, *bad_wr;
|
|
struct rpcrdma_rep *rep = req->rl_reply;
|
|
struct rpcrdma_rep *rep = req->rl_reply;
|
|
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
|
|
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
|
|
struct rpcrdma_mw *mw, *tmp;
|
|
struct rpcrdma_mw *mw, *tmp;
|
|
struct rpcrdma_frmr *f;
|
|
struct rpcrdma_frmr *f;
|
|
- int rc;
|
|
|
|
|
|
+ int count, rc;
|
|
|
|
|
|
dprintk("RPC: %s: req %p\n", __func__, req);
|
|
dprintk("RPC: %s: req %p\n", __func__, req);
|
|
|
|
|
|
@@ -496,22 +478,29 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
|
|
* a single ib_post_send() call.
|
|
* a single ib_post_send() call.
|
|
*/
|
|
*/
|
|
f = NULL;
|
|
f = NULL;
|
|
- invalidate_wrs = pos = prev = NULL;
|
|
|
|
|
|
+ count = 0;
|
|
|
|
+ prev = &first;
|
|
list_for_each_entry(mw, &req->rl_registered, mw_list) {
|
|
list_for_each_entry(mw, &req->rl_registered, mw_list) {
|
|
|
|
+ mw->frmr.fr_state = FRMR_IS_INVALID;
|
|
|
|
+
|
|
if ((rep->rr_wc_flags & IB_WC_WITH_INVALIDATE) &&
|
|
if ((rep->rr_wc_flags & IB_WC_WITH_INVALIDATE) &&
|
|
- (mw->mw_handle == rep->rr_inv_rkey)) {
|
|
|
|
- mw->frmr.fr_state = FRMR_IS_INVALID;
|
|
|
|
|
|
+ (mw->mw_handle == rep->rr_inv_rkey))
|
|
continue;
|
|
continue;
|
|
- }
|
|
|
|
-
|
|
|
|
- pos = __frwr_prepare_linv_wr(mw);
|
|
|
|
|
|
|
|
- if (!invalidate_wrs)
|
|
|
|
- invalidate_wrs = pos;
|
|
|
|
- else
|
|
|
|
- prev->next = pos;
|
|
|
|
- prev = pos;
|
|
|
|
f = &mw->frmr;
|
|
f = &mw->frmr;
|
|
|
|
+ dprintk("RPC: %s: invalidating frmr %p\n",
|
|
|
|
+ __func__, f);
|
|
|
|
+
|
|
|
|
+ f->fr_cqe.done = frwr_wc_localinv;
|
|
|
|
+ last = &f->fr_invwr;
|
|
|
|
+ memset(last, 0, sizeof(*last));
|
|
|
|
+ last->wr_cqe = &f->fr_cqe;
|
|
|
|
+ last->opcode = IB_WR_LOCAL_INV;
|
|
|
|
+ last->ex.invalidate_rkey = mw->mw_handle;
|
|
|
|
+ count++;
|
|
|
|
+
|
|
|
|
+ *prev = last;
|
|
|
|
+ prev = &last->next;
|
|
}
|
|
}
|
|
if (!f)
|
|
if (!f)
|
|
goto unmap;
|
|
goto unmap;
|
|
@@ -520,17 +509,22 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
|
|
* last WR in the chain completes, all WRs in the chain
|
|
* last WR in the chain completes, all WRs in the chain
|
|
* are complete.
|
|
* are complete.
|
|
*/
|
|
*/
|
|
- f->fr_invwr.send_flags = IB_SEND_SIGNALED;
|
|
|
|
|
|
+ last->send_flags = IB_SEND_SIGNALED;
|
|
f->fr_cqe.done = frwr_wc_localinv_wake;
|
|
f->fr_cqe.done = frwr_wc_localinv_wake;
|
|
reinit_completion(&f->fr_linv_done);
|
|
reinit_completion(&f->fr_linv_done);
|
|
- INIT_CQCOUNT(&r_xprt->rx_ep);
|
|
|
|
|
|
+
|
|
|
|
+ /* Initialize CQ count, since there is always a signaled
|
|
|
|
+ * WR being posted here. The new cqcount depends on how
|
|
|
|
+ * many SQEs are about to be consumed.
|
|
|
|
+ */
|
|
|
|
+ rpcrdma_init_cqcount(&r_xprt->rx_ep, count);
|
|
|
|
|
|
/* Transport disconnect drains the receive CQ before it
|
|
/* Transport disconnect drains the receive CQ before it
|
|
* replaces the QP. The RPC reply handler won't call us
|
|
* replaces the QP. The RPC reply handler won't call us
|
|
* unless ri_id->qp is a valid pointer.
|
|
* unless ri_id->qp is a valid pointer.
|
|
*/
|
|
*/
|
|
r_xprt->rx_stats.local_inv_needed++;
|
|
r_xprt->rx_stats.local_inv_needed++;
|
|
- rc = ib_post_send(ia->ri_id->qp, invalidate_wrs, &bad_wr);
|
|
|
|
|
|
+ rc = ib_post_send(ia->ri_id->qp, first, &bad_wr);
|
|
if (rc)
|
|
if (rc)
|
|
goto reset_mrs;
|
|
goto reset_mrs;
|
|
|
|
|
|
@@ -541,7 +535,7 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
|
|
*/
|
|
*/
|
|
unmap:
|
|
unmap:
|
|
list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) {
|
|
list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) {
|
|
- dprintk("RPC: %s: unmapping frmr %p\n",
|
|
|
|
|
|
+ dprintk("RPC: %s: DMA unmapping frmr %p\n",
|
|
__func__, &mw->frmr);
|
|
__func__, &mw->frmr);
|
|
list_del_init(&mw->mw_list);
|
|
list_del_init(&mw->mw_list);
|
|
ib_dma_unmap_sg(ia->ri_device,
|
|
ib_dma_unmap_sg(ia->ri_device,
|
|
@@ -559,7 +553,7 @@ reset_mrs:
|
|
*/
|
|
*/
|
|
list_for_each_entry(mw, &req->rl_registered, mw_list) {
|
|
list_for_each_entry(mw, &req->rl_registered, mw_list) {
|
|
f = &mw->frmr;
|
|
f = &mw->frmr;
|
|
- if (mw->frmr.fr_mr->rkey == bad_wr->ex.invalidate_rkey) {
|
|
|
|
|
|
+ if (mw->mw_handle == bad_wr->ex.invalidate_rkey) {
|
|
__frwr_reset_mr(ia, mw);
|
|
__frwr_reset_mr(ia, mw);
|
|
bad_wr = bad_wr->next;
|
|
bad_wr = bad_wr->next;
|
|
}
|
|
}
|