]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: ethtool: add netif_get_link_ksettings() for correct ops-locked use
authorJakub Kicinski <kuba@kernel.org>
Wed, 3 Jun 2026 01:28:33 +0000 (18:28 -0700)
committerJakub Kicinski <kuba@kernel.org>
Thu, 4 Jun 2026 21:04:55 +0000 (14:04 -0700)
__ethtool_get_link_ksettings() is exported and called from sysfs
and many drivers. It invokes ethtool_ops->get_link_ksettings
so by our own docs it should be holding netdev lock for ops locked
devices. Looks like commit 2bcf4772e45a ("net: ethtool:
try to protect all callback with netdev instance lock")
missed adding the ops lock here.

There's a number of callers we need to fix up so let's add the
netif_get_link_ksettings() helper first, without any actual
locking changes (this commit is a nop).

Not treating this as a fix because I don't think any driver cares
at this point, but if we want to remove the rtnl_lock protection
this will become critical.

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260603012840.2254293-5-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/ethtool.h
net/ethtool/ioctl.c
net/ethtool/linkinfo.c
net/ethtool/linkmodes.c

index 1cb0740ba3310bf8279c6d002f43288990d20d1e..f51346a6a6860130774b173224c491d2931c4abb 100644 (file)
@@ -325,6 +325,8 @@ struct ethtool_link_ksettings {
 extern int
 __ethtool_get_link_ksettings(struct net_device *dev,
                             struct ethtool_link_ksettings *link_ksettings);
+int netif_get_link_ksettings(struct net_device *dev,
+                            struct ethtool_link_ksettings *link_ksettings);
 
 struct ethtool_keee {
        __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
index bd97f9b9bf18259a2cbfda16b3d442dda38cb684..49da873b673ded64ae7d9e6ec840a1b250d2e68c 100644 (file)
@@ -436,10 +436,10 @@ struct ethtool_link_usettings {
 };
 
 /* Internal kernel helper to query a device ethtool_link_settings. */
-int __ethtool_get_link_ksettings(struct net_device *dev,
-                                struct ethtool_link_ksettings *link_ksettings)
+int netif_get_link_ksettings(struct net_device *dev,
+                            struct ethtool_link_ksettings *link_ksettings)
 {
-       ASSERT_RTNL();
+       /* once callers fixed - assert ops locked */
 
        if (!dev->ethtool_ops->get_link_ksettings)
                return -EOPNOTSUPP;
@@ -450,6 +450,17 @@ int __ethtool_get_link_ksettings(struct net_device *dev,
        memset(link_ksettings, 0, sizeof(*link_ksettings));
        return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings);
 }
+EXPORT_SYMBOL(netif_get_link_ksettings);
+
+/* Convenience helper for callers that hold only rtnl_lock(). */
+int __ethtool_get_link_ksettings(struct net_device *dev,
+                                struct ethtool_link_ksettings *link_ksettings)
+{
+       ASSERT_RTNL();
+
+       /* once callers fixed - take the ops lock around this call */
+       return netif_get_link_ksettings(dev, link_ksettings);
+}
 EXPORT_SYMBOL(__ethtool_get_link_ksettings);
 
 /* convert ethtool_link_usettings in user space to a kernel internal
index 244ff92e2ff90ba940cac00744b22ba3c84e0646..d5b3dbc53c5fc4b900cf005efd2932095d765653 100644 (file)
@@ -34,7 +34,7 @@ static int linkinfo_prepare_data(const struct ethnl_req_info *req_base,
        ret = ethnl_ops_begin(dev);
        if (ret < 0)
                return ret;
-       ret = __ethtool_get_link_ksettings(dev, &data->ksettings);
+       ret = netif_get_link_ksettings(dev, &data->ksettings);
        if (ret < 0)
                GENL_SET_ERR_MSG(info, "failed to retrieve link settings");
        ethnl_ops_complete(dev);
@@ -104,7 +104,7 @@ ethnl_set_linkinfo(struct ethnl_req_info *req_info, struct genl_info *info)
        bool mod = false;
        int ret;
 
-       ret = __ethtool_get_link_ksettings(dev, &ksettings);
+       ret = netif_get_link_ksettings(dev, &ksettings);
        if (ret < 0) {
                GENL_SET_ERR_MSG(info, "failed to retrieve link settings");
                return ret;
index 30d703531652ba18c13106d0eb35f6d428c92e36..a6d32f0d9fccd9a6ade722a1e3cd6bd36de26bca 100644 (file)
@@ -39,7 +39,7 @@ static int linkmodes_prepare_data(const struct ethnl_req_info *req_base,
        if (ret < 0)
                return ret;
 
-       ret = __ethtool_get_link_ksettings(dev, &data->ksettings);
+       ret = netif_get_link_ksettings(dev, &data->ksettings);
        if (ret < 0) {
                GENL_SET_ERR_MSG(info, "failed to retrieve link settings");
                goto out;
@@ -324,7 +324,7 @@ ethnl_set_linkmodes(struct ethnl_req_info *req_info, struct genl_info *info)
        bool mod = false;
        int ret;
 
-       ret = __ethtool_get_link_ksettings(dev, &ksettings);
+       ret = netif_get_link_ksettings(dev, &ksettings);
        if (ret < 0) {
                GENL_SET_ERR_MSG(info, "failed to retrieve link settings");
                return ret;