From: <blaisorblade_spam@yahoo.it>

From: Oleg Drokin <green@linuxhacker.ru>, Jeff Dike <jdike@addtoit.com>, 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 <blaisorblade_spam@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/um/include/user.h        |    2 +
 25-akpm/arch/um/kernel/process_kern.c |    6 +++++
 25-akpm/arch/um/main.c                |   40 ++++++++++++++++++++++++++++++----
 3 files changed, 44 insertions(+), 4 deletions(-)

diff -puN arch/um/include/user.h~uml-make-malloc-call-vmalloc-if-needed-needed-for-hostfs-on-26-host arch/um/include/user.h
--- 25/arch/um/include/user.h~uml-make-malloc-call-vmalloc-if-needed-needed-for-hostfs-on-26-host	2004-07-05 16:00:50.507342168 -0700
+++ 25-akpm/arch/um/include/user.h	2004-07-05 16:00:50.693313896 -0700
@@ -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 -puN arch/um/kernel/process_kern.c~uml-make-malloc-call-vmalloc-if-needed-needed-for-hostfs-on-26-host arch/um/kernel/process_kern.c
--- 25/arch/um/kernel/process_kern.c~uml-make-malloc-call-vmalloc-if-needed-needed-for-hostfs-on-26-host	2004-07-05 16:00:50.509341864 -0700
+++ 25-akpm/arch/um/kernel/process_kern.c	2004-07-05 16:00:50.694313744 -0700
@@ -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 -puN arch/um/main.c~uml-make-malloc-call-vmalloc-if-needed-needed-for-hostfs-on-26-host arch/um/main.c
--- 25/arch/um/main.c~uml-make-malloc-call-vmalloc-if-needed-needed-for-hostfs-on-26-host	2004-07-05 16:00:50.678316176 -0700
+++ 25-akpm/arch/um/main.c	2004-07-05 16:00:50.694313744 -0700
@@ -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);
 }
 
_