};
 
 struct tcf_block_cb;
-bool tcf_queue_work(struct work_struct *work);
+bool tcf_queue_work(struct rcu_work *rwork, work_func_t func);
 
 #ifdef CONFIG_NET_CLS
 struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
 
 }
 EXPORT_SYMBOL(unregister_tcf_proto_ops);
 
-bool tcf_queue_work(struct work_struct *work)
+bool tcf_queue_work(struct rcu_work *rwork, work_func_t func)
 {
-       return queue_work(tc_filter_wq, work);
+       INIT_RCU_WORK(rwork, func);
+       return queue_rcu_work(tc_filter_wq, rwork);
 }
 EXPORT_SYMBOL(tcf_queue_work);
 
 
        struct tcf_result       res;
        struct tcf_proto        *tp;
        struct list_head        link;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
 };
 
 static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 
 static void basic_delete_filter_work(struct work_struct *work)
 {
-       struct basic_filter *f = container_of(work, struct basic_filter, work);
-
+       struct basic_filter *f = container_of(to_rcu_work(work),
+                                             struct basic_filter,
+                                             rwork);
        rtnl_lock();
        __basic_delete_filter(f);
        rtnl_unlock();
 }
 
-static void basic_delete_filter(struct rcu_head *head)
-{
-       struct basic_filter *f = container_of(head, struct basic_filter, rcu);
-
-       INIT_WORK(&f->work, basic_delete_filter_work);
-       tcf_queue_work(&f->work);
-}
-
 static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 {
        struct basic_head *head = rtnl_dereference(tp->root);
                tcf_unbind_filter(tp, &f->res);
                idr_remove(&head->handle_idr, f->handle);
                if (tcf_exts_get_net(&f->exts))
-                       call_rcu(&f->rcu, basic_delete_filter);
+                       tcf_queue_work(&f->rwork, basic_delete_filter_work);
                else
                        __basic_delete_filter(f);
        }
        tcf_unbind_filter(tp, &f->res);
        idr_remove(&head->handle_idr, f->handle);
        tcf_exts_get_net(&f->exts);
-       call_rcu(&f->rcu, basic_delete_filter);
+       tcf_queue_work(&f->rwork, basic_delete_filter_work);
        *last = list_empty(&head->flist);
        return 0;
 }
                list_replace_rcu(&fold->link, &fnew->link);
                tcf_unbind_filter(tp, &fold->res);
                tcf_exts_get_net(&fold->exts);
-               call_rcu(&fold->rcu, basic_delete_filter);
+               tcf_queue_work(&fold->rwork, basic_delete_filter_work);
        } else {
                list_add_rcu(&fnew->link, &head->flist);
        }
 
        struct sock_filter *bpf_ops;
        const char *bpf_name;
        struct tcf_proto *tp;
-       union {
-               struct work_struct work;
-               struct rcu_head rcu;
-       };
+       struct rcu_work rwork;
 };
 
 static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = {
 
 static void cls_bpf_delete_prog_work(struct work_struct *work)
 {
-       struct cls_bpf_prog *prog = container_of(work, struct cls_bpf_prog, work);
-
+       struct cls_bpf_prog *prog = container_of(to_rcu_work(work),
+                                                struct cls_bpf_prog,
+                                                rwork);
        rtnl_lock();
        __cls_bpf_delete_prog(prog);
        rtnl_unlock();
 }
 
-static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu)
-{
-       struct cls_bpf_prog *prog = container_of(rcu, struct cls_bpf_prog, rcu);
-
-       INIT_WORK(&prog->work, cls_bpf_delete_prog_work);
-       tcf_queue_work(&prog->work);
-}
-
 static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
                             struct netlink_ext_ack *extack)
 {
        list_del_rcu(&prog->link);
        tcf_unbind_filter(tp, &prog->res);
        if (tcf_exts_get_net(&prog->exts))
-               call_rcu(&prog->rcu, cls_bpf_delete_prog_rcu);
+               tcf_queue_work(&prog->rwork, cls_bpf_delete_prog_work);
        else
                __cls_bpf_delete_prog(prog);
 }
                list_replace_rcu(&oldprog->link, &prog->link);
                tcf_unbind_filter(tp, &oldprog->res);
                tcf_exts_get_net(&oldprog->exts);
-               call_rcu(&oldprog->rcu, cls_bpf_delete_prog_rcu);
+               tcf_queue_work(&oldprog->rwork, cls_bpf_delete_prog_work);
        } else {
                list_add_rcu(&prog->link, &head->plist);
        }
 
        struct tcf_exts         exts;
        struct tcf_ematch_tree  ematches;
        struct tcf_proto        *tp;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
 };
 
 static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 
 static void cls_cgroup_destroy_work(struct work_struct *work)
 {
-       struct cls_cgroup_head *head = container_of(work,
+       struct cls_cgroup_head *head = container_of(to_rcu_work(work),
                                                    struct cls_cgroup_head,
-                                                   work);
+                                                   rwork);
        rtnl_lock();
        __cls_cgroup_destroy(head);
        rtnl_unlock();
 }
 
-static void cls_cgroup_destroy_rcu(struct rcu_head *root)
-{
-       struct cls_cgroup_head *head = container_of(root,
-                                                   struct cls_cgroup_head,
-                                                   rcu);
-
-       INIT_WORK(&head->work, cls_cgroup_destroy_work);
-       tcf_queue_work(&head->work);
-}
-
 static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
                             struct tcf_proto *tp, unsigned long base,
                             u32 handle, struct nlattr **tca,
        rcu_assign_pointer(tp->root, new);
        if (head) {
                tcf_exts_get_net(&head->exts);
-               call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
+               tcf_queue_work(&head->rwork, cls_cgroup_destroy_work);
        }
        return 0;
 errout:
        /* Head can still be NULL due to cls_cgroup_init(). */
        if (head) {
                if (tcf_exts_get_net(&head->exts))
-                       call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
+                       tcf_queue_work(&head->rwork, cls_cgroup_destroy_work);
                else
                        __cls_cgroup_destroy(head);
        }
 
        u32                     divisor;
        u32                     baseclass;
        u32                     hashrnd;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
 };
 
 static inline u32 addr_fold(void *addr)
 
 static void flow_destroy_filter_work(struct work_struct *work)
 {
-       struct flow_filter *f = container_of(work, struct flow_filter, work);
-
+       struct flow_filter *f = container_of(to_rcu_work(work),
+                                            struct flow_filter,
+                                            rwork);
        rtnl_lock();
        __flow_destroy_filter(f);
        rtnl_unlock();
 }
 
-static void flow_destroy_filter(struct rcu_head *head)
-{
-       struct flow_filter *f = container_of(head, struct flow_filter, rcu);
-
-       INIT_WORK(&f->work, flow_destroy_filter_work);
-       tcf_queue_work(&f->work);
-}
-
 static int flow_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle, struct nlattr **tca,
 
        if (fold) {
                tcf_exts_get_net(&fold->exts);
-               call_rcu(&fold->rcu, flow_destroy_filter);
+               tcf_queue_work(&fold->rwork, flow_destroy_filter_work);
        }
        return 0;
 
 
        list_del_rcu(&f->list);
        tcf_exts_get_net(&f->exts);
-       call_rcu(&f->rcu, flow_destroy_filter);
+       tcf_queue_work(&f->rwork, flow_destroy_filter_work);
        *last = list_empty(&head->filters);
        return 0;
 }
        list_for_each_entry_safe(f, next, &head->filters, list) {
                list_del_rcu(&f->list);
                if (tcf_exts_get_net(&f->exts))
-                       call_rcu(&f->rcu, flow_destroy_filter);
+                       tcf_queue_work(&f->rwork, flow_destroy_filter_work);
                else
                        __flow_destroy_filter(f);
        }
 
 struct cls_fl_head {
        struct rhashtable ht;
        struct list_head masks;
-       union {
-               struct work_struct work;
-               struct rcu_head rcu;
-       };
+       struct rcu_work rwork;
        struct idr handle_idr;
 };
 
        struct list_head list;
        u32 handle;
        u32 flags;
-       union {
-               struct work_struct work;
-               struct rcu_head rcu;
-       };
+       struct rcu_work rwork;
        struct net_device *hw_dev;
 };
 
 
 static void fl_destroy_filter_work(struct work_struct *work)
 {
-       struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work);
+       struct cls_fl_filter *f = container_of(to_rcu_work(work),
+                                       struct cls_fl_filter, rwork);
 
        rtnl_lock();
        __fl_destroy_filter(f);
        rtnl_unlock();
 }
 
-static void fl_destroy_filter(struct rcu_head *head)
-{
-       struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
-
-       INIT_WORK(&f->work, fl_destroy_filter_work);
-       tcf_queue_work(&f->work);
-}
-
 static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
                                 struct netlink_ext_ack *extack)
 {
                fl_hw_destroy_filter(tp, f, extack);
        tcf_unbind_filter(tp, &f->res);
        if (async)
-               call_rcu(&f->rcu, fl_destroy_filter);
+               tcf_queue_work(&f->rwork, fl_destroy_filter_work);
        else
                __fl_destroy_filter(f);
 
 
 static void fl_destroy_sleepable(struct work_struct *work)
 {
-       struct cls_fl_head *head = container_of(work, struct cls_fl_head,
-                                               work);
+       struct cls_fl_head *head = container_of(to_rcu_work(work),
+                                               struct cls_fl_head,
+                                               rwork);
        kfree(head);
        module_put(THIS_MODULE);
 }
 
-static void fl_destroy_rcu(struct rcu_head *rcu)
-{
-       struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
-
-       INIT_WORK(&head->work, fl_destroy_sleepable);
-       schedule_work(&head->work);
-}
-
 static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
        idr_destroy(&head->handle_idr);
 
        __module_get(THIS_MODULE);
-       call_rcu(&head->rcu, fl_destroy_rcu);
+       tcf_queue_work(&head->rwork, fl_destroy_sleepable);
 }
 
 static void *fl_get(struct tcf_proto *tp, u32 handle)
                list_replace_rcu(&fold->list, &fnew->list);
                tcf_unbind_filter(tp, &fold->res);
                tcf_exts_get_net(&fold->exts);
-               call_rcu(&fold->rcu, fl_destroy_filter);
+               tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
        } else {
                list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
        }
 
 #endif /* CONFIG_NET_CLS_IND */
        struct tcf_exts         exts;
        struct tcf_proto        *tp;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
 };
 
 static u32 fw_hash(u32 handle)
 
 static void fw_delete_filter_work(struct work_struct *work)
 {
-       struct fw_filter *f = container_of(work, struct fw_filter, work);
-
+       struct fw_filter *f = container_of(to_rcu_work(work),
+                                          struct fw_filter,
+                                          rwork);
        rtnl_lock();
        __fw_delete_filter(f);
        rtnl_unlock();
 }
 
-static void fw_delete_filter(struct rcu_head *head)
-{
-       struct fw_filter *f = container_of(head, struct fw_filter, rcu);
-
-       INIT_WORK(&f->work, fw_delete_filter_work);
-       tcf_queue_work(&f->work);
-}
-
 static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
                                         rtnl_dereference(f->next));
                        tcf_unbind_filter(tp, &f->res);
                        if (tcf_exts_get_net(&f->exts))
-                               call_rcu(&f->rcu, fw_delete_filter);
+                               tcf_queue_work(&f->rwork, fw_delete_filter_work);
                        else
                                __fw_delete_filter(f);
                }
                        RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
                        tcf_unbind_filter(tp, &f->res);
                        tcf_exts_get_net(&f->exts);
-                       call_rcu(&f->rcu, fw_delete_filter);
+                       tcf_queue_work(&f->rwork, fw_delete_filter_work);
                        ret = 0;
                        break;
                }
                rcu_assign_pointer(*fp, fnew);
                tcf_unbind_filter(tp, &f->res);
                tcf_exts_get_net(&f->exts);
-               call_rcu(&f->rcu, fw_delete_filter);
+               tcf_queue_work(&f->rwork, fw_delete_filter_work);
 
                *arg = fnew;
                return err;
 
        struct tcf_result res;
        u32 handle;
        u32 flags;
-       union {
-               struct work_struct work;
-               struct rcu_head rcu;
-       };
+       struct rcu_work rwork;
 };
 
 static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 
 static void mall_destroy_work(struct work_struct *work)
 {
-       struct cls_mall_head *head = container_of(work, struct cls_mall_head,
-                                                 work);
+       struct cls_mall_head *head = container_of(to_rcu_work(work),
+                                                 struct cls_mall_head,
+                                                 rwork);
        rtnl_lock();
        __mall_destroy(head);
        rtnl_unlock();
 }
 
-static void mall_destroy_rcu(struct rcu_head *rcu)
-{
-       struct cls_mall_head *head = container_of(rcu, struct cls_mall_head,
-                                                 rcu);
-
-       INIT_WORK(&head->work, mall_destroy_work);
-       tcf_queue_work(&head->work);
-}
-
 static void mall_destroy_hw_filter(struct tcf_proto *tp,
                                   struct cls_mall_head *head,
                                   unsigned long cookie,
                mall_destroy_hw_filter(tp, head, (unsigned long) head, extack);
 
        if (tcf_exts_get_net(&head->exts))
-               call_rcu(&head->rcu, mall_destroy_rcu);
+               tcf_queue_work(&head->rwork, mall_destroy_work);
        else
                __mall_destroy(head);
 }
 
        u32                     handle;
        struct route4_bucket    *bkt;
        struct tcf_proto        *tp;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
 };
 
 #define ROUTE4_FAILURE ((struct route4_filter *)(-1L))
 
 static void route4_delete_filter_work(struct work_struct *work)
 {
-       struct route4_filter *f = container_of(work, struct route4_filter, work);
-
+       struct route4_filter *f = container_of(to_rcu_work(work),
+                                              struct route4_filter,
+                                              rwork);
        rtnl_lock();
        __route4_delete_filter(f);
        rtnl_unlock();
 }
 
-static void route4_delete_filter(struct rcu_head *head)
+static void route4_queue_work(struct route4_filter *f)
 {
-       struct route4_filter *f = container_of(head, struct route4_filter, rcu);
-
-       INIT_WORK(&f->work, route4_delete_filter_work);
-       tcf_queue_work(&f->work);
+       tcf_queue_work(&f->rwork, route4_delete_filter_work);
 }
 
 static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
                                        RCU_INIT_POINTER(b->ht[h2], next);
                                        tcf_unbind_filter(tp, &f->res);
                                        if (tcf_exts_get_net(&f->exts))
-                                               call_rcu(&f->rcu, route4_delete_filter);
+                                               route4_queue_work(f);
                                        else
                                                __route4_delete_filter(f);
                                }
                        /* Delete it */
                        tcf_unbind_filter(tp, &f->res);
                        tcf_exts_get_net(&f->exts);
-                       call_rcu(&f->rcu, route4_delete_filter);
+                       tcf_queue_work(&f->rwork, route4_delete_filter_work);
 
                        /* Strip RTNL protected tree */
                        for (i = 0; i <= 32; i++) {
        if (fold) {
                tcf_unbind_filter(tp, &fold->res);
                tcf_exts_get_net(&fold->exts);
-               call_rcu(&fold->rcu, route4_delete_filter);
+               tcf_queue_work(&fold->rwork, route4_delete_filter_work);
        }
        return 0;
 
 
 
        u32                             handle;
        struct rsvp_session             *sess;
-       union {
-               struct work_struct              work;
-               struct rcu_head                 rcu;
-       };
+       struct rcu_work                 rwork;
 };
 
 static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
 
 static void rsvp_delete_filter_work(struct work_struct *work)
 {
-       struct rsvp_filter *f = container_of(work, struct rsvp_filter, work);
-
+       struct rsvp_filter *f = container_of(to_rcu_work(work),
+                                            struct rsvp_filter,
+                                            rwork);
        rtnl_lock();
        __rsvp_delete_filter(f);
        rtnl_unlock();
 }
 
-static void rsvp_delete_filter_rcu(struct rcu_head *head)
-{
-       struct rsvp_filter *f = container_of(head, struct rsvp_filter, rcu);
-
-       INIT_WORK(&f->work, rsvp_delete_filter_work);
-       tcf_queue_work(&f->work);
-}
-
 static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
 {
        tcf_unbind_filter(tp, &f->res);
         * in cleanup() callback
         */
        if (tcf_exts_get_net(&f->exts))
-               call_rcu(&f->rcu, rsvp_delete_filter_rcu);
+               tcf_queue_work(&f->rwork, rsvp_delete_filter_work);
        else
                __rsvp_delete_filter(f);
 }
 
 struct tcindex_filter_result {
        struct tcf_exts         exts;
        struct tcf_result       res;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
 };
 
 struct tcindex_filter {
        u16 key;
        struct tcindex_filter_result result;
        struct tcindex_filter __rcu *next;
-       union {
-               struct work_struct work;
-               struct rcu_head rcu;
-       };
+       struct rcu_work rwork;
 };
 
 
 {
        struct tcindex_filter_result *r;
 
-       r = container_of(work, struct tcindex_filter_result, work);
+       r = container_of(to_rcu_work(work),
+                        struct tcindex_filter_result,
+                        rwork);
        rtnl_lock();
        __tcindex_destroy_rexts(r);
        rtnl_unlock();
 }
 
-static void tcindex_destroy_rexts(struct rcu_head *head)
-{
-       struct tcindex_filter_result *r;
-
-       r = container_of(head, struct tcindex_filter_result, rcu);
-       INIT_WORK(&r->work, tcindex_destroy_rexts_work);
-       tcf_queue_work(&r->work);
-}
-
 static void __tcindex_destroy_fexts(struct tcindex_filter *f)
 {
        tcf_exts_destroy(&f->result.exts);
 
 static void tcindex_destroy_fexts_work(struct work_struct *work)
 {
-       struct tcindex_filter *f = container_of(work, struct tcindex_filter,
-                                               work);
+       struct tcindex_filter *f = container_of(to_rcu_work(work),
+                                               struct tcindex_filter,
+                                               rwork);
 
        rtnl_lock();
        __tcindex_destroy_fexts(f);
        rtnl_unlock();
 }
 
-static void tcindex_destroy_fexts(struct rcu_head *head)
-{
-       struct tcindex_filter *f = container_of(head, struct tcindex_filter,
-                                               rcu);
-
-       INIT_WORK(&f->work, tcindex_destroy_fexts_work);
-       tcf_queue_work(&f->work);
-}
-
 static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last,
                          struct netlink_ext_ack *extack)
 {
         */
        if (f) {
                if (tcf_exts_get_net(&f->result.exts))
-                       call_rcu(&f->rcu, tcindex_destroy_fexts);
+                       tcf_queue_work(&f->rwork, tcindex_destroy_fexts_work);
                else
                        __tcindex_destroy_fexts(f);
        } else {
                if (tcf_exts_get_net(&r->exts))
-                       call_rcu(&r->rcu, tcindex_destroy_rexts);
+                       tcf_queue_work(&r->rwork, tcindex_destroy_rexts_work);
                else
                        __tcindex_destroy_rexts(r);
        }
 
        u32 __percpu            *pcpu_success;
 #endif
        struct tcf_proto        *tp;
-       union {
-               struct work_struct      work;
-               struct rcu_head         rcu;
-       };
+       struct rcu_work         rwork;
        /* The 'sel' field MUST be the last field in structure to allow for
         * tc_u32_keys allocated at end of structure.
         */
  */
 static void u32_delete_key_work(struct work_struct *work)
 {
-       struct tc_u_knode *key = container_of(work, struct tc_u_knode, work);
-
+       struct tc_u_knode *key = container_of(to_rcu_work(work),
+                                             struct tc_u_knode,
+                                             rwork);
        rtnl_lock();
        u32_destroy_key(key->tp, key, false);
        rtnl_unlock();
 }
 
-static void u32_delete_key_rcu(struct rcu_head *rcu)
-{
-       struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu);
-
-       INIT_WORK(&key->work, u32_delete_key_work);
-       tcf_queue_work(&key->work);
-}
-
 /* u32_delete_key_freepf_rcu is the rcu callback variant
  * that free's the entire structure including the statistics
  * percpu variables. Only use this if the key is not a copy
  */
 static void u32_delete_key_freepf_work(struct work_struct *work)
 {
-       struct tc_u_knode *key = container_of(work, struct tc_u_knode, work);
-
+       struct tc_u_knode *key = container_of(to_rcu_work(work),
+                                             struct tc_u_knode,
+                                             rwork);
        rtnl_lock();
        u32_destroy_key(key->tp, key, true);
        rtnl_unlock();
 }
 
-static void u32_delete_key_freepf_rcu(struct rcu_head *rcu)
-{
-       struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu);
-
-       INIT_WORK(&key->work, u32_delete_key_freepf_work);
-       tcf_queue_work(&key->work);
-}
-
 static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
 {
        struct tc_u_knode __rcu **kp;
                                tcf_unbind_filter(tp, &key->res);
                                idr_remove(&ht->handle_idr, key->handle);
                                tcf_exts_get_net(&key->exts);
-                               call_rcu(&key->rcu, u32_delete_key_freepf_rcu);
+                               tcf_queue_work(&key->rwork, u32_delete_key_freepf_work);
                                return 0;
                        }
                }
                        u32_remove_hw_knode(tp, n, extack);
                        idr_remove(&ht->handle_idr, n->handle);
                        if (tcf_exts_get_net(&n->exts))
-                               call_rcu(&n->rcu, u32_delete_key_freepf_rcu);
+                               tcf_queue_work(&n->rwork, u32_delete_key_freepf_work);
                        else
                                u32_destroy_key(n->tp, n, true);
                }
                u32_replace_knode(tp, tp_c, new);
                tcf_unbind_filter(tp, &n->res);
                tcf_exts_get_net(&n->exts);
-               call_rcu(&n->rcu, u32_delete_key_rcu);
+               tcf_queue_work(&n->rwork, u32_delete_key_work);
                return 0;
        }