summaryrefslogtreecommitdiffstats
path: root/net/bridge/br_vlan.c
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>2015-10-12 21:47:05 +0200
committerDavid S. Miller <davem@davemloft.net>2015-10-13 04:57:58 -0700
commitf409d0ed87d2721e1099ce36266e98c5aea2d486 (patch)
treeebe13617bfc4b22390d6a73f73f9a1db9b20deb6 /net/bridge/br_vlan.c
parentb8d02c3cace37393bf9ff0a9eaa1ee39cda1d259 (diff)
downloadlinux-f409d0ed87d2721e1099ce36266e98c5aea2d486.tar.bz2
bridge: vlan: move back vlan_flush
Ido Schimmel reported a problem with switchdev devices because of the order change of del_nbp operations, more specifically the move of nbp_vlan_flush() which deletes all vlans and frees vlgrp after the rx_handler has been unregistered. So in order to fix this move vlan_flush back where it was and make it destroy the rhtable after NULLing vlgrp and waiting a grace period to make sure noone can see it. Reported-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_vlan.c')
-rw-r--r--net/bridge/br_vlan.c31
1 files changed, 24 insertions, 7 deletions
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:
return err;
}
-static void __vlan_flush(struct net_bridge_vlan_group *vlgrp)
+static void __vlan_group_free(struct net_bridge_vlan_group *vg)
+{
+ WARN_ON(!list_empty(&vg->vlan_list));
+ rhashtable_destroy(&vg->vlan_hash);
+ kfree(vg);
+}
+
+static void __vlan_flush(struct net_bridge_vlan_group *vg)
{
struct net_bridge_vlan *vlan, *tmp;
- __vlan_delete_pvid(vlgrp, vlgrp->pvid);
- list_for_each_entry_safe(vlan, tmp, &vlgrp->vlan_list, vlist)
+ __vlan_delete_pvid(vg, vg->pvid);
+ list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist)
__vlan_del(vlan);
- rhashtable_destroy(&vlgrp->vlan_hash);
- kfree_rcu(vlgrp, rcu);
}
struct sk_buff *br_handle_vlan(struct net_bridge *br,
@@ -571,9 +576,15 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
void br_vlan_flush(struct net_bridge *br)
{
+ struct net_bridge_vlan_group *vg;
+
ASSERT_RTNL();
- __vlan_flush(br_vlan_group(br));
+ vg = br_vlan_group(br);
+ __vlan_flush(vg);
+ RCU_INIT_POINTER(br->vlgrp, NULL);
+ synchronize_rcu();
+ __vlan_group_free(vg);
}
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)
void nbp_vlan_flush(struct net_bridge_port *port)
{
+ struct net_bridge_vlan_group *vg;
+
ASSERT_RTNL();
- __vlan_flush(nbp_vlan_group(port));
+ vg = nbp_vlan_group(port);
+ __vlan_flush(vg);
+ RCU_INIT_POINTER(port->vlgrp, NULL);
+ synchronize_rcu();
+ __vlan_group_free(vg);
}