Skip to content

Commit 48cf791

Browse files
brianwittegregkh
authored andcommitted
netfilter: nft_counter: serialize reset with spinlock
[ Upstream commit 779c60a ] Add a global static spinlock to serialize counter fetch+reset operations, preventing concurrent dump-and-reset from underrunning values. The lock is taken before fetching the total so that two parallel resets cannot both read the same counter values and then both subtract them. A global lock is used for simplicity since resets are infrequent. If this becomes a bottleneck, it can be replaced with a per-net lock later. Fixes: bd662c4 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") Fixes: 3d483fa ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") Fixes: 3cb03ed ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") Suggested-by: Florian Westphal <fw@strlen.de> Signed-off-by: Brian Witte <brianwitte@mailfence.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e0eed71 commit 48cf791

1 file changed

Lines changed: 16 additions & 4 deletions

File tree

net/netfilter/nft_counter.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ struct nft_counter_percpu_priv {
3232

3333
static DEFINE_PER_CPU(struct u64_stats_sync, nft_counter_sync);
3434

35+
/* control plane only: sync fetch+reset */
36+
static DEFINE_SPINLOCK(nft_counter_lock);
37+
3538
static inline void nft_counter_do_eval(struct nft_counter_percpu_priv *priv,
3639
struct nft_regs *regs,
3740
const struct nft_pktinfo *pkt)
@@ -148,23 +151,32 @@ static void nft_counter_fetch(struct nft_counter_percpu_priv *priv,
148151
}
149152
}
150153

154+
static void nft_counter_fetch_and_reset(struct nft_counter_percpu_priv *priv,
155+
struct nft_counter_tot *total)
156+
{
157+
spin_lock(&nft_counter_lock);
158+
nft_counter_fetch(priv, total);
159+
nft_counter_reset(priv, total);
160+
spin_unlock(&nft_counter_lock);
161+
}
162+
151163
static int nft_counter_do_dump(struct sk_buff *skb,
152164
struct nft_counter_percpu_priv *priv,
153165
bool reset)
154166
{
155167
struct nft_counter_tot total;
156168

157-
nft_counter_fetch(priv, &total);
169+
if (unlikely(reset))
170+
nft_counter_fetch_and_reset(priv, &total);
171+
else
172+
nft_counter_fetch(priv, &total);
158173

159174
if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes),
160175
NFTA_COUNTER_PAD) ||
161176
nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.packets),
162177
NFTA_COUNTER_PAD))
163178
goto nla_put_failure;
164179

165-
if (reset)
166-
nft_counter_reset(priv, &total);
167-
168180
return 0;
169181

170182
nla_put_failure:

0 commit comments

Comments
 (0)