summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWang Zhan <wang.zhan@smartx.com>2026-09-03 21:33:14 +0800
committerPaolo Abeni <pabeni@redhat.com>2026-09-08 15:33:45 +0200
commit5d074ded6714fe44edd10b5f20cc43d74612579f (patch)
tree81ba059b6f7301f8dce628ab2bad0a42b58448a9
parentfc73b71c1bdbf293d3fca7158424d6117466d4f8 (diff)
downloadlinux-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.c27
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;
}