patch-2.4.21 linux-2.4.21/arch/x86_64/mm/modutil.c

Next file: linux-2.4.21/arch/x86_64/mm/numa.c
Previous file: linux-2.4.21/arch/x86_64/mm/k8topology.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/arch/x86_64/mm/modutil.c linux-2.4.21/arch/x86_64/mm/modutil.c
@@ -10,11 +10,23 @@
  
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/proto.h>
 
-static struct vm_struct * modvmlist = NULL;
+extern char _text[], _end[]; 
+
+/* Kernel mapping to make the kernel alias visible to 
+   /proc/kcore and /dev/mem 
+
+   RED-PEN may want vsyscall mappings too 
+ */
+
+static struct vm_struct kernel_mapping = { 
+	.addr = (void *)KERNEL_TEXT_START, 
+}; 
 
 void module_unmap (void * addr)
 {
@@ -26,9 +38,11 @@
 		printk("Trying to unmap module with bad address (%p)\n", addr);
 		return;
 	}
-	for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
+			write_unlock(&vmlist_lock); 
 			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
 			kfree(tmp);
 			return;
@@ -45,24 +59,55 @@
 	size = PAGE_ALIGN(size);
 	if (!size || size > MODULES_LEN) return NULL;
 		
+	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area) return NULL; 
+
+	memset(area, 0, sizeof(struct vm_struct));
+
+	size = round_up(size, PAGE_SIZE); 
+
 	addr = (void *) MODULES_VADDR;
-	for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+		void *next;
 		if (size + (unsigned long) addr < (unsigned long) tmp->addr)
 			break;
-		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+		next = (void *) (tmp->size + (unsigned long) tmp->addr);
+		if (next > addr)
+			addr = next;
+	}
+	if ((unsigned long) addr + size >= MODULES_END) { 
+		write_unlock(&vmlist_lock); 
+		kfree(area);
+		return NULL;
 	}
-	if ((unsigned long) addr + size >= MODULES_END) return NULL;
 	
-	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area) return NULL;
-	area->size = size + PAGE_SIZE;
+	area->size = size;
 	area->addr = addr;
 	area->next = *p;
 	*p = area;
+	write_unlock(&vmlist_lock); 
 
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
+	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL_EXECUTABLE)) {
 		module_unmap(addr);
 		return NULL;
 	}
 	return addr;
 }
+
+static int __init mod_vmlist_init(void)
+{
+	struct vm_struct *vm, **base;
+	write_lock(&vmlist_lock); 
+	for (base = &vmlist, vm = *base; vm; base = &vm->next, vm = *base) { 
+		if (vm->addr > (void *)KERNEL_TEXT_START) 
+			break; 
+	}  
+	kernel_mapping.size = _end - _text;
+	kernel_mapping.next = vm; 
+	*base = &kernel_mapping; 
+	write_unlock(&vmlist_lock); 
+	return 0;
+} 
+
+__initcall(mod_vmlist_init);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)