@@ -9678,11 +9678,11 @@ static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
unsigned int gc_seq,
bool sync)
{
- struct nft_set_elem_catchall *catchall;
+ struct nft_set_elem_catchall *catchall, *next;
const struct nft_set *set = gc->set;
struct nft_set_ext *ext;
- list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_expired(ext))
@@ -9692,10 +9692,12 @@ static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
nft_set_elem_dead(ext);
dead_elem:
- if (sync)
+ if (sync) {
+ nft_setelem_catchall_remove(gc->net, gc->set, catchall->elem);
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
- else
+ } else {
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
+ }
if (!gc)
return NULL;
The expired catchall element is not removed from GC sync path. This path holds mutex so just call nft_setelem_catchall_remove() before queueing the GC work. Fixes: 4a9e12ea7e70 ("netfilter: nft_set_pipapo: call nft_trans_gc_queue_sync() in catchall GC") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- v2: use _safe variant for list iteration now that element gets removed. net/netfilter/nf_tables_api.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)