Skip to content

Commit

Permalink
nvme-pci: fix freeing of the HMB descriptor table
Browse files Browse the repository at this point in the history
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: 87ad72a ("nvme-pci: implement host memory buffer support")
Signed-off-by: Christoph Hellwig <[email protected]>
Signed-off-by: Keith Busch <[email protected]>
  • Loading branch information
Christoph Hellwig authored and keithbusch committed Nov 5, 2024
1 parent 5e52f71 commit 3c2fb1c
Showing 1 changed file with 9 additions and 7 deletions.
16 changes: 9 additions & 7 deletions drivers/nvme/host/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,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;
Expand Down Expand Up @@ -1966,18 +1967,18 @@ 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;
}

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;
Expand All @@ -1990,8 +1991,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;

Expand Down Expand Up @@ -2020,6 +2022,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;

Expand All @@ -2034,8 +2037,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,

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;
Expand Down

0 comments on commit 3c2fb1c

Please sign in to comment.