xprtrdma: Do not wake RPC consumer on a failed LocalInv

Throw away any reply where the LocalInv flushes or could not be
posted. The registered memory region is in an unknown state until
the disconnect completes.

rpcrdma_xprt_disconnect() will find and release the MR. No need to
put it back on the MR free list in this case.

The client retransmits pending RPC requests once it reestablishes a
fresh connection, so a replacement reply should be forthcoming on
the next connection instance.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
Chuck Lever 2021-04-19 14:03:19 -04:00 коммит произвёл Trond Myklebust
Родитель e4b52ca013
Коммит 8a053433de
3 изменённых файлов: 41 добавлений и 9 удалений

Просмотреть файл

@ -576,10 +576,14 @@ static void frwr_wc_localinv_done(struct ib_cq *cq, struct ib_wc *wc)
rep = mr->mr_req->rl_reply;
smp_rmb();
frwr_mr_done(wc, mr);
if (wc->status != IB_WC_SUCCESS) {
if (rep)
rpcrdma_unpin_rqst(rep);
rpcrdma_flush_disconnect(cq->cq_context, wc);
return;
}
frwr_mr_put(mr);
rpcrdma_complete_rqst(rep);
rpcrdma_flush_disconnect(cq->cq_context, wc);
}
/**
@ -645,8 +649,9 @@ void frwr_unmap_async(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
trace_xprtrdma_post_linv_err(req, rc);
/* The final LOCAL_INV WR in the chain is supposed to
* do the wake. If it was never posted, the wake will
* not happen, so wake here in that case.
* do the wake. If it was never posted, the wake does
* not happen. Unpin the rqst in preparation for its
* retransmission.
*/
rpcrdma_complete_rqst(req->rl_reply);
rpcrdma_unpin_rqst(req->rl_reply);
}

Просмотреть файл

@ -1326,9 +1326,35 @@ rpcrdma_decode_error(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep,
return -EIO;
}
/* Perform XID lookup, reconstruction of the RPC reply, and
* RPC completion while holding the transport lock to ensure
* the rep, rqst, and rq_task pointers remain stable.
/**
* rpcrdma_unpin_rqst - Release rqst without completing it
* @rep: RPC/RDMA Receive context
*
* This is done when a connection is lost so that a Reply
* can be dropped and its matching Call can be subsequently
* retransmitted on a new connection.
*/
void rpcrdma_unpin_rqst(struct rpcrdma_rep *rep)
{
struct rpc_xprt *xprt = &rep->rr_rxprt->rx_xprt;
struct rpc_rqst *rqst = rep->rr_rqst;
struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
req->rl_reply = NULL;
rep->rr_rqst = NULL;
spin_lock(&xprt->queue_lock);
xprt_unpin_rqst(rqst);
spin_unlock(&xprt->queue_lock);
}
/**
* rpcrdma_complete_rqst - Pass completed rqst back to RPC
* @rep: RPC/RDMA Receive context
*
* Reconstruct the RPC reply and complete the transaction
* while @rqst is still pinned to ensure the rep, rqst, and
* rq_task pointers remain stable.
*/
void rpcrdma_complete_rqst(struct rpcrdma_rep *rep)
{

Просмотреть файл

@ -561,6 +561,7 @@ int rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst);
void rpcrdma_set_max_header_sizes(struct rpcrdma_ep *ep);
void rpcrdma_reset_cwnd(struct rpcrdma_xprt *r_xprt);
void rpcrdma_complete_rqst(struct rpcrdma_rep *rep);
void rpcrdma_unpin_rqst(struct rpcrdma_rep *rep);
void rpcrdma_reply_handler(struct rpcrdma_rep *rep);
static inline void rpcrdma_set_xdrlen(struct xdr_buf *xdr, size_t len)