@@ -204,11 +204,12 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
204
204
chain = kzalloc (sizeof (* chain ), GFP_KERNEL );
205
205
if (!chain )
206
206
return NULL ;
207
- INIT_LIST_HEAD (& chain -> filter_chain_list );
208
207
list_add_tail (& chain -> list , & block -> chain_list );
209
208
chain -> block = block ;
210
209
chain -> index = chain_index ;
211
210
chain -> refcnt = 1 ;
211
+ if (!chain -> index )
212
+ block -> chain0 .chain = chain ;
212
213
return chain ;
213
214
}
214
215
@@ -218,20 +219,24 @@ static void tcf_chain_head_change_item(struct tcf_filter_chain_list_item *item,
218
219
if (item -> chain_head_change )
219
220
item -> chain_head_change (tp_head , item -> chain_head_change_priv );
220
221
}
221
- static void tcf_chain_head_change (struct tcf_chain * chain ,
222
- struct tcf_proto * tp_head )
222
+
223
+ static void tcf_chain0_head_change (struct tcf_chain * chain ,
224
+ struct tcf_proto * tp_head )
223
225
{
224
226
struct tcf_filter_chain_list_item * item ;
227
+ struct tcf_block * block = chain -> block ;
225
228
226
- list_for_each_entry (item , & chain -> filter_chain_list , list )
229
+ if (chain -> index )
230
+ return ;
231
+ list_for_each_entry (item , & block -> chain0 .filter_chain_list , list )
227
232
tcf_chain_head_change_item (item , tp_head );
228
233
}
229
234
230
235
static void tcf_chain_flush (struct tcf_chain * chain )
231
236
{
232
237
struct tcf_proto * tp = rtnl_dereference (chain -> filter_chain );
233
238
234
- tcf_chain_head_change (chain , NULL );
239
+ tcf_chain0_head_change (chain , NULL );
235
240
while (tp ) {
236
241
RCU_INIT_POINTER (chain -> filter_chain , tp -> next );
237
242
tcf_proto_destroy (tp , NULL );
@@ -245,8 +250,10 @@ static void tcf_chain_destroy(struct tcf_chain *chain)
245
250
struct tcf_block * block = chain -> block ;
246
251
247
252
list_del (& chain -> list );
253
+ if (!chain -> index )
254
+ block -> chain0 .chain = NULL ;
248
255
kfree (chain );
249
- if (list_empty (& block -> chain_list ))
256
+ if (list_empty (& block -> chain_list ) && block -> refcnt == 0 )
250
257
kfree (block );
251
258
}
252
259
@@ -346,10 +353,11 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
346
353
}
347
354
348
355
static int
349
- tcf_chain_head_change_cb_add (struct tcf_chain * chain ,
350
- struct tcf_block_ext_info * ei ,
351
- struct netlink_ext_ack * extack )
356
+ tcf_chain0_head_change_cb_add (struct tcf_block * block ,
357
+ struct tcf_block_ext_info * ei ,
358
+ struct netlink_ext_ack * extack )
352
359
{
360
+ struct tcf_chain * chain0 = block -> chain0 .chain ;
353
361
struct tcf_filter_chain_list_item * item ;
354
362
355
363
item = kmalloc (sizeof (* item ), GFP_KERNEL );
@@ -359,23 +367,25 @@ tcf_chain_head_change_cb_add(struct tcf_chain *chain,
359
367
}
360
368
item -> chain_head_change = ei -> chain_head_change ;
361
369
item -> chain_head_change_priv = ei -> chain_head_change_priv ;
362
- if (chain -> filter_chain )
363
- tcf_chain_head_change_item (item , chain -> filter_chain );
364
- list_add (& item -> list , & chain -> filter_chain_list );
370
+ if (chain0 && chain0 -> filter_chain )
371
+ tcf_chain_head_change_item (item , chain0 -> filter_chain );
372
+ list_add (& item -> list , & block -> chain0 . filter_chain_list );
365
373
return 0 ;
366
374
}
367
375
368
376
static void
369
- tcf_chain_head_change_cb_del (struct tcf_chain * chain ,
370
- struct tcf_block_ext_info * ei )
377
+ tcf_chain0_head_change_cb_del (struct tcf_block * block ,
378
+ struct tcf_block_ext_info * ei )
371
379
{
380
+ struct tcf_chain * chain0 = block -> chain0 .chain ;
372
381
struct tcf_filter_chain_list_item * item ;
373
382
374
- list_for_each_entry (item , & chain -> filter_chain_list , list ) {
383
+ list_for_each_entry (item , & block -> chain0 . filter_chain_list , list ) {
375
384
if ((!ei -> chain_head_change && !ei -> chain_head_change_priv ) ||
376
385
(item -> chain_head_change == ei -> chain_head_change &&
377
386
item -> chain_head_change_priv == ei -> chain_head_change_priv )) {
378
- tcf_chain_head_change_item (item , NULL );
387
+ if (chain0 )
388
+ tcf_chain_head_change_item (item , NULL );
379
389
list_del (& item -> list );
380
390
kfree (item );
381
391
return ;
@@ -411,8 +421,6 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
411
421
struct netlink_ext_ack * extack )
412
422
{
413
423
struct tcf_block * block ;
414
- struct tcf_chain * chain ;
415
- int err ;
416
424
417
425
block = kzalloc (sizeof (* block ), GFP_KERNEL );
418
426
if (!block ) {
@@ -422,14 +430,8 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
422
430
INIT_LIST_HEAD (& block -> chain_list );
423
431
INIT_LIST_HEAD (& block -> cb_list );
424
432
INIT_LIST_HEAD (& block -> owner_list );
433
+ INIT_LIST_HEAD (& block -> chain0 .filter_chain_list );
425
434
426
- /* Create chain 0 by default, it has to be always present. */
427
- chain = tcf_chain_create (block , 0 );
428
- if (!chain ) {
429
- NL_SET_ERR_MSG (extack , "Failed to create new tcf chain" );
430
- err = - ENOMEM ;
431
- goto err_chain_create ;
432
- }
433
435
block -> refcnt = 1 ;
434
436
block -> net = net ;
435
437
block -> index = block_index ;
@@ -438,10 +440,6 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
438
440
if (!tcf_block_shared (block ))
439
441
block -> q = q ;
440
442
return block ;
441
-
442
- err_chain_create :
443
- kfree (block );
444
- return ERR_PTR (err );
445
443
}
446
444
447
445
static struct tcf_block * tcf_block_lookup (struct net * net , u32 block_index )
@@ -523,11 +521,6 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q,
523
521
return block ;
524
522
}
525
523
526
- static struct tcf_chain * tcf_block_chain_zero (struct tcf_block * block )
527
- {
528
- return list_first_entry (& block -> chain_list , struct tcf_chain , list );
529
- }
530
-
531
524
struct tcf_block_owner_item {
532
525
struct list_head list ;
533
526
struct Qdisc * q ;
@@ -621,10 +614,9 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
621
614
622
615
tcf_block_owner_netif_keep_dst (block , q , ei -> binder_type );
623
616
624
- err = tcf_chain_head_change_cb_add (tcf_block_chain_zero (block ),
625
- ei , extack );
617
+ err = tcf_chain0_head_change_cb_add (block , ei , extack );
626
618
if (err )
627
- goto err_chain_head_change_cb_add ;
619
+ goto err_chain0_head_change_cb_add ;
628
620
629
621
err = tcf_block_offload_bind (block , q , ei , extack );
630
622
if (err )
@@ -634,15 +626,14 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
634
626
return 0 ;
635
627
636
628
err_block_offload_bind :
637
- tcf_chain_head_change_cb_del ( tcf_block_chain_zero ( block ) , ei );
638
- err_chain_head_change_cb_add :
629
+ tcf_chain0_head_change_cb_del ( block , ei );
630
+ err_chain0_head_change_cb_add :
639
631
tcf_block_owner_del (block , q , ei -> binder_type );
640
632
err_block_owner_add :
641
633
if (created ) {
642
634
if (tcf_block_shared (block ))
643
635
tcf_block_remove (block , net );
644
636
err_block_insert :
645
- kfree (tcf_block_chain_zero (block ));
646
637
kfree (block );
647
638
} else {
648
639
block -> refcnt -- ;
@@ -682,10 +673,10 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
682
673
683
674
if (!block )
684
675
return ;
685
- tcf_chain_head_change_cb_del ( tcf_block_chain_zero ( block ) , ei );
676
+ tcf_chain0_head_change_cb_del ( block , ei );
686
677
tcf_block_owner_del (block , q , ei -> binder_type );
687
678
688
- if (-- block -> refcnt == 0 ) {
679
+ if (block -> refcnt == 1 ) {
689
680
if (tcf_block_shared (block ))
690
681
tcf_block_remove (block , block -> net );
691
682
@@ -701,13 +692,14 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
701
692
702
693
tcf_block_offload_unbind (block , q , ei );
703
694
704
- if (block -> refcnt == 0 ) {
695
+ if (block -> refcnt == 1 ) {
705
696
/* At this point, all the chains should have refcnt >= 1. */
706
697
list_for_each_entry_safe (chain , tmp , & block -> chain_list , list )
707
698
tcf_chain_put (chain );
708
699
709
- /* Finally, put chain 0 and allow block to be freed. */
710
- tcf_chain_put (tcf_block_chain_zero (block ));
700
+ block -> refcnt -- ;
701
+ if (list_empty (& block -> chain_list ))
702
+ kfree (block );
711
703
}
712
704
}
713
705
EXPORT_SYMBOL (tcf_block_put_ext );
@@ -947,7 +939,7 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain,
947
939
struct tcf_proto * tp )
948
940
{
949
941
if (* chain_info -> pprev == chain -> filter_chain )
950
- tcf_chain_head_change (chain , tp );
942
+ tcf_chain0_head_change (chain , tp );
951
943
RCU_INIT_POINTER (tp -> next , tcf_chain_tp_prev (chain_info ));
952
944
rcu_assign_pointer (* chain_info -> pprev , tp );
953
945
tcf_chain_hold (chain );
@@ -960,7 +952,7 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
960
952
struct tcf_proto * next = rtnl_dereference (chain_info -> next );
961
953
962
954
if (tp == chain -> filter_chain )
963
- tcf_chain_head_change (chain , next );
955
+ tcf_chain0_head_change (chain , next );
964
956
RCU_INIT_POINTER (* chain_info -> pprev , next );
965
957
tcf_chain_put (chain );
966
958
}
0 commit comments