aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/skbuff.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 506f678e9d95..8b6d38fdb443 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -296,9 +296,12 @@ EXPORT_SYMBOL(build_skb);
296struct netdev_alloc_cache { 296struct netdev_alloc_cache {
297 struct page *page; 297 struct page *page;
298 unsigned int offset; 298 unsigned int offset;
299 unsigned int pagecnt_bias;
299}; 300};
300static DEFINE_PER_CPU(struct netdev_alloc_cache, netdev_alloc_cache); 301static DEFINE_PER_CPU(struct netdev_alloc_cache, netdev_alloc_cache);
301 302
303#define NETDEV_PAGECNT_BIAS (PAGE_SIZE / SMP_CACHE_BYTES)
304
302/** 305/**
303 * netdev_alloc_frag - allocate a page fragment 306 * netdev_alloc_frag - allocate a page fragment
304 * @fragsz: fragment size 307 * @fragsz: fragment size
@@ -317,17 +320,26 @@ void *netdev_alloc_frag(unsigned int fragsz)
317 if (unlikely(!nc->page)) { 320 if (unlikely(!nc->page)) {
318refill: 321refill:
319 nc->page = alloc_page(GFP_ATOMIC | __GFP_COLD); 322 nc->page = alloc_page(GFP_ATOMIC | __GFP_COLD);
323 if (unlikely(!nc->page))
324 goto end;
325recycle:
326 atomic_set(&nc->page->_count, NETDEV_PAGECNT_BIAS);
327 nc->pagecnt_bias = NETDEV_PAGECNT_BIAS;
320 nc->offset = 0; 328 nc->offset = 0;
321 } 329 }
322 if (likely(nc->page)) { 330
323 if (nc->offset + fragsz > PAGE_SIZE) { 331 if (nc->offset + fragsz > PAGE_SIZE) {
324 put_page(nc->page); 332 /* avoid unnecessary locked operations if possible */
325 goto refill; 333 if ((atomic_read(&nc->page->_count) == nc->pagecnt_bias) ||
326 } 334 atomic_sub_and_test(nc->pagecnt_bias, &nc->page->_count))
327 data = page_address(nc->page) + nc->offset; 335 goto recycle;
328 nc->offset += fragsz; 336 goto refill;
329 get_page(nc->page);
330 } 337 }
338
339 data = page_address(nc->page) + nc->offset;
340 nc->offset += fragsz;
341 nc->pagecnt_bias--;
342end:
331 local_irq_restore(flags); 343 local_irq_restore(flags);
332 return data; 344 return data;
333} 345}