Skip to content

Commit bcd9a07

Browse files
mgurtovoyChristoph Hellwig
authored andcommitted
nvmet: fix freeing unallocated p2pmem
In case p2p device was found but the p2p pool is empty, the nvme target is still trying to free the sgl from the p2p pool instead of the regular sgl pool and causing a crash (BUG() is called). Instead, assign the p2p_dev for the request only if it was allocated from p2p pool. This is the crash that was caused: [Sun May 30 19:13:53 2021] ------------[ cut here ]------------ [Sun May 30 19:13:53 2021] kernel BUG at lib/genalloc.c:518! [Sun May 30 19:13:53 2021] invalid opcode: 0000 [Rust-for-Linux#1] SMP PTI ... [Sun May 30 19:13:53 2021] kernel BUG at lib/genalloc.c:518! ... [Sun May 30 19:13:53 2021] RIP: 0010:gen_pool_free_owner+0xa8/0xb0 ... [Sun May 30 19:13:53 2021] Call Trace: [Sun May 30 19:13:53 2021] ------------[ cut here ]------------ [Sun May 30 19:13:53 2021] pci_free_p2pmem+0x2b/0x70 [Sun May 30 19:13:53 2021] pci_p2pmem_free_sgl+0x4f/0x80 [Sun May 30 19:13:53 2021] nvmet_req_free_sgls+0x1e/0x80 [nvmet] [Sun May 30 19:13:53 2021] kernel BUG at lib/genalloc.c:518! [Sun May 30 19:13:53 2021] nvmet_rdma_release_rsp+0x4e/0x1f0 [nvmet_rdma] [Sun May 30 19:13:53 2021] nvmet_rdma_send_done+0x1c/0x60 [nvmet_rdma] Fixes: c6e3f13 ("nvmet: add metadata support for block devices") Reviewed-by: Israel Rukshin <[email protected]> Signed-off-by: Max Gurtovoy <[email protected]> Reviewed-by: Logan Gunthorpe <[email protected]> Reviewed-by: Chaitanya Kulkarni <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 6622f9a commit bcd9a07

File tree

1 file changed

+16
-17
lines changed

1 file changed

+16
-17
lines changed

drivers/nvme/target/core.c

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,45 +1005,43 @@ static unsigned int nvmet_data_transfer_len(struct nvmet_req *req)
10051005
return req->transfer_len - req->metadata_len;
10061006
}
10071007

1008-
static int nvmet_req_alloc_p2pmem_sgls(struct nvmet_req *req)
1008+
static int nvmet_req_alloc_p2pmem_sgls(struct pci_dev *p2p_dev,
1009+
struct nvmet_req *req)
10091010
{
1010-
req->sg = pci_p2pmem_alloc_sgl(req->p2p_dev, &req->sg_cnt,
1011+
req->sg = pci_p2pmem_alloc_sgl(p2p_dev, &req->sg_cnt,
10111012
nvmet_data_transfer_len(req));
10121013
if (!req->sg)
10131014
goto out_err;
10141015

10151016
if (req->metadata_len) {
1016-
req->metadata_sg = pci_p2pmem_alloc_sgl(req->p2p_dev,
1017+
req->metadata_sg = pci_p2pmem_alloc_sgl(p2p_dev,
10171018
&req->metadata_sg_cnt, req->metadata_len);
10181019
if (!req->metadata_sg)
10191020
goto out_free_sg;
10201021
}
1022+
1023+
req->p2p_dev = p2p_dev;
1024+
10211025
return 0;
10221026
out_free_sg:
10231027
pci_p2pmem_free_sgl(req->p2p_dev, req->sg);
10241028
out_err:
10251029
return -ENOMEM;
10261030
}
10271031

1028-
static bool nvmet_req_find_p2p_dev(struct nvmet_req *req)
1032+
static struct pci_dev *nvmet_req_find_p2p_dev(struct nvmet_req *req)
10291033
{
1030-
if (!IS_ENABLED(CONFIG_PCI_P2PDMA))
1031-
return false;
1032-
1033-
if (req->sq->ctrl && req->sq->qid && req->ns) {
1034-
req->p2p_dev = radix_tree_lookup(&req->sq->ctrl->p2p_ns_map,
1035-
req->ns->nsid);
1036-
if (req->p2p_dev)
1037-
return true;
1038-
}
1039-
1040-
req->p2p_dev = NULL;
1041-
return false;
1034+
if (!IS_ENABLED(CONFIG_PCI_P2PDMA) ||
1035+
!req->sq->ctrl || !req->sq->qid || !req->ns)
1036+
return NULL;
1037+
return radix_tree_lookup(&req->sq->ctrl->p2p_ns_map, req->ns->nsid);
10421038
}
10431039

10441040
int nvmet_req_alloc_sgls(struct nvmet_req *req)
10451041
{
1046-
if (nvmet_req_find_p2p_dev(req) && !nvmet_req_alloc_p2pmem_sgls(req))
1042+
struct pci_dev *p2p_dev = nvmet_req_find_p2p_dev(req);
1043+
1044+
if (p2p_dev && !nvmet_req_alloc_p2pmem_sgls(p2p_dev, req))
10471045
return 0;
10481046

10491047
req->sg = sgl_alloc(nvmet_data_transfer_len(req), GFP_KERNEL,
@@ -1072,6 +1070,7 @@ void nvmet_req_free_sgls(struct nvmet_req *req)
10721070
pci_p2pmem_free_sgl(req->p2p_dev, req->sg);
10731071
if (req->metadata_sg)
10741072
pci_p2pmem_free_sgl(req->p2p_dev, req->metadata_sg);
1073+
req->p2p_dev = NULL;
10751074
} else {
10761075
sgl_free(req->sg);
10771076
if (req->metadata_sg)

0 commit comments

Comments
 (0)