adin1110_probe_netdevs() probes each port with get_phy_device(), which
allocates a phy_device without registering it. The pointer's only use
is phydev_name() for the phy_connect() call, and phy_connect() attaches
the device the earlier bus scan registered, not the one allocated here.
port_priv->phydev is then overwritten with the phy_connect() result and
the allocated object is lost.
The devm cleanup action only disconnects the PHY that phy_connect()
attached, so nothing frees the lost object: one struct phy_device per
port leaks on every probe.
Keep the get_phy_device() result in a local variable and free it with
phy_device_free() after phy_connect() returns, success or not, as
mdiobus_scan() already does when phy_device_register() fails.
Found during a code review of the MDIO attach paths. get_phy_device()
only calls phy_device_create(), and phy_connect() can only return a
registered device.
Signed-off-by: Xia Yan <redacted>
---
drivers/net/ethernet/adi/adin1110.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c
index 53fac3d..fd769f1 100644
--- a/drivers/net/ethernet/adi/adin1110.c
+++ b/drivers/net/ethernet/adi/adin1110.c
@@ -1571,6 +1571,7 @@ static int adin1110_probe_netdevs(struct adin1110_priv *priv)
struct device *dev = &priv->spidev->dev;
struct adin1110_port_priv *port_priv;
struct net_device *netdev;
+ struct phy_device *phydev;
int ret;
int i;
@@ -1604,16 +1605,17 @@ static int adin1110_probe_netdevs(struct adin1110_priv *priv)
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->netns_immutable = true;
- port_priv->phydev = get_phy_device(priv->mii_bus, i + 1, false);
- if (IS_ERR(port_priv->phydev)) {
+ phydev = get_phy_device(priv->mii_bus, i + 1, false);
+ if (IS_ERR(phydev)) {
netdev_err(netdev, "Could not find PHY with device address: %d.\n", i);
- return PTR_ERR(port_priv->phydev);
+ return PTR_ERR(phydev);
}
port_priv->phydev = phy_connect(netdev,
- phydev_name(port_priv->phydev),
+ phydev_name(phydev),
adin1110_adjust_link,
PHY_INTERFACE_MODE_INTERNAL);
+ phy_device_free(phydev);
if (IS_ERR(port_priv->phydev)) {
netdev_err(netdev, "Could not connect PHY with device address: %d.\n", i);
return PTR_ERR(port_priv->phydev);