--- mm/page_alloc.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) Index: linux-2.6/mm/page_alloc.c =================================================================== --- linux-2.6.orig/mm/page_alloc.c 2007-09-24 18:12:36.000000000 -0700 +++ linux-2.6/mm/page_alloc.c 2007-09-24 18:12:42.000000000 -0700 @@ -60,6 +60,9 @@ long nr_swap_pages; int percpu_pagelist_fraction; static void __free_pages_ok(struct page *page, unsigned int order); +static struct page *vcompound_alloc(gfp_t, int, + struct zonelist *, unsigned long); + /* * results with 256, 32 in the lowmem_reserve sysctl: @@ -251,7 +254,7 @@ static void prep_compound_page(struct pa set_compound_order(page, order); __SetPageHead(page); for (i = 1; i < nr_pages; i++) { - struct page *p = page + i; + struct page *p = compound_nth_page(page, i); __SetPageTail(p); p->first_page = page; @@ -270,7 +273,7 @@ static void destroy_compound_page(struct bad_page(page); __ClearPageHead(page); for (i = 1; i < nr_pages; i++) { - struct page *p = page + i; + struct page *p = compound_nth_page(page, i); if (unlikely(!PageTail(p) | (p->first_page != page))) @@ -1208,9 +1211,6 @@ zonelist_scan: #ifdef CONFIG_VFALLBACK_ALWAYS if ((gfp_mask & __GFP_VFALLBACK) && system_state == SYSTEM_RUNNING) { - struct page *vcompound_alloc(gfp_t, int, - struct zonelist *, unsigned long); - page = vcompound_alloc(gfp_mask, order, zonelist, alloc_flags); } else @@ -1247,14 +1247,14 @@ try_next_zone: * page->first_page if PageTail(page) is set can be used to determine the * head page. */ -struct page *vcompound_alloc(gfp_t gfp_mask, int order, +static noinline struct page *vcompound_alloc(gfp_t gfp_mask, int order, struct zonelist *zonelist, unsigned long alloc_flags) { void *addr; struct page *page; int i; int nr_pages = 1 << order; - struct page **pages = kzalloc((nr_pages + 1) * sizeof(struct page *), + struct page **pages = kmalloc(nr_pages * sizeof(struct page *), gfp_mask & GFP_LEVEL_MASK); if (!pages) @@ -1268,26 +1268,20 @@ struct page *vcompound_alloc(gfp_t gfp_m /* Sets PageCompound which makes PageHead(page) true */ __SetPageVcompound(page); - if (i) { - page->first_page = pages[0]; - __SetPageTail(page); - } pages[i] = page; } - addr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); if (!addr) goto abort; + prep_compound_page(pages[0], order); return pages[0]; abort: - for (i = 0; i < nr_pages; i++) { + while (i-- > 0) { page = pages[i]; if (!page) continue; - __ClearPageTail(page); - __ClearPageHead(page); __ClearPageVcompound(page); __free_page(page); } @@ -1302,21 +1296,26 @@ abort: */ static void __vcompound_free(void *addr) { - struct page **pages = vunmap(addr); + struct page **pages; int i; + struct page *page = vmalloc_to_page(addr); + int order = compound_order(page); + int nr_pages = 1 << order; + + printk(KERN_ERR "__vcompound_free(%p) page=%p order=%d pages=%d\n", + addr, page, order, nr_pages); + destroy_compound_page(page, order); + pages = vunmap(addr); /* * First page will have zero refcount since it maintains state * for the compound and was decremented before we got here. */ - __ClearPageHead(pages[0]); - __ClearPageVcompound(pages[0]); - free_hot_page(pages[0]); + __ClearPageVcompound(page); + free_hot_page(page); - for (i = 1; pages[i]; i++) { - struct page *page = pages[i]; - - __ClearPageTail(page); + for (i = 1; i < nr_pages; i++) { + page = pages[i]; __ClearPageVcompound(page); __free_page(page); } @@ -1328,7 +1327,7 @@ static void vcompound_free_work(struct w __vcompound_free((void *)w); } -static void vcompound_free(void *addr) +static noinline void vcompound_free(void *addr) { if (in_interrupt()) { struct work_struct *w = addr;