aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_cbq.c
diff options
context:
space:
mode:
authorVasily Averin <vvs@parallels.com>2014-08-14 04:27:47 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-19 13:58:44 -0400
commit73d0f37ac4ee5b60e6b9c1b3ccb8766bade9d9c5 (patch)
treeadaf72c8208c62eed0d4e6a74983cb8f6741ab03 /net/sched/sch_cbq.c
parentac32c7f705692b92fe12dcbe88fe87136fdfff6f (diff)
cbq: incorrectly low bandwidth setting blocks limited traffic
Mainstream commit f0f6ee1f70c4 ("cbq: incorrect processing of high limits") have side effect: if cbq bandwidth setting is less than real interface throughput non-limited traffic can delay limited traffic for a very long time. This happen because of q->now changes incorrectly in cbq_dequeue(): in described scenario L2T is much greater than real time delay, and q->now gets an extra boost for each transmitted packet. Accumulated boost prevents update q->now, and blocked class can wait very long time until (q->now >= cl->undertime) will be true again. To fix the problem the patch updates q->now on each cbq_update() call. L2T-related pre-modification q->now was moved to cbq_update(). My testing confirmed that it fixes the problem and did not discover any side-effects Fixes: f0f6ee1f70c4 ("cbq: incorrect processing of high limits") Signed-off-by: Vasily Averin <vvs@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_cbq.c')
-rw-r--r--net/sched/sch_cbq.c37
1 files changed, 13 insertions, 24 deletions
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index ead526467cca..550be9504fff 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -700,8 +700,13 @@ cbq_update(struct cbq_sched_data *q)
700 struct cbq_class *this = q->tx_class; 700 struct cbq_class *this = q->tx_class;
701 struct cbq_class *cl = this; 701 struct cbq_class *cl = this;
702 int len = q->tx_len; 702 int len = q->tx_len;
703 psched_time_t now;
703 704
704 q->tx_class = NULL; 705 q->tx_class = NULL;
706 /* Time integrator. We calculate EOS time
707 * by adding expected packet transmission time.
708 */
709 now = q->now + L2T(&q->link, len);
705 710
706 for ( ; cl; cl = cl->share) { 711 for ( ; cl; cl = cl->share) {
707 long avgidle = cl->avgidle; 712 long avgidle = cl->avgidle;
@@ -717,7 +722,7 @@ cbq_update(struct cbq_sched_data *q)
717 * idle = (now - last) - last_pktlen/rate 722 * idle = (now - last) - last_pktlen/rate
718 */ 723 */
719 724
720 idle = q->now - cl->last; 725 idle = now - cl->last;
721 if ((unsigned long)idle > 128*1024*1024) { 726 if ((unsigned long)idle > 128*1024*1024) {
722 avgidle = cl->maxidle; 727 avgidle = cl->maxidle;
723 } else { 728 } else {
@@ -761,7 +766,7 @@ cbq_update(struct cbq_sched_data *q)
761 idle -= L2T(&q->link, len); 766 idle -= L2T(&q->link, len);
762 idle += L2T(cl, len); 767 idle += L2T(cl, len);
763 768
764 cl->undertime = q->now + idle; 769 cl->undertime = now + idle;
765 } else { 770 } else {
766 /* Underlimit */ 771 /* Underlimit */
767 772
@@ -771,7 +776,8 @@ cbq_update(struct cbq_sched_data *q)
771 else 776 else
772 cl->avgidle = avgidle; 777 cl->avgidle = avgidle;
773 } 778 }
774 cl->last = q->now; 779 if ((s64)(now - cl->last) > 0)
780 cl->last = now;
775 } 781 }
776 782
777 cbq_update_toplevel(q, this, q->tx_borrowed); 783 cbq_update_toplevel(q, this, q->tx_borrowed);
@@ -943,30 +949,13 @@ cbq_dequeue(struct Qdisc *sch)
943 struct sk_buff *skb; 949 struct sk_buff *skb;
944 struct cbq_sched_data *q = qdisc_priv(sch); 950 struct cbq_sched_data *q = qdisc_priv(sch);
945 psched_time_t now; 951 psched_time_t now;
946 psched_tdiff_t incr;
947 952
948 now = psched_get_time(); 953 now = psched_get_time();
949 incr = now - q->now_rt; 954
950 955 if (q->tx_class)
951 if (q->tx_class) {
952 psched_tdiff_t incr2;
953 /* Time integrator. We calculate EOS time
954 * by adding expected packet transmission time.
955 * If real time is greater, we warp artificial clock,
956 * so that:
957 *
958 * cbq_time = max(real_time, work);
959 */
960 incr2 = L2T(&q->link, q->tx_len);
961 q->now += incr2;
962 cbq_update(q); 956 cbq_update(q);
963 if ((incr -= incr2) < 0) 957
964 incr = 0; 958 q->now = now;
965 q->now += incr;
966 } else {
967 if (now > q->now)
968 q->now = now;
969 }
970 q->now_rt = now; 959 q->now_rt = now;
971 960
972 for (;;) { 961 for (;;) {