diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-01-02 06:47:50 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-01-03 13:02:19 -0500 |
commit | d32ae76f2b776347051cf821ebe690602e38dfc7 (patch) | |
tree | 3f17a0c00e2ac7cc982c47e442661517ae010d5c /net/sched | |
parent | d47a0ac7b66883987275598d6039f902f4410ca9 (diff) |
sch_qfq: accurate wsum handling
We can underestimate q->wsum in case of "tc class replace ... qfq"
and/or qdisc_create_dflt() error.
wsum is not really used in fast path, only at qfq qdisc/class setup,
to catch user error.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_qfq.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 103343408593..2c5ff6148589 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c | |||
@@ -211,6 +211,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
211 | struct nlattr *tb[TCA_QFQ_MAX + 1]; | 211 | struct nlattr *tb[TCA_QFQ_MAX + 1]; |
212 | u32 weight, lmax, inv_w; | 212 | u32 weight, lmax, inv_w; |
213 | int i, err; | 213 | int i, err; |
214 | int delta_w; | ||
214 | 215 | ||
215 | if (tca[TCA_OPTIONS] == NULL) { | 216 | if (tca[TCA_OPTIONS] == NULL) { |
216 | pr_notice("qfq: no options\n"); | 217 | pr_notice("qfq: no options\n"); |
@@ -232,9 +233,10 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
232 | 233 | ||
233 | inv_w = ONE_FP / weight; | 234 | inv_w = ONE_FP / weight; |
234 | weight = ONE_FP / inv_w; | 235 | weight = ONE_FP / inv_w; |
235 | if (q->wsum + weight > QFQ_MAX_WSUM) { | 236 | delta_w = weight - (cl ? ONE_FP / cl->inv_w : 0); |
237 | if (q->wsum + delta_w > QFQ_MAX_WSUM) { | ||
236 | pr_notice("qfq: total weight out of range (%u + %u)\n", | 238 | pr_notice("qfq: total weight out of range (%u + %u)\n", |
237 | weight, q->wsum); | 239 | delta_w, q->wsum); |
238 | return -EINVAL; | 240 | return -EINVAL; |
239 | } | 241 | } |
240 | 242 | ||
@@ -256,13 +258,12 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
256 | return err; | 258 | return err; |
257 | } | 259 | } |
258 | 260 | ||
259 | sch_tree_lock(sch); | 261 | if (inv_w != cl->inv_w) { |
260 | if (tb[TCA_QFQ_WEIGHT]) { | 262 | sch_tree_lock(sch); |
261 | q->wsum = weight - ONE_FP / cl->inv_w; | 263 | q->wsum += delta_w; |
262 | cl->inv_w = inv_w; | 264 | cl->inv_w = inv_w; |
265 | sch_tree_unlock(sch); | ||
263 | } | 266 | } |
264 | sch_tree_unlock(sch); | ||
265 | |||
266 | return 0; | 267 | return 0; |
267 | } | 268 | } |
268 | 269 | ||
@@ -277,7 +278,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
277 | i = qfq_calc_index(cl->inv_w, cl->lmax); | 278 | i = qfq_calc_index(cl->inv_w, cl->lmax); |
278 | 279 | ||
279 | cl->grp = &q->groups[i]; | 280 | cl->grp = &q->groups[i]; |
280 | q->wsum += weight; | ||
281 | 281 | ||
282 | cl->qdisc = qdisc_create_dflt(sch->dev_queue, | 282 | cl->qdisc = qdisc_create_dflt(sch->dev_queue, |
283 | &pfifo_qdisc_ops, classid); | 283 | &pfifo_qdisc_ops, classid); |
@@ -294,6 +294,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
294 | return err; | 294 | return err; |
295 | } | 295 | } |
296 | } | 296 | } |
297 | q->wsum += weight; | ||
297 | 298 | ||
298 | sch_tree_lock(sch); | 299 | sch_tree_lock(sch); |
299 | qdisc_class_hash_insert(&q->clhash, &cl->common); | 300 | qdisc_class_hash_insert(&q->clhash, &cl->common); |