* [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®