@@ -22,6 +22,7 @@ struct nft_rbtree {
2222 struct rb_root root ;
2323 rwlock_t lock ;
2424 seqcount_t count ;
25+ struct delayed_work gc_work ;
2526};
2627
2728struct nft_rbtree_elem {
@@ -265,15 +266,20 @@ static void nft_rbtree_activate(const struct net *net,
265266 struct nft_rbtree_elem * rbe = elem -> priv ;
266267
267268 nft_set_elem_change_active (net , set , & rbe -> ext );
269+ nft_set_elem_clear_busy (& rbe -> ext );
268270}
269271
270272static bool nft_rbtree_flush (const struct net * net ,
271273 const struct nft_set * set , void * priv )
272274{
273275 struct nft_rbtree_elem * rbe = priv ;
274276
275- nft_set_elem_change_active (net , set , & rbe -> ext );
276- return true;
277+ if (!nft_set_elem_mark_busy (& rbe -> ext ) ||
278+ !nft_is_active (net , & rbe -> ext )) {
279+ nft_set_elem_change_active (net , set , & rbe -> ext );
280+ return true;
281+ }
282+ return false;
277283}
278284
279285static void * nft_rbtree_deactivate (const struct net * net ,
@@ -347,6 +353,62 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
347353 read_unlock_bh (& priv -> lock );
348354}
349355
356+ static void nft_rbtree_gc (struct work_struct * work )
357+ {
358+ struct nft_set_gc_batch * gcb = NULL ;
359+ struct rb_node * node , * prev = NULL ;
360+ struct nft_rbtree_elem * rbe ;
361+ struct nft_rbtree * priv ;
362+ struct nft_set * set ;
363+ int i ;
364+
365+ priv = container_of (work , struct nft_rbtree , gc_work .work );
366+ set = nft_set_container_of (priv );
367+
368+ write_lock_bh (& priv -> lock );
369+ write_seqcount_begin (& priv -> count );
370+ for (node = rb_first (& priv -> root ); node != NULL ; node = rb_next (node )) {
371+ rbe = rb_entry (node , struct nft_rbtree_elem , node );
372+
373+ if (nft_rbtree_interval_end (rbe )) {
374+ prev = node ;
375+ continue ;
376+ }
377+ if (!nft_set_elem_expired (& rbe -> ext ))
378+ continue ;
379+ if (nft_set_elem_mark_busy (& rbe -> ext ))
380+ continue ;
381+
382+ gcb = nft_set_gc_batch_check (set , gcb , GFP_ATOMIC );
383+ if (!gcb )
384+ goto out ;
385+
386+ atomic_dec (& set -> nelems );
387+ nft_set_gc_batch_add (gcb , rbe );
388+
389+ if (prev ) {
390+ rbe = rb_entry (prev , struct nft_rbtree_elem , node );
391+ atomic_dec (& set -> nelems );
392+ nft_set_gc_batch_add (gcb , rbe );
393+ }
394+ node = rb_next (node );
395+ }
396+ out :
397+ if (gcb ) {
398+ for (i = 0 ; i < gcb -> head .cnt ; i ++ ) {
399+ rbe = gcb -> elems [i ];
400+ rb_erase (& rbe -> node , & priv -> root );
401+ }
402+ }
403+ write_seqcount_end (& priv -> count );
404+ write_unlock_bh (& priv -> lock );
405+
406+ nft_set_gc_batch_complete (gcb );
407+
408+ queue_delayed_work (system_power_efficient_wq , & priv -> gc_work ,
409+ nft_set_gc_interval (set ));
410+ }
411+
350412static unsigned int nft_rbtree_privsize (const struct nlattr * const nla [],
351413 const struct nft_set_desc * desc )
352414{
@@ -362,6 +424,12 @@ static int nft_rbtree_init(const struct nft_set *set,
362424 rwlock_init (& priv -> lock );
363425 seqcount_init (& priv -> count );
364426 priv -> root = RB_ROOT ;
427+
428+ INIT_DEFERRABLE_WORK (& priv -> gc_work , nft_rbtree_gc );
429+ if (set -> flags & NFT_SET_TIMEOUT )
430+ queue_delayed_work (system_power_efficient_wq , & priv -> gc_work ,
431+ nft_set_gc_interval (set ));
432+
365433 return 0 ;
366434}
367435
@@ -371,6 +439,7 @@ static void nft_rbtree_destroy(const struct nft_set *set)
371439 struct nft_rbtree_elem * rbe ;
372440 struct rb_node * node ;
373441
442+ cancel_delayed_work_sync (& priv -> gc_work );
374443 while ((node = priv -> root .rb_node ) != NULL ) {
375444 rb_erase (node , & priv -> root );
376445 rbe = rb_entry (node , struct nft_rbtree_elem , node );
@@ -395,7 +464,7 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
395464
396465static struct nft_set_type nft_rbtree_type __read_mostly = {
397466 .owner = THIS_MODULE ,
398- .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT ,
467+ .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT | NFT_SET_TIMEOUT ,
399468 .ops = {
400469 .privsize = nft_rbtree_privsize ,
401470 .elemsize = offsetof(struct nft_rbtree_elem , ext ),
0 commit comments