mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 14:50:19 +00:00
[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: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5d39a795bf
commit
3f4cfc2d11
@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p)
|
|||||||
{
|
{
|
||||||
struct net_device *dev = p->dev;
|
struct net_device *dev = p->dev;
|
||||||
|
|
||||||
|
dev->br_port = NULL;
|
||||||
p->br = NULL;
|
p->br = NULL;
|
||||||
p->dev = NULL;
|
p->dev = NULL;
|
||||||
dev_put(dev);
|
dev_put(dev);
|
||||||
@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head)
|
|||||||
destroy_nbp(p);
|
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)
|
static void del_nbp(struct net_bridge_port *p)
|
||||||
{
|
{
|
||||||
struct net_bridge *br = p->br;
|
struct net_bridge *br = p->br;
|
||||||
struct net_device *dev = p->dev;
|
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);
|
dev_set_promiscuity(dev, -1);
|
||||||
|
|
||||||
cancel_delayed_work(&p->carrier_check);
|
cancel_delayed_work(&p->carrier_check);
|
||||||
@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p)
|
|||||||
|
|
||||||
spin_lock_bh(&br->lock);
|
spin_lock_bh(&br->lock);
|
||||||
br_stp_disable_port(p);
|
br_stp_disable_port(p);
|
||||||
|
p->deleted = 1;
|
||||||
spin_unlock_bh(&br->lock);
|
spin_unlock_bh(&br->lock);
|
||||||
|
|
||||||
br_fdb_delete_by_port(br, p);
|
br_fdb_delete_by_port(br, p);
|
||||||
|
|
||||||
list_del_rcu(&p->list);
|
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);
|
call_rcu(&p->rcu, destroy_nbp_rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ struct net_bridge_port
|
|||||||
/* STP */
|
/* STP */
|
||||||
u8 priority;
|
u8 priority;
|
||||||
u8 state;
|
u8 state;
|
||||||
|
u8 deleted;
|
||||||
u16 port_no;
|
u16 port_no;
|
||||||
unsigned char topology_change_ack;
|
unsigned char topology_change_ack;
|
||||||
unsigned char config_pending;
|
unsigned char config_pending;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user