aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r--net/sched/cls_api.c33
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
499void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) 499void 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