phydev <> netdev linking and lifecycle depends on rtnl_lock.
We want to switch to instance locks for most ethtool ops.
Let's add an assert that ops locked devices don't use phydev
today. If one does we can either opt the phy ops out of
being purely ops locked, or do deeper surgery to make phy
locking ops-compatible. I don't think there's any fundamental
challenge to make that work.
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20260605002912.3456868-3-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
#include <linux/phy.h>
#include <linux/rtnetlink.h>
#include <linux/xarray.h>
+#include <net/netdev_lock.h>
static int netdev_alloc_phy_link_topology(struct net_device *dev)
{
struct phy_device_node *pdn;
int ret;
+ /* ethtool ops may run without rtnl_lock, and rtnl_lock is what
+ * currently protects the PHY topology. No driver currently mixes
+ * the two, flag if someone tries. See also ethnl_req_get_phydev().
+ */
+ if (WARN_ON_ONCE(netdev_need_ops_lock(dev)))
+ return -EOPNOTSUPP;
+
if (!topo) {
ret = netdev_alloc_phy_link_topology(dev);
if (ret)
struct phy_device *phy;
};
+static inline bool phy_link_topo_empty(struct net_device *dev)
+{
+ return !dev->link_topo;
+}
+
#if IS_ENABLED(CONFIG_PHYLIB)
int phy_link_topo_add_phy(struct net_device *dev,
struct phy_device *phy,
{
struct phy_device *phydev;
- ASSERT_RTNL();
-
if (!req_info->dev)
return NULL;
+ /* If there is no PHY in sight there's no need for assert locking */
+ if (!phy_link_topo_empty(req_info->dev))
+ ASSERT_RTNL();
+
if (!req_info->phy_index)
return req_info->dev->phydev;
/**
* ethnl_req_get_phydev() - Gets the phy_device targeted by this request,
- * if any. Must be called under rntl_lock().
+ * if any.
* @req_info: The ethnl request to get the phy from.
* @tb: The netlink attributes array, for error reporting.
* @header: The netlink header index, used for error reporting.
* @extack: The netlink extended ACK, for error reporting.
*
- * The caller must hold RTNL, until it's done interacting with the returned
- * phy_device.
+ * If a phy_device is returned the caller must hold rtnl_lock when calling
+ * this function, and until it's done interacting with the returned phy_device.
+ * IOW caller must hold rtnl_lock unless they know netdev has no phy_device.
*
* Return: A phy_device pointer corresponding either to the passed phy_index
* if one is provided. If not, the phy_device attached to the
struct phy_device *phydev;
int ret;
- /* RTNL is held by the caller */
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PHY_HEADER,
info->extack);
if (IS_ERR_OR_NULL(phydev))