diff options
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r-- | net/sched/sch_api.c | 50 |
1 files changed, 20 insertions, 30 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 6ab4a2f92ca0..0fc4a18fd96f 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -97,10 +97,9 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, | |||
97 | 97 | ||
98 | Auxiliary routines: | 98 | Auxiliary routines: |
99 | 99 | ||
100 | ---requeue | 100 | ---peek |
101 | 101 | ||
102 | requeues once dequeued packet. It is used for non-standard or | 102 | like dequeue but without removing a packet from the queue |
103 | just buggy devices, which can defer output even if netif_queue_stopped()=0. | ||
104 | 103 | ||
105 | ---reset | 104 | ---reset |
106 | 105 | ||
@@ -147,8 +146,14 @@ int register_qdisc(struct Qdisc_ops *qops) | |||
147 | 146 | ||
148 | if (qops->enqueue == NULL) | 147 | if (qops->enqueue == NULL) |
149 | qops->enqueue = noop_qdisc_ops.enqueue; | 148 | qops->enqueue = noop_qdisc_ops.enqueue; |
150 | if (qops->requeue == NULL) | 149 | if (qops->peek == NULL) { |
151 | qops->requeue = noop_qdisc_ops.requeue; | 150 | if (qops->dequeue == NULL) { |
151 | qops->peek = noop_qdisc_ops.peek; | ||
152 | } else { | ||
153 | rc = -EINVAL; | ||
154 | goto out; | ||
155 | } | ||
156 | } | ||
152 | if (qops->dequeue == NULL) | 157 | if (qops->dequeue == NULL) |
153 | qops->dequeue = noop_qdisc_ops.dequeue; | 158 | qops->dequeue = noop_qdisc_ops.dequeue; |
154 | 159 | ||
@@ -184,7 +189,7 @@ EXPORT_SYMBOL(unregister_qdisc); | |||
184 | (root qdisc, all its children, children of children etc.) | 189 | (root qdisc, all its children, children of children etc.) |
185 | */ | 190 | */ |
186 | 191 | ||
187 | struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) | 192 | static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) |
188 | { | 193 | { |
189 | struct Qdisc *q; | 194 | struct Qdisc *q; |
190 | 195 | ||
@@ -199,28 +204,16 @@ struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) | |||
199 | return NULL; | 204 | return NULL; |
200 | } | 205 | } |
201 | 206 | ||
202 | /* | ||
203 | * This lock is needed until some qdiscs stop calling qdisc_tree_decrease_qlen() | ||
204 | * without rtnl_lock(); currently hfsc_dequeue(), netem_dequeue(), tbf_dequeue() | ||
205 | */ | ||
206 | static DEFINE_SPINLOCK(qdisc_list_lock); | ||
207 | |||
208 | static void qdisc_list_add(struct Qdisc *q) | 207 | static void qdisc_list_add(struct Qdisc *q) |
209 | { | 208 | { |
210 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { | 209 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) |
211 | spin_lock_bh(&qdisc_list_lock); | ||
212 | list_add_tail(&q->list, &qdisc_root_sleeping(q)->list); | 210 | list_add_tail(&q->list, &qdisc_root_sleeping(q)->list); |
213 | spin_unlock_bh(&qdisc_list_lock); | ||
214 | } | ||
215 | } | 211 | } |
216 | 212 | ||
217 | void qdisc_list_del(struct Qdisc *q) | 213 | void qdisc_list_del(struct Qdisc *q) |
218 | { | 214 | { |
219 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { | 215 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) |
220 | spin_lock_bh(&qdisc_list_lock); | ||
221 | list_del(&q->list); | 216 | list_del(&q->list); |
222 | spin_unlock_bh(&qdisc_list_lock); | ||
223 | } | ||
224 | } | 217 | } |
225 | EXPORT_SYMBOL(qdisc_list_del); | 218 | EXPORT_SYMBOL(qdisc_list_del); |
226 | 219 | ||
@@ -229,22 +222,17 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) | |||
229 | unsigned int i; | 222 | unsigned int i; |
230 | struct Qdisc *q; | 223 | struct Qdisc *q; |
231 | 224 | ||
232 | spin_lock_bh(&qdisc_list_lock); | ||
233 | |||
234 | for (i = 0; i < dev->num_tx_queues; i++) { | 225 | for (i = 0; i < dev->num_tx_queues; i++) { |
235 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 226 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); |
236 | struct Qdisc *txq_root = txq->qdisc_sleeping; | 227 | struct Qdisc *txq_root = txq->qdisc_sleeping; |
237 | 228 | ||
238 | q = qdisc_match_from_root(txq_root, handle); | 229 | q = qdisc_match_from_root(txq_root, handle); |
239 | if (q) | 230 | if (q) |
240 | goto unlock; | 231 | goto out; |
241 | } | 232 | } |
242 | 233 | ||
243 | q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); | 234 | q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); |
244 | 235 | out: | |
245 | unlock: | ||
246 | spin_unlock_bh(&qdisc_list_lock); | ||
247 | |||
248 | return q; | 236 | return q; |
249 | } | 237 | } |
250 | 238 | ||
@@ -462,7 +450,6 @@ static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) | |||
462 | timer); | 450 | timer); |
463 | 451 | ||
464 | wd->qdisc->flags &= ~TCQ_F_THROTTLED; | 452 | wd->qdisc->flags &= ~TCQ_F_THROTTLED; |
465 | smp_wmb(); | ||
466 | __netif_schedule(qdisc_root(wd->qdisc)); | 453 | __netif_schedule(qdisc_root(wd->qdisc)); |
467 | 454 | ||
468 | return HRTIMER_NORESTART; | 455 | return HRTIMER_NORESTART; |
@@ -892,9 +879,12 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) | |||
892 | sch->stab = stab; | 879 | sch->stab = stab; |
893 | 880 | ||
894 | if (tca[TCA_RATE]) | 881 | if (tca[TCA_RATE]) |
882 | /* NB: ignores errors from replace_estimator | ||
883 | because change can't be undone. */ | ||
895 | gen_replace_estimator(&sch->bstats, &sch->rate_est, | 884 | gen_replace_estimator(&sch->bstats, &sch->rate_est, |
896 | qdisc_root_sleeping_lock(sch), | 885 | qdisc_root_sleeping_lock(sch), |
897 | tca[TCA_RATE]); | 886 | tca[TCA_RATE]); |
887 | |||
898 | return 0; | 888 | return 0; |
899 | } | 889 | } |
900 | 890 | ||