diff options
| -rw-r--r-- | net/sched/sch_qfq.c | 118 |
1 files changed, 55 insertions, 63 deletions
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 8d86a8b5522a..a7ab323849b6 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c | |||
| @@ -1010,9 +1010,61 @@ static inline void charge_actual_service(struct qfq_aggregate *agg) | |||
| 1010 | agg->F = agg->S + (u64)service_received * agg->inv_w; | 1010 | agg->F = agg->S + (u64)service_received * agg->inv_w; |
| 1011 | } | 1011 | } |
| 1012 | 1012 | ||
| 1013 | static inline void qfq_update_agg_ts(struct qfq_sched *q, | 1013 | /* Assign a reasonable start time for a new aggregate in group i. |
| 1014 | struct qfq_aggregate *agg, | 1014 | * Admissible values for \hat(F) are multiples of \sigma_i |
| 1015 | enum update_reason reason); | 1015 | * no greater than V+\sigma_i . Larger values mean that |
| 1016 | * we had a wraparound so we consider the timestamp to be stale. | ||
| 1017 | * | ||
| 1018 | * If F is not stale and F >= V then we set S = F. | ||
| 1019 | * Otherwise we should assign S = V, but this may violate | ||
| 1020 | * the ordering in EB (see [2]). So, if we have groups in ER, | ||
| 1021 | * set S to the F_j of the first group j which would be blocking us. | ||
| 1022 | * We are guaranteed not to move S backward because | ||
| 1023 | * otherwise our group i would still be blocked. | ||
| 1024 | */ | ||
| 1025 | static void qfq_update_start(struct qfq_sched *q, struct qfq_aggregate *agg) | ||
| 1026 | { | ||
| 1027 | unsigned long mask; | ||
| 1028 | u64 limit, roundedF; | ||
| 1029 | int slot_shift = agg->grp->slot_shift; | ||
| 1030 | |||
| 1031 | roundedF = qfq_round_down(agg->F, slot_shift); | ||
| 1032 | limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift); | ||
| 1033 | |||
| 1034 | if (!qfq_gt(agg->F, q->V) || qfq_gt(roundedF, limit)) { | ||
| 1035 | /* timestamp was stale */ | ||
| 1036 | mask = mask_from(q->bitmaps[ER], agg->grp->index); | ||
| 1037 | if (mask) { | ||
| 1038 | struct qfq_group *next = qfq_ffs(q, mask); | ||
| 1039 | if (qfq_gt(roundedF, next->F)) { | ||
| 1040 | if (qfq_gt(limit, next->F)) | ||
| 1041 | agg->S = next->F; | ||
| 1042 | else /* preserve timestamp correctness */ | ||
| 1043 | agg->S = limit; | ||
| 1044 | return; | ||
| 1045 | } | ||
| 1046 | } | ||
| 1047 | agg->S = q->V; | ||
| 1048 | } else /* timestamp is not stale */ | ||
| 1049 | agg->S = agg->F; | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | /* Update the timestamps of agg before scheduling/rescheduling it for | ||
| 1053 | * service. In particular, assign to agg->F its maximum possible | ||
| 1054 | * value, i.e., the virtual finish time with which the aggregate | ||
| 1055 | * should be labeled if it used all its budget once in service. | ||
| 1056 | */ | ||
| 1057 | static inline void | ||
| 1058 | qfq_update_agg_ts(struct qfq_sched *q, | ||
| 1059 | struct qfq_aggregate *agg, enum update_reason reason) | ||
| 1060 | { | ||
| 1061 | if (reason != requeue) | ||
| 1062 | qfq_update_start(q, agg); | ||
| 1063 | else /* just charge agg for the service received */ | ||
| 1064 | agg->S = agg->F; | ||
| 1065 | |||
| 1066 | agg->F = agg->S + (u64)agg->budgetmax * agg->inv_w; | ||
| 1067 | } | ||
| 1016 | 1068 | ||
| 1017 | static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg); | 1069 | static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg); |
| 1018 | 1070 | ||
| @@ -1135,66 +1187,6 @@ static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *q) | |||
| 1135 | return agg; | 1187 | return agg; |
| 1136 | } | 1188 | } |
| 1137 | 1189 | ||
| 1138 | /* | ||
| 1139 | * Assign a reasonable start time for a new aggregate in group i. | ||
| 1140 | * Admissible values for \hat(F) are multiples of \sigma_i | ||
| 1141 | * no greater than V+\sigma_i . Larger values mean that | ||
| 1142 | * we had a wraparound so we consider the timestamp to be stale. | ||
| 1143 | * | ||
| 1144 | * If F is not stale and F >= V then we set S = F. | ||
| 1145 | * Otherwise we should assign S = V, but this may violate | ||
| 1146 | * the ordering in EB (see [2]). So, if we have groups in ER, | ||
| 1147 | * set S to the F_j of the first group j which would be blocking us. | ||
| 1148 | * We are guaranteed not to move S backward because | ||
| 1149 | * otherwise our group i would still be blocked. | ||
| 1150 | */ | ||
| 1151 | static void qfq_update_start(struct qfq_sched *q, struct qfq_aggregate *agg) | ||
| 1152 | { | ||
| 1153 | unsigned long mask; | ||
| 1154 | u64 limit, roundedF; | ||
| 1155 | int slot_shift = agg->grp->slot_shift; | ||
| 1156 | |||
| 1157 | roundedF = qfq_round_down(agg->F, slot_shift); | ||
| 1158 | limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift); | ||
| 1159 | |||
| 1160 | if (!qfq_gt(agg->F, q->V) || qfq_gt(roundedF, limit)) { | ||
| 1161 | /* timestamp was stale */ | ||
| 1162 | mask = mask_from(q->bitmaps[ER], agg->grp->index); | ||
| 1163 | if (mask) { | ||
| 1164 | struct qfq_group *next = qfq_ffs(q, mask); | ||
| 1165 | if (qfq_gt(roundedF, next->F)) { | ||
| 1166 | if (qfq_gt(limit, next->F)) | ||
| 1167 | agg->S = next->F; | ||
| 1168 | else /* preserve timestamp correctness */ | ||
| 1169 | agg->S = limit; | ||
| 1170 | return; | ||
| 1171 | } | ||
| 1172 | } | ||
| 1173 | agg->S = q->V; | ||
| 1174 | } else /* timestamp is not stale */ | ||
| 1175 | agg->S = agg->F; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | /* | ||
| 1179 | * Update the timestamps of agg before scheduling/rescheduling it for | ||
| 1180 | * service. In particular, assign to agg->F its maximum possible | ||
| 1181 | * value, i.e., the virtual finish time with which the aggregate | ||
| 1182 | * should be labeled if it used all its budget once in service. | ||
| 1183 | */ | ||
| 1184 | static inline void | ||
| 1185 | qfq_update_agg_ts(struct qfq_sched *q, | ||
| 1186 | struct qfq_aggregate *agg, enum update_reason reason) | ||
| 1187 | { | ||
| 1188 | if (reason != requeue) | ||
| 1189 | qfq_update_start(q, agg); | ||
| 1190 | else /* just charge agg for the service received */ | ||
| 1191 | agg->S = agg->F; | ||
| 1192 | |||
| 1193 | agg->F = agg->S + (u64)agg->budgetmax * agg->inv_w; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | static void qfq_schedule_agg(struct qfq_sched *, struct qfq_aggregate *); | ||
| 1197 | |||
| 1198 | static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 1190 | static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
| 1199 | { | 1191 | { |
| 1200 | struct qfq_sched *q = qdisc_priv(sch); | 1192 | struct qfq_sched *q = qdisc_priv(sch); |
