netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops
@ 2025-06-26 20:28 Jakub Kicinski
  2025-06-26 20:28 ` [PATCH net-next 1/3] net: ethtool: take rss_lock for all rxfh changes Jakub Kicinski
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Jakub Kicinski @ 2025-06-26 20:28 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, andrew+netdev, horms, ecree.xilinx,
	Jakub Kicinski

I'd like to bring RXFH and RXFHINDIR ioctls under a single set of
Netlink ops. It appears that while core takes the ethtool->rss_lock
around some of the RXFHINDIR ops, drivers (sfc) take it internally
for the RXFH.

Consistently take the lock around all ops and accesses to the XArray
within the core. This should hopefully make the rss_lock a lot less
confusing.

Jakub Kicinski (3):
  net: ethtool: take rss_lock for all rxfh changes
  net: ethtool: move rxfh_fields callbacks under the rss_lock
  net: ethtool: move get_rxfh callback under the rss_lock

 drivers/net/ethernet/sfc/ethtool_common.c |  9 +---
 net/ethtool/common.c                      |  2 +
 net/ethtool/ioctl.c                       | 66 +++++++++++++----------
 net/ethtool/rss.c                         | 23 +++++---
 4 files changed, 59 insertions(+), 41 deletions(-)

-- 
2.50.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next 1/3] net: ethtool: take rss_lock for all rxfh changes
  2025-06-26 20:28 [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops Jakub Kicinski
@ 2025-06-26 20:28 ` Jakub Kicinski
  2025-06-26 20:28 ` [PATCH net-next 2/3] net: ethtool: move rxfh_fields callbacks under the rss_lock Jakub Kicinski
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Jakub Kicinski @ 2025-06-26 20:28 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, andrew+netdev, horms, ecree.xilinx,
	Jakub Kicinski

Always take the rss_lock in ethtool_set_rxfh(). We will want to
make a similar change in ethtool_set_rxfh_fields() and some
drivers lock that callback regardless of rss context ID being set.
Having some callbacks locked unconditionally and some only if
context ID is set would be very confusing.

ethtool handling is under rtnl_lock, so rss_lock is very unlikely
to ever be congested.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/ethtool/ioctl.c | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index c34bac7bffd8..ce7d720b3c79 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1334,9 +1334,11 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
 	}
 
 	rxfh_dev.hfunc = ETH_RSS_HASH_NO_CHANGE;
+
+	mutex_lock(&dev->ethtool->rss_lock);
 	ret = ops->set_rxfh(dev, &rxfh_dev, extack);
 	if (ret)
-		goto out;
+		goto out_unlock;
 
 	/* indicate whether rxfh was set to default */
 	if (user_size == 0)
@@ -1344,6 +1346,8 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
 	else
 		dev->priv_flags |= IFF_RXFH_CONFIGURED;
 
+out_unlock:
+	mutex_unlock(&dev->ethtool->rss_lock);
 out:
 	kfree(rxfh_dev.indir);
 	return ret;
@@ -1500,7 +1504,6 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 	struct netlink_ext_ack *extack = NULL;
 	struct ethtool_rxnfc rx_rings;
 	struct ethtool_rxfh rxfh;
-	bool locked = false; /* dev->ethtool->rss_lock taken */
 	bool create = false;
 	bool mod = false;
 	u8 *rss_config;
@@ -1570,7 +1573,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 	rx_rings.cmd = ETHTOOL_GRXRINGS;
 	ret = ops->get_rxnfc(dev, &rx_rings, NULL);
 	if (ret)
-		goto out;
+		goto out_free;
 
 	/* rxfh.indir_size == 0 means reset the indir table to default (master
 	 * context) or delete the context (other RSS contexts).
@@ -1586,7 +1589,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 						  &rx_rings,
 						  rxfh.indir_size);
 		if (ret)
-			goto out;
+			goto out_free;
 	} else if (rxfh.indir_size == 0) {
 		if (rxfh.rss_context == 0) {
 			u32 *indir;
@@ -1608,30 +1611,27 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 				   useraddr + rss_cfg_offset + user_indir_len,
 				   rxfh.key_size)) {
 			ret = -EFAULT;
-			goto out;
+			goto out_free;
 		}
 	}
 
-	if (rxfh.rss_context) {
-		mutex_lock(&dev->ethtool->rss_lock);
-		locked = true;
-	}
+	mutex_lock(&dev->ethtool->rss_lock);
 
 	if (rxfh.rss_context && rxfh_dev.rss_delete) {
 		ret = ethtool_check_rss_ctx_busy(dev, rxfh.rss_context);
 		if (ret)
-			goto out;
+			goto out_unlock;
 	}
 
 	if (create) {
 		if (rxfh_dev.rss_delete) {
 			ret = -EINVAL;
-			goto out;
+			goto out_unlock;
 		}
 		ctx = ethtool_rxfh_ctx_alloc(ops, dev_indir_size, dev_key_size);
 		if (!ctx) {
 			ret = -ENOMEM;
-			goto out;
+			goto out_unlock;
 		}
 
 		if (ops->create_rxfh_context) {
@@ -1644,7 +1644,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 				       GFP_KERNEL_ACCOUNT);
 			if (ret < 0) {
 				kfree(ctx);
-				goto out;
+				goto out_unlock;
 			}
 			WARN_ON(!ctx_id); /* can't happen */
 			rxfh.rss_context = ctx_id;
@@ -1653,7 +1653,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 		ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context);
 		if (!ctx) {
 			ret = -ENOENT;
-			goto out;
+			goto out_unlock;
 		}
 	}
 	rxfh_dev.hfunc = rxfh.hfunc;
@@ -1687,7 +1687,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 				xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context);
 			kfree(ctx);
 		}
-		goto out;
+		goto out_unlock;
 	}
 	mod = !create && !rxfh_dev.rss_delete;
 
@@ -1708,13 +1708,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 		if (WARN_ON(xa_load(&dev->ethtool->rss_ctx, rxfh_dev.rss_context))) {
 			/* context ID reused, our tracking is screwed */
 			kfree(ctx);
-			goto out;
+			goto out_unlock;
 		}
 		/* Allocate the exact ID the driver gave us */
 		if (xa_is_err(xa_store(&dev->ethtool->rss_ctx, rxfh_dev.rss_context,
 				       ctx, GFP_KERNEL))) {
 			kfree(ctx);
-			goto out;
+			goto out_unlock;
 		}
 
 		/* Fetch the defaults for the old API, in the new API drivers
@@ -1730,7 +1730,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 		if (WARN_ON(ret)) {
 			xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context);
 			kfree(ctx);
-			goto out;
+			goto out_unlock;
 		}
 	}
 	if (rxfh_dev.rss_delete) {
@@ -1755,9 +1755,9 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 			ctx->input_xfrm = rxfh_dev.input_xfrm;
 	}
 
-out:
-	if (locked)
-		mutex_unlock(&dev->ethtool->rss_lock);
+out_unlock:
+	mutex_unlock(&dev->ethtool->rss_lock);
+out_free:
 	kfree(rss_config);
 	if (mod)
 		ethtool_rss_notify(dev, rxfh.rss_context);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next 2/3] net: ethtool: move rxfh_fields callbacks under the rss_lock
  2025-06-26 20:28 [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops Jakub Kicinski
  2025-06-26 20:28 ` [PATCH net-next 1/3] net: ethtool: take rss_lock for all rxfh changes Jakub Kicinski
@ 2025-06-26 20:28 ` Jakub Kicinski
  2025-06-26 20:28 ` [PATCH net-next 3/3] net: ethtool: move get_rxfh callback " Jakub Kicinski
  2025-06-30 16:10 ` [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: Jakub Kicinski @ 2025-06-26 20:28 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, andrew+netdev, horms, ecree.xilinx,
	Jakub Kicinski

Netlink code will want to perform the RSS_SET operation atomically
under the rss_lock. sfc wants to hold the rss_lock in rxfh_fields_get,
which makes that difficult. Lets move the locking up to the core
so that for all driver-facing callbacks rss_lock is taken consistently
by the core.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 drivers/net/ethernet/sfc/ethtool_common.c |  9 ++-------
 net/ethtool/ioctl.c                       | 15 ++++++++++-----
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c
index 823263969f92..fa303e171d98 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/ethtool_common.c
@@ -810,13 +810,10 @@ int efx_ethtool_get_rxfh_fields(struct net_device *net_dev,
 
 	ctx = &efx->rss_context.priv;
 
-	mutex_lock(&net_dev->ethtool->rss_lock);
 	if (info->rss_context) {
 		ctx = efx_find_rss_context_entry(efx, info->rss_context);
-		if (!ctx) {
-			rc = -ENOENT;
-			goto out_unlock;
-		}
+		if (!ctx)
+			return -ENOENT;
 	}
 
 	data = 0;
@@ -850,8 +847,6 @@ int efx_ethtool_get_rxfh_fields(struct net_device *net_dev,
 	}
 out_setdata_unlock:
 	info->data = data;
-out_unlock:
-	mutex_unlock(&net_dev->ethtool->rss_lock);
 	return rc;
 }
 
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index ce7d720b3c79..df376628ba19 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1096,7 +1096,10 @@ 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;
 
-	return ops->set_rxfh_fields(dev, &fields, NULL);
+	mutex_lock(&dev->ethtool->rss_lock);
+	rc = ops->set_rxfh_fields(dev, &fields, NULL);
+	mutex_unlock(&dev->ethtool->rss_lock);
+	return rc;
 }
 
 static noinline_for_stack int
@@ -1123,7 +1126,9 @@ ethtool_get_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);
 	ret = ops->get_rxfh_fields(dev, &fields);
+	mutex_unlock(&dev->ethtool->rss_lock);
 	if (ret < 0)
 		return ret;
 
@@ -1553,10 +1558,6 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 	     rxfh.input_xfrm == RXH_XFRM_NO_CHANGE))
 		return -EINVAL;
 
-	ret = ethtool_check_flow_types(dev, rxfh.input_xfrm);
-	if (ret)
-		return ret;
-
 	indir_bytes = dev_indir_size * sizeof(rxfh_dev.indir[0]);
 
 	/* Check settings which may be global rather than per RSS-context */
@@ -1617,6 +1618,10 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
 
 	mutex_lock(&dev->ethtool->rss_lock);
 
+	ret = ethtool_check_flow_types(dev, rxfh.input_xfrm);
+	if (ret)
+		goto out_unlock;
+
 	if (rxfh.rss_context && rxfh_dev.rss_delete) {
 		ret = ethtool_check_rss_ctx_busy(dev, rxfh.rss_context);
 		if (ret)
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next 3/3] net: ethtool: move get_rxfh callback under the rss_lock
  2025-06-26 20:28 [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops Jakub Kicinski
  2025-06-26 20:28 ` [PATCH net-next 1/3] net: ethtool: take rss_lock for all rxfh changes Jakub Kicinski
  2025-06-26 20:28 ` [PATCH net-next 2/3] net: ethtool: move rxfh_fields callbacks under the rss_lock Jakub Kicinski
@ 2025-06-26 20:28 ` Jakub Kicinski
  2025-06-30 16:10 ` [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: Jakub Kicinski @ 2025-06-26 20:28 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, andrew+netdev, horms, ecree.xilinx,
	Jakub Kicinski

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.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/ethtool/common.c |  2 ++
 net/ethtool/ioctl.c  | 11 ++++++++---
 net/ethtool/rss.c    | 23 +++++++++++++++++------
 3 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index eb253e0fd61b..d62dc56f2f5b 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -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;
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index df376628ba19..b6d96e562c9a 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -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;
diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c
index 3adddca7e215..e717f23cbc10 100644
--- a/net/ethtool/rss.c
+++ b/net/ethtool/rss.c
@@ -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
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops
  2025-06-26 20:28 [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops Jakub Kicinski
                   ` (2 preceding siblings ...)
  2025-06-26 20:28 ` [PATCH net-next 3/3] net: ethtool: move get_rxfh callback " Jakub Kicinski
@ 2025-06-30 16:10 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-06-30 16:10 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms,
	ecree.xilinx

Hello:

This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Thu, 26 Jun 2025 13:28:45 -0700 you wrote:
> I'd like to bring RXFH and RXFHINDIR ioctls under a single set of
> Netlink ops. It appears that while core takes the ethtool->rss_lock
> around some of the RXFHINDIR ops, drivers (sfc) take it internally
> for the RXFH.
> 
> Consistently take the lock around all ops and accesses to the XArray
> within the core. This should hopefully make the rss_lock a lot less
> confusing.
> 
> [...]

Here is the summary with links:
  - [net-next,1/3] net: ethtool: take rss_lock for all rxfh changes
    https://git.kernel.org/netdev/net-next/c/5ec353dbff4f
  - [net-next,2/3] net: ethtool: move rxfh_fields callbacks under the rss_lock
    https://git.kernel.org/netdev/net-next/c/739d18cce105
  - [net-next,3/3] net: ethtool: move get_rxfh callback under the rss_lock
    https://git.kernel.org/netdev/net-next/c/040cef30b5e6

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-06-30 16:09 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-26 20:28 [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops Jakub Kicinski
2025-06-26 20:28 ` [PATCH net-next 1/3] net: ethtool: take rss_lock for all rxfh changes Jakub Kicinski
2025-06-26 20:28 ` [PATCH net-next 2/3] net: ethtool: move rxfh_fields callbacks under the rss_lock Jakub Kicinski
2025-06-26 20:28 ` [PATCH net-next 3/3] net: ethtool: move get_rxfh callback " Jakub Kicinski
2025-06-30 16:10 ` [PATCH net-next 0/3] net: ethtool: consistently take rss_lock for all rxfh ops patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).