Commit 53315ac6 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso
Browse files

netfilter: nf_tables: free base chain counters from worker



No need to use synchronize_rcu() here, just swap the two pointers
and have the release occur from work queue after commit has completed.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 5e2ad02e
Loading
Loading
Loading
Loading
+10 −16
Original line number Diff line number Diff line
@@ -1449,26 +1449,19 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
	return newstats;
}

static void nft_chain_stats_replace(struct net *net,
				    struct nft_base_chain *chain,
				    struct nft_stats __percpu *newstats)
static void nft_chain_stats_replace(struct nft_trans *trans)
{
	struct nft_stats __percpu *oldstats;
	struct nft_base_chain *chain = nft_base_chain(trans->ctx.chain);

	if (newstats == NULL)
	if (!nft_trans_chain_stats(trans))
		return;

	if (rcu_access_pointer(chain->stats)) {
		oldstats = rcu_dereference_protected(chain->stats,
					lockdep_commit_lock_is_held(net));
		rcu_assign_pointer(chain->stats, newstats);
		synchronize_rcu();
		free_percpu(oldstats);
	} else {
		rcu_assign_pointer(chain->stats, newstats);
	rcu_swap_protected(chain->stats, nft_trans_chain_stats(trans),
			   lockdep_commit_lock_is_held(trans->ctx.net));

	if (!nft_trans_chain_stats(trans))
		static_branch_inc(&nft_counters_enabled);
}
}

static void nf_tables_chain_free_chain_rules(struct nft_chain *chain)
{
@@ -6360,9 +6353,9 @@ static void nft_chain_commit_update(struct nft_trans *trans)
	if (!nft_is_base_chain(trans->ctx.chain))
		return;

	nft_chain_stats_replace(trans);

	basechain = nft_base_chain(trans->ctx.chain);
	nft_chain_stats_replace(trans->ctx.net, basechain,
				nft_trans_chain_stats(trans));

	switch (nft_trans_chain_policy(trans)) {
	case NF_DROP:
@@ -6379,6 +6372,7 @@ static void nft_commit_release(struct nft_trans *trans)
		nf_tables_table_destroy(&trans->ctx);
		break;
	case NFT_MSG_NEWCHAIN:
		free_percpu(nft_trans_chain_stats(trans));
		kfree(nft_trans_chain_name(trans));
		break;
	case NFT_MSG_DELCHAIN: