diff -urN 2.4.19pre5/include/asm-alpha/module.h module-gfp/include/asm-alpha/module.h --- 2.4.19pre5/include/asm-alpha/module.h Tue Jan 22 18:53:53 2002 +++ module-gfp/include/asm-alpha/module.h Sat Mar 30 20:59:39 2002 @@ -4,8 +4,8 @@ * This file contains the alpha architecture specific module code. */ -#define module_map(x) vmalloc(x) -#define module_unmap(x) vfree(x) +#define module_map(x) alloc_exact(x) +#define module_unmap(x) free_exact((x), (x)->size) #define module_arch_init(x) alpha_module_init(x) #define arch_init_modules(x) alpha_init_modules(x) diff -urN 2.4.19pre5/include/asm-i386/module.h module-gfp/include/asm-i386/module.h --- 2.4.19pre5/include/asm-i386/module.h Tue Jan 22 18:53:54 2002 +++ module-gfp/include/asm-i386/module.h Sat Mar 30 20:59:39 2002 @@ -4,8 +4,8 @@ * This file contains the i386 architecture specific module code. */ -#define module_map(x) vmalloc(x) -#define module_unmap(x) vfree(x) +#define module_map(x) alloc_exact(x) +#define module_unmap(x) free_exact((x), (x)->size) #define module_arch_init(x) (0) #define arch_init_modules(x) do { } while (0) diff -urN 2.4.19pre5/include/linux/mm.h module-gfp/include/linux/mm.h --- 2.4.19pre5/include/linux/mm.h Sat Mar 30 00:12:05 2002 +++ module-gfp/include/linux/mm.h Sat Mar 30 20:59:39 2002 @@ -456,6 +456,9 @@ extern void FASTCALL(__free_pages(struct page *page, unsigned int order)); extern void FASTCALL(free_pages(unsigned long addr, unsigned int order)); +extern void * FASTCALL(alloc_exact(unsigned int size)); +extern void FASTCALL(free_exact(void * addr, unsigned int size)); + #define __free_page(page) __free_pages((page), 0) #define free_page(addr) free_pages((addr),0) diff -urN 2.4.19pre5/kernel/ksyms.c module-gfp/kernel/ksyms.c --- 2.4.19pre5/kernel/ksyms.c Sat Mar 30 00:12:05 2002 +++ module-gfp/kernel/ksyms.c Sat Mar 30 20:59:39 2002 @@ -97,6 +97,8 @@ EXPORT_SYMBOL(get_zeroed_page); EXPORT_SYMBOL(__free_pages); EXPORT_SYMBOL(free_pages); +EXPORT_SYMBOL(free_exact); +EXPORT_SYMBOL(alloc_exact); EXPORT_SYMBOL(num_physpages); EXPORT_SYMBOL(kmem_find_general_cachep); EXPORT_SYMBOL(kmem_cache_create); diff -urN 2.4.19pre5/mm/page_alloc.c module-gfp/mm/page_alloc.c --- 2.4.19pre5/mm/page_alloc.c Sat Mar 30 00:12:05 2002 +++ module-gfp/mm/page_alloc.c Sat Mar 30 20:59:51 2002 @@ -21,6 +21,7 @@ #include #include #include +#include int nr_swap_pages; int nr_active_pages; @@ -471,6 +472,54 @@ if (addr != 0) __free_pages(virt_to_page(addr), order); } + +static inline int nextorder(unsigned int x) +{ + int c = -PAGE_SHIFT; + while (x) { + x >>= 1; + c++; + } + if (c < 0) + c = 0; + return c; +} + +void * alloc_exact(unsigned int size) +{ + struct page *p, *w; + int order = nextorder(size); + + p = alloc_pages(GFP_KERNEL, order); + if (p) { + struct page *end = p + (1UL << order); + for (w = p+1; w < end; ++w) + set_page_count(w, 1); + for (w = p + (size>>PAGE_SHIFT)+1; w < end; ++w) + __free_pages(w, 0); + return (void *) page_address(p); + } + + return vmalloc(size); +} + +void free_exact(void * addr, unsigned int size) +{ + struct page * w; + unsigned long mptr = (unsigned long) addr; + int sz; + + if (mptr >= VMALLOC_START && mptr + size <= VMALLOC_END) { + vfree(addr); + return; + } + w = virt_to_page(addr); + for (sz = size; sz > 0; sz -= PAGE_SIZE, ++w) { + if (atomic_read(&w->count) != 1) + BUG(); + __free_pages(w, 0); + } +} /* * Total amount of free (allocatable) RAM: