--- include/linux/mm.h | 61 +++++++++++++++++++++++++++++++++-------------------- mm/vmalloc.c | 9 +++++++ 2 files changed, 48 insertions(+), 22 deletions(-) Index: linux-2.6/include/linux/mm.h =================================================================== --- linux-2.6.orig/include/linux/mm.h 2007-09-20 19:07:19.000000000 -0700 +++ linux-2.6/include/linux/mm.h 2007-09-20 19:08:28.000000000 -0700 @@ -294,6 +294,10 @@ static inline int get_page_unless_zero(s return atomic_inc_not_zero(&page->_count); } +/* + * compound_head() works on virtual compound pages since + * they also have the first_page pointer. + */ static inline struct page *compound_head(struct page *page) { if (unlikely(PageTail(page))) @@ -313,12 +317,6 @@ static inline void get_page(struct page atomic_inc(&page->_count); } -static inline struct page *virt_to_head_page(const void *x) -{ - struct page *page = virt_to_page(x); - return compound_head(page); -} - /* * Setup the page count before being freed into the page allocator for * the first time (boot or memory hotplug) @@ -334,33 +332,50 @@ void put_pages_list(struct list_head *pa void split_page(struct page *page, unsigned int order); /* - * Compound pages have a destructor function. Provide a - * prototype for that function and accessor functions. + * Compound pages have a destructor function (but not virtual compounds!). + * Provide a prototype for that function and accessor functions. * These are _only_ valid on the head of a PG_compound page. + * + * And these functions referencing page[1] will not work on a virtual + * compound page since the second page may not follow the first one + * directly. */ typedef void compound_page_dtor(struct page *); +struct page *vmalloc_to_page(const void *); +void *vmalloc_address(struct page *); + +static inline struct page *compound_part(struct page *page, int n) +{ + extern struct page *vmalloc_part(struct page *page, int n); + + if (likely(!PageVcompound(page))) + return page + n; + return vmalloc_part(page, n); +} + static inline void set_compound_page_dtor(struct page *page, compound_page_dtor *dtor) { - page[1].lru.next = (void *)dtor; + compound_part(page, 1)->lru.next = (void *)dtor; } static inline compound_page_dtor *get_compound_page_dtor(struct page *page) { - return (compound_page_dtor *)page[1].lru.next; + return (compound_page_dtor *)compound_part(page, 1)->lru.next; } -static inline int compound_order(struct page *page) +static inline void set_compound_order(struct page *page, unsigned long order) { - if (!PageHead(page)) - return 0; - return (unsigned long)page[1].lru.prev; + compound_part(page, 1)->lru.prev = (void *)order; } -static inline void set_compound_order(struct page *page, unsigned long order) +/* This is working on a compound page */ +static inline int compound_order(struct page *page) { - page[1].lru.prev = (void *)order; + if (likely(!PageHead(page))) + return 0; + return (unsigned long)compound_part(page, 1)->lru.prev; } /* @@ -1166,24 +1181,26 @@ static inline int is_vmalloc_addr(const return addr >= VMALLOC_START && addr < VMALLOC_END; } -static inline void *to_address(struct page *page) +static inline void *page_to_addr(struct page *page) { - extern void *vmalloc_address(struct page *); - if (unlikely(PageVcompound(page))) return vmalloc_address(page); return page_address(page); } -static inline struct page *to_page(void *x) +static inline struct page *addr_to_page(const void *x) { - extern struct page *vmalloc_to_page(const void *); - if (unlikely(is_vmalloc_addr(x))) return vmalloc_to_page(x); return virt_to_page(x); } +static inline struct page *virt_to_head_page(const void *x) +{ + struct page *page = addr_to_page(x); + return compound_head(page); +} + pgprot_t vm_get_page_prot(unsigned long vm_flags); struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr); int remap_pfn_range(struct vm_area_struct *, unsigned long addr, Index: linux-2.6/mm/vmalloc.c =================================================================== --- linux-2.6.orig/mm/vmalloc.c 2007-09-20 19:07:19.000000000 -0700 +++ linux-2.6/mm/vmalloc.c 2007-09-20 19:08:28.000000000 -0700 @@ -656,6 +656,15 @@ void *vmalloc(unsigned long size) } EXPORT_SYMBOL(vmalloc); +/* + * Given a pointer to the first page struct: + * Determine a pointer to the nth page. + */ +struct page *vmalloc_part(struct page *page, int n) +{ + return vmalloc_to_page(vmalloc_address(page) + n * PAGE_SIZE); +} + /** * vmalloc_user - allocate zeroed virtually contiguous memory for userspace * @size: allocation size