@@ -22,6 +22,7 @@ struct nft_rbtree {
22
22
struct rb_root root ;
23
23
rwlock_t lock ;
24
24
seqcount_t count ;
25
+ struct delayed_work gc_work ;
25
26
};
26
27
27
28
struct nft_rbtree_elem {
@@ -265,15 +266,20 @@ static void nft_rbtree_activate(const struct net *net,
265
266
struct nft_rbtree_elem * rbe = elem -> priv ;
266
267
267
268
nft_set_elem_change_active (net , set , & rbe -> ext );
269
+ nft_set_elem_clear_busy (& rbe -> ext );
268
270
}
269
271
270
272
static bool nft_rbtree_flush (const struct net * net ,
271
273
const struct nft_set * set , void * priv )
272
274
{
273
275
struct nft_rbtree_elem * rbe = priv ;
274
276
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;
277
283
}
278
284
279
285
static void * nft_rbtree_deactivate (const struct net * net ,
@@ -347,6 +353,62 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
347
353
read_unlock_bh (& priv -> lock );
348
354
}
349
355
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
+
350
412
static unsigned int nft_rbtree_privsize (const struct nlattr * const nla [],
351
413
const struct nft_set_desc * desc )
352
414
{
@@ -362,6 +424,12 @@ static int nft_rbtree_init(const struct nft_set *set,
362
424
rwlock_init (& priv -> lock );
363
425
seqcount_init (& priv -> count );
364
426
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
+
365
433
return 0 ;
366
434
}
367
435
@@ -371,6 +439,7 @@ static void nft_rbtree_destroy(const struct nft_set *set)
371
439
struct nft_rbtree_elem * rbe ;
372
440
struct rb_node * node ;
373
441
442
+ cancel_delayed_work_sync (& priv -> gc_work );
374
443
while ((node = priv -> root .rb_node ) != NULL ) {
375
444
rb_erase (node , & priv -> root );
376
445
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,
395
464
396
465
static struct nft_set_type nft_rbtree_type __read_mostly = {
397
466
.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 ,
399
468
.ops = {
400
469
.privsize = nft_rbtree_privsize ,
401
470
.elemsize = offsetof(struct nft_rbtree_elem , ext ),
0 commit comments