When the PCIe topology cannot route a P2P transfer between two devices, the DMA layer fails the mapping with -EREMOTEIO, but ib_dma_map_sg() returns 0 and the error is lost. nvme-rdma then fails the I/O with a retryable status, so multipath requeues it forever and a single path wastes its whole retry budget on an I/O that can never succeed. Map the data and metadata scatterlists with ib_dma_map_sgtable_attrs(), which preserves the error, and translate -EREMOTEIO to the new BLK_STS_P2PDMA status so the request fails fast instead of being retried. While at it, call nvme_start_request() only after mapping succeeds and ratelimit the map-failure message. Fixes: 23528aa3320a ("nvme: enable PCI P2PDMA support for RDMA transport") Cc: stable@vger.kernel.org # v7.1 Assisted-by: Claude:claude-fable-5 Signed-off-by: Mykola Marzhan --- drivers/nvme/host/rdma.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 6909e3542794..2f50509a7a61 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1469,6 +1469,7 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq, int *count, int *pi_count) { struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq); + struct sg_table sgt; int ret; req->data_sgl.sg_table.sgl = (struct scatterlist *)(req + 1); @@ -1480,12 +1481,14 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq, req->data_sgl.nents = blk_rq_map_sg(rq, req->data_sgl.sg_table.sgl); - *count = ib_dma_map_sg(ibdev, req->data_sgl.sg_table.sgl, - req->data_sgl.nents, rq_dma_dir(rq)); - if (unlikely(*count <= 0)) { - ret = -EIO; + sgt = (struct sg_table) { + .sgl = req->data_sgl.sg_table.sgl, + .orig_nents = req->data_sgl.nents, + }; + ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0); + if (unlikely(ret)) goto out_free_table; - } + *count = sgt.nents; if (blk_integrity_rq(rq)) { req->metadata_sgl->sg_table.sgl = @@ -1501,14 +1504,14 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq, req->metadata_sgl->nents = blk_rq_map_integrity_sg(rq, req->metadata_sgl->sg_table.sgl); - *pi_count = ib_dma_map_sg(ibdev, - req->metadata_sgl->sg_table.sgl, - req->metadata_sgl->nents, - rq_dma_dir(rq)); - if (unlikely(*pi_count <= 0)) { - ret = -EIO; + sgt = (struct sg_table) { + .sgl = req->metadata_sgl->sg_table.sgl, + .orig_nents = req->metadata_sgl->nents, + }; + ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0); + if (unlikely(ret)) goto out_free_pi_table; - } + *pi_count = sgt.nents; } return 0; @@ -2026,8 +2029,6 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, if (ret) goto unmap_qe; - nvme_start_request(rq); - if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) && queue->pi_support && (c->common.opcode == nvme_cmd_write || @@ -2039,11 +2040,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, err = nvme_rdma_map_data(queue, rq, c); if (unlikely(err < 0)) { - dev_err(queue->ctrl->ctrl.device, - "Failed to map data (%d)\n", err); + dev_err_ratelimited(queue->ctrl->ctrl.device, + "Failed to map data (%d)\n", err); goto err; } + nvme_start_request(rq); + sqe->cqe.done = nvme_rdma_send_done; ib_dma_sync_single_for_device(dev, sqe->dma, @@ -2063,6 +2066,9 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, ret = nvme_host_path_error(rq); else if (err == -ENOMEM || err == -EAGAIN) ret = BLK_STS_RESOURCE; + /* Peer memory unreachable from this device: don't retry. */ + else if (err == -EREMOTEIO) + ret = BLK_STS_P2PDMA; else ret = BLK_STS_IOERR; nvme_cleanup_cmd(rq); -- 2.52.0