Index: arch/i386/kernel/Makefile
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/arch/i386/kernel/Makefile,v
retrieving revision 1.1.1.23
diff -u -p -r1.1.1.23 Makefile
--- arch/i386/kernel/Makefile	27 Jan 2003 21:08:47 -0000	1.1.1.23
+++ arch/i386/kernel/Makefile	6 Feb 2003 22:18:17 -0000
@@ -29,7 +29,6 @@ obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspen
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_PROFILING)		+= profile.o
 obj-$(CONFIG_EDD)             	+= edd.o
-obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o
 
 EXTRA_AFLAGS   := -traditional
Index: arch/i386/kernel/entry.S
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/arch/i386/kernel/entry.S,v
retrieving revision 1.1.1.32
diff -u -p -r1.1.1.32 entry.S
--- arch/i386/kernel/entry.S	1 Feb 2003 20:05:35 -0000	1.1.1.32
+++ arch/i386/kernel/entry.S	6 Feb 2003 22:18:17 -0000
@@ -669,10 +669,10 @@ ENTRY(sys_call_table)
 	.long sys_adjtimex
 	.long sys_mprotect	/* 125 */
 	.long sys_sigprocmask
-	.long sys_ni_syscall	/* old "create_module" */ 
+	.long sys_create_module
 	.long sys_init_module
 	.long sys_delete_module
-	.long sys_ni_syscall	/* 130:	old "get_kernel_syms" */
+	.long sys_get_kernel_syms	/* 130 */
 	.long sys_quotactl
 	.long sys_getpgid
 	.long sys_fchdir
@@ -709,7 +709,7 @@ ENTRY(sys_call_table)
 	.long sys_setresuid16
 	.long sys_getresuid16	/* 165 */
 	.long sys_vm86
-	.long sys_ni_syscall	/* Old sys_query_module */
+	.long sys_query_module
 	.long sys_poll
 	.long sys_nfsservctl
 	.long sys_setresgid16	/* 170 */
Index: arch/i386/kernel/module.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/arch/i386/kernel/module.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 module.c
--- arch/i386/kernel/module.c	1 Feb 2003 18:10:59 -0000	1.1.1.5
+++ arch/i386/kernel/module.c	6 Feb 2003 22:18:17 -0000
@@ -1,112 +1 @@
-/*  Kernel module help for i386.
-    Copyright (C) 2001 Rusty Russell.
 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-#include <linux/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt...)
-#endif
-
-void *module_alloc(unsigned long size)
-{
-	if (size == 0)
-		return NULL;
-	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. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-			      Elf_Shdr *sechdrs,
-			      char *secstrings,
-			      struct module *mod)
-{
-	return 0;
-}
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-		   const char *strtab,
-		   unsigned int symindex,
-		   unsigned int relsec,
-		   struct module *me)
-{
-	unsigned int i;
-	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
-	Elf32_Sym *sym;
-	uint32_t *location;
-
-	DEBUGP("Applying relocate section %u to %u\n", relsec,
-	       sechdrs[relsec].sh_info);
-	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-		/* This is where to make the change */
-		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-			+ rel[i].r_offset;
-		/* This is the symbol it is referring to.  Note that all
-		   undefined symbols have been resolved.  */
-		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-			+ ELF32_R_SYM(rel[i].r_info);
-
-		switch (ELF32_R_TYPE(rel[i].r_info)) {
-		case R_386_32:
-			/* We add the value into the location given */
-			*location += sym->st_value;
-			break;
-		case R_386_PC32:
-			/* Add the value, subtract its postition */
-			*location += sym->st_value - (uint32_t)location;
-			break;
-		default:
-			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-			       me->name, ELF32_R_TYPE(rel[i].r_info));
-			return -ENOEXEC;
-		}
-	}
-	return 0;
-}
-
-int apply_relocate_add(Elf32_Shdr *sechdrs,
-		       const char *strtab,
-		       unsigned int symindex,
-		       unsigned int relsec,
-		       struct module *me)
-{
-	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
-	       me->name);
-	return -ENOEXEC;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *me)
-{
-	return 0;
-}
Index: arch/i386/kernel/cpu/mtrr/if.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/arch/i386/kernel/cpu/mtrr/if.c,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 if.c
--- arch/i386/kernel/cpu/mtrr/if.c	27 Jan 2003 19:48:30 -0000	1.1.1.2
+++ arch/i386/kernel/cpu/mtrr/if.c	6 Feb 2003 22:18:17 -0000
@@ -3,6 +3,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
 
Index: arch/i386/mm/extable.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/arch/i386/mm/extable.c,v
retrieving revision 1.1.1.4
diff -u -p -r1.1.1.4 extable.c
--- arch/i386/mm/extable.c	27 Jan 2003 23:57:15 -0000	1.1.1.4
+++ arch/i386/mm/extable.c	6 Feb 2003 22:18:18 -0000
@@ -4,6 +4,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/ptrace.h>
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
Index: drivers/char/misc.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/drivers/char/misc.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 misc.c
--- drivers/char/misc.c	11 Nov 2002 19:01:26 -0000	1.1.1.6
+++ drivers/char/misc.c	6 Feb 2003 22:18:35 -0000
@@ -45,6 +45,7 @@
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/stat.h>
+#include <linux/string.h>
 #include <linux/init.h>
 
 #include <linux/tty.h>
Index: drivers/char/agp/Makefile
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/drivers/char/agp/Makefile,v
retrieving revision 1.1.1.8
diff -u -p -r1.1.1.8 Makefile
--- drivers/char/agp/Makefile	27 Jan 2003 21:54:21 -0000	1.1.1.8
+++ drivers/char/agp/Makefile	6 Feb 2003 22:18:35 -0000
@@ -3,7 +3,7 @@
 # space ioctl interface to use agp memory.  It also adds a kernel interface
 # that other drivers could use to manipulate agp memory.
 
-export-objs := backend.o
+export-objs := backend.o generic.o
 
 agpgart-y := backend.o frontend.o generic.o
 agpgart-$(CONFIG_AGP3) += generic-3.0.o
Index: drivers/eisa/eisa-bus.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/drivers/eisa/eisa-bus.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 eisa-bus.c
--- drivers/eisa/eisa-bus.c	1 Feb 2003 20:05:31 -0000	1.1.1.1
+++ drivers/eisa/eisa-bus.c	6 Feb 2003 22:18:36 -0000
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/stat.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
 
Index: drivers/input/serio/serport.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/drivers/input/serio/serport.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 serport.c
--- drivers/input/serio/serport.c	16 Sep 2002 18:18:09 -0000	1.1.1.5
+++ drivers/input/serio/serport.c	6 Feb 2003 22:18:37 -0000
@@ -15,6 +15,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
Index: fs/filesystems.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/fs/filesystems.c,v
retrieving revision 1.1.1.7
diff -u -p -r1.1.1.7 filesystems.c
--- fs/filesystems.c	27 Jan 2003 21:03:13 -0000	1.1.1.7
+++ fs/filesystems.c	6 Feb 2003 22:18:45 -0000
@@ -8,6 +8,7 @@
 
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
@@ -20,7 +21,7 @@
  *	We can access the fields of list element if:
  *		1) spinlock is held or
  *		2) we hold the reference to the module.
- *	The latter can be guaranteed by call of try_module_get(); if it
+ *	The latter can be guaranteed by call of try_inc_mod_count(); if it
  *	returned 0 we must skip the element, otherwise we got the reference.
  *	Once the reference is obtained we can drop the spinlock.
  */
@@ -31,22 +32,14 @@ static rwlock_t file_systems_lock = RW_L
 /* WARNING: This can be used only if we _already_ own a reference */
 void get_filesystem(struct file_system_type *fs)
 {
-	if (!try_module_get(fs->owner)) {
-#ifdef CONFIG_MODULE_UNLOAD
-		unsigned int cpu = get_cpu();
-		local_inc(&fs->owner->ref[cpu].count);
-		put_cpu();
-#else
-		/* Getting filesystem while it's starting up?  We're
-                   already supposed to have a reference. */
-		BUG();
-#endif
-	}
+	if (fs->owner)
+		__MOD_INC_USE_COUNT(fs->owner);
 }
 
 void put_filesystem(struct file_system_type *fs)
 {
-	module_put(fs->owner);
+	if (fs->owner)
+		__MOD_DEC_USE_COUNT(fs->owner);
 }
 
 static struct file_system_type **find_filesystem(const char *name)
@@ -153,8 +146,8 @@ static int fs_name(unsigned int index, c
 
 	read_lock(&file_systems_lock);
 	for (tmp = file_systems; tmp; tmp = tmp->next, index--)
-		if (index <= 0 && try_module_get(tmp->owner))
-			break;
+		if (index <= 0 && try_inc_mod_count(tmp->owner))
+				break;
 	read_unlock(&file_systems_lock);
 	if (!tmp)
 		return -EINVAL;
@@ -224,13 +217,13 @@ struct file_system_type *get_fs_type(con
 
 	read_lock(&file_systems_lock);
 	fs = *(find_filesystem(name));
-	if (fs && !try_module_get(fs->owner))
+	if (fs && !try_inc_mod_count(fs->owner))
 		fs = NULL;
 	read_unlock(&file_systems_lock);
 	if (!fs && (request_module(name) == 0)) {
 		read_lock(&file_systems_lock);
 		fs = *(find_filesystem(name));
-		if (fs && !try_module_get(fs->owner))
+		if (fs && !try_inc_mod_count(fs->owner))
 			fs = NULL;
 		read_unlock(&file_systems_lock);
 	}
Index: fs/proc/proc_misc.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/fs/proc/proc_misc.c,v
retrieving revision 1.1.1.30
diff -u -p -r1.1.1.30 proc_misc.c
--- fs/proc/proc_misc.c	1 Feb 2003 19:59:21 -0000	1.1.1.30
+++ fs/proc/proc_misc.c	6 Feb 2003 22:18:46 -0000
@@ -296,6 +296,17 @@ static struct file_operations proc_modul
 	.llseek		= seq_lseek,
 	.release	= seq_release,
 };
+extern struct seq_operations ksyms_op;
+static int ksyms_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ksyms_op);
+}
+static struct file_operations proc_ksyms_operations = {
+	.open		= ksyms_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
 #endif
 
 extern struct seq_operations slabinfo_op;
@@ -594,6 +605,7 @@ void __init proc_misc_init(void)
 	create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
 #ifdef CONFIG_MODULES
 	create_seq_entry("modules", 0, &proc_modules_operations);
+	create_seq_entry("ksyms", 0, &proc_ksyms_operations);
 #endif
 	proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
 	if (proc_root_kcore) {
Index: include/asm-generic/percpu.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/asm-generic/percpu.h,v
retrieving revision 1.1.1.4
diff -u -p -r1.1.1.4 percpu.h
--- include/asm-generic/percpu.h	31 Oct 2002 13:22:30 -0000	1.1.1.4
+++ include/asm-generic/percpu.h	6 Feb 2003 22:18:49 -0000
@@ -1,6 +1,7 @@
 #ifndef _ASM_GENERIC_PERCPU_H_
 #define _ASM_GENERIC_PERCPU_H_
 #include <linux/compiler.h>
+#include <linux/smp.h>
 
 #define __GENERIC_PER_CPU
 #ifdef CONFIG_SMP
Index: include/asm-generic/vmlinux.lds.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/asm-generic/vmlinux.lds.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 vmlinux.lds.h
--- include/asm-generic/vmlinux.lds.h	1 Feb 2003 20:00:28 -0000	1.1.1.1
+++ include/asm-generic/vmlinux.lds.h	6 Feb 2003 22:18:49 -0000
@@ -12,19 +12,12 @@
 		*(.rodata1)						\
 	}								\
 									\
-	/* Kernel symbol table: Normal symbols */			\
-	__start___ksymtab = .;						\
-	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+	/* Kernel symbol table */					\
+	__ksymtab : {							\
+		__start___ksymtab = .;					\
 		*(__ksymtab)						\
+		__stop___ksymtab = .;					\
 	}								\
-	__stop___ksymtab = .;						\
-									\
-	/* Kernel symbol table: GPL-only symbols */			\
-	__start___gpl_ksymtab = .;					\
-	__gpl_ksymtab     : AT(ADDR(__gpl_ksymtab) - LOAD_OFFSET) {	\
-		*(__gpl_ksymtab)					\
-	}								\
-	__stop___gpl_ksymtab = .;					\
 									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
Index: include/asm-i386/module.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/asm-i386/module.h,v
retrieving revision 1.1.1.3
diff -u -p -r1.1.1.3 module.h
--- include/asm-i386/module.h	1 Feb 2003 20:00:31 -0000	1.1.1.3
+++ include/asm-i386/module.h	6 Feb 2003 22:18:49 -0000
@@ -1,55 +1,12 @@
 #ifndef _ASM_I386_MODULE_H
 #define _ASM_I386_MODULE_H
+/*
+ * This file contains the i386 architecture specific module code.
+ */
 
-/* x86 is simple */
-struct mod_arch_specific
-{
-};
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-#ifdef CONFIG_M386
-#define MODULE_PROC_FAMILY "386 "
-#elif CONFIG_M486
-#define MODULE_PROC_FAMILY "486 "
-#elif CONFIG_M586
-#define MODULE_PROC_FAMILY "586 "
-#elif CONFIG_M586TSC
-#define MODULE_PROC_FAMILY "586TSC "
-#elif CONFIG_M586MMX
-#define MODULE_PROC_FAMILY "586MMX "
-#elif CONFIG_M686
-#define MODULE_PROC_FAMILY "686 "
-#elif CONFIG_MPENTIUMII
-#define MODULE_PROC_FAMILY "PENTIUMII "
-#elif CONFIG_MPENTIUMIII
-#define MODULE_PROC_FAMILY "PENTIUMIII "
-#elif CONFIG_MPENTIUM4
-#define MODULE_PROC_FAMILY "PENTIUM4 "
-#elif CONFIG_MK6
-#define MODULE_PROC_FAMILY "K6 "
-#elif CONFIG_MK7
-#define MODULE_PROC_FAMILY "K7 "
-#elif CONFIG_MK8
-#define MODULE_PROC_FAMILY "K8 "
-#elif CONFIG_MELAN
-#define MODULE_PROC_FAMILY "ELAN "
-#elif CONFIG_MCRUSOE
-#define MODULE_PROC_FAMILY "CRUSOE "
-#elif CONFIG_MWINCHIPC6
-#define MODULE_PROC_FAMILY "WINCHIPC6 "
-#elif CONFIG_MWINCHIP2
-#define MODULE_PROC_FAMILY "WINCHIP2 "
-#elif CONFIG_MWINCHIP3D
-#define MODULE_PROC_FAMILY "WINCHIP3D "
-#elif CONFIG_MCYRIXIII
-#define MODULE_PROC_FAMILY "CYRIXIII "
-#else
-#error unknown processor family
-#endif
-
-#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
+#define module_map(x)		vmalloc(x)
+#define module_unmap(x)		vfree(x)
+#define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_I386_MODULE_H */
Index: include/linux/init.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/linux/init.h,v
retrieving revision 1.1.1.13
diff -u -p -r1.1.1.13 init.h
--- include/linux/init.h	27 Jan 2003 21:50:21 -0000	1.1.1.13
+++ include/linux/init.h	6 Feb 2003 22:18:53 -0000
@@ -38,35 +38,17 @@
  * Also note, that this data cannot be "const".
  */
 
-/* These are for everybody (although not all archs will actually
-   discard it in modules) */
-#define __init		__attribute__ ((__section__ (".init.text")))
-#define __initdata	__attribute__ ((__section__ (".init.data")))
-#define __exitdata	__attribute__ ((__section__(".exit.data")))
-#define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
-
-#ifdef MODULE
-#define __exit		__attribute__ ((__section__(".exit.text")))
-#else
-#define __exit		__attribute__ ((unused,__section__(".exit.text")))
-#endif
-
-/* For assembly routines */
-#define __INIT		.section	".init.text","ax"
-#define __FINIT		.previous
-#define __INITDATA	.section	".init.data","aw"
+#ifndef MODULE
 
 #ifndef __ASSEMBLY__
+
 /*
  * Used for initialization calls..
  */
 typedef int (*initcall_t)(void);
 typedef void (*exitcall_t)(void);
-#endif
-
-#ifndef MODULE
 
-#ifndef __ASSEMBLY__
+extern initcall_t __initcall_start, __initcall_end;
 
 /* initcalls are now grouped by functionality into separate 
  * subsections. Ordering inside the subsections is determined
@@ -88,30 +70,51 @@ typedef void (*exitcall_t)(void);
 
 #define __initcall(fn) device_initcall(fn)
 
-#define __exitcall(fn)							\
+#define __exitcall(fn)								\
 	static exitcall_t __exitcall_##fn __exit_call = fn
 
-struct obs_kernel_param {
+/*
+ * Used for kernel command line parameter setup
+ */
+struct kernel_param {
 	const char *str;
 	int (*setup_func)(char *);
 };
 
-/* OBSOLETE: see moduleparam.h for the right way. */
-#define __setup(str, fn)						\
-	static char __setup_str_##fn[] __initdata = str;		\
-	static struct obs_kernel_param __setup_##fn			\
-		 __attribute__((unused,__section__ (".init.setup")))	\
-		= { __setup_str_##fn, fn }
+extern struct kernel_param __setup_start, __setup_end;
+
+#define __setup(str, fn)								\
+	static char __setup_str_##fn[] __initdata = str;				\
+	static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }
 
 #endif /* __ASSEMBLY__ */
 
+/*
+ * Mark functions and data as being only used at initialization
+ * or exit time.
+ */
+#define __init		__attribute__ ((__section__ (".init.text")))
+#define __exit		__attribute__ ((unused, __section__(".exit.text")))
+#define __initdata	__attribute__ ((__section__ (".init.data")))
+#define __exitdata	__attribute__ ((unused, __section__ (".exit.data")))
+#define __initsetup	__attribute__ ((unused,__section__ (".init.setup")))
+#define __init_call(level)  __attribute__ ((unused,__section__ (".initcall" level ".init")))
+#define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
+
+/* For assembly routines */
+#define __INIT		.section	".init.text","ax"
+#define __FINIT		.previous
+#define __INITDATA	.section	".init.data","aw"
+
 /**
  * module_init() - driver initialization entry point
  * @x: function to be run at kernel boot time or module insertion
  * 
- * module_init() will either be called during do_initcalls (if
- * builtin) or at module insertion time (if a module).  There can only
- * be one per module.
+ * module_init() will add the driver initialization routine in
+ * the "__initcall.int" code segment if the driver is checked as
+ * "y" or static, or else it will wrap the driver initialization
+ * routine with init_module() which is used by insmod and
+ * modprobe when the driver is used as a module.
  */
 #define module_init(x)	__initcall(x);
 
@@ -123,55 +126,52 @@ struct obs_kernel_param {
  * with cleanup_module() when used with rmmod when
  * the driver is a module.  If the driver is statically
  * compiled into the kernel, module_exit() has no effect.
- * There can only be one per module.
  */
 #define module_exit(x)	__exitcall(x);
 
-#else /* MODULE */
+#else
 
-/* Don't use these in modules, but some people do... */
-#define core_initcall(fn)		module_init(fn)
-#define postcore_initcall(fn)		module_init(fn)
-#define arch_initcall(fn)		module_init(fn)
-#define subsys_initcall(fn)		module_init(fn)
-#define fs_initcall(fn)			module_init(fn)
-#define device_initcall(fn)		module_init(fn)
-#define late_initcall(fn)		module_init(fn)
+#define __init
+#define __exit
+#define __initdata
+#define __exitdata
+#define __initcall(fn)
+/* For assembly routines */
+#define __INIT
+#define __FINIT
+#define __INITDATA
 
 /* These macros create a dummy inline: gcc 2.9x does not count alias
  as usage, hence the `unused function' warning when __init functions
  are declared static. We use the dummy __*_module_inline functions
  both to kill the warning and check the type of the init/cleanup
  function. */
-
-/* Each module must use one module_init(), or one no_module_init */
-#define module_init(initfn)					\
-	static inline initcall_t __inittest(void)		\
-	{ return initfn; }					\
-	int init_module(void) __attribute__((alias(#initfn)));
-
-/* This is only required if you want to be unloadable. */
-#define module_exit(exitfn)					\
-	static inline exitcall_t __exittest(void)		\
-	{ return exitfn; }					\
-	void cleanup_module(void) __attribute__((alias(#exitfn)));
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+#define module_init(x) \
+	int init_module(void) __attribute__((alias(#x))); \
+	static inline __init_module_func_t __init_module_inline(void) \
+	{ return x; }
+#define module_exit(x) \
+	void cleanup_module(void) __attribute__((alias(#x))); \
+	static inline __cleanup_module_func_t __cleanup_module_inline(void) \
+	{ return x; }
 
 #define __setup(str,func) /* nothing */
+
+#define core_initcall(fn)		module_init(fn)
+#define postcore_initcall(fn)		module_init(fn)
+#define arch_initcall(fn)		module_init(fn)
+#define subsys_initcall(fn)		module_init(fn)
+#define fs_initcall(fn)			module_init(fn)
+#define device_initcall(fn)		module_init(fn)
+#define late_initcall(fn)		module_init(fn)
+
 #endif
 
 /* Data marked not to be saved by software_suspend() */
 #define __nosavedata __attribute__ ((__section__ (".data.nosave")))
 
-/* This means "can be init if no module support, otherwise module load
-   may call it." */
-#ifdef CONFIG_MODULES
-#define __init_or_module
-#define __initdata_or_module
-#else
-#define __init_or_module __init
-#define __initdata_or_module __initdata
-#endif /*CONFIG_MODULES*/
-
 #ifdef CONFIG_HOTPLUG
 #define __devinit
 #define __devinitdata
@@ -201,5 +201,5 @@ struct obs_kernel_param {
 #else
 #define __exit_p(x) NULL
 #endif
-
+	
 #endif /* _LINUX_INIT_H */
Index: include/linux/module.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/linux/module.h,v
retrieving revision 1.1.1.16
diff -u -p -r1.1.1.16 module.h
--- include/linux/module.h	1 Feb 2003 20:00:06 -0000	1.1.1.16
+++ include/linux/module.h	6 Feb 2003 22:18:53 -0000
@@ -1,47 +1,191 @@
-#ifndef _LINUX_MODULE_H
-#define _LINUX_MODULE_H
 /*
  * Dynamic loading of modules into the kernel.
  *
  * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
- * Rewritten again by Rusty Russell, 2002
  */
+
+#ifndef _LINUX_MODULE_H
+#define _LINUX_MODULE_H
+
 #include <linux/config.h>
-#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
-#include <linux/stat.h>
-#include <linux/compiler.h>
-#include <linux/cache.h>
-#include <linux/kmod.h>
-#include <linux/elf.h>
-#include <linux/stringify.h>
+#include <linux/errno.h>
 
-#include <asm/module.h>
-#include <asm/uaccess.h> /* For struct exception_table_entry */
+#include <asm/atomic.h>
 
-/* Not Yet Implemented */
-#define MODULE_AUTHOR(name)
-#define MODULE_DESCRIPTION(desc)
-#define MODULE_SUPPORTED_DEVICE(name)
-#define MODULE_PARM_DESC(var,desc)
-#define print_modules()
+/* Don't need to bring in all of uaccess.h just for this decl.  */
+struct exception_table_entry;
 
-/* v850 toolchain uses a `_' prefix for all user symbols */
-#ifndef MODULE_SYMBOL_PREFIX
-#define MODULE_SYMBOL_PREFIX ""
-#endif
+const struct exception_table_entry *search_exception_tables(unsigned long add);
+
+/* Used by get_kernel_syms, which is obsolete.  */
+struct kernel_sym
+{
+	unsigned long value;
+	char name[60];		/* should have been 64-sizeof(long); oh well */
+};
 
-#define MODULE_NAME_LEN (64 - sizeof(unsigned long))
-struct kernel_symbol
+struct module_symbol
 {
 	unsigned long value;
 	const char *name;
 };
 
-/* These are either module local, or the kernel's dummy ones. */
-extern int init_module(void);
-extern void cleanup_module(void);
+struct module_ref
+{
+	struct module *dep;	/* "parent" pointer */
+	struct module *ref;	/* "child" pointer */
+	struct module_ref *next_ref;
+};
+
+/* TBD */
+struct module_persist;
+
+struct module
+{
+	unsigned long size_of_struct;	/* == sizeof(module) */
+	struct module *next;
+	const char *name;
+	unsigned long size;
+
+	union
+	{
+		atomic_t usecount;
+		long pad;
+	} uc;				/* Needs to keep its size - so says rth */
+
+	unsigned long flags;		/* AUTOCLEAN et al */
+
+	unsigned nsyms;
+	unsigned ndeps;
+
+	struct module_symbol *syms;
+	struct module_ref *deps;
+	struct module_ref *refs;
+	int (*init)(void);
+	void (*cleanup)(void);
+	const struct exception_table_entry *ex_table_start;
+	const struct exception_table_entry *ex_table_end;
+#ifdef __alpha__
+	unsigned long gp;
+#endif
+	/* Members past this point are extensions to the basic
+	   module support and are optional.  Use mod_member_present()
+	   to examine them.  */
+	const struct module_persist *persist_start;
+	const struct module_persist *persist_end;
+	int (*can_unload)(void);
+	int runsize;			/* In modutils, not currently used */
+	const char *kallsyms_start;	/* All symbols for kernel debugging */
+	const char *kallsyms_end;
+	const char *archdata_start;	/* arch specific data for module */
+	const char *archdata_end;
+	const char *kernel_data;	/* Reserved for kernel internal use */
+};
+
+struct module_info
+{
+	unsigned long addr;
+	unsigned long size;
+	unsigned long flags;
+	long usecount;
+};
+
+/* Bits of module.flags.  */
+
+#define MOD_UNINITIALIZED	0
+#define MOD_RUNNING		1
+#define MOD_DELETED		2
+#define MOD_AUTOCLEAN		4
+#define MOD_VISITED  		8
+#define MOD_USED_ONCE		16
+#define MOD_JUST_FREED		32
+#define MOD_INITIALIZING	64
+
+/* Values for query_module's which.  */
+
+#define QM_MODULES	1
+#define QM_DEPS		2
+#define QM_REFS		3
+#define QM_SYMBOLS	4
+#define QM_INFO		5
+
+/* Can the module be queried? */
+#define MOD_CAN_QUERY(mod) (((mod)->flags & (MOD_RUNNING | MOD_INITIALIZING)) && !((mod)->flags & MOD_DELETED))
+
+/* When struct module is extended, we must test whether the new member
+   is present in the header received from insmod before we can use it.  
+   This function returns true if the member is present.  */
+
+#define mod_member_present(mod,member) 					\
+	((unsigned long)(&((struct module *)0L)->member + 1)		\
+	 <= (mod)->size_of_struct)
+
+/*
+ * Ditto for archdata.  Assumes mod->archdata_start and mod->archdata_end
+ * are validated elsewhere.
+ */
+#define mod_archdata_member_present(mod, type, member)			\
+	(((unsigned long)(&((type *)0L)->member) +			\
+	  sizeof(((type *)0L)->member)) <=				\
+	 ((mod)->archdata_end - (mod)->archdata_start))
+	 
+
+/* Check if an address p with number of entries n is within the body of module m */
+#define mod_bound(p, n, m) ((unsigned long)(p) >= ((unsigned long)(m) + ((m)->size_of_struct)) && \
+	         (unsigned long)((p)+(n)) <= (unsigned long)(m) + (m)->size)
+
+/* Backwards compatibility definition.  */
+
+#define GET_USE_COUNT(module)	(atomic_read(&(module)->uc.usecount))
+
+/* Poke the use count of a module.  */
+
+#define __MOD_INC_USE_COUNT(mod)					\
+	(atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
+#define __MOD_DEC_USE_COUNT(mod)					\
+	(atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
+#define __MOD_IN_USE(mod)						\
+	(mod_member_present((mod), can_unload) && (mod)->can_unload	\
+	 ? (mod)->can_unload() : atomic_read(&(mod)->uc.usecount))
+
+/* Indirect stringification.  */
+
+#define __MODULE_STRING_1(x)	#x
+#define __MODULE_STRING(x)	__MODULE_STRING_1(x)
+
+/* Generic inter module communication.
+ *
+ * NOTE: This interface is intended for small amounts of data that are
+ *       passed between two objects and either or both of the objects
+ *       might be compiled as modules.  Do not over use this interface.
+ *
+ *       If more than two objects need to communicate then you probably
+ *       need a specific interface instead of abusing this generic
+ *       interface.  If both objects are *always* built into the kernel
+ *       then a global extern variable is good enough, you do not need
+ *       this interface.
+ *
+ * Keith Owens <kaos@ocs.com.au> 28 Oct 2000.
+ */
+
+#ifdef __KERNEL__
+#define HAVE_INTER_MODULE
+extern void inter_module_register(const char *, struct module *, const void *);
+extern void inter_module_unregister(const char *);
+extern const void *inter_module_get(const char *);
+extern const void *inter_module_get_request(const char *, const char *);
+extern void inter_module_put(const char *);
+
+struct inter_module_entry {
+	struct list_head list;
+	const char *im_name;
+	struct module *owner;
+	const void *userdata;
+};
+
+extern int try_inc_mod_count(struct module *mod);
 
 /* Archs provide a method of finding the correct exception table. */
 const struct exception_table_entry *
@@ -49,20 +193,83 @@ search_extable(const struct exception_ta
 	       const struct exception_table_entry *last,
 	       unsigned long value);
 
-#ifdef MODULE
+#define try_module_get(mod) try_inc_mod_count(mod)
+static inline void module_put(struct module *mod)
+{
+	if (mod)
+		__MOD_DEC_USE_COUNT(mod);
+}
+
+/* This is a #define so the string doesn't get put in every .o file */
+#define module_name(mod)			\
+({						\
+	struct module *__mod = (mod);		\
+	__mod ? __mod->name : "kernel";		\
+})
 
-/* For replacement modutils, use an alias not a pointer. */
-#define MODULE_GENERIC_TABLE(gtype,name)			\
-static const unsigned long __module_##gtype##_size		\
-  __attribute__ ((unused)) = sizeof(struct gtype##_id);		\
-static const struct gtype##_id * __module_##gtype##_table	\
-  __attribute__ ((unused)) = name;				\
-extern const struct gtype##_id __mod_##gtype##_table		\
-  __attribute__ ((unused, alias(__stringify(name))))
-
-#define THIS_MODULE (&__this_module)
-#define MOD_INC_USE_COUNT _MOD_INC_USE_COUNT(THIS_MODULE)
-#define MOD_DEC_USE_COUNT __MOD_DEC_USE_COUNT(THIS_MODULE)
+#endif /* __KERNEL__ */
+
+#if defined(MODULE) && !defined(__GENKSYMS__)
+
+/* Embedded module documentation macros.  */
+
+/* For documentation purposes only.  */
+
+#define MODULE_AUTHOR(name)						   \
+const char __module_author[] __attribute__((section(".modinfo"))) = 	   \
+"author=" name
+
+#define MODULE_DESCRIPTION(desc)					   \
+const char __module_description[] __attribute__((section(".modinfo"))) =   \
+"description=" desc
+
+/* Could potentially be used by kmod...  */
+
+#define MODULE_SUPPORTED_DEVICE(dev)					   \
+const char __module_device[] __attribute__((section(".modinfo"))) = 	   \
+"device=" dev
+
+/* Used to verify parameters given to the module.  The TYPE arg should
+   be a string in the following format:
+   	[min[-max]]{b,h,i,l,s}
+   The MIN and MAX specifiers delimit the length of the array.  If MAX
+   is omitted, it defaults to MIN; if both are omitted, the default is 1.
+   The final character is a type specifier:
+	b	byte
+	h	short
+	i	int
+	l	long
+	s	string
+*/
+
+#define MODULE_PARM(var,type)			\
+const char __module_parm_##var[]		\
+__attribute__((section(".modinfo"))) =		\
+"parm_" __MODULE_STRING(var) "=" type
+
+#define MODULE_PARM_DESC(var,desc)		\
+const char __module_parm_desc_##var[]		\
+__attribute__((section(".modinfo"))) =		\
+"parm_desc_" __MODULE_STRING(var) "=" desc
+
+/*
+ * MODULE_DEVICE_TABLE exports information about devices
+ * currently supported by this module.  A device type, such as PCI,
+ * is a C-like identifier passed as the first arg to this macro.
+ * The second macro arg is the variable containing the device
+ * information being made public.
+ *
+ * The following is a list of known device types (arg 1),
+ * and the C types which are to be passed as arg 2.
+ * pci - struct pci_device_id - List of PCI ids supported by this module
+ * isapnp - struct isapnp_device_id - List of ISA PnP ids supported by this module
+ * usb - struct usb_device_id - List of USB ids supported by this module
+ */
+#define MODULE_GENERIC_TABLE(gtype,name)	\
+static const unsigned long __module_##gtype##_size \
+  __attribute__ ((unused)) = sizeof(struct gtype##_id); \
+static const struct gtype##_id * __module_##gtype##_table \
+  __attribute__ ((unused)) = name
 
 /*
  * The following license idents are currently accepted as indicating free
@@ -71,10 +278,8 @@ extern const struct gtype##_id __mod_##g
  *	"GPL"				[GNU Public License v2 or later]
  *	"GPL v2"			[GNU Public License v2]
  *	"GPL and additional rights"	[GNU Public License v2 rights and more]
- *	"Dual BSD/GPL"			[GNU Public License v2
- *					 or BSD license choice]
- *	"Dual MPL/GPL"			[GNU Public License v2
- *					 or Mozilla license choice]
+ *	"Dual BSD/GPL"			[GNU Public License v2 or BSD license choice]
+ *	"Dual MPL/GPL"			[GNU Public License v2 or Mozilla license choice]
  *
  * The following other idents are available
  *
@@ -90,369 +295,243 @@ extern const struct gtype##_id __mod_##g
  * 2.	So the community can ignore bug reports including proprietary modules
  * 3.	So vendors can do likewise based on their own policies
  */
-#define MODULE_LICENSE(license)					\
-	static const char __module_license[]			\
-		__attribute__((section(".init.license"))) = license
+ 
+#define MODULE_LICENSE(license) 	\
+static const char __module_license[]	\
+  __attribute__((section(".modinfo"), unused)) = "license=" license
 
-#else  /* !MODULE */
+/* Define the module variable, and usage macros.  */
+extern struct module __this_module;
 
-#define MODULE_GENERIC_TABLE(gtype,name)
-#define THIS_MODULE ((struct module *)0)
-#define MOD_INC_USE_COUNT	do { } while (0)
-#define MOD_DEC_USE_COUNT	do { } while (0)
-#define MODULE_LICENSE(license)
+#define THIS_MODULE		(&__this_module)
+#define MOD_INC_USE_COUNT	__MOD_INC_USE_COUNT(THIS_MODULE)
+#define MOD_DEC_USE_COUNT	__MOD_DEC_USE_COUNT(THIS_MODULE)
+#define MOD_IN_USE		__MOD_IN_USE(THIS_MODULE)
+
+#include <linux/version.h>
+static const char __module_kernel_version[]
+  __attribute__((section(".modinfo"), unused)) =
+  "kernel_version=" UTS_RELEASE;
+#ifdef CONFIG_MODVERSIONS
+static const char __module_using_checksums[]
+  __attribute__((section(".modinfo"), unused)) =
+  "using_checksums=1";
 #endif
 
-#define MODULE_DEVICE_TABLE(type,name)		\
-  MODULE_GENERIC_TABLE(type##_device,name)
-
-struct kernel_symbol_group
-{
-	/* Links us into the global symbol list */
-	struct list_head list;
-
-	/* Module which owns it (if any) */
-	struct module *owner;
-
-	/* Are we internal use only? */
-	int gplonly;
-
-	unsigned int num_syms;
-	const struct kernel_symbol *syms;
-};
-
-/* Given an address, look for it in the exception tables */
-const struct exception_table_entry *search_exception_tables(unsigned long add);
-
-struct exception_table
-{
-	struct list_head list;
+#else /* MODULE */
 
-	unsigned int num_entries;
-	const struct exception_table_entry *entry;
-};
-
-
-#ifdef CONFIG_MODULES
-/* Get/put a kernel symbol (calls must be symmetric) */
-void *__symbol_get(const char *symbol);
-void *__symbol_get_gpl(const char *symbol);
-#define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x)))
-
-/* For every exported symbol, place a struct in the __ksymtab section */
-#define EXPORT_SYMBOL(sym)					\
-	static const char __kstrtab_##sym[]			\
-	__attribute__((section("__ksymtab_strings")))		\
-	= MODULE_SYMBOL_PREFIX #sym;                    	\
-	static const struct kernel_symbol __ksymtab_##sym	\
-	__attribute__((section("__ksymtab")))			\
-	= { (unsigned long)&sym, __kstrtab_##sym }
-
-#define EXPORT_SYMBOL_NOVERS(sym) EXPORT_SYMBOL(sym)
-
-#define EXPORT_SYMBOL_GPL(sym)					\
-	static const char __kstrtab_##sym[]			\
-	__attribute__((section("__ksymtab_strings")))		\
-	= MODULE_SYMBOL_PREFIX #sym;                    	\
-	static const struct kernel_symbol __ksymtab_##sym	\
-	__attribute__((section("__gpl_ksymtab")))		\
-	= { (unsigned long)&sym, __kstrtab_##sym }
-
-struct module_ref
-{
-	atomic_t count;
-} ____cacheline_aligned;
-
-enum module_state
-{
-	MODULE_STATE_LIVE,
-	MODULE_STATE_COMING,
-	MODULE_STATE_GOING,
-};
-
-struct module
-{
-	enum module_state state;
-
-	/* Member of list of modules */
-	struct list_head list;
-
-	/* Unique handle for this module */
-	char name[MODULE_NAME_LEN];
-
-	/* Exported symbols */
-	struct kernel_symbol_group symbols;
-
-	/* GPL-only exported symbols. */
-	struct kernel_symbol_group gpl_symbols;
-
-	/* Exception tables */
-	struct exception_table extable;
-
-	/* Startup function. */
-	int (*init)(void);
-
-	/* If this is non-NULL, vfree after init() returns */
-	void *module_init;
-
-	/* Here is the actual code + data, vfree'd on unload. */
-	void *module_core;
-
-	/* Here are the sizes of the init and core sections */
-	unsigned long init_size, core_size;
-
-	/* Arch-specific module values */
-	struct mod_arch_specific arch;
-
-	/* Am I unsafe to unload? */
-	int unsafe;
-
-	/* Am I GPL-compatible */
-	int license_gplok;
-
-#ifdef CONFIG_MODULE_UNLOAD
-	/* Reference counts */
-	struct module_ref ref[NR_CPUS];
-
-	/* What modules depend on me? */
-	struct list_head modules_which_use_me;
+#define MODULE_AUTHOR(name)
+#define MODULE_LICENSE(license)
+#define MODULE_DESCRIPTION(desc)
+#define MODULE_SUPPORTED_DEVICE(name)
+#define MODULE_PARM(var,type)
+#define MODULE_PARM_DESC(var,desc)
 
-	/* Who is waiting for us to be unloaded */
-	struct task_struct *waiter;
+/* Create a dummy reference to the table to suppress gcc unused warnings.  Put
+ * the reference in the .data.exit section which is discarded when code is built
+ * in, so the reference does not bloat the running kernel.  Note: cannot be
+ * const, other exit data may be writable.
+ */
+#define MODULE_GENERIC_TABLE(gtype,name) \
+static const struct gtype##_id * __module_##gtype##_table \
+  __attribute__ ((unused, __section__(".exit.data"))) = name
 
-	/* Destruction function. */
-	void (*exit)(void);
-#endif
+#ifndef __GENKSYMS__
 
-#ifdef CONFIG_KALLSYMS
-	/* We keep the symbol and string tables for kallsyms. */
-	Elf_Sym *symtab;
-	unsigned long num_syms;
-	char *strtab;
-#endif
+#define THIS_MODULE		NULL
+#define MOD_INC_USE_COUNT	do { } while (0)
+#define MOD_DEC_USE_COUNT	do { } while (0)
+#define MOD_IN_USE		1
 
-	/* The command line arguments (may be mangled).  People like
-	   keeping pointers to this stuff */
-	char *args;
-};
+#endif /* !__GENKSYMS__ */
 
-/* FIXME: It'd be nice to isolate modules during init, too, so they
-   aren't used before they (may) fail.  But presently too much code
-   (IDE & SCSI) require entry into the module during init.*/
-static inline int module_is_live(struct module *mod)
-{
-	return mod->state != MODULE_STATE_GOING;
-}
+#endif /* MODULE */
 
-/* Is this address in a module? */
-int module_text_address(unsigned long addr);
+#define MODULE_DEVICE_TABLE(type,name)		\
+  MODULE_GENERIC_TABLE(type##_device,name)
 
-#ifdef CONFIG_MODULE_UNLOAD
+/* Export a symbol either from the kernel or a module.
 
-void __symbol_put(const char *symbol);
-#define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x)
-void symbol_put_addr(void *addr);
-
-/* We only need protection against local interrupts. */
-#ifndef __HAVE_ARCH_LOCAL_INC
-#define local_inc(x) atomic_inc(x)
-#define local_dec(x) atomic_dec(x)
-#endif
+   In the kernel, the symbol is added to the kernel's global symbol table.
 
-static inline int try_module_get(struct module *module)
-{
-	int ret = 1;
+   In a module, it controls which variables are exported.  If no
+   variables are explicitly exported, the action is controled by the
+   insmod -[xX] flags.  Otherwise, only the variables listed are exported.
+   This obviates the need for the old register_symtab() function.  */
 
-	if (module) {
-		unsigned int cpu = get_cpu();
-		if (likely(module_is_live(module)))
-			local_inc(&module->ref[cpu].count);
-		else
-			ret = 0;
-		put_cpu();
-	}
-	return ret;
-}
+/* So how does the CONFIG_MODVERSIONS magic work? 
+ *
+ * A module can only be loaded if it's undefined symbols can be resolved
+ * using symbols the kernel exports for that purpose. The idea behind
+ * CONFIG_MODVERSIONS is to mangle those symbols depending on their
+ * definition (see man genksyms) - a change in the definition will thus
+ * caused the mangled name to change, and the module will refuse to
+ * load due to unresolved symbols.
+ *
+ * Let's start with taking a look how things work when we don't use
+ * CONFIG_MODVERSIONS. In this case, the only thing which is worth
+ * mentioning is the EXPORT_SYMBOL() macro. Using EXPORT_SYMBOL(foo)
+ * will expand into __EXPORT_SYMBOL(foo, "foo"), which then uses
+ * some ELF section magic to generate a list of pairs 
+ * (address, symbol_name), which is used to resolve undefined 
+ * symbols into addresses when loading a module.
+ * 
+ * That's easy. Let's get back to CONFIG_MODVERSIONS=y.
+ *
+ * The first step is to generate the checksums. This is done at
+ * "make dep" time, code which exports symbols (using EXPORT_SYMTAB)
+ * is preprocessed with the additional macro __GENKSYMS__ set and fed
+ * into genksyms.
+ * At this stage, for each file that exports symbols an corresponding
+ * file in include/linux/module is generated, which for each exported
+ * symbol contains
+ *
+ *         #define __ver_schedule_task     2d6c3d04
+ *         #define schedule_task   _set_ver(schedule_task)
+ *
+ * In addition, include/linux/modversions.h is generated, which
+ * looks like
+ *
+ *         #include <linux/modsetver.h>
+ *         #include <linux/modules/kernel__context.ver>
+ *        <<<lists all of the files just described>>>
+ *
+ * Let's see what happens for different cases during compilation.
+ *
+ * o compile a file into the kernel which does not export symbols:
+ *
+ *   Since the file is known to not export symbols (it's not listed
+ *   in the export-objs variable in the corresponding Makefile), the
+ *   kernel build system does compile it with no extra flags set.
+ *   The macro EXPORT_SYMTAB is unset, and you can see below that
+ *   files which still try to use EXPORT_SYMBOL() will be trapped.
+ *   Other than that, just regular compilation.
+ *
+ * o compile a file into the kernel which does export symbols:
+ *
+ *   In this case, the file will compiled with the macro 
+ *   EXPORT_SYMTAB defined.
+ *   As MODULE is not set, we hit this case from below:
+ *
+ *         #define _set_ver(sym) sym
+ *         #include <linux/modversions.h>
+ *         
+ *         #define EXPORT_SYMBOL(var) \
+ *          __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
+ *
+ *   The first two lines will in essence include
+ *
+ *         #define __ver_schedule_task     2d6c3d04
+ *         #define schedule_task   schedule_task
+ *
+ *   for each symbol. The second line really doesn't do much, but the
+ *   first one gives us the checksums we generated before.
+ *   
+ *   So EXPORT_SYMBOL(schedule_task) will expand into
+ *   __EXPORT_SYMBOL(schedule_task, "schedule_task_R2d6c3d04"),
+ *   hence exporting the symbol for schedule_task under the name of
+ *   schedule_task_R2d6c3d04.
+ *
+ * o compile a file into a module
+ *   
+ *   In this case, the kernel build system will add 
+ *   "-include include/linux/modversions.h" to the command line. So
+ *   modversions.h is prepended to the actual source, turning into
+ *
+ *         #define __ver_schedule_task     2d6c3d04
+ *         #define schedule_task   schedule_task_R2d6c3d04
+ *
+ *   Though the source code says "schedule_task", the compiler will
+ *   see the mangled symbol everywhere. So the module will end up with
+ *   an undefined symbol "schedule_task_R2d6c3d04" - which is exactly
+ *   the symbols which occurs in the kernel's list of symbols, with
+ *   a value of &schedule_task - it all comes together nicely.
+ *
+ *   One question remains: What happens if a module itself exports
+ *   a symbol - the answer is simple: It's actually handled as the
+ *   CONFIG_MODVERSIONS=n case described first, only that the compiler
+ *   sees the mangled symbol everywhere. So &foo_R12345678 is exported
+ *   with the name "foo_R12345678". Think about it. It all makes sense.
+ */
 
-static inline void module_put(struct module *module)
-{
-	if (module) {
-		unsigned int cpu = get_cpu();
-		local_dec(&module->ref[cpu].count);
-		/* Maybe they're waiting for us to drop reference? */
-		if (unlikely(!module_is_live(module)))
-			wake_up_process(module->waiter);
-		put_cpu();
-	}
-}
+#if defined(__GENKSYMS__)
 
-#else /*!CONFIG_MODULE_UNLOAD*/
-static inline int try_module_get(struct module *module)
-{
-	return !module || module_is_live(module);
-}
-static inline void module_put(struct module *module)
-{
-}
-#define symbol_put(x) do { } while(0)
-#define symbol_put_addr(p) do { } while(0)
+/* We want the EXPORT_SYMBOL tag left intact for recognition.  */
 
-#endif /* CONFIG_MODULE_UNLOAD */
+#elif !defined(CONFIG_MODULES)
 
-/* This is a #define so the string doesn't get put in every .o file */
-#define module_name(mod)			\
-({						\
-	struct module *__mod = (mod);		\
-	__mod ? __mod->name : "kernel";		\
-})
+#define __EXPORT_SYMBOL(sym,str)
+#define EXPORT_SYMBOL(var)
+#define EXPORT_SYMBOL_NOVERS(var)
+#define EXPORT_SYMBOL_GPL(var)
 
-#define __unsafe(mod)							     \
-do {									     \
-	if (mod && !(mod)->unsafe) {					     \
-		printk(KERN_WARNING					     \
-		       "Module %s cannot be unloaded due to unsafe usage in" \
-		       " %s:%u\n", (mod)->name, __FILE__, __LINE__);	     \
-		(mod)->unsafe = 1;					     \
-	}								     \
-} while(0)
-
-/* For kallsyms to ask for address resolution.  NULL means not found. */
-const char *module_address_lookup(unsigned long addr,
-				  unsigned long *symbolsize,
-				  unsigned long *offset,
-				  char **modname);
-
-/* For extable.c to search modules' exception tables. */
-const struct exception_table_entry *search_module_extables(unsigned long addr);
-
-#else /* !CONFIG_MODULES... */
-#define EXPORT_SYMBOL(sym)
-#define EXPORT_SYMBOL_GPL(sym)
-#define EXPORT_SYMBOL_NOVERS(sym)
-
-/* Given an address, look for it in the exception tables. */
-static inline const struct exception_table_entry *
-search_module_extables(unsigned long addr)
-{
-	return NULL;
-}
+#elif !defined(EXPORT_SYMTAB)
 
-/* Is this address in a module? */
-static inline int module_text_address(unsigned long addr)
-{
-	return 0;
-}
+#define __EXPORT_SYMBOL(sym,str)   error this_object_must_be_defined_as_export_objs_in_the_Makefile
+#define EXPORT_SYMBOL(var)	   error this_object_must_be_defined_as_export_objs_in_the_Makefile
+#define EXPORT_SYMBOL_NOVERS(var)  error this_object_must_be_defined_as_export_objs_in_the_Makefile
+#define EXPORT_SYMBOL_GPL(var)  error this_object_must_be_defined_as_export_objs_in_the_Makefile
 
-/* Get/put a kernel symbol (calls should be symmetric) */
-#define symbol_get(x) (&(x))
-#define symbol_put(x) do { } while(0)
-#define symbol_put_addr(x) do { } while(0)
+#else
 
-static inline int try_module_get(struct module *module)
-{
-	return 1;
-}
+#define __EXPORT_SYMBOL(sym, str)			\
+const char __kstrtab_##sym[]				\
+__attribute__((section(".kstrtab"))) = str;		\
+const struct module_symbol __ksymtab_##sym 		\
+__attribute__((section("__ksymtab"))) =			\
+{ (unsigned long)&sym, __kstrtab_##sym }
 
-static inline void module_put(struct module *module)
-{
-}
+#define __EXPORT_SYMBOL_GPL(sym, str)			\
+const char __kstrtab_##sym[]				\
+__attribute__((section(".kstrtab"))) = "GPLONLY_" str;	\
+const struct module_symbol __ksymtab_##sym		\
+__attribute__((section("__ksymtab"))) =			\
+{ (unsigned long)&sym, __kstrtab_##sym }
 
-#define module_name(mod) "kernel"
+#if defined(CONFIG_MODVERSIONS) && !defined(MODULE)
 
-#define __unsafe(mod)
+#define _set_ver(sym) sym
+#include <linux/modversions.h>
 
-/* For kallsyms to ask for address resolution.  NULL means not found. */
-static inline const char *module_address_lookup(unsigned long addr,
-						unsigned long *symbolsize,
-						unsigned long *offset,
-						char **modname)
-{
-	return NULL;
-}
-#endif /* CONFIG_MODULES */
+#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
+#define EXPORT_SYMBOL_GPL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
 
-#ifdef MODULE
-extern struct module __this_module;
-#ifdef KBUILD_MODNAME
-/* We make the linker do some of the work. */
-struct module __this_module
-__attribute__((section(".gnu.linkonce.this_module"))) = {
-	.name = __stringify(KBUILD_MODNAME),
-	.symbols = { .owner = &__this_module },
-	.gpl_symbols = { .owner = &__this_module, .gplonly = 1 },
-	.init = init_module,
-#ifdef CONFIG_MODULE_UNLOAD
-	.exit = cleanup_module,
-#endif
-};
-#endif /* KBUILD_MODNAME */
-#endif /* MODULE */
+#else /* !defined (CONFIG_MODVERSIONS) || defined(MODULE) */
 
-#define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
+#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+#define EXPORT_SYMBOL_GPL(var)  __EXPORT_SYMBOL_GPL(var, __MODULE_STRING(var))
 
-/* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */
-static inline void __deprecated __MOD_INC_USE_COUNT(struct module *module)
-{
-	__unsafe(module);
-	/*
-	 * Yes, we ignore the retval here, that's why it's deprecated.
-	 */
-	try_module_get(module);
-}
+#endif /* defined(CONFIG_MODVERSIONS) && !defined(MODULE) */
 
-static inline void __deprecated __MOD_DEC_USE_COUNT(struct module *module)
-{
-	module_put(module);
-}
+#define EXPORT_SYMBOL_NOVERS(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
 
-#define SET_MODULE_OWNER(dev) ((dev)->owner = THIS_MODULE)
+#endif /* __GENKSYMS__ */
 
-struct obsolete_modparm {
-	char name[64];
-	char type[64-sizeof(void *)];
-	void *addr;
-};
-#ifdef MODULE
-/* DEPRECATED: Do not use. */
-#define MODULE_PARM(var,type)						    \
-struct obsolete_modparm __parm_##var __attribute__((section("__obsparm"))) = \
-{ __stringify(var), type };
+/* 
+ * Force a module to export no symbols.
+ * EXPORT_NO_SYMBOLS is default now, leave the define around for sources
+ * which still have it
+ */
+#define EXPORT_NO_SYMBOLS
 
-#else
-#define MODULE_PARM(var,type)
+#ifdef CONFIG_MODULES
+/* 
+ * Always allocate a section "__ksymtab". If we encounter EXPORT_SYMBOL,
+ * the exported symbol will be added to it.
+ * If it remains empty, that tells modutils that we do not want to
+ * export any symbols (as opposed to it not being present, which means
+ * "export all symbols" to modutils)
+ */
+__asm__(".section __ksymtab,\"a\"\n.previous");
 #endif
 
-/* People do this inside their init routines, when the module isn't
-   "live" yet.  They should no longer be doing that, but
-   meanwhile... */
-static inline void __deprecated _MOD_INC_USE_COUNT(struct module *module)
-{
-	__unsafe(module);
-
-#if defined(CONFIG_MODULE_UNLOAD) && defined(MODULE)
-	local_inc(&module->ref[get_cpu()].count);
-	put_cpu();
+#ifdef CONFIG_MODULES
+#define SET_MODULE_OWNER(some_struct) do { (some_struct)->owner = THIS_MODULE; } while (0)
 #else
-	try_module_get(module);
+#define SET_MODULE_OWNER(some_struct) do { } while (0)
 #endif
-}
-#define EXPORT_NO_SYMBOLS
-#define __MODULE_STRING(x) __stringify(x)
-
-/*
- * The exception and symbol tables, and the lock
- * to protect them.
- */
-extern spinlock_t modlist_lock;
-extern struct list_head extables;
-extern struct list_head symbols;
 
-/* Use symbol_get and symbol_put instead.  You'll thank me. */
-#define HAVE_INTER_MODULE
-extern void inter_module_register(const char *, struct module *, const void *);
-extern void inter_module_unregister(const char *);
-extern const void *inter_module_get(const char *);
-extern const void *inter_module_get_request(const char *, const char *);
-extern void inter_module_put(const char *);
+extern void print_modules(void);
+extern struct module *module_list;
 
 #endif /* _LINUX_MODULE_H */
Index: include/linux/moduleloader.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/linux/moduleloader.h,v
retrieving revision 1.1.1.4
diff -u -p -r1.1.1.4 moduleloader.h
--- include/linux/moduleloader.h	1 Feb 2003 18:05:56 -0000	1.1.1.4
+++ include/linux/moduleloader.h	6 Feb 2003 22:18:53 -0000
@@ -1,44 +1 @@
-#ifndef _LINUX_MODULELOADER_H
-#define _LINUX_MODULELOADER_H
-/* The stuff needed for archs to support modules. */
 
-#include <linux/module.h>
-#include <linux/elf.h>
-
-/* These must be implemented by the specific architecture */
-
-/* Adjust arch-specific sections.  Return 0 on success.  */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-			      Elf_Shdr *sechdrs,
-			      char *secstrings,
-			      struct module *mod);
-
-/* Allocator used for allocating struct module, core sections and init
-   sections.  Returns NULL on failure. */
-void *module_alloc(unsigned long size);
-
-/* Free memory returned from module_alloc. */
-void module_free(struct module *mod, void *module_region);
-
-/* Apply the given relocation to the (simplified) ELF.  Return -error
-   or 0. */
-int apply_relocate(Elf_Shdr *sechdrs,
-		   const char *strtab,
-		   unsigned int symindex,
-		   unsigned int relsec,
-		   struct module *mod);
-
-/* Apply the given add relocation to the (simplified) ELF.  Return
-   -error or 0 */
-int apply_relocate_add(Elf_Shdr *sechdrs,
-		       const char *strtab,
-		       unsigned int symindex,
-		       unsigned int relsec,
-		       struct module *mod);
-
-/* Any final processing of module before access.  Return -error or 0. */
-int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *mod);
-
-#endif
Index: include/linux/moduleparam.h
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/include/linux/moduleparam.h,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 moduleparam.h
--- include/linux/moduleparam.h	27 Jan 2003 21:04:01 -0000	1.1.1.2
+++ include/linux/moduleparam.h	6 Feb 2003 22:18:53 -0000
@@ -1,127 +1 @@
-#ifndef _LINUX_MODULE_PARAMS_H
-#define _LINUX_MODULE_PARAMS_H
-/* (C) Copyright 2001, 2002 Rusty Russell IBM Corporation */
-#include <linux/init.h>
-#include <linux/stringify.h>
 
-/* You can override this manually, but generally this should match the
-   module name. */
-#ifdef MODULE
-#define MODULE_PARAM_PREFIX /* empty */
-#else
-#define MODULE_PARAM_PREFIX __stringify(KBUILD_MODNAME) "."
-#endif
-
-struct kernel_param;
-
-/* Returns 0, or -errno.  arg is in kp->arg. */
-typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
-/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
-typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
-
-struct kernel_param {
-	const char *name;
-	unsigned int perm;
-	param_set_fn set;
-	param_get_fn get;
-	void *arg;
-};
-
-/* Special one for strings we want to copy into */
-struct kparam_string {
-	unsigned int maxlen;
-	char *string;
-};
-
-/* This is the fundamental function for registering boot/module
-   parameters.  perm sets the visibility in driverfs: 000 means it's
-   not there, read bits mean it's readable, write bits mean it's
-   writable. */
-#define __module_param_call(prefix, name, set, get, arg, perm)		\
-	static char __param_str_##name[] __initdata = prefix #name;	\
-	static struct kernel_param const __param_##name			\
-		 __attribute__ ((unused,__section__ ("__param")))	\
-	= { __param_str_##name, perm, set, get, arg }
-
-#define module_param_call(name, set, get, arg, perm)			      \
-	__module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)
-
-/* Helper functions: type is byte, short, ushort, int, uint, long,
-   ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
-   param_set_XXX and param_check_XXX. */
-#define module_param_named(name, value, type, perm)			   \
-	param_check_##type(name, &(value));				   \
-	module_param_call(name, param_set_##type, param_get_##type, &value, perm)
-
-#define module_param(name, type, perm)				\
-	module_param_named(name, name, type, perm)
-
-/* Actually copy string: maxlen param is usually sizeof(string). */
-#define module_param_string(name, string, len, perm)			\
-	static struct kparam_string __param_string_##name __initdata	\
-		= { len, string };					\
-	module_param_call(name, param_set_copystring, param_get_charp,	\
-		   &__param_string_##name, perm)
-
-/* Called on module insert or kernel boot */
-extern int parse_args(const char *name,
-		      char *args,
-		      struct kernel_param *params,
-		      unsigned num,
-		      int (*unknown)(char *param, char *val));
-
-/* All the helper functions */
-/* The macros to do compile-time type checking stolen from Jakub
-   Jelinek, who IIRC came up with this idea for the 2.4 module init code. */
-#define __param_check(name, p, type) \
-	static inline type *__check_##name(void) { return(p); }
-
-extern int param_set_short(const char *val, struct kernel_param *kp);
-extern int param_get_short(char *buffer, struct kernel_param *kp);
-#define param_check_short(name, p) __param_check(name, p, short)
-
-extern int param_set_ushort(const char *val, struct kernel_param *kp);
-extern int param_get_ushort(char *buffer, struct kernel_param *kp);
-#define param_check_ushort(name, p) __param_check(name, p, unsigned short)
-
-extern int param_set_int(const char *val, struct kernel_param *kp);
-extern int param_get_int(char *buffer, struct kernel_param *kp);
-#define param_check_int(name, p) __param_check(name, p, int)
-
-extern int param_set_uint(const char *val, struct kernel_param *kp);
-extern int param_get_uint(char *buffer, struct kernel_param *kp);
-#define param_check_uint(name, p) __param_check(name, p, unsigned int)
-
-extern int param_set_long(const char *val, struct kernel_param *kp);
-extern int param_get_long(char *buffer, struct kernel_param *kp);
-#define param_check_long(name, p) __param_check(name, p, long)
-
-extern int param_set_ulong(const char *val, struct kernel_param *kp);
-extern int param_get_ulong(char *buffer, struct kernel_param *kp);
-#define param_check_ulong(name, p) __param_check(name, p, unsigned long)
-
-extern int param_set_charp(const char *val, struct kernel_param *kp);
-extern int param_get_charp(char *buffer, struct kernel_param *kp);
-#define param_check_charp(name, p) __param_check(name, p, char *)
-
-extern int param_set_bool(const char *val, struct kernel_param *kp);
-extern int param_get_bool(char *buffer, struct kernel_param *kp);
-#define param_check_bool(name, p) __param_check(name, p, int)
-
-extern int param_set_invbool(const char *val, struct kernel_param *kp);
-extern int param_get_invbool(char *buffer, struct kernel_param *kp);
-#define param_check_invbool(name, p) __param_check(name, p, int)
-
-/* First two elements are the max and min array length (which don't change) */
-extern int param_set_intarray(const char *val, struct kernel_param *kp);
-extern int param_get_intarray(char *buffer, struct kernel_param *kp);
-#define param_check_intarray(name, p) __param_check(name, p, int *)
-
-extern int param_set_copystring(const char *val, struct kernel_param *kp);
-
-int param_array(const char *name,
-		const char *val,
-		unsigned int min, unsigned int max,
-		void *elem, int elemsize,
-		int (*set)(const char *, struct kernel_param *kp));
-#endif /* _LINUX_MODULE_PARAM_TYPES_H */
Index: init/Kconfig
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/init/Kconfig,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 Kconfig
--- init/Kconfig	1 Feb 2003 19:59:58 -0000	1.1.1.6
+++ init/Kconfig	6 Feb 2003 22:18:54 -0000
@@ -116,33 +116,21 @@ config MODULES
 	  may want to make use of modules with this kernel in the future, then
 	  say Y here.  If unsure, say Y.
 
-config MODULE_UNLOAD
-	bool "Module unloading"
+config MODVERSIONS
+	#bool "Set version information on all module symbols"
 	depends on MODULES
-	help
-	  Without this option you will not be able to unload any
-	  modules (note that some modules may not be unloadable
-	  anyway), which makes your kernel slightly smaller and
-	  simpler.  If unsure, say Y.
-
-config MODULE_FORCE_UNLOAD
-	bool "Forced module unloading"
-	depends on MODULE_UNLOAD && EXPERIMENTAL
-	help
-	  This option allows you to force a module to unload, even if the
-	  kernel believes it is unsafe: the kernel will remove the module
-	  without waiting for anyone to stop using it (using the -f option to
-	  rmmod).  This is mainly for kernel developers and desparate users.
-	  If unsure, say N.
-
-config OBSOLETE_MODPARM
-	bool
-	default y
-	depends on MODULES
-	help
-	  You need this option to use module parameters on modules which
-	  have not been converted to the new module parameter system yet.
-	  If unsure, say Y.
+	---help---
+	  Usually, modules have to be recompiled whenever you switch to a new
+	  kernel.  Saying Y here makes it possible, and safe, to use the
+	  same modules even after compiling a new kernel; this requires the
+	  program modprobe. All the software needed for module support is in
+	  the modutils package (check the file <file:Documentation/Changes>
+	  for location and latest version).  NOTE: if you say Y here but don't
+	  have the program genksyms (which is also contained in the above
+	  mentioned modutils package), then the building of your kernel will
+	  fail.  If you are going to use modules that are generated from
+	  non-kernel sources, you would benefit from this option.  Otherwise
+	  it's not that important.  So, N ought to be a safe bet.
 
 config KMOD
 	bool "Kernel module loader"
Index: init/main.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/init/main.c,v
retrieving revision 1.1.1.34
diff -u -p -r1.1.1.34 main.c
--- init/main.c	1 Feb 2003 19:59:58 -0000	1.1.1.34
+++ init/main.c	6 Feb 2003 22:18:54 -0000
@@ -34,7 +34,6 @@
 #include <linux/workqueue.h>
 #include <linux/profile.h>
 #include <linux/rcupdate.h>
-#include <linux/moduleparam.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -58,6 +57,7 @@ extern char *linux_banner;
 static int init(void *);
 
 extern void init_IRQ(void);
+extern void init_modules(void);
 extern void sock_init(void);
 extern void fork_init(unsigned long);
 extern void mca_init(void);
@@ -133,10 +133,9 @@ char * envp_init[MAX_INIT_ENVS+2] = { "H
 
 __setup("profile=", profile_setup);
 
-static int __init obsolete_checksetup(char *line)
+static int __init checksetup(char *line)
 {
-	struct obs_kernel_param *p;
-	extern struct obs_kernel_param __setup_start, __setup_end;
+	struct kernel_param *p;
 
 	p = &__setup_start;
 	do {
@@ -219,43 +218,71 @@ static int __init quiet_kernel(char *str
 __setup("debug", debug_kernel);
 __setup("quiet", quiet_kernel);
 
-/* Unknown boot options get handed to init, unless they look like
-   failed parameters */
-static int __init unknown_bootoption(char *param, char *val)
-{
-	/* Change NUL term back to "=", to make "param" the whole string. */
-	if (val)
-		val[-1] = '=';
-
-	/* Handle obsolete-style parameters */
-	if (obsolete_checksetup(param))
-		return 0;
-
-	/* Preemptive maintenance for "why didn't my mispelled command
-           line work?" */
-	if (strchr(param, '.') && (!val || strchr(param, '.') < val)) {
-		printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param);
-		return 0;
-	}
+/*
+ * This is a simple kernel command line parsing function: it parses
+ * the command line, and fills in the arguments/environment to init
+ * as appropriate. Any cmd-line option is taken to be an environment
+ * variable if it contains the character '='.
+ *
+ * This routine also checks for options meant for the kernel.
+ * These options are not given to init - they are for internal kernel use only.
+ */
+static void __init parse_options(char *line)
+{
+	char *next,*quote;
+	int args, envs;
 
-	if (val) {
-		/* Environment option */
-		unsigned int i;
-		for (i = 0; envp_init[i]; i++) {
-			if (i == MAX_INIT_ENVS)
-				panic("Too many boot env vars at `%s'", param);
+	if (!*line)
+		return;
+	args = 0;
+	envs = 1;	/* TERM is set to 'linux' by default */
+	next = line;
+	while ((line = next) != NULL) {
+                quote = strchr(line,'"');
+                next = strchr(line, ' ');
+                while (next != NULL && quote != NULL && quote < next) {
+                        /* we found a left quote before the next blank
+                         * now we have to find the matching right quote
+                         */
+                        next = strchr(quote+1, '"');
+                        if (next != NULL) {
+                                quote = strchr(next+1, '"');
+                                next = strchr(next+1, ' ');
+                        }
+                }
+                if (next != NULL)
+                        *next++ = 0;
+		if (!strncmp(line,"init=",5)) {
+			line += 5;
+			execute_command = line;
+			/* In case LILO is going to boot us with default command line,
+			 * it prepends "auto" before the whole cmdline which makes
+			 * the shell think it should execute a script with such name.
+			 * So we ignore all arguments entered _before_ init=... [MJ]
+			 */
+			args = 0;
+			continue;
 		}
-		envp_init[i] = param;
-	} else {
-		/* Command line option */
-		unsigned int i;
-		for (i = 0; argv_init[i]; i++) {
-			if (i == MAX_INIT_ARGS)
-				panic("Too many boot init vars at `%s'",param);
+		if (checksetup(line))
+			continue;
+		
+		/*
+		 * Then check if it's an environment variable or
+		 * an option.
+		 */
+		if (strchr(line,'=')) {
+			if (envs >= MAX_INIT_ENVS)
+				break;
+			envp_init[++envs] = line;
+		} else {
+			if (args >= MAX_INIT_ARGS)
+				break;
+			if (*line)
+				argv_init[++args] = line;
 		}
-		argv_init[i] = param;
 	}
-	return 0;
+	argv_init[args+1] = NULL;
+	envp_init[envs+1] = NULL;
 }
 
 static int __init init_setup(char *str)
@@ -367,7 +394,6 @@ asmlinkage void __init start_kernel(void
 {
 	char * command_line;
 	extern char saved_command_line[];
-	extern struct kernel_param __start___param, __stop___param;
 /*
  * Interrupts are still disabled. Do necessary setups, then
  * enable them
@@ -386,9 +412,7 @@ asmlinkage void __init start_kernel(void
 	build_all_zonelists();
 	page_alloc_init();
 	printk("Kernel command line: %s\n", saved_command_line);
-	parse_args("Booting kernel", command_line, &__start___param,
-		   &__stop___param - &__start___param,
-		   &unknown_bootoption);
+	parse_options(command_line);
 	trap_init();
 	rcu_init();
 	init_IRQ();
@@ -403,6 +427,9 @@ asmlinkage void __init start_kernel(void
 	 * this. But we do want output early, in case something goes wrong.
 	 */
 	console_init();
+#ifdef CONFIG_MODULES
+	init_modules();
+#endif
 	profile_init();
 	kmem_cache_init();
 	local_irq_enable();
Index: kernel/Makefile
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/Makefile,v
retrieving revision 1.1.1.19
diff -u -p -r1.1.1.19 Makefile
--- kernel/Makefile	27 Jan 2003 21:50:11 -0000	1.1.1.19
+++ kernel/Makefile	6 Feb 2003 22:18:54 -0000
@@ -4,18 +4,18 @@
 
 export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \
 		printk.o suspend.o dma.o module.o cpufreq.o \
-		profile.o rcupdate.o intermodule.o params.o
+		profile.o rcupdate.o kallsyms.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
-	    exit.o itimer.o time.o softirq.o resource.o \
+	    module.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o futex.o pid.o \
-	    rcupdate.o intermodule.o extable.o params.o
+	    rcupdate.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
 obj-$(CONFIG_UID16) += uid16.o
-obj-$(CONFIG_MODULES) += ksyms.o module.o
+obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_CPU_FREQ) += cpufreq.o
Index: kernel/extable.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/extable.c,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 extable.c
--- kernel/extable.c	27 Jan 2003 21:50:14 -0000	1.1.1.2
+++ kernel/extable.c	6 Feb 2003 22:18:54 -0000
@@ -1,42 +1 @@
-/* Rewritten by Rusty Russell, on the backs of many others...
-   Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-#include <linux/module.h>
-
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
-extern char _stext[], _etext[];
-
-/* Given an address, look for it in the exception tables. */
-const struct exception_table_entry *search_exception_tables(unsigned long addr)
-{
-	const struct exception_table_entry *e;
-
-	e = search_extable(__start___ex_table, __stop___ex_table-1, addr);
-	if (!e)
-		e = search_module_extables(addr);
-	return e;
-}
-
-int kernel_text_address(unsigned long addr)
-{
-	if (addr >= (unsigned long)_stext &&
-	    addr <= (unsigned long)_etext)
-		return 1;
-
-	return module_text_address(addr);
-}
Index: kernel/intermodule.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/intermodule.c,v
retrieving revision 1.1.1.2
diff -u -p -r1.1.1.2 intermodule.c
--- kernel/intermodule.c	27 Jan 2003 21:03:43 -0000	1.1.1.2
+++ kernel/intermodule.c	6 Feb 2003 22:18:54 -0000
@@ -1,183 +1 @@
-/* Deprecated, do not use.  Moved from module.c to here. --RR */
 
-/* Written by Keith Owens <kaos@ocs.com.au> Oct 2000 */
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-
-/* inter_module functions are always available, even when the kernel is
- * compiled without modules.  Consumers of inter_module_xxx routines
- * will always work, even when both are built into the kernel, this
- * approach removes lots of #ifdefs in mainline code.
- */
-
-static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
-static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED;
-static int kmalloc_failed;
-
-struct inter_module_entry {
-	struct list_head list;
-	const char *im_name;
-	struct module *owner;
-	const void *userdata;
-};
-
-/**
- * inter_module_register - register a new set of inter module data.
- * @im_name: an arbitrary string to identify the data, must be unique
- * @owner: module that is registering the data, always use THIS_MODULE
- * @userdata: pointer to arbitrary userdata to be registered
- *
- * Description: Check that the im_name has not already been registered,
- * complain if it has.  For new data, add it to the inter_module_entry
- * list.
- */
-void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
-{
-	struct list_head *tmp;
-	struct inter_module_entry *ime, *ime_new;
-
-	if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
-		/* Overloaded kernel, not fatal */
-		printk(KERN_ERR
-			"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
-			im_name);
-		kmalloc_failed = 1;
-		return;
-	}
-	memset(ime_new, 0, sizeof(*ime_new));
-	ime_new->im_name = im_name;
-	ime_new->owner = owner;
-	ime_new->userdata = userdata;
-
-	spin_lock(&ime_lock);
-	list_for_each(tmp, &ime_list) {
-		ime = list_entry(tmp, struct inter_module_entry, list);
-		if (strcmp(ime->im_name, im_name) == 0) {
-			spin_unlock(&ime_lock);
-			kfree(ime_new);
-			/* Program logic error, fatal */
-			printk(KERN_ERR "inter_module_register: duplicate im_name '%s'", im_name);
-			BUG();
-		}
-	}
-	list_add(&(ime_new->list), &ime_list);
-	spin_unlock(&ime_lock);
-}
-
-/**
- * inter_module_unregister - unregister a set of inter module data.
- * @im_name: an arbitrary string to identify the data, must be unique
- *
- * Description: Check that the im_name has been registered, complain if
- * it has not.  For existing data, remove it from the
- * inter_module_entry list.
- */
-void inter_module_unregister(const char *im_name)
-{
-	struct list_head *tmp;
-	struct inter_module_entry *ime;
-
-	spin_lock(&ime_lock);
-	list_for_each(tmp, &ime_list) {
-		ime = list_entry(tmp, struct inter_module_entry, list);
-		if (strcmp(ime->im_name, im_name) == 0) {
-			list_del(&(ime->list));
-			spin_unlock(&ime_lock);
-			kfree(ime);
-			return;
-		}
-	}
-	spin_unlock(&ime_lock);
-	if (kmalloc_failed) {
-		printk(KERN_ERR
-			"inter_module_unregister: no entry for '%s', "
-			"probably caused by previous kmalloc failure\n",
-			im_name);
-		return;
-	}
-	else {
-		/* Program logic error, fatal */
-		printk(KERN_ERR "inter_module_unregister: no entry for '%s'", im_name);
-		BUG();
-	}
-}
-
-/**
- * inter_module_get - return arbitrary userdata from another module.
- * @im_name: an arbitrary string to identify the data, must be unique
- *
- * Description: If the im_name has not been registered, return NULL.
- * Try to increment the use count on the owning module, if that fails
- * then return NULL.  Otherwise return the userdata.
- */
-const void *inter_module_get(const char *im_name)
-{
-	struct list_head *tmp;
-	struct inter_module_entry *ime;
-	const void *result = NULL;
-
-	spin_lock(&ime_lock);
-	list_for_each(tmp, &ime_list) {
-		ime = list_entry(tmp, struct inter_module_entry, list);
-		if (strcmp(ime->im_name, im_name) == 0) {
-			if (try_module_get(ime->owner))
-				result = ime->userdata;
-			break;
-		}
-	}
-	spin_unlock(&ime_lock);
-	return(result);
-}
-
-/**
- * inter_module_get_request - im get with automatic request_module.
- * @im_name: an arbitrary string to identify the data, must be unique
- * @modname: module that is expected to register im_name
- *
- * Description: If inter_module_get fails, do request_module then retry.
- */
-const void *inter_module_get_request(const char *im_name, const char *modname)
-{
-	const void *result = inter_module_get(im_name);
-	if (!result) {
-		request_module(modname);
-		result = inter_module_get(im_name);
-	}
-	return(result);
-}
-
-/**
- * inter_module_put - release use of data from another module.
- * @im_name: an arbitrary string to identify the data, must be unique
- *
- * Description: If the im_name has not been registered, complain,
- * otherwise decrement the use count on the owning module.
- */
-void inter_module_put(const char *im_name)
-{
-	struct list_head *tmp;
-	struct inter_module_entry *ime;
-
-	spin_lock(&ime_lock);
-	list_for_each(tmp, &ime_list) {
-		ime = list_entry(tmp, struct inter_module_entry, list);
-		if (strcmp(ime->im_name, im_name) == 0) {
-			if (ime->owner)
-				module_put(ime->owner);
-			spin_unlock(&ime_lock);
-			return;
-		}
-	}
-	spin_unlock(&ime_lock);
-	printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name);
-	BUG();
-}
-
-EXPORT_SYMBOL(inter_module_register);
-EXPORT_SYMBOL(inter_module_unregister);
-EXPORT_SYMBOL(inter_module_get);
-EXPORT_SYMBOL(inter_module_get_request);
-EXPORT_SYMBOL(inter_module_put);
Index: kernel/kallsyms.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/kallsyms.c,v
retrieving revision 1.1.1.8
diff -u -p -r1.1.1.8 kallsyms.c
--- kernel/kallsyms.c	1 Feb 2003 20:00:00 -0000	1.1.1.8
+++ kernel/kallsyms.c	6 Feb 2003 22:18:54 -0000
@@ -7,6 +7,7 @@
  * Stem compression by Andi Kleen.
  */
 #include <linux/kallsyms.h>
+#include <linux/string.h>
 #include <linux/module.h>
 
 /* These will be re-linked against their real values during the second link stage */
@@ -61,7 +62,11 @@ const char *kallsyms_lookup(unsigned lon
 		return namebuf;
 	}
 
+#if 0
 	return module_address_lookup(addr, symbolsize, offset, modname);
+#else
+	return 0;
+#endif
 }
 
 /* Replace "%s" in format with address, or returns -errno. */
Index: kernel/kmod.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/kmod.c,v
retrieving revision 1.1.1.14
diff -u -p -r1.1.1.14 kmod.c
--- kernel/kmod.c	27 Nov 2002 23:21:19 -0000	1.1.1.14
+++ kernel/kmod.c	6 Feb 2003 22:18:54 -0000
@@ -156,7 +156,7 @@ char modprobe_path[256] = "/sbin/modprob
 static int exec_modprobe(void * module_name)
 {
 	static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-	char *argv[] = { modprobe_path, "--", (char*)module_name, NULL };
+	char *argv[] = { modprobe_path, "-s", "-k", "--", (char*)module_name, NULL };
 	int ret;
 
 	if (!system_running)
Index: kernel/ksyms.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/ksyms.c,v
retrieving revision 1.1.1.52
diff -u -p -r1.1.1.52 ksyms.c
--- kernel/ksyms.c	1 Feb 2003 18:05:35 -0000	1.1.1.52
+++ kernel/ksyms.c	6 Feb 2003 22:18:54 -0000
@@ -75,6 +75,13 @@ __attribute__((section("__ksymtab"))) = 
 };
 #endif
 
+EXPORT_SYMBOL(inter_module_register);
+EXPORT_SYMBOL(inter_module_unregister);
+EXPORT_SYMBOL(inter_module_get);
+EXPORT_SYMBOL(inter_module_get_request);
+EXPORT_SYMBOL(inter_module_put);
+EXPORT_SYMBOL(try_inc_mod_count);
+
 /* process memory management */
 EXPORT_SYMBOL(do_mmap_pgoff);
 EXPORT_SYMBOL(do_munmap);
Index: kernel/module.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/module.c,v
retrieving revision 1.1.1.17
diff -u -p -r1.1.1.17 module.c
--- kernel/module.c	1 Feb 2003 19:59:59 -0000	1.1.1.17
+++ kernel/module.c	6 Feb 2003 22:18:55 -0000
@@ -1,1516 +1,1354 @@
-/* Rewritten by Rusty Russell, on the backs of many others...
-   Copyright (C) 2002 Richard Henderson
-   Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
 #include <linux/config.h>
+#include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/moduleloader.h>
+#include <asm/module.h>
+#include <asm/uaccess.h>
+#include <linux/kallsyms.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <asm/pgalloc.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/elf.h>
+#include <linux/kmod.h>
 #include <linux/seq_file.h>
-#include <linux/fcntl.h>
-#include <linux/rcupdate.h>
-#include <linux/cpu.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
-#include <asm/pgalloc.h>
+#include <linux/fs.h>
 #include <asm/cacheflush.h>
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt , a...)
-#endif
-
-#ifndef ARCH_SHF_SMALL
-#define ARCH_SHF_SMALL 0
-#endif
-
-/* If this is set, the section belongs in the init part of the module */
-#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
-
-#define symbol_is(literal, string)				\
-	(strcmp(MODULE_SYMBOL_PREFIX literal, (string)) == 0)
-
-/* Protects extables and symbols lists */
-static spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED;
-
-/* List of modules, protected by module_mutex AND modlist_lock */
-static DECLARE_MUTEX(module_mutex);
-static LIST_HEAD(modules);
-static LIST_HEAD(symbols);
-static LIST_HEAD(extables);
+/*
+ * Originally by Anonymous (as far as I know...)
+ * Linux version by Bas Laarhoven <bas@vimec.nl>
+ * 0.99.14 version by Jon Tombs <jon@gtex02.us.es>,
+ * Heavily modified by Bjorn Ekwall <bj0rn@blox.se> May 1994 (C)
+ * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
+ * Add MOD_INITIALIZING Keith Owens <kaos@ocs.com.au> Nov 1999
+ * Add kallsyms support, Keith Owens <kaos@ocs.com.au> Apr 2000
+ * Add asm/module support, IA64 has special requirements.  Keith Owens <kaos@ocs.com.au> Sep 2000
+ * Fix assorted bugs in module verification.  Keith Owens <kaos@ocs.com.au> Sep 2000
+ * Fix sys_init_module race, Andrew Morton <andrewm@uow.edu.au> Oct 2000
+ *     http://www.uwsg.iu.edu/hypermail/linux/kernel/0008.3/0379.html
+ * Replace xxx_module_symbol with inter_module_xxx.  Keith Owens <kaos@ocs.com.au> Oct 2000
+ * Add a module list lock for kernel fault race fixing. Alan Cox <alan@redhat.com>
+ *
+ * This source is covered by the GNU GPL, the same as all kernel sources.
+ */
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+extern char _stext[], _etext[];
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+extern struct module_symbol __start___ksymtab[];
+extern struct module_symbol __stop___ksymtab[];
+
+extern const char __start___kallsyms[] __attribute__((weak));
+extern const char __stop___kallsyms[] __attribute__((weak));
+
+/* modutils uses these exported symbols to figure out if
+   kallsyms support is present */
+
+EXPORT_SYMBOL(__start___kallsyms);
+EXPORT_SYMBOL(__stop___kallsyms);
+
+struct module kernel_module =
+{
+	.size_of_struct		= sizeof(struct module),
+	.name 			= "",
+	.uc	 		= {ATOMIC_INIT(1)},
+	.flags			= MOD_RUNNING,
+	.syms			= __start___ksymtab,
+	.ex_table_start		= __start___ex_table,
+	.ex_table_end		= __stop___ex_table,
+	.kallsyms_start		= __start___kallsyms,
+	.kallsyms_end		= __stop___kallsyms,
+};
 
-/* We require a truly strong try_module_get() */
-static inline int strong_try_module_get(struct module *mod)
-{
-	if (mod && mod->state == MODULE_STATE_COMING)
-		return 0;
-	return try_module_get(mod);
-}
+struct module *module_list = &kernel_module;
 
-/* Stub function for modules which don't have an initfn */
-int init_module(void)
-{
-	return 0;
-}
-EXPORT_SYMBOL(init_module);
+#endif	/* defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) */
 
-/* Find a symbol, return value and the symbol group */
-static unsigned long __find_symbol(const char *name,
-				   struct kernel_symbol_group **group,
-				   int gplok)
-{
-	struct kernel_symbol_group *ks;
+/* inter_module functions are always available, even when the kernel is
+ * compiled without modules.  Consumers of inter_module_xxx routines
+ * will always work, even when both are built into the kernel, this
+ * approach removes lots of #ifdefs in mainline code.
+ */
+
+static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
+static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED;
+static int kmalloc_failed;
+
+/*
+ *	This lock prevents modifications that might race the kernel fault
+ *	fixups. It does not prevent reader walks that the modules code
+ *	does. The kernel lock does that.
+ *
+ *	Since vmalloc fault fixups occur in any context this lock is taken
+ *	irqsave at all times.
+ */
  
-	list_for_each_entry(ks, &symbols, list) {
- 		unsigned int i;
+spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED;
 
-		if (ks->gplonly && !gplok)
-			continue;
-		for (i = 0; i < ks->num_syms; i++) {
-			if (strcmp(ks->syms[i].name, name) == 0) {
-				*group = ks;
-				return ks->syms[i].value;
-			}
+/**
+ * inter_module_register - register a new set of inter module data.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ * @owner: module that is registering the data, always use THIS_MODULE
+ * @userdata: pointer to arbitrary userdata to be registered
+ *
+ * Description: Check that the im_name has not already been registered,
+ * complain if it has.  For new data, add it to the inter_module_entry
+ * list.
+ */
+void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
+{
+	struct list_head *tmp;
+	struct inter_module_entry *ime, *ime_new;
+
+	if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+		/* Overloaded kernel, not fatal */
+		printk(KERN_ERR
+			"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
+			im_name);
+		kmalloc_failed = 1;
+		return;
+	}
+	memset(ime_new, 0, sizeof(*ime_new));
+	ime_new->im_name = im_name;
+	ime_new->owner = owner;
+	ime_new->userdata = userdata;
+
+	spin_lock(&ime_lock);
+	list_for_each(tmp, &ime_list) {
+		ime = list_entry(tmp, struct inter_module_entry, list);
+		if (strcmp(ime->im_name, im_name) == 0) {
+			spin_unlock(&ime_lock);
+			kfree(ime_new);
+			/* Program logic error, fatal */
+			printk(KERN_ERR "inter_module_register: duplicate im_name '%s'", im_name);
+			BUG();
 		}
 	}
-	DEBUGP("Failed to find symbol %s\n", name);
- 	return 0;
-}
-
-/* Find a symbol in this elf symbol table */
-static unsigned long find_local_symbol(Elf_Shdr *sechdrs,
-				       unsigned int symindex,
-				       const char *strtab,
-				       const char *name)
-{
-	unsigned int i;
-	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
-
-	/* Search (defined) internal symbols first. */
-	for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) {
-		if (sym[i].st_shndx != SHN_UNDEF
-		    && strcmp(name, strtab + sym[i].st_name) == 0)
-			return sym[i].st_value;
-	}
-	return 0;
-}
-
-/* Search for module by name: must hold module_mutex. */
-static struct module *find_module(const char *name)
-{
-	struct module *mod;
-
-	list_for_each_entry(mod, &modules, list) {
-		if (strcmp(mod->name, name) == 0)
-			return mod;
-	}
-	return NULL;
-}
-
-#ifdef CONFIG_MODULE_UNLOAD
-/* Init the unload section of the module. */
-static void module_unload_init(struct module *mod)
-{
-	unsigned int i;
-
-	INIT_LIST_HEAD(&mod->modules_which_use_me);
-	for (i = 0; i < NR_CPUS; i++)
-		atomic_set(&mod->ref[i].count, 0);
-	/* Backwards compatibility macros put refcount during init. */
-	mod->waiter = current;
+	list_add(&(ime_new->list), &ime_list);
+	spin_unlock(&ime_lock);
 }
 
-/* modules using other modules */
-struct module_use
-{
-	struct list_head list;
-	struct module *module_which_uses;
-};
-
-/* Does a already use b? */
-static int already_uses(struct module *a, struct module *b)
-{
-	struct module_use *use;
-
-	list_for_each_entry(use, &b->modules_which_use_me, list) {
-		if (use->module_which_uses == a) {
-			DEBUGP("%s uses %s!\n", a->name, b->name);
-			return 1;
+/**
+ * inter_module_unregister - unregister a set of inter module data.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ *
+ * Description: Check that the im_name has been registered, complain if
+ * it has not.  For existing data, remove it from the
+ * inter_module_entry list.
+ */
+void inter_module_unregister(const char *im_name)
+{
+	struct list_head *tmp;
+	struct inter_module_entry *ime;
+
+	spin_lock(&ime_lock);
+	list_for_each(tmp, &ime_list) {
+		ime = list_entry(tmp, struct inter_module_entry, list);
+		if (strcmp(ime->im_name, im_name) == 0) {
+			list_del(&(ime->list));
+			spin_unlock(&ime_lock);
+			kfree(ime);
+			return;
 		}
 	}
-	DEBUGP("%s does not use %s!\n", a->name, b->name);
-	return 0;
-}
-
-/* Module a uses b */
-static int use_module(struct module *a, struct module *b)
-{
-	struct module_use *use;
-	if (b == NULL || already_uses(a, b)) return 1;
-
-	DEBUGP("Allocating new usage for %s.\n", a->name);
-	use = kmalloc(sizeof(*use), GFP_ATOMIC);
-	if (!use) {
-		printk("%s: out of memory loading\n", a->name);
-		return 0;
+	spin_unlock(&ime_lock);
+	if (kmalloc_failed) {
+		printk(KERN_ERR
+			"inter_module_unregister: no entry for '%s', "
+			"probably caused by previous kmalloc failure\n",
+			im_name);
+		return;
+	}
+	else {
+		/* Program logic error, fatal */
+		printk(KERN_ERR "inter_module_unregister: no entry for '%s'", im_name);
+		BUG();
 	}
-
-	use->module_which_uses = a;
-	list_add(&use->list, &b->modules_which_use_me);
-	try_module_get(b); /* Can't fail */
-	return 1;
 }
 
-/* Clear the unload stuff of the module. */
-static void module_unload_free(struct module *mod)
-{
-	struct module *i;
-
-	list_for_each_entry(i, &modules, list) {
-		struct module_use *use;
-
-		list_for_each_entry(use, &i->modules_which_use_me, list) {
-			if (use->module_which_uses == mod) {
-				DEBUGP("%s unusing %s\n", mod->name, i->name);
-				module_put(i);
-				list_del(&use->list);
-				kfree(use);
-				/* There can be at most one match. */
-				break;
-			}
+/**
+ * inter_module_get - return arbitrary userdata from another module.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ *
+ * Description: If the im_name has not been registered, return NULL.
+ * Try to increment the use count on the owning module, if that fails
+ * then return NULL.  Otherwise return the userdata.
+ */
+const void *inter_module_get(const char *im_name)
+{
+	struct list_head *tmp;
+	struct inter_module_entry *ime;
+	const void *result = NULL;
+
+	spin_lock(&ime_lock);
+	list_for_each(tmp, &ime_list) {
+		ime = list_entry(tmp, struct inter_module_entry, list);
+		if (strcmp(ime->im_name, im_name) == 0) {
+			if (try_inc_mod_count(ime->owner))
+				result = ime->userdata;
+			break;
 		}
 	}
+	spin_unlock(&ime_lock);
+	return(result);
 }
 
-#ifdef CONFIG_SMP
-/* Thread to stop each CPU in user context. */
-enum stopref_state {
-	STOPREF_WAIT,
-	STOPREF_PREPARE,
-	STOPREF_DISABLE_IRQ,
-	STOPREF_EXIT,
-};
-
-static enum stopref_state stopref_state;
-static unsigned int stopref_num_threads;
-static atomic_t stopref_thread_ack;
-
-static int stopref(void *cpu)
-{
-	int irqs_disabled = 0;
-	int prepared = 0;
-
-	sprintf(current->comm, "kmodule%lu\n", (unsigned long)cpu);
-
-	/* Highest priority we can manage, and move to right CPU. */
-#if 0 /* FIXME */
-	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-	setscheduler(current->pid, SCHED_FIFO, &param);
-#endif
-	set_cpus_allowed(current, 1UL << (unsigned long)cpu);
-
-	/* Ack: we are alive */
-	atomic_inc(&stopref_thread_ack);
-
-	/* Simple state machine */
-	while (stopref_state != STOPREF_EXIT) {
-		if (stopref_state == STOPREF_DISABLE_IRQ && !irqs_disabled) {
-			local_irq_disable();
-			irqs_disabled = 1;
-			/* Ack: irqs disabled. */
-			atomic_inc(&stopref_thread_ack);
-		} else if (stopref_state == STOPREF_PREPARE && !prepared) {
-			/* Everyone is in place, hold CPU. */
-			preempt_disable();
-			prepared = 1;
-			atomic_inc(&stopref_thread_ack);
+/**
+ * inter_module_get_request - im get with automatic request_module.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ * @modname: module that is expected to register im_name
+ *
+ * Description: If inter_module_get fails, do request_module then retry.
+ */
+const void *inter_module_get_request(const char *im_name, const char *modname)
+{
+	const void *result = inter_module_get(im_name);
+	if (!result) {
+		request_module(modname);
+		result = inter_module_get(im_name);
+	}
+	return(result);
+}
+
+/**
+ * inter_module_put - release use of data from another module.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ *
+ * Description: If the im_name has not been registered, complain,
+ * otherwise decrement the use count on the owning module.
+ */
+void inter_module_put(const char *im_name)
+{
+	struct list_head *tmp;
+	struct inter_module_entry *ime;
+
+	spin_lock(&ime_lock);
+	list_for_each(tmp, &ime_list) {
+		ime = list_entry(tmp, struct inter_module_entry, list);
+		if (strcmp(ime->im_name, im_name) == 0) {
+			if (ime->owner)
+				__MOD_DEC_USE_COUNT(ime->owner);
+			spin_unlock(&ime_lock);
+			return;
 		}
-		if (irqs_disabled || prepared)
-			cpu_relax();
-		else
-			yield();
 	}
-
-	/* Ack: we are exiting. */
-	atomic_inc(&stopref_thread_ack);
-
-	if (irqs_disabled)
-		local_irq_enable();
-	if (prepared)
-		preempt_enable();
-
-	return 0;
+	spin_unlock(&ime_lock);
+	printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name);
+	BUG();
 }
 
-/* Change the thread state */
-static void stopref_set_state(enum stopref_state state, int sleep)
-{
-	atomic_set(&stopref_thread_ack, 0);
-	wmb();
-	stopref_state = state;
-	while (atomic_read(&stopref_thread_ack) != stopref_num_threads) {
-		if (sleep)
-			yield();
-		else
-			cpu_relax();
-	}
-}
 
-/* Stop the machine.  Disables irqs. */
-static int stop_refcounts(void)
-{
-	unsigned int i, cpu;
-	unsigned long old_allowed;
-	int ret = 0;
+#if defined(CONFIG_MODULES)	/* The rest of the source */
 
-	/* One thread per cpu.  We'll do our own. */
-	cpu = smp_processor_id();
+static long get_mod_name(const char *user_name, char **buf);
+static void put_mod_name(char *buf);
+struct module *find_module(const char *name);
+void free_module(struct module *, int tag_freed);
 
-	/* FIXME: racy with set_cpus_allowed. */
-	old_allowed = current->cpus_allowed;
-	set_cpus_allowed(current, 1UL << (unsigned long)cpu);
 
-	atomic_set(&stopref_thread_ack, 0);
-	stopref_num_threads = 0;
-	stopref_state = STOPREF_WAIT;
+/*
+ * Called at boot time
+ */
 
-	/* No CPUs can come up or down during this. */
-	down(&cpucontrol);
-
-	for (i = 0; i < NR_CPUS; i++) {
-		if (i == cpu || !cpu_online(i))
-			continue;
-		ret = kernel_thread(stopref, (void *)(long)i, CLONE_KERNEL);
-		if (ret < 0)
-			break;
-		stopref_num_threads++;
-	}
+void __init init_modules(void)
+{
+	kernel_module.nsyms = __stop___ksymtab - __start___ksymtab;
 
-	/* Wait for them all to come to life. */
-	while (atomic_read(&stopref_thread_ack) != stopref_num_threads)
-		yield();
+	arch_init_modules(&kernel_module);
+}
 
-	/* If some failed, kill them all. */
-	if (ret < 0) {
-		stopref_set_state(STOPREF_EXIT, 1);
-		up(&cpucontrol);
-		return ret;
-	}
+/*
+ * Copy the name of a module from user space.
+ */
 
-	/* Don't schedule us away at this point, please. */
-	preempt_disable();
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+	unsigned long page;
+	long retval;
 
-	/* Now they are all scheduled, make them hold the CPUs, ready. */
-	stopref_set_state(STOPREF_PREPARE, 0);
+	page = __get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
 
-	/* Make them disable irqs. */
-	stopref_set_state(STOPREF_DISABLE_IRQ, 0);
+	retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+	if (retval > 0) {
+		if (retval < PAGE_SIZE) {
+			*buf = (char *)page;
+			return retval;
+		}
+		retval = -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -EINVAL;
 
-	local_irq_disable();
-	return 0;
+	free_page(page);
+	return retval;
 }
 
-/* Restart the machine.  Re-enables irqs. */
-static void restart_refcounts(void)
-{
-	stopref_set_state(STOPREF_EXIT, 0);
-	local_irq_enable();
-	preempt_enable();
-	up(&cpucontrol);
-}
-#else /* ...!SMP */
-static inline int stop_refcounts(void)
-{
-	local_irq_disable();
-	return 0;
-}
-static inline void restart_refcounts(void)
+static inline void
+put_mod_name(char *buf)
 {
-	local_irq_enable();
+	free_page((unsigned long)buf);
 }
-#endif
 
-static unsigned int module_refcount(struct module *mod)
+/*
+ * Allocate space for a module.
+ */
+
+asmlinkage unsigned long
+sys_create_module(const char *name_user, size_t size)
 {
-	unsigned int i, total = 0;
+	char *name;
+	long namelen, error;
+	struct module *mod;
+	unsigned long flags;
 
-	for (i = 0; i < NR_CPUS; i++)
-		total += atomic_read(&mod->ref[i].count);
-	return total;
-}
+	if (!capable(CAP_SYS_MODULE))
+		return -EPERM;
+	lock_kernel();
+	if ((namelen = get_mod_name(name_user, &name)) < 0) {
+		error = namelen;
+		goto err0;
+	}
+	if (size < sizeof(struct module)+namelen) {
+		error = -EINVAL;
+		goto err1;
+	}
+	if (find_module(name) != NULL) {
+		error = -EEXIST;
+		goto err1;
+	}
+	if ((mod = (struct module *)module_map(size)) == NULL) {
+		error = -ENOMEM;
+		goto err1;
+	}
+
+	memset(mod, 0, sizeof(*mod));
+	mod->size_of_struct = sizeof(*mod);
+	mod->name = (char *)(mod + 1);
+	mod->size = size;
+	memcpy((char*)(mod+1), name, namelen+1);
 
-/* This exists whether we can unload or not */
-static void free_module(struct module *mod);
+	put_mod_name(name);
 
-#ifdef CONFIG_MODULE_FORCE_UNLOAD
-static inline int try_force(unsigned int flags)
-{
-	return (flags & O_TRUNC);
-}
-#else
-static inline int try_force(unsigned int flags)
-{
-	return 0;
-}
-#endif /* CONFIG_MODULE_FORCE_UNLOAD */
+	spin_lock_irqsave(&modlist_lock, flags);
+	mod->next = module_list;
+	module_list = mod;	/* link it in */
+	spin_unlock_irqrestore(&modlist_lock, flags);
 
-/* Stub function for modules which don't have an exitfn */
-void cleanup_module(void)
-{
+	error = (long) mod;
+	goto err0;
+err1:
+	put_mod_name(name);
+err0:
+	unlock_kernel();
+	return error;
 }
-EXPORT_SYMBOL(cleanup_module);
+
+/*
+ * Initialize a module.
+ */
 
 asmlinkage long
-sys_delete_module(const char *name_user, unsigned int flags)
+sys_init_module(const char *name_user, struct module *mod_user)
 {
-	struct module *mod;
-	char name[MODULE_NAME_LEN];
-	int ret, forced = 0;
+	struct module mod_tmp, *mod;
+	char *name, *n_name, *name_tmp = NULL;
+	long namelen, n_namelen, i, error;
+	unsigned long mod_user_size;
+	struct module_ref *dep;
 
 	if (!capable(CAP_SYS_MODULE))
 		return -EPERM;
+	lock_kernel();
+	if ((namelen = get_mod_name(name_user, &name)) < 0) {
+		error = namelen;
+		goto err0;
+	}
+	if ((mod = find_module(name)) == NULL) {
+		error = -ENOENT;
+		goto err1;
+	}
+
+	/* Check module header size.  We allow a bit of slop over the
+	   size we are familiar with to cope with a version of insmod
+	   for a newer kernel.  But don't over do it. */
+	if ((error = get_user(mod_user_size, &mod_user->size_of_struct)) != 0)
+		goto err1;
+	if (mod_user_size < (unsigned long)&((struct module *)0L)->persist_start
+	    || mod_user_size > sizeof(struct module) + 16*sizeof(void*)) {
+		printk(KERN_ERR "init_module: Invalid module header size.\n"
+		       KERN_ERR "A new version of the modutils is likely "
+				"needed.\n");
+		error = -EINVAL;
+		goto err1;
+	}
+
+	/* Hold the current contents while we play with the user's idea
+	   of righteousness.  */
+	mod_tmp = *mod;
+	name_tmp = kmalloc(strlen(mod->name) + 1, GFP_KERNEL);	/* Where's kstrdup()? */
+	if (name_tmp == NULL) {
+		error = -ENOMEM;
+		goto err1;
+	}
+	strcpy(name_tmp, mod->name);
+
+	error = copy_from_user(mod, mod_user, mod_user_size);
+	if (error) {
+		error = -EFAULT;
+		goto err2;
+	}
+
+	/* Sanity check the size of the module.  */
+	error = -EINVAL;
+
+	if (mod->size > mod_tmp.size) {
+		printk(KERN_ERR "init_module: Size of initialized module "
+				"exceeds size of created module.\n");
+		goto err2;
+	}
+
+	/* Make sure all interesting pointers are sane.  */
+
+	if (!mod_bound(mod->name, namelen, mod)) {
+		printk(KERN_ERR "init_module: mod->name out of bounds.\n");
+		goto err2;
+	}
+	if (mod->nsyms && !mod_bound(mod->syms, mod->nsyms, mod)) {
+		printk(KERN_ERR "init_module: mod->syms out of bounds.\n");
+		goto err2;
+	}
+	if (mod->ndeps && !mod_bound(mod->deps, mod->ndeps, mod)) {
+		printk(KERN_ERR "init_module: mod->deps out of bounds.\n");
+		goto err2;
+	}
+	if (mod->init && !mod_bound((unsigned long)mod->init, 0, mod)) {
+		printk(KERN_ERR "init_module: mod->init out of bounds.\n");
+		goto err2;
+	}
+	if (mod->cleanup && !mod_bound((unsigned long)mod->cleanup, 0, mod)) {
+		printk(KERN_ERR "init_module: mod->cleanup out of bounds.\n");
+		goto err2;
+	}
+	if (mod->ex_table_start > mod->ex_table_end
+	    || (mod->ex_table_start &&
+		!((unsigned long)mod->ex_table_start >= ((unsigned long)mod + mod->size_of_struct)
+		  && ((unsigned long)mod->ex_table_end
+		      < (unsigned long)mod + mod->size)))
+	    || (((unsigned long)mod->ex_table_start
+		 - (unsigned long)mod->ex_table_end)
+		% sizeof(struct exception_table_entry))) {
+		printk(KERN_ERR "init_module: mod->ex_table_* invalid.\n");
+		goto err2;
+	}
+	if (mod->flags & ~MOD_AUTOCLEAN) {
+		printk(KERN_ERR "init_module: mod->flags invalid.\n");
+		goto err2;
+	}
+	if (mod_member_present(mod, can_unload)
+	    && mod->can_unload && !mod_bound((unsigned long)mod->can_unload, 0, mod)) {
+		printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n");
+		goto err2;
+	}
+	if (mod_member_present(mod, kallsyms_end)) {
+	    if (mod->kallsyms_end &&
+		(!mod_bound(mod->kallsyms_start, 0, mod) ||
+		 !mod_bound(mod->kallsyms_end, 0, mod))) {
+		printk(KERN_ERR "init_module: mod->kallsyms out of bounds.\n");
+		goto err2;
+	    }
+	    if (mod->kallsyms_start > mod->kallsyms_end) {
+		printk(KERN_ERR "init_module: mod->kallsyms invalid.\n");
+		goto err2;
+	    }
+	}
+	if (mod_member_present(mod, archdata_end)) {
+	    if (mod->archdata_end &&
+		(!mod_bound(mod->archdata_start, 0, mod) ||
+		 !mod_bound(mod->archdata_end, 0, mod))) {
+		printk(KERN_ERR "init_module: mod->archdata out of bounds.\n");
+		goto err2;
+	    }
+	    if (mod->archdata_start > mod->archdata_end) {
+		printk(KERN_ERR "init_module: mod->archdata invalid.\n");
+		goto err2;
+	    }
+	}
+	if (mod_member_present(mod, kernel_data) && mod->kernel_data) {
+	    printk(KERN_ERR "init_module: mod->kernel_data must be zero.\n");
+	    goto err2;
+	}
+
+	/* Check that the user isn't doing something silly with the name.  */
+
+	if ((n_namelen = get_mod_name(mod->name - (unsigned long)mod
+				      + (unsigned long)mod_user,
+				      &n_name)) < 0) {
+		printk(KERN_ERR "init_module: get_mod_name failure.\n");
+		error = n_namelen;
+		goto err2;
+	}
+	if (namelen != n_namelen || strcmp(n_name, mod_tmp.name) != 0) {
+		printk(KERN_ERR "init_module: changed module name to "
+				"`%s' from `%s'\n",
+		       n_name, mod_tmp.name);
+		goto err3;
+	}
+
+	/* Ok, that's about all the sanity we can stomach; copy the rest.  */
+
+	if (copy_from_user((char *)mod+mod_user_size,
+			   (char *)mod_user+mod_user_size,
+			   mod->size-mod_user_size)) {
+		error = -EFAULT;
+		goto err3;
+	}
+
+	if (module_arch_init(mod))
+		goto err3;
+
+	/* On some machines it is necessary to do something here
+	   to make the I and D caches consistent.  */
+	flush_icache_range((unsigned long)mod, (unsigned long)mod + mod->size);
+
+	mod->next = mod_tmp.next;
+	mod->refs = NULL;
+
+	/* Sanity check the module's dependents */
+	for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
+		struct module *o, *d = dep->dep;
+
+		/* Make sure the indicated dependencies are really modules.  */
+		if (d == mod) {
+			printk(KERN_ERR "init_module: self-referential "
+					"dependency in mod->deps.\n");
+			goto err3;
+		}
 
-	if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
-		return -EFAULT;
-	name[MODULE_NAME_LEN-1] = '\0';
-
-	if (down_interruptible(&module_mutex) != 0)
-		return -EINTR;
-
-	mod = find_module(name);
-	if (!mod) {
-		ret = -ENOENT;
-		goto out;
+		/* Scan the current modules for this dependency */
+		for (o = module_list; o != &kernel_module && o != d; o = o->next)
+			;
+
+		if (o != d) {
+			printk(KERN_ERR "init_module: found dependency that is "
+				"(no longer?) a module.\n");
+			goto err3;
+		}
 	}
 
-	if (!list_empty(&mod->modules_which_use_me)) {
-		/* Other modules depend on us: get rid of them first. */
-		ret = -EWOULDBLOCK;
-		goto out;
+	/* Update module references.  */
+	for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
+		struct module *d = dep->dep;
+
+		dep->ref = mod;
+		dep->next_ref = d->refs;
+		d->refs = dep;
+		/* Being referenced by a dependent module counts as a
+		   use as far as kmod is concerned.  */
+		d->flags |= MOD_USED_ONCE;
+	}
+
+	/* Free our temporary memory.  */
+	put_mod_name(n_name);
+	put_mod_name(name);
+
+	/* Initialize the module.  */
+	atomic_set(&mod->uc.usecount,1);
+	mod->flags |= MOD_INITIALIZING;
+	if (mod->init && (error = mod->init()) != 0) {
+		atomic_set(&mod->uc.usecount,0);
+		mod->flags &= ~MOD_INITIALIZING;
+		if (error > 0)	/* Buggy module */
+			error = -EBUSY;
+		goto err0;
+	}
+	atomic_dec(&mod->uc.usecount);
+
+	/* And set it running.  */
+	mod->flags = (mod->flags | MOD_RUNNING) & ~MOD_INITIALIZING;
+	error = 0;
+	goto err0;
+
+err3:
+	put_mod_name(n_name);
+err2:
+	*mod = mod_tmp;
+	strcpy((char *)mod->name, name_tmp);	/* We know there is room for this */
+err1:
+	put_mod_name(name);
+err0:
+	unlock_kernel();
+	kfree(name_tmp);
+	return error;
+}
+
+static spinlock_t unload_lock = SPIN_LOCK_UNLOCKED;
+int try_inc_mod_count(struct module *mod)
+{
+	int res = 1;
+	if (mod) {
+		spin_lock(&unload_lock);
+		if (mod->flags & MOD_DELETED)
+			res = 0;
+		else
+			__MOD_INC_USE_COUNT(mod);
+		spin_unlock(&unload_lock);
 	}
+	return res;
+}
 
-	/* Already dying? */
-	if (mod->state == MODULE_STATE_GOING) {
-		/* FIXME: if (force), slam module count and wake up
-                   waiter --RR */
-		DEBUGP("%s already dying\n", mod->name);
-		ret = -EBUSY;
-		goto out;
-	}
+asmlinkage long
+sys_delete_module(const char *name_user)
+{
+	struct module *mod, *next;
+	char *name;
+	long error;
+	int something_changed;
 
-	/* Coming up?  Allow force on stuck modules. */
-	if (mod->state == MODULE_STATE_COMING) {
-		forced = try_force(flags);
-		if (!forced) {
-			/* This module can't be removed */
-			ret = -EBUSY;
+	if (!capable(CAP_SYS_MODULE))
+		return -EPERM;
+
+	lock_kernel();
+	if (name_user) {
+		if ((error = get_mod_name(name_user, &name)) < 0)
+			goto out;
+		error = -ENOENT;
+		if ((mod = find_module(name)) == NULL) {
+			put_mod_name(name);
 			goto out;
 		}
-	}
-
-	/* If it has an init func, it must have an exit func to unload */
-	if ((mod->init != init_module && mod->exit == cleanup_module)
-	    || mod->unsafe) {
-		forced = try_force(flags);
-		if (!forced) {
-			/* This module can't be removed */
-			ret = -EBUSY;
+		put_mod_name(name);
+		error = -EBUSY;
+		if (mod->refs != NULL)
 			goto out;
+
+		spin_lock(&unload_lock);
+		if (!__MOD_IN_USE(mod)) {
+			mod->flags |= MOD_DELETED;
+			spin_unlock(&unload_lock);
+			free_module(mod, 0);
+			error = 0;
+		} else {
+			spin_unlock(&unload_lock);
 		}
-	}
-	/* Stop the machine so refcounts can't move: irqs disabled. */
-	DEBUGP("Stopping refcounts...\n");
-	ret = stop_refcounts();
-	if (ret != 0)
 		goto out;
+	}
 
-	/* If it's not unused, quit unless we are told to block. */
-	if ((flags & O_NONBLOCK) && module_refcount(mod) != 0) {
-		forced = try_force(flags);
-		if (!forced)
-			ret = -EWOULDBLOCK;
-	} else {
-		mod->waiter = current;
-		mod->state = MODULE_STATE_GOING;
+	/* Do automatic reaping */
+restart:
+	something_changed = 0;
+	
+	for (mod = module_list; mod != &kernel_module; mod = next) {
+		next = mod->next;
+		spin_lock(&unload_lock);
+		if (mod->refs == NULL
+		    && (mod->flags & MOD_AUTOCLEAN)
+		    && (mod->flags & MOD_RUNNING)
+		    && !(mod->flags & MOD_DELETED)
+		    && (mod->flags & MOD_USED_ONCE)
+		    && !__MOD_IN_USE(mod)) {
+			if ((mod->flags & MOD_VISITED)
+			    && !(mod->flags & MOD_JUST_FREED)) {
+				spin_unlock(&unload_lock);
+				mod->flags &= ~MOD_VISITED;
+			} else {
+				mod->flags |= MOD_DELETED;
+				spin_unlock(&unload_lock);
+				free_module(mod, 1);
+				something_changed = 1;
+			}
+		} else {
+			spin_unlock(&unload_lock);
+		}
 	}
-	restart_refcounts();
+	
+	if (something_changed)
+		goto restart;
+		
+	for (mod = module_list; mod != &kernel_module; mod = mod->next)
+		mod->flags &= ~MOD_JUST_FREED;
+	
+	error = 0;
+out:
+	unlock_kernel();
+	return error;
+}
 
-	if (ret != 0)
-		goto out;
+/* Query various bits about modules.  */
 
-	if (forced)
-		goto destroy;
+static int
+qm_modules(char *buf, size_t bufsize, size_t *ret)
+{
+	struct module *mod;
+	size_t nmod, space, len;
 
-	/* Since we might sleep for some time, drop the semaphore first */
-	up(&module_mutex);
-	for (;;) {
-		DEBUGP("Looking at refcount...\n");
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (module_refcount(mod) == 0)
-			break;
-		schedule();
+	nmod = space = 0;
+
+	for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
+		len = strlen(mod->name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, mod->name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
 	}
-	current->state = TASK_RUNNING;
 
-	DEBUGP("Regrabbing mutex...\n");
-	down(&module_mutex);
+	if (put_user(nmod, ret))
+		return -EFAULT;
+	else
+		return 0;
 
- destroy:
-	/* Final destruction now noone is using it. */
-	mod->exit();
-	free_module(mod);
+calc_space_needed:
+	space += len;
+	while ((mod = mod->next) != &kernel_module)
+		space += strlen(mod->name)+1;
 
- out:
-	up(&module_mutex);
-	return ret;
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
 }
 
-static void print_unload_info(struct seq_file *m, struct module *mod)
+static int
+qm_deps(struct module *mod, char *buf, size_t bufsize, size_t *ret)
 {
-	struct module_use *use;
-	int printed_something = 0;
+	size_t i, space, len;
 
-	seq_printf(m, " %u ", module_refcount(mod));
+	if (mod == &kernel_module)
+		return -EINVAL;
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
 
-	/* Always include a trailing , so userspace can differentiate
-           between this and the old multi-field proc format. */
-	list_for_each_entry(use, &mod->modules_which_use_me, list) {
-		printed_something = 1;
-		seq_printf(m, "%s,", use->module_which_uses->name);
+	space = 0;
+	for (i = 0; i < mod->ndeps; ++i) {
+		const char *dep_name = mod->deps[i].dep->name;
+
+		len = strlen(dep_name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, dep_name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
 	}
 
-	if (mod->unsafe) {
-		printed_something = 1;
-		seq_printf(m, "[unsafe],");
-	}
+	if (put_user(i, ret))
+		return -EFAULT;
+	else
+		return 0;
 
-	if (mod->init != init_module && mod->exit == cleanup_module) {
-		printed_something = 1;
-		seq_printf(m, "[permanent],");
-	}
+calc_space_needed:
+	space += len;
+	while (++i < mod->ndeps)
+		space += strlen(mod->deps[i].dep->name)+1;
 
-	if (!printed_something)
-		seq_printf(m, "-");
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
 }
 
-void __symbol_put(const char *symbol)
+static int
+qm_refs(struct module *mod, char *buf, size_t bufsize, size_t *ret)
 {
-	struct kernel_symbol_group *ksg;
-	unsigned long flags;
+	size_t nrefs, space, len;
+	struct module_ref *ref;
 
-	spin_lock_irqsave(&modlist_lock, flags);
-	if (!__find_symbol(symbol, &ksg, 1))
-		BUG();
-	module_put(ksg->owner);
-	spin_unlock_irqrestore(&modlist_lock, flags);
-}
-EXPORT_SYMBOL(__symbol_put);
+	if (mod == &kernel_module)
+		return -EINVAL;
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
 
-void symbol_put_addr(void *addr)
-{
-	struct kernel_symbol_group *ks;
-	unsigned long flags;
+	space = 0;
+	for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
+		const char *ref_name = ref->ref->name;
+
+		len = strlen(ref_name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, ref_name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
 
-	spin_lock_irqsave(&modlist_lock, flags);
-	list_for_each_entry(ks, &symbols, list) {
- 		unsigned int i;
+	if (put_user(nrefs, ret))
+		return -EFAULT;
+	else
+		return 0;
 
-		for (i = 0; i < ks->num_syms; i++) {
-			if (ks->syms[i].value == (unsigned long)addr) {
-				module_put(ks->owner);
-				spin_unlock_irqrestore(&modlist_lock, flags);
-				return;
-			}
-		}
-	}
-	spin_unlock_irqrestore(&modlist_lock, flags);
-	BUG();
-}
-EXPORT_SYMBOL_GPL(symbol_put_addr);
+calc_space_needed:
+	space += len;
+	while ((ref = ref->next_ref) != NULL)
+		space += strlen(ref->ref->name)+1;
 
-#else /* !CONFIG_MODULE_UNLOAD */
-static void print_unload_info(struct seq_file *m, struct module *mod)
-{
-	/* We don't know the usage count, or what modules are using. */
-	seq_printf(m, " - -");
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
 }
 
-static inline void module_unload_free(struct module *mod)
+static int
+qm_symbols(struct module *mod, char *buf, size_t bufsize, size_t *ret)
 {
-}
+	size_t i, space, len;
+	struct module_symbol *s;
+	char *strings;
+	unsigned long *vals;
 
-static inline int use_module(struct module *a, struct module *b)
-{
-	return strong_try_module_get(b);
-}
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
 
-static inline void module_unload_init(struct module *mod)
-{
-}
+	space = mod->nsyms * 2*sizeof(void *);
 
-asmlinkage long
-sys_delete_module(const char *name_user, unsigned int flags)
-{
-	return -ENOSYS;
-}
+	i = len = 0;
+	s = mod->syms;
 
-#endif /* CONFIG_MODULE_UNLOAD */
+	if (space > bufsize)
+		goto calc_space_needed;
 
-#ifdef CONFIG_OBSOLETE_MODPARM
-static int param_set_byte(const char *val, struct kernel_param *kp)  
-{
-	char *endp;
-	long l;
+	if (!access_ok(VERIFY_WRITE, buf, space))
+		return -EFAULT;
 
-	if (!val) return -EINVAL;
-	l = simple_strtol(val, &endp, 0);
-	if (endp == val || *endp || ((char)l != l))
-		return -EINVAL;
-	*((char *)kp->arg) = l;
-	return 0;
-}
+	bufsize -= space;
+	vals = (unsigned long *)buf;
+	strings = buf+space;
+
+	for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
+		len = strlen(s->name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+
+		if (copy_to_user(strings, s->name, len)
+		    || __put_user(s->value, vals+0)
+		    || __put_user(space, vals+1))
+			return -EFAULT;
+
+		strings += len;
+		bufsize -= len;
+		space += len;
+	}
+	if (put_user(i, ret))
+		return -EFAULT;
+	else
+		return 0;
 
-/* Bounds checking done below */
-static int obsparm_copy_string(const char *val, struct kernel_param *kp)
-{
-	strcpy(kp->arg, val);
-	return 0;
+calc_space_needed:
+	for (; i < mod->nsyms; ++i, ++s)
+		space += strlen(s->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
 }
 
-extern int set_obsolete(const char *val, struct kernel_param *kp)
+static int
+qm_info(struct module *mod, char *buf, size_t bufsize, size_t *ret)
 {
-	unsigned int min, max;
-	unsigned int size, maxsize;
-	char *endp;
-	const char *p;
-	struct obsolete_modparm *obsparm = kp->arg;
+	int error = 0;
 
-	if (!val) {
-		printk(KERN_ERR "Parameter %s needs an argument\n", kp->name);
+	if (mod == &kernel_module)
 		return -EINVAL;
-	}
 
-	/* type is: [min[-max]]{b,h,i,l,s} */
-	p = obsparm->type;
-	min = simple_strtol(p, &endp, 10);
-	if (endp == obsparm->type)
-		min = max = 1;
-	else if (*endp == '-') {
-		p = endp+1;
-		max = simple_strtol(p, &endp, 10);
+	if (sizeof(struct module_info) <= bufsize) {
+		struct module_info info;
+		info.addr = (unsigned long)mod;
+		info.size = mod->size;
+		info.flags = mod->flags;
+		
+		/* usecount is one too high here - report appropriately to
+		   compensate for locking */
+		info.usecount = (mod_member_present(mod, can_unload)
+				 && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)-1);
+
+		if (copy_to_user(buf, &info, sizeof(struct module_info)))
+			return -EFAULT;
 	} else
-		max = min;
-	switch (*endp) {
-	case 'b':
-		return param_array(kp->name, val, min, max, obsparm->addr,
-				   1, param_set_byte);
-	case 'h':
-		return param_array(kp->name, val, min, max, obsparm->addr,
-				   sizeof(short), param_set_short);
-	case 'i':
-		return param_array(kp->name, val, min, max, obsparm->addr,
-				   sizeof(int), param_set_int);
-	case 'l':
-		return param_array(kp->name, val, min, max, obsparm->addr,
-				   sizeof(long), param_set_long);
-	case 's':
-		return param_array(kp->name, val, min, max, obsparm->addr,
-				   sizeof(char *), param_set_charp);
-
-	case 'c':
-		/* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars,
-		   and the decl is "char xxx[5][50];" */
-		p = endp+1;
-		maxsize = simple_strtol(p, &endp, 10);
-		/* We check lengths here (yes, this is a hack). */
-		p = val;
-		while (p[size = strcspn(p, ",")]) {
-			if (size >= maxsize) 
-				goto oversize;
-			p += size+1;
-		}
-		if (size >= maxsize) 
-			goto oversize;
-		return param_array(kp->name, val, min, max, obsparm->addr,
-				   maxsize, obsparm_copy_string);
-	}
-	printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type);
-	return -EINVAL;
- oversize:
-	printk(KERN_ERR
-	       "Parameter %s doesn't fit in %u chars.\n", kp->name, maxsize);
-	return -EINVAL;
-}
-
-static int obsolete_params(const char *name,
-			   char *args,
-			   struct obsolete_modparm obsparm[],
-			   unsigned int num,
-			   Elf_Shdr *sechdrs,
-			   unsigned int symindex,
-			   const char *strtab)
-{
-	struct kernel_param *kp;
-	unsigned int i;
-	int ret;
+		error = -ENOSPC;
 
-	kp = kmalloc(sizeof(kp[0]) * num, GFP_KERNEL);
-	if (!kp)
-		return -ENOMEM;
+	if (put_user(sizeof(struct module_info), ret))
+		return -EFAULT;
 
-	for (i = 0; i < num; i++) {
-		char sym_name[128 + sizeof(MODULE_SYMBOL_PREFIX)];
+	return error;
+}
 
-		snprintf(sym_name, sizeof(sym_name), "%s%s",
-			 MODULE_SYMBOL_PREFIX, obsparm[i].name);
+asmlinkage long
+sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+		 size_t *ret)
+{
+	struct module *mod;
+	int err;
 
-		kp[i].name = obsparm[i].name;
-		kp[i].perm = 000;
-		kp[i].set = set_obsolete;
-		kp[i].get = NULL;
-		obsparm[i].addr
-			= (void *)find_local_symbol(sechdrs, symindex, strtab,
-						    sym_name);
-		if (!obsparm[i].addr) {
-			printk("%s: falsely claims to have parameter %s\n",
-			       name, obsparm[i].name);
-			ret = -EINVAL;
+	lock_kernel();
+	if (name_user == NULL)
+		mod = &kernel_module;
+	else {
+		long namelen;
+		char *name;
+
+		if ((namelen = get_mod_name(name_user, &name)) < 0) {
+			err = namelen;
+			goto out;
+		}
+		err = -ENOENT;
+		if ((mod = find_module(name)) == NULL) {
+			put_mod_name(name);
 			goto out;
 		}
-		kp[i].arg = &obsparm[i];
+		put_mod_name(name);
 	}
 
-	ret = parse_args(name, args, kp, num, NULL);
- out:
-	kfree(kp);
-	return ret;
-}
-#else
-static int obsolete_params(const char *name,
-			   char *args,
-			   struct obsolete_modparm obsparm[],
-			   unsigned int num,
-			   Elf_Shdr *sechdrs,
-			   unsigned int symindex,
-			   const char *strtab)
-{
-	if (num != 0)
-		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
-		       name);
-	return 0;
-}
-#endif /* CONFIG_OBSOLETE_MODPARM */
-
-/* Resolve a symbol for this module.  I.e. if we find one, record usage.
-   Must be holding module_mutex. */
-static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
-				    unsigned int symindex,
-				    const char *strtab,
-				    const char *name,
-				    struct module *mod)
-{
-	struct kernel_symbol_group *ksg;
-	unsigned long ret;
-
-	spin_lock_irq(&modlist_lock);
-	ret = __find_symbol(name, &ksg, mod->license_gplok);
-	if (ret) {
-		/* This can fail due to OOM, or module unloading */
-		if (!use_module(mod, ksg->owner))
-			ret = 0;
+	/* __MOD_ touches the flags. We must avoid that */
+	
+	atomic_inc(&mod->uc.usecount);
+		
+	switch (which)
+	{
+	case 0:
+		err = 0;
+		break;
+	case QM_MODULES:
+		err = qm_modules(buf, bufsize, ret);
+		break;
+	case QM_DEPS:
+		err = qm_deps(mod, buf, bufsize, ret);
+		break;
+	case QM_REFS:
+		err = qm_refs(mod, buf, bufsize, ret);
+		break;
+	case QM_SYMBOLS:
+		err = qm_symbols(mod, buf, bufsize, ret);
+		break;
+	case QM_INFO:
+		err = qm_info(mod, buf, bufsize, ret);
+		break;
+	default:
+		err = -EINVAL;
+		break;
 	}
-	spin_unlock_irq(&modlist_lock);
-	return ret;
+	atomic_dec(&mod->uc.usecount);
+	
+out:
+	unlock_kernel();
+	return err;
 }
 
-/* Free a module, remove from lists, etc (must hold module mutex). */
-static void free_module(struct module *mod)
+/*
+ * Copy the kernel symbol table to user space.  If the argument is
+ * NULL, just return the size of the table.
+ *
+ * This call is obsolete.  New programs should use query_module+QM_SYMBOLS
+ * which does not arbitrarily limit the length of symbols.
+ */
+
+asmlinkage long
+sys_get_kernel_syms(struct kernel_sym *table)
 {
-	/* Delete from various lists */
-	spin_lock_irq(&modlist_lock);
-	list_del(&mod->list);
-	list_del(&mod->symbols.list);
-	list_del(&mod->gpl_symbols.list);
-	list_del(&mod->extable.list);
-	spin_unlock_irq(&modlist_lock);
+	struct module *mod;
+	int i;
+	struct kernel_sym ksym;
 
-	/* Module unload stuff */
-	module_unload_free(mod);
+	lock_kernel();
+	for (mod = module_list, i = 0; mod; mod = mod->next) {
+		/* include the count for the module name! */
+		i += mod->nsyms + 1;
+	}
 
-	/* This may be NULL, but that's OK */
-	module_free(mod, mod->module_init);
-	kfree(mod->args);
+	if (table == NULL)
+		goto out;
 
-	/* Finally, free the core (containing the module structure) */
-	module_free(mod, mod->module_core);
-}
+	/* So that we don't give the user our stack content */
+	memset (&ksym, 0, sizeof (ksym));
 
-void *__symbol_get(const char *symbol)
-{
-	struct kernel_symbol_group *ksg;
-	unsigned long value, flags;
+	for (mod = module_list, i = 0; mod; mod = mod->next) {
+		struct module_symbol *msym;
+		unsigned int j;
 
-	spin_lock_irqsave(&modlist_lock, flags);
-	value = __find_symbol(symbol, &ksg, 1);
-	if (value && !strong_try_module_get(ksg->owner))
-		value = 0;
-	spin_unlock_irqrestore(&modlist_lock, flags);
+		if (!MOD_CAN_QUERY(mod))
+			continue;
 
-	return (void *)value;
-}
-EXPORT_SYMBOL_GPL(__symbol_get);
+		/* magic: write module info as a pseudo symbol */
+		ksym.value = (unsigned long)mod;
+		ksym.name[0] = '#';
+		strncpy(ksym.name+1, mod->name, sizeof(ksym.name)-1);
+		ksym.name[sizeof(ksym.name)-1] = '\0';
 
-/* Deal with the given section */
-static int handle_section(const char *name,
-			  Elf_Shdr *sechdrs,
-			  unsigned int strindex,
-			  unsigned int symindex,
-			  unsigned int i,
-			  struct module *mod)
-{
-	int ret;
-	const char *strtab = (char *)sechdrs[strindex].sh_addr;
-
-	switch (sechdrs[i].sh_type) {
-	case SHT_REL:
-		ret = apply_relocate(sechdrs, strtab, symindex, i, mod);
-		break;
-	case SHT_RELA:
-		ret = apply_relocate_add(sechdrs, strtab, symindex, i, mod);
-		break;
-	default:
-		DEBUGP("Ignoring section %u: %s\n", i,
-		       sechdrs[i].sh_type==SHT_NULL ? "NULL":
-		       sechdrs[i].sh_type==SHT_PROGBITS ? "PROGBITS":
-		       sechdrs[i].sh_type==SHT_SYMTAB ? "SYMTAB":
-		       sechdrs[i].sh_type==SHT_STRTAB ? "STRTAB":
-		       sechdrs[i].sh_type==SHT_RELA ? "RELA":
-		       sechdrs[i].sh_type==SHT_HASH ? "HASH":
-		       sechdrs[i].sh_type==SHT_DYNAMIC ? "DYNAMIC":
-		       sechdrs[i].sh_type==SHT_NOTE ? "NOTE":
-		       sechdrs[i].sh_type==SHT_NOBITS ? "NOBITS":
-		       sechdrs[i].sh_type==SHT_REL ? "REL":
-		       sechdrs[i].sh_type==SHT_SHLIB ? "SHLIB":
-		       sechdrs[i].sh_type==SHT_DYNSYM ? "DYNSYM":
-		       sechdrs[i].sh_type==SHT_NUM ? "NUM":
-		       "UNKNOWN");
-		ret = 0;
-	}
-	return ret;
-}
-
-/* Change all symbols so that sh_value encodes the pointer directly. */
-static int simplify_symbols(Elf_Shdr *sechdrs,
-			    unsigned int symindex,
-			    unsigned int strindex,
-			    struct module *mod)
-{
-	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
-	const char *strtab = (char *)sechdrs[strindex].sh_addr;
-	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
-	int ret = 0;
-
-	for (i = 1; i < n; i++) {
-		switch (sym[i].st_shndx) {
-		case SHN_COMMON:
-			/* We compiled with -fno-common.  These are not
-			   supposed to happen.  */
-			DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name);
-			ret = -ENOEXEC;
-			break;
-
-		case SHN_ABS:
-			/* Don't need to do anything */
-			DEBUGP("Absolute symbol: 0x%08lx\n",
-			       (long)sym[i].st_value);
-			break;
+		if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
+			goto out;
+		++i, ++table;
 
-		case SHN_UNDEF:
-			sym[i].st_value
-			  = resolve_symbol(sechdrs, symindex, strtab,
-					   strtab + sym[i].st_name, mod);
-
-			/* Ok if resolved.  */
-			if (sym[i].st_value != 0)
-				break;
-			/* Ok if weak.  */
-			if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
-				break;
-
-			printk(KERN_WARNING "%s: Unknown symbol %s\n",
-			       mod->name, strtab + sym[i].st_name);
-			ret = -ENOENT;
-			break;
+		if (mod->nsyms == 0)
+			continue;
 
-		default:
-			sym[i].st_value 
-				= (unsigned long)
-				(sechdrs[sym[i].st_shndx].sh_addr
-				 + sym[i].st_value);
-			break;
+		for (j = 0, msym = mod->syms; j < mod->nsyms; ++j, ++msym) {
+			ksym.value = msym->value;
+			strncpy(ksym.name, msym->name, sizeof(ksym.name));
+			ksym.name[sizeof(ksym.name)-1] = '\0';
+
+			if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
+				goto out;
+			++i, ++table;
 		}
 	}
-
-	return ret;
+out:
+	unlock_kernel();
+	return i;
 }
 
-/* Update size with this section: return offset. */
-static long get_offset(unsigned long *size, Elf_Shdr *sechdr)
+/*
+ * Look for a module by name, ignoring modules marked for deletion.
+ */
+
+struct module *
+find_module(const char *name)
 {
-	long ret;
+	struct module *mod;
 
-	ret = ALIGN(*size, sechdr->sh_addralign ?: 1);
-	*size = ret + sechdr->sh_size;
-	return ret;
-}
-
-/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
-   might -- code, read-only data, read-write data, small data.  Tally
-   sizes, and place the offsets into sh_entsize fields: high bit means it
-   belongs in init. */
-static void layout_sections(struct module *mod,
-			    const Elf_Ehdr *hdr,
-			    Elf_Shdr *sechdrs,
-			    const char *secstrings)
-{
-	static unsigned long const masks[][2] = {
-		{ SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
-		{ SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
-		{ SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
-		{ ARCH_SHF_SMALL | SHF_ALLOC, 0 }
-	};
-	unsigned int m, i;
-
-	for (i = 0; i < hdr->e_shnum; i++)
-		sechdrs[i].sh_entsize = ~0UL;
-
-	DEBUGP("Core section allocation order:\n");
-	for (m = 0; m < ARRAY_SIZE(masks); ++m) {
-		for (i = 0; i < hdr->e_shnum; ++i) {
-			Elf_Shdr *s = &sechdrs[i];
-
-			if ((s->sh_flags & masks[m][0]) != masks[m][0]
-			    || (s->sh_flags & masks[m][1])
-			    || s->sh_entsize != ~0UL
-			    || strstr(secstrings + s->sh_name, ".init"))
-				continue;
-			s->sh_entsize = get_offset(&mod->core_size, s);
-			DEBUGP("\t%s\n", name);
-		}
+	for (mod = module_list; mod ; mod = mod->next) {
+		if (mod->flags & MOD_DELETED)
+			continue;
+		if (!strcmp(mod->name, name))
+			break;
 	}
 
-	DEBUGP("Init section allocation order:\n");
-	for (m = 0; m < ARRAY_SIZE(masks); ++m) {
-		for (i = 0; i < hdr->e_shnum; ++i) {
-			Elf_Shdr *s = &sechdrs[i];
-
-			if ((s->sh_flags & masks[m][0]) != masks[m][0]
-			    || (s->sh_flags & masks[m][1])
-			    || s->sh_entsize != ~0UL
-			    || !strstr(secstrings + s->sh_name, ".init"))
-				continue;
-			s->sh_entsize = (get_offset(&mod->init_size, s)
-					 | INIT_OFFSET_MASK);
-			DEBUGP("\t%s\n", name);
-		}
-	}
+	return mod;
 }
 
-static inline int license_is_gpl_compatible(const char *license)
-{
-	return (strcmp(license, "GPL") == 0
-		|| strcmp(license, "GPL v2") == 0
-		|| strcmp(license, "GPL and additional rights") == 0
-		|| strcmp(license, "Dual BSD/GPL") == 0
-		|| strcmp(license, "Dual MPL/GPL") == 0);
-}
+/*
+ * Free the given module.
+ */
 
-static void set_license(struct module *mod, Elf_Shdr *sechdrs, int licenseidx)
+void
+free_module(struct module *mod, int tag_freed)
 {
-	char *license;
+	struct module_ref *dep;
+	unsigned i;
+	unsigned long flags;
 
-	if (licenseidx) 
-		license = (char *)sechdrs[licenseidx].sh_addr;
-	else
-		license = "unspecified";
+	/* Let the module clean up.  */
 
-	mod->license_gplok = license_is_gpl_compatible(license);
-	if (!mod->license_gplok) {
-		printk(KERN_WARNING "%s: module license '%s' taints kernel.\n",
-		       mod->name, license);
-		tainted |= TAINT_PROPRIETARY_MODULE;
+	if (mod->flags & MOD_RUNNING)
+	{
+		if(mod->cleanup)
+			mod->cleanup();
+		mod->flags &= ~MOD_RUNNING;
 	}
-}
 
-/* From init/vermagic.o */
-extern char vermagic[];
-
-/* 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 *umod,
-				  unsigned long len,
-				  const char *uargs)
-{
-	Elf_Ehdr *hdr;
-	Elf_Shdr *sechdrs;
-	char *secstrings, *args;
-	unsigned int i, symindex, exportindex, strindex, setupindex, exindex,
-		modindex, obsparmindex, licenseindex, gplindex, vmagindex;
-	long arglen;
-	struct module *mod;
-	long err = 0;
-	void *ptr = NULL; /* Stops spurious gcc uninitialized warning */
+	/* Remove the module from the dependency lists.  */
 
-	DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
-	       umod, len, uargs);
-	if (len < sizeof(*hdr))
-		return ERR_PTR(-ENOEXEC);
-
-	/* Suck in entire file: we'll want most of it. */
-	/* vmalloc barfs on "unusual" numbers.  Check here */
-	if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
-		return ERR_PTR(-ENOMEM);
-	if (copy_from_user(hdr, umod, len) != 0) {
-		err = -EFAULT;
-		goto free_hdr;
-	}
-
-	/* Sanity checks against insmoding binaries or wrong arch,
-           weird elf version */
-	if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
-	    || hdr->e_type != ET_REL
-	    || !elf_check_arch(hdr)
-	    || hdr->e_shentsize != sizeof(*sechdrs)) {
-		err = -ENOEXEC;
-		goto free_hdr;
-	}
-
-	/* Convenience variables */
-	sechdrs = (void *)hdr + hdr->e_shoff;
-	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-
-	/* May not export symbols, or have setup params, so these may
-           not exist */
-	exportindex = setupindex = obsparmindex = gplindex = licenseindex = 0;
-
-	/* And these should exist, but gcc whinges if we don't init them */
-	symindex = strindex = exindex = modindex = vmagindex = 0;
-
-	/* Find where important sections are */
-	for (i = 1; i < hdr->e_shnum; i++) {
-		/* Mark all sections sh_addr with their address in the
-		   temporary image. */
-		sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;
-
-		if (sechdrs[i].sh_type == SHT_SYMTAB) {
-			/* Internal symbols */
-			DEBUGP("Symbol table in section %u\n", i);
-			symindex = i;
-			/* Strings */
-			strindex = sechdrs[i].sh_link;
-			DEBUGP("String table found in section %u\n", strindex);
-		} else if (strcmp(secstrings+sechdrs[i].sh_name,
-				  ".gnu.linkonce.this_module") == 0) {
-			/* The module struct */
-			DEBUGP("Module in section %u\n", i);
-			modindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name, "__ksymtab")
-			   == 0) {
-			/* Exported symbols. */
-			DEBUGP("EXPORT table in section %u\n", i);
-			exportindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name, "__param")
-			   == 0) {
-			/* Setup parameter info */
-			DEBUGP("Setup table found in section %u\n", i);
-			setupindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name, "__ex_table")
-			   == 0) {
-			/* Exception table */
-			DEBUGP("Exception table found in section %u\n", i);
-			exindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name, "__obsparm")
-			   == 0) {
-			/* Obsolete MODULE_PARM() table */
-			DEBUGP("Obsolete param found in section %u\n", i);
-			obsparmindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name,".init.license")
-			   == 0) {
-			/* MODULE_LICENSE() */
-			DEBUGP("Licence found in section %u\n", i);
-			licenseindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name,
-				  "__gpl_ksymtab") == 0) {
-			/* EXPORT_SYMBOL_GPL() */
-			DEBUGP("GPL symbols found in section %u\n", i);
-			gplindex = i;
-		} else if (strcmp(secstrings+sechdrs[i].sh_name,
-				  "__vermagic") == 0) {
-			/* Version magic. */
-			DEBUGP("Version magic found in section %u\n", i);
-			vmagindex = i;
-		}
-#ifdef CONFIG_KALLSYMS
-		/* symbol and string tables for decoding later. */
-		if (sechdrs[i].sh_type == SHT_SYMTAB || i == strindex)
-			sechdrs[i].sh_flags |= SHF_ALLOC;
-#endif
-#ifndef CONFIG_MODULE_UNLOAD
-		/* Don't load .exit sections */
-		if (strstr(secstrings+sechdrs[i].sh_name, ".exit"))
-			sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
-#endif
-	}
-
-	if (!modindex) {
-		printk(KERN_WARNING "No module found in object\n");
-		err = -ENOEXEC;
-		goto free_hdr;
-	}
-	mod = (void *)sechdrs[modindex].sh_addr;
-
-	/* This is allowed: modprobe --force will strip it. */
-	if (!vmagindex) {
-		tainted |= TAINT_FORCED_MODULE;
-		printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
-		       mod->name);
-	} else if (strcmp((char *)sechdrs[vmagindex].sh_addr, vermagic) != 0) {
-		printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
-		       mod->name, (char*)sechdrs[vmagindex].sh_addr, vermagic);
-		err = -ENOEXEC;
-		goto free_hdr;
-	}
-
-	/* Now copy in args */
-	arglen = strlen_user(uargs);
-	if (!arglen) {
-		err = -EFAULT;
-		goto free_hdr;
-	}
-	args = kmalloc(arglen, GFP_KERNEL);
-	if (!args) {
-		err = -ENOMEM;
-		goto free_hdr;
-	}
-	if (copy_from_user(args, uargs, arglen) != 0) {
-		err = -EFAULT;
-		goto free_mod;
-	}
-
-	if (find_module(mod->name)) {
-		err = -EEXIST;
-		goto free_mod;
-	}
-
-	mod->state = MODULE_STATE_COMING;
-
-	/* Allow arches to frob section contents and sizes.  */
-	err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
-	if (err < 0)
-		goto free_mod;
-
-	/* Determine total sizes, and put offsets in sh_entsize.  For now
-	   this is done generically; there doesn't appear to be any
-	   special cases for the architectures. */
-	layout_sections(mod, hdr, sechdrs, secstrings);
-
-	/* Do the allocs. */
-	ptr = module_alloc(mod->core_size);
-	if (!ptr) {
-		err = -ENOMEM;
-		goto free_mod;
-	}
-	memset(ptr, 0, mod->core_size);
-	mod->module_core = ptr;
-
-	ptr = module_alloc(mod->init_size);
-	if (!ptr && mod->init_size) {
-		err = -ENOMEM;
-		goto free_core;
-	}
-	memset(ptr, 0, mod->init_size);
-	mod->module_init = ptr;
-
-	/* Transfer each section which specifies SHF_ALLOC */
-	for (i = 0; i < hdr->e_shnum; i++) {
-		void *dest;
-
-		if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+	for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
+		struct module_ref **pp;
+		for (pp = &dep->dep->refs; *pp != dep; pp = &(*pp)->next_ref)
 			continue;
+		*pp = dep->next_ref;
+		if (tag_freed && dep->dep->refs == NULL)
+			dep->dep->flags |= MOD_JUST_FREED;
+	}
 
-		if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK)
-			dest = mod->module_init
-				+ (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK);
-		else
-			dest = mod->module_core + sechdrs[i].sh_entsize;
+	/* And from the main module list.  */
 
-		if (sechdrs[i].sh_type != SHT_NOBITS)
-			memcpy(dest, (void *)sechdrs[i].sh_addr,
-			       sechdrs[i].sh_size);
-		/* Update sh_addr to point to copy in image. */
-		sechdrs[i].sh_addr = (unsigned long)dest;
-	}
-	/* Module has been moved. */
-	mod = (void *)sechdrs[modindex].sh_addr;
-
-	/* Now we've moved module, initialize linked lists, etc. */
-	module_unload_init(mod);
-
-	/* Set up license info based on contents of section */
-	set_license(mod, sechdrs, licenseindex);
-
-	/* Fix up syms, so that st_value is a pointer to location. */
-	err = simplify_symbols(sechdrs, symindex, strindex, mod);
-	if (err < 0)
-		goto cleanup;
-
-	/* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */
-	mod->symbols.num_syms = (sechdrs[exportindex].sh_size
-				 / sizeof(*mod->symbols.syms));
-	mod->symbols.syms = (void *)sechdrs[exportindex].sh_addr;
-	mod->gpl_symbols.num_syms = (sechdrs[gplindex].sh_size
-				 / sizeof(*mod->symbols.syms));
-	mod->gpl_symbols.syms = (void *)sechdrs[gplindex].sh_addr;
-
-	/* Set up exception table */
-	if (exindex) {
-		/* FIXME: Sort exception table. */
-		mod->extable.num_entries = (sechdrs[exindex].sh_size
-					    / sizeof(struct
-						     exception_table_entry));
-		mod->extable.entry = (void *)sechdrs[exindex].sh_addr;
-	}
-
-	/* Now handle each section. */
-	for (i = 1; i < hdr->e_shnum; i++) {
-		err = handle_section(secstrings + sechdrs[i].sh_name,
-				     sechdrs, strindex, symindex, i, mod);
-		if (err < 0)
-			goto cleanup;
-	}
-
-#ifdef CONFIG_KALLSYMS
-	mod->symtab = (void *)sechdrs[symindex].sh_addr;
-	mod->num_syms = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
-	mod->strtab = (void *)sechdrs[strindex].sh_addr;
-#endif
-	err = module_finalize(hdr, sechdrs, mod);
-	if (err < 0)
-		goto cleanup;
-
-	mod->args = args;
-	if (obsparmindex) {
-		err = obsolete_params(mod->name, mod->args,
-				      (struct obsolete_modparm *)
-				      sechdrs[obsparmindex].sh_addr,
-				      sechdrs[obsparmindex].sh_size
-				      / sizeof(struct obsolete_modparm),
-				      sechdrs, symindex,
-				      (char *)sechdrs[strindex].sh_addr);
+	spin_lock_irqsave(&modlist_lock, flags);
+	if (mod == module_list) {
+		module_list = mod->next;
 	} else {
-		/* Size of section 0 is 0, so this works well if no params */
-		err = parse_args(mod->name, mod->args,
-				 (struct kernel_param *)
-				 sechdrs[setupindex].sh_addr,
-				 sechdrs[setupindex].sh_size
-				 / sizeof(struct kernel_param),
-				 NULL);
+		struct module *p;
+		for (p = module_list; p->next != mod; p = p->next)
+			continue;
+		p->next = mod->next;
 	}
-	if (err < 0)
-		goto cleanup;
-
-	/* Get rid of temporary copy */
-	vfree(hdr);
+	spin_unlock_irqrestore(&modlist_lock, flags);
 
-	/* Done! */
-	return mod;
+	/* And free the memory.  */
 
- cleanup:
-	module_unload_free(mod);
-	module_free(mod, mod->module_init);
- free_core:
-	module_free(mod, mod->module_core);
- free_mod:
-	kfree(args);
- free_hdr:
-	vfree(hdr);
-	if (err < 0) return ERR_PTR(err);
-	else return ptr;
+	module_unmap(mod);
 }
 
-/* This is where the real work happens */
-asmlinkage long
-sys_init_module(void *umod,
-		unsigned long len,
-		const char *uargs)
+/*
+ * Called by the /proc file system to return a current list of modules.
+ */
+static void *m_start(struct seq_file *m, loff_t *pos)
 {
-	struct module *mod;
-	int ret;
+	struct module *v;
+	loff_t n = *pos;
+	lock_kernel();
+	for (v = module_list; v && n--; v = v->next)
+		;
+	return v;
+}
+static void *m_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	struct module *v = p;
+	(*pos)++;
+	return v->next;
+}
+static void m_stop(struct seq_file *m, void *p)
+{
+	unlock_kernel();
+}
+static int m_show(struct seq_file *m, void *p)
+{
+	struct module *mod = p;
+	struct module_ref *ref = mod->refs;
 
-	/* Must have permission */
-	if (!capable(CAP_SYS_MODULE))
-		return -EPERM;
+	if (mod == &kernel_module)
+		return 0;
 
-	/* Only one module load at a time, please */
-	if (down_interruptible(&module_mutex) != 0)
-		return -EINTR;
-
-	/* Do all the hard work */
-	mod = load_module(umod, len, uargs);
-	if (IS_ERR(mod)) {
-		up(&module_mutex);
-		return PTR_ERR(mod);
-	}
-
-	/* Flush the instruction cache, since we've played with text */
-	if (mod->module_init)
-		flush_icache_range((unsigned long)mod->module_init,
-				   (unsigned long)mod->module_init
-				   + mod->init_size);
-	flush_icache_range((unsigned long)mod->module_core,
-			   (unsigned long)mod->module_core + mod->core_size);
-
-	/* Now sew it into the lists.  They won't access us, since
-           strong_try_module_get() will fail. */
-	spin_lock_irq(&modlist_lock);
-	list_add(&mod->extable.list, &extables);
-	list_add_tail(&mod->symbols.list, &symbols);
-	list_add_tail(&mod->gpl_symbols.list, &symbols);
-	list_add(&mod->list, &modules);
-	spin_unlock_irq(&modlist_lock);
-
-	/* Drop lock so they can recurse */
-	up(&module_mutex);
-
-	/* Start the module */
-	ret = mod->init();
-	if (ret < 0) {
-		/* Init routine failed: abort.  Try to protect us from
-                   buggy refcounters. */
-		mod->state = MODULE_STATE_GOING;
-		synchronize_kernel();
-		if (mod->unsafe)
-			printk(KERN_ERR "%s: module is now stuck!\n",
-			       mod->name);
-		else {
-			down(&module_mutex);
-			free_module(mod);
-			up(&module_mutex);
-		}
-		return ret;
+	seq_printf(m, "%-20s%8lu", mod->name, mod->size);
+	if (mod->flags & MOD_RUNNING)
+		seq_printf(m, "%4ld",
+			      (mod_member_present(mod, can_unload)
+			       && mod->can_unload
+			       ? -1L : (long)atomic_read(&mod->uc.usecount)));
+
+	if (mod->flags & MOD_DELETED)
+		seq_puts(m, " (deleted)");
+	else if (mod->flags & MOD_RUNNING) {
+		if (mod->flags & MOD_AUTOCLEAN)
+			seq_puts(m, " (autoclean)");
+		if (!(mod->flags & MOD_USED_ONCE))
+			seq_puts(m, " (unused)");
+	} else if (mod->flags & MOD_INITIALIZING)
+		seq_puts(m, " (initializing)");
+	else
+		seq_puts(m, " (uninitialized)");
+	if (ref) {
+		char c;
+		seq_putc(m, ' ');
+		for (c = '[' ; ref; c = ' ', ref = ref->next_ref)
+			seq_printf(m, "%c%s", c, ref->ref->name);
+		seq_putc(m, ']');
 	}
-
-	/* Now it's a first class citizen! */
-	mod->state = MODULE_STATE_LIVE;
-	module_free(mod, mod->module_init);
-	mod->module_init = NULL;
-	mod->init_size = 0;
-
+	seq_putc(m, '\n');
 	return 0;
 }
+struct seq_operations modules_op = {
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= m_show
+};
 
-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,
-			       unsigned long *size,
-			       unsigned long *offset)
-{
-	unsigned int i, best = 0;
-	unsigned long nextval;
-
-	/* At worse, next value is at end of module */
-	if (within(addr, mod->module_init, mod->init_size))
-		nextval = (unsigned long)mod->module_core+mod->core_size;
-	else 
-		nextval = (unsigned long)mod->module_init+mod->init_size;
-
-	/* Scan for closest preceeding symbol, and next symbol. (ELF
-           starts real symbols at 1). */
-	for (i = 1; i < mod->num_syms; i++) {
-		if (mod->symtab[i].st_shndx == SHN_UNDEF)
-			continue;
+/*
+ * Called by the /proc file system to return a current list of ksyms.
+ */
 
-		if (mod->symtab[i].st_value <= addr
-		    && mod->symtab[i].st_value > mod->symtab[best].st_value)
-			best = i;
-		if (mod->symtab[i].st_value > addr
-		    && mod->symtab[i].st_value < nextval)
-			nextval = mod->symtab[i].st_value;
-	}
-
-	if (!best)
-		return NULL;
-
-	*size = nextval - mod->symtab[best].st_value;
-	*offset = addr - mod->symtab[best].st_value;
-	return mod->strtab + mod->symtab[best].st_name;
-}
-
-/* For kallsyms to ask for address resolution.  NULL means not found.
-   We don't lock, as this is used for oops resolution and races are a
-   lesser concern. */
-const char *module_address_lookup(unsigned long addr,
-				  unsigned long *size,
-				  unsigned long *offset,
-				  char **modname)
-{
+struct mod_sym {
 	struct module *mod;
+	int index;
+};
 
-	list_for_each_entry(mod, &modules, list) {
-		if (within(addr, mod->module_init, mod->init_size)
-		    || within(addr, mod->module_core, mod->core_size)) {
-			*modname = mod->name;
-			return get_ksymbol(mod, addr, size, offset);
-		}
-	}
-	return NULL;
-}
-#endif /* CONFIG_KALLSYMS */
+/* iterator */
 
-/* Called by the /proc file system to return a list of modules. */
-static void *m_start(struct seq_file *m, loff_t *pos)
+static void *s_start(struct seq_file *m, loff_t *pos)
 {
-	struct list_head *i;
-	loff_t n = 0;
+	struct mod_sym *p = kmalloc(sizeof(*p), GFP_KERNEL);
+	struct module *v;
+	loff_t n = *pos;
 
-	down(&module_mutex);
-	list_for_each(i, &modules) {
-		if (n++ == *pos)
-			break;
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+	lock_kernel();
+	for (v = module_list; v; n -= v->nsyms, v = v->next) {
+		if (n < v->nsyms) {
+			p->mod = v;
+			p->index = n;
+			return p;
+		}
 	}
-	if (i == &modules)
-		return NULL;
-	return i;
+	unlock_kernel();
+	kfree(p);
+	return NULL;
 }
 
-static void *m_next(struct seq_file *m, void *p, loff_t *pos)
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 {
-	struct list_head *i = p;
+	struct mod_sym *v = p;
 	(*pos)++;
-	if (i->next == &modules)
-		return NULL;
-	return i->next;
+	if (++v->index >= v->mod->nsyms) {
+		do {
+			v->mod = v->mod->next;
+			if (!v->mod) {
+				unlock_kernel();
+				kfree(p);
+				return NULL;
+			}
+		} while (!v->mod->nsyms);
+		v->index = 0;
+	}
+	return p;
 }
 
-static void m_stop(struct seq_file *m, void *p)
+static void s_stop(struct seq_file *m, void *p)
 {
-	up(&module_mutex);
+	if (p && !IS_ERR(p)) {
+		unlock_kernel();
+		kfree(p);
+	}
 }
 
-static int m_show(struct seq_file *m, void *p)
+static int s_show(struct seq_file *m, void *p)
 {
-	struct module *mod = list_entry(p, struct module, list);
-	seq_printf(m, "%s %lu",
-		   mod->name, mod->init_size + mod->core_size);
-	print_unload_info(m, mod);
-
-	/* Informative for users. */
-	seq_printf(m, " %s",
-		   mod->state == MODULE_STATE_GOING ? "Unloading":
-		   mod->state == MODULE_STATE_COMING ? "Loading":
-		   "Live");
-	/* Used by oprofile and other similar tools. */
-	seq_printf(m, " 0x%p", mod->module_core);
+	struct mod_sym *v = p;
+	struct module_symbol *sym;
 
-	seq_printf(m, "\n");
+	if (!MOD_CAN_QUERY(v->mod))
+		return 0;
+	sym = &v->mod->syms[v->index];
+	if (*v->mod->name)
+		seq_printf(m, "%0*lx %s\t[%s]\n", (int)(2*sizeof(void*)),
+			       sym->value, sym->name, v->mod->name);
+	else
+		seq_printf(m, "%0*lx %s\n", (int)(2*sizeof(void*)),
+			       sym->value, sym->name);
 	return 0;
 }
 
-/* Format: modulename size refcount deps
-
-   Where refcount is a number or -, and deps is a comma-separated list
-   of depends or -.
-*/
-struct seq_operations modules_op = {
-	.start	= m_start,
-	.next	= m_next,
-	.stop	= m_stop,
-	.show	= m_show
+struct seq_operations ksyms_op = {
+	.start	= s_start,
+	.next	= s_next,
+	.stop	= s_stop,
+	.show	= s_show
 };
 
-/* Given an address, look for it in the module exception tables. */
-const struct exception_table_entry *search_module_extables(unsigned long addr)
+#define MODLIST_SIZE 4096
+
+/*
+ * this function isn't smp safe but that's not really a problem; it's
+ * called from oops context only and any locking could actually prevent
+ * the oops from going out; the line that is generated is informational
+ * only and should NEVER prevent the real oops from going out. 
+ */
+void print_modules(void)
+{
+	static char modlist[MODLIST_SIZE];
+	struct module *this_mod;
+	int pos = 0;
+
+	this_mod = module_list;
+	while (this_mod) {
+		if (this_mod->name)
+			pos += snprintf(modlist+pos, MODLIST_SIZE-pos-1, 
+					"%s ", this_mod->name);
+		this_mod = this_mod->next;
+	}
+	printk("%s\n",modlist);
+}
+
+const struct exception_table_entry *search_exception_tables(unsigned long addr)
 {
-	unsigned long flags;
 	const struct exception_table_entry *e = NULL;
-	struct exception_table *i;
+	/* The kernel is the last "module" -- no need to treat it special.  */
+	struct module *mp;
+	unsigned long flags;
 
 	spin_lock_irqsave(&modlist_lock, flags);
-	list_for_each_entry(i, &extables, list) {
-		if (i->num_entries == 0)
+	for (mp = module_list; mp != NULL; mp = mp->next) {
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
-				
-		e = search_extable(i->entry, i->entry+i->num_entries-1, addr);
+		e = search_extable(mp->ex_table_start,
+				   mp->ex_table_end - 1, addr);
 		if (e)
 			break;
 	}
 	spin_unlock_irqrestore(&modlist_lock, flags);
-
-	/* Now, if we found one, we are running inside it now, hence
-           we cannot unload the module, hence no refcnt needed. */
 	return e;
 }
 
-/* Is this a valid kernel address?  We don't grab the lock: we are oopsing. */
-int module_text_address(unsigned long addr)
+int kernel_text_address(unsigned long addr)
 {
 	struct module *mod;
 
-	list_for_each_entry(mod, &modules, list)
-		if (within(addr, mod->module_init, mod->init_size)
-		    || within(addr, mod->module_core, mod->core_size))
+	if (addr >= (unsigned long)_stext &&
+	    addr <= (unsigned long)_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		if (mod_bound(addr, 0, mod))
 			return 1;
+	}
 	return 0;
 }
 
-/* Provided by the linker */
-extern const struct kernel_symbol __start___ksymtab[];
-extern const struct kernel_symbol __stop___ksymtab[];
-extern const struct kernel_symbol __start___gpl_ksymtab[];
-extern const struct kernel_symbol __stop___gpl_ksymtab[];
-
-static struct kernel_symbol_group kernel_symbols, kernel_gpl_symbols;
-
-static int __init symbols_init(void)
-{
-	/* Add kernel symbols to symbol table */
-	kernel_symbols.num_syms = (__stop___ksymtab - __start___ksymtab);
-	kernel_symbols.syms = __start___ksymtab;
-	kernel_symbols.gplonly = 0;
-	list_add(&kernel_symbols.list, &symbols);
-	kernel_gpl_symbols.num_syms = (__stop___gpl_ksymtab
-				       - __start___gpl_ksymtab);
-	kernel_gpl_symbols.syms = __start___gpl_ksymtab;
-	kernel_gpl_symbols.gplonly = 1;
-	list_add(&kernel_gpl_symbols.list, &symbols);
+#else		/* CONFIG_MODULES */
+
+/* Dummy syscalls for people who don't want modules */
+
+asmlinkage unsigned long
+sys_create_module(const char *name_user, size_t size)
+{
+	return -ENOSYS;
+}
 
+asmlinkage long
+sys_init_module(const char *name_user, struct module *mod_user)
+{
+	return -ENOSYS;
+}
+
+asmlinkage long
+sys_delete_module(const char *name_user)
+{
+	return -ENOSYS;
+}
+
+asmlinkage long
+sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+		 size_t *ret)
+{
+	/* Let the program know about the new interface.  Not that
+	   it'll do them much good.  */
+	if (which == 0)
+		return 0;
+
+	return -ENOSYS;
+}
+
+asmlinkage long
+sys_get_kernel_syms(struct kernel_sym *table)
+{
+	return -ENOSYS;
+}
+
+int try_inc_mod_count(struct module *mod)
+{
+	return 1;
+}
+
+void print_modules(void)
+{
+}
+
+const struct exception_table_entry *search_exception_tables(unsigned long addr)
+{
+	/* There is only the kernel to search.  */
+	return search_extable(__start___ex_table, __stop___ex_table-1, addr);
+}
+
+int kernel_text_address(unsigned long addr)
+{
+	if (addr >= (unsigned long)_stext &&
+	    addr <= (unsigned long)_etext)
+		return 1;
 	return 0;
 }
 
-__initcall(symbols_init);
+#endif	/* CONFIG_MODULES */
Index: kernel/params.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/kernel/params.c,v
retrieving revision 1.1.1.3
diff -u -p -r1.1.1.3 params.c
--- kernel/params.c	27 Jan 2003 21:03:43 -0000	1.1.1.3
+++ kernel/params.c	6 Feb 2003 22:18:55 -0000
@@ -1,337 +1 @@
-/* Helpers for initial module or kernel cmdline parsing
-   Copyright (C) 2001 Rusty Russell.
 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt, a...)
-#endif
-
-static int parse_one(char *param,
-		     char *val,
-		     struct kernel_param *params, 
-		     unsigned num_params,
-		     int (*handle_unknown)(char *param, char *val))
-{
-	unsigned int i;
-
-	/* Find parameter */
-	for (i = 0; i < num_params; i++) {
-		if (strcmp(param, params[i].name) == 0) {
-			DEBUGP("They are equal!  Calling %p\n",
-			       params[i].set);
-			return params[i].set(val, &params[i]);
-		}
-	}
-
-	if (handle_unknown) {
-		DEBUGP("Unknown argument: calling %p\n", handle_unknown);
-		return handle_unknown(param, val);
-	}
-
-	DEBUGP("Unknown argument `%s'\n", param);
-	return -ENOENT;
-}
-
-/* You can use " around spaces, but can't escape ". */
-/* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
-{
-	unsigned int i, equals = 0;
-	int in_quote = 0;
-
-	/* Chew any extra spaces */
-	while (*args == ' ') args++;
-
-	for (i = 0; args[i]; i++) {
-		if (args[i] == ' ' && !in_quote)
-			break;
-		if (equals == 0) {
-			if (args[i] == '=')
-				equals = i;
-			else if (args[i] == '-')
-				args[i] = '_';
-		}
-		if (args[i] == '"')
-			in_quote = !in_quote;
-	}
-
-	*param = args;
-	if (!equals)
-		*val = NULL;
-	else {
-		args[equals] = '\0';
-		*val = args + equals + 1;
-	}
-
-	if (args[i]) {
-		args[i] = '\0';
-		return args + i + 1;
-	} else
-		return args + i;
-}
-
-/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
-int parse_args(const char *name,
-	       char *args,
-	       struct kernel_param *params,
-	       unsigned num,
-	       int (*unknown)(char *param, char *val))
-{
-	char *param, *val;
-
-	DEBUGP("Parsing ARGS: %s\n", args);
-
-	while (*args) {
-		int ret;
-
-		args = next_arg(args, &param, &val);
-		ret = parse_one(param, val, params, num, unknown);
-		switch (ret) {
-		case -ENOENT:
-			printk(KERN_ERR "%s: Unknown parameter `%s'\n",
-			       name, param);
-			return ret;
-		case -ENOSPC:
-			printk(KERN_ERR
-			       "%s: `%s' too large for parameter `%s'\n",
-			       name, val ?: "", param);
-			return ret;
-		case 0:
-			break;
-		default:
-			printk(KERN_ERR
-			       "%s: `%s' invalid for parameter `%s'\n",
-			       name, val ?: "", param);
-			return ret;
-		}
-	}
-
-	/* All parsed OK. */
-	return 0;
-}
-
-/* Lazy bastard, eh? */
-#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)      	\
-	int param_set_##name(const char *val, struct kernel_param *kp)	\
-	{								\
-		char *endp;						\
-		tmptype l;						\
-									\
-		if (!val) return -EINVAL;				\
-		l = strtolfn(val, &endp, 0);				\
-		if (endp == val || *endp || ((type)l != l))		\
-			return -EINVAL;					\
-		*((type *)kp->arg) = l;					\
-		return 0;						\
-	}								\
-	int param_get_##name(char *buffer, struct kernel_param *kp)	\
-	{								\
-		return sprintf(buffer, format, *((type *)kp->arg));	\
-	}
-
-STANDARD_PARAM_DEF(short, short, "%hi", long, simple_strtol);
-STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", long, simple_strtol);
-STANDARD_PARAM_DEF(int, int, "%i", long, simple_strtol);
-STANDARD_PARAM_DEF(uint, unsigned int, "%u", long, simple_strtol);
-STANDARD_PARAM_DEF(long, long, "%li", long, simple_strtol);
-STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, simple_strtoul);
-
-int param_set_charp(const char *val, struct kernel_param *kp)
-{
-	if (!val) {
-		printk(KERN_ERR "%s: string parameter expected\n",
-		       kp->name);
-		return -EINVAL;
-	}
-
-	if (strlen(val) > 1024) {
-		printk(KERN_ERR "%s: string parameter too long\n",
-		       kp->name);
-		return -ENOSPC;
-	}
-
-	*(char **)kp->arg = (char *)val;
-	return 0;
-}
-
-int param_get_charp(char *buffer, struct kernel_param *kp)
-{
-	return sprintf(buffer, "%s", *((char **)kp->arg));
-}
-
-int param_set_bool(const char *val, struct kernel_param *kp)
-{
-	/* No equals means "set"... */
-	if (!val) val = "1";
-
-	/* One of =[yYnN01] */
-	switch (val[0]) {
-	case 'y': case 'Y': case '1':
-		*(int *)kp->arg = 1;
-		return 0;
-	case 'n': case 'N': case '0':
-		*(int *)kp->arg = 0;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-int param_get_bool(char *buffer, struct kernel_param *kp)
-{
-	/* Y and N chosen as being relatively non-coder friendly */
-	return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N');
-}
-
-int param_set_invbool(const char *val, struct kernel_param *kp)
-{
-	int boolval, ret;
-	struct kernel_param dummy = { .arg = &boolval };
-
-	ret = param_set_bool(val, &dummy);
-	if (ret == 0)
-		*(int *)kp->arg = !boolval;
-	return ret;
-}
-
-int param_get_invbool(char *buffer, struct kernel_param *kp)
-{
-	int val;
-	struct kernel_param dummy = { .arg = &val };
-
-	val = !*(int *)kp->arg;
-	return param_get_bool(buffer, &dummy);
-}
-
-/* We cheat here and temporarily mangle the string. */
-int param_array(const char *name,
-		const char *val,
-		unsigned int min, unsigned int max,
-		void *elem, int elemsize,
-		int (*set)(const char *, struct kernel_param *kp))
-{
-	int ret;
-	unsigned int count = 0;
-	struct kernel_param kp;
-	char save;
-
-	/* Get the name right for errors. */
-	kp.name = name;
-	kp.arg = elem;
-
-	/* No equals sign? */
-	if (!val) {
-		printk(KERN_ERR "%s: expects arguments\n", name);
-		return -EINVAL;
-	}
-
-	/* We expect a comma-separated list of values. */
-	do {
-		int len;
-
-		if (count > max) {
-			printk(KERN_ERR "%s: can only take %i arguments\n",
-			       name, max);
-			return -EINVAL;
-		}
-		len = strcspn(val, ",");
-
-		/* nul-terminate and parse */
-		save = val[len];
-		((char *)val)[len] = '\0';
-		ret = set(val, &kp);
-
-		if (ret != 0)
-			return ret;
-		kp.arg += elemsize;
-		val += len+1;
-		count++;
-	} while (save == ',');
-
-	if (count < min) {
-		printk(KERN_ERR "%s: needs at least %i arguments\n",
-		       name, min);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/* First two elements are the max and min array length (which don't change) */
-int param_set_intarray(const char *val, struct kernel_param *kp)
-{
-	int *array;
-
-	/* Grab min and max as first two elements */
-	array = kp->arg;
-	return param_array(kp->name, val, array[0], array[1], &array[2],
-			   sizeof(int), param_set_int);
-}
-
-int param_get_intarray(char *buffer, struct kernel_param *kp)
-{
-	int max;
-	int *array;
-	unsigned int i;
-
-	array = kp->arg;
-	max = array[1];
-
-	for (i = 2; i < max + 2; i++)
-		sprintf(buffer, "%s%i", i > 2 ? "," : "", array[i]);
-	return strlen(buffer);
-}
-
-int param_set_copystring(const char *val, struct kernel_param *kp)
-{
-	struct kparam_string *kps = kp->arg;
-
-	if (strlen(val)+1 > kps->maxlen) {
-		printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
-		       kp->name, kps->maxlen-1);
-		return -ENOSPC;
-	}
-	strcpy(kps->string, val);
-	return 0;
-}
-
-EXPORT_SYMBOL(param_set_short);
-EXPORT_SYMBOL(param_get_short);
-EXPORT_SYMBOL(param_set_ushort);
-EXPORT_SYMBOL(param_get_ushort);
-EXPORT_SYMBOL(param_set_int);
-EXPORT_SYMBOL(param_get_int);
-EXPORT_SYMBOL(param_set_uint);
-EXPORT_SYMBOL(param_get_uint);
-EXPORT_SYMBOL(param_set_long);
-EXPORT_SYMBOL(param_get_long);
-EXPORT_SYMBOL(param_set_ulong);
-EXPORT_SYMBOL(param_get_ulong);
-EXPORT_SYMBOL(param_set_charp);
-EXPORT_SYMBOL(param_get_charp);
-EXPORT_SYMBOL(param_set_bool);
-EXPORT_SYMBOL(param_get_bool);
-EXPORT_SYMBOL(param_set_invbool);
-EXPORT_SYMBOL(param_get_invbool);
-EXPORT_SYMBOL(param_set_intarray);
-EXPORT_SYMBOL(param_get_intarray);
-EXPORT_SYMBOL(param_set_copystring);
Index: net/ipv4/netfilter/ip_nat_helper.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/net/ipv4/netfilter/ip_nat_helper.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 ip_nat_helper.c
--- net/ipv4/netfilter/ip_nat_helper.c	27 Jan 2003 22:31:16 -0000	1.1.1.6
+++ net/ipv4/netfilter/ip_nat_helper.c	6 Feb 2003 22:18:57 -0000
@@ -27,6 +27,8 @@
 #include <net/tcp.h>
 #include <net/udp.h>
 
+#define MODULE_NAME_LEN (64 - sizeof(unsigned long))
+
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
Index: scripts/Makefile.modinst
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/scripts/Makefile.modinst,v
retrieving revision 1.1.1.4
diff -u -p -r1.1.1.4 Makefile.modinst
--- scripts/Makefile.modinst	16 Dec 2002 19:40:12 -0000	1.1.1.4
+++ scripts/Makefile.modinst	6 Feb 2003 22:18:58 -0000
@@ -15,12 +15,12 @@ include scripts/Makefile.lib
 
 # ==========================================================================
 
-quiet_cmd_modules_install = INSTALL $(obj-m:.o=.ko)
-      cmd_modules_install = mkdir -p $(MODLIB)/kernel/$(obj); \
-			    cp $(obj-m:.o=.ko) $(MODLIB)/kernel/$(obj)
+quiet_cmd_modules_install = INSTALL $(obj-m)
+      cmd_modules_install = mkdir -p $(MODLIB)/kernel/$(obj) \
+			    $(foreach o,$(obj-m),; cp $(o:.o=.ko) $(MODLIB)/kernel/$(o))
 
 modules_install: $(subdir-ym)
-ifneq ($(obj-m:.o=.ko),)
+ifneq ($(obj-m),)
 	$(call cmd,modules_install)
 else
 	@:
Index: sound/sound_core.c
===================================================================
RCS file: /usr/src/cvsroot/linux-2.5/sound/sound_core.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 sound_core.c
--- sound/sound_core.c	10 Dec 2002 18:40:47 -0000	1.1.1.6
+++ sound/sound_core.c	6 Feb 2003 22:18:58 -0000
@@ -44,6 +44,7 @@
 #include <linux/sound.h>
 #include <linux/major.h>
 #include <linux/kmod.h>
+#include <linux/string.h>
 #include <linux/devfs_fs_kernel.h>
 
 #define SOUND_STEP 16
