Name: Module With try_get_module Implementation Author: Rusty Russell Status: Tested on 2.5.38 Depends: Misc/kbuild_object.patch.gz Depends: Misc/bigrefs.patch.gz Module/implicit-init-removal.patch.gz Depends: Module/everyone-needs-init.patch.gz Depends: Module/param.patch.gz D: This is an implementation of the in-kernel module loader extending D: the try_inc_mod_count() primitive and making its use compulsory. D: This has the benifit of simplicity, and similarity to the existing D: scheme. To reduce the cost of the constant increments and D: decrements, bigrefs are used. D: D: Modversions and Module parameters are not supported in this patch, D: they come in future patches. D: D: You will need the trivial replacement module utilities from: D: http://www.kernel.org/pub/linux/people/rusty/module-init-tools-0.5.tar.gz diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/Makefile .13485-linux-2.5.38.updated/Makefile --- .13485-linux-2.5.38/Makefile 2002-09-23 08:54:50.000000000 +1000 +++ .13485-linux-2.5.38.updated/Makefile 2002-09-25 10:31:42.000000000 +1000 @@ -137,7 +137,6 @@ OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms -DEPMOD = /sbin/depmod PERL = perl MODFLAGS = -DMODULE CFLAGS_MODULE = $(MODFLAGS) @@ -471,7 +470,7 @@ modules: $(SUBDIRS) # Install modules .PHONY: modules_install -modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) _modinst_post +modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) .PHONY: _modinst_ _modinst_: @@ -480,20 +479,6 @@ _modinst_: @mkdir -p $(MODLIB)/kernel @ln -s $(TOPDIR) $(MODLIB)/build -# If System.map exists, run depmod. This deliberately does not have a -# dependency on System.map since that would run the dependency tree on -# vmlinux. This depmod is only for convenience to give the initial -# boot a modules.dep even before / is mounted read-write. However the -# boot script depmod is the master version. -ifeq "$(strip $(INSTALL_MOD_PATH))" "" -depmod_opts := -else -depmod_opts := -b $(INSTALL_MOD_PATH) -r -endif -.PHONY: _modinst_post -_modinst_post: - if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi - .PHONY: $(patsubst %, _modinst_%, $(SUBDIRS)) $(patsubst %, _modinst_%, $(SUBDIRS)) : @$(MAKE) -C $(patsubst _modinst_%, %, $@) modules_install diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/Rules.make .13485-linux-2.5.38.updated/Rules.make --- .13485-linux-2.5.38/Rules.make 2002-09-25 10:31:14.000000000 +1000 +++ .13485-linux-2.5.38.updated/Rules.make 2002-09-25 10:31:42.000000000 +1000 @@ -243,9 +243,9 @@ ifeq ($(MAKECMDGOALS),modules_install) modules_install: sub_dirs ifneq ($(obj-m),) - @echo Installing modules in $(MODLIB)/kernel/$(RELDIR) - @mkdir -p $(MODLIB)/kernel/$(RELDIR) - @cp $(obj-m) $(MODLIB)/kernel/$(RELDIR) + @echo Installing modules in $(MODLIB)/kernel/ + @mkdir -p $(MODLIB)/kernel + @cp $(obj-m) $(MODLIB)/kernel else @echo -n endif diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/drivers/block/floppy.c .13485-linux-2.5.38.updated/drivers/block/floppy.c --- .13485-linux-2.5.38/drivers/block/floppy.c 2002-09-23 08:54:51.000000000 +1000 +++ .13485-linux-2.5.38.updated/drivers/block/floppy.c 2002-09-25 10:31:42.000000000 +1000 @@ -151,6 +151,7 @@ static int print_unex=1; #include #include #include +#include #define FDPATCHES #include diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/drivers/char/ftape/compressor/zftape-compress.c .13485-linux-2.5.38.updated/drivers/char/ftape/compressor/zftape-compress.c --- .13485-linux-2.5.38/drivers/char/ftape/compressor/zftape-compress.c 2002-05-25 10:58:19.000000000 +1000 +++ .13485-linux-2.5.38.updated/drivers/char/ftape/compressor/zftape-compress.c 2002-09-25 10:31:42.000000000 +1000 @@ -1266,13 +1266,6 @@ MODULE_DESCRIPTION( "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); MODULE_LICENSE("GPL"); -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18) -static int can_unload(void) -{ - return keep_module_locked ? -EBUSY : 0; -} -#endif - /* Called by modules package when installing the driver */ int init_module(void) @@ -1282,10 +1275,12 @@ int init_module(void) #if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) register_symtab(0); /* remove global ftape symbols */ #else +#if 0 /* FIXME --RR */ if (!mod_member_present(&__this_module, can_unload)) return -EBUSY; __this_module.can_unload = can_unload; #endif +#endif result = zft_compressor_init(); keep_module_locked = 0; return result; diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/fs/proc/proc_misc.c .13485-linux-2.5.38.updated/fs/proc/proc_misc.c --- .13485-linux-2.5.38/fs/proc/proc_misc.c 2002-09-21 13:55:16.000000000 +1000 +++ .13485-linux-2.5.38.updated/fs/proc/proc_misc.c 2002-09-25 10:31:42.000000000 +1000 @@ -280,17 +280,6 @@ 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; @@ -633,7 +622,6 @@ void __init proc_misc_init(void) create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_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) { diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/include/linux/elf.h .13485-linux-2.5.38.updated/include/linux/elf.h --- .13485-linux-2.5.38/include/linux/elf.h 2001-10-18 18:59:10.000000000 +1000 +++ .13485-linux-2.5.38.updated/include/linux/elf.h 2002-09-25 10:31:42.000000000 +1000 @@ -194,6 +194,9 @@ typedef struct { #define ELF32_R_SYM(x) ((x) >> 8) #define ELF32_R_TYPE(x) ((x) & 0xff) +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + #define R_386_NONE 0 #define R_386_32 1 #define R_386_PC32 2 @@ -291,6 +294,7 @@ typedef struct { #define R_SPARC_PCPLT10 29 #define R_SPARC_10 30 #define R_SPARC_11 31 +#define R_SPARC_64 32 #define R_SPARC_WDISP16 40 #define R_SPARC_WDISP19 41 #define R_SPARC_7 43 @@ -365,6 +369,47 @@ typedef struct { #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + /* Legal values for e_flags field of Elf64_Ehdr. */ #define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/include/linux/init.h .13485-linux-2.5.38.updated/include/linux/init.h --- .13485-linux-2.5.38/include/linux/init.h 2002-09-25 10:31:18.000000000 +1000 +++ .13485-linux-2.5.38.updated/include/linux/init.h 2002-09-25 10:31:42.000000000 +1000 @@ -38,17 +38,29 @@ * Also note, that this data cannot be "const". */ -#ifndef MODULE +/* These are for everybody (although not all archs will actually + discard it in modules) */ +#define __init __attribute__ ((__section__ (".text.init"))) +#define __initdata __attribute__ ((__section__ (".data.init"))) +#define __exit __attribute__ ((__section__(".text.exit"))) +#define __exitdata __attribute__ ((__section__(".data.exit"))) -#ifndef __ASSEMBLY__ +/* For assembly routines */ +#define __INIT .section ".text.init","ax" +#define __FINIT .previous +#define __INITDATA .section ".data.init","aw" +#ifndef __ASSEMBLY__ /* * Used for initialization calls.. */ typedef int (*initcall_t)(void); typedef void (*exitcall_t)(void); +#endif -extern initcall_t __initcall_start, __initcall_end; +#ifndef MODULE + +#ifndef __ASSEMBLY__ /* initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined @@ -70,7 +82,7 @@ extern initcall_t __initcall_start, __in #define __initcall(fn) device_initcall(fn) -#define __exitcall(fn) \ +#define __exitcall(fn) \ static exitcall_t __exitcall_##fn __exit_call = fn /* @@ -89,23 +101,10 @@ extern struct kernel_param __setup_start #endif /* __ASSEMBLY__ */ -/* - * Mark functions and data as being only used at initialization - * or exit time. - */ -#define __init __attribute__ ((__section__ (".text.init"))) -#define __exit __attribute__ ((unused, __section__(".text.exit"))) -#define __initdata __attribute__ ((__section__ (".data.init"))) -#define __exitdata __attribute__ ((unused, __section__ (".data.exit"))) #define __initsetup __attribute__ ((unused,__section__ (".setup.init"))) #define __init_call(level) __attribute__ ((unused,__section__ (".initcall" level ".init"))) #define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) -/* For assembly routines */ -#define __INIT .section ".text.init","ax" -#define __FINIT .previous -#define __INITDATA .section ".data.init","aw" - /** * module_init() - driver initialization entry point * @x: function to be run at kernel boot time or module insertion @@ -129,44 +128,40 @@ extern struct kernel_param __setup_start */ #define module_exit(x) __exitcall(x); -#else +#else /* MODULE */ -#define __init -#define __exit -#define __initdata -#define __exitdata -#define __initcall(fn) -/* For assembly routines */ -#define __INIT -#define __FINIT -#define __INITDATA + +/* Each module knows its own name. */ +#define __DEFINE_MODULE_NAME \ + char __module_name[] __attribute__((section(".modulename"))) = \ + __stringify(KBUILD_MODNAME) /* 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. */ -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 */ +/* This is compulsory for modules. */ +#define module_init(initfn) \ + __DEFINE_MODULE_NAME; \ + static inline initcall_t __inittest(void) \ + { return initfn; } \ + int __initfn(void) __attribute__((alias(#initfn))); -#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) +/* This is only required if you want to be unloadable. */ +#define module_exit(exitfn) \ + static inline exitcall_t __exittest(void) \ + { return exitfn; } \ + void __exitfn(void) __attribute__((alias(#exitfn))); + + +#define __setup(str,func) /* nothing */ +/* You can't just name your functions init_module() and + cleanup_module() and expect things to "just work" anymore. */ +void init_module(int *clash_with_other_decls); +void cleanup_module(int *clash_with_other_decls); #endif /* Data marked not to be saved by software_suspend() */ diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/include/linux/module.h .13485-linux-2.5.38.updated/include/linux/module.h --- .13485-linux-2.5.38/include/linux/module.h 2002-06-03 16:43:17.000000000 +1000 +++ .13485-linux-2.5.38.updated/include/linux/module.h 2002-09-25 10:31:42.000000000 +1000 @@ -1,509 +1,276 @@ +#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 /* For struct exception_table_entry */ -#include - -/* Don't need to bring in all of uaccess.h just for this decl. */ -struct exception_table_entry; - -/* 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 */ -}; +/* Not Yet Implemented */ +#define MODULE_LICENSE(name) +#define MODULE_AUTHOR(name) +#define MODULE_DESCRIPTION(desc) +#define MODULE_SUPPORTED_DEVICE(name) +#define MODULE_GENERIC_TABLE(gtype,name) +#define MODULE_DEVICE_TABLE(type,name) +#define MODULE_PARM_DESC(var,desc) -struct module_symbol +#define MODULE_NAME_LEN (64 - sizeof(unsigned long)) +struct kernel_symbol { unsigned long value; - const char *name; + char name[MODULE_NAME_LEN]; }; -struct module_ref -{ - struct module *dep; /* "parent" pointer */ - struct module *ref; /* "child" pointer */ - struct module_ref *next_ref; -}; +#ifdef MODULE +/* This is magically filled in by the linker, but THIS_MODULE must be + a constant so it works in initializers. */ +extern struct module __this_module; +#define THIS_MODULE (&__this_module) +#else +#define THIS_MODULE ((struct module *)0) +#endif -/* TBD */ -struct module_persist; +#ifdef CONFIG_MODULES +/* Get/put a kernel symbol (calls should be symmetric) */ +#define symbol_get(x) ((typeof(&x))(__get_symbol(#x))) -struct module -{ - unsigned long size_of_struct; /* == sizeof(module) */ - struct module *next; - const char *name; - unsigned long size; +/* For every exported symbol, place a struct in the __ksymtab section */ +#define EXPORT_SYMBOL(sym) \ + const struct kernel_symbol __ksymtab_##sym \ + __attribute__((section("__ksymtab"))) \ + = { (unsigned long)&sym, #sym } - union - { - atomic_t usecount; - long pad; - } uc; /* Needs to keep its size - so says rth */ +#define EXPORT_SYMBOL_NOVERS(sym) EXPORT_SYMBOL(sym) +#define EXPORT_SYMBOL_GPL(sym) EXPORT_SYMBOL(sym) - unsigned long flags; /* AUTOCLEAN et al */ +struct kernel_symbol_group +{ + /* Links us into the global symbol list */ + struct list_head list; - unsigned nsyms; - unsigned ndeps; + /* Module which owns it (if any) */ + struct module *owner; - 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 */ + unsigned int num_syms; + const struct kernel_symbol *syms; }; -struct module_info +struct exception_table { - 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); -#endif /* __KERNEL__ */ + unsigned int num_entries; + const struct exception_table_entry *entry; +}; -#if defined(MODULE) && !defined(__GENKSYMS__) +struct module +{ + struct list_head list; -/* Embedded module documentation macros. */ + /* Unique handle for this module */ + char name[MODULE_NAME_LEN]; -/* For documentation purposes only. */ + /* Exported symbols */ + struct kernel_symbol_group symbols; -#define MODULE_AUTHOR(name) \ -const char __module_author[] __attribute__((section(".modinfo"))) = \ -"author=" name + /* Exception tables */ + struct exception_table extable; -#define MODULE_DESCRIPTION(desc) \ -const char __module_description[] __attribute__((section(".modinfo"))) = \ -"description=" desc + /* Startup function. */ + int (*init)(void); -/* Could potentially be used by kmod... */ + /* If this is non-NULL, vfree after init() returns */ + void *module_init; -#define MODULE_SUPPORTED_DEVICE(dev) \ -const char __module_device[] __attribute__((section(".modinfo"))) = \ -"device=" dev + /* Here is the actual code + data, vfree'd on unload. */ + void *module_core; -/* 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 -*/ + /* Here are the sizes of the init and core sections */ + unsigned long init_size, core_size; -#define MODULE_PARM(var,type) \ -const char __module_parm_##var[] \ -__attribute__((section(".modinfo"))) = \ -"parm_" __MODULE_STRING(var) "=" type + /* Arch-specific module values */ + struct mod_arch_specific arch; -#define MODULE_PARM_DESC(var,desc) \ -const char __module_parm_desc_##var[] \ -__attribute__((section(".modinfo"))) = \ -"parm_desc_" __MODULE_STRING(var) "=" desc + /* Am I available for usage? */ + int live; -/* - * 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 + /* Am I unsafe to unload? */ + int unsafe_to_unload; -/* - * The following license idents are currently accepted as indicating free - * software modules - * - * "GPL" [GNU Public License v2 or later] - * "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] - * - * The following other idents are available - * - * "Proprietary" [Non free products] - * - * There are dual licensed components, but when running with Linux it is the - * GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL - * is a GPL combined work. - * - * This exists for several reasons - * 1. So modinfo can show license info for users wanting to vet their setup - * is free - * 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(".modinfo"))) = \ -"license=" license +#ifdef CONFIG_MODULE_UNLOAD + /* Usage count. */ + struct bigref use; -/* Define the module variable, and usage macros. */ -extern struct module __this_module; + /* What modules depend on me? */ + struct list_head modules_which_use_me; -#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) + /* Who is waiting for us to be unloaded */ + struct task_struct *waiting; -#include -static const char __module_kernel_version[] __attribute__((section(".modinfo"))) = -"kernel_version=" UTS_RELEASE; -#ifdef CONFIG_MODVERSIONS -static const char __module_using_checksums[] __attribute__((section(".modinfo"))) = -"using_checksums=1"; + /* Destruction function. */ + void (*exit)(void); #endif -#else /* MODULE */ - -#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) - -/* 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__(".data.exit"))) = name - -#ifndef __GENKSYMS__ - -#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 - -extern struct module *module_list; - -#endif /* !__GENKSYMS__ */ - -#endif /* MODULE */ - -#define MODULE_DEVICE_TABLE(type,name) \ - MODULE_GENERIC_TABLE(type##_device,name) - -/* Export a symbol either from the kernel or a module. + /* The command line arguments (may be mangled). People like + keeping pointers to this stuff */ + char args[0]; +}; - In the kernel, the symbol is added to the kernel's global symbol table. +/* Helper function for arch-specific module loaders */ +unsigned long find_symbol_internal(Elf_Shdr *sechdrs, + unsigned int symindex, + const char *strtab, + const char *name, + struct module *mod, + struct kernel_symbol_group **group); - 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. */ +/* These must be implemented by the specific architecture */ -/* 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. - */ +/* vmalloc AND zero for the non-releasable code; return ERR_PTR() on error. */ +void *module_core_alloc(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod); -#if defined(__GENKSYMS__) +/* vmalloc and zero (if any) for sections to be freed after init. + Return ERR_PTR() on error. */ +void *module_init_alloc(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod); -/* We want the EXPORT_SYMBOL tag left intact for recognition. */ +/* 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); -#elif !defined(CONFIG_MODULES) +/* 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); -#define __EXPORT_SYMBOL(sym,str) -#define EXPORT_SYMBOL(var) -#define EXPORT_SYMBOL_NOVERS(var) -#define EXPORT_SYMBOL_GPL(var) +/* 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); -#elif !defined(EXPORT_SYMTAB) +/* Free memory returned from module_core_alloc/module_init_alloc */ +void module_free(struct module *mod, void *module_region); -#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 +#ifdef CONFIG_MODULE_UNLOAD +#define symbol_put(x) __put_symbol(#x) -#else +void *__symbol_get(const char *symbol); +void __symbol_put(const char *symbol); -#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 } +extern int __try_module_get(struct module *module); +extern int __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 } +static inline int try_module_get(struct module *module) +{ + if (!module) + return 1; + else + return __try_module_get(module); +} -#if defined(CONFIG_MODVERSIONS) && !defined(MODULE) +/* Returns true if we're the last one out of a dying module */ +static inline int module_put(struct module *module) +{ + if (!module) + return 0; + return __module_put(module); +} -#define _set_ver(sym) sym -#include +#define __unsafe(mod) \ +do { \ + if ((mod) && (mod)->exit && !(mod)->unsafe_to_unload) { \ + printk(KERN_WARNING \ + "Module %s cannot be unloaded due to unsafe usage in" \ + " %s:%u\n", (mod)->name, __FILE__, __LINE__); \ + (mod)->unsafe_to_unload = 1; \ + } \ +} while(0) -#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))) +#else /*!CONFIG_MODULE_UNLOAD*/ +static inline int try_module_get(struct module *module) +{ + return !module || module->live; +} +static inline int module_put(struct module *module) +{ + return 0; +} +#define symbol_put(x) do { } while(0) -#else /* !defined (CONFIG_MODVERSIONS) || defined(MODULE) */ +#define __unsafe(mod) +#endif /* CONFIG_MODULE_UNLOAD */ -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) -#define EXPORT_SYMBOL_GPL(var) __EXPORT_SYMBOL_GPL(var, __MODULE_STRING(var)) +#else /* !CONFIG_MODULES... */ +#define EXPORT_SYMBOL(sym) +#define EXPORT_SYMBOL_GPL(sym) +#define EXPORT_SYMBOL_NOVERS(sym) -#endif /* defined(CONFIG_MODVERSIONS) && !defined(MODULE) */ +/* Get/put a kernel symbol (calls should be symmetric) */ +#define symbol_get(x) ((typeof(&x))(0)) -#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) +#define try_module_get(module) 1 +#define module_put(module) do { } while(0) -#endif /* __GENKSYMS__ */ +#define __unsafe(mod) do { } while(0) +#endif /* CONFIG_MODULES */ -/* - * 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 +/* For archs to search exception tables */ +extern struct list_head extables; +extern spinlock_t modlist_lock; -#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 +/* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */ +#define __MOD_INC_USE_COUNT(mod) \ + do { (void)try_module_get(mod); __unsafe(mod); } while(0) +#define __MOD_DEC_USE_COUNT(mod) module_put(mod) +#define SET_MODULE_OWNER(dev) ((dev)->owner = THIS_MODULE) -#ifdef CONFIG_MODULES -#define SET_MODULE_OWNER(some_struct) do { (some_struct)->owner = THIS_MODULE; } while (0) +/* People do this inside their init routines, when the module isn't + "live" yet. They should no longer be doing that, but + meanwhile... */ +#if defined(CONFIG_MODULE_UNLOAD) && defined(MODULE) +#define MOD_INC_USE_COUNT \ + do { bigref_inc(&THIS_MODULE->use); __unsafe(THIS_MODULE); } while (0) #else -#define SET_MODULE_OWNER(some_struct) do { } while (0) +#define MOD_INC_USE_COUNT \ + do { (void)try_module_get(THIS_MODULE); __unsafe(THIS_MODULE); } while (0) #endif - +#define MOD_DEC_USE_COUNT module_put(THIS_MODULE) +#define try_inc_mod_count(mod) try_module_get(mod) +#define MODULE_PARM(parm,string) +#define EXPORT_NO_SYMBOLS +extern int module_dummy_usage; +#define GET_USE_COUNT(module) (module_dummy_usage) +#define MOD_IN_USE 0 +#define __mod_between(a_start, a_len, b_start, b_len) \ +(((a_start) >= (b_start) && (a_start) <= (b_start)+(b_len)) \ + || ((a_start)+(a_len) >= (b_start) \ + && (a_start)+(a_len) <= (b_start)+(b_len))) +#define mod_bound(p, n, m) \ +(((m)->module_init \ + && __mod_between((p),(n),(m)->module_init,(m)->init_size)) \ + || __mod_between((p),(n),(m)->module_core,(m)->core_size)) #endif /* _LINUX_MODULE_H */ diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/init/Config.help .13485-linux-2.5.38.updated/init/Config.help --- .13485-linux-2.5.38/init/Config.help 2002-05-24 15:20:34.000000000 +1000 +++ .13485-linux-2.5.38.updated/init/Config.help 2002-09-25 10:31:42.000000000 +1000 @@ -91,6 +91,11 @@ 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 + Without this option you will not be able to unload any modules (note + that some modules may not be unloadable anyway). This makes your + kernel slightly smaller and simpler. If unsure, say Y. + CONFIG_MODVERSIONS Usually, modules have to be recompiled whenever you switch to a new kernel. Saying Y here makes it possible, and safe, to use the diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/init/Config.in .13485-linux-2.5.38.updated/init/Config.in --- .13485-linux-2.5.38/init/Config.in 2002-02-20 17:56:42.000000000 +1100 +++ .13485-linux-2.5.38.updated/init/Config.in 2002-09-25 10:31:42.000000000 +1000 @@ -14,8 +14,6 @@ endmenu mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES -if [ "$CONFIG_MODULES" = "y" ]; then - bool ' Set version information on all module symbols' CONFIG_MODVERSIONS - bool ' Kernel module loader' CONFIG_KMOD -fi +dep_bool ' Kernel module loader' CONFIG_KMOD $CONFIG_MODULES +dep_bool ' Module unloading' CONFIG_MODULE_UNLOAD $CONFIG_MODULES endmenu diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/init/main.c .13485-linux-2.5.38.updated/init/main.c --- .13485-linux-2.5.38/init/main.c 2002-09-25 10:31:18.000000000 +1000 +++ .13485-linux-2.5.38.updated/init/main.c 2002-09-25 10:31:42.000000000 +1000 @@ -376,9 +376,6 @@ 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 if (prof_shift) { unsigned int size; /* only text is profiled */ @@ -434,6 +431,8 @@ asmlinkage void __init start_kernel(void struct task_struct *child_reaper = &init_task; +extern initcall_t __initcall_start, __initcall_end; + static void __init do_initcalls(void) { initcall_t *call; diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/kernel/Makefile .13485-linux-2.5.38.updated/kernel/Makefile --- .13485-linux-2.5.38/kernel/Makefile 2002-09-25 10:31:18.000000000 +1000 +++ .13485-linux-2.5.38.updated/kernel/Makefile 2002-09-25 10:31:42.000000000 +1000 @@ -6,7 +6,7 @@ export-objs = signal.o sys.o kmod.o cont printk.o platform.o suspend.o dma.o bigref.o obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ - module.o exit.o itimer.o time.o softirq.o resource.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 context.o futex.o platform.o pid.o bigref.o \ params.o @@ -14,7 +14,7 @@ obj-y = sched.o fork.o exec_domain.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o obj-$(CONFIG_UID16) += uid16.o -obj-$(CONFIG_MODULES) += ksyms.o +obj-$(CONFIG_MODULES) += ksyms.o module.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/kernel/exec_domain.c .13485-linux-2.5.38.updated/kernel/exec_domain.c --- .13485-linux-2.5.38/kernel/exec_domain.c 2002-05-24 15:20:34.000000000 +1000 +++ .13485-linux-2.5.38.updated/kernel/exec_domain.c 2002-09-25 10:31:42.000000000 +1000 @@ -211,7 +211,12 @@ get_exec_domain_list(char *page) for (ep = exec_domains; ep && len < PAGE_SIZE - 80; ep = ep->next) len += sprintf(page + len, "%d-%d\t%-16s\t[%s]\n", ep->pers_low, ep->pers_high, ep->name, - ep->module ? ep->module->name : "kernel"); +#ifdef CONFIG_MODULES + ep->module ? ep->module->name : "kernel" +#else + "kernel" +#endif + ); read_unlock(&exec_domains_lock); return (len); } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/kernel/kmod.c .13485-linux-2.5.38.updated/kernel/kmod.c --- .13485-linux-2.5.38/kernel/kmod.c 2002-08-28 09:29:53.000000000 +1000 +++ .13485-linux-2.5.38.updated/kernel/kmod.c 2002-09-25 10:31:42.000000000 +1000 @@ -155,7 +155,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, "-s", "-k", "--", (char*)module_name, NULL }; + char *argv[] = { modprobe_path, "--", (char*)module_name, NULL }; int ret; if (!system_running) diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/kernel/ksyms.c .13485-linux-2.5.38.updated/kernel/ksyms.c --- .13485-linux-2.5.38/kernel/ksyms.c 2002-09-23 08:54:54.000000000 +1000 +++ .13485-linux-2.5.38.updated/kernel/ksyms.c 2002-09-25 10:31:42.000000000 +1000 @@ -76,14 +76,6 @@ __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); diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/kernel/module.c .13485-linux-2.5.38.updated/kernel/module.c --- .13485-linux-2.5.38/kernel/module.c 2002-08-02 11:15:10.000000000 +1000 +++ .13485-linux-2.5.38.updated/kernel/module.c 2002-09-25 10:33:09.000000000 +1000 @@ -1,1134 +1,964 @@ +/* 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 -#include #include -#include -#include -#include -#include -#include #include #include -#include +#include +#include #include -#include +#include +#include +#include +#include #include -/* - * 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. - */ - -#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) - -extern struct module_symbol __start___ksymtab[]; -extern struct module_symbol __stop___ksymtab[]; +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , ...) +#endif extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; +extern const struct kernel_symbol __start___ksymtab[]; +extern const struct kernel_symbol __stop___ksymtab[]; -extern const char __start___kallsyms[] __attribute__ ((weak)); -extern const char __stop___kallsyms[] __attribute__ ((weak)); - -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, -}; - -struct module *module_list = &kernel_module; - -#endif /* defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) */ +/* Protects extables and symbol tables */ +spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED; -/* 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. - */ +/* The exception and symbol tables: start with kernel only. */ +LIST_HEAD(extables); +static LIST_HEAD(symbols); -static struct list_head ime_list = LIST_HEAD_INIT(ime_list); -static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED; -static int kmalloc_failed; +static struct exception_table kernel_extable; +static struct kernel_symbol_group kernel_symbols; -/* - * 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. - */ - -spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED; +/* List of modules, protected by module_mutex */ +static DECLARE_MUTEX(module_mutex); +LIST_HEAD(modules); /* FIXME: Accessed w/o lock on oops by some archs */ -/** - * 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) +/* Convenient structure for holding init and core sizes */ +struct sizes { - struct list_head *tmp; - struct inter_module_entry *ime, *ime_new; + unsigned long init_size; + unsigned long core_size; +}; - 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; +/* Find a symbol, return value and the symbol group */ +static unsigned long __find_symbol(const char *name, + struct kernel_symbol_group **group) +{ + struct kernel_symbol_group *ks; + + list_for_each_entry(ks, &symbols, list) { + unsigned int i; - 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(); + for (i = 0; i < ks->num_syms; i++) { + if (strcmp(ks->syms[i].name, name) == 0) { + *group = ks; + return ks->syms[i].value; + } } } - list_add(&(ime_new->list), &ime_list); - spin_unlock(&ime_lock); + DEBUGP("Failed to find symbol %s\n", name); + return 0; } -/** - * 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) +/* 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) { - struct list_head *tmp; - struct inter_module_entry *ime; + unsigned int i; + Elf_Sym *sym = (void *)sechdrs[symindex].sh_offset; - 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(); + /* 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; } -/** - * 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) +/* Search for module by name: must hold module_mutex. */ +static struct module *find_module(const char *name) { - struct list_head *tmp; - struct inter_module_entry *ime; - const void *result = NULL; + struct module *mod; - 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; - } + list_for_each_entry(mod, &modules, list) { + if (strcmp(mod->name, name) == 0) + return mod; } - spin_unlock(&ime_lock); - return(result); + return NULL; } -/** - * 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) +#ifdef CONFIG_MODULE_UNLOAD +/* Init the unload section of the module */ +static void module_unload_init(struct module *mod) { - const void *result = inter_module_get(im_name); - if (!result) { - request_module(modname); - result = inter_module_get(im_name); - } - return(result); + INIT_LIST_HEAD(&mod->modules_which_use_me); + bigref_init(&mod->use, 1); } -/** - * 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) +/* modules using other modules */ +struct module_use { - struct list_head *tmp; - struct inter_module_entry *ime; + struct list_head list; + struct module *module_which_uses; +}; - 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; +/* 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; } } - spin_unlock(&ime_lock); - printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name); - BUG(); + DEBUGP("%s does not use %s!\n", a->name, b->name); + return 0; } - -#if defined(CONFIG_MODULES) /* The rest of the source */ - -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); - - -/* - * Called at boot time - */ - -void __init init_modules(void) +/* Module a uses b */ +static int use_module(struct module *a, struct module *b) { - kernel_module.nsyms = __stop___ksymtab - __start___ksymtab; + struct module_use *use; + if (b == NULL || already_uses(a, b)) return 1; - arch_init_modules(&kernel_module); -} + 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; + } -/* - * Copy the name of a module from user space. - */ + use->module_which_uses = a; + list_add(&use->list, &b->modules_which_use_me); + try_module_get(b); /* Can't fail */ + return 1; +} -static inline long -get_mod_name(const char *user_name, char **buf) +/* Clear the unload stuff of the module. */ +static void module_unload_free(struct module *mod) { - unsigned long page; - long retval; + struct module *i; - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + list_for_each_entry(i, &modules, list) { + struct module_use *use; - retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); - if (retval > 0) { - if (retval < PAGE_SIZE) { - *buf = (char *)page; - return retval; + 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; + } } - retval = -ENAMETOOLONG; - } else if (!retval) - retval = -EINVAL; - - free_page(page); - return retval; -} - -static inline void -put_mod_name(char *buf) -{ - free_page((unsigned long)buf); + } } -/* - * Allocate space for a module. - */ +/* This exists whether we can unload or not */ +static void free_module(struct module *mod); -asmlinkage unsigned long -sys_create_module(const char *name_user, size_t size) +asmlinkage long +sys_delete_module(const char *name_user, unsigned int flags) { - char *name; - long namelen, error; struct module *mod; - unsigned long flags; + char name[MODULE_NAME_LEN]; + int ret; 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); - - put_mod_name(name); - spin_lock_irqsave(&modlist_lock, flags); - mod->next = module_list; - module_list = mod; /* link it in */ - spin_unlock_irqrestore(&modlist_lock, flags); - - error = (long) mod; - goto err0; -err1: - put_mod_name(name); -err0: - unlock_kernel(); - return error; -} - -/* - * Initialize a module. - */ - -asmlinkage long -sys_init_module(const char *name_user, struct module *mod_user) -{ - 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 (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) + return -EFAULT; + name[MODULE_NAME_LEN-1] = '\0'; - 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; - } + if (down_interruptible(&module_mutex)) + return -EINTR; - /* 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; + mod = find_module(name); + if (!mod) { + ret = -ENOENT; + goto out; } - - /* 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; + if (!mod->exit || mod->unsafe_to_unload) { + /* This module can't be removed */ + ret = -EBUSY; + goto out; } - strcpy(name_tmp, mod->name); - - error = copy_from_user(mod, mod_user, mod_user_size); - if (error) { - error = -EFAULT; - goto err2; + if (!list_empty(&mod->modules_which_use_me)) { + /* Other modules depend on us: get rid of them first. */ + ret = -EWOULDBLOCK; + goto out; } - /* Sanity check the size of the module. */ - error = -EINVAL; + /* Remove symbols so module count can't increase from symbol_get() */ + spin_lock_irq(&modlist_lock); + list_del_init(&mod->symbols.list); + spin_unlock_irq(&modlist_lock); - if (mod->size > mod_tmp.size) { - printk(KERN_ERR "init_module: Size of initialized module " - "exceeds size of created module.\n"); - goto err2; - } + /* Mark it as non-live. */ + mod->live = 0; + DEBUGP("Module %s is now dying (%u)\n", + mod->name, bigref_approx_val(&mod->use)); + module_put(mod); - /* Make sure all interesting pointers are sane. */ + /* Wait for everyone to know that it's not live, so module + count can't increase. */ + synchronize_kernel(); - 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(mod->init, 0, mod)) { - printk(KERN_ERR "init_module: mod->init out of bounds.\n"); - goto err2; - } - if (mod->cleanup && !mod_bound(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(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; + /* If they don't want to wait, and refcount non-zero, bring it + back to life and report that we lost. */ + if (((flags & O_NONBLOCK) && bigref_approx_val(&mod->use) != 0) + || mod->unsafe_to_unload) { + mod->live = 1; + try_module_get(mod); /* Can't fail */ + spin_lock_irq(&modlist_lock); + list_add(&mod->symbols.list, &kernel_symbols.list); + spin_unlock_irq(&modlist_lock); + ret = -EWOULDBLOCK; + goto out; } - /* Check that the user isn't doing something silly with the name. */ + /* Since it's not live, this should monotonically decrease. */ + bigref_wait_for_zero(&mod->use); - 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; - } + /* Final destruction now noone is using it. */ + mod->exit(); + free_module(mod); + ret = 0; - /* Ok, that's about all the sanity we can stomach; copy the rest. */ + out: + up(&module_mutex); + return ret; +} - if (copy_from_user((char *)mod+mod_user_size, - (char *)mod_user+mod_user_size, - mod->size-mod_user_size)) { - error = -EFAULT; - goto err3; - } +static void print_unload_info(struct seq_file *m, struct module *mod) +{ + struct module_use *use; - if (module_arch_init(mod)) - goto err3; + /* -1 because we hold a refcount until rmmod. */ + seq_printf(m, " %u", bigref_approx_val(&mod->use) - 1); - /* 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); + list_for_each_entry(use, &mod->modules_which_use_me, list) + seq_printf(m, " %s", use->module_which_uses->name); - mod->next = mod_tmp.next; - mod->refs = NULL; + if (mod->unsafe_to_unload) + seq_printf(m, " [unsafe]"); - /* Sanity check the module's dependents */ - for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) { - struct module *o, *d = dep->dep; + if (!mod->exit) + seq_printf(m, " [permanent]"); - /* 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; - } + seq_printf(m, "\n"); +} - /* Scan the current modules for this dependency */ - for (o = module_list; o != &kernel_module && o != d; o = o->next) - ; +int __try_module_get(struct module *module) +{ + int ret = 1; - if (o != d) { - printk(KERN_ERR "init_module: found dependency that is " - "(no longer?) a module.\n"); - goto err3; - } - } + preempt_disable(); + if (likely(module->live)) + bigref_inc(&module->use); + else + ret = 0; + preempt_enable(); - /* Update module references. */ - for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) { - struct module *d = dep->dep; + return ret; +} +EXPORT_SYMBOL(__try_module_get); - 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; - } +void __symbol_put(const char *symbol) +{ + struct kernel_symbol_group *ksg; + unsigned long flags; - /* Free our temporary memory. */ - put_mod_name(n_name); - put_mod_name(name); + spin_lock_irqsave(&modlist_lock, flags); + if (!__find_symbol(symbol, &ksg)) + BUG(); + module_put(ksg->owner); + spin_unlock_irqrestore(&modlist_lock, flags); +} +EXPORT_SYMBOL(__symbol_put); - /* 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); +int __module_put(struct module *module) +{ + return bigref_dec(&module->use); +} +EXPORT_SYMBOL(__module_put); +#else /* !CONFIG_MODULE_UNLOAD */ +static void print_unload_info(struct seq_file *m, struct module *mod) +{ + seq_printf(m, "\n"); +} - /* And set it running. */ - mod->flags = (mod->flags | MOD_RUNNING) & ~MOD_INITIALIZING; - error = 0; - goto err0; +static inline void module_unload_free(struct module *mod) +{ +} -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 inline int use_module(struct module *a, struct module *b) +{ + return 1; } -static spinlock_t unload_lock = SPIN_LOCK_UNLOCKED; -int try_inc_mod_count(struct module *mod) +static inline void module_unload_init(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; } asmlinkage long -sys_delete_module(const char *name_user) +sys_delete_module(const char *name_user, unsigned int flags) { - struct module *mod, *next; - char *name; - long error; - int something_changed; - - if (!capable(CAP_SYS_MODULE)) - return -EPERM; + return -ENOSYS; +} +#endif /* CONFIG_MODULE_UNLOAD */ - 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; - } - put_mod_name(name); - error = -EBUSY; - if (mod->refs != NULL) - goto out; +/* Find an symbol for this module (ie. resolve internals first). + It we find one, record usage. Must be holding module_mutex. */ +unsigned long find_symbol_internal(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(&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); - } - goto out; + ret = find_local_symbol(sechdrs, symindex, strtab, name); + if (ret) { + *ksg = NULL; + return ret; } - - /* 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); - } + /* Look in other modules... */ + spin_lock_irq(&modlist_lock); + ret = __find_symbol(name, ksg); + if (ret) { + /* This can fail due to OOM, or module unloading */ + if (!use_module(mod, (*ksg)->owner)) + ret = 0; } - - 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; + spin_unlock_irq(&modlist_lock); + return ret; } -/* Query various bits about modules. */ - -static int -qm_modules(char *buf, size_t bufsize, size_t *ret) +/* Free a module, remove from lists, etc (must hold module mutex). */ +static void free_module(struct module *mod) { - struct module *mod; - size_t nmod, space, len; - - 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; - } + /* Delete from various lists */ + list_del(&mod->list); + spin_lock_irq(&modlist_lock); + list_del(&mod->symbols.list); + list_del(&mod->extable.list); + spin_unlock_irq(&modlist_lock); - if (put_user(nmod, ret)) - return -EFAULT; - else - return 0; + /* These may be NULL, but that's OK */ + module_free(mod, mod->module_init); + module_free(mod, mod->module_core); -calc_space_needed: - space += len; - while ((mod = mod->next) != &kernel_module) - space += strlen(mod->name)+1; + /* Module unload stuff */ + module_unload_free(mod); - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; + /* Finally, free the module structure */ + kfree(mod); } -static int -qm_deps(struct module *mod, char *buf, size_t bufsize, size_t *ret) +void *__symbol_get(const char *symbol) { - size_t i, space, len; + struct kernel_symbol_group *ksg; + unsigned long value, flags; - if (mod == &kernel_module) - return -EINVAL; - if (!MOD_CAN_QUERY(mod)) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; + spin_lock_irqsave(&modlist_lock, flags); + value = __find_symbol(symbol, &ksg); + if (value && !try_module_get(ksg->owner)) + value = 0; + spin_unlock_irqrestore(&modlist_lock, flags); - space = 0; - for (i = 0; i < mod->ndeps; ++i) { - const char *dep_name = mod->deps[i].dep->name; + return (void *)value; +} +EXPORT_SYMBOL(__symbol_get); - 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; +/* Transfer one ELF section to the correct (init or core) area. */ +static void *copy_section(const char *name, + void *base, + Elf_Shdr *sechdr, + struct module *mod, + struct sizes *used) +{ + void *dest; + unsigned long *use; + + /* Only copy to init section if there is one */ + if (strstr(name, ".init") && mod->module_init) { + dest = mod->module_init; + use = &used->init_size; + } else { + dest = mod->module_core; + use = &used->core_size; } - if (put_user(i, ret)) - return -EFAULT; - else - return 0; + /* Align up */ + *use = ALIGN(*use, sechdr->sh_addralign); + dest += *use; + *use += sechdr->sh_size; -calc_space_needed: - space += len; - while (++i < mod->ndeps) - space += strlen(mod->deps[i].dep->name)+1; + /* May not actually be in the file (eg. bss). */ + if (sechdr->sh_type != SHT_NOBITS) + memcpy(dest, base + sechdr->sh_offset, sechdr->sh_size); - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; + return dest; } -static int -qm_refs(struct module *mod, char *buf, size_t bufsize, size_t *ret) +/* Look for the special symbols */ +static int grab_private_symbols(Elf_Shdr *sechdrs, + unsigned int symbolsec, + const char *strtab, + struct module *mod) { - size_t nrefs, space, len; - struct module_ref *ref; - - if (mod == &kernel_module) - return -EINVAL; - if (!MOD_CAN_QUERY(mod)) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = 0; - for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) { - const char *ref_name = ref->ref->name; + Elf_Sym *sym = (void *)sechdrs[symbolsec].sh_offset; + unsigned int i; - 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; + for (i = 1; i < sechdrs[symbolsec].sh_size/sizeof(*sym); i++) { + if (strcmp("__initfn", strtab + sym[i].st_name) == 0) + mod->init = (void *)sym[i].st_value; +#ifdef CONFIG_MODULE_UNLOAD + if (strcmp("__exitfn", strtab + sym[i].st_name) == 0) + mod->exit = (void *)sym[i].st_value; +#endif } - if (put_user(nrefs, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while ((ref = ref->next_ref) != NULL) - space += strlen(ref->ref->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; + return 0; } -static int -qm_symbols(struct module *mod, char *buf, size_t bufsize, size_t *ret) +/* 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) { - size_t i, space, len; - struct module_symbol *s; - char *strings; - unsigned long *vals; + int ret; + const char *strtab = (char *)sechdrs[strindex].sh_offset; - if (!MOD_CAN_QUERY(mod)) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; + 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; + case SHT_SYMTAB: + ret = grab_private_symbols(sechdrs, i, strtab, 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; +} - space = mod->nsyms * 2*sizeof(void *); +/* Figure out total size desired for the common vars */ +static unsigned long read_commons(void *start, Elf_Shdr *sechdr) +{ + unsigned long size, i, max_align; + Elf_Sym *sym; + + size = max_align = 0; - i = len = 0; - s = mod->syms; + for (sym = start + sechdr->sh_offset, i = 0; + i < sechdr->sh_size / sizeof(Elf_Sym); + i++) { + if (sym[i].st_shndx == SHN_COMMON) { + /* Value encodes alignment. */ + if (sym[i].st_value > max_align) + max_align = sym[i].st_value; + /* Pad to required alignment */ + size = ALIGN(size, sym[i].st_value) + sym[i].st_size; + } + } - if (space > bufsize) - goto calc_space_needed; + /* Now, add in max alignment requirement (with align + attribute, this could be large), so we know we have space + whatever the start alignment is */ + return size + max_align; +} - if (!access_ok(VERIFY_WRITE, buf, space)) - return -EFAULT; +/* Change all symbols so that sh_value encodes the pointer directly. */ +static void simplify_symbols(Elf_Shdr *sechdrs, + unsigned int symindex, + unsigned int strindex, + void *common, + struct module *mod) +{ + unsigned int i; + Elf_Sym *sym; - bufsize -= space; - vals = (unsigned long *)buf; - strings = buf+space; + /* First simplify defined symbols, so if they become the + "answer" to undefined symbols, copying their st_value us + correct. */ + for (sym = (void *)sechdrs[symindex].sh_offset, i = 0; + i < sechdrs[symindex].sh_size / sizeof(Elf_Sym); + i++) { + switch (sym[i].st_shndx) { + case SHN_COMMON: + /* Value encodes alignment. */ + common = (void *)ALIGN((unsigned long)common, + sym[i].st_value); + /* Change it to encode pointer */ + sym[i].st_value = (unsigned long)common; + common += sym[i].st_size; + break; - for (; i < mod->nsyms ; ++i, ++s, vals += 2) { - len = strlen(s->name)+1; - if (len > bufsize) - goto calc_space_needed; + 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(strings, s->name, len) - || __put_user(s->value, vals+0) - || __put_user(space, vals+1)) - return -EFAULT; + case SHN_UNDEF: + break; - strings += len; - bufsize -= len; - space += len; + default: + sym[i].st_value + = (unsigned long) + (sechdrs[sym[i].st_shndx].sh_offset + + sym[i].st_value); + } } - if (put_user(i, ret)) - return -EFAULT; - else - return 0; -calc_space_needed: - for (; i < mod->nsyms; ++i, ++s) - space += strlen(s->name)+1; + /* Now try to resolve undefined symbols */ + for (sym = (void *)sechdrs[symindex].sh_offset, i = 0; + i < sechdrs[symindex].sh_size / sizeof(Elf_Sym); + i++) { + if (sym[i].st_shndx == SHN_UNDEF) { + /* Look for symbol */ + struct kernel_symbol_group *ksg = NULL; + const char *strtab + = (char *)sechdrs[strindex].sh_offset; - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; + sym[i].st_value + = find_symbol_internal(sechdrs, + symindex, + strtab, + strtab + sym[i].st_name, + mod, + &ksg); + /* We fake up "__this_module" */ + if (strcmp(strtab+sym[i].st_name, "__this_module")==0) + sym[i].st_value = (unsigned long)mod; + } + } } -static int -qm_info(struct module *mod, char *buf, size_t bufsize, size_t *ret) +/* Get the total allocation size of the init and non-init sections */ +static struct sizes get_sizes(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings) { - int error = 0; - - if (mod == &kernel_module) - return -EINVAL; + struct sizes ret = { 0, 0 }; + unsigned i; - 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); + /* Everything marked ALLOC (this includes the exported + symbols) */ + for (i = 1; i < hdr->e_shnum; i++) { + unsigned long *add; - if (copy_to_user(buf, &info, sizeof(struct module_info))) - return -EFAULT; - } else - error = -ENOSPC; + /* If it's called *.init*, and we're init, we're interested */ + if (strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) + add = &ret.init_size; + else + add = &ret.core_size; - if (put_user(sizeof(struct module_info), ret)) - return -EFAULT; + if (sechdrs[i].sh_flags & SHF_ALLOC) { + /* Pad up to required alignment */ + *add = ALIGN(*add, sechdrs[i].sh_addralign ?: 1); + *add += sechdrs[i].sh_size; + } + } - return error; + return ret; } -asmlinkage long -sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, - size_t *ret) +/* Allocate and load the module */ +static struct module *load_module(void *umod, + unsigned long len, + const char *uargs) { + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + char *secstrings; + unsigned int i, symindex, exportindex, strindex, setupindex, exindex, + modnameindex; + long arglen; + unsigned long common_length; + struct sizes sizes, used; struct module *mod; - int err; + int err = 0; + void *ptr = NULL; /* Stops spurious gcc uninitialized warning */ - lock_kernel(); - if (name_user == NULL) - mod = &kernel_module; - else { - long namelen; - char *name; + DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", + umod, len, uargs); + if (len < sizeof(*hdr)) + return ERR_PTR(-ENOEXEC); - 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; - } - put_mod_name(name); + /* 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; } - /* __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; + /* 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; } - atomic_dec(&mod->uc.usecount); - -out: - unlock_kernel(); - return err; -} -/* - * 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. - */ + /* Convenience variables */ + sechdrs = (void *)hdr + hdr->e_shoff; + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; -asmlinkage long -sys_get_kernel_syms(struct kernel_sym *table) -{ - struct module *mod; - int i; - struct kernel_sym ksym; + /* May not export symbols, or have setup params, so these may + not exist */ + exportindex = setupindex = 0; - lock_kernel(); - for (mod = module_list, i = 0; mod; mod = mod->next) { - /* include the count for the module name! */ - i += mod->nsyms + 1; + /* And these should exist, but gcc whinges if we don't init them */ + symindex = strindex = exindex = modnameindex = 0; + + /* Find where important sections are */ + for (i = 1; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_type == SHT_SYMTAB) { + /* Internal symbols */ + DEBUGP("Symbol table in section %u\n", i); + symindex = i; + } else if (strcmp(secstrings+sechdrs[i].sh_name, ".modulename") + == 0) { + /* This module's name */ + DEBUGP("Module name in section %u\n", i); + modnameindex = 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, ".strtab") + == 0) { + /* Strings */ + DEBUGP("String table found in section %u\n", i); + strindex = i; + } else if (strcmp(secstrings+sechdrs[i].sh_name, ".setup.init") + == 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; + } +#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 (table == NULL) - goto out; + if (!modnameindex) { + DEBUGP("Module has no name!\n"); + err = -ENOEXEC; + goto free_hdr; + } - /* So that we don't give the user our stack content */ - memset (&ksym, 0, sizeof (ksym)); + /* Now allocate space for the module proper, and copy name and args. */ + err = strlen_user(uargs); + if (err < 0) + goto free_hdr; + arglen = err; - for (mod = module_list, i = 0; mod; mod = mod->next) { - struct module_symbol *msym; - unsigned int j; + mod = kmalloc(sizeof(*mod) + arglen+1, GFP_KERNEL); + if (!mod) { + err = -ENOMEM; + goto free_hdr; + } + memset(mod, 0, sizeof(*mod) + arglen+1); + if (copy_from_user(mod->args, uargs, arglen) != 0) { + err = -EFAULT; + goto free_mod; + } + strncpy(mod->name, (char *)hdr + sechdrs[modnameindex].sh_offset, + sizeof(mod->name)-1); - if (!MOD_CAN_QUERY(mod)) - continue; + if (find_module(mod->name)) { + err = -EEXIST; + goto free_mod; + } - /* 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'; + /* Initialize the lists, since they will be list_del'd if init fails */ + INIT_LIST_HEAD(&mod->extable.list); + INIT_LIST_HEAD(&mod->list); + INIT_LIST_HEAD(&mod->symbols.list); + mod->symbols.owner = mod; + module_unload_init(mod); - if (copy_to_user(table, &ksym, sizeof(ksym)) != 0) - goto out; - ++i, ++table; + /* How much space will we need? (Common area in core) */ + sizes = get_sizes(hdr, sechdrs, secstrings); + common_length = read_commons(hdr, &sechdrs[symindex]); + sizes.core_size += common_length; - if (mod->nsyms == 0) - continue; + /* Set these up: arch's can add to them */ + mod->core_size = sizes.core_size; + mod->init_size = sizes.init_size; - 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'; + /* Allocate (this is arch specific) */ + ptr = module_core_alloc(hdr, sechdrs, secstrings, mod); + if (IS_ERR(ptr)) + goto free_mod; - if (copy_to_user(table, &ksym, sizeof(ksym)) != 0) - goto out; - ++i, ++table; + mod->module_core = ptr; + + ptr = module_init_alloc(hdr, sechdrs, secstrings, mod); + if (IS_ERR(ptr)) + goto free_core; + mod->module_init = ptr; + + /* Transfer each section which requires ALLOC, and set sh_offset + fields to absolute addresses. */ + used.core_size = common_length; + used.init_size = 0; + for (i = 1; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_flags & SHF_ALLOC) { + ptr = copy_section(secstrings + sechdrs[i].sh_name, + hdr, &sechdrs[i], mod, &used); + if (IS_ERR(ptr)) + goto cleanup; + sechdrs[i].sh_offset = (unsigned long)ptr; + } else { + sechdrs[i].sh_offset += (unsigned long)hdr; } } -out: - unlock_kernel(); - return i; -} + /* Don't use more than we allocated! */ + if (used.init_size > mod->init_size || used.core_size > mod->core_size) + BUG(); -/* - * Look for a module by name, ignoring modules marked for deletion. - */ + /* Fix up syms, so that st_value is a pointer to location. */ + simplify_symbols(sechdrs, symindex, strindex, mod->module_core, mod); -struct module * -find_module(const char *name) -{ - struct module *mod; + /* Set up EXPORTed symbols */ + if (exportindex) { + mod->symbols.num_syms = (sechdrs[exportindex].sh_size + / sizeof(*mod->symbols.syms)); + mod->symbols.syms = (void *)sechdrs[exportindex].sh_offset; + } - for (mod = module_list; mod ; mod = mod->next) { - if (mod->flags & MOD_DELETED) - continue; - if (!strcmp(mod->name, name)) - break; + /* 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_offset; } + /* 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; + } + + /* A useful module could simply export symbols, but they must + put a dummy function in, because otherwise this can be a + very confusing silent failure */ + if (!mod->init) { + printk("%s: No init function.\n", mod->name); + err = -ENOEXEC; + goto cleanup; + } + + err = module_finalize(hdr, sechdrs, mod); + if (err < 0) + goto cleanup; + +#if 0 /* Needs param support */ + /* Size of section 0 is 0, so this works well */ + err = parse_args(mod->args, + (struct kernel_param *) + sechdrs[setupindex].sh_offset, + sechdrs[setupindex].sh_size + / sizeof(struct kernel_param), + NULL); + if (err < 0) + goto cleanup; +#endif + + /* Get rid of temporary copy */ + vfree(hdr); + + /* Done! */ return mod; -} -/* - * Free the given module. - */ + cleanup: + module_unload_free(mod); + module_free(mod, mod->module_init); + free_core: + module_free(mod, mod->module_core); + free_mod: + kfree(mod); + free_hdr: + vfree(hdr); + if (err < 0) return ERR_PTR(err); + else return ptr; +} -void -free_module(struct module *mod, int tag_freed) +/* This is where the real work happens */ +asmlinkage long +sys_init_module(void *umod, + unsigned long len, + const char *uargs) { - struct module_ref *dep; - unsigned i; - unsigned long flags; - - /* Let the module clean up. */ + struct module *mod; + int ret; - if (mod->flags & MOD_RUNNING) - { - if(mod->cleanup) - mod->cleanup(); - mod->flags &= ~MOD_RUNNING; - } + /* Must have permission */ + if (!capable(CAP_SYS_MODULE)) + return -EPERM; - /* Remove the module from the dependency lists. */ + /* Only one module load at a time, please */ + if (down_interruptible(&module_mutex) != 0) + return -EINTR; - 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; + /* Do all the hard work */ + mod = load_module(umod, len, uargs); + if (IS_ERR(mod)) { + up(&module_mutex); + return PTR_ERR(mod); } - /* And from the main module list. */ + /* 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); - spin_lock_irqsave(&modlist_lock, flags); - if (mod == module_list) { - module_list = mod->next; - } else { - struct module *p; - for (p = module_list; p->next != mod; p = p->next) - continue; - p->next = mod->next; + /* Now sew it into exception list (just in case...). */ + spin_lock_irq(&modlist_lock); + list_add(&mod->extable.list, &extables); + spin_unlock_irq(&modlist_lock); + + /* Start the module */ + ret = mod->init(); + if (ret < 0) { + /* Init routine failed: abort */ + /* Try to protect us from buggy refcounters. */ + synchronize_kernel(); + if (mod->unsafe_to_unload) + printk(KERN_ERR "%s: module is now stuck!\n", + mod->name); + else + free_module(mod); + up(&module_mutex); + return ret; } - spin_unlock_irqrestore(&modlist_lock, flags); - /* And free the memory. */ + /* Now it's a first class citizen! */ + spin_lock_irq(&modlist_lock); + list_add(&mod->symbols.list, &kernel_symbols.list); + spin_unlock_irq(&modlist_lock); + list_add(&mod->list, &modules); - module_unmap(mod); + module_free(mod, mod->module_init); + mod->module_init = NULL; + + /* All ok! */ + mod->live = 1; + up(&module_mutex); + return 0; } -/* - * Called by the /proc file system to return a current list of modules. - */ +/* Called by the /proc file system to return a current list of + modules. Al Viro came up with this interface as an "improvement". + God save us from any more such interface improvements. */ static void *m_start(struct seq_file *m, loff_t *pos) { - struct module *v; - loff_t n = *pos; - lock_kernel(); - for (v = module_list; v && n--; v = v->next) - ; - return v; + struct list_head *i; + loff_t n = 0; + + down(&module_mutex); + list_for_each(i, &modules) { + if (n++ == *pos) + break; + } + if (i == &modules) + return NULL; + return i; } + static void *m_next(struct seq_file *m, void *p, loff_t *pos) { - struct module *v = p; + struct list_head *i = p; (*pos)++; - return v->next; + if (i->next == &modules) + return NULL; + return i->next; } + static void m_stop(struct seq_file *m, void *p) { - unlock_kernel(); + up(&module_mutex); } + static int m_show(struct seq_file *m, void *p) { - struct module *mod = p; - struct module_ref *ref = mod->refs; - - if (mod == &kernel_module) - return 0; - - 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, ']'); - } - seq_putc(m, '\n'); + 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); return 0; } struct seq_operations modules_op = { @@ -1138,131 +968,22 @@ struct seq_operations modules_op = { .show = m_show }; -/* - * Called by the /proc file system to return a current list of ksyms. - */ - -struct mod_sym { - struct module *mod; - int index; -}; - -/* iterator */ - -static void *s_start(struct seq_file *m, loff_t *pos) -{ - struct mod_sym *p = kmalloc(sizeof(*p), GFP_KERNEL); - struct module *v; - loff_t n = *pos; - - if (!p) - return ERR_PTR(-ENOMEM); - lock_kernel(); - for (v = module_list, n = *pos; v; n -= v->nsyms, v = v->next) { - if (n < v->nsyms) { - p->mod = v; - p->index = n; - return p; - } - } - unlock_kernel(); - kfree(p); - return NULL; -} - -static void *s_next(struct seq_file *m, void *p, loff_t *pos) -{ - struct mod_sym *v = p; - (*pos)++; - 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 s_stop(struct seq_file *m, void *p) -{ - if (p && !IS_ERR(p)) { - unlock_kernel(); - kfree(p); - } -} - -static int s_show(struct seq_file *m, void *p) +static int __init init(void) { - struct mod_sym *v = p; - struct module_symbol *sym; + /* Add kernel symbols to symbol table */ + kernel_symbols.num_syms = (__stop___ksymtab - __start___ksymtab); + kernel_symbols.syms = __start___ksymtab; + list_add(&kernel_symbols.list, &symbols); - 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); + /* Add kernel exception table to exception tables */ + kernel_extable.num_entries = (__stop___ex_table -__start___ex_table); + kernel_extable.entry = __start___ex_table; + list_add(&kernel_extable.list, &extables); return 0; } -struct seq_operations ksyms_op = { - .start = s_start, - .next = s_next, - .stop = s_stop, - .show = s_show -}; - -#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; -} +/* Obsolete lvalue for broken code which asks about usage */ +int module_dummy_usage = 1; -#endif /* CONFIG_MODULES */ +/* Call this at boot */ +__initcall(init); diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/kernel/sys.c .13485-linux-2.5.38.updated/kernel/sys.c --- .13485-linux-2.5.38/kernel/sys.c 2002-09-23 08:54:54.000000000 +1000 +++ .13485-linux-2.5.38.updated/kernel/sys.c 2002-09-25 10:31:42.000000000 +1000 @@ -202,6 +202,8 @@ asmlinkage long sys_ni_syscall(void) cond_syscall(sys_nfsservctl) cond_syscall(sys_quotactl) cond_syscall(sys_acct) +cond_syscall(sys_init_module) +cond_syscall(sys_delete_module) static int set_one_prio(struct task_struct *p, int niceval, int error) { diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/net/ipv4/netfilter/ip_nat_helper.c .13485-linux-2.5.38.updated/net/ipv4/netfilter/ip_nat_helper.c --- .13485-linux-2.5.38/net/ipv4/netfilter/ip_nat_helper.c 2002-09-18 16:03:31.000000000 +1000 +++ .13485-linux-2.5.38.updated/net/ipv4/netfilter/ip_nat_helper.c 2002-09-25 10:31:42.000000000 +1000 @@ -374,7 +374,7 @@ int ip_nat_helper_register(struct ip_nat && ct_helper->me) { __MOD_INC_USE_COUNT(ct_helper->me); } else { - +#ifdef CONFIG_MODULES /* We are a NAT helper for protocol X. If we need * respective conntrack helper for protoccol X, compute * conntrack helper name and try to load module */ @@ -404,6 +404,7 @@ int ip_nat_helper_register(struct ip_nat "module loader support\n", name); return -EBUSY; #endif +#endif } } WRITE_LOCK(&ip_nat_lock); @@ -466,9 +467,12 @@ void ip_nat_helper_unregister(struct ip_ if ((ct_helper = ip_ct_find_helper(&me->tuple)) && ct_helper->me) { __MOD_DEC_USE_COUNT(ct_helper->me); - } else + } +#ifdef CONFIG_MODULES + else printk("%s: unable to decrement usage count" " of conntrack helper %s\n", __FUNCTION__, me->me->name); +#endif } } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13485-linux-2.5.38/net/ipv6/af_inet6.c .13485-linux-2.5.38.updated/net/ipv6/af_inet6.c --- .13485-linux-2.5.38/net/ipv6/af_inet6.c 2002-09-18 16:03:31.000000000 +1000 +++ .13485-linux-2.5.38.updated/net/ipv6/af_inet6.c 2002-09-25 10:31:42.000000000 +1000 @@ -548,6 +548,7 @@ struct net_proto_family inet6_family_ops }; #ifdef MODULE +#if 0 /* FIXME --RR */ int ipv6_unload(void) { if (!unloadable) return 1; @@ -555,6 +556,8 @@ int ipv6_unload(void) return atomic_read(&(__this_module.uc.usecount)) - 3; } #endif +#endif +#endif #if defined(MODULE) && defined(CONFIG_SYSCTL) extern void ipv6_sysctl_register(void); @@ -634,11 +637,13 @@ static int __init inet6_init(void) int err; #ifdef MODULE +#if 0 /* FIXME --RR */ if (!mod_member_present(&__this_module, can_unload)) return -EINVAL; __this_module.can_unload = &ipv6_unload; #endif +#endif printk(KERN_INFO "IPv6 v0.8 for NET4.0\n");