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 -#include -#include -#include -#include -#include - -#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 #include #include +#include #include #include 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 #include +#include #include #include 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 #include #include +#include #include #include 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 #include #include +#include #include #include 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 #include +#include #include #include #include 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 #include +#include #include #include #include @@ -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 +#include #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 Dec 1996 - * Rewritten again by Rusty Russell, 2002 */ + +#ifndef _LINUX_MODULE_H +#define _LINUX_MODULE_H + #include -#include #include #include -#include -#include -#include -#include -#include -#include +#include -#include -#include /* For struct exception_table_entry */ +#include -/* 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 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 +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 + * #include + * <<>> + * + * 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 + * + * #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 -/* 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 -#include - -/* 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 -#include -/* 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 + 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 #include #include -#include #include #include @@ -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 - -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 Oct 2000 */ -#include -#include -#include -#include -#include - -/* 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 +#include #include /* 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 +#include #include -#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#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 + * 0.99.14 version by Jon Tombs , + * Heavily modified by Bjorn Ekwall May 1994 (C) + * Rewritten by Richard Henderson Dec 1996 + * Add MOD_INITIALIZING Keith Owens Nov 1999 + * Add kallsyms support, Keith Owens Apr 2000 + * Add asm/module support, IA64 has special requirements. Keith Owens Sep 2000 + * Fix assorted bugs in module verification. Keith Owens Sep 2000 + * Fix sys_init_module race, Andrew Morton Oct 2000 + * http://www.uwsg.iu.edu/hypermail/linux/kernel/0008.3/0379.html + * Replace xxx_module_symbol with inter_module_xxx. Keith Owens Oct 2000 + * Add a module list lock for kernel fault race fixing. Alan Cox + * + * 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, ¶m); -#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 -#include -#include -#include -#include - -#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, ¶ms[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, ¶m, &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 #include +#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 #include #include +#include #include #define SOUND_STEP 16