* [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices
@ 2024-10-15 6:01 Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-15 6:01 UTC (permalink / raw)
To: Igal Liberman
Cc: Aleksandr Mishin, Simon Horman, Madalin Bucur, Sean Anderson,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
netdev, linux-kernel, lvc-project
The series is intended to fix refcount handling for fman-related "struct
device" objects - the devices are not released upon driver removal or in
the error paths during probe. This leads to device reference leaks.
The device pointers are now saved to struct mac_device and properly handled
in the driver's probe and removal functions.
Originally reported by Simon Horman <horms@kernel.org>
(https://lore.kernel.org/all/20240702133651.GK598357@kernel.org/)
Compile tested only.
Aleksandr Mishin (2):
fsl/fman: Save device references taken in mac_probe()
fsl/fman: Fix refcount handling of fman-related devices
drivers/net/ethernet/freescale/fman/mac.c | 68 +++++++++++++++++------
drivers/net/ethernet/freescale/fman/mac.h | 6 +-
2 files changed, 56 insertions(+), 18 deletions(-)
--
2.30.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe()
2024-10-15 6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
@ 2024-10-15 6:01 ` Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-21 9:20 ` [PATCH net 0/2] " patchwork-bot+netdevbpf
2 siblings, 0 replies; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-15 6:01 UTC (permalink / raw)
To: Igal Liberman
Cc: Aleksandr Mishin, Simon Horman, Madalin Bucur, Sean Anderson,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
netdev, linux-kernel, lvc-project
In mac_probe() there are calls to of_find_device_by_node() which takes
references to of_dev->dev. These references are not saved and not released
later on error path in mac_probe() and in mac_remove().
Add new fields into mac_device structure to save references taken for
future use in mac_probe() and mac_remove().
This is a preparation for further reference leaks fix.
Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
---
drivers/net/ethernet/freescale/fman/mac.c | 6 ++++--
drivers/net/ethernet/freescale/fman/mac.h | 6 +++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 9767586b4eb3..9b863db0bf08 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -197,6 +197,7 @@ static int mac_probe(struct platform_device *_of_dev)
err = -EINVAL;
goto _return_of_node_put;
}
+ mac_dev->fman_dev = &of_dev->dev;
/* Get the FMan cell-index */
err = of_property_read_u32(dev_node, "cell-index", &val);
@@ -208,7 +209,7 @@ static int mac_probe(struct platform_device *_of_dev)
/* cell-index 0 => FMan id 1 */
fman_id = (u8)(val + 1);
- priv->fman = fman_bind(&of_dev->dev);
+ priv->fman = fman_bind(mac_dev->fman_dev);
if (!priv->fman) {
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
err = -ENODEV;
@@ -284,8 +285,9 @@ static int mac_probe(struct platform_device *_of_dev)
err = -EINVAL;
goto _return_of_node_put;
}
+ mac_dev->fman_port_devs[i] = &of_dev->dev;
- mac_dev->port[i] = fman_port_bind(&of_dev->dev);
+ mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
if (!mac_dev->port[i]) {
dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
dev_node);
diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h
index fe747915cc73..8b5b43d50f8e 100644
--- a/drivers/net/ethernet/freescale/fman/mac.h
+++ b/drivers/net/ethernet/freescale/fman/mac.h
@@ -19,12 +19,13 @@
struct fman_mac;
struct mac_priv_s;
+#define PORT_NUM 2
struct mac_device {
void __iomem *vaddr;
struct device *dev;
struct resource *res;
u8 addr[ETH_ALEN];
- struct fman_port *port[2];
+ struct fman_port *port[PORT_NUM];
struct phylink *phylink;
struct phylink_config phylink_config;
phy_interface_t phy_if;
@@ -52,6 +53,9 @@ struct mac_device {
struct fman_mac *fman_mac;
struct mac_priv_s *priv;
+
+ struct device *fman_dev;
+ struct device *fman_port_devs[PORT_NUM];
};
static inline struct mac_device
--
2.30.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices
2024-10-15 6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
@ 2024-10-15 6:01 ` Aleksandr Mishin
2024-10-17 10:01 ` Paolo Abeni
2024-10-21 9:20 ` [PATCH net 0/2] " patchwork-bot+netdevbpf
2 siblings, 1 reply; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-15 6:01 UTC (permalink / raw)
To: Igal Liberman
Cc: Aleksandr Mishin, Simon Horman, Madalin Bucur, Sean Anderson,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
netdev, linux-kernel, lvc-project
In mac_probe() there are multiple calls to of_find_device_by_node(),
fman_bind() and fman_port_bind() which takes references to of_dev->dev.
Not all references taken by these calls are released later on error path
in mac_probe() and in mac_remove() which lead to reference leaks.
Add references release.
Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
---
Compile tested only.
drivers/net/ethernet/freescale/fman/mac.c | 62 +++++++++++++++++------
1 file changed, 47 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 9b863db0bf08..11da139082e1 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -204,7 +204,7 @@ static int mac_probe(struct platform_device *_of_dev)
if (err) {
dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
err = -EINVAL;
- goto _return_of_node_put;
+ goto _return_dev_put;
}
/* cell-index 0 => FMan id 1 */
fman_id = (u8)(val + 1);
@@ -213,40 +213,51 @@ static int mac_probe(struct platform_device *_of_dev)
if (!priv->fman) {
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
err = -ENODEV;
- goto _return_of_node_put;
+ goto _return_dev_put;
}
+ /* Two references have been taken in of_find_device_by_node()
+ * and fman_bind(). Release one of them here. The second one
+ * will be released in mac_remove().
+ */
+ put_device(mac_dev->fman_dev);
of_node_put(dev_node);
+ dev_node = NULL;
/* Get the address of the memory mapped registers */
mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
if (!mac_dev->res) {
dev_err(dev, "could not get registers\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto _return_dev_put;
}
err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
mac_dev->res);
if (err) {
dev_err_probe(dev, err, "could not request resource\n");
- return err;
+ goto _return_dev_put;
}
mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
resource_size(mac_dev->res));
if (!mac_dev->vaddr) {
dev_err(dev, "devm_ioremap() failed\n");
- return -EIO;
+ err = -EIO;
+ goto _return_dev_put;
}
- if (!of_device_is_available(mac_node))
- return -ENODEV;
+ if (!of_device_is_available(mac_node)) {
+ err = -ENODEV;
+ goto _return_dev_put;
+ }
/* Get the cell-index */
err = of_property_read_u32(mac_node, "cell-index", &val);
if (err) {
dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
- return -EINVAL;
+ err = -EINVAL;
+ goto _return_dev_put;
}
priv->cell_index = (u8)val;
@@ -260,22 +271,26 @@ static int mac_probe(struct platform_device *_of_dev)
if (unlikely(nph < 0)) {
dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
mac_node);
- return nph;
+ err = nph;
+ goto _return_dev_put;
}
if (nph != ARRAY_SIZE(mac_dev->port)) {
dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
mac_node);
- return -EINVAL;
+ err = -EINVAL;
+ goto _return_dev_put;
}
- for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
+ /* PORT_NUM determines the size of the port array */
+ for (i = 0; i < PORT_NUM; i++) {
/* Find the port node */
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
if (!dev_node) {
dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
mac_node);
- return -EINVAL;
+ err = -EINVAL;
+ goto _return_dev_arr_put;
}
of_dev = of_find_device_by_node(dev_node);
@@ -283,7 +298,7 @@ static int mac_probe(struct platform_device *_of_dev)
dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
dev_node);
err = -EINVAL;
- goto _return_of_node_put;
+ goto _return_dev_arr_put;
}
mac_dev->fman_port_devs[i] = &of_dev->dev;
@@ -292,9 +307,15 @@ static int mac_probe(struct platform_device *_of_dev)
dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
dev_node);
err = -EINVAL;
- goto _return_of_node_put;
+ goto _return_dev_arr_put;
}
+ /* Two references have been taken in of_find_device_by_node()
+ * and fman_port_bind(). Release one of them here. The second
+ * one will be released in mac_remove().
+ */
+ put_device(mac_dev->fman_port_devs[i]);
of_node_put(dev_node);
+ dev_node = NULL;
}
/* Get the PHY connection type */
@@ -314,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
err = init(mac_dev, mac_node, ¶ms);
if (err < 0)
- return err;
+ goto _return_dev_arr_put;
if (!is_zero_ether_addr(mac_dev->addr))
dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
@@ -329,6 +350,12 @@ static int mac_probe(struct platform_device *_of_dev)
return err;
+_return_dev_arr_put:
+ /* mac_dev is kzalloc'ed */
+ for (i = 0; i < PORT_NUM; i++)
+ put_device(mac_dev->fman_port_devs[i]);
+_return_dev_put:
+ put_device(mac_dev->fman_dev);
_return_of_node_put:
of_node_put(dev_node);
return err;
@@ -337,6 +364,11 @@ static int mac_probe(struct platform_device *_of_dev)
static void mac_remove(struct platform_device *pdev)
{
struct mac_device *mac_dev = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < PORT_NUM; i++)
+ put_device(mac_dev->fman_port_devs[i]);
+ put_device(mac_dev->fman_dev);
platform_device_unregister(mac_dev->priv->eth_dev);
}
--
2.30.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices
2024-10-15 6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
@ 2024-10-17 10:01 ` Paolo Abeni
2024-10-17 10:53 ` Aleksandr Mishin
0 siblings, 1 reply; 6+ messages in thread
From: Paolo Abeni @ 2024-10-17 10:01 UTC (permalink / raw)
To: Aleksandr Mishin, Igal Liberman
Cc: Simon Horman, Madalin Bucur, Sean Anderson, David S. Miller,
Eric Dumazet, Jakub Kicinski, netdev, linux-kernel, lvc-project
On 10/15/24 08:01, Aleksandr Mishin wrote:
> In mac_probe() there are multiple calls to of_find_device_by_node(),
> fman_bind() and fman_port_bind() which takes references to of_dev->dev.
> Not all references taken by these calls are released later on error path
> in mac_probe() and in mac_remove() which lead to reference leaks.
>
> Add references release.
>
> Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
> Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
> ---
> Compile tested only.
>
> drivers/net/ethernet/freescale/fman/mac.c | 62 +++++++++++++++++------
> 1 file changed, 47 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
> index 9b863db0bf08..11da139082e1 100644
> --- a/drivers/net/ethernet/freescale/fman/mac.c
> +++ b/drivers/net/ethernet/freescale/fman/mac.c
> @@ -204,7 +204,7 @@ static int mac_probe(struct platform_device *_of_dev)
> if (err) {
> dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
> err = -EINVAL;
> - goto _return_of_node_put;
> + goto _return_dev_put;
We are after a succesful of_find_device_by_node and prior to
fman_bind(), mac_dev->fman_dev refcount is 1
> @@ -213,40 +213,51 @@ static int mac_probe(struct platform_device *_of_dev)
> if (!priv->fman) {
> dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
> err = -ENODEV;
> - goto _return_of_node_put;
> + goto _return_dev_put;
> }
>
> + /* Two references have been taken in of_find_device_by_node()
> + * and fman_bind(). Release one of them here. The second one
> + * will be released in mac_remove().
> + */
> + put_device(mac_dev->fman_dev);
> of_node_put(dev_node);
> + dev_node = NULL;
>
> /* Get the address of the memory mapped registers */
> mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
> if (!mac_dev->res) {
> dev_err(dev, "could not get registers\n");
> - return -EINVAL;
> + err = -EINVAL;
> + goto _return_dev_put;
Here we are after a successful fman_bind(), mac_dev->fman_dev refcount
is 2. _return_dev_put will drop a single reference, this error path
looks buggy.
Similar issue for the _return_dev_arr_put error path below.
Cheers,
Paolo
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices
2024-10-17 10:01 ` Paolo Abeni
@ 2024-10-17 10:53 ` Aleksandr Mishin
0 siblings, 0 replies; 6+ messages in thread
From: Aleksandr Mishin @ 2024-10-17 10:53 UTC (permalink / raw)
To: Paolo Abeni, Igal Liberman
Cc: Simon Horman, Madalin Bucur, Sean Anderson, David S. Miller,
Eric Dumazet, Jakub Kicinski, netdev, linux-kernel, lvc-project
On 17.10.2024 13:01, Paolo Abeni wrote:
> On 10/15/24 08:01, Aleksandr Mishin wrote:
>> In mac_probe() there are multiple calls to of_find_device_by_node(),
>> fman_bind() and fman_port_bind() which takes references to of_dev->dev.
>> Not all references taken by these calls are released later on error path
>> in mac_probe() and in mac_remove() which lead to reference leaks.
>>
>> Add references release.
>>
>> Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
>> Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
>> ---
>> Compile tested only.
>>
>> drivers/net/ethernet/freescale/fman/mac.c | 62 +++++++++++++++++------
>> 1 file changed, 47 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/freescale/fman/mac.c
>> b/drivers/net/ethernet/freescale/fman/mac.c
>> index 9b863db0bf08..11da139082e1 100644
>> --- a/drivers/net/ethernet/freescale/fman/mac.c
>> +++ b/drivers/net/ethernet/freescale/fman/mac.c
>> @@ -204,7 +204,7 @@ static int mac_probe(struct platform_device
>> *_of_dev)
>> if (err) {
>> dev_err(dev, "failed to read cell-index for %pOF\n",
>> dev_node);
>> err = -EINVAL;
>> - goto _return_of_node_put;
>> + goto _return_dev_put;
>
> We are after a succesful of_find_device_by_node and prior to
> fman_bind(), mac_dev->fman_dev refcount is 1
Indeed. refcounts = 1.
>
>> @@ -213,40 +213,51 @@ static int mac_probe(struct platform_device
>> *_of_dev)
>> if (!priv->fman) {
>> dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
>> err = -ENODEV;
>> - goto _return_of_node_put;
>> + goto _return_dev_put;
>> }
refcounts: 1 + 1 = 2.
>> + /* Two references have been taken in of_find_device_by_node()
>> + * and fman_bind(). Release one of them here. The second one
>> + * will be released in mac_remove().
>> + */
>> + put_device(mac_dev->fman_dev);
refcounts: 2 - 1 = 1.
>> of_node_put(dev_node);
>> + dev_node = NULL;
>> /* Get the address of the memory mapped registers */
>> mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
>> if (!mac_dev->res) {
>> dev_err(dev, "could not get registers\n");
>> - return -EINVAL;
>> + err = -EINVAL;
>> + goto _return_dev_put;
>
> Here we are after a successful fman_bind(), mac_dev->fman_dev refcount
> is 2. _return_dev_put will drop a single reference, this error path
> looks buggy.
We released 1 reference above with "put_device(mac_dev->fman_dev);".
>
> Similar issue for the _return_dev_arr_put error path below.
Similar situation: we release 1 reference with
"put_device(mac_dev->fman_port_devs[i]);".
>
> Cheers,
>
> Paolo
>
--
Kind regards
Aleksandr
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices
2024-10-15 6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
@ 2024-10-21 9:20 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+netdevbpf @ 2024-10-21 9:20 UTC (permalink / raw)
To: Aleksandr Mishin
Cc: igal.liberman, horms, madalin.bucur, sean.anderson, davem,
edumazet, kuba, pabeni, netdev, linux-kernel, lvc-project
Hello:
This series was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Tue, 15 Oct 2024 09:01:20 +0300 you wrote:
> The series is intended to fix refcount handling for fman-related "struct
> device" objects - the devices are not released upon driver removal or in
> the error paths during probe. This leads to device reference leaks.
>
> The device pointers are now saved to struct mac_device and properly handled
> in the driver's probe and removal functions.
>
> [...]
Here is the summary with links:
- [net,1/2] fsl/fman: Save device references taken in mac_probe()
https://git.kernel.org/netdev/net/c/efeddd552ec6
- [net,2/2] fsl/fman: Fix refcount handling of fman-related devices
https://git.kernel.org/netdev/net/c/1dec67e0d9fb
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-10-21 9:20 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-15 6:01 [PATCH net 0/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 1/2] fsl/fman: Save device references taken in mac_probe() Aleksandr Mishin
2024-10-15 6:01 ` [PATCH net 2/2] fsl/fman: Fix refcount handling of fman-related devices Aleksandr Mishin
2024-10-17 10:01 ` Paolo Abeni
2024-10-17 10:53 ` Aleksandr Mishin
2024-10-21 9:20 ` [PATCH net 0/2] " patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®