@@ -559,6 +559,58 @@ static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
559
559
return __nft_trans_set_add (ctx , msg_type , set , NULL );
560
560
}
561
561
562
+ static void nft_setelem_data_deactivate (const struct net * net ,
563
+ const struct nft_set * set ,
564
+ struct nft_set_elem * elem );
565
+
566
+ static int nft_mapelem_deactivate (const struct nft_ctx * ctx ,
567
+ struct nft_set * set ,
568
+ const struct nft_set_iter * iter ,
569
+ struct nft_set_elem * elem )
570
+ {
571
+ nft_setelem_data_deactivate (ctx -> net , set , elem );
572
+
573
+ return 0 ;
574
+ }
575
+
576
+ struct nft_set_elem_catchall {
577
+ struct list_head list ;
578
+ struct rcu_head rcu ;
579
+ void * elem ;
580
+ };
581
+
582
+ static void nft_map_catchall_deactivate (const struct nft_ctx * ctx ,
583
+ struct nft_set * set )
584
+ {
585
+ u8 genmask = nft_genmask_next (ctx -> net );
586
+ struct nft_set_elem_catchall * catchall ;
587
+ struct nft_set_elem elem ;
588
+ struct nft_set_ext * ext ;
589
+
590
+ list_for_each_entry (catchall , & set -> catchall_list , list ) {
591
+ ext = nft_set_elem_ext (set , catchall -> elem );
592
+ if (!nft_set_elem_active (ext , genmask ))
593
+ continue ;
594
+
595
+ elem .priv = catchall -> elem ;
596
+ nft_setelem_data_deactivate (ctx -> net , set , & elem );
597
+ break ;
598
+ }
599
+ }
600
+
601
+ static void nft_map_deactivate (const struct nft_ctx * ctx , struct nft_set * set )
602
+ {
603
+ struct nft_set_iter iter = {
604
+ .genmask = nft_genmask_next (ctx -> net ),
605
+ .fn = nft_mapelem_deactivate ,
606
+ };
607
+
608
+ set -> ops -> walk (ctx , set , & iter );
609
+ WARN_ON_ONCE (iter .err );
610
+
611
+ nft_map_catchall_deactivate (ctx , set );
612
+ }
613
+
562
614
static int nft_delset (const struct nft_ctx * ctx , struct nft_set * set )
563
615
{
564
616
int err ;
@@ -567,6 +619,9 @@ static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
567
619
if (err < 0 )
568
620
return err ;
569
621
622
+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
623
+ nft_map_deactivate (ctx , set );
624
+
570
625
nft_deactivate_next (ctx -> net , set );
571
626
ctx -> table -> use -- ;
572
627
@@ -3659,12 +3714,6 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
3659
3714
return 0 ;
3660
3715
}
3661
3716
3662
- struct nft_set_elem_catchall {
3663
- struct list_head list ;
3664
- struct rcu_head rcu ;
3665
- void * elem ;
3666
- };
3667
-
3668
3717
int nft_set_catchall_validate (const struct nft_ctx * ctx , struct nft_set * set )
3669
3718
{
3670
3719
u8 genmask = nft_genmask_next (ctx -> net );
@@ -4997,7 +5046,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
4997
5046
for (i = 0 ; i < set -> num_exprs ; i ++ )
4998
5047
nft_expr_destroy (& ctx , set -> exprs [i ]);
4999
5048
err_set_destroy :
5000
- ops -> destroy (set );
5049
+ ops -> destroy (& ctx , set );
5001
5050
err_set_init :
5002
5051
kfree (set -> name );
5003
5052
err_set_name :
@@ -5012,7 +5061,7 @@ static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
5012
5061
5013
5062
list_for_each_entry_safe (catchall , next , & set -> catchall_list , list ) {
5014
5063
list_del_rcu (& catchall -> list );
5015
- nft_set_elem_destroy ( set , catchall -> elem , true );
5064
+ nf_tables_set_elem_destroy ( ctx , set , catchall -> elem );
5016
5065
kfree_rcu (catchall , rcu );
5017
5066
}
5018
5067
}
@@ -5027,7 +5076,7 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
5027
5076
for (i = 0 ; i < set -> num_exprs ; i ++ )
5028
5077
nft_expr_destroy (ctx , set -> exprs [i ]);
5029
5078
5030
- set -> ops -> destroy (set );
5079
+ set -> ops -> destroy (ctx , set );
5031
5080
nft_set_catchall_destroy (ctx , set );
5032
5081
kfree (set -> name );
5033
5082
kvfree (set );
@@ -5192,10 +5241,60 @@ static void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
5192
5241
}
5193
5242
}
5194
5243
5244
+ static void nft_setelem_data_activate (const struct net * net ,
5245
+ const struct nft_set * set ,
5246
+ struct nft_set_elem * elem );
5247
+
5248
+ static int nft_mapelem_activate (const struct nft_ctx * ctx ,
5249
+ struct nft_set * set ,
5250
+ const struct nft_set_iter * iter ,
5251
+ struct nft_set_elem * elem )
5252
+ {
5253
+ nft_setelem_data_activate (ctx -> net , set , elem );
5254
+
5255
+ return 0 ;
5256
+ }
5257
+
5258
+ static void nft_map_catchall_activate (const struct nft_ctx * ctx ,
5259
+ struct nft_set * set )
5260
+ {
5261
+ u8 genmask = nft_genmask_next (ctx -> net );
5262
+ struct nft_set_elem_catchall * catchall ;
5263
+ struct nft_set_elem elem ;
5264
+ struct nft_set_ext * ext ;
5265
+
5266
+ list_for_each_entry (catchall , & set -> catchall_list , list ) {
5267
+ ext = nft_set_elem_ext (set , catchall -> elem );
5268
+ if (!nft_set_elem_active (ext , genmask ))
5269
+ continue ;
5270
+
5271
+ elem .priv = catchall -> elem ;
5272
+ nft_setelem_data_activate (ctx -> net , set , & elem );
5273
+ break ;
5274
+ }
5275
+ }
5276
+
5277
+ static void nft_map_activate (const struct nft_ctx * ctx , struct nft_set * set )
5278
+ {
5279
+ struct nft_set_iter iter = {
5280
+ .genmask = nft_genmask_next (ctx -> net ),
5281
+ .fn = nft_mapelem_activate ,
5282
+ };
5283
+
5284
+ set -> ops -> walk (ctx , set , & iter );
5285
+ WARN_ON_ONCE (iter .err );
5286
+
5287
+ nft_map_catchall_activate (ctx , set );
5288
+ }
5289
+
5195
5290
void nf_tables_activate_set (const struct nft_ctx * ctx , struct nft_set * set )
5196
5291
{
5197
- if (nft_set_is_anonymous (set ))
5292
+ if (nft_set_is_anonymous (set )) {
5293
+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
5294
+ nft_map_activate (ctx , set );
5295
+
5198
5296
nft_clear (ctx -> net , set );
5297
+ }
5199
5298
5200
5299
set -> use ++ ;
5201
5300
}
@@ -5214,13 +5313,20 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
5214
5313
set -> use -- ;
5215
5314
break ;
5216
5315
case NFT_TRANS_PREPARE :
5217
- if (nft_set_is_anonymous (set ))
5218
- nft_deactivate_next (ctx -> net , set );
5316
+ if (nft_set_is_anonymous (set )) {
5317
+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
5318
+ nft_map_deactivate (ctx , set );
5219
5319
5320
+ nft_deactivate_next (ctx -> net , set );
5321
+ }
5220
5322
set -> use -- ;
5221
5323
return ;
5222
5324
case NFT_TRANS_ABORT :
5223
5325
case NFT_TRANS_RELEASE :
5326
+ if (nft_set_is_anonymous (set ) &&
5327
+ set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
5328
+ nft_map_deactivate (ctx , set );
5329
+
5224
5330
set -> use -- ;
5225
5331
fallthrough ;
5226
5332
default :
@@ -5973,6 +6079,7 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
5973
6079
__nft_set_elem_expr_destroy (ctx , expr );
5974
6080
}
5975
6081
6082
+ /* Drop references and destroy. Called from gc, dynset and abort path. */
5976
6083
void nft_set_elem_destroy (const struct nft_set * set , void * elem ,
5977
6084
bool destroy_expr )
5978
6085
{
@@ -5994,11 +6101,11 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
5994
6101
}
5995
6102
EXPORT_SYMBOL_GPL (nft_set_elem_destroy );
5996
6103
5997
- /* Only called from commit path, nft_setelem_data_deactivate() already deals
5998
- * with the refcounting from the preparation phase .
6104
+ /* Destroy element. References have been already dropped in the preparation
6105
+ * path via nft_setelem_data_deactivate() .
5999
6106
*/
6000
- static void nf_tables_set_elem_destroy (const struct nft_ctx * ctx ,
6001
- const struct nft_set * set , void * elem )
6107
+ void nf_tables_set_elem_destroy (const struct nft_ctx * ctx ,
6108
+ const struct nft_set * set , void * elem )
6002
6109
{
6003
6110
struct nft_set_ext * ext = nft_set_elem_ext (set , elem );
6004
6111
@@ -6631,7 +6738,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
6631
6738
if (obj )
6632
6739
obj -> use -- ;
6633
6740
err_elem_userdata :
6634
- nf_tables_set_elem_destroy ( ctx , set , elem .priv );
6741
+ nft_set_elem_destroy ( set , elem .priv , true );
6635
6742
err_parse_data :
6636
6743
if (nla [NFTA_SET_ELEM_DATA ] != NULL )
6637
6744
nft_data_release (& elem .data .val , desc .type );
@@ -9799,6 +9906,9 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
9799
9906
case NFT_MSG_DESTROYSET :
9800
9907
trans -> ctx .table -> use ++ ;
9801
9908
nft_clear (trans -> ctx .net , nft_trans_set (trans ));
9909
+ if (nft_trans_set (trans )-> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
9910
+ nft_map_activate (& trans -> ctx , nft_trans_set (trans ));
9911
+
9802
9912
nft_trans_destroy (trans );
9803
9913
break ;
9804
9914
case NFT_MSG_NEWSETELEM :
@@ -10568,6 +10678,9 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
10568
10678
list_for_each_entry_safe (set , ns , & table -> sets , list ) {
10569
10679
list_del (& set -> list );
10570
10680
table -> use -- ;
10681
+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
10682
+ nft_map_deactivate (& ctx , set );
10683
+
10571
10684
nft_set_destroy (& ctx , set );
10572
10685
}
10573
10686
list_for_each_entry_safe (obj , ne , & table -> objects , list ) {
0 commit comments