aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorJohn Fastabend <john.fastabend@gmail.com>2014-09-12 23:09:49 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-13 12:30:26 -0400
commitb929d86d25352496c528fcd74fdcabe3f6a4994a (patch)
tree6536ad5e227b16b6e9d7090a928b87eab38246a1 /net/sched
parent1ce87720d456e471de0fbd814dc5d1fe10fc1c44 (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.h160
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
76struct rsvp_session { 77struct 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
87struct rsvp_filter { 89struct 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
100static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) 103static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
@@ -128,7 +131,7 @@ static inline unsigned int hash_src(__be32 *src)
128static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp, 131static 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
219static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) 225static 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
263static void rsvp_destroy(struct tcf_proto *tp) 271static 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
294static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) 301static 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
334static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt) 341static 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
362static void tunnel_recycle(struct rsvp_head *data) 369static 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
566static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg) 584static 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;