aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q/vlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r--net/8021q/vlan.c90
1 files changed, 30 insertions, 60 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index dd9aa400888b..efea35b02e7f 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -51,27 +51,6 @@ const char vlan_version[] = DRV_VERSION;
51 51
52/* End of global variables definitions. */ 52/* End of global variables definitions. */
53 53
54static void vlan_group_free(struct vlan_group *grp)
55{
56 int i;
57
58 for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
59 kfree(grp->vlan_devices_arrays[i]);
60 kfree(grp);
61}
62
63static struct vlan_group *vlan_group_alloc(struct net_device *real_dev)
64{
65 struct vlan_group *grp;
66
67 grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
68 if (!grp)
69 return NULL;
70
71 grp->real_dev = real_dev;
72 return grp;
73}
74
75static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id) 54static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
76{ 55{
77 struct net_device **array; 56 struct net_device **array;
@@ -92,22 +71,20 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
92 return 0; 71 return 0;
93} 72}
94 73
95static void vlan_rcu_free(struct rcu_head *rcu)
96{
97 vlan_group_free(container_of(rcu, struct vlan_group, rcu));
98}
99
100void unregister_vlan_dev(struct net_device *dev, struct list_head *head) 74void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
101{ 75{
102 struct vlan_dev_priv *vlan = vlan_dev_priv(dev); 76 struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
103 struct net_device *real_dev = vlan->real_dev; 77 struct net_device *real_dev = vlan->real_dev;
78 struct vlan_info *vlan_info;
104 struct vlan_group *grp; 79 struct vlan_group *grp;
105 u16 vlan_id = vlan->vlan_id; 80 u16 vlan_id = vlan->vlan_id;
106 81
107 ASSERT_RTNL(); 82 ASSERT_RTNL();
108 83
109 grp = rtnl_dereference(real_dev->vlgrp); 84 vlan_info = rtnl_dereference(real_dev->vlan_info);
110 BUG_ON(!grp); 85 BUG_ON(!vlan_info);
86
87 grp = &vlan_info->grp;
111 88
112 /* Take it out of our own structures, but be sure to interlock with 89 /* Take it out of our own structures, but be sure to interlock with
113 * HW accelerating devices or SW vlan input packet processing if 90 * HW accelerating devices or SW vlan input packet processing if
@@ -116,7 +93,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
116 if (vlan_id) 93 if (vlan_id)
117 vlan_vid_del(real_dev, vlan_id); 94 vlan_vid_del(real_dev, vlan_id);
118 95
119 grp->nr_vlans--; 96 grp->nr_vlan_devs--;
120 97
121 if (vlan->flags & VLAN_FLAG_GVRP) 98 if (vlan->flags & VLAN_FLAG_GVRP)
122 vlan_gvrp_request_leave(dev); 99 vlan_gvrp_request_leave(dev);
@@ -128,16 +105,9 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
128 */ 105 */
129 unregister_netdevice_queue(dev, head); 106 unregister_netdevice_queue(dev, head);
130 107
131 /* If the group is now empty, kill off the group. */ 108 if (grp->nr_vlan_devs == 0)
132 if (grp->nr_vlans == 0) {
133 vlan_gvrp_uninit_applicant(real_dev); 109 vlan_gvrp_uninit_applicant(real_dev);
134 110
135 RCU_INIT_POINTER(real_dev->vlgrp, NULL);
136
137 /* Free the group, after all cpu's are done. */
138 call_rcu(&grp->rcu, vlan_rcu_free);
139 }
140
141 /* Get rid of the vlan's reference to real_dev */ 111 /* Get rid of the vlan's reference to real_dev */
142 dev_put(real_dev); 112 dev_put(real_dev);
143} 113}
@@ -169,17 +139,23 @@ int register_vlan_dev(struct net_device *dev)
169 struct vlan_dev_priv *vlan = vlan_dev_priv(dev); 139 struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
170 struct net_device *real_dev = vlan->real_dev; 140 struct net_device *real_dev = vlan->real_dev;
171 u16 vlan_id = vlan->vlan_id; 141 u16 vlan_id = vlan->vlan_id;
172 struct vlan_group *grp, *ngrp = NULL; 142 struct vlan_info *vlan_info;
143 struct vlan_group *grp;
173 int err; 144 int err;
174 145
175 grp = rtnl_dereference(real_dev->vlgrp); 146 err = vlan_vid_add(real_dev, vlan_id);
176 if (!grp) { 147 if (err)
177 ngrp = grp = vlan_group_alloc(real_dev); 148 return err;
178 if (!grp) 149
179 return -ENOBUFS; 150 vlan_info = rtnl_dereference(real_dev->vlan_info);
151 /* vlan_info should be there now. vlan_vid_add took care of it */
152 BUG_ON(!vlan_info);
153
154 grp = &vlan_info->grp;
155 if (grp->nr_vlan_devs == 0) {
180 err = vlan_gvrp_init_applicant(real_dev); 156 err = vlan_gvrp_init_applicant(real_dev);
181 if (err < 0) 157 if (err < 0)
182 goto out_free_group; 158 goto out_vid_del;
183 } 159 }
184 160
185 err = vlan_group_prealloc_vid(grp, vlan_id); 161 err = vlan_group_prealloc_vid(grp, vlan_id);
@@ -200,23 +176,15 @@ int register_vlan_dev(struct net_device *dev)
200 * it into our local structure. 176 * it into our local structure.
201 */ 177 */
202 vlan_group_set_device(grp, vlan_id, dev); 178 vlan_group_set_device(grp, vlan_id, dev);
203 grp->nr_vlans++; 179 grp->nr_vlan_devs++;
204
205 if (ngrp) {
206 rcu_assign_pointer(real_dev->vlgrp, ngrp);
207 }
208 vlan_vid_add(real_dev, vlan_id);
209 180
210 return 0; 181 return 0;
211 182
212out_uninit_applicant: 183out_uninit_applicant:
213 if (ngrp) 184 if (grp->nr_vlan_devs == 0)
214 vlan_gvrp_uninit_applicant(real_dev); 185 vlan_gvrp_uninit_applicant(real_dev);
215out_free_group: 186out_vid_del:
216 if (ngrp) { 187 vlan_vid_del(real_dev, vlan_id);
217 /* Free the group, after all cpu's are done. */
218 call_rcu(&ngrp->rcu, vlan_rcu_free);
219 }
220 return err; 188 return err;
221} 189}
222 190
@@ -357,6 +325,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
357{ 325{
358 struct net_device *dev = ptr; 326 struct net_device *dev = ptr;
359 struct vlan_group *grp; 327 struct vlan_group *grp;
328 struct vlan_info *vlan_info;
360 int i, flgs; 329 int i, flgs;
361 struct net_device *vlandev; 330 struct net_device *vlandev;
362 struct vlan_dev_priv *vlan; 331 struct vlan_dev_priv *vlan;
@@ -372,9 +341,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
372 vlan_vid_add(dev, 0); 341 vlan_vid_add(dev, 0);
373 } 342 }
374 343
375 grp = rtnl_dereference(dev->vlgrp); 344 vlan_info = rtnl_dereference(dev->vlan_info);
376 if (!grp) 345 if (!vlan_info)
377 goto out; 346 goto out;
347 grp = &vlan_info->grp;
378 348
379 /* It is OK that we do not hold the group lock right now, 349 /* It is OK that we do not hold the group lock right now,
380 * as we run under the RTNL lock. 350 * as we run under the RTNL lock.
@@ -478,9 +448,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
478 if (!vlandev) 448 if (!vlandev)
479 continue; 449 continue;
480 450
481 /* unregistration of last vlan destroys group, abort 451 /* removal of last vid destroys vlan_info, abort
482 * afterwards */ 452 * afterwards */
483 if (grp->nr_vlans == 1) 453 if (vlan_info->nr_vids == 1)
484 i = VLAN_N_VID; 454 i = VLAN_N_VID;
485 455
486 unregister_vlan_dev(vlandev, &list); 456 unregister_vlan_dev(vlandev, &list);