linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* New feature: Removal of the exceptions wich belongs to the init section
@ 2003-11-28 17:58 Tiago Sant' Anna
  2003-12-01  6:03 ` Rusty Russell
  0 siblings, 1 reply; 4+ messages in thread
From: Tiago Sant' Anna @ 2003-11-28 17:58 UTC (permalink / raw)
  To: rusty; +Cc: sisopiii-l, linux-kernel, julianofs

[-- Attachment #1: Type: text/plain, Size: 1217 bytes --]

Hello Rusty,

We, Juliano (julianofs@pop.com.br) and I (Tiago Sant' Anna
(sapuglha@yahoo.com.br) developed this patch.

It adds the following feature to the kernel:
	- Removal of the exceptions which belong to the init section from the
exceptions list, when discarding the init section of some module.

	There are some things to notice:
- As we needed to add a sort function, we did it inside the kernel, not
regarding to any architeture. Thought it would be interesting to the exceptions.

But there was a necessity to implement inside each architeture its own function
to compare the values from exception_table_entry, so we tried it; take a look at
arch/<some>/mm/extable.c in the function extable_cmp(). But we didn't had the
chance to test it in other architetures than i386, and we thought it would fail
with ppc and ppc64, because it already had some functions like this.

The sort_ex_table() function is implemented inside include/linux/extable.h.
It's based on one found in the ppc code. Also, inside this header we included
the declaration to extern extable_cmp() wich must be implemented inside each
architeture.

Cheers, and thanks for your e-mails helping us.

 
=> Tiago Sant' Anna and Juliano F. Silva

[-- Attachment #2: patch-init_exceptions_removal.diff --]
[-- Type: text/plain, Size: 18673 bytes --]

diff -Nur linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c linux-2.6.0-test9-modified/arch/alpha/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c	2003-10-25 16:42:52.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/alpha/mm/extable.c	2003-11-28 10:43:18.000000000 -0200
@@ -27,3 +27,18 @@
 
         return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+   Results:
+	equal: 0
+	ex1 less than ex2: -1
+	ex1 major than ex2: 1
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/arm/mm/extable.c linux-2.6.0-test9-modified/arch/arm/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/arm/mm/extable.c	2003-10-25 16:43:46.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/arm/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -35,3 +35,19 @@
 
 	return fixup != NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/arm26/mm/extable.c linux-2.6.0-test9-modified/arch/arm26/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/arm26/mm/extable.c	2003-10-25 16:43:29.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/arm26/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -38,3 +38,18 @@
         return fixup != NULL;
 }
 
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/cris/mm/extable.c linux-2.6.0-test9-modified/arch/cris/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/cris/mm/extable.c	2003-10-25 16:45:07.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/cris/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -46,3 +46,19 @@
         }
         return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/h8300/mm/extable.c linux-2.6.0-test9-modified/arch/h8300/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/h8300/mm/extable.c	2003-10-25 16:43:29.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/h8300/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -28,3 +28,19 @@
         }
         return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+   	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/i386/kernel/module.c linux-2.6.0-test9-modified/arch/i386/kernel/module.c
--- linux-2.6.0-test9-vanilla/arch/i386/kernel/module.c	2003-10-25 16:43:36.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/i386/kernel/module.c	2003-11-28 10:54:23.725411848 -0200
@@ -21,6 +21,9 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
 
 #if 0
 #define DEBUGP printk
@@ -35,13 +38,60 @@
 	return vmalloc(size);
 }
 
+/* Verify if the addr belongs to the init section */
+static inline int within_mod_init_section(unsigned long addr, 
+                                          void *start, unsigned long size)
+{
+	    return ((void *)addr >= start && (void *)addr < start + size);
+}
+
+/* Remove exception table entries that point to init area.
+ * It will be used in the unload of init section.
+ */
+void remove_init_exceptions(struct module *mod) {
+
+	static spinlock_t init_ex_remove = SPIN_LOCK_UNLOCKED;
+
+	const struct exception_table_entry *local;
+	unsigned int i;
+	int num_init_ex=0;
+
+
+	local = mod->extable;
+	i = 1;
+
+	while (i <= mod->num_exentries) {
+		if (within_mod_init_section((unsigned long) local->insn, mod->module_init, mod->init_size)) {
+			num_init_ex++;			
+		}
+		else break;
+		local = local+1;
+		i++;
+	}
+
+	local = mod->extable;
+
+	/* Move the pointer to remove the init exceptions */
+	spin_lock(init_ex_remove);
+		mod->extable += num_init_ex;
+		mod->num_exentries -= num_init_ex;
+	spin_unlock(init_ex_remove);
+
+	/* Unload the init exceptions */
+	for(i=0; i < num_init_ex; ++i)
+		kfree(local+i);
+}
+
 
 /* Free memory returned from module_alloc */
 void module_free(struct module *mod, void *module_region)
-{
+{	
+	/* Remove exception entries of the init section */
+	if (module_region == mod->module_init) {
+		remove_init_exceptions(mod);
+	}
+	
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff -Nur linux-2.6.0-test9-vanilla/arch/i386/mm/extable.c linux-2.6.0-test9-modified/arch/i386/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/i386/mm/extable.c	2003-10-25 16:44:54.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/i386/mm/extable.c	2003-11-28 10:43:38.000000000 -0200
@@ -56,3 +56,22 @@
 
 	return 0;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered.
+        Results:
+                equal: 0
+                ex1 less than ex2: -1
+                ex1 major than ex2: 1
+
+*/
+int extable_cmp(const struct exception_table_entry ex1, 
+		const struct exception_table_entry ex2) 
+{
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+     	return(0);
+}	     	
+
+
diff -Nur linux-2.6.0-test9-vanilla/arch/ia64/mm/extable.c linux-2.6.0-test9-modified/arch/ia64/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/ia64/mm/extable.c	2003-10-25 16:43:15.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/ia64/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -44,3 +44,19 @@
 	regs->cr_iip = fix & ~0xf;
 	ia64_psr(regs)->ri = fix & 0x3;		/* set continuation slot number */
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.addr < ex2.addr)
+		return(-1);
+	else if (ex1.addr > ex2.addr)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/m68k/mm/extable.c linux-2.6.0-test9-modified/arch/m68k/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/m68k/mm/extable.c	2003-10-25 16:44:46.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/m68k/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -31,3 +31,19 @@
 	return NULL;
 }
 
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
+
diff -Nur linux-2.6.0-test9-vanilla/arch/m68knommu/mm/extable.c linux-2.6.0-test9-modified/arch/m68knommu/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/m68knommu/mm/extable.c	2003-10-25 16:43:01.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/m68knommu/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -28,3 +28,19 @@
         }
         return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/mips/mm/extable.c linux-2.6.0-test9-modified/arch/mips/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/mips/mm/extable.c	2003-10-25 16:43:50.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/mips/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -28,3 +28,19 @@
         }
         return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/parisc/mm/extable.c linux-2.6.0-test9-modified/arch/parisc/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/parisc/mm/extable.c	2003-10-25 16:43:17.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/parisc/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -35,3 +35,18 @@
         return 0;
 }
 
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.addr < ex2.addr)
+		return(-1);
+	else if (ex1.addr > ex2.addr)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/ppc/mm/extable.c linux-2.6.0-test9-modified/arch/ppc/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/ppc/mm/extable.c	2003-10-25 16:44:43.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/ppc/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -12,35 +12,6 @@
 extern struct exception_table_entry __start___ex_table[];
 extern struct exception_table_entry __stop___ex_table[];
 
-/*
- * The exception table needs to be sorted because we use the macros
- * which put things into the exception table in a variety of segments
- * such as the prep, pmac, chrp, etc. segments as well as the init
- * segment and the main kernel text segment.
- */
-static inline void
-sort_ex_table(struct exception_table_entry *start,
-	      struct exception_table_entry *finish)
-{
-	struct exception_table_entry el, *p, *q;
-
-	/* insertion sort */
-	for (p = start + 1; p < finish; ++p) {
-		/* start .. p-1 is sorted */
-		if (p[0].insn < p[-1].insn) {
-			/* move element p down to its right place */
-			el = *p;
-			q = p;
-			do {
-				/* el comes before q[-1], move q[-1] up one */
-				q[0] = q[-1];
-				--q;
-			} while (q > start && el.insn < q[-1].insn);
-			*q = el;
-		}
-	}
-}
-
 void __init
 sort_exception_table(void)
 {
@@ -68,3 +39,19 @@
         }
 	return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/ppc64/mm/extable.c linux-2.6.0-test9-modified/arch/ppc64/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/ppc64/mm/extable.c	2003-10-25 16:43:20.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/ppc64/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -72,3 +72,20 @@
 	}
 	return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
+
diff -Nur linux-2.6.0-test9-vanilla/arch/s390/mm/extable.c linux-2.6.0-test9-modified/arch/s390/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/s390/mm/extable.c	2003-10-25 16:44:06.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/s390/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -32,3 +32,19 @@
 	}
 	return NULL;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/sh/mm/extable.c linux-2.6.0-test9-modified/arch/sh/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/sh/mm/extable.c	2003-10-25 16:42:48.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/sh/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -44,3 +44,19 @@
 
 	return 0;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/sparc/mm/extable.c linux-2.6.0-test9-modified/arch/sparc/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/sparc/mm/extable.c	2003-10-25 16:43:41.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/sparc/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -70,3 +70,19 @@
 
 	return entry->fixup;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/arch/sparc64/mm/extable.c linux-2.6.0-test9-modified/arch/sparc64/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/sparc64/mm/extable.c	2003-10-25 16:43:25.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/sparc64/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -73,3 +73,20 @@
 
 	return entry->fixup;
 }
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
+
diff -Nur linux-2.6.0-test9-vanilla/arch/x86_64/mm/extable.c linux-2.6.0-test9-modified/arch/x86_64/mm/extable.c
--- linux-2.6.0-test9-vanilla/arch/x86_64/mm/extable.c	2003-10-25 16:44:44.000000000 -0200
+++ linux-2.6.0-test9-modified/arch/x86_64/mm/extable.c	2003-11-28 08:32:44.000000000 -0200
@@ -55,3 +55,19 @@
 	return 0;
 }
 core_initcall(check_extable);
+
+/* Exception_table_entry Comparison. Only the field insn is considered. 
+	Results:
+		equal: 0
+		ex1 less than ex2: -1
+		ex1 major than ex2: 1
+	
+*/
+int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
+	
+	if (ex1.insn < ex2.insn)
+		return(-1);
+	else if (ex1.insn > ex2.insn)
+		return(1);
+	return(0);
+}
diff -Nur linux-2.6.0-test9-vanilla/include/linux/extable.h linux-2.6.0-test9-modified/include/linux/extable.h
--- linux-2.6.0-test9-vanilla/include/linux/extable.h	1969-12-31 21:00:00.000000000 -0300
+++ linux-2.6.0-test9-modified/include/linux/extable.h	2003-11-28 10:40:57.000000000 -0200
@@ -0,0 +1,51 @@
+#ifndef _EXTABLE_H
+#define _EXTABLE_H
+
+/*
+ * Functions regarding to exception's table.
+ *
+ *	* Written by Juliano Silva and Tiago Silva, 2003
+ *	
+ **/
+
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/sections.h>
+#include <linux/init.h>
+ 
+/* Exception_table_entry Comparison. Only the field insn is considered.
+ *   Results:
+ *            equal: 0
+ *            ex1 less than ex2: -1
+ *            ex1 major than ex2: 1
+ *                                                         */
+extern int extable_cmp(struct exception_table_entry ex1,
+                       struct exception_table_entry ex2);
+
+/* This code sorts an exception table. It is very used with modules code 
+ * void __init_or_module sort_ex_table(struct exception_table_entry *start,
+ * struct exception_table_entry *finish);
+ */
+void __init_or_module sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (extable_cmp(p[0], p[-1]) == -1) {
+		/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+			/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && extable_cmp(el, q[-1]) == -1);
+			*q = el;
+		}
+	}
+}
+
+#endif
diff -Nur linux-2.6.0-test9-vanilla/kernel/module.c linux-2.6.0-test9-modified/kernel/module.c
--- linux-2.6.0-test9-vanilla/kernel/module.c	2003-10-25 16:44:09.000000000 -0200
+++ linux-2.6.0-test9-modified/kernel/module.c	2003-11-28 10:41:17.000000000 -0200
@@ -37,6 +37,8 @@
 #include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 
+#include <linux/extable.h>
+
 #if 0
 #define DEBUGP printk
 #else
@@ -1379,6 +1381,7 @@
 }
 #endif
 
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
 static struct module *load_module(void __user *umod,
@@ -1615,6 +1618,11 @@
 	mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
 	mod->extable = (void *)sechdrs[exindex].sh_addr;
 
+        /* Classifying the exception table */
+        sort_ex_table((struct exception_table_entry *)mod->extable,
+                      (struct exception_table_entry *)mod->extable +
+                                mod->num_exentries);
+
 	/* Now do relocations. */
 	for (i = 1; i < hdr->e_shnum; i++) {
 		const char *strtab = (char *)sechdrs[strindex].sh_addr;


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: New feature: Removal of the exceptions wich belongs to the init section
  2003-11-28 17:58 New feature: Removal of the exceptions wich belongs to the init section Tiago Sant' Anna
@ 2003-12-01  6:03 ` Rusty Russell
  2003-12-17 17:10   ` [PATCH] " Juliano F Silva
  0 siblings, 1 reply; 4+ messages in thread
From: Rusty Russell @ 2003-12-01  6:03 UTC (permalink / raw)
  To: Tiago Sant' Anna; +Cc: sisopiii-l, linux-kernel, julianofs

In message <20031128155853.33283fec.sapuglha@yahoo.com.br> you write:
> Hello Rusty,

Hi,

> We, Juliano (julianofs@pop.com.br) and I (Tiago Sant' Anna
> (sapuglha@yahoo.com.br) developed this patch.

	I've commented on your patch: I hope you find my feedback
useful.

> diff -Nur linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c linux-2.6.0-test9-modified/arch/alpha/mm/extable.c
> --- linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c	2003-10-25 16:42:52.000000000 -0200
> +++ linux-2.6.0-test9-modified/arch/alpha/mm/extable.c	2003-11-28 10:43:18.000000000 -0200
> @@ -27,3 +27,18 @@
>  
>          return NULL;
>  }

It's generally not a good idea to write code for architectures which
you don't have access to, but to leave them for arch maintainers to
sort out.

> +/* Exception_table_entry Comparison. Only the field insn is considered. 
> +   Results:
> +	equal: 0
> +	ex1 less than ex2: -1
> +	ex1 major than ex2: 1
> +*/

This comment is a little verbose: I would simply say:

/* Compare two exception table entries: < 0 if ex1 comes before ex2. */

> +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) {
> +	
> +	if (ex1.insn < ex2.insn)
> +		return(-1);
> +	else if (ex1.insn > ex2.insn)
> +		return(1);
> +	return(0);
> +}

And it can be implemented as "return (long)ex1.insn - ex2.insn;",
making it a candidate for an inline function in the asm/uaccess.h
header.

> +/* Verify if the addr belongs to the init section */
> +static inline int within_mod_init_section(unsigned long addr, 
> +                                          void *start, unsigned long size)
> +{
> +	    return ((void *)addr >= start && (void *)addr < start + size);
> +}
> +
> +/* Remove exception table entries that point to init area.
> + * It will be used in the unload of init section.
> + */
> +void remove_init_exceptions(struct module *mod) {

This comment is not quite true.  The exception entries themselves are
in the __ex_table section, which is in the module code.  Some of the
"insn" pointers are into the module init section, which is to be
discarded.

This function should be in kernel/extable.c.

> +
> +	static spinlock_t init_ex_remove = SPIN_LOCK_UNLOCKED;

Do not invent your own lock.  You only need to protect against the
exception table walk by other CPUs, for which modlist_lock is
sufficient.

> +
> +	const struct exception_table_entry *local;
> +	unsigned int i;
> +	int num_init_ex=0;
> +
> +
> +	local = mod->extable;
> +	i = 1;
> +
> +	while (i <= mod->num_exentries) {
> +		if (within_mod_init_section((unsigned long) local->insn, mod->module_init, mod->init_size)) {
> +			num_init_ex++;			
> +		}
> +		else break;
> +		local = local+1;
> +		i++;
> +	}
> +
> +	local = mod->extable;

This code is incorrect.  The init section could be before or after the
core section, meaning that all the init-related exceptions will be at
the start, or at the end.  So, the code would look like this:

void remove_init_exceptions(struct module *mod)
{
	int i;

	if (!mod->module_init)
		return;

	spin_lock(&modlist_lock);
	if (mod->module_init > mod->module_core) {
		/* init exception entries at the end.  Trim */
		for (i = mod->num_exentries-1; i >= 0; i--)
			if (within(mod->extable[i].insn,
				   mod->module_init, mod->init_size))
				mod->num_exentries--;
	} else {
		/* init exception entries at the start.  Move ptr. */
		for (i = 0; i < mod->num_exentries; i++) {
			if (!within(mod->extable[i].insn,
				    mod->module_init, mod->init_size))
				break;
		}
		mod->extable += i;
		mod->num_exentries -= i;
	}
	spin_nulock(&modlist_lock);
}
		
> +	/* Unload the init exceptions */
> +	for(i=0; i < num_init_ex; ++i)
> +		kfree(local+i);

This doesn't make sense: these are not pointers, but are part of
module->core!  They will be freed in the normal way.

>  /* Free memory returned from module_alloc */
>  void module_free(struct module *mod, void *module_region)
> -{
> +{	
> +	/* Remove exception entries of the init section */
> +	if (module_region == mod->module_init) {
> +		remove_init_exceptions(mod);
> +	}
> +	

Call this from kernel/module.c directly.

> +++ linux-2.6.0-test9-modified/include/linux/extable.h	2003-11-28 10:4
0:57.000000000 -0200
> @@ -0,0 +1,51 @@
> +#ifndef _EXTABLE_H
> +#define _EXTABLE_H
> +
> +/*
> + * Functions regarding to exception's table.
> + *
> + *	* Written by Juliano Silva and Tiago Silva, 2003
> + *	
> + **/
> +
> +
> +#include <linux/module.h>
> +#include <asm/uaccess.h>
> +#include <asm/sections.h>
> +#include <linux/init.h>
> + 
> +/* Exception_table_entry Comparison. Only the field insn is considered.
> + *   Results:
> + *            equal: 0
> + *            ex1 less than ex2: -1
> + *            ex1 major than ex2: 1
> + *                                                         */
> +extern int extable_cmp(struct exception_table_entry ex1,
> +                       struct exception_table_entry ex2);
> +
> +/* This code sorts an exception table. It is very used with modules code 
> + * void __init_or_module sort_ex_table(struct exception_table_entry *start,
> + * struct exception_table_entry *finish);
> + */
> +void __init_or_module sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish)

Never put non-inline functions in a header file.  And never inline a
function this large.

Since this is only called from module.c, perhaps put it in
include/linux/moduleloader.h and the code in extable.c.

Hope that helps,
Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] Re: New feature: Removal of the exceptions wich belongs to  the init section
  2003-12-01  6:03 ` Rusty Russell
@ 2003-12-17 17:10   ` Juliano F Silva
  2003-12-17 17:17     ` Tiago Sant' Anna
  0 siblings, 1 reply; 4+ messages in thread
From: Juliano F Silva @ 2003-12-17 17:10 UTC (permalink / raw)
  To: Rusty Russell, Tiago Sant' Anna; +Cc: sisopiii-l, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6893 bytes --]

Hi Rusty,

Tiago (sapuglha@yahoo.com.br) and I (julianofs@pop.com.br) fixed the patch
as you suggested.

We would like to comment your citation below.

>This code is incorrect. The init section could be before or after the
> core section, meaning that all the init-related exceptions will be at
> the start, or at the end. So, the code would look like this:

In this patch we classify the exception table by an increasing order. So to
verify if an exception belongs to the init section, we consider the address
of the init section (module_init) until module_init + init_size. In this
case, we believe that the address of the core section doesn't intervenes on
the code.

Thanks a lot,

Juliano F. Silva and Tiago S. Silva

----- Original Message ----- 
From: "Rusty Russell" <rusty@rustcorp.com.au>
To: "Tiago Sant' Anna" <sapuglha@yahoo.com.br>
Cc: <sisopiii-l@cscience.org>; <linux-kernel@vger.kernel.org>;
<julianofs@pop.com.br>
Sent: Monday, December 01, 2003 3:03 AM
Subject: Re: New feature: Removal of the exceptions wich belongs to the init
section


> In message <20031128155853.33283fec.sapuglha@yahoo.com.br> you write:
> > Hello Rusty,
>
> Hi,
>
> > We, Juliano (julianofs@pop.com.br) and I (Tiago Sant' Anna
> > (sapuglha@yahoo.com.br) developed this patch.
>
> I've commented on your patch: I hope you find my feedback
> useful.
>
> > diff -Nur linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c
linux-2.6.0-test9-modified/arch/alpha/mm/extable.c
> > --- linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c 2003-10-25
16:42:52.000000000 -0200
> > +++ linux-2.6.0-test9-modified/arch/alpha/mm/extable.c 2003-11-28
10:43:18.000000000 -0200
> > @@ -27,3 +27,18 @@
> >
> >          return NULL;
> >  }
>
> It's generally not a good idea to write code for architectures which
> you don't have access to, but to leave them for arch maintainers to
> sort out.
>
> > +/* Exception_table_entry Comparison. Only the field insn is considered.
> > +   Results:
> > + equal: 0
> > + ex1 less than ex2: -1
> > + ex1 major than ex2: 1
> > +*/
>
> This comment is a little verbose: I would simply say:
>
> /* Compare two exception table entries: < 0 if ex1 comes before ex2. */
>
> > +int extable_cmp(const struct exception_table_entry ex1, const struct
exception_table_entry ex2) {
> > +
> > + if (ex1.insn < ex2.insn)
> > + return(-1);
> > + else if (ex1.insn > ex2.insn)
> > + return(1);
> > + return(0);
> > +}
>
> And it can be implemented as "return (long)ex1.insn - ex2.insn;",
> making it a candidate for an inline function in the asm/uaccess.h
> header.
>
> > +/* Verify if the addr belongs to the init section */
> > +static inline int within_mod_init_section(unsigned long addr,
> > +                                          void *start, unsigned long
size)
> > +{
> > +     return ((void *)addr >= start && (void *)addr < start + size);
> > +}
> > +
> > +/* Remove exception table entries that point to init area.
> > + * It will be used in the unload of init section.
> > + */
> > +void remove_init_exceptions(struct module *mod) {
>
> This comment is not quite true.  The exception entries themselves are
> in the __ex_table section, which is in the module code.  Some of the
> "insn" pointers are into the module init section, which is to be
> discarded.
>
> This function should be in kernel/extable.c.
>
> > +
> > + static spinlock_t init_ex_remove = SPIN_LOCK_UNLOCKED;
>
> Do not invent your own lock.  You only need to protect against the
> exception table walk by other CPUs, for which modlist_lock is
> sufficient.
>
> > +
> > + const struct exception_table_entry *local;
> > + unsigned int i;
> > + int num_init_ex=0;
> > +
> > +
> > + local = mod->extable;
> > + i = 1;
> > +
> > + while (i <= mod->num_exentries) {
> > + if (within_mod_init_section((unsigned long) local->insn,
mod->module_init, mod->init_size)) {
> > + num_init_ex++;
> > + }
> > + else break;
> > + local = local+1;
> > + i++;
> > + }
> > +
> > + local = mod->extable;
>
> This code is incorrect.  The init section could be before or after the
> core section, meaning that all the init-related exceptions will be at
> the start, or at the end.  So, the code would look like this:
>
> void remove_init_exceptions(struct module *mod)
> {
> int i;
>
> if (!mod->module_init)
> return;
>
> spin_lock(&modlist_lock);
> if (mod->module_init > mod->module_core) {
> /* init exception entries at the end.  Trim */
> for (i = mod->num_exentries-1; i >= 0; i--)
> if (within(mod->extable[i].insn,
>    mod->module_init, mod->init_size))
> mod->num_exentries--;
> } else {
> /* init exception entries at the start.  Move ptr. */
> for (i = 0; i < mod->num_exentries; i++) {
> if (!within(mod->extable[i].insn,
>     mod->module_init, mod->init_size))
> break;
> }
> mod->extable += i;
> mod->num_exentries -= i;
> }
> spin_nulock(&modlist_lock);
> }
>
> > + /* Unload the init exceptions */
> > + for(i=0; i < num_init_ex; ++i)
> > + kfree(local+i);
>
> This doesn't make sense: these are not pointers, but are part of
> module->core!  They will be freed in the normal way.
>
> >  /* Free memory returned from module_alloc */
> >  void module_free(struct module *mod, void *module_region)
> > -{
> > +{
> > + /* Remove exception entries of the init section */
> > + if (module_region == mod->module_init) {
> > + remove_init_exceptions(mod);
> > + }
> > +
>
> Call this from kernel/module.c directly.
>
> > +++ linux-2.6.0-test9-modified/include/linux/extable.h 2003-11-28 10:4
> 0:57.000000000 -0200
> > @@ -0,0 +1,51 @@
> > +#ifndef _EXTABLE_H
> > +#define _EXTABLE_H
> > +
> > +/*
> > + * Functions regarding to exception's table.
> > + *
> > + * * Written by Juliano Silva and Tiago Silva, 2003
> > + *
> > + **/
> > +
> > +
> > +#include <linux/module.h>
> > +#include <asm/uaccess.h>
> > +#include <asm/sections.h>
> > +#include <linux/init.h>
> > +
> > +/* Exception_table_entry Comparison. Only the field insn is considered.
> > + *   Results:
> > + *            equal: 0
> > + *            ex1 less than ex2: -1
> > + *            ex1 major than ex2: 1
> > + *                                                         */
> > +extern int extable_cmp(struct exception_table_entry ex1,
> > +                       struct exception_table_entry ex2);
> > +
> > +/* This code sorts an exception table. It is very used with modules
code
> > + * void __init_or_module sort_ex_table(struct exception_table_entry
*start,
> > + * struct exception_table_entry *finish);
> > + */
> > +void __init_or_module sort_ex_table(struct exception_table_entry
*start, struct exception_table_entry *finish)
>
> Never put non-inline functions in a header file.  And never inline a
> function this large.
>
> Since this is only called from module.c, perhaps put it in
> include/linux/moduleloader.h and the code in extable.c.
>
> Hope that helps,
> Rusty.
> --
>   Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
>

[-- Attachment #2: patch-init_exceptions_removal-version2-test11.diff --]
[-- Type: application/octet-stream, Size: 7266 bytes --]

diff -Nur linux-2.6.0-test11/Makefile linux-2.6.0-test11-modified/Makefile
--- linux-2.6.0-test11/Makefile	2003-11-26 18:44:43.000000000 -0200
+++ linux-2.6.0-test11-modified/Makefile	2003-12-02 15:12:34.000000000 -0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -test11
+EXTRAVERSION = -test11-so3
diff -Nur linux-2.6.0-test11/arch/i386/kernel/module.c linux-2.6.0-test11-modified/arch/i386/kernel/module.c
--- linux-2.6.0-test11/arch/i386/kernel/module.c	2003-11-26 18:44:07.000000000 -0200
+++ linux-2.6.0-test11-modified/arch/i386/kernel/module.c	2003-12-02 15:17:46.000000000 -0200
@@ -35,13 +35,10 @@
 	return vmalloc(size);
 }
 
-
 /* Free memory returned from module_alloc */
 void module_free(struct module *mod, void *module_region)
-{
+{	
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff -Nur linux-2.6.0-test11/drivers/base/Kconfig linux-2.6.0-test11-modified/drivers/base/Kconfig
--- linux-2.6.0-test11/drivers/base/Kconfig	2003-11-26 18:43:09.000000000 -0200
+++ linux-2.6.0-test11-modified/drivers/base/Kconfig	2003-12-02 15:10:51.000000000 -0200
@@ -8,4 +8,7 @@
 	  require hotplug firmware loading support, but a module built outside
 	  the kernel tree does.
 
+config SISOP3
+	tristate "Modulo de SO3"
+
 endmenu
diff -Nur linux-2.6.0-test11/drivers/base/Makefile linux-2.6.0-test11-modified/drivers/base/Makefile
--- linux-2.6.0-test11/drivers/base/Makefile	2003-11-26 18:45:22.000000000 -0200
+++ linux-2.6.0-test11-modified/drivers/base/Makefile	2003-12-02 15:10:51.000000000 -0200
@@ -6,3 +6,4 @@
 obj-y			+= power/
 obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o  memblk.o
+obj-$(CONFIG_SISOP3) += sisop3.o
diff -Nur linux-2.6.0-test11/drivers/base/sisop3.c linux-2.6.0-test11-modified/drivers/base/sisop3.c
--- linux-2.6.0-test11/drivers/base/sisop3.c	1969-12-31 21:00:00.000000000 -0300
+++ linux-2.6.0-test11-modified/drivers/base/sisop3.c	2003-12-02 15:10:51.000000000 -0200
@@ -0,0 +1,11 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+/* Dummy function in the init section which causes an extable entry */
+int __init function_with_exception_init(void *uaddr, void *addr)
+{
+	return copy_from_user(addr, uaddr, 4);
+}
+
+MODULE_LICENSE("GPL");
diff -Nur linux-2.6.0-test11/include/asm-i386/uaccess.h linux-2.6.0-test11-modified/include/asm-i386/uaccess.h
--- linux-2.6.0-test11/include/asm-i386/uaccess.h	2003-11-26 18:43:07.000000000 -0200
+++ linux-2.6.0-test11-modified/include/asm-i386/uaccess.h	2003-12-02 15:10:52.000000000 -0200
@@ -123,6 +123,15 @@
 	unsigned long insn, fixup;
 };
 
+/* Compare two exception table entries: < 0 if ex1 comes before ex2 */
+static inline int extable_cmp(const struct exception_table_entry ex1, 
+                const struct exception_table_entry ex2)
+{
+	return (long)ex1.insn - ex2.insn;
+}           
+
+
+
 extern int fixup_exception(struct pt_regs *regs);
 
 /*
diff -Nur linux-2.6.0-test11/include/linux/moduleloader.h linux-2.6.0-test11-modified/include/linux/moduleloader.h
--- linux-2.6.0-test11/include/linux/moduleloader.h	2003-11-26 18:43:40.000000000 -0200
+++ linux-2.6.0-test11-modified/include/linux/moduleloader.h	2003-12-02 15:10:52.000000000 -0200
@@ -44,4 +44,8 @@
 /* Any cleanup needed when module leaves. */
 void module_arch_cleanup(struct module *mod);
 
+/* This code sorts an exception table. It is very used with modules code */
+void sort_ex_table(struct exception_table_entry *start,
+                   struct exception_table_entry *finish);
+
 #endif
diff -Nur linux-2.6.0-test11/kernel/extable.c linux-2.6.0-test11-modified/kernel/extable.c
--- linux-2.6.0-test11/kernel/extable.c	2003-11-26 18:43:32.000000000 -0200
+++ linux-2.6.0-test11-modified/kernel/extable.c	2003-12-02 15:10:52.000000000 -0200
@@ -19,6 +19,8 @@
 #include <asm/uaccess.h>
 #include <asm/sections.h>
 
+#include <linux/moduleloader.h>
+
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
 
@@ -45,3 +47,26 @@
 
 	return module_text_address(addr) != NULL;
 }
+
+
+void sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+		
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (extable_cmp(p[0], p[-1]) == -1) {
+		/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && extable_cmp(el, q[-1]) == -1);
+				*q = el;
+		}
+	}
+}
+							
diff -Nur linux-2.6.0-test11/kernel/module.c linux-2.6.0-test11-modified/kernel/module.c
--- linux-2.6.0-test11/kernel/module.c	2003-11-26 18:44:57.000000000 -0200
+++ linux-2.6.0-test11-modified/kernel/module.c	2003-12-02 15:10:52.000000000 -0200
@@ -1076,6 +1076,42 @@
 	return ret;
 }
 
+static inline int within(unsigned long addr, void *start, unsigned long size)
+{
+	return ((void *)addr >= start && (void *)addr < start + size);
+}
+
+/* Remove exception table entries which belongs to this module's init area */
+void remove_init_exceptions(struct module *mod) 
+{
+	const struct exception_table_entry *local;
+	unsigned int i;
+	int num_init_ex=0;
+
+	if (!mod->module_init)
+		return;
+
+	local = mod->extable;
+	i = 1;
+	while (i <= mod->num_exentries) {
+		if (within((unsigned long) local->insn, mod->module_init, 
+		            mod->init_size)) {
+			num_init_ex++;
+		}
+		else break;
+		local = local+1;
+		i++;
+	}
+
+	/* Move the pointer to remove the init exceptions */
+	spin_lock(&modlist_lock);
+		mod->extable += num_init_ex;
+		mod->num_exentries -= num_init_ex;
+	spin_unlock(&modlist_lock);
+}
+
+
+
 /* Free a module, remove from lists, etc (must hold module mutex). */
 static void free_module(struct module *mod)
 {
@@ -1615,6 +1651,11 @@
 	mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
 	mod->extable = (void *)sechdrs[exindex].sh_addr;
 
+        /* Classifying the exception table */
+        sort_ex_table((struct exception_table_entry *)mod->extable,
+                      (struct exception_table_entry *)mod->extable +
+                                mod->num_exentries);
+
 	/* Now do relocations. */
 	for (i = 1; i < hdr->e_shnum; i++) {
 		const char *strtab = (char *)sechdrs[strindex].sh_addr;
@@ -1753,6 +1794,7 @@
 	mod->state = MODULE_STATE_LIVE;
 	/* Drop initial reference. */
 	module_put(mod);
+	remove_init_exceptions(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
@@ -1762,11 +1804,6 @@
 	return 0;
 }
 
-static inline int within(unsigned long addr, void *start, unsigned long size)
-{
-	return ((void *)addr >= start && (void *)addr < start + size);
-}
-
 #ifdef CONFIG_KALLSYMS
 static const char *get_ksymbol(struct module *mod,
 			       unsigned long addr,

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Re: New feature: Removal of the exceptions wich belongs to  the init section
  2003-12-17 17:10   ` [PATCH] " Juliano F Silva
@ 2003-12-17 17:17     ` Tiago Sant' Anna
  0 siblings, 0 replies; 4+ messages in thread
From: Tiago Sant' Anna @ 2003-12-17 17:17 UTC (permalink / raw)
  To: Juliano F Silva; +Cc: Rusty Russell, sisopiii-l, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 7600 bytes --]

We're sorry, the patch sent in the last e-mail contains some debug stuff
inside. This new version is clean.

Maybe on Wed, 17 Dec 2003 14:10:08 -0300
Juliano F Silva wrote:

| Hi Rusty,
| 
| Tiago (sapuglha@yahoo.com.br) and I (julianofs@pop.com.br) fixed the patch
| as you suggested.
| 
| We would like to comment your citation below.
| 
| >This code is incorrect. The init section could be before or after the
| > core section, meaning that all the init-related exceptions will be at
| > the start, or at the end. So, the code would look like this:
| 
| In this patch we classify the exception table by an increasing order. So to
| verify if an exception belongs to the init section, we consider the address
| of the init section (module_init) until module_init + init_size. In this
| case, we believe that the address of the core section doesn't intervenes on
| the code.
| 
| Thanks a lot,
| 
| Juliano F. Silva and Tiago S. Silva
| 
| ----- Original Message ----- 
| From: "Rusty Russell" <rusty@rustcorp.com.au>
| To: "Tiago Sant' Anna" <sapuglha@yahoo.com.br>
| Cc: <sisopiii-l@cscience.org>; <linux-kernel@vger.kernel.org>;
| <julianofs@pop.com.br>
| Sent: Monday, December 01, 2003 3:03 AM
| Subject: Re: New feature: Removal of the exceptions wich belongs to the init
| section
| 
| 
| > In message <20031128155853.33283fec.sapuglha@yahoo.com.br> you write:
| > > Hello Rusty,
| >
| > Hi,
| >
| > > We, Juliano (julianofs@pop.com.br) and I (Tiago Sant' Anna
| > > (sapuglha@yahoo.com.br) developed this patch.
| >
| > I've commented on your patch: I hope you find my feedback
| > useful.
| >
| > > diff -Nur linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c
| linux-2.6.0-test9-modified/arch/alpha/mm/extable.c
| > > --- linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c 2003-10-25
| 16:42:52.000000000 -0200
| > > +++ linux-2.6.0-test9-modified/arch/alpha/mm/extable.c 2003-11-28
| 10:43:18.000000000 -0200
| > > @@ -27,3 +27,18 @@
| > >
| > >          return NULL;
| > >  }
| >
| > It's generally not a good idea to write code for architectures which
| > you don't have access to, but to leave them for arch maintainers to
| > sort out.
| >
| > > +/* Exception_table_entry Comparison. Only the field insn is considered.
| > > +   Results:
| > > + equal: 0
| > > + ex1 less than ex2: -1
| > > + ex1 major than ex2: 1
| > > +*/
| >
| > This comment is a little verbose: I would simply say:
| >
| > /* Compare two exception table entries: < 0 if ex1 comes before ex2. */
| >
| > > +int extable_cmp(const struct exception_table_entry ex1, const struct
| exception_table_entry ex2) {
| > > +
| > > + if (ex1.insn < ex2.insn)
| > > + return(-1);
| > > + else if (ex1.insn > ex2.insn)
| > > + return(1);
| > > + return(0);
| > > +}
| >
| > And it can be implemented as "return (long)ex1.insn - ex2.insn;",
| > making it a candidate for an inline function in the asm/uaccess.h
| > header.
| >
| > > +/* Verify if the addr belongs to the init section */
| > > +static inline int within_mod_init_section(unsigned long addr,
| > > +                                          void *start, unsigned long
| size)
| > > +{
| > > +     return ((void *)addr >= start && (void *)addr < start + size);
| > > +}
| > > +
| > > +/* Remove exception table entries that point to init area.
| > > + * It will be used in the unload of init section.
| > > + */
| > > +void remove_init_exceptions(struct module *mod) {
| >
| > This comment is not quite true.  The exception entries themselves are
| > in the __ex_table section, which is in the module code.  Some of the
| > "insn" pointers are into the module init section, which is to be
| > discarded.
| >
| > This function should be in kernel/extable.c.
| >
| > > +
| > > + static spinlock_t init_ex_remove = SPIN_LOCK_UNLOCKED;
| >
| > Do not invent your own lock.  You only need to protect against the
| > exception table walk by other CPUs, for which modlist_lock is
| > sufficient.
| >
| > > +
| > > + const struct exception_table_entry *local;
| > > + unsigned int i;
| > > + int num_init_ex=0;
| > > +
| > > +
| > > + local = mod->extable;
| > > + i = 1;
| > > +
| > > + while (i <= mod->num_exentries) {
| > > + if (within_mod_init_section((unsigned long) local->insn,
| mod->module_init, mod->init_size)) {
| > > + num_init_ex++;
| > > + }
| > > + else break;
| > > + local = local+1;
| > > + i++;
| > > + }
| > > +
| > > + local = mod->extable;
| >
| > This code is incorrect.  The init section could be before or after the
| > core section, meaning that all the init-related exceptions will be at
| > the start, or at the end.  So, the code would look like this:
| >
| > void remove_init_exceptions(struct module *mod)
| > {
| > int i;
| >
| > if (!mod->module_init)
| > return;
| >
| > spin_lock(&modlist_lock);
| > if (mod->module_init > mod->module_core) {
| > /* init exception entries at the end.  Trim */
| > for (i = mod->num_exentries-1; i >= 0; i--)
| > if (within(mod->extable[i].insn,
| >    mod->module_init, mod->init_size))
| > mod->num_exentries--;
| > } else {
| > /* init exception entries at the start.  Move ptr. */
| > for (i = 0; i < mod->num_exentries; i++) {
| > if (!within(mod->extable[i].insn,
| >     mod->module_init, mod->init_size))
| > break;
| > }
| > mod->extable += i;
| > mod->num_exentries -= i;
| > }
| > spin_nulock(&modlist_lock);
| > }
| >
| > > + /* Unload the init exceptions */
| > > + for(i=0; i < num_init_ex; ++i)
| > > + kfree(local+i);
| >
| > This doesn't make sense: these are not pointers, but are part of
| > module->core!  They will be freed in the normal way.
| >
| > >  /* Free memory returned from module_alloc */
| > >  void module_free(struct module *mod, void *module_region)
| > > -{
| > > +{
| > > + /* Remove exception entries of the init section */
| > > + if (module_region == mod->module_init) {
| > > + remove_init_exceptions(mod);
| > > + }
| > > +
| >
| > Call this from kernel/module.c directly.
| >
| > > +++ linux-2.6.0-test9-modified/include/linux/extable.h 2003-11-28 10:4
| > 0:57.000000000 -0200
| > > @@ -0,0 +1,51 @@
| > > +#ifndef _EXTABLE_H
| > > +#define _EXTABLE_H
| > > +
| > > +/*
| > > + * Functions regarding to exception's table.
| > > + *
| > > + * * Written by Juliano Silva and Tiago Silva, 2003
| > > + *
| > > + **/
| > > +
| > > +
| > > +#include <linux/module.h>
| > > +#include <asm/uaccess.h>
| > > +#include <asm/sections.h>
| > > +#include <linux/init.h>
| > > +
| > > +/* Exception_table_entry Comparison. Only the field insn is considered.
| > > + *   Results:
| > > + *            equal: 0
| > > + *            ex1 less than ex2: -1
| > > + *            ex1 major than ex2: 1
| > > + *                                                         */
| > > +extern int extable_cmp(struct exception_table_entry ex1,
| > > +                       struct exception_table_entry ex2);
| > > +
| > > +/* This code sorts an exception table. It is very used with modules
| code
| > > + * void __init_or_module sort_ex_table(struct exception_table_entry
| *start,
| > > + * struct exception_table_entry *finish);
| > > + */
| > > +void __init_or_module sort_ex_table(struct exception_table_entry
| *start, struct exception_table_entry *finish)
| >
| > Never put non-inline functions in a header file.  And never inline a
| > function this large.
| >
| > Since this is only called from module.c, perhaps put it in
| > include/linux/moduleloader.h and the code in extable.c.
| >
| > Hope that helps,
| > Rusty.
| > --
| >   Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
| >
| 


-- 
 
=> Tiago Sant' Anna - UIN: 14252973 - Linux user #136940
	[.. ..]

[-- Attachment #2: patch-init_exceptions_removal-version3-test11.diff --]
[-- Type: text/plain, Size: 5282 bytes --]

diff -Nur linux-2.6.0-test11/arch/i386/kernel/module.c linux-2.6.0-test11-modified/arch/i386/kernel/module.c
--- linux-2.6.0-test11/arch/i386/kernel/module.c	2003-11-26 18:44:07.000000000 -0200
+++ linux-2.6.0-test11-modified/arch/i386/kernel/module.c	2003-12-02 15:17:46.000000000 -0200
@@ -35,13 +35,10 @@
 	return vmalloc(size);
 }
 
-
 /* Free memory returned from module_alloc */
 void module_free(struct module *mod, void *module_region)
-{
+{	
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff -Nur linux-2.6.0-test11/include/asm-i386/uaccess.h linux-2.6.0-test11-modified/include/asm-i386/uaccess.h
--- linux-2.6.0-test11/include/asm-i386/uaccess.h	2003-11-26 18:43:07.000000000 -0200
+++ linux-2.6.0-test11-modified/include/asm-i386/uaccess.h	2003-12-02 15:10:52.000000000 -0200
@@ -123,6 +123,15 @@
 	unsigned long insn, fixup;
 };
 
+/* Compare two exception table entries: < 0 if ex1 comes before ex2 */
+static inline int extable_cmp(const struct exception_table_entry ex1, 
+                const struct exception_table_entry ex2)
+{
+	return (long)ex1.insn - ex2.insn;
+}           
+
+
+
 extern int fixup_exception(struct pt_regs *regs);
 
 /*
diff -Nur linux-2.6.0-test11/include/linux/moduleloader.h linux-2.6.0-test11-modified/include/linux/moduleloader.h
--- linux-2.6.0-test11/include/linux/moduleloader.h	2003-11-26 18:43:40.000000000 -0200
+++ linux-2.6.0-test11-modified/include/linux/moduleloader.h	2003-12-02 15:10:52.000000000 -0200
@@ -44,4 +44,8 @@
 /* Any cleanup needed when module leaves. */
 void module_arch_cleanup(struct module *mod);
 
+/* This code sorts an exception table. It is very used with modules code */
+void sort_ex_table(struct exception_table_entry *start,
+                   struct exception_table_entry *finish);
+
 #endif
diff -Nur linux-2.6.0-test11/kernel/extable.c linux-2.6.0-test11-modified/kernel/extable.c
--- linux-2.6.0-test11/kernel/extable.c	2003-11-26 18:43:32.000000000 -0200
+++ linux-2.6.0-test11-modified/kernel/extable.c	2003-12-02 15:10:52.000000000 -0200
@@ -19,6 +19,8 @@
 #include <asm/uaccess.h>
 #include <asm/sections.h>
 
+#include <linux/moduleloader.h>
+
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
 
@@ -45,3 +47,26 @@
 
 	return module_text_address(addr) != NULL;
 }
+
+
+void sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+		
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (extable_cmp(p[0], p[-1]) == -1) {
+		/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && extable_cmp(el, q[-1]) == -1);
+				*q = el;
+		}
+	}
+}
+							
diff -Nur linux-2.6.0-test11/kernel/module.c linux-2.6.0-test11-modified/kernel/module.c
--- linux-2.6.0-test11/kernel/module.c	2003-11-26 18:44:57.000000000 -0200
+++ linux-2.6.0-test11-modified/kernel/module.c	2003-12-02 15:10:52.000000000 -0200
@@ -1076,6 +1076,42 @@
 	return ret;
 }
 
+static inline int within(unsigned long addr, void *start, unsigned long size)
+{
+	return ((void *)addr >= start && (void *)addr < start + size);
+}
+
+/* Remove exception table entries which belongs to this module's init area */
+void remove_init_exceptions(struct module *mod) 
+{
+	const struct exception_table_entry *local;
+	unsigned int i;
+	int num_init_ex=0;
+
+	if (!mod->module_init)
+		return;
+
+	local = mod->extable;
+	i = 1;
+	while (i <= mod->num_exentries) {
+		if (within((unsigned long) local->insn, mod->module_init, 
+		            mod->init_size)) {
+			num_init_ex++;
+		}
+		else break;
+		local = local+1;
+		i++;
+	}
+
+	/* Move the pointer to remove the init exceptions */
+	spin_lock(&modlist_lock);
+		mod->extable += num_init_ex;
+		mod->num_exentries -= num_init_ex;
+	spin_unlock(&modlist_lock);
+}
+
+
+
 /* Free a module, remove from lists, etc (must hold module mutex). */
 static void free_module(struct module *mod)
 {
@@ -1615,6 +1651,11 @@
 	mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
 	mod->extable = (void *)sechdrs[exindex].sh_addr;
 
+        /* Classifying the exception table */
+        sort_ex_table((struct exception_table_entry *)mod->extable,
+                      (struct exception_table_entry *)mod->extable +
+                                mod->num_exentries);
+
 	/* Now do relocations. */
 	for (i = 1; i < hdr->e_shnum; i++) {
 		const char *strtab = (char *)sechdrs[strindex].sh_addr;
@@ -1753,6 +1794,7 @@
 	mod->state = MODULE_STATE_LIVE;
 	/* Drop initial reference. */
 	module_put(mod);
+	remove_init_exceptions(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
@@ -1762,11 +1804,6 @@
 	return 0;
 }
 
-static inline int within(unsigned long addr, void *start, unsigned long size)
-{
-	return ((void *)addr >= start && (void *)addr < start + size);
-}
-
 #ifdef CONFIG_KALLSYMS
 static const char *get_ksymbol(struct module *mod,
 			       unsigned long addr,

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2003-12-17 17:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-28 17:58 New feature: Removal of the exceptions wich belongs to the init section Tiago Sant' Anna
2003-12-01  6:03 ` Rusty Russell
2003-12-17 17:10   ` [PATCH] " Juliano F Silva
2003-12-17 17:17     ` Tiago Sant' Anna

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).