diff options
author | Paolo Valente <paolo.valente@unimore.it> | 2013-03-05 03:04:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-06 02:47:05 -0500 |
commit | 2f3b89a1fe0823fceb544856c9eeb036a75ff091 (patch) | |
tree | 7f44914069b1af78b69ac40fbf2be6f4fd18429e /net/sched | |
parent | 624b85fb96206879c8146abdba071222bbd25259 (diff) |
pkt_sched: sch_qfq: serve activated aggregates immediately if the scheduler is empty
If no aggregate is in service, then the function qfq_dequeue() does
not dequeue any packet. For this reason, to guarantee QFQ+ to be work
conserving, a just-activated aggregate must be set as in service
immediately if it happens to be the only active aggregate.
This is done by the function qfq_enqueue().
Unfortunately, the function qfq_add_to_agg(), used to add a class to
an aggregate, does not perform this important additional operation.
In particular, if: 1) qfq_add_to_agg() is invoked to complete the move
of a class from a source aggregate, becoming, for this move, inactive,
to a destination aggregate, becoming instead active, and 2) the
destination aggregate becomes the only active aggregate, then this
aggregate is not however set as in service. QFQ+ remains then in a
non-work-conserving state until a new invocation of qfq_enqueue()
recovers the situation.
This fix solves the problem by moving the logic for setting an
aggregate as in service directly into the function qfq_activate_agg().
Hence, from whatever point qfq_activate_aggregate() is invoked, QFQ+
remains work conserving. Since the more-complex logic of this new
version of activate_aggregate() is not necessary, in qfq_dequeue(), to
reschedule an aggregate that finishes its budget, then the aggregate
is now rescheduled by invoking directly the functions needed.
Signed-off-by: Paolo Valente <paolo.valente@unimore.it>
Reviewed-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_qfq.c | 36 |
1 files changed, 22 insertions, 14 deletions
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 39d85cc0db26..8c5172c7f193 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c | |||
@@ -1003,6 +1003,12 @@ static inline void charge_actual_service(struct qfq_aggregate *agg) | |||
1003 | agg->F = agg->S + (u64)service_received * agg->inv_w; | 1003 | agg->F = agg->S + (u64)service_received * agg->inv_w; |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | static inline void qfq_update_agg_ts(struct qfq_sched *q, | ||
1007 | struct qfq_aggregate *agg, | ||
1008 | enum update_reason reason); | ||
1009 | |||
1010 | static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg); | ||
1011 | |||
1006 | static struct sk_buff *qfq_dequeue(struct Qdisc *sch) | 1012 | static struct sk_buff *qfq_dequeue(struct Qdisc *sch) |
1007 | { | 1013 | { |
1008 | struct qfq_sched *q = qdisc_priv(sch); | 1014 | struct qfq_sched *q = qdisc_priv(sch); |
@@ -1030,7 +1036,7 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) | |||
1030 | in_serv_agg->initial_budget = in_serv_agg->budget = | 1036 | in_serv_agg->initial_budget = in_serv_agg->budget = |
1031 | in_serv_agg->budgetmax; | 1037 | in_serv_agg->budgetmax; |
1032 | 1038 | ||
1033 | if (!list_empty(&in_serv_agg->active)) | 1039 | if (!list_empty(&in_serv_agg->active)) { |
1034 | /* | 1040 | /* |
1035 | * Still active: reschedule for | 1041 | * Still active: reschedule for |
1036 | * service. Possible optimization: if no other | 1042 | * service. Possible optimization: if no other |
@@ -1041,8 +1047,9 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) | |||
1041 | * handle it, we would need to maintain an | 1047 | * handle it, we would need to maintain an |
1042 | * extra num_active_aggs field. | 1048 | * extra num_active_aggs field. |
1043 | */ | 1049 | */ |
1044 | qfq_activate_agg(q, in_serv_agg, requeue); | 1050 | qfq_update_agg_ts(q, in_serv_agg, requeue); |
1045 | else if (sch->q.qlen == 0) { /* no aggregate to serve */ | 1051 | qfq_schedule_agg(q, in_serv_agg); |
1052 | } else if (sch->q.qlen == 0) { /* no aggregate to serve */ | ||
1046 | q->in_serv_agg = NULL; | 1053 | q->in_serv_agg = NULL; |
1047 | return NULL; | 1054 | return NULL; |
1048 | } | 1055 | } |
@@ -1226,17 +1233,11 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
1226 | cl->deficit = agg->lmax; | 1233 | cl->deficit = agg->lmax; |
1227 | list_add_tail(&cl->alist, &agg->active); | 1234 | list_add_tail(&cl->alist, &agg->active); |
1228 | 1235 | ||
1229 | if (list_first_entry(&agg->active, struct qfq_class, alist) != cl) | 1236 | if (list_first_entry(&agg->active, struct qfq_class, alist) != cl || |
1230 | return err; /* aggregate was not empty, nothing else to do */ | 1237 | q->in_serv_agg == agg) |
1231 | 1238 | return err; /* non-empty or in service, nothing else to do */ | |
1232 | /* recharge budget */ | ||
1233 | agg->initial_budget = agg->budget = agg->budgetmax; | ||
1234 | 1239 | ||
1235 | qfq_update_agg_ts(q, agg, enqueue); | 1240 | qfq_activate_agg(q, agg, enqueue); |
1236 | if (q->in_serv_agg == NULL) | ||
1237 | q->in_serv_agg = agg; | ||
1238 | else if (agg != q->in_serv_agg) | ||
1239 | qfq_schedule_agg(q, agg); | ||
1240 | 1241 | ||
1241 | return err; | 1242 | return err; |
1242 | } | 1243 | } |
@@ -1293,8 +1294,15 @@ skip_update: | |||
1293 | static void qfq_activate_agg(struct qfq_sched *q, struct qfq_aggregate *agg, | 1294 | static void qfq_activate_agg(struct qfq_sched *q, struct qfq_aggregate *agg, |
1294 | enum update_reason reason) | 1295 | enum update_reason reason) |
1295 | { | 1296 | { |
1297 | agg->initial_budget = agg->budget = agg->budgetmax; /* recharge budg. */ | ||
1298 | |||
1296 | qfq_update_agg_ts(q, agg, reason); | 1299 | qfq_update_agg_ts(q, agg, reason); |
1297 | qfq_schedule_agg(q, agg); | 1300 | if (q->in_serv_agg == NULL) { /* no aggr. in service or scheduled */ |
1301 | q->in_serv_agg = agg; /* start serving this aggregate */ | ||
1302 | /* update V: to be in service, agg must be eligible */ | ||
1303 | q->oldV = q->V = agg->S; | ||
1304 | } else if (agg != q->in_serv_agg) | ||
1305 | qfq_schedule_agg(q, agg); | ||
1298 | } | 1306 | } |
1299 | 1307 | ||
1300 | static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, | 1308 | static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, |