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 /include/linux | |
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 'include/linux')
-rw-r--r-- | include/linux/if_vlan.h | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 35cb38573583..d103580c72d2 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h | |||
@@ -70,15 +70,34 @@ extern void vlan_ioctl_set(int (*hook)(void __user *)); | |||
70 | * depends on completely exhausting the VLAN identifier space. Thus | 70 | * depends on completely exhausting the VLAN identifier space. Thus |
71 | * it gives constant time look-up, but in many cases it wastes memory. | 71 | * it gives constant time look-up, but in many cases it wastes memory. |
72 | */ | 72 | */ |
73 | #define VLAN_GROUP_ARRAY_LEN 4096 | 73 | #define VLAN_GROUP_ARRAY_LEN 4096 |
74 | #define VLAN_GROUP_ARRAY_SPLIT_PARTS 8 | ||
75 | #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_GROUP_ARRAY_LEN/VLAN_GROUP_ARRAY_SPLIT_PARTS) | ||
74 | 76 | ||
75 | struct vlan_group { | 77 | struct vlan_group { |
76 | int real_dev_ifindex; /* The ifindex of the ethernet(like) device the vlan is attached to. */ | 78 | int real_dev_ifindex; /* The ifindex of the ethernet(like) device the vlan is attached to. */ |
77 | struct hlist_node hlist; /* linked list */ | 79 | struct hlist_node hlist; /* linked list */ |
78 | struct net_device *vlan_devices[VLAN_GROUP_ARRAY_LEN]; | 80 | struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; |
79 | struct rcu_head rcu; | 81 | struct rcu_head rcu; |
80 | }; | 82 | }; |
81 | 83 | ||
84 | static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, int vlan_id) | ||
85 | { | ||
86 | struct net_device **array; | ||
87 | array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | ||
88 | return array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN]; | ||
89 | } | ||
90 | |||
91 | static inline void vlan_group_set_device(struct vlan_group *vg, int vlan_id, | ||
92 | struct net_device *dev) | ||
93 | { | ||
94 | struct net_device **array; | ||
95 | if (!vg) | ||
96 | return; | ||
97 | array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | ||
98 | array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; | ||
99 | } | ||
100 | |||
82 | struct vlan_priority_tci_mapping { | 101 | struct vlan_priority_tci_mapping { |
83 | unsigned long priority; | 102 | unsigned long priority; |
84 | unsigned short vlan_qos; /* This should be shifted when first set, so we only do it | 103 | unsigned short vlan_qos; /* This should be shifted when first set, so we only do it |
@@ -160,7 +179,7 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, | |||
160 | return NET_RX_DROP; | 179 | return NET_RX_DROP; |
161 | } | 180 | } |
162 | 181 | ||
163 | skb->dev = grp->vlan_devices[vlan_tag & VLAN_VID_MASK]; | 182 | skb->dev = vlan_group_get_device(grp, vlan_tag & VLAN_VID_MASK); |
164 | if (skb->dev == NULL) { | 183 | if (skb->dev == NULL) { |
165 | dev_kfree_skb_any(skb); | 184 | dev_kfree_skb_any(skb); |
166 | 185 | ||