Commit d32ae76f authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
CC: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d47a0ac7
...@@ -211,6 +211,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -211,6 +211,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
struct nlattr *tb[TCA_QFQ_MAX + 1]; struct nlattr *tb[TCA_QFQ_MAX + 1];
u32 weight, lmax, inv_w; u32 weight, lmax, inv_w;
int i, err; int i, err;
int delta_w;
if (tca[TCA_OPTIONS] == NULL) { if (tca[TCA_OPTIONS] == NULL) {
pr_notice("qfq: no options\n"); pr_notice("qfq: no options\n");
...@@ -232,9 +233,10 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -232,9 +233,10 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
inv_w = ONE_FP / weight; inv_w = ONE_FP / weight;
weight = ONE_FP / inv_w; weight = ONE_FP / inv_w;
if (q->wsum + weight > QFQ_MAX_WSUM) { delta_w = weight - (cl ? ONE_FP / cl->inv_w : 0);
if (q->wsum + delta_w > QFQ_MAX_WSUM) {
pr_notice("qfq: total weight out of range (%u + %u)\n", pr_notice("qfq: total weight out of range (%u + %u)\n",
weight, q->wsum); delta_w, q->wsum);
return -EINVAL; return -EINVAL;
} }
...@@ -256,13 +258,12 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -256,13 +258,12 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
return err; return err;
} }
sch_tree_lock(sch); if (inv_w != cl->inv_w) {
if (tb[TCA_QFQ_WEIGHT]) { sch_tree_lock(sch);
q->wsum = weight - ONE_FP / cl->inv_w; q->wsum += delta_w;
cl->inv_w = inv_w; cl->inv_w = inv_w;
sch_tree_unlock(sch);
} }
sch_tree_unlock(sch);
return 0; return 0;
} }
...@@ -277,7 +278,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -277,7 +278,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
i = qfq_calc_index(cl->inv_w, cl->lmax); i = qfq_calc_index(cl->inv_w, cl->lmax);
cl->grp = &q->groups[i]; cl->grp = &q->groups[i];
q->wsum += weight;
cl->qdisc = qdisc_create_dflt(sch->dev_queue, cl->qdisc = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, classid); &pfifo_qdisc_ops, classid);
...@@ -294,6 +294,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -294,6 +294,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
return err; return err;
} }
} }
q->wsum += weight;
sch_tree_lock(sch); sch_tree_lock(sch);
qdisc_class_hash_insert(&q->clhash, &cl->common); qdisc_class_hash_insert(&q->clhash, &cl->common);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment