diff options
| author | Wang Zhan <wang.zhan@smartx.com> | 2026-09-03 21:33:14 +0800 |
|---|---|---|
| committer | Paolo Abeni <pabeni@redhat.com> | 2026-09-08 15:33:45 +0200 |
| commit | 5d074ded6714fe44edd10b5f20cc43d74612579f (patch) | |
| tree | 81ba059b6f7301f8dce628ab2bad0a42b58448a9 | |
| parent | fc73b71c1bdbf293d3fca7158424d6117466d4f8 (diff) | |
| download | linux-next-5d074ded6714fe44edd10b5f20cc43d74612579f.tar.gz linux-next-5d074ded6714fe44edd10b5f20cc43d74612579f.zip | |
net: sysfs: use ops lock for speed and duplex
Reading /sys/class/net/<dev>/{speed,duplex} takes rtnl_lock() even for
ops-locked devices whose get_link_ksettings callback does not require it.
This unnecessarily serializes monitoring reads with unrelated rtnetlink
operations.
On CPU-throttled hosts, a periodic reader such as node-exporter can hold
RTNL for hundreds of milliseconds while an mlx5 callback runs, delaying
unrelated rtnetlink operations.
Use the netdev instance lock for these devices. Retain sysfs_rtnl_lock()
for legacy devices and callbacks that request
ETHTOOL_OP_NEEDS_RTNL_LINKSETTINGS.
Preserve the existing speed and duplex sysfs ABI, including -EINVAL for
devices that are down or callbacks that fail.
Assisted-by: LLM
Signed-off-by: Wang Zhan <wang.zhan@smartx.com>
Link: https://patch.msgid.link/20260903133314.3703381-3-wang.zhan@smartx.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
| -rw-r--r-- | net/core/net-sysfs.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7bb8bbc1f71e..fa790e442570 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -123,26 +123,41 @@ static int sysfs_get_link_ksettings(struct device *dev, struct ethtool_link_ksettings *cmd) { struct net_device *netdev = to_net_dev(dev); + bool need_rtnl; int ret; /* - * The check is also done in __ethtool_get_link_ksettings; this helps + * The check is also done in netif_get_link_ksettings; this helps * returning early without hitting the locking section below. */ if (!netdev->ethtool_ops->get_link_ksettings) return -EINVAL; - ret = sysfs_rtnl_lock(&dev->kobj, &attr->attr, netdev); - if (ret) - return ret; + need_rtnl = !netdev_need_ops_lock(netdev) || + (netdev->ethtool_ops->op_needs_rtnl & + ETHTOOL_OP_NEEDS_RTNL_LINKSETTINGS); + if (need_rtnl) { + ret = sysfs_rtnl_lock(&dev->kobj, &attr->attr, netdev); + if (ret) + return ret; + } + netdev_lock_ops(netdev); + + if (!dev_isalive(netdev)) { + ret = -ENODEV; + goto unlock; + } ret = -EINVAL; if (netif_running(netdev)) { - if (!__ethtool_get_link_ksettings(netdev, cmd)) + if (!netif_get_link_ksettings(netdev, cmd)) ret = 0; } - rtnl_unlock(); +unlock: + netdev_unlock_ops(netdev); + if (need_rtnl) + rtnl_unlock(); return ret; } |
