aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2008-03-26 19:27:22 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-26 19:27:22 -0400
commit67727184f28c38d06013c6659560bb046c1d9f9c (patch)
treefce5871c7fe554e05aa61fcc2d2d86afe7befdbc /net
parent789e41e6f496022ac1639aaae38ea1943606a9d0 (diff)
[VLAN]: Reduce memory consumed by vlan_groups
Currently each vlan_groupd contains 8 pointers on arrays with 512 pointers on struct net_device each :) Such a construction "in many cases ... wastes memory". My proposal is to allow for some of these arrays pointers be NULL, meaning that there are no devices in it. When a new device is added to the vlan_group, the appropriate array is allocated. The check in vlan_group_get_device's is safe, since the pointer vg->vlan_devices_arrays[x] can only switch from NULL to not-NULL. The vlan_group_prealloc_vid() is guarded with rtnl lock and is also safe. I've checked (I hope that) all the places, that use these arrays and found, that the register_vlan_dev is the only place, that can put a vlan device on an empty vlan_group. Rough calculations shows, that after the patch a setup with a single vlan dev (or up to 512 vlans with sequential vids) will occupy approximately 8 times less memory. The question I have is - does this patch makes sense, or a totally new structures are required to store the vlan_devs? Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index c35dc230365c..694be86e4490 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -106,29 +106,35 @@ static void vlan_group_free(struct vlan_group *grp)
106static struct vlan_group *vlan_group_alloc(int ifindex) 106static struct vlan_group *vlan_group_alloc(int ifindex)
107{ 107{
108 struct vlan_group *grp; 108 struct vlan_group *grp;
109 unsigned int size;
110 unsigned int i;
111 109
112 grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL); 110 grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
113 if (!grp) 111 if (!grp)
114 return NULL; 112 return NULL;
115 113
116 size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
117
118 for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
119 grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL);
120 if (!grp->vlan_devices_arrays[i])
121 goto err;
122 }
123
124 grp->real_dev_ifindex = ifindex; 114 grp->real_dev_ifindex = ifindex;
125 hlist_add_head_rcu(&grp->hlist, 115 hlist_add_head_rcu(&grp->hlist,
126 &vlan_group_hash[vlan_grp_hashfn(ifindex)]); 116 &vlan_group_hash[vlan_grp_hashfn(ifindex)]);
127 return grp; 117 return grp;
118}
128 119
129err: 120static int vlan_group_prealloc_vid(struct vlan_group *vg, int vid)
130 vlan_group_free(grp); 121{
131 return NULL; 122 struct net_device **array;
123 unsigned int size;
124
125 ASSERT_RTNL();
126
127 array = vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN];
128 if (array != NULL)
129 return 0;
130
131 size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
132 array = kzalloc(size, GFP_KERNEL);
133 if (array == NULL)
134 return -ENOBUFS;
135
136 vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN] = array;
137 return 0;
132} 138}
133 139
134static void vlan_rcu_free(struct rcu_head *rcu) 140static void vlan_rcu_free(struct rcu_head *rcu)
@@ -247,6 +253,10 @@ int register_vlan_dev(struct net_device *dev)
247 return -ENOBUFS; 253 return -ENOBUFS;
248 } 254 }
249 255
256 err = vlan_group_prealloc_vid(grp, vlan_id);
257 if (err < 0)
258 goto out_free_group;
259
250 err = register_netdevice(dev); 260 err = register_netdevice(dev);
251 if (err < 0) 261 if (err < 0)
252 goto out_free_group; 262 goto out_free_group;