diff options
Diffstat (limited to 'net/sched/sch_qfq.c')
-rw-r--r-- | net/sched/sch_qfq.c | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 103343408593..e68cb440756a 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, 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; } - sch_tree_lock(sch); - if (tb[TCA_QFQ_WEIGHT]) { - q->wsum = weight - ONE_FP / cl->inv_w; + if (inv_w != cl->inv_w) { + sch_tree_lock(sch); + q->wsum += delta_w; cl->inv_w = inv_w; + sch_tree_unlock(sch); } - 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); @@ -817,11 +818,11 @@ skip_unblock: static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl) { unsigned long mask; - uint32_t limit, roundedF; + u64 limit, roundedF; int slot_shift = cl->grp->slot_shift; roundedF = qfq_round_down(cl->F, slot_shift); - limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift); + limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift); if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) { /* timestamp was stale */ |