[PATCH net-next v4 1/4] net: phy: cache MDIO bus owner before dropping PHY reference
From: James Hilliard
Date: Thu Aug 06 2026 - 23:56:44 EST
phy_attach_direct() and phy_detach() cache the MDIO bus pointer, drop their
PHY device reference, and then read bus->owner. If the put releases the PHY
during concurrent teardown, the cached pointer does not itself keep the
parent bus alive.
Cache the module pointer before dropping the PHY reference. The existing
module reference protects the cached pointer whenever the MDIO bus and
network device have different owners.
Fixes: ec988ad78ed6 ("phy: Don't increment MDIO bus refcount unless it's a different owner")
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/net/phy/phy_device.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 94b2e85e00a3..34d00f1ee483 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1752,7 +1752,7 @@ static bool phy_drv_supports_irq(const struct phy_driver *phydrv)
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
- struct mii_bus *bus = phydev->mdio.bus;
+ struct module *bus_owner = phydev->mdio.bus->owner;
struct device *d = &phydev->mdio.dev;
struct module *ndev_owner = NULL;
int err;
@@ -1764,7 +1764,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
*/
if (dev)
ndev_owner = dev->dev.parent->driver->owner;
- if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
+ if (ndev_owner != bus_owner && !try_module_get(bus_owner)) {
phydev_err(phydev, "failed to get the bus module\n");
return -EIO;
}
@@ -1900,8 +1900,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
d->driver = NULL;
error_put_device:
put_device(d);
- if (ndev_owner != bus->owner)
- module_put(bus->owner);
+ if (ndev_owner != bus_owner)
+ module_put(bus_owner);
return err;
}
EXPORT_SYMBOL(phy_attach_direct);
@@ -1917,7 +1917,7 @@ void phy_detach(struct phy_device *phydev)
{
struct net_device *dev = phydev->attached_dev;
struct module *ndev_owner = NULL;
- struct mii_bus *bus;
+ struct module *bus_owner;
if (phydev->devlink) {
device_link_del(phydev->devlink);
@@ -1972,17 +1972,14 @@ void phy_detach(struct phy_device *phydev)
/* Assert the reset signal */
phy_device_reset(phydev, 1);
- /*
- * The phydev might go away on the put_device() below, so avoid
- * a use-after-free bug by reading the underlying bus first.
- */
- bus = phydev->mdio.bus;
+ /* The PHY and its parent bus may be released by put_device() below. */
+ bus_owner = phydev->mdio.bus->owner;
put_device(&phydev->mdio.dev);
if (dev)
ndev_owner = dev->dev.parent->driver->owner;
- if (ndev_owner != bus->owner)
- module_put(bus->owner);
+ if (ndev_owner != bus_owner)
+ module_put(bus_owner);
}
EXPORT_SYMBOL(phy_detach);
--
2.53.0