From d87a62d43f0b94cac4a3624b67a86a562bc6abd1 Mon Sep 17 00:00:00 2001 From: luigi Date: Thu, 15 Feb 2007 19:49:27 +0000 Subject: [PATCH] MFC kern_linker.c 1.133 and related changes: - push Giant into linker_reference_module(); - introduce linker_release_module(), which also takes care of proper locking. The latter also fixes a missing mtx_loc/unlock in subr_firmware.c . Apparently, digi.c is the only external client of linker_reference_module() which is a bit suspicious - perhaps dev/digi/ could make with a bit of review from someone knowledgeable to check how the function is used, and whether it could be replaced by something else. --- sys/dev/digi/digi.c | 6 +++--- sys/kern/kern_linker.c | 32 +++++++++++++++++++++++++++++++- sys/kern/subr_firmware.c | 4 +--- sys/sys/linker.h | 8 ++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/sys/dev/digi/digi.c b/sys/dev/digi/digi.c index 66f0b96a195c..8912fb15b02b 100644 --- a/sys/dev/digi/digi.c +++ b/sys/dev/digi/digi.c @@ -795,7 +795,7 @@ digi_loadmoduledata(struct digi_softc *sc) free(sym, M_TEMP); if (symptr == NULL) { printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym); - linker_file_unload(lf, LINKER_UNLOAD_FORCE); + linker_release_module(NULL, NULL, lf); return (EINVAL); } @@ -803,7 +803,7 @@ digi_loadmoduledata(struct digi_softc *sc) if (digi_mod->dm_version != DIGI_MOD_VERSION) { printf("digi_%s.ko: Invalid version %d (need %d)\n", sc->module, digi_mod->dm_version, DIGI_MOD_VERSION); - linker_file_unload(lf, LINKER_UNLOAD_FORCE); + linker_release_module(NULL, NULL, lf); return (EINVAL); } @@ -825,7 +825,7 @@ digi_loadmoduledata(struct digi_softc *sc) bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size); } - linker_file_unload(lf, LINKER_UNLOAD_FORCE); + linker_release_module(NULL, NULL, lf); return (0); } diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index ca05cc062190..bc86faf87315 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -397,14 +397,44 @@ linker_reference_module(const char *modname, struct mod_depend *verinfo, linker_file_t *result) { modlist_t mod; + int error; + mtx_lock(&Giant); if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { *result = mod->container; (*result)->refs++; + mtx_unlock(&Giant); return (0); } - return (linker_load_module(NULL, modname, NULL, verinfo, result)); + error = linker_load_module(NULL, modname, NULL, verinfo, result); + mtx_unlock(&Giant); + return (error); +} + +int +linker_release_module(const char *modname, struct mod_depend *verinfo, + linker_file_t lf) +{ + modlist_t mod; + int error; + + mtx_lock(&Giant); + if (lf == NULL) { + KASSERT(modname != NULL, + ("linker_release_module: no file or name")); + mod = modlist_lookup2(modname, verinfo); + if (mod == NULL) { + mtx_unlock(&Giant); + return (ESRCH); + } + lf = mod->container; + } else + KASSERT(modname == NULL && verinfo == NULL, + ("linker_release_module: both file and name")); + error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL); + mtx_unlock(&Giant); + return (error); } linker_file_t diff --git a/sys/kern/subr_firmware.c b/sys/kern/subr_firmware.c index 43ed1aee479a..2fe696b262c7 100644 --- a/sys/kern/subr_firmware.c +++ b/sys/kern/subr_firmware.c @@ -197,9 +197,7 @@ again: "load firmware image %s\n", __func__, imagename); return NULL; } - mtx_lock(&Giant); /* XXX */ (void) linker_reference_module(imagename, NULL, &result); - mtx_unlock(&Giant); /* XXX */ requested_load = 1; goto again; /* sort of an Algol-style for loop */ } @@ -218,7 +216,7 @@ unloadentry(void *unused1, int unused2) */ mtx_unlock(&firmware_mtx); - linker_file_unload(fp->file, LINKER_UNLOAD_NORMAL); + linker_release_module(NULL, NULL, fp->file); mtx_lock(&firmware_mtx); clearentry(fp, 0); diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 90ed2433405f..1a47587fe5ef 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -117,6 +117,14 @@ int linker_load_module(const char *_kldname, const char *_modname, int linker_reference_module(const char* _modname, struct mod_depend *_verinfo, linker_file_t* _result); +/* + * Release a reference to a module, unloading it if there are no more + * references. Note that one should either provide a module name and + * optional version info or a linker file, but not both. + */ +int linker_release_module(const char *_modname, struct mod_depend *_verinfo, + linker_file_t _file); + /* * Find a currently loaded file given its filename. */