aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-10-27 03:06:49 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-28 05:22:08 -0400
commit63c8099d90096db56ee1c66c31f05d4fcfbc1c69 (patch)
tree1c0393ab776d49476858a4f97b3d60597330f370
parent23289a37e2b127dfc4de1313fba15bb4c9f0cd5b (diff)
vlan: Optimize multiple unregistration
Use unregister_netdevice_many() to speedup master device unregister. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_vlan.h1
-rw-r--r--net/8021q/vlan.c49
-rw-r--r--net/core/dev.c1
3 files changed, 35 insertions, 16 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 8898cbebcf34..71a4870c09a9 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -85,6 +85,7 @@ struct vlan_group {
85 * the vlan is attached to. 85 * the vlan is attached to.
86 */ 86 */
87 unsigned int nr_vlans; 87 unsigned int nr_vlans;
88 int killall;
88 struct hlist_node hlist; /* linked list */ 89 struct hlist_node hlist; /* linked list */
89 struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; 90 struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS];
90 struct rcu_head rcu; 91 struct rcu_head rcu;
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 6b5c9dddaa72..511afe72af31 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -159,11 +159,12 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
159 if (real_dev->features & NETIF_F_HW_VLAN_FILTER) 159 if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
160 ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); 160 ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
161 161
162 vlan_group_set_device(grp, vlan_id, NULL);
163 grp->nr_vlans--; 162 grp->nr_vlans--;
164 163
165 synchronize_net(); 164 if (!grp->killall) {
166 165 vlan_group_set_device(grp, vlan_id, NULL);
166 synchronize_net();
167 }
167 unregister_netdevice_queue(dev, head); 168 unregister_netdevice_queue(dev, head);
168 169
169 /* If the group is now empty, kill off the group. */ 170 /* If the group is now empty, kill off the group. */
@@ -183,6 +184,34 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
183 dev_put(real_dev); 184 dev_put(real_dev);
184} 185}
185 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
186static void vlan_transfer_operstate(const struct net_device *dev, 215static void vlan_transfer_operstate(const struct net_device *dev,
187 struct net_device *vlandev) 216 struct net_device *vlandev)
188{ 217{
@@ -524,19 +553,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
524 break; 553 break;
525 554
526 case NETDEV_UNREGISTER: 555 case NETDEV_UNREGISTER:
527 /* Delete all VLANs for this dev. */ 556 unregister_vlan_dev_alls(grp);
528 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
529 vlandev = vlan_group_get_device(grp, i);
530 if (!vlandev)
531 continue;
532
533 /* unregistration of last vlan destroys group, abort
534 * afterwards */
535 if (grp->nr_vlans == 1)
536 i = VLAN_GROUP_ARRAY_LEN;
537
538 unregister_vlan_dev(vlandev, NULL);
539 }
540 break; 557 break;
541 } 558 }
542 559
diff --git a/net/core/dev.c b/net/core/dev.c
index 4513dfd5718e..09551cc143a9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5303,6 +5303,7 @@ void unregister_netdevice_many(struct list_head *head)
5303 net_set_todo(dev); 5303 net_set_todo(dev);
5304 } 5304 }
5305} 5305}
5306EXPORT_SYMBOL(unregister_netdevice_many);
5306 5307
5307/** 5308/**
5308 * unregister_netdev - remove device from the kernel 5309 * unregister_netdev - remove device from the kernel