[BRIDGE]: Fix device delete race.
authorStephen Hemminger <shemminger@osdl.org>
Wed, 1 Feb 2006 01:44:07 +0000 (17:44 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 1 Feb 2006 01:44:07 +0000 (17:44 -0800)
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>
net/bridge/br_if.c
net/bridge/br_private.h

index ba442883e877fbda4808db858f215ac9c30334df..da687c8dc6ff013e62f04b535f2a26483e4db284 100644 (file)
@@ -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);
 }
 
index c5bd631ffcd5793d67c29009151c380b6af03cac..e330b17b6d816620f2706fc4eab15c1f4ef21481 100644 (file)
@@ -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;