Commit a1bcfacd authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

netpoll: private skb pool (rev3)

It was a dark and stormy night when Steve first saw the
netpoll beast. The beast was odd, and misshapen but not
extremely ugly.

"Let me take off one of your warts" he said. This wart
is where you tried to make an skb list yourself. If the
beast had ever run out of memory, he would have stupefied
himself unnecessarily.

The first try was painful, so he tried again till the bleeding
stopped. And again, and again...
Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
parent d23ca15a
...@@ -36,9 +36,7 @@ ...@@ -36,9 +36,7 @@
#define MAX_QUEUE_DEPTH (MAX_SKBS / 2) #define MAX_QUEUE_DEPTH (MAX_SKBS / 2)
#define MAX_RETRIES 20000 #define MAX_RETRIES 20000
static DEFINE_SPINLOCK(skb_list_lock); static struct sk_buff_head skb_pool;
static int nr_skbs;
static struct sk_buff *skbs;
static DEFINE_SPINLOCK(queue_lock); static DEFINE_SPINLOCK(queue_lock);
static int queue_depth; static int queue_depth;
...@@ -190,17 +188,15 @@ static void refill_skbs(void) ...@@ -190,17 +188,15 @@ static void refill_skbs(void)
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&skb_list_lock, flags); spin_lock_irqsave(&skb_pool.lock, flags);
while (nr_skbs < MAX_SKBS) { while (skb_pool.qlen < MAX_SKBS) {
skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC); skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
if (!skb) if (!skb)
break; break;
skb->next = skbs; __skb_queue_tail(&skb_pool, skb);
skbs = skb;
nr_skbs++;
} }
spin_unlock_irqrestore(&skb_list_lock, flags); spin_unlock_irqrestore(&skb_pool.lock, flags);
} }
static void zap_completion_queue(void) static void zap_completion_queue(void)
...@@ -229,39 +225,26 @@ static void zap_completion_queue(void) ...@@ -229,39 +225,26 @@ static void zap_completion_queue(void)
put_cpu_var(softnet_data); put_cpu_var(softnet_data);
} }
static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve) static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
{ {
int once = 1, count = 0; int count = 0;
unsigned long flags; struct sk_buff *skb;
struct sk_buff *skb = NULL;
zap_completion_queue(); zap_completion_queue();
repeat:
if (nr_skbs < MAX_SKBS)
refill_skbs(); refill_skbs();
repeat:
skb = alloc_skb(len, GFP_ATOMIC); skb = alloc_skb(len, GFP_ATOMIC);
if (!skb)
if (!skb) { skb = skb_dequeue(&skb_pool);
spin_lock_irqsave(&skb_list_lock, flags);
skb = skbs;
if (skb) {
skbs = skb->next;
skb->next = NULL;
nr_skbs--;
}
spin_unlock_irqrestore(&skb_list_lock, flags);
}
if(!skb) { if(!skb) {
count++; if (++count < 10) {
if (once && (count == 1000000)) {
printk("out of netpoll skbs!\n");
once = 0;
}
netpoll_poll(np); netpoll_poll(np);
goto repeat; goto repeat;
} }
return NULL;
}
atomic_set(&skb->users, 1); atomic_set(&skb->users, 1);
skb_reserve(skb, reserve); skb_reserve(skb, reserve);
...@@ -770,6 +753,12 @@ int netpoll_setup(struct netpoll *np) ...@@ -770,6 +753,12 @@ int netpoll_setup(struct netpoll *np)
return -1; return -1;
} }
static int __init netpoll_init(void) {
skb_queue_head_init(&skb_pool);
return 0;
}
core_initcall(netpoll_init);
void netpoll_cleanup(struct netpoll *np) void netpoll_cleanup(struct netpoll *np)
{ {
struct netpoll_info *npinfo; struct netpoll_info *npinfo;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment