@@ -146,6 +146,40 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
146
146
return err ;
147
147
}
148
148
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
+
149
183
/* This is the shared VLAN add function which works for both ports and bridge
150
184
* devices. There are four possible calls to this function in terms of the
151
185
* vlan entry type:
@@ -196,16 +230,9 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
196
230
goto out_filt ;
197
231
}
198
232
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 ;
209
236
v -> brvlan = masterv ;
210
237
}
211
238
@@ -240,7 +267,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
240
267
if (p ) {
241
268
__vlan_vid_del (dev , br , v -> vid );
242
269
if (masterv ) {
243
- atomic_dec ( & masterv -> refcnt );
270
+ br_vlan_put_master ( masterv );
244
271
v -> brvlan = NULL ;
245
272
}
246
273
}
@@ -289,12 +316,7 @@ static int __vlan_del(struct net_bridge_vlan *v)
289
316
kfree_rcu (v , rcu );
290
317
}
291
318
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 );
298
320
out :
299
321
return err ;
300
322
}
0 commit comments