diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_api.c | 11 | ||||
-rw-r--r-- | net/sched/sch_hfsc.c | 6 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 42 | ||||
-rw-r--r-- | net/sched/sch_multiq.c | 2 |
4 files changed, 43 insertions, 18 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 0fc4a18fd96f..32009793307b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -444,6 +444,17 @@ out: | |||
444 | } | 444 | } |
445 | EXPORT_SYMBOL(qdisc_calculate_pkt_len); | 445 | EXPORT_SYMBOL(qdisc_calculate_pkt_len); |
446 | 446 | ||
447 | void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) | ||
448 | { | ||
449 | if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { | ||
450 | printk(KERN_WARNING | ||
451 | "%s: %s qdisc %X: is non-work-conserving?\n", | ||
452 | txt, qdisc->ops->id, qdisc->handle >> 16); | ||
453 | qdisc->flags |= TCQ_F_WARN_NONWC; | ||
454 | } | ||
455 | } | ||
456 | EXPORT_SYMBOL(qdisc_warn_nonwc); | ||
457 | |||
447 | static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) | 458 | static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) |
448 | { | 459 | { |
449 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, | 460 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, |
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 45c31b1a4e1d..74226b265528 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
@@ -887,8 +887,7 @@ qdisc_peek_len(struct Qdisc *sch) | |||
887 | 887 | ||
888 | skb = sch->ops->peek(sch); | 888 | skb = sch->ops->peek(sch); |
889 | if (skb == NULL) { | 889 | if (skb == NULL) { |
890 | if (net_ratelimit()) | 890 | qdisc_warn_nonwc("qdisc_peek_len", sch); |
891 | printk("qdisc_peek_len: non work-conserving qdisc ?\n"); | ||
892 | return 0; | 891 | return 0; |
893 | } | 892 | } |
894 | len = qdisc_pkt_len(skb); | 893 | len = qdisc_pkt_len(skb); |
@@ -1642,8 +1641,7 @@ hfsc_dequeue(struct Qdisc *sch) | |||
1642 | 1641 | ||
1643 | skb = qdisc_dequeue_peeked(cl->qdisc); | 1642 | skb = qdisc_dequeue_peeked(cl->qdisc); |
1644 | if (skb == NULL) { | 1643 | if (skb == NULL) { |
1645 | if (net_ratelimit()) | 1644 | qdisc_warn_nonwc("HFSC", cl->qdisc); |
1646 | printk("HFSC: Non-work-conserving qdisc ?\n"); | ||
1647 | return NULL; | 1645 | return NULL; |
1648 | } | 1646 | } |
1649 | 1647 | ||
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 2f0f0b04d3fb..355974f610c5 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/list.h> | 35 | #include <linux/list.h> |
36 | #include <linux/compiler.h> | 36 | #include <linux/compiler.h> |
37 | #include <linux/rbtree.h> | 37 | #include <linux/rbtree.h> |
38 | #include <linux/workqueue.h> | ||
38 | #include <net/netlink.h> | 39 | #include <net/netlink.h> |
39 | #include <net/pkt_sched.h> | 40 | #include <net/pkt_sched.h> |
40 | 41 | ||
@@ -114,8 +115,6 @@ struct htb_class { | |||
114 | struct tcf_proto *filter_list; | 115 | struct tcf_proto *filter_list; |
115 | int filter_cnt; | 116 | int filter_cnt; |
116 | 117 | ||
117 | int warned; /* only one warning about non work conserving .. */ | ||
118 | |||
119 | /* token bucket parameters */ | 118 | /* token bucket parameters */ |
120 | struct qdisc_rate_table *rate; /* rate table of the class itself */ | 119 | struct qdisc_rate_table *rate; /* rate table of the class itself */ |
121 | struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */ | 120 | struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */ |
@@ -155,6 +154,10 @@ struct htb_sched { | |||
155 | int direct_qlen; /* max qlen of above */ | 154 | int direct_qlen; /* max qlen of above */ |
156 | 155 | ||
157 | long direct_pkts; | 156 | long direct_pkts; |
157 | |||
158 | #define HTB_WARN_TOOMANYEVENTS 0x1 | ||
159 | unsigned int warned; /* only one warning */ | ||
160 | struct work_struct work; | ||
158 | }; | 161 | }; |
159 | 162 | ||
160 | /* find class in global hash table using given handle */ | 163 | /* find class in global hash table using given handle */ |
@@ -658,7 +661,7 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, | |||
658 | * htb_do_events - make mode changes to classes at the level | 661 | * htb_do_events - make mode changes to classes at the level |
659 | * | 662 | * |
660 | * Scans event queue for pending events and applies them. Returns time of | 663 | * Scans event queue for pending events and applies them. Returns time of |
661 | * next pending event (0 for no event in pq). | 664 | * next pending event (0 for no event in pq, q->now for too many events). |
662 | * Note: Applied are events whose have cl->pq_key <= q->now. | 665 | * Note: Applied are events whose have cl->pq_key <= q->now. |
663 | */ | 666 | */ |
664 | static psched_time_t htb_do_events(struct htb_sched *q, int level, | 667 | static psched_time_t htb_do_events(struct htb_sched *q, int level, |
@@ -686,8 +689,14 @@ static psched_time_t htb_do_events(struct htb_sched *q, int level, | |||
686 | if (cl->cmode != HTB_CAN_SEND) | 689 | if (cl->cmode != HTB_CAN_SEND) |
687 | htb_add_to_wait_tree(q, cl, diff); | 690 | htb_add_to_wait_tree(q, cl, diff); |
688 | } | 691 | } |
689 | /* too much load - let's continue on next jiffie (including above) */ | 692 | |
690 | return q->now + 2 * PSCHED_TICKS_PER_SEC / HZ; | 693 | /* too much load - let's continue after a break for scheduling */ |
694 | if (!(q->warned & HTB_WARN_TOOMANYEVENTS)) { | ||
695 | printk(KERN_WARNING "htb: too many events!\n"); | ||
696 | q->warned |= HTB_WARN_TOOMANYEVENTS; | ||
697 | } | ||
698 | |||
699 | return q->now; | ||
691 | } | 700 | } |
692 | 701 | ||
693 | /* Returns class->node+prio from id-tree where classe's id is >= id. NULL | 702 | /* Returns class->node+prio from id-tree where classe's id is >= id. NULL |
@@ -809,13 +818,8 @@ next: | |||
809 | skb = cl->un.leaf.q->dequeue(cl->un.leaf.q); | 818 | skb = cl->un.leaf.q->dequeue(cl->un.leaf.q); |
810 | if (likely(skb != NULL)) | 819 | if (likely(skb != NULL)) |
811 | break; | 820 | break; |
812 | if (!cl->warned) { | ||
813 | printk(KERN_WARNING | ||
814 | "htb: class %X isn't work conserving ?!\n", | ||
815 | cl->common.classid); | ||
816 | cl->warned = 1; | ||
817 | } | ||
818 | 821 | ||
822 | qdisc_warn_nonwc("htb", cl->un.leaf.q); | ||
819 | htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> | 823 | htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> |
820 | ptr[0]) + prio); | 824 | ptr[0]) + prio); |
821 | cl = htb_lookup_leaf(q->row[level] + prio, prio, | 825 | cl = htb_lookup_leaf(q->row[level] + prio, prio, |
@@ -892,7 +896,10 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) | |||
892 | } | 896 | } |
893 | } | 897 | } |
894 | sch->qstats.overlimits++; | 898 | sch->qstats.overlimits++; |
895 | qdisc_watchdog_schedule(&q->watchdog, next_event); | 899 | if (likely(next_event > q->now)) |
900 | qdisc_watchdog_schedule(&q->watchdog, next_event); | ||
901 | else | ||
902 | schedule_work(&q->work); | ||
896 | fin: | 903 | fin: |
897 | return skb; | 904 | return skb; |
898 | } | 905 | } |
@@ -962,6 +969,14 @@ static const struct nla_policy htb_policy[TCA_HTB_MAX + 1] = { | |||
962 | [TCA_HTB_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, | 969 | [TCA_HTB_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE }, |
963 | }; | 970 | }; |
964 | 971 | ||
972 | static void htb_work_func(struct work_struct *work) | ||
973 | { | ||
974 | struct htb_sched *q = container_of(work, struct htb_sched, work); | ||
975 | struct Qdisc *sch = q->watchdog.qdisc; | ||
976 | |||
977 | __netif_schedule(qdisc_root(sch)); | ||
978 | } | ||
979 | |||
965 | static int htb_init(struct Qdisc *sch, struct nlattr *opt) | 980 | static int htb_init(struct Qdisc *sch, struct nlattr *opt) |
966 | { | 981 | { |
967 | struct htb_sched *q = qdisc_priv(sch); | 982 | struct htb_sched *q = qdisc_priv(sch); |
@@ -996,6 +1011,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) | |||
996 | INIT_LIST_HEAD(q->drops + i); | 1011 | INIT_LIST_HEAD(q->drops + i); |
997 | 1012 | ||
998 | qdisc_watchdog_init(&q->watchdog, sch); | 1013 | qdisc_watchdog_init(&q->watchdog, sch); |
1014 | INIT_WORK(&q->work, htb_work_func); | ||
999 | skb_queue_head_init(&q->direct_queue); | 1015 | skb_queue_head_init(&q->direct_queue); |
1000 | 1016 | ||
1001 | q->direct_qlen = qdisc_dev(sch)->tx_queue_len; | 1017 | q->direct_qlen = qdisc_dev(sch)->tx_queue_len; |
@@ -1188,7 +1204,6 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) | |||
1188 | kfree(cl); | 1204 | kfree(cl); |
1189 | } | 1205 | } |
1190 | 1206 | ||
1191 | /* always caled under BH & queue lock */ | ||
1192 | static void htb_destroy(struct Qdisc *sch) | 1207 | static void htb_destroy(struct Qdisc *sch) |
1193 | { | 1208 | { |
1194 | struct htb_sched *q = qdisc_priv(sch); | 1209 | struct htb_sched *q = qdisc_priv(sch); |
@@ -1196,6 +1211,7 @@ static void htb_destroy(struct Qdisc *sch) | |||
1196 | struct htb_class *cl; | 1211 | struct htb_class *cl; |
1197 | unsigned int i; | 1212 | unsigned int i; |
1198 | 1213 | ||
1214 | cancel_work_sync(&q->work); | ||
1199 | qdisc_watchdog_cancel(&q->watchdog); | 1215 | qdisc_watchdog_cancel(&q->watchdog); |
1200 | /* This line used to be after htb_destroy_class call below | 1216 | /* This line used to be after htb_destroy_class call below |
1201 | and surprisingly it worked in 2.4. But it must precede it | 1217 | and surprisingly it worked in 2.4. But it must precede it |
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 7e151861794b..912731203047 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c | |||
@@ -202,7 +202,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
202 | int i; | 202 | int i; |
203 | 203 | ||
204 | if (!netif_is_multiqueue(qdisc_dev(sch))) | 204 | if (!netif_is_multiqueue(qdisc_dev(sch))) |
205 | return -EINVAL; | 205 | return -EOPNOTSUPP; |
206 | if (nla_len(opt) < sizeof(*qopt)) | 206 | if (nla_len(opt) < sizeof(*qopt)) |
207 | return -EINVAL; | 207 | return -EINVAL; |
208 | 208 | ||