diff options
author | John Fastabend <john.fastabend@gmail.com> | 2014-09-26 13:02:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-29 00:04:55 -0400 |
commit | 53dfd501819a6e9c3a7d56cac1ddaf03fe90800d (patch) | |
tree | 20e32493fd39370d3d790b79c54f078d9fa3e484 /net/sched | |
parent | 3d9a0d2f8212879407e58d67f460d8920eb6543d (diff) |
net: sched: cls_rcvp, complete rcu conversion
This completes the cls_rsvp conversion to RCU safe
copy, update semantics.
As a result all cases of tcf_exts_change occur on
empty lists now.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/cls_rsvp.h | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 1c64a09753c4..6bb55f277a5a 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h | |||
@@ -222,6 +222,33 @@ matched: | |||
222 | return -1; | 222 | return -1; |
223 | } | 223 | } |
224 | 224 | ||
225 | static void rsvp_replace(struct tcf_proto *tp, struct rsvp_filter *n, u32 h) | ||
226 | { | ||
227 | struct rsvp_head *head = rtnl_dereference(tp->root); | ||
228 | struct rsvp_session *s; | ||
229 | struct rsvp_filter __rcu **ins; | ||
230 | struct rsvp_filter *pins; | ||
231 | unsigned int h1 = h & 0xFF; | ||
232 | unsigned int h2 = (h >> 8) & 0xFF; | ||
233 | |||
234 | for (s = rtnl_dereference(head->ht[h1]); s; | ||
235 | s = rtnl_dereference(s->next)) { | ||
236 | for (ins = &s->ht[h2], pins = rtnl_dereference(*ins); ; | ||
237 | ins = &pins->next, pins = rtnl_dereference(*ins)) { | ||
238 | if (pins->handle == h) { | ||
239 | RCU_INIT_POINTER(n->next, pins->next); | ||
240 | rcu_assign_pointer(*ins, n); | ||
241 | return; | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /* Something went wrong if we are trying to replace a non-existant | ||
247 | * node. Mind as well halt instead of silently failing. | ||
248 | */ | ||
249 | BUG_ON(1); | ||
250 | } | ||
251 | |||
225 | static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) | 252 | static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) |
226 | { | 253 | { |
227 | struct rsvp_head *head = rtnl_dereference(tp->root); | 254 | struct rsvp_head *head = rtnl_dereference(tp->root); |
@@ -454,15 +481,26 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, | |||
454 | f = (struct rsvp_filter *)*arg; | 481 | f = (struct rsvp_filter *)*arg; |
455 | if (f) { | 482 | if (f) { |
456 | /* Node exists: adjust only classid */ | 483 | /* Node exists: adjust only classid */ |
484 | struct rsvp_filter *n; | ||
457 | 485 | ||
458 | if (f->handle != handle && handle) | 486 | if (f->handle != handle && handle) |
459 | goto errout2; | 487 | goto errout2; |
488 | |||
489 | n = kmemdup(f, sizeof(*f), GFP_KERNEL); | ||
490 | if (!n) { | ||
491 | err = -ENOMEM; | ||
492 | goto errout2; | ||
493 | } | ||
494 | |||
495 | tcf_exts_init(&n->exts, TCA_RSVP_ACT, TCA_RSVP_POLICE); | ||
496 | |||
460 | if (tb[TCA_RSVP_CLASSID]) { | 497 | if (tb[TCA_RSVP_CLASSID]) { |
461 | f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]); | 498 | n->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]); |
462 | tcf_bind_filter(tp, &f->res, base); | 499 | tcf_bind_filter(tp, &n->res, base); |
463 | } | 500 | } |
464 | 501 | ||
465 | tcf_exts_change(tp, &f->exts, &e); | 502 | tcf_exts_change(tp, &n->exts, &e); |
503 | rsvp_replace(tp, n, handle); | ||
466 | return 0; | 504 | return 0; |
467 | } | 505 | } |
468 | 506 | ||