--- mm/page_alloc.c | 14 ++++++++++++-- mm/rmap.c | 3 +++ mm/vmalloc.c | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) Index: linux-2.6/mm/page_alloc.c =================================================================== --- linux-2.6.orig/mm/page_alloc.c 2007-09-25 00:16:01.000000000 -0700 +++ linux-2.6/mm/page_alloc.c 2007-09-25 00:16:06.000000000 -0700 @@ -1259,7 +1259,7 @@ static noinline struct page *vcompound_a if (!pages) return NULL; - for (i = 0; i < nr_pages; i++) { + for (i = nr_pages - 1; i >=0; i--) { page = get_page_from_freelist(gfp_mask & ~__GFP_VFALLBACK, 0, zonelist, alloc_flags); if (!page) @@ -1274,6 +1274,10 @@ static noinline struct page *vcompound_a goto abort; prep_compound_page(pages[0], order); + printk("VC-N %p/%d", addr, order); + for (i = 0; i < nr_pages; i++) + printk(" %p", pages[i]); + printk("\n"); return pages[0]; abort: @@ -1298,7 +1302,8 @@ static void __vcompound_free(void *addr) struct page **pages; int i; struct page *page = vmalloc_to_page(addr); - int order = compound_order(page); + extern int vmalloc_order(struct page *); + int order = vmalloc_order(page); int nr_pages = 1 << order; destroy_compound_page(page, order); @@ -1310,11 +1315,16 @@ static void __vcompound_free(void *addr) __ClearPageVcompound(page); free_hot_page(page); + BUG_ON(page != pages[0]); + + printk("VC-F %p/%d %p", addr, order, page); for (i = 1; i < nr_pages; i++) { page = pages[i]; + printk(" %p", page); __ClearPageVcompound(page); __free_page(page); } + printk("\n"); kfree(pages); } Index: linux-2.6/mm/vmalloc.c =================================================================== --- linux-2.6.orig/mm/vmalloc.c 2007-09-25 00:15:09.000000000 -0700 +++ linux-2.6/mm/vmalloc.c 2007-09-25 00:16:06.000000000 -0700 @@ -669,9 +669,44 @@ EXPORT_SYMBOL(vmalloc); */ struct page *vmalloc_nth_page(struct page *page, int n) { - return vmalloc_to_page(vmalloc_address(page) + n * PAGE_SIZE); + void *addr; + struct page *p2; + + addr = vmalloc_address(page) + n * PAGE_SIZE; + p2 = vmalloc_to_page(addr); + +// printk("vmalloc_nth_page(%p, %d) addr=%p page=%p %p\n", +// page, n, addr, p2, pfn_to_page(page_to_pfn(p2))); + return p2; +} + +int vmalloc_order(struct page *page) +{ + void *addr = vmalloc_address(page); + struct vm_struct *vm; + + read_lock(&vmlist_lock); + vm = __find_vm_area(addr); + read_unlock(&vmlist_lock); + if (!vm) + return 0; +// printk("vmalloc_order(%p) pages=%d order=%d\n", +// page, vm->nr_pages, fls(vm->nr_pages) - 1); + return fls(vm->nr_pages) - 1; } +struct page **vmalloc_array(struct page *page) +{ + void *addr = vmalloc_address(page); + struct vm_struct *vm; + + read_lock(&vmlist_lock); + vm = __find_vm_area(addr); + read_unlock(&vmlist_lock); + if (!vm) + return NULL; + return vm->pages; +} /** * vmalloc_user - allocate zeroed virtually contiguous memory for userspace * @size: allocation size Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c 2007-09-25 00:15:09.000000000 -0700 +++ linux-2.6/mm/rmap.c 2007-09-25 00:16:06.000000000 -0700 @@ -547,6 +547,7 @@ static void __page_check_anon_rmap(struc void page_add_anon_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address) { + BUG_ON(PageTail(page)); VM_BUG_ON(!PageLocked(page)); VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end); if (atomic_inc_and_test(&page->_mapcount)) @@ -581,6 +582,7 @@ void page_add_new_anon_rmap(struct page */ void page_add_file_rmap(struct page *page) { + BUG_ON(PageTail(page)); if (atomic_inc_and_test(&page->_mapcount)) __inc_zone_page_state(page, NR_FILE_MAPPED); } @@ -613,6 +615,7 @@ void page_dup_rmap(struct page *page, st */ void page_remove_rmap(struct page *page, struct vm_area_struct *vma) { + BUG_ON(PageTail(page)); if (atomic_add_negative(-1, &page->_mapcount)) { if (unlikely(page_mapcount(page) < 0)) { printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page));