Commit 1bf86336 authored by Keith Busch's avatar Keith Busch
Browse files

nvme-pci: fix dma mapping leak on data setup error



We're leaking the initial DMA mapping during iteration if we fail to
allocate the tracking descriptor for both PRP and SGL. Unmap the
iterator directly; we can't use the existing unmap helper because it
depends on the tracking descriptor being successfully allocated, so a
new one for an in-use iterator is provided.

The mappings were also leaking when the driver detects an invalid
bio_vec when mapping PRPs, so fix that too.

Fixes: b8b7570a ("nvme-pci: fix dma unmapping when using PRPs and not using the IOVA mapping")
Fixes: 7ce3c1dd ("nvme-pci: convert the data mapping to blk_rq_dma_map")
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
parent 85686c72
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -997,6 +997,23 @@ static bool nvme_pci_prp_iter_next(struct request *req, struct device *dma_dev,
	return nvme_pci_prp_save_mapping(req, dma_dev, iter);
}

static void nvme_unmap_iter(struct request *req, struct blk_dma_iter *iter,
			    struct dma_iova_state *state)
{
	struct nvme_queue *nvmeq = req->mq_hctx->driver_data;
	struct device *dev = nvmeq->dev->dev;

	if (!blk_rq_dma_unmap(req, dev, state, iter->len, iter->p2pdma.map)) {
		unsigned int attrs = 0;

		if (iter->p2pdma.map == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE)
			attrs |= DMA_ATTR_MMIO;

		dma_unmap_phys(dev, iter->addr, iter->len, rq_dma_dir(req),
			       attrs);
	}
}

static blk_status_t nvme_pci_setup_data_prp(struct request *req,
		struct blk_dma_iter *iter)
{
@@ -1007,8 +1024,10 @@ static blk_status_t nvme_pci_setup_data_prp(struct request *req,
	unsigned int prp_len, i;
	__le64 *prp_list;

	if (!nvme_pci_prp_save_mapping(req, nvmeq->dev->dev, iter))
	if (!nvme_pci_prp_save_mapping(req, nvmeq->dev->dev, iter)) {
		nvme_unmap_iter(req, iter, &iod->dma_state);
		return iter->status;
	}

	/*
	 * PRP1 always points to the start of the DMA transfers.
@@ -1113,6 +1132,7 @@ static blk_status_t nvme_pci_setup_data_prp(struct request *req,
	dev_err_once(nvmeq->dev->dev,
		"Incorrectly formed request for payload:%d nents:%d\n",
		blk_rq_payload_bytes(req), blk_rq_nr_phys_segments(req));
	nvme_unmap_data(req);
	return BLK_STS_IOERR;
}

@@ -1156,8 +1176,11 @@ static blk_status_t nvme_pci_setup_data_sgl(struct request *req,

	sg_list = dma_pool_alloc(nvme_dma_pool(nvmeq, iod), GFP_ATOMIC,
			&sgl_dma);
	if (!sg_list)
	if (!sg_list) {
		nvme_unmap_iter(req, iter, &iod->dma_state);
		return BLK_STS_RESOURCE;
	}

	iod->descriptors[iod->nr_descriptors++] = sg_list;

	do {
@@ -1314,8 +1337,10 @@ static blk_status_t nvme_pci_setup_meta_iter(struct request *req)

	sg_list = dma_pool_alloc(nvmeq->descriptor_pools.small, GFP_ATOMIC,
			&sgl_dma);
	if (!sg_list)
	if (!sg_list) {
		nvme_unmap_iter(req, &iter, &iod->meta_dma_state);
		return BLK_STS_RESOURCE;
	}

	iod->meta_descriptor = sg_list;
	iod->meta_dma = sgl_dma;