From patchwork Wed Mar 12 22:35:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 14014016 X-Patchwork-Delegate: kuba@kernel.org Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E906E1F03DE for ; Wed, 12 Mar 2025 22:35:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741818943; cv=none; b=DiNu+1vrQziIGAceTGPLw0EzjWLAywgR7QfPm4XIFtP9XCL8jOFO0vSC+LW4sN2w1ni2gIlHuFlS9D1kSLZT5UtSd5yhHrp7ZlyyZtMdx2S7PUbcwQ1weevSdLeFAJD6HJh9LHOmG0joYqTMqFE+eO7jW8jPNcLbvazJ16FQ40w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741818943; c=relaxed/simple; bh=7fX/ZtP8jrUk1NoUgi1jNBTjW7S9t+rPPz3YeCB9bHc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RuDb43yH8TtWfCHY5LDP++yFw9DRGs2jhKfVxJx+fMImh3uTgtXuIl/C8xzpfgP8IBlIaEVhYmM/LOzdn1katCcCAOOWbGRiAogUCyMYLhDK9M8TyVYoCSJcv4FuZhlZOoA7iwrR/OPXHbecPVlCRI7clQkJFyySw6y2gtt86gQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GZ+XI4UW; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GZ+XI4UW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C38C2C4CEEE; Wed, 12 Mar 2025 22:35:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741818942; bh=7fX/ZtP8jrUk1NoUgi1jNBTjW7S9t+rPPz3YeCB9bHc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GZ+XI4UWZ66MuBIlSYgAQrcyNAxhJlYW+QV4PiDJPPbGPbyfzPzTyI2i5c/4zw+YJ g/HUu/YGgOm4QsDikt/qYgUwuYXeKGJvlHxgGp+sPDf2XcAQp20a8gKaLis/qoQXSU TYAjyOxyXUYFHZeJOZZKIViurgxYUpA0YMAlwGcvqPSxjguI/wBL+DQJz74Es8Qap7 DA+ikdlNq5aO9It1rGkrpH17lYhHGjUFGMlpowxNcjwdn47Zr7D9wl2dxjE54TQMav aXKCUU1RUwa8S9cccVx37fmXgzlH8QW4xD++EuwWDkaTz/4RY4USjNQB/i/nf2pOqq 8gF8fvQfbP03A== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch, horms@kernel.org, sdf@fomichev.me, Jakub Kicinski Subject: [PATCH net-next 10/11] netdev: add "ops compat locking" helpers Date: Wed, 12 Mar 2025 23:35:06 +0100 Message-ID: <20250312223507.805719-11-kuba@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250312223507.805719-1-kuba@kernel.org> References: <20250312223507.805719-1-kuba@kernel.org> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Add helpers to "lock a netdev in a backward-compatible way", which for ops-locked netdevs will mean take the instance lock. For drivers which haven't opted into the ops locking we'll take rtnl_lock. The scoped foreach is dropping and re-taking the lock for each device, even if prev and next are both under rtnl_lock. I hope that's fine since we expect that netdev nl to be mostly supported by modern drivers, and modern drivers should also opt into the instance locking. Note that these helpers are mostly needed for queue related state, because drivers modify queue config in their ops in a non-atomic way. Or differently put, queue changes don't have a clear-cut API like NAPI configuration. Any state that can should just use the instance lock directly, not the "compat" hacks. Signed-off-by: Jakub Kicinski --- include/net/netdev_lock.h | 16 +++++++++++++ net/core/dev.h | 15 ++++++++++++ net/core/dev.c | 49 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/include/net/netdev_lock.h b/include/net/netdev_lock.h index 1c0c9a94cc22..76cbf5a449b6 100644 --- a/include/net/netdev_lock.h +++ b/include/net/netdev_lock.h @@ -64,6 +64,22 @@ netdev_ops_assert_locked_or_invisible(const struct net_device *dev) netdev_ops_assert_locked(dev); } +static inline void netdev_lock_ops_compat(struct net_device *dev) +{ + if (netdev_need_ops_lock(dev)) + netdev_lock(dev); + else + rtnl_lock(); +} + +static inline void netdev_unlock_ops_compat(struct net_device *dev) +{ + if (netdev_need_ops_lock(dev)) + netdev_unlock(dev); + else + rtnl_unlock(); +} + static inline int netdev_lock_cmp_fn(const struct lockdep_map *a, const struct lockdep_map *b) { diff --git a/net/core/dev.h b/net/core/dev.h index 0ddd3631acb0..f1e9f51f36d4 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -42,6 +42,21 @@ DEFINE_FREE(netdev_unlock, struct net_device *, if (_T) netdev_unlock(_T)); (var_name = netdev_xa_find_lock(net, var_name, &ifindex)); \ ifindex++) +struct net_device * +netdev_get_by_index_lock_ops_compat(struct net *net, int ifindex); +struct net_device * +netdev_xa_find_lock_ops_compat(struct net *net, struct net_device *dev, + unsigned long *index); + +DEFINE_FREE(netdev_unlock_ops_compat, struct net_device *, + if (_T) netdev_unlock_ops_compat(_T)); + +#define for_each_netdev_lock_ops_compat_scoped(net, var_name, ifindex) \ + for (struct net_device *var_name __free(netdev_unlock_ops_compat) = NULL; \ + (var_name = netdev_xa_find_lock_ops_compat(net, var_name, \ + &ifindex)); \ + ifindex++) + #ifdef CONFIG_PROC_FS int __init dev_proc_init(void); #else diff --git a/net/core/dev.c b/net/core/dev.c index 8296b4c159fe..1477bbae0ee0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1037,6 +1037,18 @@ struct net_device *__netdev_put_lock(struct net_device *dev) return dev; } +static struct net_device *__netdev_put_lock_ops_compat(struct net_device *dev) +{ + netdev_lock_ops_compat(dev); + if (dev->reg_state > NETREG_REGISTERED) { + netdev_unlock_ops_compat(dev); + dev_put(dev); + return NULL; + } + dev_put(dev); + return dev; +} + /** * netdev_get_by_index_lock() - find a device by its ifindex * @net: the applicable net namespace @@ -1059,6 +1071,18 @@ struct net_device *netdev_get_by_index_lock(struct net *net, int ifindex) return __netdev_put_lock(dev); } +struct net_device * +netdev_get_by_index_lock_ops_compat(struct net *net, int ifindex) +{ + struct net_device *dev; + + dev = dev_get_by_index(net, ifindex); + if (!dev) + return NULL; + + return __netdev_put_lock_ops_compat(dev); +} + /** * netdev_get_by_name_lock() - find a device by its name * @net: the applicable net namespace @@ -1106,6 +1130,31 @@ netdev_xa_find_lock(struct net *net, struct net_device *dev, } while (true); } +struct net_device * +netdev_xa_find_lock_ops_compat(struct net *net, struct net_device *dev, + unsigned long *index) +{ + if (dev) + netdev_unlock_ops_compat(dev); + + do { + rcu_read_lock(); + dev = xa_find(&net->dev_by_index, index, ULONG_MAX, XA_PRESENT); + if (!dev) { + rcu_read_unlock(); + return NULL; + } + dev_hold(dev); + rcu_read_unlock(); + + dev = __netdev_put_lock_ops_compat(dev); + if (dev) + return dev; + + (*index)++; + } while (true); +} + static DEFINE_SEQLOCK(netdev_rename_lock); void netdev_copy_name(struct net_device *dev, char *name)