]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: ethtool: move get_rxfh callback under the rss_lock
authorJakub Kicinski <kuba@kernel.org>
Thu, 26 Jun 2025 20:28:48 +0000 (13:28 -0700)
committerJakub Kicinski <kuba@kernel.org>
Mon, 30 Jun 2025 15:41:25 +0000 (08:41 -0700)
We already call get_rxfh under the rss_lock when we read back
context state after changes. Let's be consistent and always
hold the lock. The existing callers are all under rtnl_lock
so this should make no difference in practice, but it makes
the locking rules far less confusing IMHO. Any RSS callback
and any access to the RSS XArray should hold the lock.

Link: https://patch.msgid.link/20250626202848.104457-4-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ethtool/common.c
net/ethtool/ioctl.c
net/ethtool/rss.c

index eb253e0fd61b5d84c0d5d6c24e19e665b6182f2f..d62dc56f2f5b34029761cbe78da70e79e68aef4c 100644 (file)
@@ -707,7 +707,9 @@ static u32 ethtool_get_max_rxfh_channel(struct net_device *dev)
        if (!rxfh.indir)
                return U32_MAX;
 
+       mutex_lock(&dev->ethtool->rss_lock);
        ret = dev->ethtool_ops->get_rxfh(dev, &rxfh);
+       mutex_unlock(&dev->ethtool->rss_lock);
        if (ret) {
                current_max = U32_MAX;
                goto out_free;
index df376628ba191de03eb7f560400eed82e90d6b6d..b6d96e562c9a7b3663dd885c2b6db501166646ef 100644 (file)
@@ -1079,16 +1079,17 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)
            !ops->rxfh_per_ctx_fields)
                return -EINVAL;
 
+       mutex_lock(&dev->ethtool->rss_lock);
        if (ops->get_rxfh) {
                struct ethtool_rxfh_param rxfh = {};
 
                rc = ops->get_rxfh(dev, &rxfh);
                if (rc)
-                       return rc;
+                       goto exit_unlock;
 
                rc = ethtool_check_xfrm_rxfh(rxfh.input_xfrm, info.data);
                if (rc)
-                       return rc;
+                       goto exit_unlock;
        }
 
        fields.data = info.data;
@@ -1096,8 +1097,8 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)
        if (info.flow_type & FLOW_RSS)
                fields.rss_context = info.rss_context;
 
-       mutex_lock(&dev->ethtool->rss_lock);
        rc = ops->set_rxfh_fields(dev, &fields, NULL);
+exit_unlock:
        mutex_unlock(&dev->ethtool->rss_lock);
        return rc;
 }
@@ -1274,7 +1275,9 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
        if (!rxfh.indir)
                return -ENOMEM;
 
+       mutex_lock(&dev->ethtool->rss_lock);
        ret = dev->ethtool_ops->get_rxfh(dev, &rxfh);
+       mutex_unlock(&dev->ethtool->rss_lock);
        if (ret)
                goto out;
        if (copy_to_user(useraddr +
@@ -1413,6 +1416,7 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
        if (user_key_size)
                rxfh_dev.key = rss_config + indir_bytes;
 
+       mutex_lock(&dev->ethtool->rss_lock);
        if (rxfh.rss_context) {
                ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context);
                if (!ctx) {
@@ -1458,6 +1462,7 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
                ret = -EFAULT;
        }
 out:
+       mutex_unlock(&dev->ethtool->rss_lock);
        kfree(rss_config);
 
        return ret;
index 3adddca7e215ffc0ac454bd4cc19f6d0df8d707a..e717f23cbc1061152c115331d33d57f86b34d831 100644 (file)
@@ -138,6 +138,15 @@ rss_prepare_ctx(const struct rss_req_info *request, struct net_device *dev,
        return 0;
 }
 
+static int
+rss_prepare(const struct rss_req_info *request, struct net_device *dev,
+           struct rss_reply_data *data, const struct genl_info *info)
+{
+       if (request->rss_context)
+               return rss_prepare_ctx(request, dev, data, info);
+       return rss_prepare_get(request, dev, data, info);
+}
+
 static int
 rss_prepare_data(const struct ethnl_req_info *req_base,
                 struct ethnl_reply_data *reply_base,
@@ -147,20 +156,22 @@ rss_prepare_data(const struct ethnl_req_info *req_base,
        struct rss_req_info *request = RSS_REQINFO(req_base);
        struct net_device *dev = reply_base->dev;
        const struct ethtool_ops *ops;
+       int ret;
 
        ops = dev->ethtool_ops;
        if (!ops->get_rxfh)
                return -EOPNOTSUPP;
 
        /* Some drivers don't handle rss_context */
-       if (request->rss_context) {
-               if (!ops->cap_rss_ctx_supported && !ops->create_rxfh_context)
-                       return -EOPNOTSUPP;
+       if (request->rss_context &&
+           !ops->cap_rss_ctx_supported && !ops->create_rxfh_context)
+               return -EOPNOTSUPP;
 
-               return rss_prepare_ctx(request, dev, data, info);
-       }
+       mutex_lock(&dev->ethtool->rss_lock);
+       ret = rss_prepare(request, dev, data, info);
+       mutex_unlock(&dev->ethtool->rss_lock);
 
-       return rss_prepare_get(request, dev, data, info);
+       return ret;
 }
 
 static int