kfree(trans);
 }
 
-static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
+static void __nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set,
+                                bool bind)
 {
        struct nftables_pernet *nft_net;
        struct net *net = ctx->net;
                switch (trans->msg_type) {
                case NFT_MSG_NEWSET:
                        if (nft_trans_set(trans) == set)
-                               nft_trans_set_bound(trans) = true;
+                               nft_trans_set_bound(trans) = bind;
                        break;
                case NFT_MSG_NEWSETELEM:
                        if (nft_trans_elem_set(trans) == set)
-                               nft_trans_elem_set_bound(trans) = true;
+                               nft_trans_elem_set_bound(trans) = bind;
                        break;
                }
        }
 }
 
-static void nft_chain_trans_bind(const struct nft_ctx *ctx, struct nft_chain *chain)
+static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
+{
+       return __nft_set_trans_bind(ctx, set, true);
+}
+
+static void nft_set_trans_unbind(const struct nft_ctx *ctx, struct nft_set *set)
+{
+       return __nft_set_trans_bind(ctx, set, false);
+}
+
+static void __nft_chain_trans_bind(const struct nft_ctx *ctx,
+                                  struct nft_chain *chain, bool bind)
 {
        struct nftables_pernet *nft_net;
        struct net *net = ctx->net;
                switch (trans->msg_type) {
                case NFT_MSG_NEWCHAIN:
                        if (nft_trans_chain(trans) == chain)
-                               nft_trans_chain_bound(trans) = true;
+                               nft_trans_chain_bound(trans) = bind;
                        break;
                case NFT_MSG_NEWRULE:
                        if (trans->ctx.chain == chain)
-                               nft_trans_rule_bound(trans) = true;
+                               nft_trans_rule_bound(trans) = bind;
                        break;
                }
        }
 }
 
+static void nft_chain_trans_bind(const struct nft_ctx *ctx,
+                                struct nft_chain *chain)
+{
+       __nft_chain_trans_bind(ctx, chain, true);
+}
+
 int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
 {
        if (!nft_chain_binding(chain))
        return 0;
 }
 
+void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
+{
+       __nft_chain_trans_bind(ctx, chain, false);
+}
+
 static int nft_netdev_register_hooks(struct net *net,
                                     struct list_head *hook_list)
 {
        if (flow)
                nft_flow_rule_destroy(flow);
 err_release_rule:
-       nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
+       nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR);
        nf_tables_rule_destroy(&ctx, rule);
 err_release_expr:
        for (i = 0; i < n; i++) {
                              enum nft_trans_phase phase)
 {
        switch (phase) {
+       case NFT_TRANS_PREPARE_ERROR:
+               nft_set_trans_unbind(ctx, set);
+               if (nft_set_is_anonymous(set))
+                       nft_deactivate_next(ctx->net, set);
+
+               set->use--;
+               break;
        case NFT_TRANS_PREPARE:
                if (nft_set_is_anonymous(set))
                        nft_deactivate_next(ctx->net, set);
                                    enum nft_trans_phase phase)
 {
        switch (phase) {
+       case NFT_TRANS_PREPARE_ERROR:
        case NFT_TRANS_PREPARE:
        case NFT_TRANS_ABORT:
        case NFT_TRANS_RELEASE: