aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_if.c3
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/br_vlan.c31
3 files changed, 25 insertions, 10 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 934cae9fa317..45e4757c6fd2 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -248,6 +248,7 @@ static void del_nbp(struct net_bridge_port *p)
248 248
249 list_del_rcu(&p->list); 249 list_del_rcu(&p->list);
250 250
251 nbp_vlan_flush(p);
251 br_fdb_delete_by_port(br, p, 0, 1); 252 br_fdb_delete_by_port(br, p, 0, 1);
252 nbp_update_port_count(br); 253 nbp_update_port_count(br);
253 254
@@ -256,8 +257,6 @@ static void del_nbp(struct net_bridge_port *p)
256 dev->priv_flags &= ~IFF_BRIDGE_PORT; 257 dev->priv_flags &= ~IFF_BRIDGE_PORT;
257 258
258 netdev_rx_handler_unregister(dev); 259 netdev_rx_handler_unregister(dev);
259 /* use the synchronize_rcu done by netdev_rx_handler_unregister */
260 nbp_vlan_flush(p);
261 260
262 br_multicast_del_port(p); 261 br_multicast_del_port(p);
263 262
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8835642a6326..216018c76018 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -132,7 +132,6 @@ struct net_bridge_vlan_group {
132 struct list_head vlan_list; 132 struct list_head vlan_list;
133 u16 num_vlans; 133 u16 num_vlans;
134 u16 pvid; 134 u16 pvid;
135 struct rcu_head rcu;
136}; 135};
137 136
138struct net_bridge_fdb_entry 137struct net_bridge_fdb_entry
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 85e67568092e..5f0d0cc4744f 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -307,15 +307,20 @@ out:
307 return err; 307 return err;
308} 308}
309 309
310static void __vlan_flush(struct net_bridge_vlan_group *vlgrp) 310static void __vlan_group_free(struct net_bridge_vlan_group *vg)
311{
312 WARN_ON(!list_empty(&vg->vlan_list));
313 rhashtable_destroy(&vg->vlan_hash);
314 kfree(vg);
315}
316
317static void __vlan_flush(struct net_bridge_vlan_group *vg)
311{ 318{
312 struct net_bridge_vlan *vlan, *tmp; 319 struct net_bridge_vlan *vlan, *tmp;
313 320
314 __vlan_delete_pvid(vlgrp, vlgrp->pvid); 321 __vlan_delete_pvid(vg, vg->pvid);
315 list_for_each_entry_safe(vlan, tmp, &vlgrp->vlan_list, vlist) 322 list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist)
316 __vlan_del(vlan); 323 __vlan_del(vlan);
317 rhashtable_destroy(&vlgrp->vlan_hash);
318 kfree_rcu(vlgrp, rcu);
319} 324}
320 325
321struct sk_buff *br_handle_vlan(struct net_bridge *br, 326struct sk_buff *br_handle_vlan(struct net_bridge *br,
@@ -571,9 +576,15 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
571 576
572void br_vlan_flush(struct net_bridge *br) 577void br_vlan_flush(struct net_bridge *br)
573{ 578{
579 struct net_bridge_vlan_group *vg;
580
574 ASSERT_RTNL(); 581 ASSERT_RTNL();
575 582
576 __vlan_flush(br_vlan_group(br)); 583 vg = br_vlan_group(br);
584 __vlan_flush(vg);
585 RCU_INIT_POINTER(br->vlgrp, NULL);
586 synchronize_rcu();
587 __vlan_group_free(vg);
577} 588}
578 589
579struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) 590struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid)
@@ -959,7 +970,13 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
959 970
960void nbp_vlan_flush(struct net_bridge_port *port) 971void nbp_vlan_flush(struct net_bridge_port *port)
961{ 972{
973 struct net_bridge_vlan_group *vg;
974
962 ASSERT_RTNL(); 975 ASSERT_RTNL();
963 976
964 __vlan_flush(nbp_vlan_group(port)); 977 vg = nbp_vlan_group(port);
978 __vlan_flush(vg);
979 RCU_INIT_POINTER(port->vlgrp, NULL);
980 synchronize_rcu();
981 __vlan_group_free(vg);
965} 982}