# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1016.1.2 -> 1.1016.1.3 # kernel/ksyms.c 1.77 -> 1.78 # mm/vmalloc.c 1.15 -> 1.16 # include/linux/vmalloc.h 1.2 -> 1.3 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/07/18 hch@lst.de 1.1016.1.3 # [PATCH] vmap() backport # # Hi Marcelo, # # this patch backports vmap() from 2.5. vmap() is needed for # # - XFS # - proper AGP support on ia64 and ppc # (- latest ALSA seems to have some use for in on 2.5) # # the 2.4 implementation is not as sound as the 2.5 one but far less # intrusive. It has been tested for more than a year in the XFS tree # and -aa and in -ac for a while. # -------------------------------------------- # diff -Nru a/include/linux/vmalloc.h b/include/linux/vmalloc.h --- a/include/linux/vmalloc.h Thu Aug 7 10:21:35 2003 +++ b/include/linux/vmalloc.h Thu Aug 7 10:21:35 2003 @@ -21,6 +21,9 @@ 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, + unsigned long flags, pgprot_t prot); 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 -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Thu Aug 7 10:21:35 2003 +++ b/kernel/ksyms.c Thu Aug 7 10:21:35 2003 @@ -112,6 +112,7 @@ EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); EXPORT_SYMBOL(__vmalloc); +EXPORT_SYMBOL(vmap); EXPORT_SYMBOL(vmalloc_to_page); EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(remap_page_range); diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c --- a/mm/vmalloc.c Thu Aug 7 10:21:35 2003 +++ b/mm/vmalloc.c Thu Aug 7 10:21:35 2003 @@ -93,7 +93,8 @@ } 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; @@ -103,9 +104,20 @@ 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) @@ -117,7 +129,9 @@ 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; @@ -129,7 +143,8 @@ pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; - if (alloc_area_pte(pte, address, end - address, gfp_mask, prot)) + if (alloc_area_pte(pte, address, end - address, + gfp_mask, prot, pages)) return -ENOMEM; address = (address + PMD_SIZE) & PMD_MASK; pmd++; @@ -137,8 +152,11 @@ 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; @@ -155,7 +173,7 @@ 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; @@ -168,6 +186,12 @@ 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, next; @@ -246,7 +270,30 @@ 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, + unsigned long flags, pgprot_t prot) +{ + 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, flags); + if (!area) { + return NULL; + } + addr = area->addr; + if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, 0, + prot, &pages)) { vfree(addr); return NULL; }