return __nft_trans_set_add(ctx, msg_type, set, NULL);
 }
 
+static void nft_setelem_data_deactivate(const struct net *net,
+                                       const struct nft_set *set,
+                                       struct nft_set_elem *elem);
+
+static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
+                                 struct nft_set *set,
+                                 const struct nft_set_iter *iter,
+                                 struct nft_set_elem *elem)
+{
+       nft_setelem_data_deactivate(ctx->net, set, elem);
+
+       return 0;
+}
+
+struct nft_set_elem_catchall {
+       struct list_head        list;
+       struct rcu_head         rcu;
+       void                    *elem;
+};
+
+static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
+                                       struct nft_set *set)
+{
+       u8 genmask = nft_genmask_next(ctx->net);
+       struct nft_set_elem_catchall *catchall;
+       struct nft_set_elem elem;
+       struct nft_set_ext *ext;
+
+       list_for_each_entry(catchall, &set->catchall_list, list) {
+               ext = nft_set_elem_ext(set, catchall->elem);
+               if (!nft_set_elem_active(ext, genmask))
+                       continue;
+
+               elem.priv = catchall->elem;
+               nft_setelem_data_deactivate(ctx->net, set, &elem);
+               break;
+       }
+}
+
+static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
+{
+       struct nft_set_iter iter = {
+               .genmask        = nft_genmask_next(ctx->net),
+               .fn             = nft_mapelem_deactivate,
+       };
+
+       set->ops->walk(ctx, set, &iter);
+       WARN_ON_ONCE(iter.err);
+
+       nft_map_catchall_deactivate(ctx, set);
+}
+
 static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
 {
        int err;
        if (err < 0)
                return err;
 
+       if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
+               nft_map_deactivate(ctx, set);
+
        nft_deactivate_next(ctx->net, set);
        ctx->table->use--;
 
        return 0;
 }
 
-struct nft_set_elem_catchall {
-       struct list_head        list;
-       struct rcu_head         rcu;
-       void                    *elem;
-};
-
 int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
 {
        u8 genmask = nft_genmask_next(ctx->net);
        for (i = 0; i < set->num_exprs; i++)
                nft_expr_destroy(&ctx, set->exprs[i]);
 err_set_destroy:
-       ops->destroy(set);
+       ops->destroy(&ctx, set);
 err_set_init:
        kfree(set->name);
 err_set_name:
 
        list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
                list_del_rcu(&catchall->list);
-               nft_set_elem_destroy(set, catchall->elem, true);
+               nf_tables_set_elem_destroy(ctx, set, catchall->elem);
                kfree_rcu(catchall, rcu);
        }
 }
        for (i = 0; i < set->num_exprs; i++)
                nft_expr_destroy(ctx, set->exprs[i]);
 
-       set->ops->destroy(set);
+       set->ops->destroy(ctx, set);
        nft_set_catchall_destroy(ctx, set);
        kfree(set->name);
        kvfree(set);
        }
 }
 
+static void nft_setelem_data_activate(const struct net *net,
+                                     const struct nft_set *set,
+                                     struct nft_set_elem *elem);
+
+static int nft_mapelem_activate(const struct nft_ctx *ctx,
+                               struct nft_set *set,
+                               const struct nft_set_iter *iter,
+                               struct nft_set_elem *elem)
+{
+       nft_setelem_data_activate(ctx->net, set, elem);
+
+       return 0;
+}
+
+static void nft_map_catchall_activate(const struct nft_ctx *ctx,
+                                     struct nft_set *set)
+{
+       u8 genmask = nft_genmask_next(ctx->net);
+       struct nft_set_elem_catchall *catchall;
+       struct nft_set_elem elem;
+       struct nft_set_ext *ext;
+
+       list_for_each_entry(catchall, &set->catchall_list, list) {
+               ext = nft_set_elem_ext(set, catchall->elem);
+               if (!nft_set_elem_active(ext, genmask))
+                       continue;
+
+               elem.priv = catchall->elem;
+               nft_setelem_data_activate(ctx->net, set, &elem);
+               break;
+       }
+}
+
+static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
+{
+       struct nft_set_iter iter = {
+               .genmask        = nft_genmask_next(ctx->net),
+               .fn             = nft_mapelem_activate,
+       };
+
+       set->ops->walk(ctx, set, &iter);
+       WARN_ON_ONCE(iter.err);
+
+       nft_map_catchall_activate(ctx, set);
+}
+
 void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
 {
-       if (nft_set_is_anonymous(set))
+       if (nft_set_is_anonymous(set)) {
+               if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
+                       nft_map_activate(ctx, set);
+
                nft_clear(ctx->net, set);
+       }
 
        set->use++;
 }
                set->use--;
                break;
        case NFT_TRANS_PREPARE:
-               if (nft_set_is_anonymous(set))
-                       nft_deactivate_next(ctx->net, set);
+               if (nft_set_is_anonymous(set)) {
+                       if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
+                               nft_map_deactivate(ctx, set);
 
+                       nft_deactivate_next(ctx->net, set);
+               }
                set->use--;
                return;
        case NFT_TRANS_ABORT:
        case NFT_TRANS_RELEASE:
+               if (nft_set_is_anonymous(set) &&
+                   set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
+                       nft_map_deactivate(ctx, set);
+
                set->use--;
                fallthrough;
        default:
                __nft_set_elem_expr_destroy(ctx, expr);
 }
 
+/* Drop references and destroy. Called from gc, dynset and abort path. */
 void nft_set_elem_destroy(const struct nft_set *set, void *elem,
                          bool destroy_expr)
 {
 }
 EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
 
-/* Only called from commit path, nft_setelem_data_deactivate() already deals
- * with the refcounting from the preparation phase.
+/* Destroy element. References have been already dropped in the preparation
+ * path via nft_setelem_data_deactivate().
  */
-static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
-                                      const struct nft_set *set, void *elem)
+void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
+                               const struct nft_set *set, void *elem)
 {
        struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
 
        if (obj)
                obj->use--;
 err_elem_userdata:
-       nf_tables_set_elem_destroy(ctx, set, elem.priv);
+       nft_set_elem_destroy(set, elem.priv, true);
 err_parse_data:
        if (nla[NFTA_SET_ELEM_DATA] != NULL)
                nft_data_release(&elem.data.val, desc.type);
                case NFT_MSG_DESTROYSET:
                        trans->ctx.table->use++;
                        nft_clear(trans->ctx.net, nft_trans_set(trans));
+                       if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
+                               nft_map_activate(&trans->ctx, nft_trans_set(trans));
+
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWSETELEM:
        list_for_each_entry_safe(set, ns, &table->sets, list) {
                list_del(&set->list);
                table->use--;
+               if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
+                       nft_map_deactivate(&ctx, set);
+
                nft_set_destroy(&ctx, set);
        }
        list_for_each_entry_safe(obj, ne, &table->objects, list) {
 
        return 0;
 }
 
+struct nft_rhash_ctx {
+       const struct nft_ctx    ctx;
+       const struct nft_set    *set;
+};
+
 static void nft_rhash_elem_destroy(void *ptr, void *arg)
 {
-       nft_set_elem_destroy(arg, ptr, true);
+       struct nft_rhash_ctx *rhash_ctx = arg;
+
+       nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, ptr);
 }
 
-static void nft_rhash_destroy(const struct nft_set *set)
+static void nft_rhash_destroy(const struct nft_ctx *ctx,
+                             const struct nft_set *set)
 {
        struct nft_rhash *priv = nft_set_priv(set);
+       struct nft_rhash_ctx rhash_ctx = {
+               .ctx    = *ctx,
+               .set    = set,
+       };
 
        cancel_delayed_work_sync(&priv->gc_work);
        rcu_barrier();
        rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
-                                   (void *)set);
+                                   (void *)&rhash_ctx);
 }
 
 /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
        return 0;
 }
 
-static void nft_hash_destroy(const struct nft_set *set)
+static void nft_hash_destroy(const struct nft_ctx *ctx,
+                            const struct nft_set *set)
 {
        struct nft_hash *priv = nft_set_priv(set);
        struct nft_hash_elem *he;
        for (i = 0; i < priv->buckets; i++) {
                hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
                        hlist_del_rcu(&he->node);
-                       nft_set_elem_destroy(set, he, true);
+                       nf_tables_set_elem_destroy(ctx, set, he);
                }
        }
 }