Virtual Compound Pages: vmalloc compound support --- mm/vmalloc.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) Index: linux-2.6/mm/vmalloc.c =================================================================== --- linux-2.6.orig/mm/vmalloc.c 2007-09-15 20:33:01.000000000 -0700 +++ linux-2.6/mm/vmalloc.c 2007-09-15 20:40:49.000000000 -0700 @@ -169,7 +169,7 @@ EXPORT_SYMBOL_GPL(map_vm_area); /* * Map a vmalloc()-space virtual address to the physical page. */ -struct page *vmalloc_to_page(void *vmalloc_addr) +struct page *vmalloc_to_page(const void *vmalloc_addr) { unsigned long addr = (unsigned long) vmalloc_addr; struct page *page = NULL; @@ -403,10 +403,24 @@ static void __vunmap(void *addr, int dea if (deallocate_pages) { int i; + int comp = PageCompound(area->pages[0]); for (i = 0; i < area->nr_pages; i++) { - BUG_ON(!area->pages[i]); - __free_page(area->pages[i]); + struct page *page = area->pages[i]; + + BUG_ON(!page); + if (comp) { + if (i) { + BUG_ON(page->first_page != area->pages[0] || + PageHead(page) || !PageTail(page)); + __ClearPageTail(page); + } + else { + BUG_ON(PageTail(page) || !PageHead(page)); + __ClearPageHead(page); + } + } + __free_page(page); } if (area->flags & VM_VPAGES) @@ -527,16 +541,26 @@ void *__vmalloc_area_node(struct vm_stru return NULL; } + if (nr_pages < 2) + gfp_mask &= ~__GFP_COMP; + 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 = alloc_pages_node(node, gfp_mask, 0); + + if (unlikely(!page)) { /* Successfully allocated i pages, free them in __vunmap() */ area->nr_pages = i; goto fail; } + if (gfp_mask & __GFP_COMP) { + if (i) { + __SetPageTail(page); + page->first_page = area->pages[0]; + } else { + __SetPageHead(page); + } + } + area->pages[i] = page; } if (map_vm_area(area, prot, &pages))