mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 00:34:20 +08:00
hwrng: geode - Fix PCI device refcount leak
[ Upstream commit9f6ec8dc57
] for_each_pci_dev() is implemented by pci_get_device(). The comment of pci_get_device() says that it will increase the reference count for the returned pci_dev and also decrease the reference count for the input pci_dev @from if it is not NULL. If we break for_each_pci_dev() loop with pdev not NULL, we need to call pci_dev_put() to decrease the reference count. We add a new struct 'amd_geode_priv' to record pointer of the pci_dev and membase, and then add missing pci_dev_put() for the normal and error path. Fixes:ef5d862734
("[PATCH] Add Geode HW RNG driver") Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
2b79a5e560
commit
82bd423ed9
@ -51,6 +51,10 @@ static const struct pci_device_id pci_tbl[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_tbl);
|
||||
|
||||
struct amd_geode_priv {
|
||||
struct pci_dev *pcidev;
|
||||
void __iomem *membase;
|
||||
};
|
||||
|
||||
static int geode_rng_data_read(struct hwrng *rng, u32 *data)
|
||||
{
|
||||
@ -90,6 +94,7 @@ static int __init geode_rng_init(void)
|
||||
const struct pci_device_id *ent;
|
||||
void __iomem *mem;
|
||||
unsigned long rng_base;
|
||||
struct amd_geode_priv *priv;
|
||||
|
||||
for_each_pci_dev(pdev) {
|
||||
ent = pci_match_id(pci_tbl, pdev);
|
||||
@ -97,17 +102,26 @@ static int __init geode_rng_init(void)
|
||||
goto found;
|
||||
}
|
||||
/* Device not found. */
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
found:
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
err = -ENOMEM;
|
||||
goto put_dev;
|
||||
}
|
||||
|
||||
rng_base = pci_resource_start(pdev, 0);
|
||||
if (rng_base == 0)
|
||||
goto out;
|
||||
goto free_priv;
|
||||
err = -ENOMEM;
|
||||
mem = ioremap(rng_base, 0x58);
|
||||
if (!mem)
|
||||
goto out;
|
||||
geode_rng.priv = (unsigned long)mem;
|
||||
goto free_priv;
|
||||
|
||||
geode_rng.priv = (unsigned long)priv;
|
||||
priv->membase = mem;
|
||||
priv->pcidev = pdev;
|
||||
|
||||
pr_info("AMD Geode RNG detected\n");
|
||||
err = hwrng_register(&geode_rng);
|
||||
@ -116,20 +130,26 @@ found:
|
||||
err);
|
||||
goto err_unmap;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
|
||||
err_unmap:
|
||||
iounmap(mem);
|
||||
goto out;
|
||||
free_priv:
|
||||
kfree(priv);
|
||||
put_dev:
|
||||
pci_dev_put(pdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit geode_rng_exit(void)
|
||||
{
|
||||
void __iomem *mem = (void __iomem *)geode_rng.priv;
|
||||
struct amd_geode_priv *priv;
|
||||
|
||||
priv = (struct amd_geode_priv *)geode_rng.priv;
|
||||
hwrng_unregister(&geode_rng);
|
||||
iounmap(mem);
|
||||
iounmap(priv->membase);
|
||||
pci_dev_put(priv->pcidev);
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
module_init(geode_rng_init);
|
||||
|
Loading…
Reference in New Issue
Block a user