diff options
author | jhb <jhb@FreeBSD.org> | 2008-12-05 13:40:25 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-12-05 13:40:25 +0000 |
commit | 0ac14961cc48c1ab4910a0dfb21d6d4a3137f5a6 (patch) | |
tree | a8522c6b0e4d16f7f55489f7822e5cbf7405ddf4 /sys | |
parent | d57e5b9d8b3abb250cd15d2e7d49be4668ad956a (diff) | |
download | FreeBSD-src-0ac14961cc48c1ab4910a0dfb21d6d4a3137f5a6.zip FreeBSD-src-0ac14961cc48c1ab4910a0dfb21d6d4a3137f5a6.tar.gz |
- Invoke MOD_QUIESCE on all modules in a linker file (kld) before
unloading any modules. As a result, if any module veto's an unload
request via MOD_QUIESCE, the entire set of modules for that linker
file will remain loaded and active now rather than leaving the kld
in a weird state where some modules are loaded and some are unloaded.
- This also moves the logic for handling the "forced" unload flag out of
kern_module.c and into kern_linker.c which is a bit cleaner.
- Add a module_name() routine that returns the name of a module and use that
instead of printing pointer values in debug messages when a module fails
MOD_QUIESCE or MOD_UNLOAD.
MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_linker.c | 31 | ||||
-rw-r--r-- | sys/kern/kern_module.c | 25 | ||||
-rw-r--r-- | sys/sys/module.h | 4 |
3 files changed, 50 insertions, 10 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index e232cdc..f657efa 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -587,7 +587,30 @@ linker_file_unload(linker_file_t file, int flags) " informing modules\n")); /* - * Inform any modules associated with this file. + * Quiesce all the modules to give them a chance to veto the unload. + */ + MOD_SLOCK; + for (mod = TAILQ_FIRST(&file->modules); mod; + mod = module_getfnext(mod)) { + + error = module_quiesce(mod); + if (error != 0 && flags != LINKER_UNLOAD_FORCE) { + KLD_DPF(FILE, ("linker_file_unload: module %s" + " vetoed unload\n", module_getname(mod))); + /* + * XXX: Do we need to tell all the quiesced modules + * that they can resume work now via a new module + * event? + */ + MOD_SUNLOCK; + return (error); + } + } + MOD_SUNLOCK; + + /* + * Inform any modules associated with this file that they are + * being be unloaded. */ MOD_XLOCK; for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { @@ -597,9 +620,9 @@ linker_file_unload(linker_file_t file, int flags) /* * Give the module a chance to veto the unload. */ - if ((error = module_unload(mod, flags)) != 0) { - KLD_DPF(FILE, ("linker_file_unload: module %p" - " vetoes unload\n", mod)); + if ((error = module_unload(mod)) != 0) { + KLD_DPF(FILE, ("linker_file_unload: module %s" + " failed unload\n", mod)); return (error); } MOD_XLOCK; diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c index e2c02b8..fef7f87 100644 --- a/sys/kern/kern_module.c +++ b/sys/kern/kern_module.c @@ -196,9 +196,7 @@ module_release(module_t mod) TAILQ_REMOVE(&modules, mod, link); if (mod->file) TAILQ_REMOVE(&mod->file->modules, mod, flink); - MOD_XUNLOCK; free(mod, M_MODULE); - MOD_XLOCK; } } @@ -232,16 +230,25 @@ module_lookupbyid(int modid) } int -module_unload(module_t mod, int flags) +module_quiesce(module_t mod) { int error; mtx_lock(&Giant); error = MOD_EVENT(mod, MOD_QUIESCE); + mtx_unlock(&Giant); if (error == EOPNOTSUPP || error == EINVAL) error = 0; - if (error == 0 || flags == LINKER_UNLOAD_FORCE) - error = MOD_EVENT(mod, MOD_UNLOAD); + return (error); +} + +int +module_unload(module_t mod) +{ + int error; + + mtx_lock(&Giant); + error = MOD_EVENT(mod, MOD_UNLOAD); mtx_unlock(&Giant); return (error); } @@ -262,6 +269,14 @@ module_getfnext(module_t mod) return (TAILQ_NEXT(mod, flink)); } +const char * +module_getname(module_t mod) +{ + + MOD_LOCK_ASSERT; + return (mod->name); +} + void module_setspecific(module_t mod, modspecific_t *datap) { diff --git a/sys/sys/module.h b/sys/sys/module.h index 6fbf524..2abad63 100644 --- a/sys/sys/module.h +++ b/sys/sys/module.h @@ -154,11 +154,13 @@ void module_register_init(const void *); int module_register(const struct moduledata *, struct linker_file *); module_t module_lookupbyname(const char *); module_t module_lookupbyid(int); +int module_quiesce(module_t); void module_reference(module_t); void module_release(module_t); -int module_unload(module_t, int flags); +int module_unload(module_t); int module_getid(module_t); module_t module_getfnext(module_t); +const char * module_getname(module_t); void module_setspecific(module_t, modspecific_t *); struct linker_file *module_file(module_t); |