diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/os/modctl.c | 71 | ||||
-rw-r--r-- | usr/src/uts/common/sys/modctl.h | 4 |
2 files changed, 66 insertions, 9 deletions
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c index 72a08a5ff9..73e0447ab1 100644 --- a/usr/src/uts/common/os/modctl.c +++ b/usr/src/uts/common/os/modctl.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -127,6 +127,12 @@ kmutex_t mod_lock; /* protects &modules insert linkage, */ kmutex_t mod_uninstall_lock; /* protects mod_uninstall_cv */ kthread_id_t mod_aul_thread; +int modunload_wait; +kmutex_t modunload_wait_mutex; +kcondvar_t modunload_wait_cv; +int modunload_active_count; +int modunload_disable_count; + int isminiroot; /* set if running as miniroot */ int modrootloaded; /* set after root driver and fs are loaded */ int moddebug = 0x0; /* debug flags for module writers */ @@ -392,7 +398,6 @@ modctl_modunload(modid_t id) #endif mod_uninstall_all(); } else { - (void) devfs_clean(ddi_root_node(), NULL, 0); rval = modunload(id); } return (rval); @@ -2016,7 +2021,15 @@ modunrload(modid_t id, struct modctl **rmodp, int unload) int modunload(modid_t id) { - return (modunrload(id, NULL, 1)); + int retval; + + /* synchronize with any active modunload_disable() */ + modunload_begin(); + if (ddi_root_node()) + (void) devfs_clean(ddi_root_node(), NULL, 0); + retval = modunrload(id, NULL, 1); + modunload_end(); + return (retval); } /* @@ -2797,6 +2810,8 @@ modinstall(struct modctl *mp) return (val); } +int detach_driver_unconfig = 0; + static int detach_driver(char *name) { @@ -2815,7 +2830,7 @@ detach_driver(char *name) return (0); error = ndi_devi_unconfig_driver(ddi_root_node(), - NDI_DETACH_DRIVER, major); + NDI_DETACH_DRIVER | detach_driver_unconfig, major); return (error == NDI_SUCCESS ? 0 : -1); } @@ -2941,6 +2956,9 @@ mod_uninstall_all(void) struct modctl *mp; modid_t modid = 0; + /* synchronize with any active modunload_disable() */ + modunload_begin(); + /* mark this thread as doing autounloading */ (void) tsd_set(mod_autounload_key, (void *)1); @@ -2965,20 +2983,57 @@ mod_uninstall_all(void) } (void) tsd_set(mod_autounload_key, NULL); + modunload_end(); } -static int modunload_disable_count; - +/* wait for unloads that have begun before registering disable */ void modunload_disable(void) { - INCR_COUNT(&modunload_disable_count, &mod_uninstall_lock); + mutex_enter(&modunload_wait_mutex); + while (modunload_active_count) { + modunload_wait++; + cv_wait(&modunload_wait_cv, &modunload_wait_mutex); + modunload_wait--; + } + modunload_disable_count++; + mutex_exit(&modunload_wait_mutex); } +/* mark end of disable and signal waiters */ void modunload_enable(void) { - DECR_COUNT(&modunload_disable_count, &mod_uninstall_lock); + mutex_enter(&modunload_wait_mutex); + modunload_disable_count--; + if ((modunload_disable_count == 0) && modunload_wait) + cv_broadcast(&modunload_wait_cv); + mutex_exit(&modunload_wait_mutex); +} + +/* wait for disables to complete before begining unload */ +void +modunload_begin() +{ + mutex_enter(&modunload_wait_mutex); + while (modunload_disable_count) { + modunload_wait++; + cv_wait(&modunload_wait_cv, &modunload_wait_mutex); + modunload_wait--; + } + modunload_active_count++; + mutex_exit(&modunload_wait_mutex); +} + +/* mark end of unload and signal waiters */ +void +modunload_end() +{ + mutex_enter(&modunload_wait_mutex); + modunload_active_count--; + if ((modunload_active_count == 0) && modunload_wait) + cv_broadcast(&modunload_wait_cv); + mutex_exit(&modunload_wait_mutex); } void diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h index c151de9900..06019d5f0f 100644 --- a/usr/src/uts/common/sys/modctl.h +++ b/usr/src/uts/common/sys/modctl.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -488,6 +488,8 @@ extern int modunload(int); extern int mod_hold_stub(struct mod_stub_info *); extern void modunload_disable(void); extern void modunload_enable(void); +extern void modunload_begin(void); +extern void modunload_end(void); extern int mod_remove_by_name(char *); extern int mod_sysvar(const char *, const char *, u_longlong_t *); extern int mod_sysctl(int, void *); |