mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
nvme-pci: fix freeing of the HMB descriptor table
[ Upstream commit 3c2fb1ca8086eb139b2a551358137525ae8e0d7a ]
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
f892ddcf9f
commit
fb96d5cfa9
@@ -153,6 +153,7 @@ struct nvme_dev {
|
|||||||
/* host memory buffer support: */
|
/* host memory buffer support: */
|
||||||
u64 host_mem_size;
|
u64 host_mem_size;
|
||||||
u32 nr_host_mem_descs;
|
u32 nr_host_mem_descs;
|
||||||
|
u32 host_mem_descs_size;
|
||||||
dma_addr_t host_mem_descs_dma;
|
dma_addr_t host_mem_descs_dma;
|
||||||
struct nvme_host_mem_buf_desc *host_mem_descs;
|
struct nvme_host_mem_buf_desc *host_mem_descs;
|
||||||
void **host_mem_desc_bufs;
|
void **host_mem_desc_bufs;
|
||||||
@@ -2007,10 +2008,10 @@ static void nvme_free_host_mem(struct nvme_dev *dev)
|
|||||||
|
|
||||||
kfree(dev->host_mem_desc_bufs);
|
kfree(dev->host_mem_desc_bufs);
|
||||||
dev->host_mem_desc_bufs = NULL;
|
dev->host_mem_desc_bufs = NULL;
|
||||||
dma_free_coherent(dev->dev,
|
dma_free_coherent(dev->dev, dev->host_mem_descs_size,
|
||||||
dev->nr_host_mem_descs * sizeof(*dev->host_mem_descs),
|
|
||||||
dev->host_mem_descs, dev->host_mem_descs_dma);
|
dev->host_mem_descs, dev->host_mem_descs_dma);
|
||||||
dev->host_mem_descs = NULL;
|
dev->host_mem_descs = NULL;
|
||||||
|
dev->host_mem_descs_size = 0;
|
||||||
dev->nr_host_mem_descs = 0;
|
dev->nr_host_mem_descs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2018,7 +2019,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
|
|||||||
u32 chunk_size)
|
u32 chunk_size)
|
||||||
{
|
{
|
||||||
struct nvme_host_mem_buf_desc *descs;
|
struct nvme_host_mem_buf_desc *descs;
|
||||||
u32 max_entries, len;
|
u32 max_entries, len, descs_size;
|
||||||
dma_addr_t descs_dma;
|
dma_addr_t descs_dma;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
void **bufs;
|
void **bufs;
|
||||||
@@ -2031,8 +2032,9 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
|
|||||||
if (dev->ctrl.hmmaxd && dev->ctrl.hmmaxd < max_entries)
|
if (dev->ctrl.hmmaxd && dev->ctrl.hmmaxd < max_entries)
|
||||||
max_entries = dev->ctrl.hmmaxd;
|
max_entries = dev->ctrl.hmmaxd;
|
||||||
|
|
||||||
descs = dma_alloc_coherent(dev->dev, max_entries * sizeof(*descs),
|
descs_size = max_entries * sizeof(*descs);
|
||||||
&descs_dma, GFP_KERNEL);
|
descs = dma_alloc_coherent(dev->dev, descs_size, &descs_dma,
|
||||||
|
GFP_KERNEL);
|
||||||
if (!descs)
|
if (!descs)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -2061,6 +2063,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
|
|||||||
dev->host_mem_size = size;
|
dev->host_mem_size = size;
|
||||||
dev->host_mem_descs = descs;
|
dev->host_mem_descs = descs;
|
||||||
dev->host_mem_descs_dma = descs_dma;
|
dev->host_mem_descs_dma = descs_dma;
|
||||||
|
dev->host_mem_descs_size = descs_size;
|
||||||
dev->host_mem_desc_bufs = bufs;
|
dev->host_mem_desc_bufs = bufs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -2075,8 +2078,7 @@ out_free_bufs:
|
|||||||
|
|
||||||
kfree(bufs);
|
kfree(bufs);
|
||||||
out_free_descs:
|
out_free_descs:
|
||||||
dma_free_coherent(dev->dev, max_entries * sizeof(*descs), descs,
|
dma_free_coherent(dev->dev, descs_size, descs, descs_dma);
|
||||||
descs_dma);
|
|
||||||
out:
|
out:
|
||||||
dev->host_mem_descs = NULL;
|
dev->host_mem_descs = NULL;
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|||||||
Reference in New Issue
Block a user