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
OBJDUMP = $(CROSS_COMPILE)objdump
AWK = awk
GENKSYMS = /sbin/genksyms
DEPMOD = /sbin/depmod
KALLSYMS = /sbin/kallsyms
PERL = perl
MODFLAGS = -DMODULE
......@@ -516,7 +515,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_:
......@@ -525,20 +524,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)) :
$(Q)$(MAKE) -f scripts/Makefile.modinst obj=$(patsubst _modinst_%,%,$@)
......
......@@ -1604,13 +1604,14 @@ config DEBUG_HIGHMEM
This options enables addition error checking for high memory systems.
Disable for production systems.
config KALLSYMS
bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL
help
Say Y here to let the kernel print out symbolic crash information and
symbolic stack backtraces. This increases the size of the kernel
somewhat, as all symbols have to be loaded into the kernel image.
# Reimplemented RSN.
#config KALLSYMS
# bool "Load all symbols for debugging/kksymoops"
# depends on DEBUG_KERNEL
# help
# Say Y here to let the kernel print out symbolic crash information and
# 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
bool
......
......@@ -813,13 +813,13 @@ config DEBUG_KERNEL
Say Y here if you are developing drivers or trying to debug and
identify kernel problems.
config KALLSYMS
bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL
help
Say Y here to let the kernel print out symbolic crash information and
symbolic stack backtraces. This increases the size of the kernel
somewhat, as all symbols have to be loaded into the kernel image.
# config KALLSYMS
# bool "Load all symbols for debugging/kksymoops"
# depends on DEBUG_KERNEL
# help
# Say Y here to let the kernel print out symbolic crash information and
# symbolic stack backtraces. This increases the size of the kernel
# somewhat, as all symbols have to be loaded into the kernel image.
config IA64_PRINT_HAZARDS
bool "Print possible IA-64 dependency violations to console"
......
......@@ -1807,9 +1807,9 @@ config DEBUG_HIGHMEM
bool "Highmem debugging"
depends on DEBUG_KERNEL && HIGHMEM
config KALLSYMS
bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL
# config KALLSYMS
# bool "Load all symbols for debugging/kksymoops"
# depends on DEBUG_KERNEL
config KGDB
bool "Include kgdb kernel debugger"
......
......@@ -739,13 +739,13 @@ config INIT_DEBUG
help
Fill __init and __initdata at the end of boot. This is only for debugging.
config KALLSYMS
bool "Load all symbols for debugging/kksymoops"
depends on DEBUG_KERNEL
help
Say Y here to let the kernel print out symbolic crash information and
symbolic stack backtraces. This increases the size of the kernel
somewhat, as all symbols have to be loaded into the kernel image.
# config KALLSYMS
# bool "Load all symbols for debugging/kksymoops"
# depends on DEBUG_KERNEL
# help
# Say Y here to let the kernel print out symbolic crash information and
# symbolic stack backtraces. This increases the size of the kernel
# somewhat, as all symbols have to be loaded into the kernel image.
endmenu
......
......@@ -151,6 +151,7 @@ static int print_unex=1;
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/version.h>
#define FDPATCHES
#include <linux/fdreg.h>
......
......@@ -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,9 +1275,11 @@ 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;
......
......@@ -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 */
void get_filesystem(struct file_system_type *fs)
{
if (fs->owner)
__MOD_INC_USE_COUNT(fs->owner);
if (!try_module_get(fs->owner)) {
#ifdef CONFIG_MODULE_UNLOAD
unsigned int cpu = get_cpu();
local_inc(&fs->owner->ref[cpu].count);
put_cpu();
#else
/* Getting filesystem while it's starting up? We're
already supposed to have a reference. */
BUG();
#endif
}
}
void put_filesystem(struct file_system_type *fs)
{
if (fs->owner)
__MOD_DEC_USE_COUNT(fs->owner);
module_put(fs->owner);
}
static struct file_system_type **find_filesystem(const char *name)
......
......@@ -296,17 +296,6 @@ static struct file_operations proc_modules_operations = {
.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;
......@@ -604,7 +593,6 @@ void __init proc_misc_init(void)
create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
#ifdef CONFIG_MODULES
create_seq_entry("modules", 0, &proc_modules_operations);
create_seq_entry("ksyms", 0, &proc_ksyms_operations);
#endif
proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
if (proc_root_kcore) {
......
......@@ -21,6 +21,7 @@
#include <linux/device.h>
#include <linux/node.h>
#include <asm/semaphore.h>
struct cpu {
int node_id; /* The node which contains the CPU */
......@@ -29,4 +30,6 @@ struct cpu {
extern int register_cpu(struct cpu *, int, struct node *);
/* Stop CPUs going up and down. */
extern struct semaphore cpucontrol;
#endif /* _LINUX_CPU_H_ */
......@@ -198,6 +198,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
......@@ -295,6 +298,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
......@@ -369,6 +373,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 */
......
......@@ -38,17 +38,30 @@
* 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..
*/
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 +83,7 @@ extern initcall_t __initcall_start, __initcall_end;
#define __initcall(fn) device_initcall(fn)
#define __exitcall(fn) \
#define __exitcall(fn) \
static exitcall_t __exitcall_##fn __exit_call = fn
/*
......@@ -83,39 +96,21 @@ struct kernel_param {
extern struct kernel_param __setup_start, __setup_end;
#define __setup(str, fn) \
static char __setup_str_##fn[] __initdata = str; \
static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }
#define __setup(str, fn) \
static char __setup_str_##fn[] __initdata = str; \
static struct kernel_param __setup_##fn \
__attribute__((unused,__section__ (".init.setup"))) \
= { __setup_str_##fn, fn }
#endif /* __ASSEMBLY__ */
/*
* Mark functions and data as being only used at initialization
* or exit time.
*/
#define __init __attribute__ ((__section__ (".init.text")))
#define __exit __attribute__ ((unused, __section__(".exit.text")))
#define __initdata __attribute__ ((__section__ (".init.data")))
#define __exitdata __attribute__ ((unused, __section__ (".exit.data")))
#define __initsetup __attribute__ ((unused,__section__ (".init.setup")))
#define __init_call(level) __attribute__ ((unused,__section__ (".initcall" level ".init")))
#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
/* For assembly routines */
#define __INIT .section ".init.text","ax"
#define __FINIT .previous
#define __INITDATA .section ".init.data","aw"
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* module_init() will add the driver initialization routine in
* the "__initcall.int" code segment if the driver is checked as
* "y" or static, or else it will wrap the driver initialization
* routine with init_module() which is used by insmod and
* modprobe when the driver is used as a module.
*/
* module_init() will either be called during do_initcalls (if
* builtin) or at module insertion time (if a module). There can only
* be one per module. */
#define module_init(x) __initcall(x);
/**
......@@ -126,39 +121,21 @@ extern struct kernel_param __setup_start, __setup_end;
* with cleanup_module() when used with rmmod when
* the driver is a module. If the driver is statically
* compiled into the kernel, module_exit() has no effect.
* There can only be one per module.
*/
#define module_exit(x) __exitcall(x);
#else
#define __init
#define __exit
#define __initdata
#define __exitdata
#define __initcall(fn)
/* For assembly routines */
#define __INIT
#define __FINIT
#define __INITDATA
/* These macros create a dummy inline: gcc 2.9x does not count alias
as usage, hence the `unused function' warning when __init functions
are declared static. We use the dummy __*_module_inline functions
both to kill the warning and check the type of the init/cleanup
function. */
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; }
/**
* no_module_init - code needs no initialization.
*
* The equivalent of declaring an empty init function which returns 0.
* Every module must have exactly one module_init() or no_module_init
* invocation. */
#define no_module_init
#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 postcore_initcall(fn) module_init(fn)
#define arch_initcall(fn) module_init(fn)
......@@ -167,6 +144,34 @@ typedef void (*__cleanup_module_func_t)(void);
#define device_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
/* Data marked not to be saved by software_suspend() */
......
......@@ -28,6 +28,7 @@ extern int request_module(const char * name);
static inline int request_module(const char * name) { return -ENOSYS; }
#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 call_usermodehelper(char *path, char *argv[], char *envp[]);
......
This diff is collapsed.
......@@ -116,21 +116,14 @@ config MODULES
may want to make use of modules with this kernel in the future, then
say Y here. If unsure, say Y.
config MODVERSIONS
bool "Set version information on all module symbols"
config MODULE_UNLOAD
bool "Module unloading"
depends on MODULES
---help---
Usually, modules have to be recompiled whenever you switch to a new
kernel. Saying Y here makes it possible, and safe, to use the
same modules even after compiling a new kernel; this requires the
program modprobe. All the software needed for module support is in
the modutils package (check the file <file:Documentation/Changes>
for location and latest version). NOTE: if you say Y here but don't
have the program genksyms (which is also contained in the above
mentioned modutils package), then the building of your kernel will
fail. If you are going to use modules that are generated from
non-kernel sources, you would benefit from this option. Otherwise
it's not that important. So, N ought to be a safe bet.
help
Without this option you will not be able to unload any
modules (note that some modules may not be unloadable
anyway), which makes your kernel slightly smaller and
simpler. If unsure, say Y.
config KMOD
bool "Kernel module loader"
......
......@@ -406,9 +406,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
profile_init();
kmem_cache_init();
local_irq_enable();
......@@ -457,6 +454,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;
......
......@@ -4,18 +4,18 @@
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 \
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 \
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 workqueue.o futex.o platform.o pid.o \
rcupdate.o
rcupdate.o intermodule.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_KALLSYMS) += kallsyms.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
......
......@@ -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);
}
......
/* 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";
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)
......
......@@ -71,14 +71,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);
......
This diff is collapsed.
......@@ -206,6 +206,8 @@ cond_syscall(sys_acct)
cond_syscall(sys_lookup_dcookie)
cond_syscall(sys_swapon)
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)
{
......
......@@ -19,3 +19,5 @@ EXPORT_SYMBOL(zlib_deflateReset);
EXPORT_SYMBOL(zlib_deflateCopy);
EXPORT_SYMBOL(zlib_deflateParams);
MODULE_LICENSE("GPL");
no_module_init;
......@@ -20,3 +20,5 @@ EXPORT_SYMBOL(zlib_inflateReset);
EXPORT_SYMBOL(zlib_inflateSyncPoint);
EXPORT_SYMBOL(zlib_inflateIncomp);
MODULE_LICENSE("GPL");
no_module_init;
......@@ -374,7 +374,7 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
&& 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 */
......@@ -403,6 +403,7 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
"because kernel was compiled without kernel "
"module loader support\n", name);
return -EBUSY;
#endif
#endif
}
}
......@@ -466,9 +467,12 @@ void ip_nat_helper_unregister(struct ip_nat_helper *me)
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
}
}
......@@ -538,6 +538,7 @@ struct net_proto_family inet6_family_ops = {
};
#ifdef MODULE
#if 0 /* FIXME --RR */
int ipv6_unload(void)
{
if (!unloadable) return 1;
......@@ -545,6 +546,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);
......@@ -624,10 +627,12 @@ 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");
......
......@@ -16,8 +16,8 @@ include scripts/Makefile.lib
# ==========================================================================
quiet_cmd_modules_install = INSTALL $(obj-m)
cmd_modules_install = mkdir -p $(MODLIB)/kernel/$(obj); \
cp $(obj-m) $(MODLIB)/kernel/$(obj)
cmd_modules_install = mkdir -p $(MODLIB)/kernel && \
cp $(obj-m) $(MODLIB)/kernel/
modules_install: $(subdir-ym)
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