--- include/linux/gfp.h | 1 + include/linux/mm.h | 18 ++++++++++++++++-- mm/page_alloc.c | 15 ++++++++++++--- mm/vmalloc.c | 18 +++++++++++++----- 4 files changed, 42 insertions(+), 10 deletions(-) Index: linux-2.6/include/linux/gfp.h =================================================================== --- linux-2.6.orig/include/linux/gfp.h 2007-09-13 14:26:14.000000000 -0700 +++ linux-2.6/include/linux/gfp.h 2007-09-13 14:27:15.000000000 -0700 @@ -43,6 +43,7 @@ struct vm_area_struct; #define __GFP_REPEAT ((__force gfp_t)0x400u) /* Retry the allocation. Might fail */ #define __GFP_NOFAIL ((__force gfp_t)0x800u) /* Retry for ever. Cannot fail */ #define __GFP_NORETRY ((__force gfp_t)0x1000u)/* Do not retry. Might fail */ +#define __GFP_VMALLOC ((__force gfp_t)0x2000u)/* Fall back to vmalloc for __GFP_COMP */ #define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */ #define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */ #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */ Index: linux-2.6/include/linux/mm.h =================================================================== --- linux-2.6.orig/include/linux/mm.h 2007-09-13 09:42:31.000000000 -0700 +++ linux-2.6/include/linux/mm.h 2007-09-13 14:34:57.000000000 -0700 @@ -313,10 +313,24 @@ static inline void get_page(struct page atomic_inc(&page->_count); } +static inline void *comp_address(struct page *page) +{ + if (PageVirt(page)) + return vmalloc_address(page); + else + return page_addrress(page) +} + static inline struct page *virt_to_head_page(const void *x) { - struct page *page = virt_to_page(x); - return compound_head(page); + if (x >= VMALLOC_START && x <= VMALLOC_END) { + return vmalloc_head(page); + } else { + struct page *page; + + page = virt_to_page(x); + return compound_head(page); + } } /* Index: linux-2.6/mm/page_alloc.c =================================================================== --- linux-2.6.orig/mm/page_alloc.c 2007-09-13 14:27:20.000000000 -0700 +++ linux-2.6/mm/page_alloc.c 2007-09-13 14:34:06.000000000 -0700 @@ -513,7 +513,7 @@ static void __free_pages_ok(struct page return; if (!PageHighMem(page)) - debug_check_no_locks_freed(page_address(page),PAGE_SIZE< PAGE_ALLOC_COSTLY_ORDER) goto nopage; @@ -1414,7 +1423,7 @@ fastcall unsigned long __get_free_pages( page = alloc_pages(gfp_mask, order); if (!page) return 0; - return (unsigned long) page_address(page); + return (unsigned long) comp_address(page); } EXPORT_SYMBOL(__get_free_pages); @@ -1431,7 +1440,7 @@ fastcall unsigned long get_zeroed_page(g page = alloc_pages(gfp_mask | __GFP_ZERO, 0); if (page) - return (unsigned long) page_address(page); + return (unsigned long) comp_address(page); return 0; } Index: linux-2.6/mm/vmalloc.c =================================================================== --- linux-2.6.orig/mm/vmalloc.c 2007-09-13 14:35:01.000000000 -0700 +++ linux-2.6/mm/vmalloc.c 2007-09-13 14:45:01.000000000 -0700 @@ -450,15 +450,23 @@ void *__vmalloc_area_node(struct vm_stru } for (i = 0; i < area->nr_pages; i++) { - if (node < 0) - area->pages[i] = alloc_page(gfp_mask); - else - area->pages[i] = alloc_pages_node(node, gfp_mask, 0); - if (unlikely(!area->pages[i])) { + struct page *page; + + page = alloc_pages_node(node, gfp_mask, 0); + if (unlikely(!pages)) { /* Successfully allocated i pages, free them in __vunmap() */ area->nr_pages = i; goto fail; } + if (gfp_mask && __GFP_COMP) { + __SetPageVmalloc(page); + if (i) { + __SetPageTail(page); + page->firstpage = area->pages[0]; + } else + __SetPageHead(page); + } + area->pages[i] = page; } if (map_vm_area(area, prot, &pages))