summaryrefslogtreecommitdiff
path: root/net/bridge/br_if.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2006-02-06 15:43:13 +0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-02-06 15:43:13 +0300
commitb2faf597d93bdf5e2d12d93ea0815935a73f749e (patch)
tree1876616290ff282b8a0814e2429d23e0104f3701 /net/bridge/br_if.c
parent638e174688f58200d0deb7435093435e7d737b09 (diff)
parent410c05427a69f53851637ccb85c2212131409fbd (diff)
downloadlinux-b2faf597d93bdf5e2d12d93ea0815935a73f749e.tar.xz
Merge branch 'origin'
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r--net/bridge/br_if.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index ba442883e877..da687c8dc6ff 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);
}