]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
hsr: use rtnl lock when iterating over ports
authorHangbin Liu <liuhangbin@gmail.com>
Fri, 5 Sep 2025 09:15:31 +0000 (09:15 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Sep 2025 14:35:50 +0000 (16:35 +0200)
[ Upstream commit 8884c693991333ae065830554b9b0c96590b1bb2 ]

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: c5a759117210 ("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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/hsr/hsr_device.c
net/hsr/hsr_main.c
net/hsr/hsr_main.h

index 9f1106bdd4f09f733e8a01e69ffb9a089ac33d9a..56b49d477bec00ed9d87a51b78bbaf80bec8e08b 100644 (file)
@@ -49,7 +49,7 @@ static bool hsr_check_carrier(struct hsr_port *master)
 
        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)) {
                        netif_carrier_on(master->dev);
                        return true;
@@ -105,7 +105,7 @@ int hsr_get_max_mtu(struct hsr_priv *hsr)
        struct hsr_port *port;
 
        mtu_max = ETH_DATA_LEN;
-       hsr_for_each_port(hsr, port)
+       hsr_for_each_port_rtnl(hsr, port)
                if (port->type != HSR_PT_MASTER)
                        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_for_each_port(hsr, port) {
+       hsr_for_each_port_rtnl(hsr, port) {
                if (port->type == HSR_PT_MASTER)
                        continue;
                switch (port->type) {
@@ -172,7 +172,7 @@ static int hsr_dev_close(struct net_device *dev)
        struct hsr_priv *hsr;
 
        hsr = netdev_priv(dev);
-       hsr_for_each_port(hsr, port) {
+       hsr_for_each_port_rtnl(hsr, port) {
                if (port->type == HSR_PT_MASTER)
                        continue;
                switch (port->type) {
@@ -205,7 +205,7 @@ static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr,
         * may become enabled.
         */
        features &= ~NETIF_F_ONE_FOR_ALL;
-       hsr_for_each_port(hsr, port)
+       hsr_for_each_port_rtnl(hsr, port)
                features = netdev_increment_features(features,
                                                     port->dev->features,
                                                     mask);
@@ -483,7 +483,7 @@ static void hsr_set_rx_mode(struct net_device *dev)
 
        hsr = netdev_priv(dev);
 
-       hsr_for_each_port(hsr, port) {
+       hsr_for_each_port_rtnl(hsr, port) {
                if (port->type == HSR_PT_MASTER)
                        continue;
                switch (port->type) {
@@ -505,7 +505,7 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
 
        hsr = netdev_priv(dev);
 
-       hsr_for_each_port(hsr, port) {
+       hsr_for_each_port_rtnl(hsr, port) {
                if (port->type == HSR_PT_MASTER)
                        continue;
                switch (port->type) {
@@ -533,7 +533,7 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
 
        hsr = netdev_priv(dev);
 
-       hsr_for_each_port(hsr, port) {
+       hsr_for_each_port_rtnl(hsr, port) {
                if (port->type == HSR_PT_MASTER ||
                    port->type == HSR_PT_INTERLINK)
                        continue;
@@ -579,7 +579,7 @@ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
 
        hsr = netdev_priv(dev);
 
-       hsr_for_each_port(hsr, port) {
+       hsr_for_each_port_rtnl(hsr, port) {
                switch (port->type) {
                case HSR_PT_SLAVE_A:
                case HSR_PT_SLAVE_B:
index d7ae32473c41a641bff1c0783ca5867d8acae052..e1afa54b3fba8c76afaa15d040cfb0cebe6ecef9 100644 (file)
@@ -22,7 +22,7 @@ static bool hsr_slave_empty(struct hsr_priv *hsr)
 {
        struct hsr_port *port;
 
-       hsr_for_each_port(hsr, port)
+       hsr_for_each_port_rtnl(hsr, port)
                if (port->type != HSR_PT_MASTER)
                        return false;
        return true;
index e26244456f63961ee6c513c41611e579e75fbf7f..f066c9c401c605729d353e6eab5129574dd4096e 100644 (file)
@@ -231,6 +231,9 @@ struct hsr_priv {
 #define hsr_for_each_port(hsr, port) \
        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);
 
 /* Caller must ensure skb is a valid HSR frame */