aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@unimore.it>2013-03-05 03:04:59 -0500
committerDavid S. Miller <davem@davemloft.net>2013-03-06 02:47:05 -0500
commit2f3b89a1fe0823fceb544856c9eeb036a75ff091 (patch)
tree7f44914069b1af78b69ac40fbf2be6f4fd18429e /net/sched
parent624b85fb96206879c8146abdba071222bbd25259 (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.c36
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
1006static inline void qfq_update_agg_ts(struct qfq_sched *q,
1007 struct qfq_aggregate *agg,
1008 enum update_reason reason);
1009
1010static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg);
1011
1006static struct sk_buff *qfq_dequeue(struct Qdisc *sch) 1012static 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:
1293static void qfq_activate_agg(struct qfq_sched *q, struct qfq_aggregate *agg, 1294static 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
1300static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, 1308static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp,