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 | |
| 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>
| -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 | ||
