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 f4d443aeae54..8f575899adfa 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c | |||
@@ -153,8 +153,9 @@ prio_destroy(struct Qdisc *sch) | |||
153 | static int prio_tune(struct Qdisc *sch, struct nlattr *opt) | 153 | static 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 | ||
210 | static int prio_init(struct Qdisc *sch, struct nlattr *opt) | 202 | static 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 | ||
229 | static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) | 210 | static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) |