aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/8021q/vlan.c72
1 files changed, 32 insertions, 40 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 006d9a9bac90..ad34e4a0326a 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -142,63 +142,55 @@ static void vlan_rcu_free(struct rcu_head *rcu)
142static int unregister_vlan_dev(struct net_device *real_dev, 142static int unregister_vlan_dev(struct net_device *real_dev,
143 unsigned short vlan_id) 143 unsigned short vlan_id)
144{ 144{
145 struct net_device *dev = NULL; 145 struct net_device *dev;
146 int real_dev_ifindex = real_dev->ifindex; 146 int real_dev_ifindex = real_dev->ifindex;
147 struct vlan_group *grp; 147 struct vlan_group *grp;
148 int i, ret; 148 unsigned int i;
149 int ret;
149 150
150 /* sanity check */
151 if (vlan_id >= VLAN_VID_MASK) 151 if (vlan_id >= VLAN_VID_MASK)
152 return -EINVAL; 152 return -EINVAL;
153 153
154 ASSERT_RTNL(); 154 ASSERT_RTNL();
155 grp = __vlan_find_group(real_dev_ifindex); 155 grp = __vlan_find_group(real_dev_ifindex);
156 if (!grp)
157 return -ENOENT;
156 158
157 ret = 0; 159 dev = vlan_group_get_device(grp, vlan_id);
158 160 if (!dev)
159 if (grp) { 161 return -ENOENT;
160 dev = vlan_group_get_device(grp, vlan_id);
161 if (dev) {
162 /* Remove proc entry */
163 vlan_proc_rem_dev(dev);
164
165 /* Take it out of our own structures, but be sure to
166 * interlock with HW accelerating devices or SW vlan
167 * input packet processing.
168 */
169 if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
170 real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
171 162
172 vlan_group_set_device(grp, vlan_id, NULL); 163 vlan_proc_rem_dev(dev);
173 synchronize_net();
174 164
165 /* Take it out of our own structures, but be sure to interlock with
166 * HW accelerating devices or SW vlan input packet processing.
167 */
168 if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
169 real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
175 170
176 /* Caller unregisters (and if necessary, puts) 171 vlan_group_set_device(grp, vlan_id, NULL);
177 * VLAN device, but we get rid of the reference to 172 synchronize_net();
178 * real_dev here.
179 */
180 dev_put(real_dev);
181 173
182 /* If the group is now empty, kill off the 174 /* Caller unregisters (and if necessary, puts) VLAN device, but we
183 * group. 175 * get rid of the reference to real_dev here.
184 */ 176 */
185 for (i = 0; i < VLAN_VID_MASK; i++) 177 dev_put(real_dev);
186 if (vlan_group_get_device(grp, i))
187 break;
188 178
189 if (i == VLAN_VID_MASK) { 179 /* If the group is now empty, kill off the group. */
190 if (real_dev->features & NETIF_F_HW_VLAN_RX) 180 ret = 0;
191 real_dev->vlan_rx_register(real_dev, NULL); 181 for (i = 0; i < VLAN_VID_MASK; i++)
182 if (vlan_group_get_device(grp, i))
183 break;
192 184
193 hlist_del_rcu(&grp->hlist); 185 if (i == VLAN_VID_MASK) {
186 if (real_dev->features & NETIF_F_HW_VLAN_RX)
187 real_dev->vlan_rx_register(real_dev, NULL);
194 188
195 /* Free the group, after all cpu's are done. */ 189 hlist_del_rcu(&grp->hlist);
196 call_rcu(&grp->rcu, vlan_rcu_free);
197 190
198 grp = NULL; 191 /* Free the group, after all cpu's are done. */
199 ret = 1; 192 call_rcu(&grp->rcu, vlan_rcu_free);
200 } 193 ret = 1;
201 }
202 } 194 }
203 195
204 return ret; 196 return ret;