The vlan state can change under RTNL or RCU (mst), so use the helper
to get the state properly throughout the bridge driver.

Signed-off-by: Nikolay Aleksandrov <[email protected]>
---
v2: use br_vlan_get_state consistently where needed (Ido)

 net/bridge/br_mst.c          |  7 ++++---
 net/bridge/br_private.h      | 21 +++++++++++----------
 net/bridge/br_vlan.c         |  2 +-
 net/bridge/br_vlan_options.c |  2 +-
 4 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c
index 76a5bf287578..ecd8bba7430e 100644
--- a/net/bridge/br_mst.c
+++ b/net/bridge/br_mst.c
@@ -70,7 +70,7 @@ int br_mst_get_state(const struct net_device *dev, u16 msti, 
u8 *state)
 
        list_for_each_entry(v, &vg->vlan_list, vlist) {
                if (v->brvlan->msti == msti) {
-                       *state = v->state;
+                       *state = br_vlan_get_state(v);
                        return 0;
                }
        }
@@ -145,7 +145,7 @@ static void br_mst_vlan_sync_state(struct net_bridge_vlan 
*pv, u16 msti)
                 * it.
                 */
                if (v != pv && v->brvlan->msti == msti) {
-                       br_mst_vlan_set_state(vg, pv, v->state);
+                       br_mst_vlan_set_state(vg, pv, br_vlan_get_state(v));
                        return;
                }
        }
@@ -282,7 +282,8 @@ int br_mst_fill_info(struct sk_buff *skb,
                nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
                if (!nest ||
                    nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, 
v->brvlan->msti) ||
-                   nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
+                   nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE,
+                              br_vlan_get_state(v))) {
                        err = -EMSGSIZE;
                        break;
                }
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c7b64b5da012..df1500391f1d 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -687,6 +687,15 @@ static inline bool br_vlan_should_use(const struct 
net_bridge_vlan *v)
        return true;
 }
 
+/* The vlan state can be changed with only rcu held by the mst code so
+ * annotate the lock-free read. br_vlan_set_state() is kept further down
+ * because it needs br_multicast_update_vlan_mcast_ctx().
+ */
+static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)
+{
+       return READ_ONCE(v->state);
+}
+
 static inline bool nbp_state_should_learn(const struct net_bridge_port *p)
 {
        return p->state == BR_STATE_LEARNING || p->state == BR_STATE_FORWARDING;
@@ -1299,7 +1308,7 @@ br_multicast_port_ctx_state_disabled(const struct 
net_bridge_mcast_port *pmctx)
        return pmctx->port->state == BR_STATE_DISABLED ||
               (br_multicast_port_ctx_is_vlan(pmctx) &&
                (br_multicast_port_ctx_vlan_disabled(pmctx) ||
-                pmctx->vlan->state == BR_STATE_DISABLED));
+                br_vlan_get_state(pmctx->vlan) == BR_STATE_DISABLED));
 }
 
 static inline bool
@@ -1308,7 +1317,7 @@ br_multicast_port_ctx_state_stopped(const struct 
net_bridge_mcast_port *pmctx)
        return br_multicast_port_ctx_state_disabled(pmctx) ||
               pmctx->port->state == BR_STATE_BLOCKING ||
               (br_multicast_port_ctx_is_vlan(pmctx) &&
-               pmctx->vlan->state == BR_STATE_BLOCKING);
+               br_vlan_get_state(pmctx->vlan) == BR_STATE_BLOCKING);
 }
 
 static inline bool
@@ -1916,14 +1925,6 @@ bool br_vlan_global_opts_can_enter_range(const struct 
net_bridge_vlan *v_curr,
 bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range,
                              const struct net_bridge_vlan *v_opts);
 
-/* vlan state manipulation helpers using *_ONCE to annotate lock-free access,
- * while br_vlan_set_state() may access data protected by multicast_lock.
- */
-static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)
-{
-       return READ_ONCE(v->state);
-}
-
 static inline void br_vlan_set_state(struct net_bridge_vlan *v, u8 state)
 {
        WRITE_ONCE(v->state, state);
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 95187a607ec2..72b75757ac85 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -40,7 +40,7 @@ static void __vlan_add_pvid(struct net_bridge_vlan_group *vg,
        if (vg->pvid == v->vid)
                return;
 
-       br_vlan_set_pvid_state(vg, v->state);
+       br_vlan_set_pvid_state(vg, br_vlan_get_state(v));
        WRITE_ONCE(vg->pvid, v->vid);
 }
 
diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c
index bd049d268fe7..506668fc31d9 100644
--- a/net/bridge/br_vlan_options.c
+++ b/net/bridge/br_vlan_options.c
@@ -43,7 +43,7 @@ bool br_vlan_opts_eq_range(const struct net_bridge_vlan 
*v_curr,
        u8 range_mc_rtr = br_vlan_multicast_router(range_end);
        u8 curr_mc_rtr = br_vlan_multicast_router(v_curr);
 
-       if (v_curr->state != range_end->state)
+       if (br_vlan_get_state(v_curr) != br_vlan_get_state(range_end))
                return false;
 
        if (!__vlan_tun_can_enter_range(v_curr, range_end))
-- 
2.47.3


Reply via email to