]> git.apps.os.sepia.ceph.com Git - ceph-client.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)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 11 Sep 2025 09:49:19 +0000 (11:49 +0200)
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>
net/hsr/hsr_device.c
net/hsr/hsr_main.c
net/hsr/hsr_main.h

index 88657255fec12b8cbf9edf4634899046381afc1d..bce7b4061ce08bfe5eb1bc4b6e586f52eac95eb8 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);
@@ -484,7 +484,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) {
@@ -506,7 +506,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) {
@@ -534,7 +534,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;
@@ -580,7 +580,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 192893c3f2ec7360695b178970cc4870002f702b..ac1eb1db1a52b4bfebb998a2b7a15cfc94b70dd8 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 135ec5fce0196741f4035a74a4f965e7fa015504..33b0d2460c9bcd5886bf7b20dfc6b8c8ca7e1741 100644 (file)
@@ -224,6 +224,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 */