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 f4d443aeae54..8f575899adfa 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -153,8 +153,9 @@ prio_destroy(struct Qdisc *sch)
153static int prio_tune(struct Qdisc *sch, struct nlattr *opt) 153static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
154{ 154{
155 struct prio_sched_data *q = qdisc_priv(sch); 155 struct prio_sched_data *q = qdisc_priv(sch);
156 struct Qdisc *queues[TCQ_PRIO_BANDS];
157 int oldbands = q->bands, i;
156 struct tc_prio_qopt *qopt; 158 struct tc_prio_qopt *qopt;
157 int i;
158 159
159 if (nla_len(opt) < sizeof(*qopt)) 160 if (nla_len(opt) < sizeof(*qopt))
160 return -EINVAL; 161 return -EINVAL;
@@ -168,62 +169,42 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
168 return -EINVAL; 169 return -EINVAL;
169 } 170 }
170 171
172 /* Before commit, make sure we can allocate all new qdiscs */
173 for (i = oldbands; i < qopt->bands; i++) {
174 queues[i] = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
175 TC_H_MAKE(sch->handle, i + 1));
176 if (!queues[i]) {
177 while (i > oldbands)
178 qdisc_destroy(queues[--i]);
179 return -ENOMEM;
180 }
181 }
182
171 sch_tree_lock(sch); 183 sch_tree_lock(sch);
172 q->bands = qopt->bands; 184 q->bands = qopt->bands;
173 memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); 185 memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
174 186
175 for (i = q->bands; i < TCQ_PRIO_BANDS; i++) { 187 for (i = q->bands; i < oldbands; i++) {
176 struct Qdisc *child = q->queues[i]; 188 struct Qdisc *child = q->queues[i];
177 q->queues[i] = &noop_qdisc;
178 if (child != &noop_qdisc) {
179 qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog);
180 qdisc_destroy(child);
181 }
182 }
183 sch_tree_unlock(sch);
184 189
185 for (i = 0; i < q->bands; i++) { 190 qdisc_tree_reduce_backlog(child, child->q.qlen,
186 if (q->queues[i] == &noop_qdisc) { 191 child->qstats.backlog);
187 struct Qdisc *child, *old; 192 qdisc_destroy(child);
188
189 child = qdisc_create_dflt(sch->dev_queue,
190 &pfifo_qdisc_ops,
191 TC_H_MAKE(sch->handle, i + 1));
192 if (child) {
193 sch_tree_lock(sch);
194 old = q->queues[i];
195 q->queues[i] = child;
196
197 if (old != &noop_qdisc) {
198 qdisc_tree_reduce_backlog(old,
199 old->q.qlen,
200 old->qstats.backlog);
201 qdisc_destroy(old);
202 }
203 sch_tree_unlock(sch);
204 }
205 }
206 } 193 }
194
195 for (i = oldbands; i < q->bands; i++)
196 q->queues[i] = queues[i];
197
198 sch_tree_unlock(sch);
207 return 0; 199 return 0;
208} 200}
209 201
210static int prio_init(struct Qdisc *sch, struct nlattr *opt) 202static int prio_init(struct Qdisc *sch, struct nlattr *opt)
211{ 203{
212 struct prio_sched_data *q = qdisc_priv(sch); 204 if (!opt)
213 int i;
214
215 for (i = 0; i < TCQ_PRIO_BANDS; i++)
216 q->queues[i] = &noop_qdisc;
217
218 if (opt == NULL) {
219 return -EINVAL; 205 return -EINVAL;
220 } else {
221 int err;
222 206
223 if ((err = prio_tune(sch, opt)) != 0) 207 return prio_tune(sch, opt);
224 return err;
225 }
226 return 0;
227} 208}
228 209
229static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) 210static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)