diff options
-rw-r--r-- | net/bridge/br_if.c | 3 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 31 |
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 | ||
138 | struct net_bridge_fdb_entry | 137 | struct 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 | ||
310 | static void __vlan_flush(struct net_bridge_vlan_group *vlgrp) | 310 | static 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 | |||
317 | static 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 | ||
321 | struct sk_buff *br_handle_vlan(struct net_bridge *br, | 326 | struct 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 | ||
572 | void br_vlan_flush(struct net_bridge *br) | 577 | void 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 | ||
579 | struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) | 590 | struct 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 | ||
960 | void nbp_vlan_flush(struct net_bridge_port *port) | 971 | void 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 | } |