diff options
author | Hannes Reinecke <hare@suse.de> | 2010-04-26 10:15:05 +0200 |
---|---|---|
committer | Hannes Reinecke <hare@suse.de> | 2011-05-03 09:54:40 +0200 |
commit | 323090f890af84c5063ff43c44d04ccde475963e (patch) | |
tree | a3f78202da87dd968b399857814b5ed0aef964e6 | |
parent | dbf3c1cf2cd67be810176226bdc75904e51357eb (diff) | |
download | multipath-tools-323090f890af84c5063ff43c44d04ccde475963e.tar.gz |
Use refcounting for checkers
The checkers are not accessed directly but rather via private
copies of the original instance. However, the pointers in the
private copy point to the original ones, making them potentially
invalid when the original instance is deleted.
So we need to introduce proper refcounting here.
Signed-off-by: Hannes Reinecke <hare@suse.de>
-rw-r--r-- | libmultipath/checkers.c | 74 | ||||
-rw-r--r-- | libmultipath/checkers.h | 2 |
2 files changed, 56 insertions, 20 deletions
diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c index 5cc31d2..3bc3e5a 100644 --- a/libmultipath/checkers.c +++ b/libmultipath/checkers.c @@ -2,6 +2,7 @@ #include <string.h> #include <stddef.h> #include <dlfcn.h> +#include <sys/stat.h> #include "debug.h" #include "checkers.h" @@ -34,11 +35,34 @@ int init_checkers (void) struct checker * alloc_checker (void) { - return MALLOC(sizeof(struct checker)); + struct checker *c; + + c = MALLOC(sizeof(struct checker)); + if (c) { + INIT_LIST_HEAD(&c->node); + c->refcount = 1; + } + return c; } void free_checker (struct checker * c) { + if (!c) + return; + c->refcount--; + if (c->refcount) { + condlog(3, "%s checker refcount %d", + c->name, c->refcount); + return; + } + condlog(3, "unloading %s checker", c->name); + list_del(&c->node); + if (c->handle) { + if (dlclose(c->handle) != 0) { + condlog(0, "Cannot unload checker %s: %s", + c->name, dlerror()); + } + } FREE(c); } @@ -48,7 +72,6 @@ void cleanup_checkers (void) struct checker * checker_temp; list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) { - list_del(&checker_loop->node); free_checker(checker_loop); } } @@ -67,45 +90,50 @@ struct checker * checker_lookup (char * name) struct checker * add_checker (char * name) { char libname[LIB_CHECKER_NAMELEN]; - void * handle; + struct stat stbuf; struct checker * c; char *errstr; c = alloc_checker(); if (!c) return NULL; + snprintf(c->name, CHECKER_NAME_LEN, "%s", name); snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so", conf->multipath_dir, name); + if (stat(libname,&stbuf) < 0) { + condlog(0,"Checker '%s' not found in %s", + name, conf->multipath_dir); + goto out; + } condlog(3, "loading %s checker", libname); - handle = dlopen(libname, RTLD_NOW); - errstr = dlerror(); - if (errstr != NULL) - condlog(0, "A dynamic linking error occurred: (%s)", errstr); - if (!handle) + c->handle = dlopen(libname, RTLD_NOW); + if (!c->handle) { + if ((errstr = dlerror()) != NULL) + condlog(0, "A dynamic linking error occurred: (%s)", + errstr); goto out; - - c->check = (int (*)(struct checker *)) dlsym(handle, "libcheck_check"); + } + c->check = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_check"); errstr = dlerror(); if (errstr != NULL) - condlog(0, "A dynamic linking error occurred: (%s)", errstr); + condlog(0, "A dynamic linking error occurred: (%s)", errstr); if (!c->check) goto out; - c->init = (int (*)(struct checker *)) dlsym(handle, "libcheck_init"); + c->init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_init"); errstr = dlerror(); if (errstr != NULL) - condlog(0, "A dynamic linking error occurred: (%s)", errstr); + condlog(0, "A dynamic linking error occurred: (%s)", errstr); if (!c->init) goto out; - c->free = (void (*)(struct checker *)) dlsym(handle, "libcheck_free"); + c->free = (void (*)(struct checker *)) dlsym(c->handle, "libcheck_free"); errstr = dlerror(); if (errstr != NULL) - condlog(0, "A dynamic linking error occurred: (%s)", errstr); + condlog(0, "A dynamic linking error occurred: (%s)", errstr); if (!c->free) goto out; - snprintf(c->name, CHECKER_NAME_LEN, "%s", name); c->fd = 0; c->sync = 1; list_add(&c->node, &checkers); @@ -146,11 +174,15 @@ int checker_init (struct checker * c, void ** mpctxt_addr) return c->init(c); } -void checker_put (struct checker * c) +void checker_put (struct checker * dst) { - if (c->free) - c->free(c); - memset(c, 0x0, sizeof(struct checker)); + struct checker * src; + + src = checker_lookup(dst->name); + if (dst->free) + dst->free(dst); + memset(dst, 0x0, sizeof(struct checker)); + free_checker(src); } int checker_check (struct checker * c) @@ -203,4 +235,6 @@ void checker_get (struct checker * dst, char * name) dst->check = src->check; dst->init = src->init; dst->free = src->free; + dst->handle = NULL; + src->refcount++; } diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h index e61280d..5a96165 100644 --- a/libmultipath/checkers.h +++ b/libmultipath/checkers.h @@ -80,6 +80,8 @@ enum path_check_state { struct checker { struct list_head node; + void *handle; + int refcount; int fd; int sync; unsigned int timeout; |