@@ -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 );
298320out :
299321 return err ;
300322}
0 commit comments