From a44f67027ef85a3ed05b3c61095692be3ef817ca Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Tue, 28 May 2024 11:37:53 +0200 Subject: [PATCH] nvme: fix memory leak when nvme_init_ctrl() fails Signed-off-by: Maurizio Lombardi --- drivers/nvme/host/core.c | 15 ++++++--------- drivers/nvme/host/fc.c | 9 ++++++++- drivers/nvme/host/pci.c | 9 ++++++++- drivers/nvme/host/rdma.c | 6 +++++- drivers/nvme/host/tcp.c | 6 +++++- drivers/nvme/target/loop.c | 3 +++ 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 954f850f113a..85c2f1cb9466 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -4638,8 +4638,10 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, } ret = ida_alloc(&nvme_instance_ida, GFP_KERNEL); - if (ret < 0) + if (ret < 0) { + __free_page(ctrl->discard_page); goto out; + } ctrl->instance = ret; device_initialize(&ctrl->ctrl_device); @@ -4656,14 +4658,14 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, dev_set_drvdata(ctrl->device, ctrl); ret = dev_set_name(ctrl->device, "nvme%d", ctrl->instance); if (ret) - goto out_release_instance; + goto out; nvme_get_ctrl(ctrl); cdev_init(&ctrl->cdev, &nvme_dev_fops); ctrl->cdev.owner = ops->module; ret = cdev_device_add(&ctrl->cdev, ctrl->device); if (ret) - goto out_free_name; + goto out_put_ctrl; /* * Initialize latency tolerance controls. The sysfs files won't @@ -4684,14 +4686,9 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, nvme_fault_inject_fini(&ctrl->fault_inject); dev_pm_qos_hide_latency_tolerance(ctrl->device); cdev_device_del(&ctrl->cdev, ctrl->device); -out_free_name: +out_put_ctrl: nvme_put_ctrl(ctrl); - kfree_const(ctrl->device->kobj.name); -out_release_instance: - ida_free(&nvme_instance_ida, ctrl->instance); out: - if (ctrl->discard_page) - __free_page(ctrl->discard_page); return ret; } EXPORT_SYMBOL_GPL(nvme_init_ctrl); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index f0b081332749..e0e41042cabb 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3533,8 +3533,11 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, */ ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_fc_ctrl_ops, 0); - if (ret) + if (ret) { + if (ctrl->ctrl.device) + goto out_put_ctrl; goto out_free_queues; + } if (lport->dev) ctrl->ctrl.numa_node = dev_to_node(lport->dev); @@ -3598,6 +3601,10 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, return ERR_PTR(-EIO); +out_put_ctrl: + nvme_put_ctrl(&ctrl->ctrl); + return ERR_PTR(ret); + out_free_queues: kfree(ctrl->queues); out_free_ida: diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 710043086dff..6d349f2e6a41 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2972,8 +2972,11 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, } ret = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops, quirks); - if (ret) + if (ret) { + if (dev->ctrl.device) + goto out_put_ctrl; goto out_put_device; + } if (dev->ctrl.quirks & NVME_QUIRK_DMA_ADDRESS_BITS_48) dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); @@ -3003,6 +3006,10 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, out_free_dev: kfree(dev); return ERR_PTR(ret); + +out_put_ctrl: + nvme_put_ctrl(&dev->ctrl); + return ERR_PTR(ret); } static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 51a62b0c645a..56c2833c61b1 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -2301,8 +2301,11 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev, ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_rdma_ctrl_ops, 0 /* no quirks, we're perfect! */); - if (ret) + if (ret) { + if (ctrl->ctrl.device) + goto out_put_ctrl; goto out_kfree_queues; + } changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING); WARN_ON_ONCE(!changed); @@ -2322,6 +2325,7 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev, out_uninit_ctrl: nvme_uninit_ctrl(&ctrl->ctrl); +out_put_ctrl: nvme_put_ctrl(&ctrl->ctrl); if (ret > 0) ret = -EIO; diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 8b5e4327fe83..94ca0eea724b 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2758,8 +2758,11 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev, } ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_tcp_ctrl_ops, 0); - if (ret) + if (ret) { + if (ctrl->ctrl.device) + goto out_put_ctrl; goto out_kfree_queues; + } if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { WARN_ON_ONCE(1); @@ -2782,6 +2785,7 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev, out_uninit_ctrl: nvme_uninit_ctrl(&ctrl->ctrl); +out_put_ctrl: nvme_put_ctrl(&ctrl->ctrl); if (ret > 0) ret = -EIO; diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index e589915ddef8..6cd1a68555c3 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -551,6 +551,8 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev, ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_loop_ctrl_ops, 0 /* no quirks, we're perfect! */); if (ret) { + if (ctrl->ctrl.device) + goto out_put_ctrl; kfree(ctrl); goto out; } @@ -611,6 +613,7 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev, kfree(ctrl->queues); out_uninit_ctrl: nvme_uninit_ctrl(&ctrl->ctrl); +out_put_ctrl: nvme_put_ctrl(&ctrl->ctrl); out: if (ret > 0) -- 2.43.0