const struct tcf_proto *,
                                            struct tcf_result *);
        int                     (*init)(struct tcf_proto*);
-       void                    (*destroy)(struct tcf_proto*);
+       bool                    (*destroy)(struct tcf_proto*, bool);
 
        unsigned long           (*get)(struct tcf_proto*, u32 handle);
        int                     (*change)(struct net *net, struct sk_buff *,
                                const struct Qdisc_ops *ops, u32 parentid);
 void __qdisc_calculate_pkt_len(struct sk_buff *skb,
                               const struct qdisc_size_table *stab);
-void tcf_destroy(struct tcf_proto *tp);
+bool tcf_destroy(struct tcf_proto *tp, bool force);
 void tcf_destroy_chain(struct tcf_proto __rcu **fl);
 
 /* Reset all TX qdiscs greater then index of a device.  */
 
                        RCU_INIT_POINTER(*back, next);
 
                        tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
-                       tcf_destroy(tp);
+                       tcf_destroy(tp, true);
                        err = 0;
                        goto errout;
                }
                        err = -EEXIST;
                        if (n->nlmsg_flags & NLM_F_EXCL) {
                                if (tp_created)
-                                       tcf_destroy(tp);
+                                       tcf_destroy(tp, true);
                                goto errout;
                        }
                        break;
                case RTM_DELTFILTER:
                        err = tp->ops->delete(tp, fh);
-                       if (err == 0)
+                       if (err == 0) {
                                tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
+                               if (tcf_destroy(tp, false)) {
+                                       struct tcf_proto *next = rtnl_dereference(tp->next);
+
+                                       RCU_INIT_POINTER(*back, next);
+                               }
+                       }
                        goto errout;
                case RTM_GETTFILTER:
                        err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
                tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
        } else {
                if (tp_created)
-                       tcf_destroy(tp);
+                       tcf_destroy(tp, true);
        }
 
 errout:
 
        kfree(f);
 }
 
-static void basic_destroy(struct tcf_proto *tp)
+static bool basic_destroy(struct tcf_proto *tp, bool force)
 {
        struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f, *n;
 
+       if (!force && !list_empty(&head->flist))
+               return false;
+
        list_for_each_entry_safe(f, n, &head->flist, link) {
                list_del_rcu(&f->link);
                tcf_unbind_filter(tp, &f->res);
        }
        RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
+       return true;
 }
 
 static int basic_delete(struct tcf_proto *tp, unsigned long arg)
 
        return 0;
 }
 
-static void cls_bpf_destroy(struct tcf_proto *tp)
+static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
        struct cls_bpf_prog *prog, *tmp;
 
+       if (!force && !list_empty(&head->plist))
+               return false;
+
        list_for_each_entry_safe(prog, tmp, &head->plist, link) {
                list_del_rcu(&prog->link);
                tcf_unbind_filter(tp, &prog->res);
 
        RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
+       return true;
 }
 
 static unsigned long cls_bpf_get(struct tcf_proto *tp, u32 handle)
 
        return err;
 }
 
-static void cls_cgroup_destroy(struct tcf_proto *tp)
+static bool cls_cgroup_destroy(struct tcf_proto *tp, bool force)
 {
        struct cls_cgroup_head *head = rtnl_dereference(tp->root);
 
+       if (!force)
+               return false;
+
        if (head) {
                RCU_INIT_POINTER(tp->root, NULL);
                call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
        }
+       return true;
 }
 
 static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg)
 
        return 0;
 }
 
-static void flow_destroy(struct tcf_proto *tp)
+static bool flow_destroy(struct tcf_proto *tp, bool force)
 {
        struct flow_head *head = rtnl_dereference(tp->root);
        struct flow_filter *f, *next;
 
+       if (!force && !list_empty(&head->filters))
+               return false;
+
        list_for_each_entry_safe(f, next, &head->filters, list) {
                list_del_rcu(&f->list);
                call_rcu(&f->rcu, flow_destroy_filter);
        }
        RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
+       return true;
 }
 
 static unsigned long flow_get(struct tcf_proto *tp, u32 handle)
 
        kfree(f);
 }
 
-static void fw_destroy(struct tcf_proto *tp)
+static bool fw_destroy(struct tcf_proto *tp, bool force)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
        struct fw_filter *f;
        int h;
 
        if (head == NULL)
-               return;
+               return true;
+
+       if (!force) {
+               for (h = 0; h < HTSIZE; h++)
+                       if (rcu_access_pointer(head->ht[h]))
+                               return false;
+       }
 
        for (h = 0; h < HTSIZE; h++) {
                while ((f = rtnl_dereference(head->ht[h])) != NULL) {
        }
        RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
+       return true;
 }
 
 static int fw_delete(struct tcf_proto *tp, unsigned long arg)
 
        kfree(f);
 }
 
-static void route4_destroy(struct tcf_proto *tp)
+static bool route4_destroy(struct tcf_proto *tp, bool force)
 {
        struct route4_head *head = rtnl_dereference(tp->root);
        int h1, h2;
 
        if (head == NULL)
-               return;
+               return true;
+
+       if (!force) {
+               for (h1 = 0; h1 <= 256; h1++) {
+                       if (rcu_access_pointer(head->table[h1]))
+                               return false;
+               }
+       }
 
        for (h1 = 0; h1 <= 256; h1++) {
                struct route4_bucket *b;
        }
        RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
+       return true;
 }
 
 static int route4_delete(struct tcf_proto *tp, unsigned long arg)
 
        kfree_rcu(f, rcu);
 }
 
-static void rsvp_destroy(struct tcf_proto *tp)
+static bool rsvp_destroy(struct tcf_proto *tp, bool force)
 {
        struct rsvp_head *data = rtnl_dereference(tp->root);
        int h1, h2;
 
        if (data == NULL)
-               return;
+               return true;
+
+       if (!force) {
+               for (h1 = 0; h1 < 256; h1++) {
+                       if (rcu_access_pointer(data->ht[h1]))
+                               return false;
+               }
+       }
 
        RCU_INIT_POINTER(tp->root, NULL);
 
                }
        }
        kfree_rcu(data, rcu);
+       return true;
 }
 
 static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
 
        }
 }
 
-static void tcindex_destroy(struct tcf_proto *tp)
+static bool tcindex_destroy(struct tcf_proto *tp, bool force)
 {
        struct tcindex_data *p = rtnl_dereference(tp->root);
        struct tcf_walker walker;
 
+       if (!force)
+               return false;
+
        pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
        walker.count = 0;
        walker.skip = 0;
 
        RCU_INIT_POINTER(tp->root, NULL);
        call_rcu(&p->rcu, __tcindex_destroy);
+       return true;
 }
 
 
 
        return -ENOENT;
 }
 
-static void u32_destroy(struct tcf_proto *tp)
+static bool ht_empty(struct tc_u_hnode *ht)
+{
+       unsigned int h;
+
+       for (h = 0; h <= ht->divisor; h++)
+               if (rcu_access_pointer(ht->ht[h]))
+                       return false;
+
+       return true;
+}
+
+static bool u32_destroy(struct tcf_proto *tp, bool force)
 {
        struct tc_u_common *tp_c = tp->data;
        struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
 
        WARN_ON(root_ht == NULL);
 
+       if (!force) {
+               if (root_ht) {
+                       if (root_ht->refcnt > 1)
+                               return false;
+                       if (root_ht->refcnt == 1) {
+                               if (!ht_empty(root_ht))
+                                       return false;
+                       }
+               }
+       }
+
        if (root_ht && --root_ht->refcnt == 0)
                u32_destroy_hnode(tp, root_ht);
 
        }
 
        tp->data = NULL;
+       return true;
 }
 
 static int u32_delete(struct tcf_proto *tp, unsigned long arg)
 
 }
 EXPORT_SYMBOL(tc_classify);
 
-void tcf_destroy(struct tcf_proto *tp)
+bool tcf_destroy(struct tcf_proto *tp, bool force)
 {
-       tp->ops->destroy(tp);
-       module_put(tp->ops->owner);
-       kfree_rcu(tp, rcu);
+       if (tp->ops->destroy(tp, force)) {
+               module_put(tp->ops->owner);
+               kfree_rcu(tp, rcu);
+               return true;
+       }
+
+       return false;
 }
 
 void tcf_destroy_chain(struct tcf_proto __rcu **fl)
 
        while ((tp = rtnl_dereference(*fl)) != NULL) {
                RCU_INIT_POINTER(*fl, tp->next);
-               tcf_destroy(tp);
+               tcf_destroy(tp, true);
        }
 }
 EXPORT_SYMBOL(tcf_destroy_chain);