diff options
Diffstat (limited to 'sys/kern/kern_linker.c')
-rw-r--r-- | sys/kern/kern_linker.c | 35 |
1 files changed, 24 insertions, 11 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 86a14ae..f919254 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -70,6 +70,9 @@ SYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RW, #define KLD_LOCK() sx_xlock(&kld_sx) #define KLD_UNLOCK() sx_xunlock(&kld_sx) +#define KLD_DOWNGRADE() sx_downgrade(&kld_sx) +#define KLD_LOCK_READ() sx_slock(&kld_sx) +#define KLD_UNLOCK_READ() sx_sunlock(&kld_sx) #define KLD_LOCKED() sx_xlocked(&kld_sx) #define KLD_LOCK_ASSERT() do { \ if (!cold) \ @@ -1019,18 +1022,24 @@ kern_kldload(struct thread *td, const char *file, int *fileid) KLD_LOCK(); error = linker_load_module(kldname, modname, NULL, NULL, &lf); - if (error) - goto unlock; + if (error) { + KLD_UNLOCK(); + goto done; + } + lf->userrefs++; + if (fileid != NULL) + *fileid = lf->id; #ifdef HWPMC_HOOKS + KLD_DOWNGRADE(); pkm.pm_file = lf->filename; pkm.pm_address = (uintptr_t) lf->address; PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); -#endif - lf->userrefs++; - if (fileid != NULL) - *fileid = lf->id; -unlock: + KLD_UNLOCK_READ(); +#else KLD_UNLOCK(); +#endif + +done: CURVNET_RESTORE(); return (error); } @@ -1102,10 +1111,14 @@ kern_kldunload(struct thread *td, int fileid, int flags) error = ENOENT; #ifdef HWPMC_HOOKS - if (error == 0) + if (error == 0) { + KLD_DOWNGRADE(); PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); + KLD_UNLOCK_READ(); + } else +#else + KLD_UNLOCK(); #endif - KLD_UNLOCK(); CURVNET_RESTORE(); return (error); } @@ -1932,7 +1945,7 @@ linker_hwpmc_list_objects(void) int i, nmappings; nmappings = 0; - KLD_LOCK(); + KLD_LOCK_READ(); TAILQ_FOREACH(lf, &linker_files, link) nmappings++; @@ -1947,7 +1960,7 @@ linker_hwpmc_list_objects(void) kobase[i].pm_address = (uintptr_t)lf->address; i++; } - KLD_UNLOCK(); + KLD_UNLOCK_READ(); KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?")); |