From fbb214aabaea95697460ccd6288995cd4592996d Mon Sep 17 00:00:00 2001 From: "Paolo \\'Blaisorblade\\' Giarrusso" Date: Mon, 23 Aug 2004 21:17:56 -0700 Subject: [PATCH] [PATCH] uml: Make malloc() call vmalloc if needed. Needed for hostfs on 2.6 host. From: Oleg Drokin , Jeff Dike , and me If size > 128K, with this patch malloc will call vmalloc; free will detect whether to call vfree or kfree or __real_free(). The 2.4 version could forget free()ing something; this has been fixed. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/user.h | 2 ++ arch/um/kernel/process_kern.c | 6 ++++++ arch/um/main.c | 40 +++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/arch/um/include/user.h b/arch/um/include/user.h index e9cf19eb11ad3..57ee9e2612284 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h @@ -15,6 +15,8 @@ extern void kfree(void *ptr); 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 diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 6e2e88b04663b..0853625a62256 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -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 @@ void *um_kmalloc_atomic(int size) 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); diff --git a/arch/um/main.c b/arch/um/main.c index ead5e2cf0f623..92ff6f9e544d5 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -163,10 +163,21 @@ extern void *__real_malloc(int); 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 <= 128 * 1024) /* kmalloc is good for only 128K */ + 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) @@ -180,9 +191,30 @@ void *__wrap_calloc(int n, int size) 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. + */ + if(CAN_KMALLOC()){ + if((addr >= uml_physmem) && (addr <= high_physmem)) + kfree(ptr); + else if((addr >= start_vm) && (addr <= end_vm)) + vfree(ptr); + else + __real_free(ptr); + } else __real_free(ptr); } -- 2.53.0