[PATCH] nvme-pci: always use blk_map_iter for metadata
Keith Busch
kbusch at meta.com
Mon Oct 20 11:24:44 PDT 2025
From: Keith Busch <kbusch at kernel.org>
The dma_map_bvec helper doesn't work for p2p data. Rather than special
case it, just use the same mapping logic so that the driver doesn't need
to consider memory types.
Reported-by: Leon Romanovsky <leon at kernel.org>
Signed-off-by: Keith Busch <kbusch at kernel.org>
---
drivers/nvme/host/pci.c | 89 ++++++++++++++---------------------------
1 file changed, 31 insertions(+), 58 deletions(-)
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index c916176bd9f05..3acb5843de450 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -259,9 +259,6 @@ enum nvme_iod_flags {
/* single segment dma mapping */
IOD_SINGLE_SEGMENT = 1U << 2,
-
- /* Metadata using non-coalesced MPTR */
- IOD_SINGLE_META_SEGMENT = 1U << 5,
};
struct nvme_dma_vec {
@@ -596,17 +593,6 @@ enum nvme_use_sgl {
SGL_FORCED,
};
-static inline bool nvme_pci_metadata_use_sgls(struct request *req)
-{
- struct nvme_queue *nvmeq = req->mq_hctx->driver_data;
- struct nvme_dev *dev = nvmeq->dev;
-
- if (!nvme_ctrl_meta_sgl_supported(&dev->ctrl))
- return false;
- return req->nr_integrity_segments > 1 ||
- nvme_req(req)->flags & NVME_REQ_USERCMD;
-}
-
static inline enum nvme_use_sgl nvme_pci_use_sgls(struct nvme_dev *dev,
struct request *req)
{
@@ -724,13 +710,6 @@ static void nvme_unmap_metadata(struct request *req)
struct device *dma_dev = nvmeq->dev->dev;
struct nvme_sgl_desc *sge = iod->meta_descriptor;
- if (iod->flags & IOD_SINGLE_META_SEGMENT) {
- dma_unmap_page(dma_dev, iod->meta_dma,
- rq_integrity_vec(req).bv_len,
- rq_dma_dir(req));
- return;
- }
-
if (!blk_rq_integrity_dma_unmap(req, dma_dev, &iod->meta_dma_state,
iod->meta_total_len)) {
if (nvme_pci_cmd_use_meta_sgl(&iod->cmd))
@@ -1042,21 +1021,27 @@ static blk_status_t nvme_map_data(struct request *req)
return nvme_pci_setup_data_prp(req, &iter);
}
-static blk_status_t nvme_pci_setup_meta_sgls(struct request *req)
+static blk_status_t nvme_pci_setup_meta_mptr(struct nvme_iod *iod,
+ struct blk_dma_iter *iter)
+{
+ iod->cmd.common.metadata = cpu_to_le64(iter->addr);
+ iod->meta_total_len = iter->len;
+ iod->meta_dma = iter->addr;
+ iod->meta_descriptor = NULL;
+ return BLK_STS_OK;
+}
+
+static blk_status_t nvme_pci_setup_meta_sgls(struct request *req,
+ struct blk_dma_iter *iter)
{
struct nvme_queue *nvmeq = req->mq_hctx->driver_data;
unsigned int entries = req->nr_integrity_segments;
struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
struct nvme_dev *dev = nvmeq->dev;
struct nvme_sgl_desc *sg_list;
- struct blk_dma_iter iter;
dma_addr_t sgl_dma;
int i = 0;
- if (!blk_rq_integrity_dma_map_iter_start(req, dev->dev,
- &iod->meta_dma_state, &iter))
- return iter.status;
-
if (blk_rq_dma_map_coalesce(&iod->meta_dma_state))
entries = 1;
@@ -1073,13 +1058,8 @@ static blk_status_t nvme_pci_setup_meta_sgls(struct request *req)
* mechanism to catch any misunderstandings between the application and
* device.
*/
- if (entries == 1 && !(nvme_req(req)->flags & NVME_REQ_USERCMD)) {
- iod->cmd.common.metadata = cpu_to_le64(iter.addr);
- iod->meta_total_len = iter.len;
- iod->meta_dma = iter.addr;
- iod->meta_descriptor = NULL;
- return BLK_STS_OK;
- }
+ if (entries == 1 && !(nvme_req(req)->flags & NVME_REQ_USERCMD))
+ return nvme_pci_setup_meta_mptr(iod, iter);
sg_list = dma_pool_alloc(nvmeq->descriptor_pools.small, GFP_ATOMIC,
&sgl_dma);
@@ -1091,45 +1071,38 @@ static blk_status_t nvme_pci_setup_meta_sgls(struct request *req)
iod->cmd.common.flags = NVME_CMD_SGL_METASEG;
iod->cmd.common.metadata = cpu_to_le64(sgl_dma);
if (entries == 1) {
- iod->meta_total_len = iter.len;
- nvme_pci_sgl_set_data(sg_list, &iter);
+ iod->meta_total_len = iter->len;
+ nvme_pci_sgl_set_data(sg_list, iter);
return BLK_STS_OK;
}
sgl_dma += sizeof(*sg_list);
do {
- nvme_pci_sgl_set_data(&sg_list[++i], &iter);
- iod->meta_total_len += iter.len;
- } while (blk_rq_integrity_dma_map_iter_next(req, dev->dev, &iter));
+ nvme_pci_sgl_set_data(&sg_list[++i], iter);
+ iod->meta_total_len += iter->len;
+ } while (blk_rq_integrity_dma_map_iter_next(req, dev->dev, iter));
nvme_pci_sgl_set_seg(sg_list, sgl_dma, i);
- if (unlikely(iter.status))
+ if (unlikely(iter->status))
nvme_unmap_metadata(req);
- return iter.status;
+ return iter->status;
}
-static blk_status_t nvme_pci_setup_meta_mptr(struct request *req)
+static blk_status_t nvme_map_metadata(struct request *req)
{
- struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
struct nvme_queue *nvmeq = req->mq_hctx->driver_data;
- struct bio_vec bv = rq_integrity_vec(req);
+ struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+ struct nvme_dev *dev = nvmeq->dev;
+ struct blk_dma_iter iter;
- iod->meta_dma = dma_map_bvec(nvmeq->dev->dev, &bv, rq_dma_dir(req), 0);
- if (dma_mapping_error(nvmeq->dev->dev, iod->meta_dma))
- return BLK_STS_IOERR;
- iod->cmd.common.metadata = cpu_to_le64(iod->meta_dma);
- iod->flags |= IOD_SINGLE_META_SEGMENT;
- return BLK_STS_OK;
-}
+ if (blk_rq_integrity_dma_map_iter_start(req, dev->dev,
+ &iod->meta_dma_state, &iter))
+ return iter.status;
-static blk_status_t nvme_map_metadata(struct request *req)
-{
- struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+ if (!nvme_ctrl_meta_sgl_supported(&dev->ctrl))
+ return nvme_pci_setup_meta_mptr(iod, &iter);
- if ((iod->cmd.common.flags & NVME_CMD_SGL_METABUF) &&
- nvme_pci_metadata_use_sgls(req))
- return nvme_pci_setup_meta_sgls(req);
- return nvme_pci_setup_meta_mptr(req);
+ return nvme_pci_setup_meta_sgls(req, &iter);
}
static blk_status_t nvme_prep_rq(struct request *req)
--
2.47.3
More information about the Linux-nvme
mailing list