aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2009-10-30 02:43:00 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-30 02:43:00 -0400
commit29906f6a427d2004a515ebbcdc7b28bae8f6c19c (patch)
tree12749e2d6afd82ec9c1b40aa08d012a5d4709cc6 /net/8021q
parentf0816ce39d8de7646301aac52cc7351a2424d97f (diff)
vlan: cleanup multiple unregistrations
The temporary copy of the VLAN group is not neccessary since the lower device is already in the process of being unregistered, if it was neccessary the memset of the global group would introduce a race condition. With this removed, the changes to the original code are only a few lines, so remove the new function and move the code back into vlan_device_event(). Signed-off-by: Patrick McHardy <kaber@trash.net> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q')
-rw-r--r--net/8021q/vlan.c52
1 files changed, 20 insertions, 32 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 511afe72af31..39f8d0120104 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -161,10 +161,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
161 161
162 grp->nr_vlans--; 162 grp->nr_vlans--;
163 163
164 if (!grp->killall) { 164 vlan_group_set_device(grp, vlan_id, NULL);
165 vlan_group_set_device(grp, vlan_id, NULL); 165 if (!grp->killall)
166 synchronize_net(); 166 synchronize_net();
167 } 167
168 unregister_netdevice_queue(dev, head); 168 unregister_netdevice_queue(dev, head);
169 169
170 /* If the group is now empty, kill off the group. */ 170 /* If the group is now empty, kill off the group. */
@@ -184,34 +184,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
184 dev_put(real_dev); 184 dev_put(real_dev);
185} 185}
186 186
187void unregister_vlan_dev_alls(struct vlan_group *grp)
188{
189 LIST_HEAD(list);
190 int i;
191 struct net_device *vlandev;
192 struct vlan_group save;
193
194 memcpy(&save, grp, sizeof(save));
195 memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays));
196 grp->killall = 1;
197
198 synchronize_net();
199
200 /* Delete all VLANs for this dev. */
201 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
202 vlandev = vlan_group_get_device(&save, i);
203 if (!vlandev)
204 continue;
205
206 unregister_vlan_dev(vlandev, &list);
207 if (grp->nr_vlans == 0)
208 break;
209 }
210 unregister_netdevice_many(&list);
211 for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
212 kfree(save.vlan_devices_arrays[i]);
213}
214
215static void vlan_transfer_operstate(const struct net_device *dev, 187static void vlan_transfer_operstate(const struct net_device *dev,
216 struct net_device *vlandev) 188 struct net_device *vlandev)
217{ 189{
@@ -456,6 +428,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
456 struct vlan_group *grp; 428 struct vlan_group *grp;
457 int i, flgs; 429 int i, flgs;
458 struct net_device *vlandev; 430 struct net_device *vlandev;
431 LIST_HEAD(list);
459 432
460 if (is_vlan_dev(dev)) 433 if (is_vlan_dev(dev))
461 __vlan_device_event(dev, event); 434 __vlan_device_event(dev, event);
@@ -553,7 +526,22 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
553 break; 526 break;
554 527
555 case NETDEV_UNREGISTER: 528 case NETDEV_UNREGISTER:
556 unregister_vlan_dev_alls(grp); 529 /* Delete all VLANs for this dev. */
530 grp->killall = 1;
531
532 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
533 vlandev = vlan_group_get_device(grp, i);
534 if (!vlandev)
535 continue;
536
537 /* unregistration of last vlan destroys group, abort
538 * afterwards */
539 if (grp->nr_vlans == 1)
540 i = VLAN_GROUP_ARRAY_LEN;
541
542 unregister_vlan_dev(vlandev, &list);
543 }
544 unregister_netdevice_many(&list);
557 break; 545 break;
558 } 546 }
559 547