Skip to content

Commit fa07321

Browse files
author
Christoph Hellwig
committed
nvme-pci: fix error unwind in nvme_map_data
Properly unwind step by step using refactored helpers from nvme_unmap_data to avoid a potential double dma_unmap on a mapping failure. Fixes: 7fe07d1 ("nvme-pci: merge nvme_free_iod into nvme_unmap_data") Reported-by: Marc Orr <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Keith Busch <[email protected]> Reviewed-by: Marc Orr <[email protected]>
1 parent 9275c20 commit fa07321

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

drivers/nvme/host/pci.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
683683
__le64 *old_prp_list = prp_list;
684684
prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
685685
if (!prp_list)
686-
return BLK_STS_RESOURCE;
686+
goto free_prps;
687687
list[iod->npages++] = prp_list;
688688
prp_list[0] = old_prp_list[i - 1];
689689
old_prp_list[i - 1] = cpu_to_le64(prp_dma);
@@ -703,14 +703,14 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
703703
dma_addr = sg_dma_address(sg);
704704
dma_len = sg_dma_len(sg);
705705
}
706-
707706
done:
708707
cmnd->dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
709708
cmnd->dptr.prp2 = cpu_to_le64(iod->first_dma);
710-
711709
return BLK_STS_OK;
712-
713-
bad_sgl:
710+
free_prps:
711+
nvme_free_prps(dev, req);
712+
return BLK_STS_RESOURCE;
713+
bad_sgl:
714714
WARN(DO_ONCE(nvme_print_sgl, iod->sg, iod->nents),
715715
"Invalid SGL for payload:%d nents:%d\n",
716716
blk_rq_payload_bytes(req), iod->nents);
@@ -782,7 +782,7 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
782782

783783
sg_list = dma_pool_alloc(pool, GFP_ATOMIC, &sgl_dma);
784784
if (!sg_list)
785-
return BLK_STS_RESOURCE;
785+
goto free_sgls;
786786

787787
i = 0;
788788
nvme_pci_iod_list(req)[iod->npages++] = sg_list;
@@ -795,6 +795,9 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
795795
} while (--entries > 0);
796796

797797
return BLK_STS_OK;
798+
free_sgls:
799+
nvme_free_sgls(dev, req);
800+
return BLK_STS_RESOURCE;
798801
}
799802

800803
static blk_status_t nvme_setup_prp_simple(struct nvme_dev *dev,
@@ -863,7 +866,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
863866
sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
864867
iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
865868
if (!iod->nents)
866-
goto out;
869+
goto out_free_sg;
867870

868871
if (is_pci_p2pdma_page(sg_page(iod->sg)))
869872
nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
@@ -872,16 +875,21 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
872875
nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
873876
rq_dma_dir(req), DMA_ATTR_NO_WARN);
874877
if (!nr_mapped)
875-
goto out;
878+
goto out_free_sg;
876879

877880
iod->use_sgl = nvme_pci_use_sgls(dev, req);
878881
if (iod->use_sgl)
879882
ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw, nr_mapped);
880883
else
881884
ret = nvme_pci_setup_prps(dev, req, &cmnd->rw);
882-
out:
883885
if (ret != BLK_STS_OK)
884-
nvme_unmap_data(dev, req);
886+
goto out_unmap_sg;
887+
return BLK_STS_OK;
888+
889+
out_unmap_sg:
890+
nvme_unmap_sg(dev, req);
891+
out_free_sg:
892+
mempool_free(iod->sg, dev->iod_mempool);
885893
return ret;
886894
}
887895

0 commit comments

Comments
 (0)