diff -u linux-2.2.17-orig/kernel/module.c linux-2.2.17-patched/kernel/module.c --- linux-2.2.17-orig/kernel/module.c Wed May 3 20:16:53 2000 +++ linux-2.2.17-patched/kernel/module.c Mon Nov 27 14:38:21 2000 @@ -6,6 +6,8 @@ #include #include #include +#include +#include /* * Originally by Anonymous (as far as I know...) @@ -14,11 +16,12 @@ * Heavily modified by Bjorn Ekwall May 1994 (C) * Rewritten by Richard Henderson Dec 1996 * Add MOD_INITIALIZING Keith Owens Nov 1999 + * Backport inter_module_xxx from 2.4. Keith Owens Oct 2000 * * This source is covered by the GNU GPL, the same as all kernel sources. */ -#ifdef CONFIG_MODULES /* a *big* #ifdef block... */ +#ifdef CONFIG_MODULES extern struct module_symbol __start___ksymtab[]; extern struct module_symbol __stop___ksymtab[]; @@ -47,6 +50,174 @@ }; struct module *module_list = &kernel_module; + +#endif /* CONFIG_MODULES */ + +/* 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; + +/** + * 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 */ + panic("inter_module_register: duplicate im_name '%s'", im_name); + } + } + 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 */ + panic("inter_module_unregister: no entry for '%s'", im_name); + } +} + +/** + * 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) { + /* This should be try_inc_use_count but that function is + * not in 2.2 kernels. I am not opening that can of worms + * for 2.2. Keith Owens + */ + if (ime->owner) + __MOD_INC_USE_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); + panic("inter_module_put: no entry for '%s'", im_name); +} + +#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); diff -u linux-2.2.17-orig/kernel/ksyms.c linux-2.2.17-patched/kernel/ksyms.c --- linux-2.2.17-orig/kernel/ksyms.c Mon Sep 4 13:39:28 2000 +++ linux-2.2.17-patched/kernel/ksyms.c Mon Nov 27 14:35:05 2000 @@ -81,6 +81,11 @@ #ifdef CONFIG_MODULES EXPORT_SYMBOL(get_module_symbol); #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(get_options); /* process memory management */ diff -u linux-2.2.17-orig/include/linux/module.h linux-2.2.17-patched/include/linux/module.h --- linux-2.2.17-orig/include/linux/module.h Wed May 3 20:16:52 2000 +++ linux-2.2.17-patched/include/linux/module.h Mon Nov 27 14:35:05 2000 @@ -8,6 +8,7 @@ #define _LINUX_MODULE_H #include +#include #ifdef __GENKSYMS__ # define _set_ver(sym) sym @@ -140,6 +141,35 @@ #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. + */ + +#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; +}; /* Find a symbol exported by the kernel or another module */ extern unsigned long get_module_symbol(char *, char *); diff -u linux-2.2.17-orig/include/linux/list.h linux-2.2.17-patched/include/linux/list.h --- linux-2.2.17-orig/include/linux/list.h Mon Dec 1 14:16:57 1997 +++ linux-2.2.17-patched/include/linux/list.h Mon Nov 27 14:35:13 2000 @@ -17,6 +17,8 @@ struct list_head *next, *prev; }; +#define LIST_HEAD_INIT(name) { &(name), &(name) } + #define LIST_HEAD(name) \ struct list_head name = { &name, &name } @@ -49,6 +51,14 @@ } /* + * Insert a new entry at the tail + */ +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* * Delete a list entry by making the prev/next entries * point to each other. * @@ -93,6 +103,9 @@ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) #endif /* __KERNEL__ */ diff -u linux-2.2.17-orig/Makefile linux-2.2.17-patched/Makefile --- linux-2.2.17-orig/Makefile Mon Sep 4 13:47:54 2000 +++ linux-2.2.17-patched/Makefile Mon Nov 27 14:35:05 2000 @@ -233,7 +233,7 @@ $(LIBS) \ --end-group \ -o vmlinux - $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map symlinks: rm -f include/asm