@@ -195,12 +195,19 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
195
195
return chain ;
196
196
}
197
197
198
+ static void tcf_chain_head_change (struct tcf_chain * chain ,
199
+ struct tcf_proto * tp_head )
200
+ {
201
+ if (chain -> chain_head_change )
202
+ chain -> chain_head_change (tp_head ,
203
+ chain -> chain_head_change_priv );
204
+ }
205
+
198
206
static void tcf_chain_flush (struct tcf_chain * chain )
199
207
{
200
208
struct tcf_proto * tp ;
201
209
202
- if (chain -> p_filter_chain )
203
- RCU_INIT_POINTER (* chain -> p_filter_chain , NULL );
210
+ tcf_chain_head_change (chain , NULL );
204
211
while ((tp = rtnl_dereference (chain -> filter_chain )) != NULL ) {
205
212
RCU_INIT_POINTER (chain -> filter_chain , tp -> next );
206
213
tcf_chain_put (chain );
@@ -242,13 +249,6 @@ void tcf_chain_put(struct tcf_chain *chain)
242
249
}
243
250
EXPORT_SYMBOL (tcf_chain_put );
244
251
245
- static void
246
- tcf_chain_filter_chain_ptr_set (struct tcf_chain * chain ,
247
- struct tcf_proto __rcu * * p_filter_chain )
248
- {
249
- chain -> p_filter_chain = p_filter_chain ;
250
- }
251
-
252
252
static void tcf_block_offload_cmd (struct tcf_block * block , struct Qdisc * q ,
253
253
struct tcf_block_ext_info * ei ,
254
254
enum tc_block_command command )
@@ -276,8 +276,7 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
276
276
tcf_block_offload_cmd (block , q , ei , TC_BLOCK_UNBIND );
277
277
}
278
278
279
- int tcf_block_get_ext (struct tcf_block * * p_block ,
280
- struct tcf_proto __rcu * * p_filter_chain , struct Qdisc * q ,
279
+ int tcf_block_get_ext (struct tcf_block * * p_block , struct Qdisc * q ,
281
280
struct tcf_block_ext_info * ei )
282
281
{
283
282
struct tcf_block * block = kzalloc (sizeof (* block ), GFP_KERNEL );
@@ -295,7 +294,9 @@ int tcf_block_get_ext(struct tcf_block **p_block,
295
294
err = - ENOMEM ;
296
295
goto err_chain_create ;
297
296
}
298
- tcf_chain_filter_chain_ptr_set (chain , p_filter_chain );
297
+ WARN_ON (!ei -> chain_head_change );
298
+ chain -> chain_head_change = ei -> chain_head_change ;
299
+ chain -> chain_head_change_priv = ei -> chain_head_change_priv ;
299
300
block -> net = qdisc_net (q );
300
301
block -> q = q ;
301
302
tcf_block_offload_bind (block , q , ei );
@@ -308,12 +309,23 @@ int tcf_block_get_ext(struct tcf_block **p_block,
308
309
}
309
310
EXPORT_SYMBOL (tcf_block_get_ext );
310
311
312
+ static void tcf_chain_head_change_dflt (struct tcf_proto * tp_head , void * priv )
313
+ {
314
+ struct tcf_proto __rcu * * p_filter_chain = priv ;
315
+
316
+ rcu_assign_pointer (* p_filter_chain , tp_head );
317
+ }
318
+
311
319
int tcf_block_get (struct tcf_block * * p_block ,
312
320
struct tcf_proto __rcu * * p_filter_chain , struct Qdisc * q )
313
321
{
314
- struct tcf_block_ext_info ei = {0 , };
322
+ struct tcf_block_ext_info ei = {
323
+ .chain_head_change = tcf_chain_head_change_dflt ,
324
+ .chain_head_change_priv = p_filter_chain ,
325
+ };
315
326
316
- return tcf_block_get_ext (p_block , p_filter_chain , q , & ei );
327
+ WARN_ON (!p_filter_chain );
328
+ return tcf_block_get_ext (p_block , q , & ei );
317
329
}
318
330
EXPORT_SYMBOL (tcf_block_get );
319
331
@@ -334,8 +346,7 @@ static void tcf_block_put_final(struct work_struct *work)
334
346
* actions should be all removed after flushing. However, filters are now
335
347
* destroyed in tc filter workqueue with RTNL lock, they can not race here.
336
348
*/
337
- void tcf_block_put_ext (struct tcf_block * block ,
338
- struct tcf_proto __rcu * * p_filter_chain , struct Qdisc * q ,
349
+ void tcf_block_put_ext (struct tcf_block * block , struct Qdisc * q ,
339
350
struct tcf_block_ext_info * ei )
340
351
{
341
352
struct tcf_chain * chain , * tmp ;
@@ -361,7 +372,7 @@ void tcf_block_put(struct tcf_block *block)
361
372
362
373
if (!block )
363
374
return ;
364
- tcf_block_put_ext (block , NULL , block -> q , & ei );
375
+ tcf_block_put_ext (block , block -> q , & ei );
365
376
}
366
377
367
378
EXPORT_SYMBOL (tcf_block_put );
@@ -537,9 +548,8 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain,
537
548
struct tcf_chain_info * chain_info ,
538
549
struct tcf_proto * tp )
539
550
{
540
- if (chain -> p_filter_chain &&
541
- * chain_info -> pprev == chain -> filter_chain )
542
- rcu_assign_pointer (* chain -> p_filter_chain , tp );
551
+ if (* chain_info -> pprev == chain -> filter_chain )
552
+ tcf_chain_head_change (chain , tp );
543
553
RCU_INIT_POINTER (tp -> next , tcf_chain_tp_prev (chain_info ));
544
554
rcu_assign_pointer (* chain_info -> pprev , tp );
545
555
tcf_chain_hold (chain );
@@ -551,8 +561,8 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
551
561
{
552
562
struct tcf_proto * next = rtnl_dereference (chain_info -> next );
553
563
554
- if (chain -> p_filter_chain && tp == chain -> filter_chain )
555
- RCU_INIT_POINTER ( * chain -> p_filter_chain , next );
564
+ if (tp == chain -> filter_chain )
565
+ tcf_chain_head_change ( chain , next );
556
566
RCU_INIT_POINTER (* chain_info -> pprev , next );
557
567
tcf_chain_put (chain );
558
568
}
0 commit comments