nvme-pci: fix freeing of the HMB descriptor table
[ Upstream commit3c2fb1ca80] The HMB descriptor table is sized to the maximum number of descriptors that could be used for a given device, but __nvme_alloc_host_mem could break out of the loop earlier on memory allocation failure and end up using less descriptors than planned for, which leads to an incorrect size passed to dma_free_coherent. In practice this was not showing up because the number of descriptors tends to be low and the dma coherent allocator always allocates and frees at least a page. Fixes:87ad72a59a("nvme-pci: implement host memory buffer support") Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Keith Busch <kbusch@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
d3df9f26cf
commit
452f9ddd12
@@ -147,6 +147,7 @@ struct nvme_dev {
|
||||
/* host memory buffer support: */
|
||||
u64 host_mem_size;
|
||||
u32 nr_host_mem_descs;
|
||||
u32 host_mem_descs_size;
|
||||
dma_addr_t host_mem_descs_dma;
|
||||
struct nvme_host_mem_buf_desc *host_mem_descs;
|
||||
void **host_mem_desc_bufs;
|
||||
@@ -1925,10 +1926,10 @@ static void nvme_free_host_mem(struct nvme_dev *dev)
|
||||
|
||||
kfree(dev->host_mem_desc_bufs);
|
||||
dev->host_mem_desc_bufs = NULL;
|
||||
dma_free_coherent(dev->dev,
|
||||
dev->nr_host_mem_descs * sizeof(*dev->host_mem_descs),
|
||||
dma_free_coherent(dev->dev, dev->host_mem_descs_size,
|
||||
dev->host_mem_descs, dev->host_mem_descs_dma);
|
||||
dev->host_mem_descs = NULL;
|
||||
dev->host_mem_descs_size = 0;
|
||||
dev->nr_host_mem_descs = 0;
|
||||
}
|
||||
|
||||
@@ -1936,7 +1937,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
|
||||
u32 chunk_size)
|
||||
{
|
||||
struct nvme_host_mem_buf_desc *descs;
|
||||
u32 max_entries, len;
|
||||
u32 max_entries, len, descs_size;
|
||||
dma_addr_t descs_dma;
|
||||
int i = 0;
|
||||
void **bufs;
|
||||
@@ -1949,8 +1950,9 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
|
||||
if (dev->ctrl.hmmaxd && dev->ctrl.hmmaxd < max_entries)
|
||||
max_entries = dev->ctrl.hmmaxd;
|
||||
|
||||
descs = dma_alloc_coherent(dev->dev, max_entries * sizeof(*descs),
|
||||
&descs_dma, GFP_KERNEL);
|
||||
descs_size = max_entries * sizeof(*descs);
|
||||
descs = dma_alloc_coherent(dev->dev, descs_size, &descs_dma,
|
||||
GFP_KERNEL);
|
||||
if (!descs)
|
||||
goto out;
|
||||
|
||||
@@ -1979,6 +1981,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
|
||||
dev->host_mem_size = size;
|
||||
dev->host_mem_descs = descs;
|
||||
dev->host_mem_descs_dma = descs_dma;
|
||||
dev->host_mem_descs_size = descs_size;
|
||||
dev->host_mem_desc_bufs = bufs;
|
||||
return 0;
|
||||
|
||||
@@ -1993,8 +1996,7 @@ out_free_bufs:
|
||||
|
||||
kfree(bufs);
|
||||
out_free_descs:
|
||||
dma_free_coherent(dev->dev, max_entries * sizeof(*descs), descs,
|
||||
descs_dma);
|
||||
dma_free_coherent(dev->dev, descs_size, descs, descs_dma);
|
||||
out:
|
||||
dev->host_mem_descs = NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
Reference in New Issue
Block a user