Remove the kld lock macros and just use the sx(9) API. Add locking in

linker_init_kernel_modules() and linker_preload() in order to remove most
of the checks for !cold before asserting that the kld lock is held. These
routines are invoked by SYSINIT(9), so there's no harm in them taking the
kld lock.
This commit is contained in:
Mark Johnston 2013-08-24 21:07:04 +00:00
parent 1f97b64cbb
commit 3a277424e6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=254810

View File

@ -71,17 +71,6 @@ SYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RW | CTLFLAG_TUN,
TUNABLE_INT("debug.kld_debug", &kld_debug);
#endif
#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) \
sx_assert(&kld_sx, SX_XLOCKED); \
} while (0)
/*
* static char *linker_search_path(const char *name, struct mod_depend
* *verinfo);
@ -121,7 +110,8 @@ static int linker_no_more_classes = 0;
#define LINKER_GET_NEXT_FILE_ID(a) do { \
linker_file_t lftmp; \
\
KLD_LOCK_ASSERT(); \
if (!cold) \
sx_assert(&kld_sx, SA_XLOCKED); \
retry: \
TAILQ_FOREACH(lftmp, &linker_files, link) { \
if (next_file_id == lftmp->id) { \
@ -360,7 +350,9 @@ static void
linker_init_kernel_modules(void)
{
sx_xlock(&kld_sx);
linker_file_register_modules(linker_kernel_file);
sx_xunlock(&kld_sx);
}
SYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules,
@ -377,7 +369,7 @@ linker_load_file(const char *filename, linker_file_t *result)
if (prison0.pr_securelevel > 0)
return (EPERM);
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
lf = linker_find_file_by_name(filename);
if (lf) {
KLD_DPF(FILE, ("linker_load_file: file %s is already loaded,"
@ -411,10 +403,10 @@ linker_load_file(const char *filename, linker_file_t *result)
return (error);
}
modules = !TAILQ_EMPTY(&lf->modules);
KLD_UNLOCK();
sx_xunlock(&kld_sx);
linker_file_register_sysctls(lf);
linker_file_sysinit(lf);
KLD_LOCK();
sx_xlock(&kld_sx);
lf->flags |= LINKER_FILE_LINKED;
/*
@ -465,16 +457,16 @@ linker_reference_module(const char *modname, struct mod_depend *verinfo,
modlist_t mod;
int error;
KLD_LOCK();
sx_xlock(&kld_sx);
if ((mod = modlist_lookup2(modname, verinfo)) != NULL) {
*result = mod->container;
(*result)->refs++;
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (0);
}
error = linker_load_module(NULL, modname, NULL, verinfo, result);
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
@ -485,13 +477,13 @@ linker_release_module(const char *modname, struct mod_depend *verinfo,
modlist_t mod;
int error;
KLD_LOCK();
sx_xlock(&kld_sx);
if (lf == NULL) {
KASSERT(modname != NULL,
("linker_release_module: no file or name"));
mod = modlist_lookup2(modname, verinfo);
if (mod == NULL) {
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (ESRCH);
}
lf = mod->container;
@ -499,7 +491,7 @@ linker_release_module(const char *modname, struct mod_depend *verinfo,
KASSERT(modname == NULL && verinfo == NULL,
("linker_release_module: both file and name"));
error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL);
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
@ -512,7 +504,7 @@ linker_find_file_by_name(const char *filename)
koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
sprintf(koname, "%s.ko", filename);
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
TAILQ_FOREACH(lf, &linker_files, link) {
if (strcmp(lf->filename, koname) == 0)
break;
@ -528,7 +520,7 @@ linker_find_file_by_id(int fileid)
{
linker_file_t lf;
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
TAILQ_FOREACH(lf, &linker_files, link)
if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED)
break;
@ -541,13 +533,13 @@ linker_file_foreach(linker_predicate_t *predicate, void *context)
linker_file_t lf;
int retval = 0;
KLD_LOCK();
sx_xlock(&kld_sx);
TAILQ_FOREACH(lf, &linker_files, link) {
retval = predicate(lf, context);
if (retval != 0)
break;
}
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (retval);
}
@ -557,7 +549,8 @@ linker_make_file(const char *pathname, linker_class_t lc)
linker_file_t lf;
const char *filename;
KLD_LOCK_ASSERT();
if (!cold)
sx_assert(&kld_sx, SA_XLOCKED);
filename = linker_basename(pathname);
KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname));
@ -591,7 +584,7 @@ linker_file_unload(linker_file_t file, int flags)
if (prison0.pr_securelevel > 0)
return (EPERM);
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
/* Easy case of just dropping a reference. */
@ -664,10 +657,10 @@ linker_file_unload(linker_file_t file, int flags)
*/
if (file->flags & LINKER_FILE_LINKED) {
file->flags &= ~LINKER_FILE_LINKED;
KLD_UNLOCK();
sx_xunlock(&kld_sx);
linker_file_sysuninit(file);
linker_file_unregister_sysctls(file);
KLD_LOCK();
sx_xlock(&kld_sx);
}
TAILQ_REMOVE(&linker_files, file, link);
@ -706,7 +699,7 @@ linker_file_add_dependency(linker_file_t file, linker_file_t dep)
{
linker_file_t *newdeps;
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *),
M_LINKER, M_WAITOK | M_ZERO);
if (newdeps == NULL)
@ -738,12 +731,12 @@ linker_file_lookup_set(linker_file_t file, const char *name,
{
int error, locked;
locked = KLD_LOCKED();
locked = sx_xlocked(&kld_sx);
if (!locked)
KLD_LOCK();
sx_xlock(&kld_sx);
error = LINKER_LOOKUP_SET(file, name, firstp, lastp, countp);
if (!locked)
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
@ -763,12 +756,12 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
caddr_t sym;
int locked;
locked = KLD_LOCKED();
locked = sx_xlocked(&kld_sx);
if (!locked)
KLD_LOCK();
sx_xlock(&kld_sx);
sym = linker_file_lookup_symbol_internal(file, name, deps);
if (!locked)
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (sym);
}
@ -782,7 +775,7 @@ linker_file_lookup_symbol_internal(linker_file_t file, const char *name,
size_t common_size = 0;
int i;
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n",
file, name, deps));
@ -982,9 +975,9 @@ linker_search_symbol_name(caddr_t value, char *buf, u_int buflen,
{
int error;
KLD_LOCK();
sx_xlock(&kld_sx);
error = linker_debug_search_symbol_name(value, buf, buflen, offset);
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
@ -1026,10 +1019,10 @@ kern_kldload(struct thread *td, const char *file, int *fileid)
modname = file;
}
KLD_LOCK();
sx_xlock(&kld_sx);
error = linker_load_module(kldname, modname, NULL, NULL, &lf);
if (error) {
KLD_UNLOCK();
sx_xunlock(&kld_sx);
goto done;
}
lf->userrefs++;
@ -1039,13 +1032,13 @@ kern_kldload(struct thread *td, const char *file, int *fileid)
EVENTHANDLER_INVOKE(kld_load, lf);
#ifdef HWPMC_HOOKS
KLD_DOWNGRADE();
sx_downgrade(&kld_sx);
pkm.pm_file = lf->filename;
pkm.pm_address = (uintptr_t) lf->address;
PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm);
KLD_UNLOCK_READ();
sx_sunlock(&kld_sx);
#else
KLD_UNLOCK();
sx_xunlock(&kld_sx);
#endif
done:
@ -1088,7 +1081,7 @@ kern_kldunload(struct thread *td, int fileid, int flags)
return (error);
CURVNET_SET(TD_TO_VNET(td));
KLD_LOCK();
sx_xlock(&kld_sx);
lf = linker_find_file_by_id(fileid);
if (lf) {
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
@ -1119,13 +1112,13 @@ kern_kldunload(struct thread *td, int fileid, int flags)
#ifdef HWPMC_HOOKS
if (error == 0) {
KLD_DOWNGRADE();
sx_downgrade(&kld_sx);
PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm);
KLD_UNLOCK_READ();
sx_sunlock(&kld_sx);
} else
KLD_UNLOCK();
sx_xunlock(&kld_sx);
#else
KLD_UNLOCK();
sx_xunlock(&kld_sx);
#endif
CURVNET_RESTORE();
return (error);
@ -1169,13 +1162,13 @@ sys_kldfind(struct thread *td, struct kldfind_args *uap)
goto out;
filename = linker_basename(pathname);
KLD_LOCK();
sx_xlock(&kld_sx);
lf = linker_find_file_by_name(filename);
if (lf)
td->td_retval[0] = lf->id;
else
error = ENOENT;
KLD_UNLOCK();
sx_xunlock(&kld_sx);
out:
free(pathname, M_TEMP);
return (error);
@ -1193,7 +1186,7 @@ sys_kldnext(struct thread *td, struct kldnext_args *uap)
return (error);
#endif
KLD_LOCK();
sx_xlock(&kld_sx);
if (uap->fileid == 0)
lf = TAILQ_FIRST(&linker_files);
else {
@ -1214,7 +1207,7 @@ sys_kldnext(struct thread *td, struct kldnext_args *uap)
else
td->td_retval[0] = 0;
out:
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
@ -1253,10 +1246,10 @@ kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat)
return (error);
#endif
KLD_LOCK();
sx_xlock(&kld_sx);
lf = linker_find_file_by_id(fileid);
if (lf == NULL) {
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (ENOENT);
}
@ -1274,7 +1267,7 @@ kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat)
if (namelen > MAXPATHLEN)
namelen = MAXPATHLEN;
bcopy(lf->pathname, &stat->pathname[0], namelen);
KLD_UNLOCK();
sx_xunlock(&kld_sx);
td->td_retval[0] = 0;
return (0);
@ -1293,7 +1286,7 @@ sys_kldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
return (error);
#endif
KLD_LOCK();
sx_xlock(&kld_sx);
lf = linker_find_file_by_id(uap->fileid);
if (lf) {
MOD_SLOCK;
@ -1305,7 +1298,7 @@ sys_kldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
MOD_SUNLOCK;
} else
error = ENOENT;
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
@ -1333,7 +1326,7 @@ sys_kldsym(struct thread *td, struct kldsym_args *uap)
symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
goto out;
KLD_LOCK();
sx_xlock(&kld_sx);
if (uap->fileid != 0) {
lf = linker_find_file_by_id(uap->fileid);
if (lf == NULL)
@ -1359,7 +1352,7 @@ sys_kldsym(struct thread *td, struct kldsym_args *uap)
if (lf == NULL)
error = ENOENT;
}
KLD_UNLOCK();
sx_xunlock(&kld_sx);
out:
free(symstr, M_TEMP);
return (error);
@ -1468,6 +1461,7 @@ linker_preload(void *arg)
error = 0;
modptr = NULL;
sx_xlock(&kld_sx);
while ((modptr = preload_search_next_name(modptr)) != NULL) {
modname = (char *)preload_search_info(modptr, MODINFO_NAME);
modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
@ -1649,6 +1643,7 @@ linker_preload(void *arg)
TAILQ_REMOVE(&depended_files, lf, loaded);
linker_file_unload(lf, LINKER_UNLOAD_FORCE);
}
sx_xunlock(&kld_sx);
/* woohoo! we made it! */
}
@ -1948,7 +1943,7 @@ linker_hwpmc_list_objects(void)
int i, nmappings;
nmappings = 0;
KLD_LOCK_READ();
sx_slock(&kld_sx);
TAILQ_FOREACH(lf, &linker_files, link)
nmappings++;
@ -1963,7 +1958,7 @@ linker_hwpmc_list_objects(void)
kobase[i].pm_address = (uintptr_t)lf->address;
i++;
}
KLD_UNLOCK_READ();
sx_sunlock(&kld_sx);
KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?"));
@ -1989,7 +1984,7 @@ linker_load_module(const char *kldname, const char *modname,
char *pathname;
int error;
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
if (modname == NULL) {
/*
* We have to load KLD
@ -2063,7 +2058,7 @@ linker_load_dependencies(linker_file_t lf)
/*
* All files are dependant on /kernel.
*/
KLD_LOCK_ASSERT();
sx_assert(&kld_sx, SA_XLOCKED);
if (linker_kernel_file) {
linker_kernel_file->refs++;
error = linker_file_add_dependency(lf, linker_kernel_file);
@ -2155,16 +2150,16 @@ sysctl_kern_function_list(SYSCTL_HANDLER_ARGS)
error = sysctl_wire_old_buffer(req, 0);
if (error != 0)
return (error);
KLD_LOCK();
sx_xlock(&kld_sx);
TAILQ_FOREACH(lf, &linker_files, link) {
error = LINKER_EACH_FUNCTION_NAME(lf,
sysctl_kern_function_list_iterate, req);
if (error) {
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (error);
}
}
KLD_UNLOCK();
sx_xunlock(&kld_sx);
return (SYSCTL_OUT(req, "", 1));
}