xprtrdma: Pre-mark remotely invalidated MRs
There are rare cases where an rpcrdma_req and its matched
rpcrdma_rep can be re-used, via rpcrdma_buffer_put, while the RPC
reply handler is still using that req. This is typically due to a
signal firing at just the wrong instant.
As part of closing this race window, avoid using the wrong
rpcrdma_rep to detect remotely invalidated MRs. Mark MRs as
invalidated while we are sure the rep is still OK to use.
BugLink: https://bugzilla.linux-nfs.org/show_bug.cgi?id=305
Fixes: 68791649a7
('xprtrdma: Invalidate in the RPC reply ... ')
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
04d25b7d5d
commit
4b196dc6fe
@ -464,7 +464,6 @@ 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 *first, **prev, *last, *bad_wr;
|
struct ib_send_wr *first, **prev, *last, *bad_wr;
|
||||||
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_frmr *f;
|
struct rpcrdma_frmr *f;
|
||||||
struct rpcrdma_mw *mw;
|
struct rpcrdma_mw *mw;
|
||||||
@ -483,8 +482,7 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
|
|||||||
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;
|
mw->frmr.fr_state = FRMR_IS_INVALID;
|
||||||
|
|
||||||
if ((rep->rr_wc_flags & IB_WC_WITH_INVALIDATE) &&
|
if (mw->mw_flags & RPCRDMA_MW_F_RI)
|
||||||
(mw->mw_handle == rep->rr_inv_rkey))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
f = &mw->frmr;
|
f = &mw->frmr;
|
||||||
|
@ -928,6 +928,24 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
|
|||||||
return fixup_copy_count;
|
return fixup_copy_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Caller must guarantee @rep remains stable during this call.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rpcrdma_mark_remote_invalidation(struct list_head *mws,
|
||||||
|
struct rpcrdma_rep *rep)
|
||||||
|
{
|
||||||
|
struct rpcrdma_mw *mw;
|
||||||
|
|
||||||
|
if (!(rep->rr_wc_flags & IB_WC_WITH_INVALIDATE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry(mw, mws, mw_list)
|
||||||
|
if (mw->mw_handle == rep->rr_inv_rkey) {
|
||||||
|
mw->mw_flags = RPCRDMA_MW_F_RI;
|
||||||
|
break; /* only one invalidated MR per RPC */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||||
/* By convention, backchannel calls arrive via rdma_msg type
|
/* By convention, backchannel calls arrive via rdma_msg type
|
||||||
* messages, and never populate the chunk lists. This makes
|
* messages, and never populate the chunk lists. This makes
|
||||||
@ -1006,13 +1024,13 @@ rpcrdma_reply_handler(struct work_struct *work)
|
|||||||
/* Sanity checking has passed. We are now committed
|
/* Sanity checking has passed. We are now committed
|
||||||
* to complete this transaction.
|
* to complete this transaction.
|
||||||
*/
|
*/
|
||||||
|
rpcrdma_mark_remote_invalidation(&req->rl_registered, rep);
|
||||||
list_del_init(&rqst->rq_list);
|
list_del_init(&rqst->rq_list);
|
||||||
|
req->rl_reply = rep;
|
||||||
spin_unlock_bh(&xprt->transport_lock);
|
spin_unlock_bh(&xprt->transport_lock);
|
||||||
dprintk("RPC: %s: reply %p completes request %p (xid 0x%08x)\n",
|
dprintk("RPC: %s: reply %p completes request %p (xid 0x%08x)\n",
|
||||||
__func__, rep, req, be32_to_cpu(headerp->rm_xid));
|
__func__, rep, req, be32_to_cpu(headerp->rm_xid));
|
||||||
|
|
||||||
/* from here on, the reply is no longer an orphan */
|
|
||||||
req->rl_reply = rep;
|
|
||||||
xprt->reestablish_timeout = 0;
|
xprt->reestablish_timeout = 0;
|
||||||
|
|
||||||
if (headerp->rm_vers != rpcrdma_version)
|
if (headerp->rm_vers != rpcrdma_version)
|
||||||
|
@ -1187,6 +1187,7 @@ rpcrdma_get_mw(struct rpcrdma_xprt *r_xprt)
|
|||||||
|
|
||||||
if (!mw)
|
if (!mw)
|
||||||
goto out_nomws;
|
goto out_nomws;
|
||||||
|
mw->mw_flags = 0;
|
||||||
return mw;
|
return mw;
|
||||||
|
|
||||||
out_nomws:
|
out_nomws:
|
||||||
|
@ -271,6 +271,7 @@ struct rpcrdma_mw {
|
|||||||
struct scatterlist *mw_sg;
|
struct scatterlist *mw_sg;
|
||||||
int mw_nents;
|
int mw_nents;
|
||||||
enum dma_data_direction mw_dir;
|
enum dma_data_direction mw_dir;
|
||||||
|
unsigned long mw_flags;
|
||||||
union {
|
union {
|
||||||
struct rpcrdma_fmr fmr;
|
struct rpcrdma_fmr fmr;
|
||||||
struct rpcrdma_frmr frmr;
|
struct rpcrdma_frmr frmr;
|
||||||
@ -282,6 +283,11 @@ struct rpcrdma_mw {
|
|||||||
struct list_head mw_all;
|
struct list_head mw_all;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* mw_flags */
|
||||||
|
enum {
|
||||||
|
RPCRDMA_MW_F_RI = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct rpcrdma_req -- structure central to the request/reply sequence.
|
* struct rpcrdma_req -- structure central to the request/reply sequence.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user