aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/if_vlan.h2
-rw-r--r--net/8021q/vlan.c36
2 files changed, 24 insertions, 14 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 79504b22a932..edd55af7ebd6 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -93,7 +93,7 @@ static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
93{ 93{
94 struct net_device **array; 94 struct net_device **array;
95 array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; 95 array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
96 return array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN]; 96 return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
97} 97}
98 98
99static inline void vlan_group_set_device(struct vlan_group *vg, 99static inline void vlan_group_set_device(struct vlan_group *vg,
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;