Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f409d0ed authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller
Browse files

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: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Reviewed-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b8d02c3c
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -248,6 +248,7 @@ static void del_nbp(struct net_bridge_port *p)

	list_del_rcu(&p->list);

	nbp_vlan_flush(p);
	br_fdb_delete_by_port(br, p, 0, 1);
	nbp_update_port_count(br);

@@ -256,8 +257,6 @@ static void del_nbp(struct net_bridge_port *p)
	dev->priv_flags &= ~IFF_BRIDGE_PORT;

	netdev_rx_handler_unregister(dev);
	/* use the synchronize_rcu done by netdev_rx_handler_unregister */
	nbp_vlan_flush(p);

	br_multicast_del_port(p);

+0 −1
Original line number Diff line number Diff line
@@ -132,7 +132,6 @@ struct net_bridge_vlan_group {
	struct list_head		vlan_list;
	u16				num_vlans;
	u16				pvid;
	struct rcu_head			rcu;
};

struct net_bridge_fdb_entry
+24 −7
Original line number Diff line number Diff line
@@ -307,15 +307,20 @@ static int __vlan_del(struct net_bridge_vlan *v)
	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);
}