summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2009-10-29 23:43:00 -0700
committerDavid S. Miller <davem@davemloft.net>2009-10-29 23:43:00 -0700
commit29906f6a427d2004a515ebbcdc7b28bae8f6c19c (patch)
tree12749e2d6afd82ec9c1b40aa08d012a5d4709cc6
parentf0816ce39d8de7646301aac52cc7351a2424d97f (diff)
downloadlinux-29906f6a427d2004a515ebbcdc7b28bae8f6c19c.tar.bz2
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>
-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)
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;
}