Index: include/linux/notifier.h =================================================================== RCS file: /home/cvs/linux-2.4/include/linux/notifier.h,v retrieving revision 1.3 diff -u -r1.3 notifier.h --- include/linux/notifier.h 4 Aug 2002 00:02:49 -0000 1.3 +++ include/linux/notifier.h 27 May 2003 13:39:02 -0000 @@ -10,18 +10,22 @@ #ifndef _LINUX_NOTIFIER_H #define _LINUX_NOTIFIER_H #include +#include struct notifier_block { int (*notifier_call)(struct notifier_block *self, unsigned long, void *); struct notifier_block *next; int priority; + + struct module *owner; /* NULL if not from a module */ }; #ifdef __KERNEL__ extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n); +extern int notifier_chain_register_module(struct notifier_block **list, struct notifier_block *n, struct module *owner); extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n); extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v); Index: kernel/sys.c =================================================================== RCS file: /home/cvs/linux-2.4/kernel/sys.c,v retrieving revision 1.14 diff -u -r1.14 sys.c --- kernel/sys.c 9 May 2003 00:35:17 -0000 1.14 +++ kernel/sys.c 27 May 2003 13:39:03 -0000 @@ -71,16 +71,19 @@ rwlock_t notifier_lock = RW_LOCK_UNLOCKED; /** - * notifier_chain_register - Add notifier to a notifier chain + * notifier_chain_register_module - Add notifier to a notifier chain + * for a module. + * * @list: Pointer to root list pointer * @n: New entry in notifier chain + * @owner: The module that owns this notifier block * * Adds a notifier to a notifier chain. * * Currently always returns zero. */ -int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) +int notifier_chain_register_module(struct notifier_block **list, struct notifier_block *n, struct module *owner) { write_lock(¬ifier_lock); while(*list) @@ -90,12 +93,28 @@ list= &((*list)->next); } n->next = *list; + n->owner = owner; *list=n; write_unlock(¬ifier_lock); return 0; } /** + * notifier_chain_register - Add notifier to a notifier chain + * @list: Pointer to root list pointer + * @n: New entry in notifier chain + * + * Adds a notifier to a notifier chain. + * + * Currently always returns zero. + */ + +int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) +{ + return notifier_chain_register_module(list, n, NULL); +} + +/** * notifier_chain_unregister - Remove notifier from a notifier chain * @nl: Pointer to root list pointer * @n: New entry in notifier chain @@ -128,7 +147,8 @@ * @val: Value passed unmodified to notifier function * @v: Pointer passed unmodified to notifier function * - * Calls each function in a notifier chain in turn. + * Calls each function in a notifier chain in turn. If it is owned + * by a module, increment that module's use count while in the call. * * If the return value of the notifier can be and'd * with %NOTIFY_STOP_MASK, then notifier_call_chain @@ -142,15 +162,24 @@ { int ret=NOTIFY_DONE; struct notifier_block *nb = *n; + struct notifier_block *next; + struct module *owner; - while(nb) + for (; nb; nb=next) { + owner = nb->owner; + next = nb->next; + if ((owner) && (!try_inc_mod_count(owner))) + /* The module that owns us has ceased to + exist, just go on. */ + continue; ret=nb->notifier_call(nb,val,v); + if (owner) + __MOD_DEC_USE_COUNT(owner); if(ret&NOTIFY_STOP_MASK) { return ret; } - nb=nb->next; } return ret; }