struct basic_head {
        u32                     hgenerator;
        struct list_head        flist;
+       struct rcu_head         rcu;
 };
 
 struct basic_filter {
        struct tcf_exts         exts;
        struct tcf_ematch_tree  ematches;
        struct tcf_result       res;
+       struct tcf_proto        *tp;
        struct list_head        link;
+       struct rcu_head         rcu;
 };
 
 static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                          struct tcf_result *res)
 {
        int r;
-       struct basic_head *head = tp->root;
+       struct basic_head *head = rcu_dereference_bh(tp->root);
        struct basic_filter *f;
 
-       list_for_each_entry(f, &head->flist, link) {
+       list_for_each_entry_rcu(f, &head->flist, link) {
                if (!tcf_em_tree_match(skb, &f->ematches, NULL))
                        continue;
                *res = f->res;
 static unsigned long basic_get(struct tcf_proto *tp, u32 handle)
 {
        unsigned long l = 0UL;
-       struct basic_head *head = tp->root;
+       struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f;
 
        if (head == NULL)
        if (head == NULL)
                return -ENOBUFS;
        INIT_LIST_HEAD(&head->flist);
-       tp->root = head;
+       rcu_assign_pointer(tp->root, head);
        return 0;
 }
 
-static void basic_delete_filter(struct tcf_proto *tp, struct basic_filter *f)
+static void basic_delete_filter(struct rcu_head *head)
 {
+       struct basic_filter *f = container_of(head, struct basic_filter, rcu);
+       struct tcf_proto *tp = f->tp;
+
        tcf_unbind_filter(tp, &f->res);
        tcf_exts_destroy(tp, &f->exts);
        tcf_em_tree_destroy(tp, &f->ematches);
 
 static void basic_destroy(struct tcf_proto *tp)
 {
-       struct basic_head *head = tp->root;
+       struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f, *n;
 
        list_for_each_entry_safe(f, n, &head->flist, link) {
-               list_del(&f->link);
-               basic_delete_filter(tp, f);
+               list_del_rcu(&f->link);
+               call_rcu(&f->rcu, basic_delete_filter);
        }
-       kfree(head);
+       RCU_INIT_POINTER(tp->root, NULL);
+       kfree_rcu(head, rcu);
 }
 
 static int basic_delete(struct tcf_proto *tp, unsigned long arg)
 {
-       struct basic_head *head = tp->root;
+       struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *t, *f = (struct basic_filter *) arg;
 
        list_for_each_entry(t, &head->flist, link)
                if (t == f) {
-                       tcf_tree_lock(tp);
-                       list_del(&t->link);
-                       tcf_tree_unlock(tp);
-                       basic_delete_filter(tp, t);
+                       list_del_rcu(&t->link);
+                       call_rcu(&t->rcu, basic_delete_filter);
                        return 0;
                }
 
 
        tcf_exts_change(tp, &f->exts, &e);
        tcf_em_tree_change(tp, &f->ematches, &t);
+       f->tp = tp;
 
        return 0;
 errout:
                        struct nlattr **tca, unsigned long *arg, bool ovr)
 {
        int err;
-       struct basic_head *head = tp->root;
+       struct basic_head *head = rtnl_dereference(tp->root);
        struct nlattr *tb[TCA_BASIC_MAX + 1];
-       struct basic_filter *f = (struct basic_filter *) *arg;
+       struct basic_filter *fold = (struct basic_filter *) *arg;
+       struct basic_filter *fnew;
 
        if (tca[TCA_OPTIONS] == NULL)
                return -EINVAL;
        if (err < 0)
                return err;
 
-       if (f != NULL) {
-               if (handle && f->handle != handle)
+       if (fold != NULL) {
+               if (handle && fold->handle != handle)
                        return -EINVAL;
-               return basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
        }
 
        err = -ENOBUFS;
-       f = kzalloc(sizeof(*f), GFP_KERNEL);
-       if (f == NULL)
+       fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
+       if (fnew == NULL)
                goto errout;
 
-       tcf_exts_init(&f->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE);
+       tcf_exts_init(&fnew->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE);
        err = -EINVAL;
-       if (handle)
-               f->handle = handle;
-       else {
+       if (handle) {
+               fnew->handle = handle;
+       } else if (fold) {
+               fnew->handle = fold->handle;
+       } else {
                unsigned int i = 0x80000000;
                do {
                        if (++head->hgenerator == 0x7FFFFFFF)
                        goto errout;
                }
 
-               f->handle = head->hgenerator;
+               fnew->handle = head->hgenerator;
        }
 
-       err = basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
+       err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr);
        if (err < 0)
                goto errout;
 
-       tcf_tree_lock(tp);
-       list_add(&f->link, &head->flist);
-       tcf_tree_unlock(tp);
-       *arg = (unsigned long) f;
+       *arg = (unsigned long)fnew;
+
+       if (fold) {
+               list_replace_rcu(&fold->link, &fnew->link);
+               call_rcu(&fold->rcu, basic_delete_filter);
+       } else {
+               list_add_rcu(&fnew->link, &head->flist);
+       }
 
        return 0;
 errout:
-       if (*arg == 0UL && f)
-               kfree(f);
-
+       kfree(fnew);
        return err;
 }
 
 static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 {
-       struct basic_head *head = tp->root;
+       struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f;
 
        list_for_each_entry(f, &head->flist, link) {