Skip to content

Commit f8ed289

Browse files
Nikolay Aleksandrovdavem330
Nikolay Aleksandrov
authored andcommitted
bridge: vlan: use br_vlan_(get|put)_master to deal with refcounts
Introduce br_vlan_(get|put)_master which take a reference (or create the master vlan first if it didn't exist) and drop a reference respectively. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 586c2b5 commit f8ed289

File tree

1 file changed

+39
-17
lines changed

1 file changed

+39
-17
lines changed

net/bridge/br_vlan.c

+39-17
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,40 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
146146
return err;
147147
}
148148

149+
/* Returns a master vlan, if it didn't exist it gets created. In all cases a
150+
* a reference is taken to the master vlan before returning.
151+
*/
152+
static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid)
153+
{
154+
struct net_bridge_vlan *masterv;
155+
156+
masterv = br_vlan_find(br->vlgrp, vid);
157+
if (!masterv) {
158+
/* missing global ctx, create it now */
159+
if (br_vlan_add(br, vid, 0))
160+
return NULL;
161+
masterv = br_vlan_find(br->vlgrp, vid);
162+
if (WARN_ON(!masterv))
163+
return NULL;
164+
}
165+
atomic_inc(&masterv->refcnt);
166+
167+
return masterv;
168+
}
169+
170+
static void br_vlan_put_master(struct net_bridge_vlan *masterv)
171+
{
172+
if (!br_vlan_is_master(masterv))
173+
return;
174+
175+
if (atomic_dec_and_test(&masterv->refcnt)) {
176+
rhashtable_remove_fast(&masterv->br->vlgrp->vlan_hash,
177+
&masterv->vnode, br_vlan_rht_params);
178+
__vlan_del_list(masterv);
179+
kfree_rcu(masterv, rcu);
180+
}
181+
}
182+
149183
/* This is the shared VLAN add function which works for both ports and bridge
150184
* devices. There are four possible calls to this function in terms of the
151185
* vlan entry type:
@@ -196,16 +230,9 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
196230
goto out_filt;
197231
}
198232

199-
masterv = br_vlan_find(br->vlgrp, v->vid);
200-
if (!masterv) {
201-
/* missing global ctx, create it now */
202-
err = br_vlan_add(br, v->vid, 0);
203-
if (err)
204-
goto out_filt;
205-
masterv = br_vlan_find(br->vlgrp, v->vid);
206-
WARN_ON(!masterv);
207-
}
208-
atomic_inc(&masterv->refcnt);
233+
masterv = br_vlan_get_master(br, v->vid);
234+
if (!masterv)
235+
goto out_filt;
209236
v->brvlan = masterv;
210237
}
211238

@@ -240,7 +267,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
240267
if (p) {
241268
__vlan_vid_del(dev, br, v->vid);
242269
if (masterv) {
243-
atomic_dec(&masterv->refcnt);
270+
br_vlan_put_master(masterv);
244271
v->brvlan = NULL;
245272
}
246273
}
@@ -289,12 +316,7 @@ static int __vlan_del(struct net_bridge_vlan *v)
289316
kfree_rcu(v, rcu);
290317
}
291318

292-
if (atomic_dec_and_test(&masterv->refcnt)) {
293-
rhashtable_remove_fast(&masterv->br->vlgrp->vlan_hash,
294-
&masterv->vnode, br_vlan_rht_params);
295-
__vlan_del_list(masterv);
296-
kfree_rcu(masterv, rcu);
297-
}
319+
br_vlan_put_master(masterv);
298320
out:
299321
return err;
300322
}

0 commit comments

Comments
 (0)