diff options
Diffstat (limited to 'net/sched/act_api.c')
-rw-r--r-- | net/sched/act_api.c | 149 |
1 files changed, 53 insertions, 96 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 47ec2305f920..d97419f35e7e 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -38,7 +38,7 @@ static void free_tcf(struct rcu_head *head) | |||
38 | 38 | ||
39 | static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *a) | 39 | static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *a) |
40 | { | 40 | { |
41 | struct tcf_common *p = a->priv; | 41 | struct tcf_common *p = (struct tcf_common *)a; |
42 | 42 | ||
43 | spin_lock_bh(&hinfo->lock); | 43 | spin_lock_bh(&hinfo->lock); |
44 | hlist_del(&p->tcfc_head); | 44 | hlist_del(&p->tcfc_head); |
@@ -54,7 +54,7 @@ static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *a) | |||
54 | 54 | ||
55 | int __tcf_hash_release(struct tc_action *a, bool bind, bool strict) | 55 | int __tcf_hash_release(struct tc_action *a, bool bind, bool strict) |
56 | { | 56 | { |
57 | struct tcf_common *p = a->priv; | 57 | struct tcf_common *p = (struct tcf_common *)a; |
58 | int ret = 0; | 58 | int ret = 0; |
59 | 59 | ||
60 | if (p) { | 60 | if (p) { |
@@ -67,6 +67,7 @@ int __tcf_hash_release(struct tc_action *a, bool bind, bool strict) | |||
67 | if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) { | 67 | if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) { |
68 | if (a->ops->cleanup) | 68 | if (a->ops->cleanup) |
69 | a->ops->cleanup(a, bind); | 69 | a->ops->cleanup(a, bind); |
70 | list_del(&a->list); | ||
70 | tcf_hash_destroy(a->hinfo, a); | 71 | tcf_hash_destroy(a->hinfo, a); |
71 | ret = ACT_P_DELETED; | 72 | ret = ACT_P_DELETED; |
72 | } | 73 | } |
@@ -77,10 +78,8 @@ int __tcf_hash_release(struct tc_action *a, bool bind, bool strict) | |||
77 | EXPORT_SYMBOL(__tcf_hash_release); | 78 | EXPORT_SYMBOL(__tcf_hash_release); |
78 | 79 | ||
79 | static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, | 80 | static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, |
80 | struct netlink_callback *cb, struct tc_action *a) | 81 | struct netlink_callback *cb) |
81 | { | 82 | { |
82 | struct hlist_head *head; | ||
83 | struct tcf_common *p; | ||
84 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; | 83 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; |
85 | struct nlattr *nest; | 84 | struct nlattr *nest; |
86 | 85 | ||
@@ -89,19 +88,20 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, | |||
89 | s_i = cb->args[0]; | 88 | s_i = cb->args[0]; |
90 | 89 | ||
91 | for (i = 0; i < (hinfo->hmask + 1); i++) { | 90 | for (i = 0; i < (hinfo->hmask + 1); i++) { |
91 | struct hlist_head *head; | ||
92 | struct tcf_common *p; | ||
93 | |||
92 | head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; | 94 | head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; |
93 | 95 | ||
94 | hlist_for_each_entry_rcu(p, head, tcfc_head) { | 96 | hlist_for_each_entry_rcu(p, head, tcfc_head) { |
95 | index++; | 97 | index++; |
96 | if (index < s_i) | 98 | if (index < s_i) |
97 | continue; | 99 | continue; |
98 | a->priv = p; | ||
99 | a->order = n_i; | ||
100 | 100 | ||
101 | nest = nla_nest_start(skb, a->order); | 101 | nest = nla_nest_start(skb, n_i); |
102 | if (nest == NULL) | 102 | if (nest == NULL) |
103 | goto nla_put_failure; | 103 | goto nla_put_failure; |
104 | err = tcf_action_dump_1(skb, a, 0, 0); | 104 | err = tcf_action_dump_1(skb, (struct tc_action *)p, 0, 0); |
105 | if (err < 0) { | 105 | if (err < 0) { |
106 | index--; | 106 | index--; |
107 | nlmsg_trim(skb, nest); | 107 | nlmsg_trim(skb, nest); |
@@ -125,27 +125,27 @@ nla_put_failure: | |||
125 | } | 125 | } |
126 | 126 | ||
127 | static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, | 127 | static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, |
128 | struct tc_action *a) | 128 | const struct tc_action_ops *ops) |
129 | { | 129 | { |
130 | struct hlist_head *head; | ||
131 | struct hlist_node *n; | ||
132 | struct tcf_common *p; | ||
133 | struct nlattr *nest; | 130 | struct nlattr *nest; |
134 | int i = 0, n_i = 0; | 131 | int i = 0, n_i = 0; |
135 | int ret = -EINVAL; | 132 | int ret = -EINVAL; |
136 | 133 | ||
137 | nest = nla_nest_start(skb, a->order); | 134 | nest = nla_nest_start(skb, 0); |
138 | if (nest == NULL) | 135 | if (nest == NULL) |
139 | goto nla_put_failure; | 136 | goto nla_put_failure; |
140 | if (nla_put_string(skb, TCA_KIND, a->ops->kind)) | 137 | if (nla_put_string(skb, TCA_KIND, ops->kind)) |
141 | goto nla_put_failure; | 138 | goto nla_put_failure; |
142 | for (i = 0; i < (hinfo->hmask + 1); i++) { | 139 | for (i = 0; i < (hinfo->hmask + 1); i++) { |
140 | struct hlist_head *head; | ||
141 | struct hlist_node *n; | ||
142 | struct tcf_common *p; | ||
143 | |||
143 | head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; | 144 | head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; |
144 | hlist_for_each_entry_safe(p, n, head, tcfc_head) { | 145 | hlist_for_each_entry_safe(p, n, head, tcfc_head) { |
145 | a->priv = p; | 146 | ret = __tcf_hash_release((struct tc_action *)p, false, true); |
146 | ret = __tcf_hash_release(a, false, true); | ||
147 | if (ret == ACT_P_DELETED) { | 147 | if (ret == ACT_P_DELETED) { |
148 | module_put(a->ops->owner); | 148 | module_put(p->tcfc_act.ops->owner); |
149 | n_i++; | 149 | n_i++; |
150 | } else if (ret < 0) | 150 | } else if (ret < 0) |
151 | goto nla_put_failure; | 151 | goto nla_put_failure; |
@@ -163,16 +163,14 @@ nla_put_failure: | |||
163 | 163 | ||
164 | int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, | 164 | int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, |
165 | struct netlink_callback *cb, int type, | 165 | struct netlink_callback *cb, int type, |
166 | struct tc_action *a) | 166 | const struct tc_action_ops *ops) |
167 | { | 167 | { |
168 | struct tcf_hashinfo *hinfo = tn->hinfo; | 168 | struct tcf_hashinfo *hinfo = tn->hinfo; |
169 | 169 | ||
170 | a->hinfo = hinfo; | ||
171 | |||
172 | if (type == RTM_DELACTION) { | 170 | if (type == RTM_DELACTION) { |
173 | return tcf_del_walker(hinfo, skb, a); | 171 | return tcf_del_walker(hinfo, skb, ops); |
174 | } else if (type == RTM_GETACTION) { | 172 | } else if (type == RTM_GETACTION) { |
175 | return tcf_dump_walker(hinfo, skb, cb, a); | 173 | return tcf_dump_walker(hinfo, skb, cb); |
176 | } else { | 174 | } else { |
177 | WARN(1, "tcf_generic_walker: unknown action %d\n", type); | 175 | WARN(1, "tcf_generic_walker: unknown action %d\n", type); |
178 | return -EINVAL; | 176 | return -EINVAL; |
@@ -210,21 +208,20 @@ u32 tcf_hash_new_index(struct tc_action_net *tn) | |||
210 | } | 208 | } |
211 | EXPORT_SYMBOL(tcf_hash_new_index); | 209 | EXPORT_SYMBOL(tcf_hash_new_index); |
212 | 210 | ||
213 | int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index) | 211 | int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index) |
214 | { | 212 | { |
215 | struct tcf_hashinfo *hinfo = tn->hinfo; | 213 | struct tcf_hashinfo *hinfo = tn->hinfo; |
216 | struct tcf_common *p = tcf_hash_lookup(index, hinfo); | 214 | struct tcf_common *p = tcf_hash_lookup(index, hinfo); |
217 | 215 | ||
218 | if (p) { | 216 | if (p) { |
219 | a->priv = p; | 217 | *a = &p->tcfc_act; |
220 | a->hinfo = hinfo; | ||
221 | return 1; | 218 | return 1; |
222 | } | 219 | } |
223 | return 0; | 220 | return 0; |
224 | } | 221 | } |
225 | EXPORT_SYMBOL(tcf_hash_search); | 222 | EXPORT_SYMBOL(tcf_hash_search); |
226 | 223 | ||
227 | bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a, | 224 | bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a, |
228 | int bind) | 225 | int bind) |
229 | { | 226 | { |
230 | struct tcf_hashinfo *hinfo = tn->hinfo; | 227 | struct tcf_hashinfo *hinfo = tn->hinfo; |
@@ -233,8 +230,7 @@ bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a, | |||
233 | if (bind) | 230 | if (bind) |
234 | p->tcfc_bindcnt++; | 231 | p->tcfc_bindcnt++; |
235 | p->tcfc_refcnt++; | 232 | p->tcfc_refcnt++; |
236 | a->priv = p; | 233 | *a = &p->tcfc_act; |
237 | a->hinfo = hinfo; | ||
238 | return true; | 234 | return true; |
239 | } | 235 | } |
240 | return false; | 236 | return false; |
@@ -243,7 +239,7 @@ EXPORT_SYMBOL(tcf_hash_check); | |||
243 | 239 | ||
244 | void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est) | 240 | void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est) |
245 | { | 241 | { |
246 | struct tcf_common *pc = a->priv; | 242 | struct tcf_common *pc = (struct tcf_common *)a; |
247 | if (est) | 243 | if (est) |
248 | gen_kill_estimator(&pc->tcfc_bstats, | 244 | gen_kill_estimator(&pc->tcfc_bstats, |
249 | &pc->tcfc_rate_est); | 245 | &pc->tcfc_rate_est); |
@@ -252,9 +248,10 @@ void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est) | |||
252 | EXPORT_SYMBOL(tcf_hash_cleanup); | 248 | EXPORT_SYMBOL(tcf_hash_cleanup); |
253 | 249 | ||
254 | int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est, | 250 | int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est, |
255 | struct tc_action *a, int size, int bind, bool cpustats) | 251 | struct tc_action **a, const struct tc_action_ops *ops, |
252 | int bind, bool cpustats) | ||
256 | { | 253 | { |
257 | struct tcf_common *p = kzalloc(size, GFP_KERNEL); | 254 | struct tcf_common *p = kzalloc(ops->size, GFP_KERNEL); |
258 | struct tcf_hashinfo *hinfo = tn->hinfo; | 255 | struct tcf_hashinfo *hinfo = tn->hinfo; |
259 | int err = -ENOMEM; | 256 | int err = -ENOMEM; |
260 | 257 | ||
@@ -294,15 +291,17 @@ err2: | |||
294 | } | 291 | } |
295 | } | 292 | } |
296 | 293 | ||
297 | a->priv = (void *) p; | 294 | p->tcfc_act.hinfo = hinfo; |
298 | a->hinfo = hinfo; | 295 | p->tcfc_act.ops = ops; |
296 | INIT_LIST_HEAD(&p->tcfc_act.list); | ||
297 | *a = &p->tcfc_act; | ||
299 | return 0; | 298 | return 0; |
300 | } | 299 | } |
301 | EXPORT_SYMBOL(tcf_hash_create); | 300 | EXPORT_SYMBOL(tcf_hash_create); |
302 | 301 | ||
303 | void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a) | 302 | void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a) |
304 | { | 303 | { |
305 | struct tcf_common *p = a->priv; | 304 | struct tcf_common *p = (struct tcf_common *)a; |
306 | struct tcf_hashinfo *hinfo = tn->hinfo; | 305 | struct tcf_hashinfo *hinfo = tn->hinfo; |
307 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); | 306 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); |
308 | 307 | ||
@@ -315,10 +314,6 @@ EXPORT_SYMBOL(tcf_hash_insert); | |||
315 | void tcf_hashinfo_destroy(const struct tc_action_ops *ops, | 314 | void tcf_hashinfo_destroy(const struct tc_action_ops *ops, |
316 | struct tcf_hashinfo *hinfo) | 315 | struct tcf_hashinfo *hinfo) |
317 | { | 316 | { |
318 | struct tc_action a = { | ||
319 | .ops = ops, | ||
320 | .hinfo = hinfo, | ||
321 | }; | ||
322 | int i; | 317 | int i; |
323 | 318 | ||
324 | for (i = 0; i < hinfo->hmask + 1; i++) { | 319 | for (i = 0; i < hinfo->hmask + 1; i++) { |
@@ -328,8 +323,7 @@ void tcf_hashinfo_destroy(const struct tc_action_ops *ops, | |||
328 | hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfc_head) { | 323 | hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfc_head) { |
329 | int ret; | 324 | int ret; |
330 | 325 | ||
331 | a.priv = p; | 326 | ret = __tcf_hash_release((struct tc_action *)p, false, true); |
332 | ret = __tcf_hash_release(&a, false, true); | ||
333 | if (ret == ACT_P_DELETED) | 327 | if (ret == ACT_P_DELETED) |
334 | module_put(ops->owner); | 328 | module_put(ops->owner); |
335 | else if (ret < 0) | 329 | else if (ret < 0) |
@@ -466,8 +460,6 @@ int tcf_action_destroy(struct list_head *actions, int bind) | |||
466 | module_put(a->ops->owner); | 460 | module_put(a->ops->owner); |
467 | else if (ret < 0) | 461 | else if (ret < 0) |
468 | return ret; | 462 | return ret; |
469 | list_del(&a->list); | ||
470 | kfree(a); | ||
471 | } | 463 | } |
472 | return ret; | 464 | return ret; |
473 | } | 465 | } |
@@ -581,20 +573,13 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, | |||
581 | goto err_out; | 573 | goto err_out; |
582 | } | 574 | } |
583 | 575 | ||
584 | err = -ENOMEM; | ||
585 | a = kzalloc(sizeof(*a), GFP_KERNEL); | ||
586 | if (a == NULL) | ||
587 | goto err_mod; | ||
588 | |||
589 | a->ops = a_o; | ||
590 | INIT_LIST_HEAD(&a->list); | ||
591 | /* backward compatibility for policer */ | 576 | /* backward compatibility for policer */ |
592 | if (name == NULL) | 577 | if (name == NULL) |
593 | err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind); | 578 | err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind); |
594 | else | 579 | else |
595 | err = a_o->init(net, nla, est, a, ovr, bind); | 580 | err = a_o->init(net, nla, est, &a, ovr, bind); |
596 | if (err < 0) | 581 | if (err < 0) |
597 | goto err_free; | 582 | goto err_mod; |
598 | 583 | ||
599 | /* module count goes up only when brand new policy is created | 584 | /* module count goes up only when brand new policy is created |
600 | * if it exists and is only bound to in a_o->init() then | 585 | * if it exists and is only bound to in a_o->init() then |
@@ -605,8 +590,6 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, | |||
605 | 590 | ||
606 | return a; | 591 | return a; |
607 | 592 | ||
608 | err_free: | ||
609 | kfree(a); | ||
610 | err_mod: | 593 | err_mod: |
611 | module_put(a_o->owner); | 594 | module_put(a_o->owner); |
612 | err_out: | 595 | err_out: |
@@ -647,7 +630,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, | |||
647 | { | 630 | { |
648 | int err = 0; | 631 | int err = 0; |
649 | struct gnet_dump d; | 632 | struct gnet_dump d; |
650 | struct tcf_common *p = a->priv; | 633 | struct tcf_common *p = (struct tcf_common *)a; |
651 | 634 | ||
652 | if (p == NULL) | 635 | if (p == NULL) |
653 | goto errout; | 636 | goto errout; |
@@ -740,24 +723,11 @@ act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, | |||
740 | return rtnl_unicast(skb, net, portid); | 723 | return rtnl_unicast(skb, net, portid); |
741 | } | 724 | } |
742 | 725 | ||
743 | static struct tc_action *create_a(int i) | ||
744 | { | ||
745 | struct tc_action *act; | ||
746 | |||
747 | act = kzalloc(sizeof(*act), GFP_KERNEL); | ||
748 | if (act == NULL) { | ||
749 | pr_debug("create_a: failed to alloc!\n"); | ||
750 | return NULL; | ||
751 | } | ||
752 | act->order = i; | ||
753 | INIT_LIST_HEAD(&act->list); | ||
754 | return act; | ||
755 | } | ||
756 | |||
757 | static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, | 726 | static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, |
758 | struct nlmsghdr *n, u32 portid) | 727 | struct nlmsghdr *n, u32 portid) |
759 | { | 728 | { |
760 | struct nlattr *tb[TCA_ACT_MAX + 1]; | 729 | struct nlattr *tb[TCA_ACT_MAX + 1]; |
730 | const struct tc_action_ops *ops; | ||
761 | struct tc_action *a; | 731 | struct tc_action *a; |
762 | int index; | 732 | int index; |
763 | int err; | 733 | int err; |
@@ -772,26 +742,19 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, | |||
772 | goto err_out; | 742 | goto err_out; |
773 | index = nla_get_u32(tb[TCA_ACT_INDEX]); | 743 | index = nla_get_u32(tb[TCA_ACT_INDEX]); |
774 | 744 | ||
775 | err = -ENOMEM; | ||
776 | a = create_a(0); | ||
777 | if (a == NULL) | ||
778 | goto err_out; | ||
779 | |||
780 | err = -EINVAL; | 745 | err = -EINVAL; |
781 | a->ops = tc_lookup_action(tb[TCA_ACT_KIND]); | 746 | ops = tc_lookup_action(tb[TCA_ACT_KIND]); |
782 | if (a->ops == NULL) /* could happen in batch of actions */ | 747 | if (!ops) /* could happen in batch of actions */ |
783 | goto err_free; | 748 | goto err_out; |
784 | err = -ENOENT; | 749 | err = -ENOENT; |
785 | if (a->ops->lookup(net, a, index) == 0) | 750 | if (ops->lookup(net, &a, index) == 0) |
786 | goto err_mod; | 751 | goto err_mod; |
787 | 752 | ||
788 | module_put(a->ops->owner); | 753 | module_put(ops->owner); |
789 | return a; | 754 | return a; |
790 | 755 | ||
791 | err_mod: | 756 | err_mod: |
792 | module_put(a->ops->owner); | 757 | module_put(ops->owner); |
793 | err_free: | ||
794 | kfree(a); | ||
795 | err_out: | 758 | err_out: |
796 | return ERR_PTR(err); | 759 | return ERR_PTR(err); |
797 | } | 760 | } |
@@ -816,8 +779,8 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, | |||
816 | struct netlink_callback dcb; | 779 | struct netlink_callback dcb; |
817 | struct nlattr *nest; | 780 | struct nlattr *nest; |
818 | struct nlattr *tb[TCA_ACT_MAX + 1]; | 781 | struct nlattr *tb[TCA_ACT_MAX + 1]; |
782 | const struct tc_action_ops *ops; | ||
819 | struct nlattr *kind; | 783 | struct nlattr *kind; |
820 | struct tc_action a; | ||
821 | int err = -ENOMEM; | 784 | int err = -ENOMEM; |
822 | 785 | ||
823 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 786 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
@@ -834,10 +797,8 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, | |||
834 | 797 | ||
835 | err = -EINVAL; | 798 | err = -EINVAL; |
836 | kind = tb[TCA_ACT_KIND]; | 799 | kind = tb[TCA_ACT_KIND]; |
837 | memset(&a, 0, sizeof(struct tc_action)); | 800 | ops = tc_lookup_action(kind); |
838 | INIT_LIST_HEAD(&a.list); | 801 | if (!ops) /*some idjot trying to flush unknown action */ |
839 | a.ops = tc_lookup_action(kind); | ||
840 | if (a.ops == NULL) /*some idjot trying to flush unknown action */ | ||
841 | goto err_out; | 802 | goto err_out; |
842 | 803 | ||
843 | nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, | 804 | nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, |
@@ -853,7 +814,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, | |||
853 | if (nest == NULL) | 814 | if (nest == NULL) |
854 | goto out_module_put; | 815 | goto out_module_put; |
855 | 816 | ||
856 | err = a.ops->walk(net, skb, &dcb, RTM_DELACTION, &a); | 817 | err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops); |
857 | if (err < 0) | 818 | if (err < 0) |
858 | goto out_module_put; | 819 | goto out_module_put; |
859 | if (err == 0) | 820 | if (err == 0) |
@@ -863,7 +824,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, | |||
863 | 824 | ||
864 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; | 825 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
865 | nlh->nlmsg_flags |= NLM_F_ROOT; | 826 | nlh->nlmsg_flags |= NLM_F_ROOT; |
866 | module_put(a.ops->owner); | 827 | module_put(ops->owner); |
867 | err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, | 828 | err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, |
868 | n->nlmsg_flags & NLM_F_ECHO); | 829 | n->nlmsg_flags & NLM_F_ECHO); |
869 | if (err > 0) | 830 | if (err > 0) |
@@ -872,7 +833,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, | |||
872 | return err; | 833 | return err; |
873 | 834 | ||
874 | out_module_put: | 835 | out_module_put: |
875 | module_put(a.ops->owner); | 836 | module_put(ops->owner); |
876 | err_out: | 837 | err_out: |
877 | noflush_out: | 838 | noflush_out: |
878 | kfree_skb(skb); | 839 | kfree_skb(skb); |
@@ -1084,7 +1045,6 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) | |||
1084 | unsigned char *b = skb_tail_pointer(skb); | 1045 | unsigned char *b = skb_tail_pointer(skb); |
1085 | struct nlattr *nest; | 1046 | struct nlattr *nest; |
1086 | struct tc_action_ops *a_o; | 1047 | struct tc_action_ops *a_o; |
1087 | struct tc_action a; | ||
1088 | int ret = 0; | 1048 | int ret = 0; |
1089 | struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh); | 1049 | struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh); |
1090 | struct nlattr *kind = find_dump_kind(cb->nlh); | 1050 | struct nlattr *kind = find_dump_kind(cb->nlh); |
@@ -1098,9 +1058,6 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) | |||
1098 | if (a_o == NULL) | 1058 | if (a_o == NULL) |
1099 | return 0; | 1059 | return 0; |
1100 | 1060 | ||
1101 | memset(&a, 0, sizeof(struct tc_action)); | ||
1102 | a.ops = a_o; | ||
1103 | |||
1104 | nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, | 1061 | nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, |
1105 | cb->nlh->nlmsg_type, sizeof(*t), 0); | 1062 | cb->nlh->nlmsg_type, sizeof(*t), 0); |
1106 | if (!nlh) | 1063 | if (!nlh) |
@@ -1114,7 +1071,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) | |||
1114 | if (nest == NULL) | 1071 | if (nest == NULL) |
1115 | goto out_module_put; | 1072 | goto out_module_put; |
1116 | 1073 | ||
1117 | ret = a_o->walk(net, skb, cb, RTM_GETACTION, &a); | 1074 | ret = a_o->walk(net, skb, cb, RTM_GETACTION, a_o); |
1118 | if (ret < 0) | 1075 | if (ret < 0) |
1119 | goto out_module_put; | 1076 | goto out_module_put; |
1120 | 1077 | ||