aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2010-04-26 10:15:05 +0200
committerHannes Reinecke <hare@suse.de>2011-05-03 09:54:40 +0200
commit323090f890af84c5063ff43c44d04ccde475963e (patch)
treea3f78202da87dd968b399857814b5ed0aef964e6
parentdbf3c1cf2cd67be810176226bdc75904e51357eb (diff)
downloadmultipath-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.c74
-rw-r--r--libmultipath/checkers.h2
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;