Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -211,6 +211,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
	struct nlattr *tb[TCA_QFQ_MAX + 1];
	u32 weight, lmax, inv_w;
	int i, err;
	int delta_w;

	if (tca[TCA_OPTIONS] == NULL) {
		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;
	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",
			  weight, q->wsum);
			  delta_w, q->wsum);
		return -EINVAL;
	}

@@ -256,13 +258,12 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
				return err;
		}

		if (inv_w != cl->inv_w) {
			sch_tree_lock(sch);
		if (tb[TCA_QFQ_WEIGHT]) {
			q->wsum = weight - ONE_FP / cl->inv_w;
			q->wsum += delta_w;
			cl->inv_w = inv_w;
		}
			sch_tree_unlock(sch);

		}
		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);

	cl->grp = &q->groups[i];
	q->wsum += weight;

	cl->qdisc = qdisc_create_dflt(sch->dev_queue,
				      &pfifo_qdisc_ops, classid);
@@ -294,6 +294,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
			return err;
		}
	}
	q->wsum += weight;

	sch_tree_lock(sch);
	qdisc_class_hash_insert(&q->clhash, &cl->common);