Only load plugins once and never unload them
Its expensive to load and unload plugins all the time, so lets stop doing that. Run over the plugin directory and load all plugins and remember them all. In the future, something should watch the directory and if it changes, load the new plugins that was put there.
This commit is contained in:
@@ -40,19 +40,28 @@
|
|||||||
|
|
||||||
struct krb5_plugin {
|
struct krb5_plugin {
|
||||||
void *symbol;
|
void *symbol;
|
||||||
void *dsohandle;
|
|
||||||
struct krb5_plugin *next;
|
struct krb5_plugin *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct plugin {
|
struct plugin {
|
||||||
|
enum { DSO, SYMBOL } type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
char *path;
|
||||||
|
void *dsohandle;
|
||||||
|
} dso;
|
||||||
|
struct {
|
||||||
enum krb5_plugin_type type;
|
enum krb5_plugin_type type;
|
||||||
void *name;
|
char *name;
|
||||||
void *symbol;
|
char *symbol;
|
||||||
|
} symbol;
|
||||||
|
} u;
|
||||||
struct plugin *next;
|
struct plugin *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
|
static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
|
||||||
static struct plugin *registered = NULL;
|
static struct plugin *registered = NULL;
|
||||||
|
static int plugins_needs_scan = 1;
|
||||||
|
|
||||||
static const char *sysplugin_dirs[] = {
|
static const char *sysplugin_dirs[] = {
|
||||||
LIBDIR "/plugin/krb5",
|
LIBDIR "/plugin/krb5",
|
||||||
@@ -85,14 +94,12 @@ _krb5_plugin_get_next(struct krb5_plugin *p)
|
|||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
loadlib(krb5_context context,
|
loadlib(krb5_context context, char *path)
|
||||||
enum krb5_plugin_type type,
|
|
||||||
const char *name,
|
|
||||||
const char *lib,
|
|
||||||
struct krb5_plugin **e)
|
|
||||||
{
|
{
|
||||||
*e = calloc(1, sizeof(**e));
|
struct plugin *e;
|
||||||
if (*e == NULL) {
|
|
||||||
|
e = calloc(1, sizeof(*e));
|
||||||
|
if (e == NULL) {
|
||||||
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -103,24 +110,13 @@ loadlib(krb5_context context,
|
|||||||
#ifndef RTLD_LOCAL
|
#ifndef RTLD_LOCAL
|
||||||
#define RTLD_LOCAL 0
|
#define RTLD_LOCAL 0
|
||||||
#endif
|
#endif
|
||||||
|
e->type = DSO;
|
||||||
|
/* ignore error from dlopen, and just keep it as negative cache entry */
|
||||||
|
e->u.dso.dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY);
|
||||||
|
e->u.dso.path = path;
|
||||||
|
|
||||||
(*e)->dsohandle = dlopen(lib, RTLD_LOCAL|RTLD_LAZY);
|
e->next = registered;
|
||||||
if ((*e)->dsohandle == NULL) {
|
registered = e->next;
|
||||||
free(*e);
|
|
||||||
*e = NULL;
|
|
||||||
krb5_set_error_message(context, ENOMEM, "Failed to load %s: %s",
|
|
||||||
lib, dlerror());
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dlsym doesn't care about the type */
|
|
||||||
(*e)->symbol = dlsym((*e)->dsohandle, name);
|
|
||||||
if ((*e)->symbol == NULL) {
|
|
||||||
dlclose((*e)->dsohandle);
|
|
||||||
free(*e);
|
|
||||||
krb5_clear_error_message(context);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -146,26 +142,35 @@ krb5_plugin_register(krb5_context context,
|
|||||||
{
|
{
|
||||||
struct plugin *e;
|
struct plugin *e;
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_lock(&plugin_mutex);
|
||||||
|
|
||||||
/* check for duplicates */
|
/* check for duplicates */
|
||||||
for (e = registered; e != NULL; e = e->next)
|
for (e = registered; e != NULL; e = e->next) {
|
||||||
if (e->type == type && strcmp(e->name,name)== 0 && e->symbol == symbol)
|
if (e->type == SYMBOL &&
|
||||||
|
strcmp(e->u.symbol.name, name) == 0 &&
|
||||||
|
e->u.symbol.type == type && e->u.symbol.symbol == symbol) {
|
||||||
|
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
e = calloc(1, sizeof(*e));
|
e = calloc(1, sizeof(*e));
|
||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
|
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
||||||
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
e->type = type;
|
e->type = SYMBOL;
|
||||||
e->name = strdup(name);
|
e->u.symbol.type = type;
|
||||||
if (e->name == NULL) {
|
e->u.symbol.name = strdup(name);
|
||||||
|
if (e->u.symbol.name == NULL) {
|
||||||
|
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
||||||
free(e);
|
free(e);
|
||||||
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
e->symbol = symbol;
|
e->u.symbol.symbol = symbol;
|
||||||
|
|
||||||
HEIMDAL_MUTEX_lock(&plugin_mutex);
|
|
||||||
e->next = registered;
|
e->next = registered;
|
||||||
registered = e;
|
registered = e;
|
||||||
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
||||||
@@ -173,41 +178,19 @@ krb5_plugin_register(krb5_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code
|
static krb5_error_code
|
||||||
_krb5_plugin_find(krb5_context context,
|
load_plugins(krb5_context context)
|
||||||
enum krb5_plugin_type type,
|
|
||||||
const char *name,
|
|
||||||
struct krb5_plugin **list)
|
|
||||||
{
|
{
|
||||||
struct krb5_plugin *e;
|
struct plugin *e;
|
||||||
struct plugin *p;
|
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
char **dirs = NULL, **di;
|
char **dirs = NULL, **di;
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
char *path;
|
char *path;
|
||||||
DIR *d = NULL;
|
DIR *d = NULL;
|
||||||
|
|
||||||
*list = NULL;
|
if (!plugins_needs_scan)
|
||||||
|
return 0;
|
||||||
HEIMDAL_MUTEX_lock(&plugin_mutex);
|
plugins_needs_scan = 0;
|
||||||
|
|
||||||
for (p = registered; p != NULL; p = p->next) {
|
|
||||||
if (p->type != type || strcmp(p->name, name) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
e = calloc(1, sizeof(*e));
|
|
||||||
if (e == NULL) {
|
|
||||||
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
|
||||||
ret = ENOMEM;
|
|
||||||
krb5_set_error_message(context, ret, "malloc: out of memory");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
e->symbol = p->symbol;
|
|
||||||
e->dsohandle = NULL;
|
|
||||||
e->next = *list;
|
|
||||||
*list = e;
|
|
||||||
}
|
|
||||||
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
|
||||||
|
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
|
|
||||||
@@ -244,21 +227,83 @@ _krb5_plugin_find(krb5_context context,
|
|||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
ret = ENOMEM;
|
ret = ENOMEM;
|
||||||
krb5_set_error_message(context, ret, "malloc: out of memory");
|
krb5_set_error_message(context, ret, "malloc: out of memory");
|
||||||
goto out;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = loadlib(context, type, name, path, &e);
|
|
||||||
free(path);
|
|
||||||
if (ret)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
e->next = *list;
|
/* check if already tried */
|
||||||
*list = e;
|
for (e = registered; e != NULL; e = e->next)
|
||||||
|
if (e->type == DSO && strcmp(e->u.dso.path, path) == 0)
|
||||||
|
break;
|
||||||
|
if (e == NULL) {
|
||||||
|
ret = loadlib(context, path);
|
||||||
|
if (ret)
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
}
|
}
|
||||||
if (dirs != rk_UNCONST(sysplugin_dirs))
|
if (dirs != rk_UNCONST(sysplugin_dirs))
|
||||||
krb5_config_free_strings(dirs);
|
krb5_config_free_strings(dirs);
|
||||||
#endif /* HAVE_DLOPEN */
|
#endif /* HAVE_DLOPEN */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
add_symbol(krb5_context context, struct krb5_plugin **list, void *symbol)
|
||||||
|
{
|
||||||
|
struct krb5_plugin *e;
|
||||||
|
|
||||||
|
e = calloc(1, sizeof(*e));
|
||||||
|
if (e == NULL) {
|
||||||
|
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
e->symbol = symbol;
|
||||||
|
e->next = *list;
|
||||||
|
*list = e;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
_krb5_plugin_find(krb5_context context,
|
||||||
|
enum krb5_plugin_type type,
|
||||||
|
const char *name,
|
||||||
|
struct krb5_plugin **list)
|
||||||
|
{
|
||||||
|
struct plugin *e;
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
*list = NULL;
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_lock(&plugin_mutex);
|
||||||
|
|
||||||
|
load_plugins(context);
|
||||||
|
|
||||||
|
for (ret = 0, e = registered; e != NULL; e = e->next) {
|
||||||
|
switch(e->type) {
|
||||||
|
case DSO: {
|
||||||
|
void *sym;
|
||||||
|
if (e->u.dso.dsohandle == NULL)
|
||||||
|
continue;
|
||||||
|
sym = dlsym(e->u.dso.dsohandle, name);
|
||||||
|
if (sym)
|
||||||
|
ret = add_symbol(context, list, sym);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SYMBOL:
|
||||||
|
if (strcmp(e->u.symbol.name, name) == 0 && e->u.symbol.type == type)
|
||||||
|
ret = add_symbol(context, list, e->u.symbol.symbol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
_krb5_plugin_free(*list);
|
||||||
|
*list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HEIMDAL_MUTEX_unlock(&plugin_mutex);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (*list == NULL) {
|
if (*list == NULL) {
|
||||||
krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name);
|
krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name);
|
||||||
@@ -266,16 +311,6 @@ _krb5_plugin_find(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
|
||||||
if (dirs != rk_UNCONST(sysplugin_dirs))
|
|
||||||
krb5_config_free_strings(dirs);
|
|
||||||
if (d)
|
|
||||||
closedir(d);
|
|
||||||
_krb5_plugin_free(*list);
|
|
||||||
*list = NULL;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -284,8 +319,6 @@ _krb5_plugin_free(struct krb5_plugin *list)
|
|||||||
struct krb5_plugin *next;
|
struct krb5_plugin *next;
|
||||||
while (list) {
|
while (list) {
|
||||||
next = list->next;
|
next = list->next;
|
||||||
if (list->dsohandle)
|
|
||||||
dlclose(list->dsohandle);
|
|
||||||
free(list);
|
free(list);
|
||||||
list = next;
|
list = next;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user