diff options
Diffstat (limited to 'net/sched/sch_prio.c')
-rw-r--r-- | net/sched/sch_prio.c | 67 |
1 files changed, 24 insertions, 43 deletions
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 4b0a82191bc4..a356450b747b 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c | |||
@@ -172,8 +172,9 @@ prio_destroy(struct Qdisc *sch) | |||
172 | static int prio_tune(struct Qdisc *sch, struct nlattr *opt) | 172 | static int prio_tune(struct Qdisc *sch, struct nlattr *opt) |
173 | { | 173 | { |
174 | struct prio_sched_data *q = qdisc_priv(sch); | 174 | struct prio_sched_data *q = qdisc_priv(sch); |
175 | struct Qdisc *queues[TCQ_PRIO_BANDS]; | ||
176 | int oldbands = q->bands, i; | ||
175 | struct tc_prio_qopt *qopt; | 177 | struct tc_prio_qopt *qopt; |
176 | int i; | ||
177 | 178 | ||
178 | if (nla_len(opt) < sizeof(*qopt)) | 179 | if (nla_len(opt) < sizeof(*qopt)) |
179 | return -EINVAL; | 180 | return -EINVAL; |
@@ -187,62 +188,42 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) | |||
187 | return -EINVAL; | 188 | return -EINVAL; |
188 | } | 189 | } |
189 | 190 | ||
191 | /* Before commit, make sure we can allocate all new qdiscs */ | ||
192 | for (i = oldbands; i < qopt->bands; i++) { | ||
193 | queues[i] = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, | ||
194 | TC_H_MAKE(sch->handle, i + 1)); | ||
195 | if (!queues[i]) { | ||
196 | while (i > oldbands) | ||
197 | qdisc_destroy(queues[--i]); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | } | ||
201 | |||
190 | sch_tree_lock(sch); | 202 | sch_tree_lock(sch); |
191 | q->bands = qopt->bands; | 203 | q->bands = qopt->bands; |
192 | memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); | 204 | memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); |
193 | 205 | ||
194 | for (i = q->bands; i < TCQ_PRIO_BANDS; i++) { | 206 | for (i = q->bands; i < oldbands; i++) { |
195 | struct Qdisc *child = q->queues[i]; | 207 | struct Qdisc *child = q->queues[i]; |
196 | q->queues[i] = &noop_qdisc; | ||
197 | if (child != &noop_qdisc) { | ||
198 | qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog); | ||
199 | qdisc_destroy(child); | ||
200 | } | ||
201 | } | ||
202 | sch_tree_unlock(sch); | ||
203 | 208 | ||
204 | for (i = 0; i < q->bands; i++) { | 209 | qdisc_tree_reduce_backlog(child, child->q.qlen, |
205 | if (q->queues[i] == &noop_qdisc) { | 210 | child->qstats.backlog); |
206 | struct Qdisc *child, *old; | 211 | qdisc_destroy(child); |
207 | |||
208 | child = qdisc_create_dflt(sch->dev_queue, | ||
209 | &pfifo_qdisc_ops, | ||
210 | TC_H_MAKE(sch->handle, i + 1)); | ||
211 | if (child) { | ||
212 | sch_tree_lock(sch); | ||
213 | old = q->queues[i]; | ||
214 | q->queues[i] = child; | ||
215 | |||
216 | if (old != &noop_qdisc) { | ||
217 | qdisc_tree_reduce_backlog(old, | ||
218 | old->q.qlen, | ||
219 | old->qstats.backlog); | ||
220 | qdisc_destroy(old); | ||
221 | } | ||
222 | sch_tree_unlock(sch); | ||
223 | } | ||
224 | } | ||
225 | } | 212 | } |
213 | |||
214 | for (i = oldbands; i < q->bands; i++) | ||
215 | q->queues[i] = queues[i]; | ||
216 | |||
217 | sch_tree_unlock(sch); | ||
226 | return 0; | 218 | return 0; |
227 | } | 219 | } |
228 | 220 | ||
229 | static int prio_init(struct Qdisc *sch, struct nlattr *opt) | 221 | static int prio_init(struct Qdisc *sch, struct nlattr *opt) |
230 | { | 222 | { |
231 | struct prio_sched_data *q = qdisc_priv(sch); | 223 | if (!opt) |
232 | int i; | ||
233 | |||
234 | for (i = 0; i < TCQ_PRIO_BANDS; i++) | ||
235 | q->queues[i] = &noop_qdisc; | ||
236 | |||
237 | if (opt == NULL) { | ||
238 | return -EINVAL; | 224 | return -EINVAL; |
239 | } else { | ||
240 | int err; | ||
241 | 225 | ||
242 | if ((err = prio_tune(sch, opt)) != 0) | 226 | return prio_tune(sch, opt); |
243 | return err; | ||
244 | } | ||
245 | return 0; | ||
246 | } | 227 | } |
247 | 228 | ||
248 | static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) | 229 | static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) |