*     @dtype: data type (verdict or numeric type defined by userspace)
  *     @objtype: object type (see NFT_OBJECT_* definitions)
  *     @size: maximum set size
+ *     @use: number of rules references to this set
  *     @nelems: number of elements
  *     @ndeact: number of deactivated elements queued for removal
  *     @timeout: default timeout value in jiffies
        u32                             dtype;
        u32                             objtype;
        u32                             size;
+       u32                             use;
        atomic_t                        nelems;
        u32                             ndeact;
        u64                             timeout;
        u32                             flags;
 };
 
+enum nft_trans_phase;
+void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
+                             struct nft_set_binding *binding,
+                             enum nft_trans_phase phase);
 int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
                       struct nft_set_binding *binding);
 void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
 
 
 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);
                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;
        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;
 
        binding->chain = ctx->chain;
        list_add_tail_rcu(&binding->list, &set->bindings);
        nft_set_trans_bind(ctx, set);
+       set->use++;
 
        return 0;
 }
 }
 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))
 
 {
        struct nft_dynset *priv = nft_expr_priv(expr);
 
-       if (phase == NFT_TRANS_PREPARE)
-               return;
+       nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
+}
+
+static void nft_dynset_activate(const struct nft_ctx *ctx,
+                               const struct nft_expr *expr)
+{
+       struct nft_dynset *priv = nft_expr_priv(expr);
 
-       nf_tables_unbind_set(ctx, priv->set, &priv->binding,
-                            phase == NFT_TRANS_COMMIT);
+       priv->set->use++;
 }
 
 static void nft_dynset_destroy(const struct nft_ctx *ctx,
        .eval           = nft_dynset_eval,
        .init           = nft_dynset_init,
        .destroy        = nft_dynset_destroy,
+       .activate       = nft_dynset_activate,
        .deactivate     = nft_dynset_deactivate,
        .dump           = nft_dynset_dump,
 };
 
 {
        struct nft_lookup *priv = nft_expr_priv(expr);
 
-       if (phase == NFT_TRANS_PREPARE)
-               return;
+       nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
+}
+
+static void nft_lookup_activate(const struct nft_ctx *ctx,
+                               const struct nft_expr *expr)
+{
+       struct nft_lookup *priv = nft_expr_priv(expr);
 
-       nf_tables_unbind_set(ctx, priv->set, &priv->binding,
-                            phase == NFT_TRANS_COMMIT);
+       priv->set->use++;
 }
 
 static void nft_lookup_destroy(const struct nft_ctx *ctx,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
        .eval           = nft_lookup_eval,
        .init           = nft_lookup_init,
+       .activate       = nft_lookup_activate,
        .deactivate     = nft_lookup_deactivate,
        .destroy        = nft_lookup_destroy,
        .dump           = nft_lookup_dump,
 
 {
        struct nft_objref_map *priv = nft_expr_priv(expr);
 
-       if (phase == NFT_TRANS_PREPARE)
-               return;
+       nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
+}
+
+static void nft_objref_map_activate(const struct nft_ctx *ctx,
+                                   const struct nft_expr *expr)
+{
+       struct nft_objref_map *priv = nft_expr_priv(expr);
 
-       nf_tables_unbind_set(ctx, priv->set, &priv->binding,
-                            phase == NFT_TRANS_COMMIT);
+       priv->set->use++;
 }
 
 static void nft_objref_map_destroy(const struct nft_ctx *ctx,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
        .eval           = nft_objref_map_eval,
        .init           = nft_objref_map_init,
+       .activate       = nft_objref_map_activate,
        .deactivate     = nft_objref_map_deactivate,
        .destroy        = nft_objref_map_destroy,
        .dump           = nft_objref_map_dump,