diff options
author | Vasily Averin <vvs@parallels.com> | 2014-08-14 04:27:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-19 13:58:44 -0400 |
commit | 73d0f37ac4ee5b60e6b9c1b3ccb8766bade9d9c5 (patch) | |
tree | adaf72c8208c62eed0d4e6a74983cb8f6741ab03 /net/sched/sch_cbq.c | |
parent | ac32c7f705692b92fe12dcbe88fe87136fdfff6f (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.c | 37 |
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 (;;) { |