[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>
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index ba44288..da687c8 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -104,6 +104,7 @@
 {
 	struct net_device *dev = p->dev;
 
+	dev->br_port = NULL;
 	p->br = NULL;
 	p->dev = NULL;
 	dev_put(dev);
@@ -118,13 +119,24 @@
 	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 @@
 
 	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);
 }