]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Revert "net: remove zap_completion_queue"
authorDavid S. Miller <davem@davemloft.net>
Tue, 3 Aug 2010 07:24:04 +0000 (00:24 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 Aug 2010 07:24:04 +0000 (00:24 -0700)
This reverts commit 15e83ed78864d0625e87a85f09b297c0919a4797.

As explained by Johannes Berg, the optimization made here is
invalid.  Or, at best, incomplete.

Not only destructor invocation, but conntract entry releasing
must be executed outside of hw IRQ context.

So just checking "skb->destructor" is insufficient.

Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/dev.c
net/core/netpoll.c

index 8c663dbf1d77406059254060a3d3a18e91ce02d2..e1c1cdcc2bb0429d65fea408625e9dec0c317a59 100644 (file)
@@ -1591,9 +1591,7 @@ EXPORT_SYMBOL(__netif_schedule);
 
 void dev_kfree_skb_irq(struct sk_buff *skb)
 {
-       if (!skb->destructor)
-               dev_kfree_skb(skb);
-       else if (atomic_dec_and_test(&skb->users)) {
+       if (atomic_dec_and_test(&skb->users)) {
                struct softnet_data *sd;
                unsigned long flags;
 
index c2b7a8bed8f64e4474a75a563cc930c1f9eb326d..537e01afd81baf1e9bc7269e0c97ca3fb3844ffe 100644 (file)
@@ -49,6 +49,7 @@ static atomic_t trapped;
                (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
                                sizeof(struct iphdr) + sizeof(struct ethhdr))
 
+static void zap_completion_queue(void);
 static void arp_reply(struct sk_buff *skb);
 
 static unsigned int carrier_timeout = 4;
@@ -196,6 +197,7 @@ void netpoll_poll_dev(struct net_device *dev)
 
        service_arp_queue(dev->npinfo);
 
+       zap_completion_queue();
 }
 EXPORT_SYMBOL(netpoll_poll_dev);
 
@@ -221,11 +223,40 @@ static void refill_skbs(void)
        spin_unlock_irqrestore(&skb_pool.lock, flags);
 }
 
+static void zap_completion_queue(void)
+{
+       unsigned long flags;
+       struct softnet_data *sd = &get_cpu_var(softnet_data);
+
+       if (sd->completion_queue) {
+               struct sk_buff *clist;
+
+               local_irq_save(flags);
+               clist = sd->completion_queue;
+               sd->completion_queue = NULL;
+               local_irq_restore(flags);
+
+               while (clist != NULL) {
+                       struct sk_buff *skb = clist;
+                       clist = clist->next;
+                       if (skb->destructor) {
+                               atomic_inc(&skb->users);
+                               dev_kfree_skb_any(skb); /* put this one back */
+                       } else {
+                               __kfree_skb(skb);
+                       }
+               }
+       }
+
+       put_cpu_var(softnet_data);
+}
+
 static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
 {
        int count = 0;
        struct sk_buff *skb;
 
+       zap_completion_queue();
        refill_skbs();
 repeat: