diff options
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r-- | net/core/skbuff.c | 106 |
1 files changed, 63 insertions, 43 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3528c7510..95e4d8e17 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4,7 +4,7 @@ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk> * Florian La Roche <rzsfl@rz.uni-sb.de> * - * Version: $Id: skbuff.c,v 1.64 2000/01/16 05:11:03 davem Exp $ + * Version: $Id: skbuff.c,v 1.66 2000/02/09 21:11:30 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -61,18 +61,15 @@ #include <asm/uaccess.h> #include <asm/system.h> -/* - * Resource tracking variables - */ - -static atomic_t net_skbcount = ATOMIC_INIT(0); -static atomic_t net_allocs = ATOMIC_INIT(0); -static atomic_t net_fails = ATOMIC_INIT(0); - -extern atomic_t ip_frag_mem; +int sysctl_hot_list_len = 128; static kmem_cache_t *skbuff_head_cache; +static union { + struct sk_buff_head list; + char pad[SMP_CACHE_BYTES]; +} skb_head_pool[NR_CPUS]; + /* * Keep out-of-line to prevent kernel bloat. * __builtin_return_address is not used because it is not always @@ -93,20 +90,39 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here) *(int*)0 = 0; } -void show_net_buffers(void) +static __inline__ struct sk_buff *skb_head_from_pool(void) { - printk("Networking buffers in use : %u\n", - atomic_read(&net_skbcount)); - printk("Total network buffer allocations : %u\n", - atomic_read(&net_allocs)); - printk("Total failed network buffer allocs : %u\n", - atomic_read(&net_fails)); -#ifdef CONFIG_INET - printk("IP fragment buffer size : %u\n", - atomic_read(&ip_frag_mem)); -#endif + struct sk_buff_head *list = &skb_head_pool[smp_processor_id()].list; + + if (skb_queue_len(list)) { + struct sk_buff *skb; + unsigned long flags; + + local_irq_save(flags); + skb = __skb_dequeue(list); + local_irq_restore(flags); + return skb; + } + return NULL; } +static __inline__ void skb_head_to_pool(struct sk_buff *skb) +{ + struct sk_buff_head *list = &skb_head_pool[smp_processor_id()].list; + + if (skb_queue_len(list) < sysctl_hot_list_len) { + unsigned long flags; + + local_irq_save(flags); + __skb_queue_head(list, skb); + local_irq_restore(flags); + + return; + } + kmem_cache_free(skbuff_head_cache, skb); +} + + /* Allocate a new skbuff. We do this ourselves so we can fill in a few * 'private' fields and also do memory statistics to find all the * [BEEP] leaks. @@ -129,9 +145,12 @@ struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) } /* Get the HEAD */ - skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask); - if (skb == NULL) - goto nohead; + skb = skb_head_from_pool(); + if (skb == NULL) { + skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask); + if (skb == NULL) + goto nohead; + } /* Get the DATA. Size must match skb_add_mtu(). */ size = ((size + 15) & ~15); @@ -139,17 +158,9 @@ struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) if (data == NULL) goto nodata; - /* Note that this counter is useless now - you can just look in the - * skbuff_head entry in /proc/slabinfo. We keep it only for emergency - * cases. - */ - atomic_inc(&net_allocs); - /* XXX: does not include slab overhead */ skb->truesize = size + sizeof(struct sk_buff); - atomic_inc(&net_skbcount); - /* Load the data pointers. */ skb->head = data; skb->data = data; @@ -166,9 +177,8 @@ struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) return skb; nodata: - kmem_cache_free(skbuff_head_cache, skb); + skb_head_to_pool(skb); nohead: - atomic_inc(&net_fails); return NULL; } @@ -213,8 +223,7 @@ void kfree_skbmem(struct sk_buff *skb) if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb))) kfree(skb->head); - kmem_cache_free(skbuff_head_cache, skb); - atomic_dec(&net_skbcount); + skb_head_to_pool(skb); } /* @@ -230,8 +239,13 @@ void __kfree_skb(struct sk_buff *skb) } dst_release(skb->dst); - if(skb->destructor) + if(skb->destructor) { + if (in_irq()) { + printk(KERN_WARNING "Warning: kfree_skb on hard IRQ %p\n", + NET_CALLER(skb)); + } skb->destructor(skb); + } #ifdef CONFIG_NET if(skb->rx_dev) dev_put(skb->rx_dev); @@ -247,17 +261,18 @@ void __kfree_skb(struct sk_buff *skb) struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) { struct sk_buff *n; - - n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); - if (!n) - return NULL; + + n = skb_head_from_pool(); + if (!n) { + n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); + if (!n) + return NULL; + } memcpy(n, skb, sizeof(*n)); atomic_inc(skb_datarefp(skb)); skb->cloned = 1; - atomic_inc(&net_allocs); - atomic_inc(&net_skbcount); dst_clone(n->dst); n->rx_dev = NULL; n->cloned = 1; @@ -379,6 +394,8 @@ void skb_add_mtu(int mtu) void __init skb_init(void) { + int i; + skbuff_head_cache = kmem_cache_create("skbuff_head_cache", sizeof(struct sk_buff), 0, @@ -386,4 +403,7 @@ void __init skb_init(void) skb_headerinit, NULL); if (!skbuff_head_cache) panic("cannot create skbuff cache"); + + for (i=0; i<NR_CPUS; i++) + skb_queue_head_init(&skb_head_pool[i].list); } |