diff options
author | Steve French <sfrench@us.ibm.com> | 2006-02-01 15:16:53 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-02-01 15:16:53 -0500 |
commit | e6da74e1f20ea7822e52a9e4fbd3d25bd907e471 (patch) | |
tree | d9b3bc7e654fb788d1cf3a1759b1b3c74cc56a04 /net/bridge/br_if.c | |
parent | 1877c9ea66a29563987f22d0a86c66f438a87ce2 (diff) | |
parent | 3c3b809e256c417847f1a96b2f9d9f66c7fcb02c (diff) |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
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 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) | |||
104 | { | 104 | { |
105 | struct net_device *dev = p->dev; | 105 | struct net_device *dev = p->dev; |
106 | 106 | ||
107 | dev->br_port = NULL; | ||
107 | p->br = NULL; | 108 | p->br = NULL; |
108 | p->dev = NULL; | 109 | p->dev = NULL; |
109 | dev_put(dev); | 110 | dev_put(dev); |
@@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head) | |||
118 | destroy_nbp(p); | 119 | destroy_nbp(p); |
119 | } | 120 | } |
120 | 121 | ||
121 | /* called with RTNL */ | 122 | /* Delete port(interface) from bridge is done in two steps. |
123 | * via RCU. First step, marks device as down. That deletes | ||
124 | * all the timers and stops new packets from flowing through. | ||
125 | * | ||
126 | * Final cleanup doesn't occur until after all CPU's finished | ||
127 | * processing packets. | ||
128 | * | ||
129 | * Protected from multiple admin operations by RTNL mutex | ||
130 | */ | ||
122 | static void del_nbp(struct net_bridge_port *p) | 131 | static void del_nbp(struct net_bridge_port *p) |
123 | { | 132 | { |
124 | struct net_bridge *br = p->br; | 133 | struct net_bridge *br = p->br; |
125 | struct net_device *dev = p->dev; | 134 | struct net_device *dev = p->dev; |
126 | 135 | ||
127 | dev->br_port = NULL; | 136 | /* Race between RTNL notify and RCU callback */ |
137 | if (p->deleted) | ||
138 | return; | ||
139 | |||
128 | dev_set_promiscuity(dev, -1); | 140 | dev_set_promiscuity(dev, -1); |
129 | 141 | ||
130 | cancel_delayed_work(&p->carrier_check); | 142 | cancel_delayed_work(&p->carrier_check); |
@@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p) | |||
132 | 144 | ||
133 | spin_lock_bh(&br->lock); | 145 | spin_lock_bh(&br->lock); |
134 | br_stp_disable_port(p); | 146 | br_stp_disable_port(p); |
147 | p->deleted = 1; | ||
135 | spin_unlock_bh(&br->lock); | 148 | spin_unlock_bh(&br->lock); |
136 | 149 | ||
137 | br_fdb_delete_by_port(br, p); | 150 | br_fdb_delete_by_port(br, p); |
138 | 151 | ||
139 | list_del_rcu(&p->list); | 152 | list_del_rcu(&p->list); |
140 | 153 | ||
141 | del_timer_sync(&p->message_age_timer); | ||
142 | del_timer_sync(&p->forward_delay_timer); | ||
143 | del_timer_sync(&p->hold_timer); | ||
144 | |||
145 | call_rcu(&p->rcu, destroy_nbp_rcu); | 154 | call_rcu(&p->rcu, destroy_nbp_rcu); |
146 | } | 155 | } |
147 | 156 | ||