diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2006-02-02 01:12:54 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-02-02 01:12:54 -0500 |
commit | 18ee3610040a4c008ce08a40a5dd025241cc7e97 (patch) | |
tree | 32a996a5123726b63c31a1522f230933fb967a32 /net/bridge/br_if.c | |
parent | e4e7b89280d1d666e2c09e5ad36cf071796c4c7e (diff) | |
parent | b4103333d7904310d34de18d85e51e3d74f00a3b (diff) |
Merge branch 'master'
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r-- | net/bridge/br_if.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index ba442883e87..da687c8dc6f 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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); } |