RE: [PATCH] EDAC/i3000: Fix mci_pdev reference leak in i3000_init_one()
From: Leo Zhuo
Date: Wed Sep 16 2026 - 11:27:48 EST
> From: Wentao Liang <vulab@xxxxxxxxxxx>
> Sent: Wednesday, September 16, 2026 5:14 PM
> To: akpm@xxxxxxxxxxxxxxxxxxxx
> Cc: bp@xxxxxxxxx; dougthompson@xxxxxxxxxxxx; juhlenko@xxxxxxxxxx; linux-
> edac@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; tony.luck@xxxxxxxxx; Wentao
> Liang <vulab@xxxxxxxxxxx>; stable@xxxxxxxxxxxxxxx
> Subject: [PATCH] EDAC/i3000: Fix mci_pdev reference leak in i3000_init_one()
>
>
> In i3000_init_one(), a reference to the PCI device is taken with
> pci_dev_get() and stored in the global mci_pdev even when
> i3000_probe1() fails. On that path i3000_registered keeps its initial value of 1, so
> i3000_exit() skips the pci_dev_put() and the reference is leaked.
>
> Only take the reference after i3000_probe1() succeeds.
>
> Fixes: 535c6a53035d ("drivers/edac: new inte 30x0 MC driver")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
> ---
> drivers/edac/i3000_edac.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index
> 9065bc4386ff..d4ee6e185c80 100644
> --- a/drivers/edac/i3000_edac.c
> +++ b/drivers/edac/i3000_edac.c
> @@ -461,10 +461,13 @@ static int i3000_init_one(struct pci_dev *pdev, const
> struct pci_device_id *ent)
> return -EIO;
>
> rc = i3000_probe1(pdev, ent->driver_data);
> + if (rc)
> + return rc;
> +
> if (!mci_pdev)
> mci_pdev = pci_dev_get(pdev);
>
> - return rc;
> + return 0;
For a successful normal probe() and exit() path,
the extra mci_pdev reference is not released because i3200_exit() skips pci_dev_put().
How about the following fix:
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index d600b6c05217..ddfbbbbf8147 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -439,10 +439,13 @@ static int i3200_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -EIO;
rc = i3200_probe1(pdev, ent->driver_data);
+ if (rc)
+ return rc;
+
if (!mci_pdev)
mci_pdev = pci_dev_get(pdev);
- return rc;
+ return 0;
}
static void i3200_remove_one(struct pci_dev *pdev)
@@ -529,10 +532,10 @@ static void __exit i3200_exit(void)
edac_dbg(3, "MC:\n");
pci_unregister_driver(&i3200_driver);
- if (!i3200_registered) {
+ if (!i3200_registered)
i3200_remove_one(mci_pdev);
- pci_dev_put(mci_pdev);
- }
+
+ pci_dev_put(mci_pdev);
}
module_init(i3200_init);
> }
>
> static void i3000_remove_one(struct pci_dev *pdev)
> --
> 2.34.1
>