diff options
author | Sagi Grimberg <sagi@grimberg.me> | 2017-11-23 10:35:22 -0500 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2017-11-26 09:33:32 -0500 |
commit | 4af7f7ff92a42b6c713293c99e7982bcfcf51a70 (patch) | |
tree | 49ab3f97188e32b101fd008db4205024ff8109fd | |
parent | b4b591c87f2b0f4ebaf3a68d4f13873b241aa584 (diff) |
nvme-rdma: don't complete requests before a send work request has completed
In order to guarantee that the HCA will never get an access violation
(either from invalidated rkey or from iommu) when retrying a send
operation we must complete a request only when both send completion and
the nvme cqe has arrived. We need to set the send/recv completions flags
atomically because we might have more than a single context accessing the
request concurrently (one is cq irq-poll context and the other is
user-polling used in IOCB_HIPRI).
Only then we are safe to invalidate the rkey (if needed), unmap the host
buffers, and complete the IO.
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Max Gurtovoy <maxg@mellanox.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | drivers/nvme/host/rdma.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 61511bed8aca..502f7c515a99 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c | |||
@@ -59,6 +59,9 @@ struct nvme_rdma_request { | |||
59 | struct nvme_request req; | 59 | struct nvme_request req; |
60 | struct ib_mr *mr; | 60 | struct ib_mr *mr; |
61 | struct nvme_rdma_qe sqe; | 61 | struct nvme_rdma_qe sqe; |
62 | union nvme_result result; | ||
63 | __le16 status; | ||
64 | refcount_t ref; | ||
62 | struct ib_sge sge[1 + NVME_RDMA_MAX_INLINE_SEGMENTS]; | 65 | struct ib_sge sge[1 + NVME_RDMA_MAX_INLINE_SEGMENTS]; |
63 | u32 num_sge; | 66 | u32 num_sge; |
64 | int nents; | 67 | int nents; |
@@ -1162,6 +1165,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, | |||
1162 | req->num_sge = 1; | 1165 | req->num_sge = 1; |
1163 | req->inline_data = false; | 1166 | req->inline_data = false; |
1164 | req->mr->need_inval = false; | 1167 | req->mr->need_inval = false; |
1168 | refcount_set(&req->ref, 2); /* send and recv completions */ | ||
1165 | 1169 | ||
1166 | c->common.flags |= NVME_CMD_SGL_METABUF; | 1170 | c->common.flags |= NVME_CMD_SGL_METABUF; |
1167 | 1171 | ||
@@ -1198,8 +1202,19 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, | |||
1198 | 1202 | ||
1199 | static void nvme_rdma_send_done(struct ib_cq *cq, struct ib_wc *wc) | 1203 | static void nvme_rdma_send_done(struct ib_cq *cq, struct ib_wc *wc) |
1200 | { | 1204 | { |
1201 | if (unlikely(wc->status != IB_WC_SUCCESS)) | 1205 | struct nvme_rdma_qe *qe = |
1206 | container_of(wc->wr_cqe, struct nvme_rdma_qe, cqe); | ||
1207 | struct nvme_rdma_request *req = | ||
1208 | container_of(qe, struct nvme_rdma_request, sqe); | ||
1209 | struct request *rq = blk_mq_rq_from_pdu(req); | ||
1210 | |||
1211 | if (unlikely(wc->status != IB_WC_SUCCESS)) { | ||
1202 | nvme_rdma_wr_error(cq, wc, "SEND"); | 1212 | nvme_rdma_wr_error(cq, wc, "SEND"); |
1213 | return; | ||
1214 | } | ||
1215 | |||
1216 | if (refcount_dec_and_test(&req->ref)) | ||
1217 | nvme_end_request(rq, req->status, req->result); | ||
1203 | } | 1218 | } |
1204 | 1219 | ||
1205 | static int nvme_rdma_post_send(struct nvme_rdma_queue *queue, | 1220 | static int nvme_rdma_post_send(struct nvme_rdma_queue *queue, |
@@ -1318,14 +1333,19 @@ static int nvme_rdma_process_nvme_rsp(struct nvme_rdma_queue *queue, | |||
1318 | } | 1333 | } |
1319 | req = blk_mq_rq_to_pdu(rq); | 1334 | req = blk_mq_rq_to_pdu(rq); |
1320 | 1335 | ||
1321 | if (rq->tag == tag) | 1336 | req->status = cqe->status; |
1322 | ret = 1; | 1337 | req->result = cqe->result; |
1323 | 1338 | ||
1324 | if ((wc->wc_flags & IB_WC_WITH_INVALIDATE) && | 1339 | if ((wc->wc_flags & IB_WC_WITH_INVALIDATE) && |
1325 | wc->ex.invalidate_rkey == req->mr->rkey) | 1340 | wc->ex.invalidate_rkey == req->mr->rkey) |
1326 | req->mr->need_inval = false; | 1341 | req->mr->need_inval = false; |
1327 | 1342 | ||
1328 | nvme_end_request(rq, cqe->status, cqe->result); | 1343 | if (refcount_dec_and_test(&req->ref)) { |
1344 | if (rq->tag == tag) | ||
1345 | ret = 1; | ||
1346 | nvme_end_request(rq, req->status, req->result); | ||
1347 | } | ||
1348 | |||
1329 | return ret; | 1349 | return ret; |
1330 | } | 1350 | } |
1331 | 1351 | ||