diff -urNp ref/include/linux/vmalloc.h 2.4.20pre5aa2/include/linux/vmalloc.h --- ref/include/linux/vmalloc.h Thu Aug 29 02:13:20 2002 +++ 2.4.20pre5aa2/include/linux/vmalloc.h Fri Sep 6 01:18:24 2002 @@ -21,6 +21,8 @@ struct vm_struct { extern struct vm_struct * get_vm_area (unsigned long size, unsigned long flags); extern void vfree(void * addr); +#define vunmap(addr) vfree(addr) +extern void * vmap(struct page **pages, int count); extern void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot); extern long vread(char *buf, char *addr, unsigned long count); extern void vmfree_area_pages(unsigned long address, unsigned long size); diff -urNp ref/kernel/ksyms.c 2.4.20pre5aa2/kernel/ksyms.c --- ref/kernel/ksyms.c Fri Sep 6 01:18:21 2002 +++ 2.4.20pre5aa2/kernel/ksyms.c Fri Sep 6 01:18:35 2002 @@ -114,6 +114,7 @@ EXPORT_SYMBOL(kmalloc); EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); EXPORT_SYMBOL(__vmalloc); +EXPORT_SYMBOL(vmap); EXPORT_SYMBOL(vmalloc_to_page); #ifndef CONFIG_DISCONTIGMEM EXPORT_SYMBOL(contig_page_data); diff -urNp ref/mm/vmalloc.c 2.4.20pre5aa2/mm/vmalloc.c --- ref/mm/vmalloc.c Fri Sep 6 01:18:18 2002 +++ 2.4.20pre5aa2/mm/vmalloc.c Fri Sep 6 01:18:24 2002 @@ -94,7 +94,8 @@ void vmfree_area_pages(unsigned long add } static inline int alloc_area_pte (pte_t * pte, unsigned long address, - unsigned long size, int gfp_mask, pgprot_t prot) + unsigned long size, int gfp_mask, + pgprot_t prot, struct page ***pages) { unsigned long end; @@ -104,9 +105,20 @@ static inline int alloc_area_pte (pte_t end = PMD_SIZE; do { struct page * page; - spin_unlock(&init_mm.page_table_lock); - page = alloc_page(gfp_mask); - spin_lock(&init_mm.page_table_lock); + + if (!pages) { + spin_unlock(&init_mm.page_table_lock); + page = alloc_page(gfp_mask); + spin_lock(&init_mm.page_table_lock); + } else { + page = (**pages); + (*pages)++; + + /* Add a reference to the page so we can free later */ + if (page) + atomic_inc(&page->count); + + } if (!pte_none(*pte)) printk(KERN_ERR "alloc_area_pte: page already exists\n"); if (!page) @@ -118,7 +130,9 @@ static inline int alloc_area_pte (pte_t return 0; } -static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot) +static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, + unsigned long size, int gfp_mask, + pgprot_t prot, struct page ***pages) { unsigned long end; @@ -131,7 +145,7 @@ static inline int alloc_area_pmd(pmd_t * pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; - err = alloc_area_pte(pte, address, end - address, gfp_mask, prot); + err = alloc_area_pte(pte, address, end - address, gfp_mask, prot, pages); pte_kunmap(pte); if (err) return -ENOMEM; @@ -141,8 +155,11 @@ static inline int alloc_area_pmd(pmd_t * return 0; } -inline int vmalloc_area_pages (unsigned long address, unsigned long size, - int gfp_mask, pgprot_t prot) +static inline int __vmalloc_area_pages (unsigned long address, + unsigned long size, + int gfp_mask, + pgprot_t prot, + struct page ***pages) { pgd_t * dir; unsigned long end = address + size; @@ -160,7 +177,7 @@ inline int vmalloc_area_pages (unsigned break; ret = -ENOMEM; - if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot)) + if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages)) break; address = (address + PGDIR_SIZE) & PGDIR_MASK; @@ -173,6 +190,12 @@ inline int vmalloc_area_pages (unsigned return ret; } +int vmalloc_area_pages(unsigned long address, unsigned long size, + int gfp_mask, pgprot_t prot) +{ + return __vmalloc_area_pages(address, size, gfp_mask, prot, NULL); +} + struct vm_struct * get_vm_area(unsigned long size, unsigned long flags) { unsigned long addr; @@ -245,7 +268,29 @@ void * __vmalloc (unsigned long size, in if (!area) return NULL; addr = area->addr; - if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) { + if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, + prot, NULL)) { + vfree(addr); + return NULL; + } + return addr; +} + +void * vmap(struct page **pages, int count) +{ + void * addr; + struct vm_struct *area; + unsigned long size = count << PAGE_SHIFT; + + if (!size || size > (max_mapnr << PAGE_SHIFT)) + return NULL; + area = get_vm_area(size, VM_ALLOC); + if (!area) { + return NULL; + } + addr = area->addr; + if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, 0, + PAGE_KERNEL, &pages)) { vfree(addr); return NULL; }