Skip to content

Commit 6c108d9

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: nft_set_pipapo: prepare walk function for on-demand clone
The existing code uses iter->type to figure out what data is needed, the live copy (READ) or clone (UPDATE). Without pending updates, priv->clone and priv->match will point to different memory locations, but they have identical content. Future patch will make priv->clone == NULL if there are no pending changes, in this case we must copy the live data for the UPDATE case. Currently this would require GFP_ATOMIC allocation. Split the walk function in two parts: one that does the walk and one that decides which data is needed. In the UPDATE case, callers hold the transaction mutex so we do not need the rcu read lock. This allows to use GFP_KERNEL allocation while cloning. Signed-off-by: Florian Westphal <fw@strlen.de> Reviewed-by: Stefano Brivio <sbrivio@redhat.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 8b8a241 commit 6c108d9

1 file changed

Lines changed: 39 additions & 21 deletions

File tree

net/netfilter/nft_set_pipapo.c

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,35 +2106,23 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
21062106
}
21072107

21082108
/**
2109-
* nft_pipapo_walk() - Walk over elements
2109+
* nft_pipapo_do_walk() - Walk over elements in m
21102110
* @ctx: nftables API context
21112111
* @set: nftables API set representation
2112+
* @m: matching data pointing to key mapping array
21122113
* @iter: Iterator
21132114
*
21142115
* As elements are referenced in the mapping array for the last field, directly
21152116
* scan that array: there's no need to follow rule mappings from the first
2116-
* field.
2117+
* field. @m is protected either by RCU read lock or by transaction mutex.
21172118
*/
2118-
static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
2119-
struct nft_set_iter *iter)
2119+
static void nft_pipapo_do_walk(const struct nft_ctx *ctx, struct nft_set *set,
2120+
const struct nft_pipapo_match *m,
2121+
struct nft_set_iter *iter)
21202122
{
2121-
struct nft_pipapo *priv = nft_set_priv(set);
2122-
const struct nft_pipapo_match *m;
21232123
const struct nft_pipapo_field *f;
21242124
unsigned int i, r;
21252125

2126-
WARN_ON_ONCE(iter->type != NFT_ITER_READ &&
2127-
iter->type != NFT_ITER_UPDATE);
2128-
2129-
rcu_read_lock();
2130-
if (iter->type == NFT_ITER_READ)
2131-
m = rcu_dereference(priv->match);
2132-
else
2133-
m = priv->clone;
2134-
2135-
if (unlikely(!m))
2136-
goto out;
2137-
21382126
for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
21392127
;
21402128

@@ -2151,14 +2139,44 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
21512139

21522140
iter->err = iter->fn(ctx, set, iter, &e->priv);
21532141
if (iter->err < 0)
2154-
goto out;
2142+
return;
21552143

21562144
cont:
21572145
iter->count++;
21582146
}
2147+
}
21592148

2160-
out:
2161-
rcu_read_unlock();
2149+
/**
2150+
* nft_pipapo_walk() - Walk over elements
2151+
* @ctx: nftables API context
2152+
* @set: nftables API set representation
2153+
* @iter: Iterator
2154+
*
2155+
* Test if destructive action is needed or not, clone active backend if needed
2156+
* and call the real function to work on the data.
2157+
*/
2158+
static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
2159+
struct nft_set_iter *iter)
2160+
{
2161+
struct nft_pipapo *priv = nft_set_priv(set);
2162+
const struct nft_pipapo_match *m;
2163+
2164+
switch (iter->type) {
2165+
case NFT_ITER_UPDATE:
2166+
m = priv->clone;
2167+
nft_pipapo_do_walk(ctx, set, m, iter);
2168+
break;
2169+
case NFT_ITER_READ:
2170+
rcu_read_lock();
2171+
m = rcu_dereference(priv->match);
2172+
nft_pipapo_do_walk(ctx, set, m, iter);
2173+
rcu_read_unlock();
2174+
break;
2175+
default:
2176+
iter->err = -EINVAL;
2177+
WARN_ON_ONCE(1);
2178+
break;
2179+
}
21622180
}
21632181

21642182
/**

0 commit comments

Comments
 (0)