diff options
author | Dan Aloni <da-x@monatomic.org> | 2007-03-02 23:44:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-03-02 23:44:51 -0500 |
commit | 5c15bdec5c38f4ccf73ef2585fc80a6164de9554 (patch) | |
tree | c99084e96238eb9ce40e8d9d90e0097c4e92111d /net/8021q | |
parent | b5284e5aa94be2f88dc92b29e97aff3da0c45f9f (diff) |
[VLAN]: Avoid a 4-order allocation.
This patch splits the vlan_group struct into a multi-allocated struct. On
x86_64, the size of the original struct is a little more than 32KB, causing
a 4-order allocation, which is prune to problems caused by buddy-system
external fragmentation conditions.
I couldn't just use vmalloc() because vfree() cannot be called in the
softirq context of the RCU callback.
Signed-off-by: Dan Aloni <da-x@monatomic.org>
Acked-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/vlan.c | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index c1c205fad4fb..eb1c71ed7dfe 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -184,14 +184,23 @@ struct net_device *__find_vlan_dev(struct net_device *real_dev, | |||
184 | struct vlan_group *grp = __vlan_find_group(real_dev->ifindex); | 184 | struct vlan_group *grp = __vlan_find_group(real_dev->ifindex); |
185 | 185 | ||
186 | if (grp) | 186 | if (grp) |
187 | return grp->vlan_devices[VID]; | 187 | return vlan_group_get_device(grp, VID); |
188 | 188 | ||
189 | return NULL; | 189 | return NULL; |
190 | } | 190 | } |
191 | 191 | ||
192 | static void vlan_group_free(struct vlan_group *grp) | ||
193 | { | ||
194 | int i; | ||
195 | |||
196 | for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) | ||
197 | kfree(grp->vlan_devices_arrays[i]); | ||
198 | kfree(grp); | ||
199 | } | ||
200 | |||
192 | static void vlan_rcu_free(struct rcu_head *rcu) | 201 | static void vlan_rcu_free(struct rcu_head *rcu) |
193 | { | 202 | { |
194 | kfree(container_of(rcu, struct vlan_group, rcu)); | 203 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); |
195 | } | 204 | } |
196 | 205 | ||
197 | 206 | ||
@@ -223,7 +232,7 @@ static int unregister_vlan_dev(struct net_device *real_dev, | |||
223 | ret = 0; | 232 | ret = 0; |
224 | 233 | ||
225 | if (grp) { | 234 | if (grp) { |
226 | dev = grp->vlan_devices[vlan_id]; | 235 | dev = vlan_group_get_device(grp, vlan_id); |
227 | if (dev) { | 236 | if (dev) { |
228 | /* Remove proc entry */ | 237 | /* Remove proc entry */ |
229 | vlan_proc_rem_dev(dev); | 238 | vlan_proc_rem_dev(dev); |
@@ -237,7 +246,7 @@ static int unregister_vlan_dev(struct net_device *real_dev, | |||
237 | real_dev->vlan_rx_kill_vid(real_dev, vlan_id); | 246 | real_dev->vlan_rx_kill_vid(real_dev, vlan_id); |
238 | } | 247 | } |
239 | 248 | ||
240 | grp->vlan_devices[vlan_id] = NULL; | 249 | vlan_group_set_device(grp, vlan_id, NULL); |
241 | synchronize_net(); | 250 | synchronize_net(); |
242 | 251 | ||
243 | 252 | ||
@@ -251,7 +260,7 @@ static int unregister_vlan_dev(struct net_device *real_dev, | |||
251 | * group. | 260 | * group. |
252 | */ | 261 | */ |
253 | for (i = 0; i < VLAN_VID_MASK; i++) | 262 | for (i = 0; i < VLAN_VID_MASK; i++) |
254 | if (grp->vlan_devices[i]) | 263 | if (vlan_group_get_device(grp, i)) |
255 | break; | 264 | break; |
256 | 265 | ||
257 | if (i == VLAN_VID_MASK) { | 266 | if (i == VLAN_VID_MASK) { |
@@ -379,6 +388,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
379 | struct net_device *new_dev; | 388 | struct net_device *new_dev; |
380 | struct net_device *real_dev; /* the ethernet device */ | 389 | struct net_device *real_dev; /* the ethernet device */ |
381 | char name[IFNAMSIZ]; | 390 | char name[IFNAMSIZ]; |
391 | int i; | ||
382 | 392 | ||
383 | #ifdef VLAN_DEBUG | 393 | #ifdef VLAN_DEBUG |
384 | printk(VLAN_DBG "%s: if_name -:%s:- vid: %i\n", | 394 | printk(VLAN_DBG "%s: if_name -:%s:- vid: %i\n", |
@@ -544,6 +554,15 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
544 | if (!grp) | 554 | if (!grp) |
545 | goto out_free_unregister; | 555 | goto out_free_unregister; |
546 | 556 | ||
557 | for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) { | ||
558 | grp->vlan_devices_arrays[i] = kzalloc( | ||
559 | sizeof(struct net_device *)*VLAN_GROUP_ARRAY_PART_LEN, | ||
560 | GFP_KERNEL); | ||
561 | |||
562 | if (!grp->vlan_devices_arrays[i]) | ||
563 | goto out_free_arrays; | ||
564 | } | ||
565 | |||
547 | /* printk(KERN_ALERT "VLAN REGISTER: Allocated new group.\n"); */ | 566 | /* printk(KERN_ALERT "VLAN REGISTER: Allocated new group.\n"); */ |
548 | grp->real_dev_ifindex = real_dev->ifindex; | 567 | grp->real_dev_ifindex = real_dev->ifindex; |
549 | 568 | ||
@@ -554,7 +573,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
554 | real_dev->vlan_rx_register(real_dev, grp); | 573 | real_dev->vlan_rx_register(real_dev, grp); |
555 | } | 574 | } |
556 | 575 | ||
557 | grp->vlan_devices[VLAN_ID] = new_dev; | 576 | vlan_group_set_device(grp, VLAN_ID, new_dev); |
558 | 577 | ||
559 | if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */ | 578 | if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */ |
560 | printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n", | 579 | printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n", |
@@ -571,6 +590,9 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
571 | #endif | 590 | #endif |
572 | return new_dev; | 591 | return new_dev; |
573 | 592 | ||
593 | out_free_arrays: | ||
594 | vlan_group_free(grp); | ||
595 | |||
574 | out_free_unregister: | 596 | out_free_unregister: |
575 | unregister_netdev(new_dev); | 597 | unregister_netdev(new_dev); |
576 | goto out_unlock; | 598 | goto out_unlock; |
@@ -606,7 +628,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
606 | case NETDEV_CHANGE: | 628 | case NETDEV_CHANGE: |
607 | /* Propagate real device state to vlan devices */ | 629 | /* Propagate real device state to vlan devices */ |
608 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 630 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
609 | vlandev = grp->vlan_devices[i]; | 631 | vlandev = vlan_group_get_device(grp, i); |
610 | if (!vlandev) | 632 | if (!vlandev) |
611 | continue; | 633 | continue; |
612 | 634 | ||
@@ -617,7 +639,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
617 | case NETDEV_DOWN: | 639 | case NETDEV_DOWN: |
618 | /* Put all VLANs for this dev in the down state too. */ | 640 | /* Put all VLANs for this dev in the down state too. */ |
619 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 641 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
620 | vlandev = grp->vlan_devices[i]; | 642 | vlandev = vlan_group_get_device(grp, i); |
621 | if (!vlandev) | 643 | if (!vlandev) |
622 | continue; | 644 | continue; |
623 | 645 | ||
@@ -632,7 +654,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
632 | case NETDEV_UP: | 654 | case NETDEV_UP: |
633 | /* Put all VLANs for this dev in the up state too. */ | 655 | /* Put all VLANs for this dev in the up state too. */ |
634 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 656 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
635 | vlandev = grp->vlan_devices[i]; | 657 | vlandev = vlan_group_get_device(grp, i); |
636 | if (!vlandev) | 658 | if (!vlandev) |
637 | continue; | 659 | continue; |
638 | 660 | ||
@@ -649,7 +671,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
649 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 671 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
650 | int ret; | 672 | int ret; |
651 | 673 | ||
652 | vlandev = grp->vlan_devices[i]; | 674 | vlandev = vlan_group_get_device(grp, i); |
653 | if (!vlandev) | 675 | if (!vlandev) |
654 | continue; | 676 | continue; |
655 | 677 | ||