diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 511afe72af31fe92ba11e30cf706168d993625b2..39f8d0120104ce316bfe35c3f1977ec4e5af7379 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) grp->nr_vlans--; - if (!grp->killall) { - vlan_group_set_device(grp, vlan_id, NULL); + vlan_group_set_device(grp, vlan_id, NULL); + if (!grp->killall) synchronize_net(); - } + unregister_netdevice_queue(dev, head); /* 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) dev_put(real_dev); } -void unregister_vlan_dev_alls(struct vlan_group *grp) -{ - LIST_HEAD(list); - int i; - struct net_device *vlandev; - struct vlan_group save; - - memcpy(&save, grp, sizeof(save)); - memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays)); - grp->killall = 1; - - synchronize_net(); - - /* Delete all VLANs for this dev. */ - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - vlandev = vlan_group_get_device(&save, i); - if (!vlandev) - continue; - - unregister_vlan_dev(vlandev, &list); - if (grp->nr_vlans == 0) - break; - } - unregister_netdevice_many(&list); - for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) - kfree(save.vlan_devices_arrays[i]); -} - static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) { @@ -456,6 +428,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, struct vlan_group *grp; int i, flgs; struct net_device *vlandev; + LIST_HEAD(list); if (is_vlan_dev(dev)) __vlan_device_event(dev, event); @@ -553,7 +526,22 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, break; case NETDEV_UNREGISTER: - unregister_vlan_dev_alls(grp); + /* Delete all VLANs for this dev. */ + grp->killall = 1; + + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + vlandev = vlan_group_get_device(grp, i); + if (!vlandev) + continue; + + /* unregistration of last vlan destroys group, abort + * afterwards */ + if (grp->nr_vlans == 1) + i = VLAN_GROUP_ARRAY_LEN; + + unregister_vlan_dev(vlandev, &list); + } + unregister_netdevice_many(&list); break; }