X Xia Yan #
Message details and related content
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);