aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/netpoll.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-08-03 00:24:04 -0700
committerDavid S. Miller <davem@davemloft.net>2010-08-03 00:24:04 -0700
commit3578b0c8abc7bdb4f02152ce5db7e09d484c6866 (patch)
treea884f8467e5700b798d52a038d56f99ee5bd73f1 /net/core/netpoll.c
parentnet: cleanup inclusion (diff)
downloadlinux-dev-3578b0c8abc7bdb4f02152ce5db7e09d484c6866.tar.xz
linux-dev-3578b0c8abc7bdb4f02152ce5db7e09d484c6866.zip
Revert "net: remove zap_completion_queue"
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>
Diffstat (limited to 'net/core/netpoll.c')
-rw-r--r--net/core/netpoll.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index c2b7a8bed8f6..537e01afd81b 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -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: