netpoll deferred transmit path
authorStephen Hemminger <shemminger@osdl.org>
Thu, 26 Oct 2006 22:46:53 +0000 (15:46 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Sun, 3 Dec 2006 05:22:35 +0000 (21:22 -0800)
When the netpoll beast got busy, he tended to babble.
Instead of talking out of his large mouth as normal,
he tended to try to snort out other orifices. This lead
to words (skbs) ending up in odd places (like NIT) that
he did not intend.

The normal way of talking wouldn't work, but he could
at least change to using the same tone all the time.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
net/core/netpoll.c

index 621baa5da49f433d5b9925facd5fcbab80189ac9..93cb828f3aaffa51306762132d61c18b4742a2c9 100644 (file)
@@ -55,9 +55,25 @@ static void queue_process(void *p)
        struct netpoll_info *npinfo = p;
        struct sk_buff *skb;
 
-       while ((skb = skb_dequeue(&npinfo->txq)))
-               dev_queue_xmit(skb);
+       while ((skb = skb_dequeue(&npinfo->txq))) {
+               struct net_device *dev = skb->dev;
 
+               if (!netif_device_present(dev) || !netif_running(dev)) {
+                       __kfree_skb(skb);
+                       continue;
+               }
+
+               netif_tx_lock_bh(dev);
+               if (netif_queue_stopped(dev) ||
+                   dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
+                       skb_queue_head(&npinfo->txq, skb);
+                       netif_tx_unlock_bh(dev);
+
+                       schedule_delayed_work(&npinfo->tx_work, HZ/10);
+                       return;
+               }
+               netif_tx_unlock_bh(dev);
+       }
 }
 
 void netpoll_queue(struct sk_buff *skb)
@@ -765,6 +781,7 @@ void netpoll_cleanup(struct netpoll *np)
                        if (atomic_dec_and_test(&npinfo->refcnt)) {
                                skb_queue_purge(&npinfo->arp_tx);
                                skb_queue_purge(&npinfo->txq);
+                               cancel_rearming_delayed_work(&npinfo->tx_work);
                                flush_scheduled_work();
 
                                kfree(npinfo);