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

Commit 3f4cfc2d authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller
Browse files

[BRIDGE]: Fix device delete race.



This is a simpler fix for the two races in bridge device removal.
The Xen race of delif and notify is managed now by a new deleted flag.
No need for barriers or other locking because of rtnl mutex.

The del_timer_sync()'s are unnecessary, because br_stp_disable_port
delete's the timers, and they will finish running before RCU callback.

Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5d39a795
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p)
{
	struct net_device *dev = p->dev;

	dev->br_port = NULL;
	p->br = NULL;
	p->dev = NULL;
	dev_put(dev);
@@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head)
	destroy_nbp(p);
}

/* called with RTNL */
/* Delete port(interface) from bridge is done in two steps.
 * via RCU. First step, marks device as down. That deletes
 * all the timers and stops new packets from flowing through.
 *
 * Final cleanup doesn't occur until after all CPU's finished
 * processing packets.
 *
 * Protected from multiple admin operations by RTNL mutex
 */
static void del_nbp(struct net_bridge_port *p)
{
	struct net_bridge *br = p->br;
	struct net_device *dev = p->dev;

	dev->br_port = NULL;
	/* Race between RTNL notify and RCU callback */
	if (p->deleted)
		return;

	dev_set_promiscuity(dev, -1);

	cancel_delayed_work(&p->carrier_check);
@@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p)

	spin_lock_bh(&br->lock);
	br_stp_disable_port(p);
	p->deleted = 1;
	spin_unlock_bh(&br->lock);

	br_fdb_delete_by_port(br, p);

	list_del_rcu(&p->list);

	del_timer_sync(&p->message_age_timer);
	del_timer_sync(&p->forward_delay_timer);
	del_timer_sync(&p->hold_timer);
	
	call_rcu(&p->rcu, destroy_nbp_rcu);
}

+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ struct net_bridge_port
	/* STP */
	u8				priority;
	u8				state;
	u8				deleted;
	u16				port_no;
	unsigned char			topology_change_ack;
	unsigned char			config_pending;