From 5d074ded6714fe44edd10b5f20cc43d74612579f Mon Sep 17 00:00:00 2001 From: Wang Zhan Date: Thu, 3 Sep 2026 21:33:14 +0800 Subject: [PATCH] net: sysfs: use ops lock for speed and duplex Reading /sys/class/net//{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 Link: https://patch.msgid.link/20260903133314.3703381-3-wang.zhan@smartx.com Signed-off-by: Paolo Abeni --- net/core/net-sysfs.c | 27 +++++++++++++++++++++------ 1 file 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; }