Re: [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers

[email protected] Thu, 23 Jul 2026 21:19:39 +0000
Newsgroups org.kernel.vger.linux-raid,org.kernel.vger.linux-pci
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Modifying the PI metadata buffer via nvme_start_request() after it has been mapped for DMA causes cache coherency issues on non-coherent architectures.

Pre-existing issues:
- [High] Accessing the block request and its associated PDU after being freed on the error handling path when mapping or post_send fails with -EIO.
- [High] Returning BLK_STS_RESOURCE after the request has been started triggers kernel warnings and false timeouts.
- [Medium] Returning a hard error from queue_rq after calling nvme_start_request() bypasses nvme_mpath_end_request(), leaking the nr_active counter.
--

--- Patch [10]: [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers ---
commit 2111f8ba9b5738dc4d1ef4e08339058c75231ebd
Author: Mykola Marzhan <[email protected]>

nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers

> A P2P transfer the PCIe topology cannot route fails DMA mapping
> with -EREMOTEIO.  nvme-rdma folds every mapping error into -EIO, a
> retryable host-path error: multipath requeues the I/O forever, a
> single path burns its whole retry budget.
> 
> Propagate the real error code and return the unroutable case as the
> non-retryable BLK_STS_P2PDMA.  As in nvme-pci, -ENOMEM now requeues
> (BLK_STS_RESOURCE) and -EINVAL fails (BLK_STS_IOERR); -EIO stays a
> retryable host-path error.  While at it, start the request only
> after mapping succeeds -- nvme-pci's order -- and ratelimit the
> map-failure message.

> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index 63830334c73e2..2f50509a7a616 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> [ ... ]
> @@ -2033,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 ||
> @@ -2046,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);

[Severity: High]
Since the patch moves nvme_start_request() to execute after
nvme_rdma_map_data() has mapped the metadata buffer for streaming DMA, can this
cause cache coherency issues on non-coherent architectures?

nvme_start_request() invokes blk_integrity_prepare(), which writes to the PI
tags directly in the CPU cache. 

Because this now happens after the memory is mapped, those modifications might
not be synced to main memory, causing the RDMA NIC to read stale PI tags and
leading to silent data corruption and I/O failures.

> +
>  	sqe->cqe.done = nvme_rdma_send_done;
>  
>  	ib_dma_sync_single_for_device(dev, sqe->dma,
> [ ... ]
> @@ -2070,6 +2066,9 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>  
>  err_unmap:
>  	nvme_rdma_unmap_data(queue, rq);
>  err:
>  	if (err == -EIO)
>  		ret = nvme_host_path_error(rq);

[Severity: High]
This is a pre-existing issue, but does this lead to a use-after-free when
nvme_rdma_map_data() or nvme_rdma_post_send() fails with -EIO?

nvme_host_path_error() synchronously completes the request via
blk_mq_set_request_complete() and __nvme_complete_rq(). This frees the request
and its PDU back to the tag allocator, where it can be immediately reallocated.

The code then falls through and accesses the freed request by calling
nvme_cleanup_cmd(rq) and reading req->sqe.dma during ib_dma_unmap_single().

>  	else if (err == -ENOMEM || err == -EAGAIN)
>  		ret = BLK_STS_RESOURCE;

[Severity: High]
This is a pre-existing issue, but does returning BLK_STS_RESOURCE here cause
false I/O timeouts?

At this point, nvme_start_request() has already been called, placing the
request in the MQ_RQ_IN_FLIGHT state and starting its timeout timer. 

When returning BLK_STS_RESOURCE, the block layer requeues the request without
reverting its state to MQ_RQ_IDLE. This leaves the timer ticking while the
request is on the dispatch queue, eventually triggering a false timeout and
controller reset.

> +	/* 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);

[Severity: Medium]
This is a pre-existing issue, but does returning a hard error here leak the
multipath nr_active counter?

When a hard error is returned to the block layer from nvme_rdma_queue_rq(),
it directly completes the request via blk_mq_end_request(), bypassing the
driver's .complete callback. 

Since nvme_start_request() was already called and incremented the multipath
nr_active counter, bypassing the completion callback means
nvme_mpath_end_request() is never invoked to balance the counter.

>  unmap_qe:
>  	ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
>  			    DMA_TO_DEVICE);
>  	return ret;
>  }

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=10