diff options
author | John Fastabend <john.fastabend@gmail.com> | 2014-09-12 23:09:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-13 12:30:26 -0400 |
commit | b929d86d25352496c528fcd74fdcabe3f6a4994a (patch) | |
tree | 6536ad5e227b16b6e9d7090a928b87eab38246a1 /net/sched | |
parent | 1ce87720d456e471de0fbd814dc5d1fe10fc1c44 (diff) |
net: sched: rcu'ify cls_rsvp
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/cls_rsvp.h | 160 |
1 files changed, 90 insertions, 70 deletions
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 1020e233a5d6..b044c208b133 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h | |||
@@ -70,31 +70,34 @@ struct rsvp_head { | |||
70 | u32 tmap[256/32]; | 70 | u32 tmap[256/32]; |
71 | u32 hgenerator; | 71 | u32 hgenerator; |
72 | u8 tgenerator; | 72 | u8 tgenerator; |
73 | struct rsvp_session *ht[256]; | 73 | struct rsvp_session __rcu *ht[256]; |
74 | struct rcu_head rcu; | ||
74 | }; | 75 | }; |
75 | 76 | ||
76 | struct rsvp_session { | 77 | struct rsvp_session { |
77 | struct rsvp_session *next; | 78 | struct rsvp_session __rcu *next; |
78 | __be32 dst[RSVP_DST_LEN]; | 79 | __be32 dst[RSVP_DST_LEN]; |
79 | struct tc_rsvp_gpi dpi; | 80 | struct tc_rsvp_gpi dpi; |
80 | u8 protocol; | 81 | u8 protocol; |
81 | u8 tunnelid; | 82 | u8 tunnelid; |
82 | /* 16 (src,sport) hash slots, and one wildcard source slot */ | 83 | /* 16 (src,sport) hash slots, and one wildcard source slot */ |
83 | struct rsvp_filter *ht[16 + 1]; | 84 | struct rsvp_filter __rcu *ht[16 + 1]; |
85 | struct rcu_head rcu; | ||
84 | }; | 86 | }; |
85 | 87 | ||
86 | 88 | ||
87 | struct rsvp_filter { | 89 | struct rsvp_filter { |
88 | struct rsvp_filter *next; | 90 | struct rsvp_filter __rcu *next; |
89 | __be32 src[RSVP_DST_LEN]; | 91 | __be32 src[RSVP_DST_LEN]; |
90 | struct tc_rsvp_gpi spi; | 92 | struct tc_rsvp_gpi spi; |
91 | u8 tunnelhdr; | 93 | u8 tunnelhdr; |
92 | 94 | ||
93 | struct tcf_result res; | 95 | struct tcf_result res; |
94 | struct tcf_exts exts; | 96 | struct tcf_exts exts; |
95 | 97 | ||
96 | u32 handle; | 98 | u32 handle; |
97 | struct rsvp_session *sess; | 99 | struct rsvp_session *sess; |
100 | struct rcu_head rcu; | ||
98 | }; | 101 | }; |
99 | 102 | ||
100 | static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) | 103 | static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) |
@@ -128,7 +131,7 @@ static inline unsigned int hash_src(__be32 *src) | |||
128 | static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 131 | static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
129 | struct tcf_result *res) | 132 | struct tcf_result *res) |
130 | { | 133 | { |
131 | struct rsvp_session **sht = ((struct rsvp_head *)tp->root)->ht; | 134 | struct rsvp_head *head = rcu_dereference_bh(tp->root); |
132 | struct rsvp_session *s; | 135 | struct rsvp_session *s; |
133 | struct rsvp_filter *f; | 136 | struct rsvp_filter *f; |
134 | unsigned int h1, h2; | 137 | unsigned int h1, h2; |
@@ -169,7 +172,8 @@ restart: | |||
169 | h1 = hash_dst(dst, protocol, tunnelid); | 172 | h1 = hash_dst(dst, protocol, tunnelid); |
170 | h2 = hash_src(src); | 173 | h2 = hash_src(src); |
171 | 174 | ||
172 | for (s = sht[h1]; s; s = s->next) { | 175 | for (s = rcu_dereference_bh(head->ht[h1]); s; |
176 | s = rcu_dereference_bh(s->next)) { | ||
173 | if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] && | 177 | if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] && |
174 | protocol == s->protocol && | 178 | protocol == s->protocol && |
175 | !(s->dpi.mask & | 179 | !(s->dpi.mask & |
@@ -181,7 +185,8 @@ restart: | |||
181 | #endif | 185 | #endif |
182 | tunnelid == s->tunnelid) { | 186 | tunnelid == s->tunnelid) { |
183 | 187 | ||
184 | for (f = s->ht[h2]; f; f = f->next) { | 188 | for (f = rcu_dereference_bh(s->ht[h2]); f; |
189 | f = rcu_dereference_bh(f->next)) { | ||
185 | if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] && | 190 | if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] && |
186 | !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key)) | 191 | !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key)) |
187 | #if RSVP_DST_LEN == 4 | 192 | #if RSVP_DST_LEN == 4 |
@@ -205,7 +210,8 @@ matched: | |||
205 | } | 210 | } |
206 | 211 | ||
207 | /* And wildcard bucket... */ | 212 | /* And wildcard bucket... */ |
208 | for (f = s->ht[16]; f; f = f->next) { | 213 | for (f = rcu_dereference_bh(s->ht[16]); f; |
214 | f = rcu_dereference_bh(f->next)) { | ||
209 | *res = f->res; | 215 | *res = f->res; |
210 | RSVP_APPLY_RESULT(); | 216 | RSVP_APPLY_RESULT(); |
211 | goto matched; | 217 | goto matched; |
@@ -218,7 +224,7 @@ matched: | |||
218 | 224 | ||
219 | static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) | 225 | static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) |
220 | { | 226 | { |
221 | struct rsvp_session **sht = ((struct rsvp_head *)tp->root)->ht; | 227 | struct rsvp_head *head = rtnl_dereference(tp->root); |
222 | struct rsvp_session *s; | 228 | struct rsvp_session *s; |
223 | struct rsvp_filter *f; | 229 | struct rsvp_filter *f; |
224 | unsigned int h1 = handle & 0xFF; | 230 | unsigned int h1 = handle & 0xFF; |
@@ -227,8 +233,10 @@ static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) | |||
227 | if (h2 > 16) | 233 | if (h2 > 16) |
228 | return 0; | 234 | return 0; |
229 | 235 | ||
230 | for (s = sht[h1]; s; s = s->next) { | 236 | for (s = rtnl_dereference(head->ht[h1]); s; |
231 | for (f = s->ht[h2]; f; f = f->next) { | 237 | s = rtnl_dereference(s->next)) { |
238 | for (f = rtnl_dereference(s->ht[h2]); f; | ||
239 | f = rtnl_dereference(f->next)) { | ||
232 | if (f->handle == handle) | 240 | if (f->handle == handle) |
233 | return (unsigned long)f; | 241 | return (unsigned long)f; |
234 | } | 242 | } |
@@ -246,7 +254,7 @@ static int rsvp_init(struct tcf_proto *tp) | |||
246 | 254 | ||
247 | data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL); | 255 | data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL); |
248 | if (data) { | 256 | if (data) { |
249 | tp->root = data; | 257 | rcu_assign_pointer(tp->root, data); |
250 | return 0; | 258 | return 0; |
251 | } | 259 | } |
252 | return -ENOBUFS; | 260 | return -ENOBUFS; |
@@ -257,53 +265,54 @@ rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) | |||
257 | { | 265 | { |
258 | tcf_unbind_filter(tp, &f->res); | 266 | tcf_unbind_filter(tp, &f->res); |
259 | tcf_exts_destroy(tp, &f->exts); | 267 | tcf_exts_destroy(tp, &f->exts); |
260 | kfree(f); | 268 | kfree_rcu(f, rcu); |
261 | } | 269 | } |
262 | 270 | ||
263 | static void rsvp_destroy(struct tcf_proto *tp) | 271 | static void rsvp_destroy(struct tcf_proto *tp) |
264 | { | 272 | { |
265 | struct rsvp_head *data = xchg(&tp->root, NULL); | 273 | struct rsvp_head *data = rtnl_dereference(tp->root); |
266 | struct rsvp_session **sht; | ||
267 | int h1, h2; | 274 | int h1, h2; |
268 | 275 | ||
269 | if (data == NULL) | 276 | if (data == NULL) |
270 | return; | 277 | return; |
271 | 278 | ||
272 | sht = data->ht; | 279 | RCU_INIT_POINTER(tp->root, NULL); |
273 | 280 | ||
274 | for (h1 = 0; h1 < 256; h1++) { | 281 | for (h1 = 0; h1 < 256; h1++) { |
275 | struct rsvp_session *s; | 282 | struct rsvp_session *s; |
276 | 283 | ||
277 | while ((s = sht[h1]) != NULL) { | 284 | while ((s = rtnl_dereference(data->ht[h1])) != NULL) { |
278 | sht[h1] = s->next; | 285 | RCU_INIT_POINTER(data->ht[h1], s->next); |
279 | 286 | ||
280 | for (h2 = 0; h2 <= 16; h2++) { | 287 | for (h2 = 0; h2 <= 16; h2++) { |
281 | struct rsvp_filter *f; | 288 | struct rsvp_filter *f; |
282 | 289 | ||
283 | while ((f = s->ht[h2]) != NULL) { | 290 | while ((f = rtnl_dereference(s->ht[h2])) != NULL) { |
284 | s->ht[h2] = f->next; | 291 | rcu_assign_pointer(s->ht[h2], f->next); |
285 | rsvp_delete_filter(tp, f); | 292 | rsvp_delete_filter(tp, f); |
286 | } | 293 | } |
287 | } | 294 | } |
288 | kfree(s); | 295 | kfree_rcu(s, rcu); |
289 | } | 296 | } |
290 | } | 297 | } |
291 | kfree(data); | 298 | kfree_rcu(data, rcu); |
292 | } | 299 | } |
293 | 300 | ||
294 | static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) | 301 | static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) |
295 | { | 302 | { |
296 | struct rsvp_filter **fp, *f = (struct rsvp_filter *)arg; | 303 | struct rsvp_head *head = rtnl_dereference(tp->root); |
304 | struct rsvp_filter *nfp, *f = (struct rsvp_filter *)arg; | ||
305 | struct rsvp_filter __rcu **fp; | ||
297 | unsigned int h = f->handle; | 306 | unsigned int h = f->handle; |
298 | struct rsvp_session **sp; | 307 | struct rsvp_session __rcu **sp; |
299 | struct rsvp_session *s = f->sess; | 308 | struct rsvp_session *nsp, *s = f->sess; |
300 | int i; | 309 | int i; |
301 | 310 | ||
302 | for (fp = &s->ht[(h >> 8) & 0xFF]; *fp; fp = &(*fp)->next) { | 311 | fp = &s->ht[(h >> 8) & 0xFF]; |
303 | if (*fp == f) { | 312 | for (nfp = rtnl_dereference(*fp); nfp; |
304 | tcf_tree_lock(tp); | 313 | fp = &nfp->next, nfp = rtnl_dereference(*fp)) { |
305 | *fp = f->next; | 314 | if (nfp == f) { |
306 | tcf_tree_unlock(tp); | 315 | RCU_INIT_POINTER(*fp, f->next); |
307 | rsvp_delete_filter(tp, f); | 316 | rsvp_delete_filter(tp, f); |
308 | 317 | ||
309 | /* Strip tree */ | 318 | /* Strip tree */ |
@@ -313,14 +322,12 @@ static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) | |||
313 | return 0; | 322 | return 0; |
314 | 323 | ||
315 | /* OK, session has no flows */ | 324 | /* OK, session has no flows */ |
316 | for (sp = &((struct rsvp_head *)tp->root)->ht[h & 0xFF]; | 325 | sp = &head->ht[h & 0xFF]; |
317 | *sp; sp = &(*sp)->next) { | 326 | for (nsp = rtnl_dereference(*sp); nsp; |
318 | if (*sp == s) { | 327 | sp = &nsp->next, nsp = rtnl_dereference(*sp)) { |
319 | tcf_tree_lock(tp); | 328 | if (nsp == s) { |
320 | *sp = s->next; | 329 | RCU_INIT_POINTER(*sp, s->next); |
321 | tcf_tree_unlock(tp); | 330 | kfree_rcu(s, rcu); |
322 | |||
323 | kfree(s); | ||
324 | return 0; | 331 | return 0; |
325 | } | 332 | } |
326 | } | 333 | } |
@@ -333,7 +340,7 @@ static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) | |||
333 | 340 | ||
334 | static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt) | 341 | static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt) |
335 | { | 342 | { |
336 | struct rsvp_head *data = tp->root; | 343 | struct rsvp_head *data = rtnl_dereference(tp->root); |
337 | int i = 0xFFFF; | 344 | int i = 0xFFFF; |
338 | 345 | ||
339 | while (i-- > 0) { | 346 | while (i-- > 0) { |
@@ -361,7 +368,7 @@ static int tunnel_bts(struct rsvp_head *data) | |||
361 | 368 | ||
362 | static void tunnel_recycle(struct rsvp_head *data) | 369 | static void tunnel_recycle(struct rsvp_head *data) |
363 | { | 370 | { |
364 | struct rsvp_session **sht = data->ht; | 371 | struct rsvp_session __rcu **sht = data->ht; |
365 | u32 tmap[256/32]; | 372 | u32 tmap[256/32]; |
366 | int h1, h2; | 373 | int h1, h2; |
367 | 374 | ||
@@ -369,11 +376,13 @@ static void tunnel_recycle(struct rsvp_head *data) | |||
369 | 376 | ||
370 | for (h1 = 0; h1 < 256; h1++) { | 377 | for (h1 = 0; h1 < 256; h1++) { |
371 | struct rsvp_session *s; | 378 | struct rsvp_session *s; |
372 | for (s = sht[h1]; s; s = s->next) { | 379 | for (s = rtnl_dereference(sht[h1]); s; |
380 | s = rtnl_dereference(s->next)) { | ||
373 | for (h2 = 0; h2 <= 16; h2++) { | 381 | for (h2 = 0; h2 <= 16; h2++) { |
374 | struct rsvp_filter *f; | 382 | struct rsvp_filter *f; |
375 | 383 | ||
376 | for (f = s->ht[h2]; f; f = f->next) { | 384 | for (f = rtnl_dereference(s->ht[h2]); f; |
385 | f = rtnl_dereference(f->next)) { | ||
377 | if (f->tunnelhdr == 0) | 386 | if (f->tunnelhdr == 0) |
378 | continue; | 387 | continue; |
379 | data->tgenerator = f->res.classid; | 388 | data->tgenerator = f->res.classid; |
@@ -417,9 +426,11 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, | |||
417 | struct nlattr **tca, | 426 | struct nlattr **tca, |
418 | unsigned long *arg, bool ovr) | 427 | unsigned long *arg, bool ovr) |
419 | { | 428 | { |
420 | struct rsvp_head *data = tp->root; | 429 | struct rsvp_head *data = rtnl_dereference(tp->root); |
421 | struct rsvp_filter *f, **fp; | 430 | struct rsvp_filter *f, *nfp; |
422 | struct rsvp_session *s, **sp; | 431 | struct rsvp_filter __rcu **fp; |
432 | struct rsvp_session *nsp, *s; | ||
433 | struct rsvp_session __rcu **sp; | ||
423 | struct tc_rsvp_pinfo *pinfo = NULL; | 434 | struct tc_rsvp_pinfo *pinfo = NULL; |
424 | struct nlattr *opt = tca[TCA_OPTIONS]; | 435 | struct nlattr *opt = tca[TCA_OPTIONS]; |
425 | struct nlattr *tb[TCA_RSVP_MAX + 1]; | 436 | struct nlattr *tb[TCA_RSVP_MAX + 1]; |
@@ -499,7 +510,9 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, | |||
499 | goto errout; | 510 | goto errout; |
500 | } | 511 | } |
501 | 512 | ||
502 | for (sp = &data->ht[h1]; (s = *sp) != NULL; sp = &s->next) { | 513 | for (sp = &data->ht[h1]; |
514 | (s = rtnl_dereference(*sp)) != NULL; | ||
515 | sp = &s->next) { | ||
503 | if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && | 516 | if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && |
504 | pinfo && pinfo->protocol == s->protocol && | 517 | pinfo && pinfo->protocol == s->protocol && |
505 | memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 && | 518 | memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 && |
@@ -521,12 +534,16 @@ insert: | |||
521 | 534 | ||
522 | tcf_exts_change(tp, &f->exts, &e); | 535 | tcf_exts_change(tp, &f->exts, &e); |
523 | 536 | ||
524 | for (fp = &s->ht[h2]; *fp; fp = &(*fp)->next) | 537 | fp = &s->ht[h2]; |
525 | if (((*fp)->spi.mask & f->spi.mask) != f->spi.mask) | 538 | for (nfp = rtnl_dereference(*fp); nfp; |
539 | fp = &nfp->next, nfp = rtnl_dereference(*fp)) { | ||
540 | __u32 mask = nfp->spi.mask & f->spi.mask; | ||
541 | |||
542 | if (mask != f->spi.mask) | ||
526 | break; | 543 | break; |
527 | f->next = *fp; | 544 | } |
528 | wmb(); | 545 | RCU_INIT_POINTER(f->next, nfp); |
529 | *fp = f; | 546 | rcu_assign_pointer(*fp, f); |
530 | 547 | ||
531 | *arg = (unsigned long)f; | 548 | *arg = (unsigned long)f; |
532 | return 0; | 549 | return 0; |
@@ -546,13 +563,14 @@ insert: | |||
546 | s->protocol = pinfo->protocol; | 563 | s->protocol = pinfo->protocol; |
547 | s->tunnelid = pinfo->tunnelid; | 564 | s->tunnelid = pinfo->tunnelid; |
548 | } | 565 | } |
549 | for (sp = &data->ht[h1]; *sp; sp = &(*sp)->next) { | 566 | sp = &data->ht[h1]; |
550 | if (((*sp)->dpi.mask&s->dpi.mask) != s->dpi.mask) | 567 | for (nsp = rtnl_dereference(*sp); nsp; |
568 | sp = &nsp->next, nsp = rtnl_dereference(*sp)) { | ||
569 | if ((nsp->dpi.mask & s->dpi.mask) != s->dpi.mask) | ||
551 | break; | 570 | break; |
552 | } | 571 | } |
553 | s->next = *sp; | 572 | RCU_INIT_POINTER(s->next, nsp); |
554 | wmb(); | 573 | rcu_assign_pointer(*sp, s); |
555 | *sp = s; | ||
556 | 574 | ||
557 | goto insert; | 575 | goto insert; |
558 | 576 | ||
@@ -565,7 +583,7 @@ errout2: | |||
565 | 583 | ||
566 | static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg) | 584 | static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg) |
567 | { | 585 | { |
568 | struct rsvp_head *head = tp->root; | 586 | struct rsvp_head *head = rtnl_dereference(tp->root); |
569 | unsigned int h, h1; | 587 | unsigned int h, h1; |
570 | 588 | ||
571 | if (arg->stop) | 589 | if (arg->stop) |
@@ -574,11 +592,13 @@ static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
574 | for (h = 0; h < 256; h++) { | 592 | for (h = 0; h < 256; h++) { |
575 | struct rsvp_session *s; | 593 | struct rsvp_session *s; |
576 | 594 | ||
577 | for (s = head->ht[h]; s; s = s->next) { | 595 | for (s = rtnl_dereference(head->ht[h]); s; |
596 | s = rtnl_dereference(s->next)) { | ||
578 | for (h1 = 0; h1 <= 16; h1++) { | 597 | for (h1 = 0; h1 <= 16; h1++) { |
579 | struct rsvp_filter *f; | 598 | struct rsvp_filter *f; |
580 | 599 | ||
581 | for (f = s->ht[h1]; f; f = f->next) { | 600 | for (f = rtnl_dereference(s->ht[h1]); f; |
601 | f = rtnl_dereference(f->next)) { | ||
582 | if (arg->count < arg->skip) { | 602 | if (arg->count < arg->skip) { |
583 | arg->count++; | 603 | arg->count++; |
584 | continue; | 604 | continue; |