aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r--net/sched/sch_generic.c40
1 files changed, 31 insertions, 9 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index b1e4c5e20ac7..74d4a1dceeec 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -90,14 +90,17 @@ void qdisc_unlock_tree(struct net_device *dev)
90 NOTE: Called under dev->queue_lock with locally disabled BH. 90 NOTE: Called under dev->queue_lock with locally disabled BH.
91*/ 91*/
92 92
93int qdisc_restart(struct net_device *dev) 93static inline int qdisc_restart(struct net_device *dev)
94{ 94{
95 struct Qdisc *q = dev->qdisc; 95 struct Qdisc *q = dev->qdisc;
96 struct sk_buff *skb; 96 struct sk_buff *skb;
97 97
98 /* Dequeue packet */ 98 /* Dequeue packet */
99 if ((skb = q->dequeue(q)) != NULL) { 99 if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
100 unsigned nolock = (dev->features & NETIF_F_LLTX); 100 unsigned nolock = (dev->features & NETIF_F_LLTX);
101
102 dev->gso_skb = NULL;
103
101 /* 104 /*
102 * When the driver has LLTX set it does its own locking 105 * When the driver has LLTX set it does its own locking
103 * in start_xmit. No need to add additional overhead by 106 * in start_xmit. No need to add additional overhead by
@@ -134,10 +137,8 @@ int qdisc_restart(struct net_device *dev)
134 137
135 if (!netif_queue_stopped(dev)) { 138 if (!netif_queue_stopped(dev)) {
136 int ret; 139 int ret;
137 if (netdev_nit)
138 dev_queue_xmit_nit(skb, dev);
139 140
140 ret = dev->hard_start_xmit(skb, dev); 141 ret = dev_hard_start_xmit(skb, dev);
141 if (ret == NETDEV_TX_OK) { 142 if (ret == NETDEV_TX_OK) {
142 if (!nolock) { 143 if (!nolock) {
143 netif_tx_unlock(dev); 144 netif_tx_unlock(dev);
@@ -171,7 +172,10 @@ int qdisc_restart(struct net_device *dev)
171 */ 172 */
172 173
173requeue: 174requeue:
174 q->ops->requeue(skb, q); 175 if (skb->next)
176 dev->gso_skb = skb;
177 else
178 q->ops->requeue(skb, q);
175 netif_schedule(dev); 179 netif_schedule(dev);
176 return 1; 180 return 1;
177 } 181 }
@@ -179,6 +183,18 @@ requeue:
179 return q->q.qlen; 183 return q->q.qlen;
180} 184}
181 185
186void __qdisc_run(struct net_device *dev)
187{
188 if (unlikely(dev->qdisc == &noop_qdisc))
189 goto out;
190
191 while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
192 /* NOTHING */;
193
194out:
195 clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
196}
197
182static void dev_watchdog(unsigned long arg) 198static void dev_watchdog(unsigned long arg)
183{ 199{
184 struct net_device *dev = (struct net_device *)arg; 200 struct net_device *dev = (struct net_device *)arg;
@@ -575,10 +591,17 @@ void dev_deactivate(struct net_device *dev)
575 591
576 dev_watchdog_down(dev); 592 dev_watchdog_down(dev);
577 593
578 while (test_bit(__LINK_STATE_SCHED, &dev->state)) 594 /* Wait for outstanding dev_queue_xmit calls. */
595 synchronize_rcu();
596
597 /* Wait for outstanding qdisc_run calls. */
598 while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
579 yield(); 599 yield();
580 600
581 spin_unlock_wait(&dev->_xmit_lock); 601 if (dev->gso_skb) {
602 kfree_skb(dev->gso_skb);
603 dev->gso_skb = NULL;
604 }
582} 605}
583 606
584void dev_init_scheduler(struct net_device *dev) 607void dev_init_scheduler(struct net_device *dev)
@@ -620,6 +643,5 @@ EXPORT_SYMBOL(qdisc_create_dflt);
620EXPORT_SYMBOL(qdisc_alloc); 643EXPORT_SYMBOL(qdisc_alloc);
621EXPORT_SYMBOL(qdisc_destroy); 644EXPORT_SYMBOL(qdisc_destroy);
622EXPORT_SYMBOL(qdisc_reset); 645EXPORT_SYMBOL(qdisc_reset);
623EXPORT_SYMBOL(qdisc_restart);
624EXPORT_SYMBOL(qdisc_lock_tree); 646EXPORT_SYMBOL(qdisc_lock_tree);
625EXPORT_SYMBOL(qdisc_unlock_tree); 647EXPORT_SYMBOL(qdisc_unlock_tree);