const struct tc_action_ops      *ops;
        __u32                   type; /* for backward compat(TCA_OLD_COMPAT) */
        __u32                   order;
-       struct tc_action        *next;
+       struct list_head        list;
 };
 
 #define TCA_CAP_NONE 0
 
 int tcf_register_action(struct tc_action_ops *a);
 int tcf_unregister_action(struct tc_action_ops *a);
-void tcf_action_destroy(struct tc_action *a, int bind);
-int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a,
+void tcf_action_destroy(struct list_head *actions, int bind);
+int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
                    struct tcf_result *res);
-struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
+int tcf_action_init(struct net *net, struct nlattr *nla,
                                  struct nlattr *est, char *n, int ovr,
-                                 int bind);
+                                 int bind, struct list_head *);
 struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
                                    struct nlattr *est, char *n, int ovr,
                                    int bind);
-int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
+int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
 int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
 int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
 
 }
 #endif
 
-int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
+int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
                    struct tcf_result *res)
 {
        const struct tc_action *a;
                ret = TC_ACT_OK;
                goto exec_done;
        }
-       while ((a = act) != NULL) {
+       list_for_each_entry(a, actions, list) {
 repeat:
                if (a->ops) {
                        ret = a->ops->act(skb, a, res);
                        if (ret != TC_ACT_PIPE)
                                goto exec_done;
                }
-               act = a->next;
        }
 exec_done:
        return ret;
 }
 EXPORT_SYMBOL(tcf_action_exec);
 
-void tcf_action_destroy(struct tc_action *act, int bind)
+void tcf_action_destroy(struct list_head *actions, int bind)
 {
-       struct tc_action *a;
+       struct tc_action *a, *tmp;
 
-       for (a = act; a; a = act) {
+       list_for_each_entry_safe(a, tmp, actions, list) {
                if (a->ops) {
                        if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
                                module_put(a->ops->owner);
-                       act = act->next;
+                       list_del(&a->list);
                        kfree(a);
                } else {
                        /*FIXME: Remove later - catch insertion bugs*/
                        WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
-                       act = act->next;
+                       list_del(&a->list);
                        kfree(a);
                }
        }
 EXPORT_SYMBOL(tcf_action_dump_1);
 
 int
-tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref)
+tcf_action_dump(struct sk_buff *skb, struct list_head *actions, int bind, int ref)
 {
        struct tc_action *a;
        int err = -EINVAL;
        struct nlattr *nest;
 
-       while ((a = act) != NULL) {
-               act = a->next;
+       list_for_each_entry(a, actions, list) {
                nest = nla_nest_start(skb, a->order);
                if (nest == NULL)
                        goto nla_put_failure;
        if (a == NULL)
                goto err_mod;
 
+       INIT_LIST_HEAD(&a->list);
        /* backward compatibility for policer */
        if (name == NULL)
                err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
        return ERR_PTR(err);
 }
 
-struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
+int tcf_action_init(struct net *net, struct nlattr *nla,
                                  struct nlattr *est, char *name, int ovr,
-                                 int bind)
+                                 int bind, struct list_head *actions)
 {
        struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
-       struct tc_action *head = NULL, *act, *act_prev = NULL;
+       struct tc_action *act;
        int err;
        int i;
 
        err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
        if (err < 0)
-               return ERR_PTR(err);
+               return err;
 
        for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
                act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
-               if (IS_ERR(act))
+               if (IS_ERR(act)) {
+                       err = PTR_ERR(act);
                        goto err;
+               }
                act->order = i;
-
-               if (head == NULL)
-                       head = act;
-               else
-                       act_prev->next = act;
-               act_prev = act;
+               list_add_tail(&act->list, actions);
        }
-       return head;
+       return 0;
 
 err:
-       if (head != NULL)
-               tcf_action_destroy(head, bind);
-       return act;
+       tcf_action_destroy(actions, bind);
+       return err;
 }
 
 int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
 }
 
 static int
-tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
+tca_get_fill(struct sk_buff *skb, struct list_head *actions, u32 portid, u32 seq,
             u16 flags, int event, int bind, int ref)
 {
        struct tcamsg *t;
        if (nest == NULL)
                goto out_nlmsg_trim;
 
-       if (tcf_action_dump(skb, a, bind, ref) < 0)
+       if (tcf_action_dump(skb, actions, bind, ref) < 0)
                goto out_nlmsg_trim;
 
        nla_nest_end(skb, nest);
 
 static int
 act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
-              struct tc_action *a, int event)
+              struct list_head *actions, int event)
 {
        struct sk_buff *skb;
 
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!skb)
                return -ENOBUFS;
-       if (tca_get_fill(skb, a, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
+       if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
                kfree_skb(skb);
                return -EINVAL;
        }
        if (a == NULL)
                goto err_out;
 
+       INIT_LIST_HEAD(&a->list);
        err = -EINVAL;
        a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
        if (a->ops == NULL)
        return ERR_PTR(err);
 }
 
-static void cleanup_a(struct tc_action *act)
+static void cleanup_a(struct list_head *actions)
 {
-       struct tc_action *a;
+       struct tc_action *a, *tmp;
 
-       for (a = act; a; a = act) {
-               act = a->next;
+       list_for_each_entry_safe(a, tmp, actions, list) {
+               list_del(&a->list);
                kfree(a);
        }
 }
                return NULL;
        }
        act->order = i;
+       INIT_LIST_HEAD(&act->list);
        return act;
 }
 
 {
        int i, ret;
        struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
-       struct tc_action *head = NULL, *act, *act_prev = NULL;
+       struct tc_action *act;
+       LIST_HEAD(actions);
 
        ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
        if (ret < 0)
                        goto err;
                }
                act->order = i;
-
-               if (head == NULL)
-                       head = act;
-               else
-                       act_prev->next = act;
-               act_prev = act;
+               list_add_tail(&act->list, &actions);
        }
 
        if (event == RTM_GETACTION)
-               ret = act_get_notify(net, portid, n, head, event);
+               ret = act_get_notify(net, portid, n, &actions, event);
        else { /* delete */
                struct sk_buff *skb;
 
                        goto err;
                }
 
-               if (tca_get_fill(skb, head, portid, n->nlmsg_seq, 0, event,
+               if (tca_get_fill(skb, &actions, portid, n->nlmsg_seq, 0, event,
                                 0, 1) <= 0) {
                        kfree_skb(skb);
                        ret = -EINVAL;
                }
 
                /* now do the delete */
-               tcf_action_destroy(head, 0);
+               tcf_action_destroy(&actions, 0);
                ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
                                     n->nlmsg_flags & NLM_F_ECHO);
                if (ret > 0)
                return ret;
        }
 err:
-       cleanup_a(head);
+       cleanup_a(&actions);
        return ret;
 }
 
-static int tcf_add_notify(struct net *net, struct tc_action *a,
+static int tcf_add_notify(struct net *net, struct list_head *actions,
                          u32 portid, u32 seq, int event, u16 flags)
 {
        struct tcamsg *t;
        if (nest == NULL)
                goto out_kfree_skb;
 
-       if (tcf_action_dump(skb, a, 0, 0) < 0)
+       if (tcf_action_dump(skb, actions, 0, 0) < 0)
                goto out_kfree_skb;
 
        nla_nest_end(skb, nest);
               u32 portid, int ovr)
 {
        int ret = 0;
-       struct tc_action *act;
-       struct tc_action *a;
+       LIST_HEAD(actions);
        u32 seq = n->nlmsg_seq;
 
-       act = tcf_action_init(net, nla, NULL, NULL, ovr, 0);
-       if (act == NULL)
-               goto done;
-       if (IS_ERR(act)) {
-               ret = PTR_ERR(act);
+       ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
+       if (ret)
                goto done;
-       }
 
        /* dump then free all the actions after update; inserted policy
         * stays intact
         */
-       ret = tcf_add_notify(net, act, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
-       for (a = act; a; a = act) {
-               act = a->next;
-               kfree(a);
-       }
+       ret = tcf_add_notify(net, &actions, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
+       cleanup_a(&actions);
 done:
        return ret;
 }
 
 void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       if (exts->action) {
-               tcf_action_destroy(exts->action, TCA_ACT_UNBIND);
-               exts->action = NULL;
-       }
+       tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND);
+       INIT_LIST_HEAD(&exts->actions);
 #endif
 }
 EXPORT_SYMBOL(tcf_exts_destroy);
        {
                struct tc_action *act;
 
+               INIT_LIST_HEAD(&exts->actions);
                if (map->police && tb[map->police]) {
                        act = tcf_action_init_1(net, tb[map->police], rate_tlv,
                                                "police", TCA_ACT_NOREPLACE,
                        if (IS_ERR(act))
                                return PTR_ERR(act);
 
-                       act->type = TCA_OLD_COMPAT;
-                       exts->action = act;
+                       act->type = exts->type = TCA_OLD_COMPAT;
+                       list_add(&act->list, &exts->actions);
                } else if (map->action && tb[map->action]) {
-                       act = tcf_action_init(net, tb[map->action], rate_tlv,
+                       int err;
+                       err = tcf_action_init(net, tb[map->action], rate_tlv,
                                              NULL, TCA_ACT_NOREPLACE,
-                                             TCA_ACT_BIND);
-                       if (IS_ERR(act))
-                               return PTR_ERR(act);
-
-                       exts->action = act;
+                                             TCA_ACT_BIND, &exts->actions);
+                       if (err)
+                               return err;
                }
        }
 #else
                     struct tcf_exts *src)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       if (src->action) {
-               struct tc_action *act;
+       if (!list_empty(&src->actions)) {
+               LIST_HEAD(tmp);
                tcf_tree_lock(tp);
-               act = dst->action;
-               dst->action = src->action;
+               list_splice_init(&dst->actions, &tmp);
+               list_splice(&src->actions, &dst->actions);
                tcf_tree_unlock(tp);
-               if (act)
-                       tcf_action_destroy(act, TCA_ACT_UNBIND);
+               tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
        }
 #endif
 }
 EXPORT_SYMBOL(tcf_exts_change);
 
+#define tcf_exts_first_act(ext) \
+               list_first_entry(&(exts)->actions, struct tc_action, list)
+
 int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
                  const struct tcf_ext_map *map)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       if (map->action && exts->action) {
+       if (map->action && !list_empty(&exts->actions)) {
                /*
                 * again for backward compatible mode - we want
                 * to work with both old and new modes of entering
                 * tc data even if iproute2  was newer - jhs
                 */
                struct nlattr *nest;
-
-               if (exts->action->type != TCA_OLD_COMPAT) {
+               if (exts->type != TCA_OLD_COMPAT) {
                        nest = nla_nest_start(skb, map->action);
                        if (nest == NULL)
                                goto nla_put_failure;
-                       if (tcf_action_dump(skb, exts->action, 0, 0) < 0)
+                       if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0)
                                goto nla_put_failure;
                        nla_nest_end(skb, nest);
                } else if (map->police) {
+                       struct tc_action *act = tcf_exts_first_act(exts);
                        nest = nla_nest_start(skb, map->police);
                        if (nest == NULL)
                                goto nla_put_failure;
-                       if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0)
+                       if (tcf_action_dump_old(skb, act, 0, 0) < 0)
                                goto nla_put_failure;
                        nla_nest_end(skb, nest);
                }
                        const struct tcf_ext_map *map)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       if (exts->action)
-               if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
-                       goto nla_put_failure;
+       struct tc_action *a = tcf_exts_first_act(exts);
+       if (tcf_action_copy_stats(skb, a, 1) < 0)
+               return -1;
 #endif
        return 0;
-nla_put_failure: __attribute__ ((unused))
-       return -1;
 }
 EXPORT_SYMBOL(tcf_exts_dump_stats);