diff options
Diffstat (limited to 'net/sched/cls_api.c')
| -rw-r--r-- | net/sched/cls_api.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index c28b0d327b12..aad6a679fb13 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
| @@ -117,7 +117,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) | |||
| 117 | { | 117 | { |
| 118 | struct net *net = sock_net(skb->sk); | 118 | struct net *net = sock_net(skb->sk); |
| 119 | struct nlattr *tca[TCA_MAX + 1]; | 119 | struct nlattr *tca[TCA_MAX + 1]; |
| 120 | spinlock_t *root_lock; | ||
| 121 | struct tcmsg *t; | 120 | struct tcmsg *t; |
| 122 | u32 protocol; | 121 | u32 protocol; |
| 123 | u32 prio; | 122 | u32 prio; |
| @@ -125,7 +124,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) | |||
| 125 | u32 parent; | 124 | u32 parent; |
| 126 | struct net_device *dev; | 125 | struct net_device *dev; |
| 127 | struct Qdisc *q; | 126 | struct Qdisc *q; |
| 128 | struct tcf_proto **back, **chain; | 127 | struct tcf_proto __rcu **back; |
| 128 | struct tcf_proto __rcu **chain; | ||
| 129 | struct tcf_proto *tp; | 129 | struct tcf_proto *tp; |
| 130 | const struct tcf_proto_ops *tp_ops; | 130 | const struct tcf_proto_ops *tp_ops; |
| 131 | const struct Qdisc_class_ops *cops; | 131 | const struct Qdisc_class_ops *cops; |
| @@ -197,7 +197,9 @@ replay: | |||
| 197 | goto errout; | 197 | goto errout; |
| 198 | 198 | ||
| 199 | /* Check the chain for existence of proto-tcf with this priority */ | 199 | /* Check the chain for existence of proto-tcf with this priority */ |
| 200 | for (back = chain; (tp = *back) != NULL; back = &tp->next) { | 200 | for (back = chain; |
| 201 | (tp = rtnl_dereference(*back)) != NULL; | ||
| 202 | back = &tp->next) { | ||
| 201 | if (tp->prio >= prio) { | 203 | if (tp->prio >= prio) { |
| 202 | if (tp->prio == prio) { | 204 | if (tp->prio == prio) { |
| 203 | if (!nprio || | 205 | if (!nprio || |
| @@ -209,8 +211,6 @@ replay: | |||
| 209 | } | 211 | } |
| 210 | } | 212 | } |
| 211 | 213 | ||
| 212 | root_lock = qdisc_root_sleeping_lock(q); | ||
| 213 | |||
| 214 | if (tp == NULL) { | 214 | if (tp == NULL) { |
| 215 | /* Proto-tcf does not exist, create new one */ | 215 | /* Proto-tcf does not exist, create new one */ |
| 216 | 216 | ||
| @@ -259,7 +259,8 @@ replay: | |||
| 259 | } | 259 | } |
| 260 | tp->ops = tp_ops; | 260 | tp->ops = tp_ops; |
| 261 | tp->protocol = protocol; | 261 | tp->protocol = protocol; |
| 262 | tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back)); | 262 | tp->prio = nprio ? : |
| 263 | TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back))); | ||
| 263 | tp->q = q; | 264 | tp->q = q; |
| 264 | tp->classify = tp_ops->classify; | 265 | tp->classify = tp_ops->classify; |
| 265 | tp->classid = parent; | 266 | tp->classid = parent; |
| @@ -280,9 +281,9 @@ replay: | |||
| 280 | 281 | ||
| 281 | if (fh == 0) { | 282 | if (fh == 0) { |
| 282 | if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { | 283 | if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { |
| 283 | spin_lock_bh(root_lock); | 284 | struct tcf_proto *next = rtnl_dereference(tp->next); |
| 284 | *back = tp->next; | 285 | |
| 285 | spin_unlock_bh(root_lock); | 286 | RCU_INIT_POINTER(*back, next); |
| 286 | 287 | ||
| 287 | tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); | 288 | tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); |
| 288 | tcf_destroy(tp); | 289 | tcf_destroy(tp); |
| @@ -322,10 +323,8 @@ replay: | |||
| 322 | n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE); | 323 | n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE); |
| 323 | if (err == 0) { | 324 | if (err == 0) { |
| 324 | if (tp_created) { | 325 | if (tp_created) { |
| 325 | spin_lock_bh(root_lock); | 326 | RCU_INIT_POINTER(tp->next, rtnl_dereference(*back)); |
| 326 | tp->next = *back; | 327 | rcu_assign_pointer(*back, tp); |
| 327 | *back = tp; | ||
| 328 | spin_unlock_bh(root_lock); | ||
| 329 | } | 328 | } |
| 330 | tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); | 329 | tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); |
| 331 | } else { | 330 | } else { |
| @@ -420,7 +419,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 420 | int s_t; | 419 | int s_t; |
| 421 | struct net_device *dev; | 420 | struct net_device *dev; |
| 422 | struct Qdisc *q; | 421 | struct Qdisc *q; |
| 423 | struct tcf_proto *tp, **chain; | 422 | struct tcf_proto *tp, __rcu **chain; |
| 424 | struct tcmsg *tcm = nlmsg_data(cb->nlh); | 423 | struct tcmsg *tcm = nlmsg_data(cb->nlh); |
| 425 | unsigned long cl = 0; | 424 | unsigned long cl = 0; |
| 426 | const struct Qdisc_class_ops *cops; | 425 | const struct Qdisc_class_ops *cops; |
| @@ -454,7 +453,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 454 | 453 | ||
| 455 | s_t = cb->args[0]; | 454 | s_t = cb->args[0]; |
| 456 | 455 | ||
| 457 | for (tp = *chain, t = 0; tp; tp = tp->next, t++) { | 456 | for (tp = rtnl_dereference(*chain), t = 0; |
| 457 | tp; tp = rtnl_dereference(tp->next), t++) { | ||
| 458 | if (t < s_t) | 458 | if (t < s_t) |
| 459 | continue; | 459 | continue; |
| 460 | if (TC_H_MAJ(tcm->tcm_info) && | 460 | if (TC_H_MAJ(tcm->tcm_info) && |
| @@ -496,7 +496,7 @@ out: | |||
| 496 | return skb->len; | 496 | return skb->len; |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) | 499 | void tcf_exts_destroy(struct tcf_exts *exts) |
| 500 | { | 500 | { |
| 501 | #ifdef CONFIG_NET_CLS_ACT | 501 | #ifdef CONFIG_NET_CLS_ACT |
| 502 | tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); | 502 | tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); |
| @@ -549,6 +549,7 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, | |||
| 549 | tcf_tree_lock(tp); | 549 | tcf_tree_lock(tp); |
| 550 | list_splice_init(&dst->actions, &tmp); | 550 | list_splice_init(&dst->actions, &tmp); |
| 551 | list_splice(&src->actions, &dst->actions); | 551 | list_splice(&src->actions, &dst->actions); |
| 552 | dst->type = src->type; | ||
| 552 | tcf_tree_unlock(tp); | 553 | tcf_tree_unlock(tp); |
| 553 | tcf_action_destroy(&tmp, TCA_ACT_UNBIND); | 554 | tcf_action_destroy(&tmp, TCA_ACT_UNBIND); |
| 554 | #endif | 555 | #endif |
