Commit aa65be3f authored by Rusty Russell's avatar Rusty Russell Committed by Andy Grover

[PATCH] In-kernel Module Loader

This is an implementation of the in-kernel module loader extending
the try_inc_mod_count() primitive and making its use compulsory.
This has the benifit of simplicity, and similarity to the existing
scheme.  To reduce the cost of the constant increments and
decrements, reference counters are lockless and per-cpu.

Eliminated (coming in following patches):
 o Modversions
 o Module parameters
 o kallsyms
 o EXPORT_SYMBOL_GPL and MODULE_LICENCE checks
 o DEVICE_TABLE support.

New features:
 o Typesafe symbol_get/symbol_put
 o Single "insert this module" syscall interface allows trivial userspace.
 o Raceless loading and unloading

You will need the trivial replacement module utilities from:
	http://ozlabs.org/~rusty/module-init-tools-0.6.tar.gz
parent 850b830c
...@@ -157,7 +157,6 @@ OBJCOPY = $(CROSS_COMPILE)objcopy ...@@ -157,7 +157,6 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump OBJDUMP = $(CROSS_COMPILE)objdump
AWK = awk AWK = awk
GENKSYMS = /sbin/genksyms GENKSYMS = /sbin/genksyms
DEPMOD = /sbin/depmod
KALLSYMS = /sbin/kallsyms KALLSYMS = /sbin/kallsyms
PERL = perl PERL = perl
MODFLAGS = -DMODULE MODFLAGS = -DMODULE
...@@ -516,7 +515,7 @@ modules: $(SUBDIRS) ...@@ -516,7 +515,7 @@ modules: $(SUBDIRS)
# Install modules # Install modules
.PHONY: modules_install .PHONY: modules_install
modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) _modinst_post modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS))
.PHONY: _modinst_ .PHONY: _modinst_
_modinst_: _modinst_:
...@@ -525,20 +524,6 @@ _modinst_: ...@@ -525,20 +524,6 @@ _modinst_:
@mkdir -p $(MODLIB)/kernel @mkdir -p $(MODLIB)/kernel
@ln -s $(TOPDIR) $(MODLIB)/build @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)) .PHONY: $(patsubst %, _modinst_%, $(SUBDIRS))
$(patsubst %, _modinst_%, $(SUBDIRS)) : $(patsubst %, _modinst_%, $(SUBDIRS)) :
$(Q)$(MAKE) -f scripts/Makefile.modinst obj=$(patsubst _modinst_%,%,$@) $(Q)$(MAKE) -f scripts/Makefile.modinst obj=$(patsubst _modinst_%,%,$@)
......
...@@ -1604,13 +1604,14 @@ config DEBUG_HIGHMEM ...@@ -1604,13 +1604,14 @@ config DEBUG_HIGHMEM
This options enables addition error checking for high memory systems. This options enables addition error checking for high memory systems.
Disable for production systems. Disable for production systems.
config KALLSYMS # Reimplemented RSN.
bool "Load all symbols for debugging/kksymoops" #config KALLSYMS
depends on DEBUG_KERNEL # bool "Load all symbols for debugging/kksymoops"
help # depends on DEBUG_KERNEL
Say Y here to let the kernel print out symbolic crash information and # help
symbolic stack backtraces. This increases the size of the kernel # Say Y here to let the kernel print out symbolic crash information and
somewhat, as all symbols have to be loaded into the kernel image. # symbolic stack backtraces. This increases the size of the kernel
# somewhat, as all symbols have to be loaded into the kernel image.
config X86_EXTRA_IRQS config X86_EXTRA_IRQS
bool bool
......
...@@ -813,13 +813,13 @@ config DEBUG_KERNEL ...@@ -813,13 +813,13 @@ config DEBUG_KERNEL
Say Y here if you are developing drivers or trying to debug and Say Y here if you are developing drivers or trying to debug and
identify kernel problems. identify kernel problems.
config KALLSYMS # config KALLSYMS
bool "Load all symbols for debugging/kksymoops" # bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL # depends on DEBUG_KERNEL
help # help
Say Y here to let the kernel print out symbolic crash information and # Say Y here to let the kernel print out symbolic crash information and
symbolic stack backtraces. This increases the size of the kernel # symbolic stack backtraces. This increases the size of the kernel
somewhat, as all symbols have to be loaded into the kernel image. # somewhat, as all symbols have to be loaded into the kernel image.
config IA64_PRINT_HAZARDS config IA64_PRINT_HAZARDS
bool "Print possible IA-64 dependency violations to console" bool "Print possible IA-64 dependency violations to console"
......
...@@ -1807,9 +1807,9 @@ config DEBUG_HIGHMEM ...@@ -1807,9 +1807,9 @@ config DEBUG_HIGHMEM
bool "Highmem debugging" bool "Highmem debugging"
depends on DEBUG_KERNEL && HIGHMEM depends on DEBUG_KERNEL && HIGHMEM
config KALLSYMS # config KALLSYMS
bool "Load all symbols for debugging/kksymoops" # bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL # depends on DEBUG_KERNEL
config KGDB config KGDB
bool "Include kgdb kernel debugger" bool "Include kgdb kernel debugger"
......
...@@ -739,13 +739,13 @@ config INIT_DEBUG ...@@ -739,13 +739,13 @@ config INIT_DEBUG
help help
Fill __init and __initdata at the end of boot. This is only for debugging. Fill __init and __initdata at the end of boot. This is only for debugging.
config KALLSYMS # config KALLSYMS
bool "Load all symbols for debugging/kksymoops" # bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL # depends on DEBUG_KERNEL
help # help
Say Y here to let the kernel print out symbolic crash information and # Say Y here to let the kernel print out symbolic crash information and
symbolic stack backtraces. This increases the size of the kernel # symbolic stack backtraces. This increases the size of the kernel
somewhat, as all symbols have to be loaded into the kernel image. # somewhat, as all symbols have to be loaded into the kernel image.
endmenu endmenu
......
...@@ -151,6 +151,7 @@ static int print_unex=1; ...@@ -151,6 +151,7 @@ static int print_unex=1;
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/version.h>
#define FDPATCHES #define FDPATCHES
#include <linux/fdreg.h> #include <linux/fdreg.h>
......
...@@ -1266,13 +1266,6 @@ MODULE_DESCRIPTION( ...@@ -1266,13 +1266,6 @@ MODULE_DESCRIPTION(
"Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams");
MODULE_LICENSE("GPL"); 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 /* Called by modules package when installing the driver
*/ */
int init_module(void) int init_module(void)
...@@ -1282,9 +1275,11 @@ int init_module(void) ...@@ -1282,9 +1275,11 @@ int init_module(void)
#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) #if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
register_symtab(0); /* remove global ftape symbols */ register_symtab(0); /* remove global ftape symbols */
#else #else
#if 0 /* FIXME --RR */
if (!mod_member_present(&__this_module, can_unload)) if (!mod_member_present(&__this_module, can_unload))
return -EBUSY; return -EBUSY;
__this_module.can_unload = can_unload; __this_module.can_unload = can_unload;
#endif
#endif #endif
result = zft_compressor_init(); result = zft_compressor_init();
keep_module_locked = 0; keep_module_locked = 0;
......
...@@ -31,14 +31,22 @@ static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED; ...@@ -31,14 +31,22 @@ static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
/* WARNING: This can be used only if we _already_ own a reference */ /* WARNING: This can be used only if we _already_ own a reference */
void get_filesystem(struct file_system_type *fs) void get_filesystem(struct file_system_type *fs)
{ {
if (fs->owner) if (!try_module_get(fs->owner)) {
__MOD_INC_USE_COUNT(fs->owner); #ifdef CONFIG_MODULE_UNLOAD
unsigned int cpu = get_cpu();
local_inc(&fs->owner->ref[cpu].count);
put_cpu();
#else
/* Getting filesystem while it's starting up? We're
already supposed to have a reference. */
BUG();
#endif
}
} }
void put_filesystem(struct file_system_type *fs) void put_filesystem(struct file_system_type *fs)
{ {
if (fs->owner) module_put(fs->owner);
__MOD_DEC_USE_COUNT(fs->owner);
} }
static struct file_system_type **find_filesystem(const char *name) static struct file_system_type **find_filesystem(const char *name)
......
...@@ -296,17 +296,6 @@ static struct file_operations proc_modules_operations = { ...@@ -296,17 +296,6 @@ static struct file_operations proc_modules_operations = {
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release, .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 #endif
extern struct seq_operations slabinfo_op; extern struct seq_operations slabinfo_op;
...@@ -604,7 +593,6 @@ void __init proc_misc_init(void) ...@@ -604,7 +593,6 @@ void __init proc_misc_init(void)
create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
create_seq_entry("modules", 0, &proc_modules_operations); create_seq_entry("modules", 0, &proc_modules_operations);
create_seq_entry("ksyms", 0, &proc_ksyms_operations);
#endif #endif
proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL); proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
if (proc_root_kcore) { if (proc_root_kcore) {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/node.h> #include <linux/node.h>
#include <asm/semaphore.h>
struct cpu { struct cpu {
int node_id; /* The node which contains the CPU */ int node_id; /* The node which contains the CPU */
...@@ -29,4 +30,6 @@ struct cpu { ...@@ -29,4 +30,6 @@ struct cpu {
extern int register_cpu(struct cpu *, int, struct node *); extern int register_cpu(struct cpu *, int, struct node *);
/* Stop CPUs going up and down. */
extern struct semaphore cpucontrol;
#endif /* _LINUX_CPU_H_ */ #endif /* _LINUX_CPU_H_ */
...@@ -198,6 +198,9 @@ typedef struct { ...@@ -198,6 +198,9 @@ typedef struct {
#define ELF32_R_SYM(x) ((x) >> 8) #define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff) #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_NONE 0
#define R_386_32 1 #define R_386_32 1
#define R_386_PC32 2 #define R_386_PC32 2
...@@ -295,6 +298,7 @@ typedef struct { ...@@ -295,6 +298,7 @@ typedef struct {
#define R_SPARC_PCPLT10 29 #define R_SPARC_PCPLT10 29
#define R_SPARC_10 30 #define R_SPARC_10 30
#define R_SPARC_11 31 #define R_SPARC_11 31
#define R_SPARC_64 32
#define R_SPARC_WDISP16 40 #define R_SPARC_WDISP16 40
#define R_SPARC_WDISP19 41 #define R_SPARC_WDISP19 41
#define R_SPARC_7 43 #define R_SPARC_7 43
...@@ -369,6 +373,47 @@ typedef struct { ...@@ -369,6 +373,47 @@ typedef struct {
#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ #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. */ /* Legal values for e_flags field of Elf64_Ehdr. */
#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ #define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */
......
...@@ -38,17 +38,30 @@ ...@@ -38,17 +38,30 @@
* Also note, that this data cannot be "const". * 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__ (".init.text")))
#define __initdata __attribute__ ((__section__ (".init.data")))
#define __exit __attribute__ ((__section__(".exit.text")))
#define __exitdata __attribute__ ((__section__(".exit.data")))
#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
#ifndef __ASSEMBLY__ /* For assembly routines */
#define __INIT .section ".init.text","ax"
#define __FINIT .previous
#define __INITDATA .section ".init.data","aw"
#ifndef __ASSEMBLY__
/* /*
* Used for initialization calls.. * Used for initialization calls..
*/ */
typedef int (*initcall_t)(void); typedef int (*initcall_t)(void);
typedef void (*exitcall_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 /* initcalls are now grouped by functionality into separate
* subsections. Ordering inside the subsections is determined * subsections. Ordering inside the subsections is determined
...@@ -70,7 +83,7 @@ extern initcall_t __initcall_start, __initcall_end; ...@@ -70,7 +83,7 @@ extern initcall_t __initcall_start, __initcall_end;
#define __initcall(fn) device_initcall(fn) #define __initcall(fn) device_initcall(fn)
#define __exitcall(fn) \ #define __exitcall(fn) \
static exitcall_t __exitcall_##fn __exit_call = fn static exitcall_t __exitcall_##fn __exit_call = fn
/* /*
...@@ -83,39 +96,21 @@ struct kernel_param { ...@@ -83,39 +96,21 @@ struct kernel_param {
extern struct kernel_param __setup_start, __setup_end; extern struct kernel_param __setup_start, __setup_end;
#define __setup(str, fn) \ #define __setup(str, fn) \
static char __setup_str_##fn[] __initdata = str; \ static char __setup_str_##fn[] __initdata = str; \
static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn } static struct kernel_param __setup_##fn \
__attribute__((unused,__section__ (".init.setup"))) \
= { __setup_str_##fn, fn }
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
/*
* Mark functions and data as being only used at initialization
* or exit time.
*/
#define __init __attribute__ ((__section__ (".init.text")))
#define __exit __attribute__ ((unused, __section__(".exit.text")))
#define __initdata __attribute__ ((__section__ (".init.data")))
#define __exitdata __attribute__ ((unused, __section__ (".exit.data")))
#define __initsetup __attribute__ ((unused,__section__ (".init.setup")))
#define __init_call(level) __attribute__ ((unused,__section__ (".initcall" level ".init")))
#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
/* For assembly routines */
#define __INIT .section ".init.text","ax"
#define __FINIT .previous
#define __INITDATA .section ".init.data","aw"
/** /**
* module_init() - driver initialization entry point * module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion * @x: function to be run at kernel boot time or module insertion
* *
* module_init() will add the driver initialization routine in * module_init() will either be called during do_initcalls (if
* the "__initcall.int" code segment if the driver is checked as * builtin) or at module insertion time (if a module). There can only
* "y" or static, or else it will wrap the driver initialization * be one per module. */
* routine with init_module() which is used by insmod and
* modprobe when the driver is used as a module.
*/
#define module_init(x) __initcall(x); #define module_init(x) __initcall(x);
/** /**
...@@ -126,39 +121,21 @@ extern struct kernel_param __setup_start, __setup_end; ...@@ -126,39 +121,21 @@ extern struct kernel_param __setup_start, __setup_end;
* with cleanup_module() when used with rmmod when * with cleanup_module() when used with rmmod when
* the driver is a module. If the driver is statically * the driver is a module. If the driver is statically
* compiled into the kernel, module_exit() has no effect. * compiled into the kernel, module_exit() has no effect.
* There can only be one per module.
*/ */
#define module_exit(x) __exitcall(x); #define module_exit(x) __exitcall(x);
#else /**
* no_module_init - code needs no initialization.
#define __init *
#define __exit * The equivalent of declaring an empty init function which returns 0.
#define __initdata * Every module must have exactly one module_init() or no_module_init
#define __exitdata * invocation. */
#define __initcall(fn) #define no_module_init
/* For assembly routines */
#define __INIT
#define __FINIT
#define __INITDATA
/* These macros create a dummy inline: gcc 2.9x does not count alias
as usage, hence the `unused function' warning when __init functions
are declared static. We use the dummy __*_module_inline functions
both to kill the warning and check the type of the init/cleanup
function. */
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 */ #else /* MODULE */
/* Don't use these in modules, but some people do... */
#define core_initcall(fn) module_init(fn) #define core_initcall(fn) module_init(fn)
#define postcore_initcall(fn) module_init(fn) #define postcore_initcall(fn) module_init(fn)
#define arch_initcall(fn) module_init(fn) #define arch_initcall(fn) module_init(fn)
...@@ -167,6 +144,34 @@ typedef void (*__cleanup_module_func_t)(void); ...@@ -167,6 +144,34 @@ typedef void (*__cleanup_module_func_t)(void);
#define device_initcall(fn) module_init(fn) #define device_initcall(fn) module_init(fn)
#define late_initcall(fn) module_init(fn) #define late_initcall(fn) module_init(fn)
/* 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. */
/* Each module must use one module_init(), or one no_module_init */
#define module_init(initfn) \
__DEFINE_MODULE_NAME; \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int __initfn(void) __attribute__((alias(#initfn)));
#define no_module_init __DEFINE_MODULE_NAME
/* 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 */
#endif #endif
/* Data marked not to be saved by software_suspend() */ /* Data marked not to be saved by software_suspend() */
......
...@@ -28,6 +28,7 @@ extern int request_module(const char * name); ...@@ -28,6 +28,7 @@ extern int request_module(const char * name);
static inline int request_module(const char * name) { return -ENOSYS; } static inline int request_module(const char * name) { return -ENOSYS; }
#endif #endif
#define try_then_request_module(x, mod) ((x) ?: request_module(mod), (x))
extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]); extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
extern int call_usermodehelper(char *path, char *argv[], char *envp[]); extern int call_usermodehelper(char *path, char *argv[], char *envp[]);
......
This diff is collapsed.
...@@ -116,21 +116,14 @@ config MODULES ...@@ -116,21 +116,14 @@ config MODULES
may want to make use of modules with this kernel in the future, then may want to make use of modules with this kernel in the future, then
say Y here. If unsure, say Y. say Y here. If unsure, say Y.
config MODVERSIONS config MODULE_UNLOAD
bool "Set version information on all module symbols" bool "Module unloading"
depends on MODULES depends on MODULES
---help--- help
Usually, modules have to be recompiled whenever you switch to a new Without this option you will not be able to unload any
kernel. Saying Y here makes it possible, and safe, to use the modules (note that some modules may not be unloadable
same modules even after compiling a new kernel; this requires the anyway), which makes your kernel slightly smaller and
program modprobe. All the software needed for module support is in simpler. If unsure, say Y.
the modutils package (check the file <file:Documentation/Changes>
for location and latest version). NOTE: if you say Y here but don't
have the program genksyms (which is also contained in the above
mentioned modutils package), then the building of your kernel will
fail. If you are going to use modules that are generated from
non-kernel sources, you would benefit from this option. Otherwise
it's not that important. So, N ought to be a safe bet.
config KMOD config KMOD
bool "Kernel module loader" bool "Kernel module loader"
......
...@@ -406,9 +406,6 @@ asmlinkage void __init start_kernel(void) ...@@ -406,9 +406,6 @@ asmlinkage void __init start_kernel(void)
* this. But we do want output early, in case something goes wrong. * this. But we do want output early, in case something goes wrong.
*/ */
console_init(); console_init();
#ifdef CONFIG_MODULES
init_modules();
#endif
profile_init(); profile_init();
kmem_cache_init(); kmem_cache_init();
local_irq_enable(); local_irq_enable();
...@@ -457,6 +454,8 @@ asmlinkage void __init start_kernel(void) ...@@ -457,6 +454,8 @@ asmlinkage void __init start_kernel(void)
struct task_struct *child_reaper = &init_task; struct task_struct *child_reaper = &init_task;
extern initcall_t __initcall_start, __initcall_end;
static void __init do_initcalls(void) static void __init do_initcalls(void)
{ {
initcall_t *call; initcall_t *call;
......
...@@ -4,18 +4,18 @@ ...@@ -4,18 +4,18 @@
export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \
printk.o platform.o suspend.o dma.o module.o cpufreq.o \ printk.o platform.o suspend.o dma.o module.o cpufreq.o \
profile.o rcupdate.o profile.o rcupdate.o intermodule.o
obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.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 \ sysctl.o capability.o ptrace.o timer.o user.o \
signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \ signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \
rcupdate.o rcupdate.o intermodule.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o obj-$(CONFIG_SMP) += cpu.o
obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_MODULES) += ksyms.o module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o
......
...@@ -211,7 +211,12 @@ get_exec_domain_list(char *page) ...@@ -211,7 +211,12 @@ get_exec_domain_list(char *page)
for (ep = exec_domains; ep && len < PAGE_SIZE - 80; ep = ep->next) for (ep = exec_domains; ep && len < PAGE_SIZE - 80; ep = ep->next)
len += sprintf(page + len, "%d-%d\t%-16s\t[%s]\n", len += sprintf(page + len, "%d-%d\t%-16s\t[%s]\n",
ep->pers_low, ep->pers_high, ep->name, 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); read_unlock(&exec_domains_lock);
return (len); return (len);
} }
......
/* Deprecated, do not use. Moved from module.c to here. --RR */
/* Written by Keith Owens <kaos@ocs.com.au> Oct 2000 */
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/slab.h>
/* inter_module functions are always available, even when the kernel is
* compiled without modules. Consumers of inter_module_xxx routines
* will always work, even when both are built into the kernel, this
* approach removes lots of #ifdefs in mainline code.
*/
static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED;
static int kmalloc_failed;
struct inter_module_entry {
struct list_head list;
const char *im_name;
struct module *owner;
const void *userdata;
};
/**
* inter_module_register - register a new set of inter module data.
* @im_name: an arbitrary string to identify the data, must be unique
* @owner: module that is registering the data, always use THIS_MODULE
* @userdata: pointer to arbitrary userdata to be registered
*
* Description: Check that the im_name has not already been registered,
* complain if it has. For new data, add it to the inter_module_entry
* list.
*/
void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
{
struct list_head *tmp;
struct inter_module_entry *ime, *ime_new;
if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
/* Overloaded kernel, not fatal */
printk(KERN_ERR
"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
im_name);
kmalloc_failed = 1;
return;
}
memset(ime_new, 0, sizeof(*ime_new));
ime_new->im_name = im_name;
ime_new->owner = owner;
ime_new->userdata = userdata;
spin_lock(&ime_lock);
list_for_each(tmp, &ime_list) {
ime = list_entry(tmp, struct inter_module_entry, list);
if (strcmp(ime->im_name, im_name) == 0) {
spin_unlock(&ime_lock);
kfree(ime_new);
/* Program logic error, fatal */
printk(KERN_ERR "inter_module_register: duplicate im_name '%s'", im_name);
BUG();
}
}
list_add(&(ime_new->list), &ime_list);
spin_unlock(&ime_lock);
}
/**
* inter_module_unregister - unregister a set of inter module data.
* @im_name: an arbitrary string to identify the data, must be unique
*
* Description: Check that the im_name has been registered, complain if
* it has not. For existing data, remove it from the
* inter_module_entry list.
*/
void inter_module_unregister(const char *im_name)
{
struct list_head *tmp;
struct inter_module_entry *ime;
spin_lock(&ime_lock);
list_for_each(tmp, &ime_list) {
ime = list_entry(tmp, struct inter_module_entry, list);
if (strcmp(ime->im_name, im_name) == 0) {
list_del(&(ime->list));
spin_unlock(&ime_lock);
kfree(ime);
return;
}
}
spin_unlock(&ime_lock);
if (kmalloc_failed) {
printk(KERN_ERR
"inter_module_unregister: no entry for '%s', "
"probably caused by previous kmalloc failure\n",
im_name);
return;
}
else {
/* Program logic error, fatal */
printk(KERN_ERR "inter_module_unregister: no entry for '%s'", im_name);
BUG();
}
}
/**
* inter_module_get - return arbitrary userdata from another module.
* @im_name: an arbitrary string to identify the data, must be unique
*
* Description: If the im_name has not been registered, return NULL.
* Try to increment the use count on the owning module, if that fails
* then return NULL. Otherwise return the userdata.
*/
const void *inter_module_get(const char *im_name)
{
struct list_head *tmp;
struct inter_module_entry *ime;
const void *result = NULL;
spin_lock(&ime_lock);
list_for_each(tmp, &ime_list) {
ime = list_entry(tmp, struct inter_module_entry, list);
if (strcmp(ime->im_name, im_name) == 0) {
if (try_inc_mod_count(ime->owner))
result = ime->userdata;
break;
}
}
spin_unlock(&ime_lock);
return(result);
}
/**
* inter_module_get_request - im get with automatic request_module.
* @im_name: an arbitrary string to identify the data, must be unique
* @modname: module that is expected to register im_name
*
* Description: If inter_module_get fails, do request_module then retry.
*/
const void *inter_module_get_request(const char *im_name, const char *modname)
{
const void *result = inter_module_get(im_name);
if (!result) {
request_module(modname);
result = inter_module_get(im_name);
}
return(result);
}
/**
* inter_module_put - release use of data from another module.
* @im_name: an arbitrary string to identify the data, must be unique
*
* Description: If the im_name has not been registered, complain,
* otherwise decrement the use count on the owning module.
*/
void inter_module_put(const char *im_name)
{
struct list_head *tmp;
struct inter_module_entry *ime;
spin_lock(&ime_lock);
list_for_each(tmp, &ime_list) {
ime = list_entry(tmp, struct inter_module_entry, list);
if (strcmp(ime->im_name, im_name) == 0) {
if (ime->owner)
__MOD_DEC_USE_COUNT(ime->owner);
spin_unlock(&ime_lock);
return;
}
}
spin_unlock(&ime_lock);
printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name);
BUG();
}
EXPORT_SYMBOL(inter_module_register);
EXPORT_SYMBOL(inter_module_unregister);
EXPORT_SYMBOL(inter_module_get);
EXPORT_SYMBOL(inter_module_get_request);
EXPORT_SYMBOL(inter_module_put);
...@@ -155,7 +155,7 @@ char modprobe_path[256] = "/sbin/modprobe"; ...@@ -155,7 +155,7 @@ char modprobe_path[256] = "/sbin/modprobe";
static int exec_modprobe(void * module_name) static int exec_modprobe(void * module_name)
{ {
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; 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; int ret;
if (!system_running) if (!system_running)
......
...@@ -71,14 +71,6 @@ __attribute__((section("__ksymtab"))) = { ...@@ -71,14 +71,6 @@ __attribute__((section("__ksymtab"))) = {
}; };
#endif #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 */ /* process memory management */
EXPORT_SYMBOL(do_mmap_pgoff); EXPORT_SYMBOL(do_mmap_pgoff);
EXPORT_SYMBOL(do_munmap); EXPORT_SYMBOL(do_munmap);
......
This diff is collapsed.
...@@ -206,6 +206,8 @@ cond_syscall(sys_acct) ...@@ -206,6 +206,8 @@ cond_syscall(sys_acct)
cond_syscall(sys_lookup_dcookie) cond_syscall(sys_lookup_dcookie)
cond_syscall(sys_swapon) cond_syscall(sys_swapon)
cond_syscall(sys_swapoff) cond_syscall(sys_swapoff)
cond_syscall(sys_init_module)
cond_syscall(sys_delete_module)
static int set_one_prio(struct task_struct *p, int niceval, int error) static int set_one_prio(struct task_struct *p, int niceval, int error)
{ {
......
...@@ -19,3 +19,5 @@ EXPORT_SYMBOL(zlib_deflateReset); ...@@ -19,3 +19,5 @@ EXPORT_SYMBOL(zlib_deflateReset);
EXPORT_SYMBOL(zlib_deflateCopy); EXPORT_SYMBOL(zlib_deflateCopy);
EXPORT_SYMBOL(zlib_deflateParams); EXPORT_SYMBOL(zlib_deflateParams);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
no_module_init;
...@@ -20,3 +20,5 @@ EXPORT_SYMBOL(zlib_inflateReset); ...@@ -20,3 +20,5 @@ EXPORT_SYMBOL(zlib_inflateReset);
EXPORT_SYMBOL(zlib_inflateSyncPoint); EXPORT_SYMBOL(zlib_inflateSyncPoint);
EXPORT_SYMBOL(zlib_inflateIncomp); EXPORT_SYMBOL(zlib_inflateIncomp);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
no_module_init;
...@@ -374,7 +374,7 @@ int ip_nat_helper_register(struct ip_nat_helper *me) ...@@ -374,7 +374,7 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
&& ct_helper->me) { && ct_helper->me) {
__MOD_INC_USE_COUNT(ct_helper->me); __MOD_INC_USE_COUNT(ct_helper->me);
} else { } else {
#ifdef CONFIG_MODULES
/* We are a NAT helper for protocol X. If we need /* We are a NAT helper for protocol X. If we need
* respective conntrack helper for protoccol X, compute * respective conntrack helper for protoccol X, compute
* conntrack helper name and try to load module */ * conntrack helper name and try to load module */
...@@ -403,6 +403,7 @@ int ip_nat_helper_register(struct ip_nat_helper *me) ...@@ -403,6 +403,7 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
"because kernel was compiled without kernel " "because kernel was compiled without kernel "
"module loader support\n", name); "module loader support\n", name);
return -EBUSY; return -EBUSY;
#endif
#endif #endif
} }
} }
...@@ -466,9 +467,12 @@ void ip_nat_helper_unregister(struct ip_nat_helper *me) ...@@ -466,9 +467,12 @@ void ip_nat_helper_unregister(struct ip_nat_helper *me)
if ((ct_helper = ip_ct_find_helper(&me->tuple)) if ((ct_helper = ip_ct_find_helper(&me->tuple))
&& ct_helper->me) { && ct_helper->me) {
__MOD_DEC_USE_COUNT(ct_helper->me); __MOD_DEC_USE_COUNT(ct_helper->me);
} else }
#ifdef CONFIG_MODULES
else
printk("%s: unable to decrement usage count" printk("%s: unable to decrement usage count"
" of conntrack helper %s\n", " of conntrack helper %s\n",
__FUNCTION__, me->me->name); __FUNCTION__, me->me->name);
#endif
} }
} }
...@@ -538,6 +538,7 @@ struct net_proto_family inet6_family_ops = { ...@@ -538,6 +538,7 @@ struct net_proto_family inet6_family_ops = {
}; };
#ifdef MODULE #ifdef MODULE
#if 0 /* FIXME --RR */
int ipv6_unload(void) int ipv6_unload(void)
{ {
if (!unloadable) return 1; if (!unloadable) return 1;
...@@ -545,6 +546,8 @@ int ipv6_unload(void) ...@@ -545,6 +546,8 @@ int ipv6_unload(void)
return atomic_read(&(__this_module.uc.usecount)) - 3; return atomic_read(&(__this_module.uc.usecount)) - 3;
} }
#endif #endif
#endif
#endif
#if defined(MODULE) && defined(CONFIG_SYSCTL) #if defined(MODULE) && defined(CONFIG_SYSCTL)
extern void ipv6_sysctl_register(void); extern void ipv6_sysctl_register(void);
...@@ -624,10 +627,12 @@ static int __init inet6_init(void) ...@@ -624,10 +627,12 @@ static int __init inet6_init(void)
int err; int err;
#ifdef MODULE #ifdef MODULE
#if 0 /* FIXME --RR */
if (!mod_member_present(&__this_module, can_unload)) if (!mod_member_present(&__this_module, can_unload))
return -EINVAL; return -EINVAL;
__this_module.can_unload = &ipv6_unload; __this_module.can_unload = &ipv6_unload;
#endif
#endif #endif
printk(KERN_INFO "IPv6 v0.8 for NET4.0\n"); printk(KERN_INFO "IPv6 v0.8 for NET4.0\n");
......
...@@ -16,8 +16,8 @@ include scripts/Makefile.lib ...@@ -16,8 +16,8 @@ include scripts/Makefile.lib
# ========================================================================== # ==========================================================================
quiet_cmd_modules_install = INSTALL $(obj-m) quiet_cmd_modules_install = INSTALL $(obj-m)
cmd_modules_install = mkdir -p $(MODLIB)/kernel/$(obj); \ cmd_modules_install = mkdir -p $(MODLIB)/kernel && \
cp $(obj-m) $(MODLIB)/kernel/$(obj) cp $(obj-m) $(MODLIB)/kernel/
modules_install: $(subdir-ym) modules_install: $(subdir-ym)
ifneq ($(obj-m),) ifneq ($(obj-m),)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment