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>
This commit is contained in:
parent
d47a0ac7b6
commit
d32ae76f2b
|
@ -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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue