public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: Natarajan KV <natarajankv91@gmail.com>
To: stable@vger.kernel.org
Cc: gregkh@linuxfoundation.org, pablo@netfilter.org,
	kadlec@netfilter.org, fw@strlen.de
Subject: [PATCH v3 6.6.y 7/8] netfilter: nft_set_pipapo: move cloning of match info to insert/removal path
Date: Wed, 04 Mar 2026 20:55:26 +0400	[thread overview]
Message-ID: <1772643278.pipapo-v3.7@gmail.com> (raw)
In-Reply-To: <1772643278.pipapo-v3.0@gmail.com>

Adaptation of commit 3f1d886cc7c3 ("netfilter: nft_set_pipapo: move
cloning of match info to insert/removal path") to 6.6.122.

Currently pipapo_clone() is called from the commit and abort
callbacks.  commit and abort must not fail, but pipapo_clone()
can fail with ENOMEM.

Move pipapo_clone() from the commit/abort callbacks to the
insert and removal paths via pipapo_maybe_clone(), which
creates the working copy on demand and can propagate allocation
failures.

commit just swaps clone to match and sets clone to NULL.
abort just frees the clone.

Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Natarajan KV <natarajankv91@gmail.com>
---
 net/netfilter/nft_set_pipapo.c | 89 ++++++++++++++++++----------------
 1 file changed, 46 insertions(+), 43 deletions(-)

diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 176f1a8956a9..57b45e3b11ca 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -1208,14 +1208,16 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
 	union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
 	const u8 *start = (const u8 *)elem->key.val.data, *end;
 	struct nft_pipapo_elem *e = elem->priv, *dup;
-	struct nft_pipapo *priv = nft_set_priv(set);
-	struct nft_pipapo_match *m = priv->clone;
+	struct nft_pipapo_match *m = pipapo_maybe_clone(set);
 	u8 genmask = nft_genmask_next(net);
 	u64 tstamp = nft_net_tstamp(net);
 	struct nft_pipapo_field *f;
 	const u8 *start_p, *end_p;
 	int i, bsize_max, err = 0;
 
+	if (!m)
+		return -ENOMEM;
+
 	if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
 		end = (const u8 *)nft_set_ext_key_end(ext)->data;
 	else
@@ -1269,8 +1271,6 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
 	}
 
 	/* Insert */
-	priv->dirty = true;
-
 	bsize_max = m->bsize_max;
 
 	nft_pipapo_for_each_field(f, i, m) {
@@ -1630,8 +1630,6 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
 		 * NFT_SET_ELEM_DEAD_BIT.
 		 */
 		if (__nft_set_elem_expired(&e->ext, tstamp)) {
-			priv->dirty = true;
-
 			gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
 			if (!gc)
 				return;
@@ -1709,46 +1707,54 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
 static void nft_pipapo_commit(struct nft_set *set)
 {
 	struct nft_pipapo *priv = nft_set_priv(set);
-	struct nft_pipapo_match *new_clone, *old;
-
-	if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
-		pipapo_gc(set, priv->clone);
-
-	if (!priv->dirty)
-		return;
+	struct nft_pipapo_match *old;
 
-	new_clone = pipapo_clone(priv->clone);
-	if (!new_clone)
+	if (!priv->clone)
 		return;
 
-	priv->dirty = false;
+	if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
+		pipapo_gc(set, priv->clone);
 
 	old = rcu_access_pointer(priv->match);
 	rcu_assign_pointer(priv->match, priv->clone);
+	priv->clone = NULL;
+
 	if (old)
 		call_rcu(&old->rcu, pipapo_reclaim_match);
-
-	priv->clone = new_clone;
 }
 
-static void nft_pipapo_abort(const struct nft_set *set)
+static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old);
+
+/**
+ * pipapo_maybe_clone() - Build clone for pending data changes, if not existing
+ * @set:	nftables API set representation
+ *
+ * Return: newly created or existing clone, if any. NULL on allocation failure.
+ */
+static struct nft_pipapo_match *pipapo_maybe_clone(const struct nft_set *set)
 {
 	struct nft_pipapo *priv = nft_set_priv(set);
-	struct nft_pipapo_match *new_clone, *m;
+	struct nft_pipapo_match *m;
 
-	if (!priv->dirty)
-		return;
+	if (priv->clone)
+		return priv->clone;
 
-	m = rcu_dereference_protected(priv->match, nft_pipapo_transaction_mutex_held(set));
+	m = rcu_dereference_protected(priv->match,
+				      nft_pipapo_transaction_mutex_held(set));
+	priv->clone = pipapo_clone(m);
 
-	new_clone = pipapo_clone(m);
-	if (!new_clone)
-		return;
+	return priv->clone;
+}
 
-	priv->dirty = false;
+static void nft_pipapo_abort(const struct nft_set *set)
+{
+	struct nft_pipapo *priv = nft_set_priv(set);
+
+	if (!priv->clone)
+		return;
 
 	pipapo_free_match(priv->clone);
-	priv->clone = new_clone;
+	priv->clone = NULL;
 }
 
 /**
@@ -1787,10 +1793,13 @@ static void nft_pipapo_activate(const struct net *net,
 static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
 			       const u8 *data, const struct nft_set_ext *ext)
 {
-	struct nft_pipapo *priv = nft_set_priv(set);
+	struct nft_pipapo_match *m = pipapo_maybe_clone(set);
 	struct nft_pipapo_elem *e;
 
-	e = pipapo_get(priv->clone, data, nft_genmask_next(net), nft_net_tstamp(net));
+	if (!m)
+		return NULL;
+
+	e = pipapo_get(m, data, nft_genmask_next(net), nft_net_tstamp(net));
 	if (IS_ERR(e))
 		return NULL;
 
@@ -1973,8 +1982,7 @@ static bool pipapo_match_field(struct nft_pipapo_field *f,
 static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
 			      const struct nft_set_elem *elem)
 {
-	struct nft_pipapo *priv = nft_set_priv(set);
-	struct nft_pipapo_match *m = priv->clone;
+	struct nft_pipapo_match *m = pipapo_maybe_clone(set);
 	struct nft_pipapo_elem *e = elem->priv;
 	int rules_f0, first_rule = 0;
 	const u8 *data;
@@ -2014,7 +2022,6 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
 			match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
 
 			if (last && f->mt[rulemap[i].to].e == e) {
-				priv->dirty = true;
 				pipapo_drop(m, rulemap);
 				return;
 			}
@@ -2087,7 +2094,11 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
 
 	switch (iter->type) {
 	case NFT_ITER_UPDATE:
-		m = priv->clone;
+		m = pipapo_maybe_clone(set);
+		if (!m) {
+			iter->err = -ENOMEM;
+			break;
+		}
 		nft_pipapo_do_walk(ctx, set, m, iter);
 		break;
 	case NFT_ITER_READ:
@@ -2199,20 +2210,12 @@ static int nft_pipapo_init(const struct nft_set *set,
 		f->mt = NULL;
 	}
 
-	/* Create an initial clone of matching data for next insertion */
-	priv->clone = pipapo_clone(m);
-	if (!priv->clone) {
-		err = -ENOMEM;
-		goto out_free;
-	}
-
-	priv->dirty = false;
+	priv->clone = NULL;
 
 	rcu_assign_pointer(priv->match, m);
 
 	return 0;
 
-out_free:
 	free_percpu(m->scratch);
 out_scratch:
 	kfree(m);
-- 
2.34.1


  parent reply	other threads:[~2026-03-04 16:55 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-04 13:38 [PATCH] netfilter: nft_set_pipapo: clear dirty flag on abort/commit clone failure Natarajan KV
2026-03-04 13:47 ` Greg KH
2026-03-04 13:50 ` Florian Westphal
2026-03-04 15:08 ` [PATCH v2] netfilter: nft_set_pipapo: move clone allocation to insert/removal path Natarajan KV
2026-03-04 15:12   ` Greg KH
2026-03-04 16:54     ` [PATCH v3 6.6.y 0/8] " Natarajan KV
2026-03-04 16:54       ` [PATCH v3 6.6.y 1/8] netfilter: nft_set_pipapo: move prove_locking helper around Natarajan KV
2026-03-04 16:54       ` [PATCH v3 6.6.y 2/8] netfilter: nft_set_pipapo: make pipapo_clone helper return NULL Natarajan KV
2026-03-04 16:55       ` [PATCH v3 6.6.y 3/8] netfilter: nft_set_pipapo: prepare destroy function for on-demand clone Natarajan KV
2026-03-04 16:55       ` [PATCH v3 6.6.y 4/8] netfilter: nft_set_pipapo: prepare walk " Natarajan KV
2026-03-04 16:55       ` [PATCH v3 6.6.y 5/8] netfilter: nft_set_pipapo: merge deactivate helper into caller Natarajan KV
2026-03-04 16:55       ` [PATCH v3 6.6.y 6/8] netfilter: nft_set_pipapo: prepare pipapo_get helper for on-demand clone Natarajan KV
2026-03-04 16:55       ` Natarajan KV [this message]
2026-03-04 16:55       ` [PATCH v3 6.6.y 8/8] netfilter: nft_set_pipapo: remove dirty flag Natarajan KV
2026-03-04 21:30       ` [PATCH v3 6.6.y 0/8] netfilter: nft_set_pipapo: move clone allocation to insert/removal path Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1772643278.pipapo-v3.7@gmail.com \
    --to=natarajankv91@gmail.com \
    --cc=fw@strlen.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=kadlec@netfilter.org \
    --cc=pablo@netfilter.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox