# __wrap_malloc now chooses between kmalloc and vmalloc based on the size of # the allocation. PAGE_SIZE or smaller go to kmalloc, anything larger goes # to vmalloc. # __wrap_free is now careful about freeing to the same allocator that allocated # the buffer. Index: um/arch/um/include/user.h =================================================================== --- um.orig/arch/um/include/user.h 2004-08-05 20:22:46.000000000 -0400 +++ um/arch/um/include/user.h 2004-08-05 20:23:14.000000000 -0400 @@ -15,6 +15,8 @@ extern int in_aton(char *str); extern int open_gdb_chan(void); extern int strlcpy(char *, const char *, int); +extern void *um_vmalloc(int size); +extern void vfree(void *ptr); #endif Index: um/arch/um/kernel/process_kern.c =================================================================== --- um.orig/arch/um/kernel/process_kern.c 2004-08-05 20:22:46.000000000 -0400 +++ um/arch/um/kernel/process_kern.c 2004-08-05 20:23:14.000000000 -0400 @@ -16,6 +16,7 @@ #include "linux/module.h" #include "linux/init.h" #include "linux/capability.h" +#include "linux/vmalloc.h" #include "linux/spinlock.h" #include "asm/unistd.h" #include "asm/mman.h" @@ -301,6 +302,11 @@ return(kmalloc(size, GFP_ATOMIC)); } +void *um_vmalloc(int size) +{ + return(vmalloc(size)); +} + unsigned long get_fault_addr(void) { return((unsigned long) current->thread.fault_addr); Index: um/arch/um/main.c =================================================================== --- um.orig/arch/um/main.c 2004-08-05 20:22:49.000000000 -0400 +++ um/arch/um/main.c 2004-08-05 20:23:14.000000000 -0400 @@ -178,10 +178,21 @@ void *__wrap_malloc(int size) { - if(CAN_KMALLOC()) - return(um_kmalloc(size)); - else + void *ret; + + if(!CAN_KMALLOC()) return(__real_malloc(size)); + else if(size <= PAGE_SIZE) /* finding contiguos pages is hard */ + ret = um_kmalloc(size); + else ret = um_vmalloc(size); + + /* glibc people insist that if malloc fails, errno should be + * set by malloc as well. So we do. + */ + if(ret == NULL) + errno = ENOMEM; + + return(ret); } void *__wrap_calloc(int n, int size) @@ -195,9 +206,35 @@ extern void __real_free(void *); +extern unsigned long high_physmem; + void __wrap_free(void *ptr) { - if(CAN_KMALLOC()) kfree(ptr); + unsigned long addr = (unsigned long) ptr; + + /* We need to know how the allocation happened, so it can be correctly + * freed. This is done by seeing what region of memory the pointer is + * in - + * physical memory - kmalloc/kfree + * kernel virtual memory - vmalloc/vfree + * anywhere else - malloc/free + * If kmalloc is not yet possible, then the kernel memory regions + * may not be set up yet, and the variables not initialized. So, + * free is called. + * + * CAN_KMALLOC is checked because it would be bad to free a buffer + * with kmalloc/vmalloc after they have been turned off during + * shutdown. + */ + + if((addr >= uml_physmem) && (addr <= high_physmem)){ + if(CAN_KMALLOC()) + kfree(ptr); + } + else if((addr >= start_vm) && (addr <= end_vm)){ + if(CAN_KMALLOC()) + vfree(ptr); + } else __real_free(ptr); }