Index: linux-2.6/mm/page_alloc.c =================================================================== --- linux-2.6.orig/mm/page_alloc.c 2007-09-08 15:18:00.000000000 -0700 +++ linux-2.6/mm/page_alloc.c 2007-09-08 15:44:04.000000000 -0700 @@ -405,8 +405,13 @@ unsigned long page_idx; int order_size = 1 << order; - if (unlikely(PageHead(page))) + if (unlikely(PageHead(page))) { + if (pagepool_page(page)) { + pagepool_free(page); + return; + } destroy_compound_page(page, order); + } page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1); @@ -843,7 +848,7 @@ struct zone *zone, int order, gfp_t gfp_flags) { unsigned long flags; - struct page *page; + struct page *page = NULL; int cold = !!(gfp_flags & __GFP_COLD); int cpu; @@ -864,9 +869,13 @@ list_del(&page->lru); pcp->count--; } else { - spin_lock_irqsave(&zone->lock, flags); - page = __rmqueue(zone, order); - spin_unlock(&zone->lock); + if (order > PAGE_ORDER_COSTLY) + page = pagepool_alloc(zone, order, flags); + if (!page) { + spin_lock_irqsave(&zone->lock, flags); + page = __rmqueue(zone, order); + spin_unlock(&zone->lock); + } if (!page) goto failed; } Index: linux-2.6/arch/x86_64/kernel/setup.c =================================================================== --- linux-2.6.orig/arch/x86_64/kernel/setup.c 2007-09-08 15:38:57.000000000 -0700 +++ linux-2.6/arch/x86_64/kernel/setup.c 2007-09-08 15:42:14.000000000 -0700 @@ -170,6 +170,7 @@ e820_register_active_regions(0, start_pfn, end_pfn); free_bootmem_with_active_regions(0, end_pfn); reserve_bootmem(bootmap, bootmap_size); + setup_page_pools(0); } #endif Index: linux-2.6/arch/x86_64/mm/numa.c =================================================================== --- linux-2.6.orig/arch/x86_64/mm/numa.c 2007-09-08 15:40:45.000000000 -0700 +++ linux-2.6/arch/x86_64/mm/numa.c 2007-09-08 15:42:02.000000000 -0700 @@ -218,7 +218,7 @@ start_pfn, end_pfn); free_bootmem_with_active_regions(nodeid, end); - + setup_pagepools(node); reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size); reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages< + */ +struct page *pool_alloc(struct zone *, gfp_t mask); +void pool_free(struct page *page); +void setup_page_pools(void); Index: linux-2.6/mm/pagepool.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6/mm/pagepool.c 2007-09-08 16:19:36.000000000 -0700 @@ -0,0 +1,77 @@ + +struct largepage { + /* First page struct */ + struct page page; + /* Second page struct. Must match struct page */ + unsigned long dontuse[2]; /* Flags / refcounters */ + struct page *first_page; /* Points back to first page struct*/ + void *virtual; /* Point to data. Overloads mapping */ + unsigned zeroing:1; + unsigned zero:1; + unsigned free:1; + unsigned unused:29; + compound_page_dtor dtor; + unsigned long order; +} + +struct page_pool { + void *start; + struct largepage *page; + int nr; + unsigned long reclaiming; + unsigned long allocating; + unsigned long zeroing; +} pool[MAX_NUM_NODES][32 - PAGE_SHIFT]; + +/* Setup stuff */ +__setup pagepool_setup("pagepool="); + +struct page *pagepool_alloc(struct zone *z, int order, gfp_t flags) +{ + int node = zone_to_nid(z); + struct page_pool *pp = &pool[node][order]; + int at = pp->allocating; + +retry: + at++; + if (at == nr) + at = 0; + page = pp->page + (at << pp->order); + if (!page->free) { + if (at != pp->allocating) + goto retry; + return NULL; + } + /* Check if this matches the zeroing status */ + pp->allocating = at; + /* Prep page */ + if (flags & __GFP_ZERO && !PagePoolZeroed(page)) + /* Zero page */ + return page; +} + +void pagepool_free(struct page *page) +{ + int node = page_to_nid(page); + struct page_pool *pp = &pool[node][order]; + + SetPagePoolFree(page); +} + +void pagepool_reclaim(int node, int nr) +{ + /* + * Search through zone following reclaim. Writeback + * and then try to unmap the pages + */ +} +/* Setup handling ! */ + +void setup_page_pools(int node) +{ + BUILD_BUG_ON(sizeof(struct largepage_struct) != + 2 * sizeof(struct page)); + /* Overlapping nodes */ + alloc_bootmem_node(node, n * sizeof(order)); +} +