Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Patrick McHardy and committed by
David S. Miller
29906f6a f0816ce3

+20 -32
+20 -32
net/8021q/vlan.c
··· 161 161 162 162 grp->nr_vlans--; 163 163 164 - if (!grp->killall) { 165 - vlan_group_set_device(grp, vlan_id, NULL); 164 + vlan_group_set_device(grp, vlan_id, NULL); 165 + if (!grp->killall) 166 166 synchronize_net(); 167 - } 167 + 168 168 unregister_netdevice_queue(dev, head); 169 169 170 170 /* If the group is now empty, kill off the group. */ ··· 182 182 183 183 /* Get rid of the vlan's reference to real_dev */ 184 184 dev_put(real_dev); 185 - } 186 - 187 - void 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 185 } 214 186 215 187 static void vlan_transfer_operstate(const struct net_device *dev, ··· 428 456 struct vlan_group *grp; 429 457 int i, flgs; 430 458 struct net_device *vlandev; 459 + LIST_HEAD(list); 431 460 432 461 if (is_vlan_dev(dev)) 433 462 __vlan_device_event(dev, event); ··· 526 553 break; 527 554 528 555 case NETDEV_UNREGISTER: 529 - unregister_vlan_dev_alls(grp); 556 + /* Delete all VLANs for this dev. */ 557 + grp->killall = 1; 558 + 559 + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { 560 + vlandev = vlan_group_get_device(grp, i); 561 + if (!vlandev) 562 + continue; 563 + 564 + /* unregistration of last vlan destroys group, abort 565 + * afterwards */ 566 + if (grp->nr_vlans == 1) 567 + i = VLAN_GROUP_ARRAY_LEN; 568 + 569 + unregister_vlan_dev(vlandev, &list); 570 + } 571 + unregister_netdevice_many(&list); 530 572 break; 531 573 } 532 574