hsr: use rtnl lock when iterating over ports

hsr_for_each_port is called in many places without holding the RCU read
lock, this may trigger warnings on debug kernels. Most of the callers
are actually hold rtnl lock. So add a new helper hsr_for_each_port_rtnl
to allow callers in suitable contexts to iterate ports safely without
explicit RCU locking.

This patch only fixed the callers that is hold rtnl lock. Other caller
issues will be fixed in later patches.

Fixes: c5a7591172 ("net/hsr: Use list_head (and rcu) instead of array for slave devices.")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250905091533.377443-2-liuhangbin@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Hangbin Liu
2025-09-05 09:15:31 +00:00
committed by Paolo Abeni
parent 3a1a66d124
commit 8884c69399
3 changed files with 13 additions and 10 deletions

View File

@@ -49,7 +49,7 @@ static bool hsr_check_carrier(struct hsr_port *master)
ASSERT_RTNL(); ASSERT_RTNL();
hsr_for_each_port(master->hsr, port) { hsr_for_each_port_rtnl(master->hsr, port) {
if (port->type != HSR_PT_MASTER && is_slave_up(port->dev)) { if (port->type != HSR_PT_MASTER && is_slave_up(port->dev)) {
netif_carrier_on(master->dev); netif_carrier_on(master->dev);
return true; return true;
@@ -105,7 +105,7 @@ int hsr_get_max_mtu(struct hsr_priv *hsr)
struct hsr_port *port; struct hsr_port *port;
mtu_max = ETH_DATA_LEN; mtu_max = ETH_DATA_LEN;
hsr_for_each_port(hsr, port) hsr_for_each_port_rtnl(hsr, port)
if (port->type != HSR_PT_MASTER) if (port->type != HSR_PT_MASTER)
mtu_max = min(port->dev->mtu, mtu_max); mtu_max = min(port->dev->mtu, mtu_max);
@@ -139,7 +139,7 @@ static int hsr_dev_open(struct net_device *dev)
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) { hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER) if (port->type == HSR_PT_MASTER)
continue; continue;
switch (port->type) { switch (port->type) {
@@ -172,7 +172,7 @@ static int hsr_dev_close(struct net_device *dev)
struct hsr_priv *hsr; struct hsr_priv *hsr;
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) { hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER) if (port->type == HSR_PT_MASTER)
continue; continue;
switch (port->type) { switch (port->type) {
@@ -205,7 +205,7 @@ static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr,
* may become enabled. * may become enabled.
*/ */
features &= ~NETIF_F_ONE_FOR_ALL; features &= ~NETIF_F_ONE_FOR_ALL;
hsr_for_each_port(hsr, port) hsr_for_each_port_rtnl(hsr, port)
features = netdev_increment_features(features, features = netdev_increment_features(features,
port->dev->features, port->dev->features,
mask); mask);
@@ -484,7 +484,7 @@ static void hsr_set_rx_mode(struct net_device *dev)
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) { hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER) if (port->type == HSR_PT_MASTER)
continue; continue;
switch (port->type) { switch (port->type) {
@@ -506,7 +506,7 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) { hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER) if (port->type == HSR_PT_MASTER)
continue; continue;
switch (port->type) { switch (port->type) {
@@ -534,7 +534,7 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) { hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER || if (port->type == HSR_PT_MASTER ||
port->type == HSR_PT_INTERLINK) port->type == HSR_PT_INTERLINK)
continue; continue;
@@ -580,7 +580,7 @@ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
hsr = netdev_priv(dev); hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) { hsr_for_each_port_rtnl(hsr, port) {
switch (port->type) { switch (port->type) {
case HSR_PT_SLAVE_A: case HSR_PT_SLAVE_A:
case HSR_PT_SLAVE_B: case HSR_PT_SLAVE_B:

View File

@@ -22,7 +22,7 @@ static bool hsr_slave_empty(struct hsr_priv *hsr)
{ {
struct hsr_port *port; struct hsr_port *port;
hsr_for_each_port(hsr, port) hsr_for_each_port_rtnl(hsr, port)
if (port->type != HSR_PT_MASTER) if (port->type != HSR_PT_MASTER)
return false; return false;
return true; return true;

View File

@@ -224,6 +224,9 @@ struct hsr_priv {
#define hsr_for_each_port(hsr, port) \ #define hsr_for_each_port(hsr, port) \
list_for_each_entry_rcu((port), &(hsr)->ports, port_list) list_for_each_entry_rcu((port), &(hsr)->ports, port_list)
#define hsr_for_each_port_rtnl(hsr, port) \
list_for_each_entry_rcu((port), &(hsr)->ports, port_list, lockdep_rtnl_is_held())
struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt); struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt);
/* Caller must ensure skb is a valid HSR frame */ /* Caller must ensure skb is a valid HSR frame */