aboutsummaryrefslogtreecommitdiff
path: root/net/bridge/br_if.c
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2006-02-01 13:08:56 +0100
committerJaroslav Kysela <perex@suse.cz>2006-02-01 13:08:56 +0100
commit847b9d01474f710e7a018186917d05e59e258309 (patch)
treec0da8777ce350c4b048aa6ed2c41fdd109c42e92 /net/bridge/br_if.c
parentd1d051b28e9d3c3bed0bd15a2b49df3d04f7768f (diff)
parenta6df590dd8b7644c8e298e3b13442bcd6ceeb739 (diff)
Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
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 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);
}