aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_prio.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_prio.c')
-rw-r--r--net/sched/sch_prio.c67
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)
172static int prio_tune(struct Qdisc *sch, struct nlattr *opt) 172static 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
229static int prio_init(struct Qdisc *sch, struct nlattr *opt) 221static 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
248static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) 229static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)