Skip to content

Commit 525c253

Browse files
ummakynesshaoyingxu
authored andcommitted
netfilter: nf_tables: split async and sync catchall in two functions
[ Upstream commit 8837ba3 ] list_for_each_entry_safe() does not work for the async case which runs under RCU, therefore, split GC logic for catchall in two functions instead, one for each of the sync and async GC variants. The catchall sync GC variant never sees a _DEAD bit set on ever, thus, this handling is removed in such case, moreover, allocate GC sync batch via GFP_KERNEL. Fixes: 93995bf ("netfilter: nf_tables: remove catchall element in GC sync path") Reported-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Puranjay Mohan <pjy@amazon.com>
1 parent 58b5613 commit 525c253

File tree

1 file changed

+32
-29
lines changed

1 file changed

+32
-29
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9047,16 +9047,14 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
90479047
call_rcu(&trans->rcu, nft_trans_gc_trans_free);
90489048
}
90499049

9050-
static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
9051-
unsigned int gc_seq,
9052-
bool sync)
9050+
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9051+
unsigned int gc_seq)
90539052
{
9054-
struct nft_set_elem_catchall *catchall, *next;
9053+
struct nft_set_elem_catchall *catchall;
90559054
const struct nft_set *set = gc->set;
9056-
struct nft_elem_priv *elem_priv;
90579055
struct nft_set_ext *ext;
90589056

9059-
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
9057+
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
90609058
ext = nft_set_elem_ext(set, catchall->elem);
90619059

90629060
if (!nft_set_elem_expired(ext))
@@ -9066,39 +9064,44 @@ static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
90669064

90679065
nft_set_elem_dead(ext);
90689066
dead_elem:
9069-
if (sync)
9070-
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
9071-
else
9072-
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
9073-
9067+
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
90749068
if (!gc)
90759069
return NULL;
90769070

9077-
elem_priv = catchall->elem;
9078-
if (sync) {
9079-
struct nft_set_elem elem = {
9080-
.priv = elem_priv,
9081-
};
9082-
9083-
nft_setelem_data_deactivate(gc->net, gc->set, &elem);
9084-
nft_setelem_catchall_destroy(catchall);
9085-
}
9086-
9087-
nft_trans_gc_elem_add(gc, elem_priv);
9071+
nft_trans_gc_elem_add(gc, catchall->elem);
90889072
}
90899073

90909074
return gc;
90919075
}
90929076

9093-
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9094-
unsigned int gc_seq)
9095-
{
9096-
return nft_trans_gc_catchall(gc, gc_seq, false);
9097-
}
9098-
90999077
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
91009078
{
9101-
return nft_trans_gc_catchall(gc, 0, true);
9079+
struct nft_set_elem_catchall *catchall, *next;
9080+
const struct nft_set *set = gc->set;
9081+
struct nft_set_elem elem;
9082+
struct nft_set_ext *ext;
9083+
9084+
WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net));
9085+
9086+
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
9087+
ext = nft_set_elem_ext(set, catchall->elem);
9088+
9089+
if (!nft_set_elem_expired(ext))
9090+
continue;
9091+
9092+
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
9093+
if (!gc)
9094+
return NULL;
9095+
9096+
memset(&elem, 0, sizeof(elem));
9097+
elem.priv = catchall->elem;
9098+
9099+
nft_setelem_data_deactivate(gc->net, gc->set, &elem);
9100+
nft_setelem_catchall_destroy(catchall);
9101+
nft_trans_gc_elem_add(gc, elem.priv);
9102+
}
9103+
9104+
return gc;
91029105
}
91039106

91049107
static void nf_tables_module_autoload_cleanup(struct net *net)

0 commit comments

Comments
 (0)