X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=net%2Fsched%2Fsch_generic.c;h=6f91518997951cbd13056373f36a98c0f87136b2;hb=27bf71c2a7e596ed34e9bf2d4a5030321a09a1ad;hp=d7aca8ef524ab8f9ea9d01b986d0ea7a88c72c3a;hpb=af57d238aa2107e1b45d8dacad6e50db938f0567;p=powerpc.git diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index d7aca8ef52..6f91518997 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -96,8 +95,11 @@ static inline int qdisc_restart(struct net_device *dev) struct sk_buff *skb; /* Dequeue packet */ - if ((skb = q->dequeue(q)) != NULL) { + if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) { unsigned nolock = (dev->features & NETIF_F_LLTX); + + dev->gso_skb = NULL; + /* * When the driver has LLTX set it does its own locking * in start_xmit. No need to add additional overhead by @@ -134,10 +136,8 @@ static inline int qdisc_restart(struct net_device *dev) if (!netif_queue_stopped(dev)) { int ret; - if (netdev_nit) - dev_queue_xmit_nit(skb, dev); - ret = dev->hard_start_xmit(skb, dev); + ret = dev_hard_start_xmit(skb, dev); if (ret == NETDEV_TX_OK) { if (!nolock) { netif_tx_unlock(dev); @@ -171,7 +171,10 @@ static inline int qdisc_restart(struct net_device *dev) */ requeue: - q->ops->requeue(skb, q); + if (skb->next) + dev->gso_skb = skb; + else + q->ops->requeue(skb, q); netif_schedule(dev); return 1; } @@ -181,9 +184,13 @@ requeue: void __qdisc_run(struct net_device *dev) { + if (unlikely(dev->qdisc == &noop_qdisc)) + goto out; + while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev)) /* NOTHING */; +out: clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); } @@ -231,9 +238,7 @@ void __netdev_watchdog_up(struct net_device *dev) static void dev_watchdog_up(struct net_device *dev) { - netif_tx_lock_bh(dev); __netdev_watchdog_up(dev); - netif_tx_unlock_bh(dev); } static void dev_watchdog_down(struct net_device *dev) @@ -425,10 +430,9 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) size = QDISC_ALIGN(sizeof(*sch)); size += ops->priv_size + (QDISC_ALIGNTO - 1); - p = kmalloc(size, GFP_KERNEL); + p = kzalloc(size, GFP_KERNEL); if (!p) goto errout; - memset(p, 0, size); sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); sch->padded = (char *) sch - (char *) p; @@ -583,10 +587,17 @@ void dev_deactivate(struct net_device *dev) dev_watchdog_down(dev); - while (test_bit(__LINK_STATE_SCHED, &dev->state)) + /* Wait for outstanding dev_queue_xmit calls. */ + synchronize_rcu(); + + /* Wait for outstanding qdisc_run calls. */ + while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) yield(); - spin_unlock_wait(&dev->_xmit_lock); + if (dev->gso_skb) { + kfree_skb(dev->gso_skb); + dev->gso_skb = NULL; + } } void dev_init_scheduler(struct net_device *dev)