@@ -561,6 +561,58 @@ static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
561561 return __nft_trans_set_add (ctx , msg_type , set , NULL );
562562}
563563
564+ static void nft_setelem_data_deactivate (const struct net * net ,
565+ const struct nft_set * set ,
566+ struct nft_set_elem * elem );
567+
568+ static int nft_mapelem_deactivate (const struct nft_ctx * ctx ,
569+ struct nft_set * set ,
570+ const struct nft_set_iter * iter ,
571+ struct nft_set_elem * elem )
572+ {
573+ nft_setelem_data_deactivate (ctx -> net , set , elem );
574+
575+ return 0 ;
576+ }
577+
578+ struct nft_set_elem_catchall {
579+ struct list_head list ;
580+ struct rcu_head rcu ;
581+ void * elem ;
582+ };
583+
584+ static void nft_map_catchall_deactivate (const struct nft_ctx * ctx ,
585+ struct nft_set * set )
586+ {
587+ u8 genmask = nft_genmask_next (ctx -> net );
588+ struct nft_set_elem_catchall * catchall ;
589+ struct nft_set_elem elem ;
590+ struct nft_set_ext * ext ;
591+
592+ list_for_each_entry (catchall , & set -> catchall_list , list ) {
593+ ext = nft_set_elem_ext (set , catchall -> elem );
594+ if (!nft_set_elem_active (ext , genmask ))
595+ continue ;
596+
597+ elem .priv = catchall -> elem ;
598+ nft_setelem_data_deactivate (ctx -> net , set , & elem );
599+ break ;
600+ }
601+ }
602+
603+ static void nft_map_deactivate (const struct nft_ctx * ctx , struct nft_set * set )
604+ {
605+ struct nft_set_iter iter = {
606+ .genmask = nft_genmask_next (ctx -> net ),
607+ .fn = nft_mapelem_deactivate ,
608+ };
609+
610+ set -> ops -> walk (ctx , set , & iter );
611+ WARN_ON_ONCE (iter .err );
612+
613+ nft_map_catchall_deactivate (ctx , set );
614+ }
615+
564616static int nft_delset (const struct nft_ctx * ctx , struct nft_set * set )
565617{
566618 int err ;
@@ -569,6 +621,9 @@ static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
569621 if (err < 0 )
570622 return err ;
571623
624+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
625+ nft_map_deactivate (ctx , set );
626+
572627 nft_deactivate_next (ctx -> net , set );
573628 ctx -> table -> use -- ;
574629
@@ -3413,12 +3468,6 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
34133468 return 0 ;
34143469}
34153470
3416- struct nft_set_elem_catchall {
3417- struct list_head list ;
3418- struct rcu_head rcu ;
3419- void * elem ;
3420- };
3421-
34223471int nft_set_catchall_validate (const struct nft_ctx * ctx , struct nft_set * set )
34233472{
34243473 u8 genmask = nft_genmask_next (ctx -> net );
@@ -4747,7 +4796,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
47474796 for (i = 0 ; i < set -> num_exprs ; i ++ )
47484797 nft_expr_destroy (& ctx , set -> exprs [i ]);
47494798err_set_destroy :
4750- ops -> destroy (set );
4799+ ops -> destroy (& ctx , set );
47514800err_set_init :
47524801 kfree (set -> name );
47534802err_set_name :
@@ -4762,7 +4811,7 @@ static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
47624811
47634812 list_for_each_entry_safe (catchall , next , & set -> catchall_list , list ) {
47644813 list_del_rcu (& catchall -> list );
4765- nft_set_elem_destroy ( set , catchall -> elem , true );
4814+ nf_tables_set_elem_destroy ( ctx , set , catchall -> elem );
47664815 kfree_rcu (catchall , rcu );
47674816 }
47684817}
@@ -4777,7 +4826,7 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
47774826 for (i = 0 ; i < set -> num_exprs ; i ++ )
47784827 nft_expr_destroy (ctx , set -> exprs [i ]);
47794828
4780- set -> ops -> destroy (set );
4829+ set -> ops -> destroy (ctx , set );
47814830 nft_set_catchall_destroy (ctx , set );
47824831 kfree (set -> name );
47834832 kvfree (set );
@@ -4942,10 +4991,60 @@ static void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
49424991 }
49434992}
49444993
4994+ static void nft_setelem_data_activate (const struct net * net ,
4995+ const struct nft_set * set ,
4996+ struct nft_set_elem * elem );
4997+
4998+ static int nft_mapelem_activate (const struct nft_ctx * ctx ,
4999+ struct nft_set * set ,
5000+ const struct nft_set_iter * iter ,
5001+ struct nft_set_elem * elem )
5002+ {
5003+ nft_setelem_data_activate (ctx -> net , set , elem );
5004+
5005+ return 0 ;
5006+ }
5007+
5008+ static void nft_map_catchall_activate (const struct nft_ctx * ctx ,
5009+ struct nft_set * set )
5010+ {
5011+ u8 genmask = nft_genmask_next (ctx -> net );
5012+ struct nft_set_elem_catchall * catchall ;
5013+ struct nft_set_elem elem ;
5014+ struct nft_set_ext * ext ;
5015+
5016+ list_for_each_entry (catchall , & set -> catchall_list , list ) {
5017+ ext = nft_set_elem_ext (set , catchall -> elem );
5018+ if (!nft_set_elem_active (ext , genmask ))
5019+ continue ;
5020+
5021+ elem .priv = catchall -> elem ;
5022+ nft_setelem_data_activate (ctx -> net , set , & elem );
5023+ break ;
5024+ }
5025+ }
5026+
5027+ static void nft_map_activate (const struct nft_ctx * ctx , struct nft_set * set )
5028+ {
5029+ struct nft_set_iter iter = {
5030+ .genmask = nft_genmask_next (ctx -> net ),
5031+ .fn = nft_mapelem_activate ,
5032+ };
5033+
5034+ set -> ops -> walk (ctx , set , & iter );
5035+ WARN_ON_ONCE (iter .err );
5036+
5037+ nft_map_catchall_activate (ctx , set );
5038+ }
5039+
49455040void nf_tables_activate_set (const struct nft_ctx * ctx , struct nft_set * set )
49465041{
4947- if (nft_set_is_anonymous (set ))
5042+ if (nft_set_is_anonymous (set )) {
5043+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
5044+ nft_map_activate (ctx , set );
5045+
49485046 nft_clear (ctx -> net , set );
5047+ }
49495048
49505049 set -> use ++ ;
49515050}
@@ -4966,13 +5065,20 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
49665065 set -> use -- ;
49675066 break ;
49685067 case NFT_TRANS_PREPARE :
4969- if (nft_set_is_anonymous (set ))
4970- nft_deactivate_next (ctx -> net , set );
5068+ if (nft_set_is_anonymous (set )) {
5069+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
5070+ nft_map_deactivate (ctx , set );
49715071
5072+ nft_deactivate_next (ctx -> net , set );
5073+ }
49725074 set -> use -- ;
49735075 return ;
49745076 case NFT_TRANS_ABORT :
49755077 case NFT_TRANS_RELEASE :
5078+ if (nft_set_is_anonymous (set ) &&
5079+ set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
5080+ nft_map_deactivate (ctx , set );
5081+
49765082 set -> use -- ;
49775083 fallthrough ;
49785084 default :
@@ -5747,6 +5853,7 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
57475853 __nft_set_elem_expr_destroy (ctx , expr );
57485854}
57495855
5856+ /* Drop references and destroy. Called from gc, dynset and abort path. */
57505857void nft_set_elem_destroy (const struct nft_set * set , void * elem ,
57515858 bool destroy_expr )
57525859{
@@ -5768,11 +5875,11 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
57685875}
57695876EXPORT_SYMBOL_GPL (nft_set_elem_destroy );
57705877
5771- /* Only called from commit path, nft_setelem_data_deactivate() already deals
5772- * with the refcounting from the preparation phase .
5878+ /* Destroy element. References have been already dropped in the preparation
5879+ * path via nft_setelem_data_deactivate() .
57735880 */
5774- static void nf_tables_set_elem_destroy (const struct nft_ctx * ctx ,
5775- const struct nft_set * set , void * elem )
5881+ void nf_tables_set_elem_destroy (const struct nft_ctx * ctx ,
5882+ const struct nft_set * set , void * elem )
57765883{
57775884 struct nft_set_ext * ext = nft_set_elem_ext (set , elem );
57785885
@@ -6405,7 +6512,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
64056512 if (obj )
64066513 obj -> use -- ;
64076514err_elem_userdata :
6408- nf_tables_set_elem_destroy ( ctx , set , elem .priv );
6515+ nft_set_elem_destroy ( set , elem .priv , true );
64096516err_parse_data :
64106517 if (nla [NFTA_SET_ELEM_DATA ] != NULL )
64116518 nft_data_release (& elem .data .val , desc .type );
@@ -9481,6 +9588,9 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
94819588 case NFT_MSG_DESTROYSET :
94829589 trans -> ctx .table -> use ++ ;
94839590 nft_clear (trans -> ctx .net , nft_trans_set (trans ));
9591+ if (nft_trans_set (trans )-> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
9592+ nft_map_activate (& trans -> ctx , nft_trans_set (trans ));
9593+
94849594 nft_trans_destroy (trans );
94859595 break ;
94869596 case NFT_MSG_NEWSETELEM :
@@ -10251,6 +10361,9 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
1025110361 list_for_each_entry_safe (set , ns , & table -> sets , list ) {
1025210362 list_del (& set -> list );
1025310363 table -> use -- ;
10364+ if (set -> flags & (NFT_SET_MAP | NFT_SET_OBJECT ))
10365+ nft_map_deactivate (& ctx , set );
10366+
1025410367 nft_set_destroy (& ctx , set );
1025510368 }
1025610369 list_for_each_entry_safe (obj , ne , & table -> objects , list ) {
0 commit comments