]> www.infradead.org Git - nvme.git/commitdiff
nvme: apple: fix device reference counting
authorKeith Busch <kbusch@kernel.org>
Tue, 4 Jun 2024 18:59:04 +0000 (11:59 -0700)
committerKeith Busch <kbusch@kernel.org>
Mon, 24 Jun 2024 19:53:41 +0000 (12:53 -0700)
Drivers must call nvme_uninit_ctrl after a successful nvme_init_ctrl.
Split the allocation side out to make the error handling boundary easier
to navigate. The apple driver had been doing this wrong, leaking the
controller device memory on a tagset failure.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/host/apple.c

index dd6ec0865141a9f8a3e6e90fdfb7888e7e56f810..c43ada920c3b279111e8c9183329843b39b8de0a 100644 (file)
@@ -1388,7 +1388,7 @@ static void devm_apple_nvme_mempool_destroy(void *data)
        mempool_destroy(data);
 }
 
-static int apple_nvme_probe(struct platform_device *pdev)
+static struct apple_nvme *apple_nvme_alloc(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct apple_nvme *anv;
@@ -1396,7 +1396,7 @@ static int apple_nvme_probe(struct platform_device *pdev)
 
        anv = devm_kzalloc(dev, sizeof(*anv), GFP_KERNEL);
        if (!anv)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        anv->dev = get_device(dev);
        anv->adminq.is_adminq = true;
@@ -1516,10 +1516,26 @@ static int apple_nvme_probe(struct platform_device *pdev)
                goto put_dev;
        }
 
+       return anv;
+put_dev:
+       put_device(anv->dev);
+       return ERR_PTR(ret);
+}
+
+static int apple_nvme_probe(struct platform_device *pdev)
+{
+       struct apple_nvme *anv;
+       int ret;
+
+       anv = apple_nvme_alloc(pdev);
+       if (IS_ERR(anv))
+               return PTR_ERR(anv);
+
        anv->ctrl.admin_q = blk_mq_alloc_queue(&anv->admin_tagset, NULL, NULL);
        if (IS_ERR(anv->ctrl.admin_q)) {
                ret = -ENOMEM;
-               goto put_dev;
+               anv->ctrl.admin_q = NULL;
+               goto out_uninit_ctrl;
        }
 
        nvme_reset_ctrl(&anv->ctrl);
@@ -1527,8 +1543,9 @@ static int apple_nvme_probe(struct platform_device *pdev)
 
        return 0;
 
-put_dev:
-       put_device(anv->dev);
+out_uninit_ctrl:
+       nvme_uninit_ctrl(&anv->ctrl);
+       nvme_put_ctrl(&anv->ctrl);
        return ret;
 }