Split removal of a VLAN from its lookup and flood structures from object destruction. Pass the VLAN group explicitly to __vlan_del() and call both operations consecutively for now. This prepares deletion paths to quiesce readers after making an entry unreachable and before freeing it.
Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: Nikolay Aleksandrov <[email protected]> --- net/bridge/br_vlan.c | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 7ba6e57b18fa..8a914e249767 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -429,22 +429,34 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags, goto out; } -static void __vlan_del(struct net_bridge_vlan *v) +static void __vlan_unpublish(struct net_bridge_vlan_group *vg, + struct net_bridge_vlan *v) +{ + __vlan_delete_pvid(vg, v); + if (!br_vlan_is_master(v)) { + struct net_bridge_vlan *masterv = v->brvlan; + + rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, + br_vlan_rht_params); + __vlan_del_list(v); + /* -1 because br_vlan_put_master() is called later */ + br_vlan_rebuild_port_array(masterv, + br_vlan_num_ports(masterv) - 1); + } +} + +static void __vlan_del(struct net_bridge_vlan_group *vg, + struct net_bridge_vlan *v) { struct net_bridge_vlan *masterv = v; - struct net_bridge_vlan_group *vg; struct net_bridge_port *p = NULL; int err; - if (br_vlan_is_master(v)) { - vg = br_vlan_group(v->br); - } else { + if (!br_vlan_is_master(v)) { p = v->port; - vg = nbp_vlan_group(v->port); masterv = v->brvlan; } - __vlan_delete_pvid(vg, v); if (p) { err = __vlan_vid_del(p->dev, p->br, v); if (err) @@ -467,12 +479,6 @@ static void __vlan_del(struct net_bridge_vlan *v) if (masterv != v) { vlan_tunnel_info_del(vg, v); - rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, - br_vlan_rht_params); - __vlan_del_list(v); - /* -1 because br_vlan_put_master() is called later */ - br_vlan_rebuild_port_array(masterv, - br_vlan_num_ports(masterv) - 1); nbp_vlan_set_vlan_dev_state(p, v->vid); br_multicast_toggle_one_vlan(v, false); br_multicast_port_ctx_deinit(&v->port_mcast_ctx); @@ -509,7 +515,8 @@ static void __vlan_flush(const struct net_bridge *br, } v_end = vlan->vid; - __vlan_del(vlan); + __vlan_unpublish(vg, vlan); + __vlan_del(vg, vlan); } /* notify about the last/whole vlan range */ @@ -873,7 +880,8 @@ int br_vlan_delete(struct net_bridge *br, u16 vid) br_fdb_cleanup_by_dst(br, br_port_to_dst(NULL), vid, 0); vlan_tunnel_info_del(vg, v); - __vlan_del(v); + __vlan_unpublish(vg, v); + __vlan_del(vg, v); return 0; } @@ -1389,15 +1397,18 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags, */ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) { + struct net_bridge_vlan_group *vg; struct net_bridge_vlan *v; ASSERT_RTNL(); - v = br_vlan_find(nbp_vlan_group(port), vid); + vg = nbp_vlan_group(port); + v = br_vlan_find(vg, vid); if (!v) return -ENOENT; br_fdb_cleanup_by_dst(port->br, br_vlan_to_dst(v), vid, 0); - __vlan_del(v); + __vlan_unpublish(vg, v); + __vlan_del(vg, v); return 0; } -- 2.47.3
