|
|
@@ -3585,6 +3585,9 @@ err1:
|
|
|
|
|
|
static void nft_set_destroy(struct nft_set *set)
|
|
|
{
|
|
|
+ if (WARN_ON(set->use > 0))
|
|
|
+ return;
|
|
|
+
|
|
|
set->ops->destroy(set);
|
|
|
module_put(to_set_type(set->ops)->owner);
|
|
|
kfree(set->name);
|
|
|
@@ -3625,7 +3628,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
|
|
|
NL_SET_BAD_ATTR(extack, attr);
|
|
|
return PTR_ERR(set);
|
|
|
}
|
|
|
- if (!list_empty(&set->bindings) ||
|
|
|
+ if (set->use ||
|
|
|
(nlh->nlmsg_flags & NLM_F_NONREC && atomic_read(&set->nelems) > 0)) {
|
|
|
NL_SET_BAD_ATTR(extack, attr);
|
|
|
return -EBUSY;
|
|
|
@@ -3655,6 +3658,9 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|
|
struct nft_set_binding *i;
|
|
|
struct nft_set_iter iter;
|
|
|
|
|
|
+ if (set->use == UINT_MAX)
|
|
|
+ return -EOVERFLOW;
|
|
|
+
|
|
|
if (!list_empty(&set->bindings) && nft_set_is_anonymous(set))
|
|
|
return -EBUSY;
|
|
|
|
|
|
@@ -3682,6 +3688,7 @@ bind:
|
|
|
binding->chain = ctx->chain;
|
|
|
list_add_tail_rcu(&binding->list, &set->bindings);
|
|
|
nft_set_trans_bind(ctx, set);
|
|
|
+ set->use++;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -3701,6 +3708,25 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nf_tables_unbind_set);
|
|
|
|
|
|
+void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|
|
+ struct nft_set_binding *binding,
|
|
|
+ enum nft_trans_phase phase)
|
|
|
+{
|
|
|
+ switch (phase) {
|
|
|
+ case NFT_TRANS_PREPARE:
|
|
|
+ set->use--;
|
|
|
+ return;
|
|
|
+ case NFT_TRANS_ABORT:
|
|
|
+ case NFT_TRANS_RELEASE:
|
|
|
+ set->use--;
|
|
|
+ /* fall through */
|
|
|
+ default:
|
|
|
+ nf_tables_unbind_set(ctx, set, binding,
|
|
|
+ phase == NFT_TRANS_COMMIT);
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(nf_tables_deactivate_set);
|
|
|
+
|
|
|
void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set)
|
|
|
{
|
|
|
if (list_empty(&set->bindings) && nft_set_is_anonymous(set))
|