diff --git a/main/loader.c b/main/loader.c index 549e3f0e52..208e5a2c6f 100644 --- a/main/loader.c +++ b/main/loader.c @@ -1241,8 +1241,17 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f } if (!mod->flags.running || mod->flags.declined) { - ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name); - error = 1; + /* If the user asks to unload a module that didn't load, obey. + * Otherwise, we never dlclose() modules that fail to load, + * which means if the module (shared object) is updated, + * we can't load the updated module since we never dlclose()'d it. + * Accordingly, obey the unload request so we can load the module + * from scratch next time. + */ + ast_log(LOG_NOTICE, "Unloading module '%s' that previously declined to load\n", resource_name); + error = 0; + res = 0; + goto exit; /* Skip all the intervening !error checks, only the last one is relevant. */ } if (!error && (mod->usecount > 0)) { @@ -1284,6 +1293,7 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f if (!error) mod->flags.running = mod->flags.declined = 0; +exit: AST_DLLIST_UNLOCK(&module_list); if (!error) { @@ -1823,7 +1833,18 @@ prestart_error: int ast_load_resource(const char *resource_name) { + struct ast_module *mod; int res; + + /* If we're trying to load a module that previously declined to load, + * transparently unload it first so we dlclose, then dlopen it afresh. + * Otherwise, we won't actually load a (potentially) updated module. */ + mod = find_resource(resource_name, 0); + if (mod && mod->flags.declined) { + ast_debug(1, "Module %s previously declined to load, unloading it first before loading again\n", resource_name); + ast_unload_resource(resource_name, 0); + } + AST_DLLIST_LOCK(&module_list); res = load_resource(resource_name, 0, NULL, 0, 0); if (!res) {