aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sched/sch_atm.c98
1 files changed, 41 insertions, 57 deletions
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index fcbb86a486a2..e114f23d5eae 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -52,7 +52,7 @@ struct atm_flow_data {
52 int ref; /* reference count */ 52 int ref; /* reference count */
53 struct gnet_stats_basic_packed bstats; 53 struct gnet_stats_basic_packed bstats;
54 struct gnet_stats_queue qstats; 54 struct gnet_stats_queue qstats;
55 struct atm_flow_data *next; 55 struct list_head list;
56 struct atm_flow_data *excess; /* flow for excess traffic; 56 struct atm_flow_data *excess; /* flow for excess traffic;
57 NULL to set CLP instead */ 57 NULL to set CLP instead */
58 int hdr_len; 58 int hdr_len;
@@ -61,34 +61,23 @@ struct atm_flow_data {
61 61
62struct atm_qdisc_data { 62struct atm_qdisc_data {
63 struct atm_flow_data link; /* unclassified skbs go here */ 63 struct atm_flow_data link; /* unclassified skbs go here */
64 struct atm_flow_data *flows; /* NB: "link" is also on this 64 struct list_head flows; /* NB: "link" is also on this
65 list */ 65 list */
66 struct tasklet_struct task; /* dequeue tasklet */ 66 struct tasklet_struct task; /* dequeue tasklet */
67}; 67};
68 68
69/* ------------------------- Class/flow operations ------------------------- */ 69/* ------------------------- Class/flow operations ------------------------- */
70 70
71static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow)
72{
73 struct atm_flow_data *walk;
74
75 pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
76 for (walk = qdisc->flows; walk; walk = walk->next)
77 if (walk == flow)
78 return 1;
79 pr_debug("find_flow: not found\n");
80 return 0;
81}
82
83static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) 71static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
84{ 72{
85 struct atm_qdisc_data *p = qdisc_priv(sch); 73 struct atm_qdisc_data *p = qdisc_priv(sch);
86 struct atm_flow_data *flow; 74 struct atm_flow_data *flow;
87 75
88 for (flow = p->flows; flow; flow = flow->next) 76 list_for_each_entry(flow, &p->flows, list) {
89 if (flow->classid == classid) 77 if (flow->classid == classid)
90 break; 78 return flow;
91 return flow; 79 }
80 return NULL;
92} 81}
93 82
94static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, 83static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
@@ -99,7 +88,7 @@ static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
99 88
100 pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", 89 pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
101 sch, p, flow, new, old); 90 sch, p, flow, new, old);
102 if (!find_flow(p, flow)) 91 if (list_empty(&flow->list))
103 return -EINVAL; 92 return -EINVAL;
104 if (!new) 93 if (!new)
105 new = &noop_qdisc; 94 new = &noop_qdisc;
@@ -146,20 +135,12 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
146{ 135{
147 struct atm_qdisc_data *p = qdisc_priv(sch); 136 struct atm_qdisc_data *p = qdisc_priv(sch);
148 struct atm_flow_data *flow = (struct atm_flow_data *)cl; 137 struct atm_flow_data *flow = (struct atm_flow_data *)cl;
149 struct atm_flow_data **prev;
150 138
151 pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); 139 pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
152 if (--flow->ref) 140 if (--flow->ref)
153 return; 141 return;
154 pr_debug("atm_tc_put: destroying\n"); 142 pr_debug("atm_tc_put: destroying\n");
155 for (prev = &p->flows; *prev; prev = &(*prev)->next) 143 list_del_init(&flow->list);
156 if (*prev == flow)
157 break;
158 if (!*prev) {
159 printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow);
160 return;
161 }
162 *prev = flow->next;
163 pr_debug("atm_tc_put: qdisc %p\n", flow->q); 144 pr_debug("atm_tc_put: qdisc %p\n", flow->q);
164 qdisc_destroy(flow->q); 145 qdisc_destroy(flow->q);
165 tcf_destroy_chain(&flow->filter_list); 146 tcf_destroy_chain(&flow->filter_list);
@@ -274,7 +255,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
274 error = -EINVAL; 255 error = -EINVAL;
275 goto err_out; 256 goto err_out;
276 } 257 }
277 if (find_flow(p, flow)) { 258 if (!list_empty(&flow->list)) {
278 error = -EEXIST; 259 error = -EEXIST;
279 goto err_out; 260 goto err_out;
280 } 261 }
@@ -313,8 +294,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
313 flow->classid = classid; 294 flow->classid = classid;
314 flow->ref = 1; 295 flow->ref = 1;
315 flow->excess = excess; 296 flow->excess = excess;
316 flow->next = p->link.next; 297 list_add(&flow->list, &p->link.list);
317 p->link.next = flow;
318 flow->hdr_len = hdr_len; 298 flow->hdr_len = hdr_len;
319 if (hdr) 299 if (hdr)
320 memcpy(flow->hdr, hdr, hdr_len); 300 memcpy(flow->hdr, hdr, hdr_len);
@@ -335,7 +315,7 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
335 struct atm_flow_data *flow = (struct atm_flow_data *)arg; 315 struct atm_flow_data *flow = (struct atm_flow_data *)arg;
336 316
337 pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); 317 pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
338 if (!find_flow(qdisc_priv(sch), flow)) 318 if (list_empty(&flow->list))
339 return -EINVAL; 319 return -EINVAL;
340 if (flow->filter_list || flow == &p->link) 320 if (flow->filter_list || flow == &p->link)
341 return -EBUSY; 321 return -EBUSY;
@@ -361,12 +341,12 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
361 pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); 341 pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
362 if (walker->stop) 342 if (walker->stop)
363 return; 343 return;
364 for (flow = p->flows; flow; flow = flow->next) { 344 list_for_each_entry(flow, &p->flows, list) {
365 if (walker->count >= walker->skip) 345 if (walker->count >= walker->skip &&
366 if (walker->fn(sch, (unsigned long)flow, walker) < 0) { 346 walker->fn(sch, (unsigned long)flow, walker) < 0) {
367 walker->stop = 1; 347 walker->stop = 1;
368 break; 348 break;
369 } 349 }
370 walker->count++; 350 walker->count++;
371 } 351 }
372} 352}
@@ -385,16 +365,17 @@ static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl)
385static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) 365static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
386{ 366{
387 struct atm_qdisc_data *p = qdisc_priv(sch); 367 struct atm_qdisc_data *p = qdisc_priv(sch);
388 struct atm_flow_data *flow = NULL; /* @@@ */ 368 struct atm_flow_data *flow;
389 struct tcf_result res; 369 struct tcf_result res;
390 int result; 370 int result;
391 int ret = NET_XMIT_POLICED; 371 int ret = NET_XMIT_POLICED;
392 372
393 pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); 373 pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
394 result = TC_POLICE_OK; /* be nice to gcc */ 374 result = TC_POLICE_OK; /* be nice to gcc */
375 flow = NULL;
395 if (TC_H_MAJ(skb->priority) != sch->handle || 376 if (TC_H_MAJ(skb->priority) != sch->handle ||
396 !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) 377 !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) {
397 for (flow = p->flows; flow; flow = flow->next) 378 list_for_each_entry(flow, &p->flows, list) {
398 if (flow->filter_list) { 379 if (flow->filter_list) {
399 result = tc_classify_compat(skb, 380 result = tc_classify_compat(skb,
400 flow->filter_list, 381 flow->filter_list,
@@ -404,8 +385,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
404 flow = (struct atm_flow_data *)res.class; 385 flow = (struct atm_flow_data *)res.class;
405 if (!flow) 386 if (!flow)
406 flow = lookup_flow(sch, res.classid); 387 flow = lookup_flow(sch, res.classid);
407 break; 388 goto done;
408 } 389 }
390 }
391 flow = NULL;
392 done:
393 ;
394 }
409 if (!flow) 395 if (!flow)
410 flow = &p->link; 396 flow = &p->link;
411 else { 397 else {
@@ -477,7 +463,9 @@ static void sch_atm_dequeue(unsigned long data)
477 struct sk_buff *skb; 463 struct sk_buff *skb;
478 464
479 pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); 465 pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
480 for (flow = p->link.next; flow; flow = flow->next) 466 list_for_each_entry(flow, &p->flows, list) {
467 if (flow == &p->link)
468 continue;
481 /* 469 /*
482 * If traffic is properly shaped, this won't generate nasty 470 * If traffic is properly shaped, this won't generate nasty
483 * little bursts. Otherwise, it may ... (but that's okay) 471 * little bursts. Otherwise, it may ... (but that's okay)
@@ -512,6 +500,7 @@ static void sch_atm_dequeue(unsigned long data)
512 /* atm.atm_options are already set by atm_tc_enqueue */ 500 /* atm.atm_options are already set by atm_tc_enqueue */
513 flow->vcc->send(flow->vcc, skb); 501 flow->vcc->send(flow->vcc, skb);
514 } 502 }
503 }
515} 504}
516 505
517static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) 506static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
@@ -543,9 +532,10 @@ static unsigned int atm_tc_drop(struct Qdisc *sch)
543 unsigned int len; 532 unsigned int len;
544 533
545 pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); 534 pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
546 for (flow = p->flows; flow; flow = flow->next) 535 list_for_each_entry(flow, &p->flows, list) {
547 if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) 536 if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
548 return len; 537 return len;
538 }
549 return 0; 539 return 0;
550} 540}
551 541
@@ -554,7 +544,9 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
554 struct atm_qdisc_data *p = qdisc_priv(sch); 544 struct atm_qdisc_data *p = qdisc_priv(sch);
555 545
556 pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); 546 pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
557 p->flows = &p->link; 547 INIT_LIST_HEAD(&p->flows);
548 INIT_LIST_HEAD(&p->link.list);
549 list_add(&p->link.list, &p->flows);
558 p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, 550 p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
559 &pfifo_qdisc_ops, sch->handle); 551 &pfifo_qdisc_ops, sch->handle);
560 if (!p->link.q) 552 if (!p->link.q)
@@ -565,7 +557,6 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
565 p->link.sock = NULL; 557 p->link.sock = NULL;
566 p->link.classid = sch->handle; 558 p->link.classid = sch->handle;
567 p->link.ref = 1; 559 p->link.ref = 1;
568 p->link.next = NULL;
569 tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch); 560 tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
570 return 0; 561 return 0;
571} 562}
@@ -576,7 +567,7 @@ static void atm_tc_reset(struct Qdisc *sch)
576 struct atm_flow_data *flow; 567 struct atm_flow_data *flow;
577 568
578 pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); 569 pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
579 for (flow = p->flows; flow; flow = flow->next) 570 list_for_each_entry(flow, &p->flows, list)
580 qdisc_reset(flow->q); 571 qdisc_reset(flow->q);
581 sch->q.qlen = 0; 572 sch->q.qlen = 0;
582} 573}
@@ -584,24 +575,17 @@ static void atm_tc_reset(struct Qdisc *sch)
584static void atm_tc_destroy(struct Qdisc *sch) 575static void atm_tc_destroy(struct Qdisc *sch)
585{ 576{
586 struct atm_qdisc_data *p = qdisc_priv(sch); 577 struct atm_qdisc_data *p = qdisc_priv(sch);
587 struct atm_flow_data *flow; 578 struct atm_flow_data *flow, *tmp;
588 579
589 pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); 580 pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
590 for (flow = p->flows; flow; flow = flow->next) 581 list_for_each_entry(flow, &p->flows, list)
591 tcf_destroy_chain(&flow->filter_list); 582 tcf_destroy_chain(&flow->filter_list);
592 583
593 /* races ? */ 584 list_for_each_entry_safe(flow, tmp, &p->flows, list) {
594 while ((flow = p->flows)) {
595 if (flow->ref > 1) 585 if (flow->ref > 1)
596 printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow, 586 printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
597 flow->ref); 587 flow->ref);
598 atm_tc_put(sch, (unsigned long)flow); 588 atm_tc_put(sch, (unsigned long)flow);
599 if (p->flows == flow) {
600 printk(KERN_ERR "atm_destroy: putting flow %p didn't "
601 "kill it\n", flow);
602 p->flows = flow->next; /* brute force */
603 break;
604 }
605 } 589 }
606 tasklet_kill(&p->task); 590 tasklet_kill(&p->task);
607} 591}
@@ -615,7 +599,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
615 599
616 pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", 600 pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
617 sch, p, flow, skb, tcm); 601 sch, p, flow, skb, tcm);
618 if (!find_flow(p, flow)) 602 if (list_empty(&flow->list))
619 return -EINVAL; 603 return -EINVAL;
620 tcm->tcm_handle = flow->classid; 604 tcm->tcm_handle = flow->classid;
621 tcm->tcm_info = flow->q->handle; 605 tcm->tcm_info = flow->q->handle;