int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
 
 #ifdef CONFIG_NET_CLS
-void tcf_destroy_chain(struct tcf_proto __rcu **fl);
+int tcf_block_get(struct tcf_block **p_block,
+                 struct tcf_proto __rcu **p_filter_chain);
+void tcf_block_put(struct tcf_block *block);
 int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                 struct tcf_result *res, bool compat_mode);
 
 #else
-static inline void tcf_destroy_chain(struct tcf_proto __rcu **fl)
+static inline
+int tcf_block_get(struct tcf_block **p_block,
+                 struct tcf_proto __rcu **p_filter_chain)
+{
+       return 0;
+}
+
+static inline void tcf_block_put(struct tcf_block *block)
 {
 }
 
 
        void                    (*walk)(struct Qdisc *, struct qdisc_walker * arg);
 
        /* Filter manipulation */
-       struct tcf_proto __rcu ** (*tcf_chain)(struct Qdisc *, unsigned long);
+       struct tcf_block *      (*tcf_block)(struct Qdisc *, unsigned long);
        bool                    (*tcf_cl_offload)(u32 classid);
        unsigned long           (*bind_tcf)(struct Qdisc *, unsigned long,
                                        u32 classid);
        struct Qdisc            *q;
        void                    *data;
        const struct tcf_proto_ops      *ops;
+       struct tcf_block        *block;
        struct rcu_head         rcu;
 };
 
        unsigned char           data[QDISC_CB_PRIV_LEN];
 };
 
+struct tcf_block {
+       struct tcf_proto __rcu **p_filter_chain;
+};
+
 static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
 {
        struct qdisc_skb_cb *qcb;
 
 }
 
 static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
-                                         u32 prio, u32 parent, struct Qdisc *q)
+                                         u32 prio, u32 parent, struct Qdisc *q,
+                                         struct tcf_block *block)
 {
        struct tcf_proto *tp;
        int err;
        tp->prio = prio;
        tp->classid = parent;
        tp->q = q;
+       tp->block = block;
 
        err = tp->ops->init(tp);
        if (err) {
        kfree_rcu(tp, rcu);
 }
 
-void tcf_destroy_chain(struct tcf_proto __rcu **fl)
+static void tcf_destroy_chain(struct tcf_proto __rcu **fl)
 {
        struct tcf_proto *tp;
 
                tcf_proto_destroy(tp);
        }
 }
-EXPORT_SYMBOL(tcf_destroy_chain);
+
+int tcf_block_get(struct tcf_block **p_block,
+                 struct tcf_proto __rcu **p_filter_chain)
+{
+       struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
+
+       if (!block)
+               return -ENOMEM;
+       block->p_filter_chain = p_filter_chain;
+       *p_block = block;
+       return 0;
+}
+EXPORT_SYMBOL(tcf_block_get);
+
+void tcf_block_put(struct tcf_block *block)
+{
+       if (!block)
+               return;
+       tcf_destroy_chain(block->p_filter_chain);
+       kfree(block);
+}
+EXPORT_SYMBOL(tcf_block_put);
 
 /* Main classifier routine: scans classifier chain attached
  * to this qdisc, (optionally) tests for protocol and asks
        struct Qdisc  *q;
        struct tcf_proto __rcu **back;
        struct tcf_proto __rcu **chain;
+       struct tcf_block *block;
        struct tcf_proto *next;
        struct tcf_proto *tp;
        const struct Qdisc_class_ops *cops;
        if (!cops)
                return -EINVAL;
 
-       if (cops->tcf_chain == NULL)
+       if (!cops->tcf_block)
                return -EOPNOTSUPP;
 
        /* Do we search for filter, attached to class? */
        }
 
        /* And the last stroke */
-       chain = cops->tcf_chain(q, cl);
-       if (chain == NULL) {
+       block = cops->tcf_block(q, cl);
+       if (!block) {
                err = -EINVAL;
                goto errout;
        }
+       chain = block->p_filter_chain;
+
        if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
                tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
                tcf_destroy_chain(chain);
                        nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
 
                tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
-                                     protocol, nprio, parent, q);
+                                     protocol, nprio, parent, q, block);
                if (IS_ERR(tp)) {
                        err = PTR_ERR(tp);
                        goto errout;
        int s_t;
        struct net_device *dev;
        struct Qdisc *q;
+       struct tcf_block *block;
        struct tcf_proto *tp, __rcu **chain;
        struct tcmsg *tcm = nlmsg_data(cb->nlh);
        unsigned long cl = 0;
        cops = q->ops->cl_ops;
        if (!cops)
                goto errout;
-       if (cops->tcf_chain == NULL)
+       if (!cops->tcf_block)
                goto errout;
        if (TC_H_MIN(tcm->tcm_parent)) {
                cl = cops->get(q, tcm->tcm_parent);
                if (cl == 0)
                        goto errout;
        }
-       chain = cops->tcf_chain(q, cl);
-       if (chain == NULL)
+       block = cops->tcf_block(q, cl);
+       if (!block)
                goto errout;
+       chain = block->p_filter_chain;
 
        s_t = cb->args[0];
 
 
                if (!(cops->get && cops->put && cops->walk && cops->leaf))
                        goto out_einval;
 
-               if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
+               if (cops->tcf_block && !(cops->bind_tcf && cops->unbind_tcf))
                        goto out_einval;
        }
 
 
 struct atm_flow_data {
        struct Qdisc            *q;     /* FIFO, TBF, etc. */
        struct tcf_proto __rcu  *filter_list;
+       struct tcf_block        *block;
        struct atm_vcc          *vcc;   /* VCC; NULL if VCC is closed */
        void                    (*old_pop)(struct atm_vcc *vcc,
                                           struct sk_buff *skb); /* chaining */
        list_del_init(&flow->list);
        pr_debug("atm_tc_put: qdisc %p\n", flow->q);
        qdisc_destroy(flow->q);
-       tcf_destroy_chain(&flow->filter_list);
+       tcf_block_put(flow->block);
        if (flow->sock) {
                pr_debug("atm_tc_put: f_count %ld\n",
                        file_count(flow->sock->file));
                error = -ENOBUFS;
                goto err_out;
        }
-       RCU_INIT_POINTER(flow->filter_list, NULL);
+
+       error = tcf_block_get(&flow->block, &flow->filter_list);
+       if (error) {
+               kfree(flow);
+               goto err_out;
+       }
+
        flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
        if (!flow->q)
                flow->q = &noop_qdisc;
        }
 }
 
-static struct tcf_proto __rcu **atm_tc_find_tcf(struct Qdisc *sch,
-                                               unsigned long cl)
+static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct atm_qdisc_data *p = qdisc_priv(sch);
        struct atm_flow_data *flow = (struct atm_flow_data *)cl;
 
        pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
-       return flow ? &flow->filter_list : &p->link.filter_list;
+       return flow ? flow->block : p->link.block;
 }
 
 /* --------------------------- Qdisc operations ---------------------------- */
 static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct atm_qdisc_data *p = qdisc_priv(sch);
+       int err;
 
        pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
        INIT_LIST_HEAD(&p->flows);
        if (!p->link.q)
                p->link.q = &noop_qdisc;
        pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
-       RCU_INIT_POINTER(p->link.filter_list, NULL);
+
+       err = tcf_block_get(&p->link.block, &p->link.filter_list);
+       if (err)
+               return err;
+
        p->link.vcc = NULL;
        p->link.sock = NULL;
        p->link.classid = sch->handle;
 
        pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
        list_for_each_entry(flow, &p->flows, list)
-               tcf_destroy_chain(&flow->filter_list);
+               tcf_block_put(flow->block);
 
        list_for_each_entry_safe(flow, tmp, &p->flows, list) {
                if (flow->ref > 1)
        .change         = atm_tc_change,
        .delete         = atm_tc_delete,
        .walk           = atm_tc_walk,
-       .tcf_chain      = atm_tc_find_tcf,
+       .tcf_block      = atm_tc_tcf_block,
        .bind_tcf       = atm_tc_bind_filter,
        .unbind_tcf     = atm_tc_put,
        .dump           = atm_tc_dump_class,
 
        struct tc_cbq_xstats    xstats;
 
        struct tcf_proto __rcu  *filter_list;
+       struct tcf_block        *block;
 
        int                     refcnt;
        int                     filters;
 
        WARN_ON(cl->filters);
 
-       tcf_destroy_chain(&cl->filter_list);
+       tcf_block_put(cl->block);
        qdisc_destroy(cl->q);
        qdisc_put_rtab(cl->R_tab);
        gen_kill_estimator(&cl->rate_est);
         */
        for (h = 0; h < q->clhash.hashsize; h++) {
                hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode)
-                       tcf_destroy_chain(&cl->filter_list);
+                       tcf_block_put(cl->block);
        }
        for (h = 0; h < q->clhash.hashsize; h++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
        if (cl == NULL)
                goto failure;
 
+       err = tcf_block_get(&cl->block, &cl->filter_list);
+       if (err) {
+               kfree(cl);
+               return err;
+       }
+
        if (tca[TCA_RATE]) {
                err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
                                        NULL,
                                        qdisc_root_sleeping_running(sch),
                                        tca[TCA_RATE]);
                if (err) {
+                       tcf_block_put(cl->block);
                        kfree(cl);
                        goto failure;
                }
        return 0;
 }
 
-static struct tcf_proto __rcu **cbq_find_tcf(struct Qdisc *sch,
-                                            unsigned long arg)
+static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg)
 {
        struct cbq_sched_data *q = qdisc_priv(sch);
        struct cbq_class *cl = (struct cbq_class *)arg;
        if (cl == NULL)
                cl = &q->link;
 
-       return &cl->filter_list;
+       return cl->block;
 }
 
 static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
        .change         =       cbq_change_class,
        .delete         =       cbq_delete,
        .walk           =       cbq_walk,
-       .tcf_chain      =       cbq_find_tcf,
+       .tcf_block      =       cbq_tcf_block,
        .bind_tcf       =       cbq_bind_filter,
        .unbind_tcf     =       cbq_unbind_filter,
        .dump           =       cbq_dump_class,
 
 struct drr_sched {
        struct list_head                active;
        struct tcf_proto __rcu          *filter_list;
+       struct tcf_block                *block;
        struct Qdisc_class_hash         clhash;
 };
 
                drr_destroy_class(sch, cl);
 }
 
-static struct tcf_proto __rcu **drr_tcf_chain(struct Qdisc *sch,
-                                             unsigned long cl)
+static struct tcf_block *drr_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct drr_sched *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
 
-       return &q->filter_list;
+       return q->block;
 }
 
 static unsigned long drr_bind_tcf(struct Qdisc *sch, unsigned long parent,
        struct drr_sched *q = qdisc_priv(sch);
        int err;
 
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
        err = qdisc_class_hash_init(&q->clhash);
        if (err < 0)
                return err;
        struct hlist_node *next;
        unsigned int i;
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
 
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
        .delete         = drr_delete_class,
        .get            = drr_get_class,
        .put            = drr_put_class,
-       .tcf_chain      = drr_tcf_chain,
+       .tcf_block      = drr_tcf_block,
        .bind_tcf       = drr_bind_tcf,
        .unbind_tcf     = drr_unbind_tcf,
        .graft          = drr_graft_class,
 
 struct dsmark_qdisc_data {
        struct Qdisc            *q;
        struct tcf_proto __rcu  *filter_list;
+       struct tcf_block        *block;
        struct mask_value       *mv;
        u16                     indices;
        u8                      set_tc_index;
        }
 }
 
-static inline struct tcf_proto __rcu **dsmark_find_tcf(struct Qdisc *sch,
-                                                      unsigned long cl)
+static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct dsmark_qdisc_data *p = qdisc_priv(sch);
-       return &p->filter_list;
+
+       return p->block;
 }
 
 /* --------------------------- Qdisc operations ---------------------------- */
 {
        struct dsmark_qdisc_data *p = qdisc_priv(sch);
        struct nlattr *tb[TCA_DSMARK_MAX + 1];
-       int err = -EINVAL;
+       int err;
        u32 default_index = NO_DEFAULT_INDEX;
        u16 indices;
        int i;
        if (!opt)
                goto errout;
 
+       err = tcf_block_get(&p->block, &p->filter_list);
+       if (err)
+               return err;
+
        err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy, NULL);
        if (err < 0)
                goto errout;
 
        pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
 
-       tcf_destroy_chain(&p->filter_list);
+       tcf_block_put(p->block);
        qdisc_destroy(p->q);
        if (p->mv != p->embedded)
                kfree(p->mv);
        .change         =       dsmark_change,
        .delete         =       dsmark_delete,
        .walk           =       dsmark_walk,
-       .tcf_chain      =       dsmark_find_tcf,
+       .tcf_block      =       dsmark_tcf_block,
        .bind_tcf       =       dsmark_bind_filter,
        .unbind_tcf     =       dsmark_put,
        .dump           =       dsmark_dump_class,
 
 
 struct fq_codel_sched_data {
        struct tcf_proto __rcu *filter_list; /* optional external classifier */
+       struct tcf_block *block;
        struct fq_codel_flow *flows;    /* Flows table [flows_cnt] */
        u32             *backlogs;      /* backlog table [flows_cnt] */
        u32             flows_cnt;      /* number of flows */
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
        kvfree(q->backlogs);
        kvfree(q->flows);
 }
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
        int i;
+       int err;
 
        sch->limit = 10*1024;
        q->flows_cnt = 1024;
                        return err;
        }
 
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
+
        if (!q->flows) {
                q->flows = kvzalloc(q->flows_cnt *
                                           sizeof(struct fq_codel_flow), GFP_KERNEL);
 {
 }
 
-static struct tcf_proto __rcu **fq_codel_find_tcf(struct Qdisc *sch,
-                                                 unsigned long cl)
+static struct tcf_block *fq_codel_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
-       return &q->filter_list;
+       return q->block;
 }
 
 static int fq_codel_dump_class(struct Qdisc *sch, unsigned long cl,
        .leaf           =       fq_codel_leaf,
        .get            =       fq_codel_get,
        .put            =       fq_codel_put,
-       .tcf_chain      =       fq_codel_find_tcf,
+       .tcf_block      =       fq_codel_tcf_block,
        .bind_tcf       =       fq_codel_bind,
        .unbind_tcf     =       fq_codel_put,
        .dump           =       fq_codel_dump_class,
 
        struct gnet_stats_queue qstats;
        struct net_rate_estimator __rcu *rate_est;
        struct tcf_proto __rcu *filter_list; /* filter list */
+       struct tcf_block *block;
        unsigned int    filter_cnt;     /* filter count */
        unsigned int    level;          /* class level in hierarchy */
 
        if (cl == NULL)
                return -ENOBUFS;
 
+       err = tcf_block_get(&cl->block, &cl->filter_list);
+       if (err) {
+               kfree(cl);
+               return err;
+       }
+
        if (tca[TCA_RATE]) {
                err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
                                        NULL,
                                        qdisc_root_sleeping_running(sch),
                                        tca[TCA_RATE]);
                if (err) {
+                       tcf_block_put(cl->block);
                        kfree(cl);
                        return err;
                }
 {
        struct hfsc_sched *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&cl->filter_list);
+       tcf_block_put(cl->block);
        qdisc_destroy(cl->qdisc);
        gen_kill_estimator(&cl->rate_est);
        if (cl != &q->root)
        cl->filter_cnt--;
 }
 
-static struct tcf_proto __rcu **
-hfsc_tcf_chain(struct Qdisc *sch, unsigned long arg)
+static struct tcf_block *hfsc_tcf_block(struct Qdisc *sch, unsigned long arg)
 {
        struct hfsc_sched *q = qdisc_priv(sch);
        struct hfsc_class *cl = (struct hfsc_class *)arg;
        if (cl == NULL)
                cl = &q->root;
 
-       return &cl->filter_list;
+       return cl->block;
 }
 
 static int
 
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode)
-                       tcf_destroy_chain(&cl->filter_list);
+                       tcf_block_put(cl->block);
        }
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
        .put            = hfsc_put_class,
        .bind_tcf       = hfsc_bind_tcf,
        .unbind_tcf     = hfsc_unbind_tcf,
-       .tcf_chain      = hfsc_tcf_chain,
+       .tcf_block      = hfsc_tcf_block,
        .dump           = hfsc_dump_class,
        .dump_stats     = hfsc_dump_class_stats,
        .walk           = hfsc_walk
 
        int                     quantum;        /* but stored for parent-to-leaf return */
 
        struct tcf_proto __rcu  *filter_list;   /* class attached filters */
+       struct tcf_block        *block;
        int                     filter_cnt;
        int                     refcnt;         /* usage count of this class */
 
 
        /* filters for qdisc itself */
        struct tcf_proto __rcu  *filter_list;
+       struct tcf_block        *block;
 
 #define HTB_WARN_TOOMANYEVENTS 0x1
        unsigned int            warned; /* only one warning */
        if (!opt)
                return -EINVAL;
 
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
+
        err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy, NULL);
        if (err < 0)
                return err;
                qdisc_destroy(cl->un.leaf.q);
        }
        gen_kill_estimator(&cl->rate_est);
-       tcf_destroy_chain(&cl->filter_list);
+       tcf_block_put(cl->block);
        kfree(cl);
 }
 
         * because filter need its target class alive to be able to call
         * unbind_filter on it (without Oops).
         */
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
 
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode)
-                       tcf_destroy_chain(&cl->filter_list);
+                       tcf_block_put(cl->block);
        }
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
                if (!cl)
                        goto failure;
 
+               err = tcf_block_get(&cl->block, &cl->filter_list);
+               if (err) {
+                       kfree(cl);
+                       goto failure;
+               }
                if (htb_rate_est || tca[TCA_RATE]) {
                        err = gen_new_estimator(&cl->bstats, NULL,
                                                &cl->rate_est,
                                                qdisc_root_sleeping_running(sch),
                                                tca[TCA_RATE] ? : &est.nla);
                        if (err) {
+                               tcf_block_put(cl->block);
                                kfree(cl);
                                goto failure;
                        }
        return err;
 }
 
-static struct tcf_proto __rcu **htb_find_tcf(struct Qdisc *sch,
-                                            unsigned long arg)
+static struct tcf_block *htb_tcf_block(struct Qdisc *sch, unsigned long arg)
 {
        struct htb_sched *q = qdisc_priv(sch);
        struct htb_class *cl = (struct htb_class *)arg;
-       struct tcf_proto __rcu **fl = cl ? &cl->filter_list : &q->filter_list;
 
-       return fl;
+       return cl ? cl->block : q->block;
 }
 
 static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent,
        .change         =       htb_change_class,
        .delete         =       htb_delete,
        .walk           =       htb_walk,
-       .tcf_chain      =       htb_find_tcf,
+       .tcf_block      =       htb_tcf_block,
        .bind_tcf       =       htb_bind_filter,
        .unbind_tcf     =       htb_unbind_filter,
        .dump           =       htb_dump_class,
 
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
 
+struct ingress_sched_data {
+       struct tcf_block *block;
+};
+
 static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
 {
        return NULL;
 {
 }
 
-static struct tcf_proto __rcu **ingress_find_tcf(struct Qdisc *sch,
-                                                unsigned long cl)
+static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
-       struct net_device *dev = qdisc_dev(sch);
+       struct ingress_sched_data *q = qdisc_priv(sch);
 
-       return &dev->ingress_cl_list;
+       return q->block;
 }
 
 static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
 {
+       struct ingress_sched_data *q = qdisc_priv(sch);
+       struct net_device *dev = qdisc_dev(sch);
+       int err;
+
+       err = tcf_block_get(&q->block, &dev->ingress_cl_list);
+       if (err)
+               return err;
+
        net_inc_ingress_queue();
        sch->flags |= TCQ_F_CPUSTATS;
 
 
 static void ingress_destroy(struct Qdisc *sch)
 {
-       struct net_device *dev = qdisc_dev(sch);
+       struct ingress_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&dev->ingress_cl_list);
+       tcf_block_put(q->block);
        net_dec_ingress_queue();
 }
 
        .get            =       ingress_get,
        .put            =       ingress_put,
        .walk           =       ingress_walk,
-       .tcf_chain      =       ingress_find_tcf,
+       .tcf_block      =       ingress_tcf_block,
        .tcf_cl_offload =       ingress_cl_offload,
        .bind_tcf       =       ingress_bind_filter,
        .unbind_tcf     =       ingress_put,
 static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
        .cl_ops         =       &ingress_class_ops,
        .id             =       "ingress",
+       .priv_size      =       sizeof(struct ingress_sched_data),
        .init           =       ingress_init,
        .destroy        =       ingress_destroy,
        .dump           =       ingress_dump,
        .owner          =       THIS_MODULE,
 };
 
+struct clsact_sched_data {
+       struct tcf_block *ingress_block;
+       struct tcf_block *egress_block;
+};
+
 static unsigned long clsact_get(struct Qdisc *sch, u32 classid)
 {
        switch (TC_H_MIN(classid)) {
        return clsact_get(sch, classid);
 }
 
-static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch,
-                                               unsigned long cl)
+static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
-       struct net_device *dev = qdisc_dev(sch);
+       struct clsact_sched_data *q = qdisc_priv(sch);
 
        switch (cl) {
        case TC_H_MIN(TC_H_MIN_INGRESS):
-               return &dev->ingress_cl_list;
+               return q->ingress_block;
        case TC_H_MIN(TC_H_MIN_EGRESS):
-               return &dev->egress_cl_list;
+               return q->egress_block;
        default:
                return NULL;
        }
 
 static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
 {
+       struct clsact_sched_data *q = qdisc_priv(sch);
+       struct net_device *dev = qdisc_dev(sch);
+       int err;
+
+       err = tcf_block_get(&q->ingress_block, &dev->ingress_cl_list);
+       if (err)
+               return err;
+
+       err = tcf_block_get(&q->egress_block, &dev->egress_cl_list);
+       if (err)
+               return err;
+
        net_inc_ingress_queue();
        net_inc_egress_queue();
 
 
 static void clsact_destroy(struct Qdisc *sch)
 {
-       struct net_device *dev = qdisc_dev(sch);
+       struct clsact_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&dev->ingress_cl_list);
-       tcf_destroy_chain(&dev->egress_cl_list);
+       tcf_block_put(q->egress_block);
+       tcf_block_put(q->ingress_block);
 
        net_dec_ingress_queue();
        net_dec_egress_queue();
        .get            =       clsact_get,
        .put            =       ingress_put,
        .walk           =       ingress_walk,
-       .tcf_chain      =       clsact_find_tcf,
+       .tcf_block      =       clsact_tcf_block,
        .tcf_cl_offload =       clsact_cl_offload,
        .bind_tcf       =       clsact_bind_filter,
        .unbind_tcf     =       ingress_put,
 static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
        .cl_ops         =       &clsact_class_ops,
        .id             =       "clsact",
+       .priv_size      =       sizeof(struct clsact_sched_data),
        .init           =       clsact_init,
        .destroy        =       clsact_destroy,
        .dump           =       ingress_dump,
 
        u16 max_bands;
        u16 curband;
        struct tcf_proto __rcu *filter_list;
+       struct tcf_block *block;
        struct Qdisc **queues;
 };
 
        int band;
        struct multiq_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
        for (band = 0; band < q->bands; band++)
                qdisc_destroy(q->queues[band]);
 
        if (opt == NULL)
                return -EINVAL;
 
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
+
        q->max_bands = qdisc_dev(sch)->num_tx_queues;
 
        q->queues = kcalloc(q->max_bands, sizeof(struct Qdisc *), GFP_KERNEL);
        }
 }
 
-static struct tcf_proto __rcu **multiq_find_tcf(struct Qdisc *sch,
-                                               unsigned long cl)
+static struct tcf_block *multiq_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct multiq_sched_data *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
-       return &q->filter_list;
+       return q->block;
 }
 
 static const struct Qdisc_class_ops multiq_class_ops = {
        .get            =       multiq_get,
        .put            =       multiq_put,
        .walk           =       multiq_walk,
-       .tcf_chain      =       multiq_find_tcf,
+       .tcf_block      =       multiq_tcf_block,
        .bind_tcf       =       multiq_bind,
        .unbind_tcf     =       multiq_put,
        .dump           =       multiq_dump_class,
 
 struct prio_sched_data {
        int bands;
        struct tcf_proto __rcu *filter_list;
+       struct tcf_block *block;
        u8  prio2band[TC_PRIO_MAX+1];
        struct Qdisc *queues[TCQ_PRIO_BANDS];
 };
        int prio;
        struct prio_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
        for (prio = 0; prio < q->bands; prio++)
                qdisc_destroy(q->queues[prio]);
 }
 
 static int prio_init(struct Qdisc *sch, struct nlattr *opt)
 {
+       struct prio_sched_data *q = qdisc_priv(sch);
+       int err;
+
        if (!opt)
                return -EINVAL;
 
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
+
        return prio_tune(sch, opt);
 }
 
        }
 }
 
-static struct tcf_proto __rcu **prio_find_tcf(struct Qdisc *sch,
-                                             unsigned long cl)
+static struct tcf_block *prio_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct prio_sched_data *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
-       return &q->filter_list;
+       return q->block;
 }
 
 static const struct Qdisc_class_ops prio_class_ops = {
        .get            =       prio_get,
        .put            =       prio_put,
        .walk           =       prio_walk,
-       .tcf_chain      =       prio_find_tcf,
+       .tcf_block      =       prio_tcf_block,
        .bind_tcf       =       prio_bind,
        .unbind_tcf     =       prio_put,
        .dump           =       prio_dump_class,
 
 
 struct qfq_sched {
        struct tcf_proto __rcu *filter_list;
+       struct tcf_block        *block;
        struct Qdisc_class_hash clhash;
 
        u64                     oldV, V;        /* Precise virtual times. */
                qfq_destroy_class(sch, cl);
 }
 
-static struct tcf_proto __rcu **qfq_tcf_chain(struct Qdisc *sch,
-                                             unsigned long cl)
+static struct tcf_block *qfq_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct qfq_sched *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
 
-       return &q->filter_list;
+       return q->block;
 }
 
 static unsigned long qfq_bind_tcf(struct Qdisc *sch, unsigned long parent,
        int i, j, err;
        u32 max_cl_shift, maxbudg_shift, max_classes;
 
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
+
        err = qdisc_class_hash_init(&q->clhash);
        if (err < 0)
                return err;
        struct hlist_node *next;
        unsigned int i;
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
 
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
        .delete         = qfq_delete_class,
        .get            = qfq_get_class,
        .put            = qfq_put_class,
-       .tcf_chain      = qfq_tcf_chain,
+       .tcf_block      = qfq_tcf_block,
        .bind_tcf       = qfq_bind_tcf,
        .unbind_tcf     = qfq_unbind_tcf,
        .graft          = qfq_graft_class,
 
 struct sfb_sched_data {
        struct Qdisc    *qdisc;
        struct tcf_proto __rcu *filter_list;
+       struct tcf_block *block;
        unsigned long   rehash_interval;
        unsigned long   warmup_time;    /* double buffering warmup time in jiffies */
        u32             max;
 {
        struct sfb_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
        qdisc_destroy(q->qdisc);
 }
 
 static int sfb_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct sfb_sched_data *q = qdisc_priv(sch);
+       int err;
+
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
 
        q->qdisc = &noop_qdisc;
        return sfb_change(sch, opt);
        }
 }
 
-static struct tcf_proto __rcu **sfb_find_tcf(struct Qdisc *sch,
-                                            unsigned long cl)
+static struct tcf_block *sfb_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct sfb_sched_data *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
-       return &q->filter_list;
+       return q->block;
 }
 
 static unsigned long sfb_bind(struct Qdisc *sch, unsigned long parent,
        .change         =       sfb_change_class,
        .delete         =       sfb_delete,
        .walk           =       sfb_walk,
-       .tcf_chain      =       sfb_find_tcf,
+       .tcf_block      =       sfb_tcf_block,
        .bind_tcf       =       sfb_bind,
        .unbind_tcf     =       sfb_put,
        .dump           =       sfb_dump_class,
 
        u8              flags;
        unsigned short  scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
        struct tcf_proto __rcu *filter_list;
+       struct tcf_block *block;
        sfq_index       *ht;            /* Hash table ('divisor' slots) */
        struct sfq_slot *slots;         /* Flows table ('maxflows' entries) */
 
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
 
-       tcf_destroy_chain(&q->filter_list);
+       tcf_block_put(q->block);
        q->perturb_period = 0;
        del_timer_sync(&q->perturb_timer);
        sfq_free(q->ht);
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
        int i;
+       int err;
+
+       err = tcf_block_get(&q->block, &q->filter_list);
+       if (err)
+               return err;
 
        setup_deferrable_timer(&q->perturb_timer, sfq_perturbation,
                               (unsigned long)sch);
 {
 }
 
-static struct tcf_proto __rcu **sfq_find_tcf(struct Qdisc *sch,
-                                            unsigned long cl)
+static struct tcf_block *sfq_tcf_block(struct Qdisc *sch, unsigned long cl)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
 
        if (cl)
                return NULL;
-       return &q->filter_list;
+       return q->block;
 }
 
 static int sfq_dump_class(struct Qdisc *sch, unsigned long cl,
        .leaf           =       sfq_leaf,
        .get            =       sfq_get,
        .put            =       sfq_put,
-       .tcf_chain      =       sfq_find_tcf,
+       .tcf_block      =       sfq_tcf_block,
        .bind_tcf       =       sfq_bind,
        .unbind_tcf     =       sfq_put,
        .dump           =       sfq_dump_class,