mirror of https://github.com/torvalds/linux.git
net: dsa: remove redundant netdev_lock_ops() from conduit ethtool ops
DSA replaces the conduit (master) device's ethtool_ops with its own
wrappers that aggregate stats from both the conduit and DSA switch
ports. Taking the lock again inside the DSA wrappers causes a deadlock.
Stumbled upon this when booting qemu with fbnic and CONFIG_NET_DSA_LOOP=y
(which looks like some kind of testing device that auto-populates the ports
of eth0). `ethtool -i` is enough to deadlock. This means we have basically zero
coverage for DSA stuff with real ops locked devs.
Remove the redundant netdev_lock_ops()/netdev_unlock_ops() calls from
the DSA conduit ethtool wrappers.
Fixes: 2bcf4772e4 ("net: ethtool: try to protect all callback with netdev instance lock")
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20260414231035.1917035-1-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
105425b196
commit
0f99e0c3e1
|
|
@ -27,9 +27,7 @@ static int dsa_conduit_get_regs_len(struct net_device *dev)
|
|||
int len;
|
||||
|
||||
if (ops && ops->get_regs_len) {
|
||||
netdev_lock_ops(dev);
|
||||
len = ops->get_regs_len(dev);
|
||||
netdev_unlock_ops(dev);
|
||||
if (len < 0)
|
||||
return len;
|
||||
ret += len;
|
||||
|
|
@ -60,15 +58,11 @@ static void dsa_conduit_get_regs(struct net_device *dev,
|
|||
int len;
|
||||
|
||||
if (ops && ops->get_regs_len && ops->get_regs) {
|
||||
netdev_lock_ops(dev);
|
||||
len = ops->get_regs_len(dev);
|
||||
if (len < 0) {
|
||||
netdev_unlock_ops(dev);
|
||||
if (len < 0)
|
||||
return;
|
||||
}
|
||||
regs->len = len;
|
||||
ops->get_regs(dev, regs, data);
|
||||
netdev_unlock_ops(dev);
|
||||
data += regs->len;
|
||||
}
|
||||
|
||||
|
|
@ -115,10 +109,8 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev,
|
|||
int count, mcount = 0;
|
||||
|
||||
if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
|
||||
netdev_lock_ops(dev);
|
||||
mcount = ops->get_sset_count(dev, ETH_SS_STATS);
|
||||
ops->get_ethtool_stats(dev, stats, data);
|
||||
netdev_unlock_ops(dev);
|
||||
}
|
||||
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
|
|
@ -149,10 +141,8 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev,
|
|||
if (count >= 0)
|
||||
phy_ethtool_get_stats(dev->phydev, stats, data);
|
||||
} else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) {
|
||||
netdev_lock_ops(dev);
|
||||
count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
|
||||
ops->get_ethtool_phy_stats(dev, stats, data);
|
||||
netdev_unlock_ops(dev);
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
|
|
@ -176,13 +166,11 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset)
|
|||
struct dsa_switch_tree *dst = cpu_dp->dst;
|
||||
int count = 0;
|
||||
|
||||
netdev_lock_ops(dev);
|
||||
if (sset == ETH_SS_PHY_STATS && dev->phydev &&
|
||||
(!ops || !ops->get_ethtool_phy_stats))
|
||||
count = phy_ethtool_get_sset_count(dev->phydev);
|
||||
else if (ops && ops->get_sset_count)
|
||||
count = ops->get_sset_count(dev, sset);
|
||||
netdev_unlock_ops(dev);
|
||||
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
|
|
@ -239,7 +227,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
|
|||
struct dsa_switch_tree *dst = cpu_dp->dst;
|
||||
int count, mcount = 0;
|
||||
|
||||
netdev_lock_ops(dev);
|
||||
if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
|
||||
!ops->get_ethtool_phy_stats) {
|
||||
mcount = phy_ethtool_get_sset_count(dev->phydev);
|
||||
|
|
@ -253,7 +240,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
|
|||
mcount = 0;
|
||||
ops->get_strings(dev, stringset, data);
|
||||
}
|
||||
netdev_unlock_ops(dev);
|
||||
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp))
|
||||
|
|
|
|||
Loading…
Reference in New Issue