aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r--net/sched/sch_api.c50
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
187struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) 192static 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 */
206static DEFINE_SPINLOCK(qdisc_list_lock);
207
208static void qdisc_list_add(struct Qdisc *q) 207static 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
217void qdisc_list_del(struct Qdisc *q) 213void 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}
225EXPORT_SYMBOL(qdisc_list_del); 218EXPORT_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 235out:
245unlock:
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