Skip to content

Commit e2f34e2

Browse files
chuckleveramschuma-ntap
authored andcommitted
xprtrdma: Yet another double DMA-unmap
While chasing yet another set of DMAR fault reports, I noticed that the frwr recycler conflates whether or not an MR has been DMA unmapped with frwr->fr_state. Actually the two have only an indirect relationship. It's in fact impossible to guess reliably whether the MR has been DMA unmapped based on its fr_state field, especially as the surrounding code and its assumptions have changed over time. A better approach is to track the DMA mapping status explicitly so that the recycler is less brittle to unexpected situations, and attempts to DMA-unmap a second time are prevented. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Cc: stable@vger.kernel.org # v4.20 Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
1 parent 594d164 commit e2f34e2

File tree

2 files changed

+10
-5
lines changed

2 files changed

+10
-5
lines changed

net/sunrpc/xprtrdma/frwr_ops.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@ static void
117117
frwr_mr_recycle_worker(struct work_struct *work)
118118
{
119119
struct rpcrdma_mr *mr = container_of(work, struct rpcrdma_mr, mr_recycle);
120-
enum rpcrdma_frwr_state state = mr->frwr.fr_state;
121120
struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
122121

123122
trace_xprtrdma_mr_recycle(mr);
124123

125-
if (state != FRWR_FLUSHED_LI) {
124+
if (mr->mr_dir != DMA_NONE) {
126125
trace_xprtrdma_mr_unmap(mr);
127126
ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
128127
mr->mr_sg, mr->mr_nents, mr->mr_dir);
128+
mr->mr_dir = DMA_NONE;
129129
}
130130

131131
spin_lock(&r_xprt->rx_buf.rb_mrlock);
@@ -150,6 +150,8 @@ frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
150150
if (!mr->mr_sg)
151151
goto out_list_err;
152152

153+
frwr->fr_state = FRWR_IS_INVALID;
154+
mr->mr_dir = DMA_NONE;
153155
INIT_LIST_HEAD(&mr->mr_list);
154156
INIT_WORK(&mr->mr_recycle, frwr_mr_recycle_worker);
155157
sg_init_table(mr->mr_sg, depth);

net/sunrpc/xprtrdma/verbs.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,9 +1329,12 @@ rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr)
13291329
{
13301330
struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
13311331

1332-
trace_xprtrdma_mr_unmap(mr);
1333-
ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
1334-
mr->mr_sg, mr->mr_nents, mr->mr_dir);
1332+
if (mr->mr_dir != DMA_NONE) {
1333+
trace_xprtrdma_mr_unmap(mr);
1334+
ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
1335+
mr->mr_sg, mr->mr_nents, mr->mr_dir);
1336+
mr->mr_dir = DMA_NONE;
1337+
}
13351338
__rpcrdma_mr_put(&r_xprt->rx_buf, mr);
13361339
}
13371340

0 commit comments

Comments
 (0)