Commit ec988ad7 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller

phy: Don't increment MDIO bus refcount unless it's a different owner

Commit 3e3aaf64 ("phy: fix mdiobus module safety") fixed the way we
dealt with MDIO bus module reference count, but sort of introduced a
regression in that, if an Ethernet driver registers its own MDIO bus
driver, as is common, we will end up with the Ethernet driver's
module->refnct set to 1, thus preventing this driver from any removal.

Fix this by comparing the network device's device driver owner against
the MDIO bus driver owner, and only if they are different, increment the
MDIO bus module refcount.

Fixes: 3e3aaf64 ("phy: fix mdiobus module safety")
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a50af86d
...@@ -857,11 +857,17 @@ EXPORT_SYMBOL(phy_attached_print); ...@@ -857,11 +857,17 @@ EXPORT_SYMBOL(phy_attached_print);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface) u32 flags, phy_interface_t interface)
{ {
struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus = phydev->mdio.bus; struct mii_bus *bus = phydev->mdio.bus;
struct device *d = &phydev->mdio.dev; struct device *d = &phydev->mdio.dev;
int err; int err;
if (!try_module_get(bus->owner)) { /* For Ethernet device drivers that register their own MDIO bus, we
* will have bus->owner match ndev_mod, so we do not want to increment
* our own module->refcnt here, otherwise we would not be able to
* unload later on.
*/
if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
dev_err(&dev->dev, "failed to get the bus module\n"); dev_err(&dev->dev, "failed to get the bus module\n");
return -EIO; return -EIO;
} }
...@@ -921,7 +927,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -921,7 +927,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
error: error:
put_device(d); put_device(d);
module_put(bus->owner); if (ndev_owner != bus->owner)
module_put(bus->owner);
return err; return err;
} }
EXPORT_SYMBOL(phy_attach_direct); EXPORT_SYMBOL(phy_attach_direct);
...@@ -971,6 +978,8 @@ EXPORT_SYMBOL(phy_attach); ...@@ -971,6 +978,8 @@ EXPORT_SYMBOL(phy_attach);
*/ */
void phy_detach(struct phy_device *phydev) void phy_detach(struct phy_device *phydev)
{ {
struct net_device *dev = phydev->attached_dev;
struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus; struct mii_bus *bus;
int i; int i;
...@@ -998,7 +1007,8 @@ void phy_detach(struct phy_device *phydev) ...@@ -998,7 +1007,8 @@ void phy_detach(struct phy_device *phydev)
bus = phydev->mdio.bus; bus = phydev->mdio.bus;
put_device(&phydev->mdio.dev); put_device(&phydev->mdio.dev);
module_put(bus->owner); if (ndev_owner != bus->owner)
module_put(bus->owner);
} }
EXPORT_SYMBOL(phy_detach); EXPORT_SYMBOL(phy_detach);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment