Skip to content

Commit 9f6ec8d

Browse files
fenghusthuherbertx
authored andcommitted
hwrng: geode - Fix PCI device refcount leak
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: ef5d862 ("[PATCH] Add Geode HW RNG driver") Signed-off-by: Xiongfeng Wang <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent ecadb5b commit 9f6ec8d

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

drivers/char/hw_random/geode-rng.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ static const struct pci_device_id pci_tbl[] = {
5151
};
5252
MODULE_DEVICE_TABLE(pci, pci_tbl);
5353

54+
struct amd_geode_priv {
55+
struct pci_dev *pcidev;
56+
void __iomem *membase;
57+
};
5458

5559
static int geode_rng_data_read(struct hwrng *rng, u32 *data)
5660
{
@@ -90,24 +94,34 @@ static int __init geode_rng_init(void)
9094
const struct pci_device_id *ent;
9195
void __iomem *mem;
9296
unsigned long rng_base;
97+
struct amd_geode_priv *priv;
9398

9499
for_each_pci_dev(pdev) {
95100
ent = pci_match_id(pci_tbl, pdev);
96101
if (ent)
97102
goto found;
98103
}
99104
/* Device not found. */
100-
goto out;
105+
return err;
101106

102107
found:
108+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
109+
if (!priv) {
110+
err = -ENOMEM;
111+
goto put_dev;
112+
}
113+
103114
rng_base = pci_resource_start(pdev, 0);
104115
if (rng_base == 0)
105-
goto out;
116+
goto free_priv;
106117
err = -ENOMEM;
107118
mem = ioremap(rng_base, 0x58);
108119
if (!mem)
109-
goto out;
110-
geode_rng.priv = (unsigned long)mem;
120+
goto free_priv;
121+
122+
geode_rng.priv = (unsigned long)priv;
123+
priv->membase = mem;
124+
priv->pcidev = pdev;
111125

112126
pr_info("AMD Geode RNG detected\n");
113127
err = hwrng_register(&geode_rng);
@@ -116,20 +130,26 @@ static int __init geode_rng_init(void)
116130
err);
117131
goto err_unmap;
118132
}
119-
out:
120133
return err;
121134

122135
err_unmap:
123136
iounmap(mem);
124-
goto out;
137+
free_priv:
138+
kfree(priv);
139+
put_dev:
140+
pci_dev_put(pdev);
141+
return err;
125142
}
126143

127144
static void __exit geode_rng_exit(void)
128145
{
129-
void __iomem *mem = (void __iomem *)geode_rng.priv;
146+
struct amd_geode_priv *priv;
130147

148+
priv = (struct amd_geode_priv *)geode_rng.priv;
131149
hwrng_unregister(&geode_rng);
132-
iounmap(mem);
150+
iounmap(priv->membase);
151+
pci_dev_put(priv->pcidev);
152+
kfree(priv);
133153
}
134154

135155
module_init(geode_rng_init);

0 commit comments

Comments
 (0)