From 33eee869d3672e9b12f9f3b853416db12a3b0f0b Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Wed, 15 Mar 2006 11:15:06 +0100 Subject: [PATCH] [libmultipath] a bit of code reorganisation o locking primitives moved to libmultipath/lock.[ch] o waiter threads control primitives moved to libmultipath/waiter.[ch] o update_multipath() and queue_mode_{add,del}_path() moved to libmultipath/structs_vec.c --- libmultipath/Makefile | 1 + libmultipath/lock.c | 8 ++ libmultipath/lock.h | 22 +++ libmultipath/structs.c | 1 + libmultipath/structs.h | 4 +- libmultipath/structs_vec.c | 88 ++++++++++++ libmultipath/structs_vec.h | 14 +- libmultipath/waiter.c | 234 +++++++++++++++++++++++++++++++ libmultipath/waiter.h | 20 +++ multipathd/main.c | 337 +-------------------------------------------- 10 files changed, 383 insertions(+), 346 deletions(-) create mode 100644 libmultipath/lock.c create mode 100644 libmultipath/lock.h create mode 100644 libmultipath/waiter.c create mode 100644 libmultipath/waiter.h diff --git a/libmultipath/Makefile b/libmultipath/Makefile index e5d5b10..5d8c586 100644 --- a/libmultipath/Makefile +++ b/libmultipath/Makefile @@ -18,6 +18,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \ PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe) ifeq ($(strip $(DAEMON)),1) + OBJS += lock.o waiter.o CFLAGS += -DDAEMON CLEAN = $(shell if [ "x$(PREVBUILD)" = "x" ]; then echo clean; fi) else diff --git a/libmultipath/lock.c b/libmultipath/lock.c new file mode 100644 index 0000000..0ca8783 --- /dev/null +++ b/libmultipath/lock.c @@ -0,0 +1,8 @@ +#include +#include "lock.h" + +void cleanup_lock (void * data) +{ + unlock((pthread_mutex_t *)data); +} + diff --git a/libmultipath/lock.h b/libmultipath/lock.h new file mode 100644 index 0000000..6afecda --- /dev/null +++ b/libmultipath/lock.h @@ -0,0 +1,22 @@ +#ifndef _LOCK_H +#define _LOCK_H + +#ifdef LCKDBG +#define lock(a) \ + fprintf(stderr, "%s:%s(%i) lock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \ + pthread_mutex_lock(a) +#define unlock(a) \ + fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \ + pthread_mutex_unlock(a) +#define lock_cleanup_pop(a) \ + fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \ + pthread_cleanup_pop(1); +#else +#define lock(a) pthread_mutex_lock(a) +#define unlock(a) pthread_mutex_unlock(a) +#define lock_cleanup_pop(a) pthread_cleanup_pop(1); +#endif + +void cleanup_lock (void * data); + +#endif /* _LOCK_H */ diff --git a/libmultipath/structs.c b/libmultipath/structs.c index 024e790..af1a9a7 100644 --- a/libmultipath/structs.c +++ b/libmultipath/structs.c @@ -16,6 +16,7 @@ #include "debug.h" #include "structs_vec.h" #include "blacklist.h" +#include "waiter.h" struct path * alloc_path (void) diff --git a/libmultipath/structs.h b/libmultipath/structs.h index 2b96cfb..a8f37aa 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -142,7 +142,7 @@ struct multipath { struct mpentry * mpe; struct hwentry * hwe; - /* daemon store a data blob for DM event waiter threads */ + /* threads */ void * waiter; /* stats */ @@ -189,4 +189,4 @@ int pathcount (struct multipath *, int); char sysfs_path[FILE_NAME_SIZE]; -#endif +#endif /* _STRUCTS_H */ diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c index 86bf2a5..b0dc095 100644 --- a/libmultipath/structs_vec.c +++ b/libmultipath/structs_vec.c @@ -14,6 +14,7 @@ #include "config.h" #include "propsel.h" #include "discovery.h" +#include "waiter.h" /* @@ -382,3 +383,90 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec) return count; } +int update_multipath (struct vectors *vecs, char *mapname) +{ + struct multipath *mpp; + struct pathgroup *pgp; + struct path *pp; + int i, j; + int r = 1; + + mpp = find_mp_by_alias(vecs->mpvec, mapname); + + if (!mpp) + goto out; + + free_pgvec(mpp->pg, KEEP_PATHS); + mpp->pg = NULL; + + if (setup_multipath(vecs, mpp)) + goto out; /* mpp freed in setup_multipath */ + + /* + * compare checkers states with DM states + */ + vector_foreach_slot (mpp->pg, pgp, i) { + vector_foreach_slot (pgp->paths, pp, j) { + if (pp->dmstate != PSTATE_FAILED) + continue; + + if (pp->state != PATH_DOWN) { + int oldstate = pp->state; + condlog(2, "%s: mark as failed", pp->dev_t); + mpp->stat_path_failures++; + pp->state = PATH_DOWN; + if (oldstate == PATH_UP || + oldstate == PATH_GHOST) + update_queue_mode_del_path(mpp); + + /* + * if opportune, + * schedule the next check earlier + */ + if (pp->tick > conf->checkint) + pp->tick = conf->checkint; + } + } + } + r = 0; +out: + if (r) + condlog(0, "failed to update multipath"); + return r; +} + +/* + * mpp->no_path_retry: + * -2 (QUEUE) : queue_if_no_path enabled, never turned off + * -1 (FAIL) : fail_if_no_path + * 0 (UNDEF) : nothing + * >0 : queue_if_no_path enabled, turned off after polling n times + */ +void update_queue_mode_del_path(struct multipath *mpp) +{ + if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) { + /* + * Enter retry mode. + * meaning of +1: retry_tick may be decremented in + * checkerloop before starting retry. + */ + mpp->stat_queueing_timeouts++; + mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1; + condlog(1, "%s: Entering recovery mode: max_retries=%d", + mpp->alias, mpp->no_path_retry); + } + condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active); +} + +void update_queue_mode_add_path(struct multipath *mpp) +{ + if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) { + /* come back to normal mode from retry mode */ + mpp->retry_tick = 0; + dm_queue_if_no_path(mpp->alias, 1); + condlog(2, "%s: queue_if_no_path enabled", mpp->alias); + condlog(1, "%s: Recovered to normal mode", mpp->alias); + } + condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active); +} + diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h index 348e9e5..81d9eaa 100644 --- a/libmultipath/structs_vec.h +++ b/libmultipath/structs_vec.h @@ -9,17 +9,6 @@ struct vectors { vector mpvec; }; -#if DAEMON -struct event_thread { - struct dm_task *dmt; - pthread_t thread; - int event_nr; - char mapname[WWID_SIZE]; - struct vectors *vecs; - struct multipath *mpp; -}; -#endif - typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *); typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *); @@ -44,5 +33,8 @@ struct multipath * add_map_without_path (struct vectors * vecs, start_waiter_thread_func *start_waiter); struct multipath * add_map_with_path (struct vectors * vecs, struct path * pp, int add_vec); +int update_multipath (struct vectors *vecs, char *mapname); +void update_queue_mode_del_path(struct multipath *mpp); +void update_queue_mode_add_path(struct multipath *mpp); #endif /* _STRUCTS_VEC_H */ diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c new file mode 100644 index 0000000..75ed90c --- /dev/null +++ b/libmultipath/waiter.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2004, 2005 Christophe Varoqui + * Copyright (c) 2005 Kiyoshi Ueda, NEC + * Copyright (c) 2005 Benjamin Marzinski, Redhat + * Copyright (c) 2005 Edward Goggin, EMC + */ +#include +#include +#include +#include +#include + +#include "vector.h" +#include "memory.h" +#include "checkers.h" +#include "structs.h" +#include "structs_vec.h" +#include "devmapper.h" +#include "debug.h" +#include "lock.h" +#include "waiter.h" + +struct event_thread *alloc_waiter (void) +{ + + struct event_thread *wp; + + wp = (struct event_thread *)MALLOC(sizeof(struct event_thread)); + + return wp; +} + +void free_waiter (void *data) +{ + struct event_thread *wp = (struct event_thread *)data; + + /* + * indicate in mpp that the wp is already freed storage + */ + lock(wp->vecs->lock); + + if (wp->mpp) + /* + * be careful, mpp may already be freed -- null if so + */ + wp->mpp->waiter = NULL; + else + condlog(3, "free_waiter, mpp freed before wp=%p,", wp); + + unlock(wp->vecs->lock); + + if (wp->dmt) + dm_task_destroy(wp->dmt); + + FREE(wp); +} + +void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs) +{ + struct event_thread *wp = (struct event_thread *)mpp->waiter; + + if (!wp) { + condlog(3, "%s: no waiter thread", mpp->alias); + return; + } + condlog(2, "%s: stop event checker thread", wp->mapname); + pthread_kill((pthread_t)wp->thread, SIGUSR1); +} + +static sigset_t unblock_signals(void) +{ + sigset_t set, old; + + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGUSR1); + pthread_sigmask(SIG_UNBLOCK, &set, &old); + return old; +} + +/* + * returns the reschedule delay + * negative means *stop* + */ +int waiteventloop (struct event_thread *waiter) +{ + sigset_t set; + int event_nr; + int r; + + if (!waiter->event_nr) + waiter->event_nr = dm_geteventnr(waiter->mapname); + + if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) { + condlog(0, "%s: devmap event #%i dm_task_create error", + waiter->mapname, waiter->event_nr); + return 1; + } + + if (!dm_task_set_name(waiter->dmt, waiter->mapname)) { + condlog(0, "%s: devmap event #%i dm_task_set_name error", + waiter->mapname, waiter->event_nr); + dm_task_destroy(waiter->dmt); + return 1; + } + + if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt, + waiter->event_nr)) { + condlog(0, "%s: devmap event #%i dm_task_set_event_nr error", + waiter->mapname, waiter->event_nr); + dm_task_destroy(waiter->dmt); + return 1; + } + + dm_task_no_open_count(waiter->dmt); + + /* accept wait interruption */ + set = unblock_signals(); + + /* interruption spits messages */ + dm_shut_log(); + + /* wait */ + r = dm_task_run(waiter->dmt); + + /* wait is over : event or interrupt */ + pthread_sigmask(SIG_SETMASK, &set, NULL); + //dm_restore_log(); + + if (!r) /* wait interrupted by signal */ + return -1; + + dm_task_destroy(waiter->dmt); + waiter->dmt = NULL; + waiter->event_nr++; + + /* + * upon event ... + */ + while (1) { + condlog(3, "%s: devmap event #%i", + waiter->mapname, waiter->event_nr); + + /* + * event might be : + * + * 1) a table reload, which means our mpp structure is + * obsolete : refresh it through update_multipath() + * 2) a path failed by DM : mark as such through + * update_multipath() + * 3) map has gone away : stop the thread. + * 4) a path reinstate : nothing to do + * 5) a switch group : nothing to do + */ + pthread_cleanup_push(cleanup_lock, waiter->vecs->lock); + lock(waiter->vecs->lock); + r = update_multipath(waiter->vecs, waiter->mapname); + lock_cleanup_pop(waiter->vecs->lock); + + if (r) + return -1; /* stop the thread */ + + event_nr = dm_geteventnr(waiter->mapname); + + if (waiter->event_nr == event_nr) + return 1; /* upon problem reschedule 1s later */ + + waiter->event_nr = event_nr; + } + return -1; /* never reach there */ +} + +void *waitevent (void *et) +{ + int r; + struct event_thread *waiter; + + mlockall(MCL_CURRENT | MCL_FUTURE); + + waiter = (struct event_thread *)et; + pthread_cleanup_push(free_waiter, et); + + while (1) { + r = waiteventloop(waiter); + + if (r < 0) + break; + + sleep(r); + } + + pthread_cleanup_pop(1); + return NULL; +} + +int start_waiter_thread (struct multipath *mpp, struct vectors *vecs) +{ + pthread_attr_t attr; + struct event_thread *wp; + + if (!mpp) + return 0; + + if (pthread_attr_init(&attr)) + goto out; + + pthread_attr_setstacksize(&attr, 32 * 1024); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + wp = alloc_waiter(); + + if (!wp) + goto out; + + mpp->waiter = (void *)wp; + strncpy(wp->mapname, mpp->alias, WWID_SIZE); + wp->vecs = vecs; + wp->mpp = mpp; + + if (pthread_create(&wp->thread, &attr, waitevent, wp)) { + condlog(0, "%s: cannot create event checker", wp->mapname); + goto out1; + } + condlog(2, "%s: event checker started", wp->mapname); + + return 0; +out1: + free_waiter(wp); + mpp->waiter = NULL; +out: + condlog(0, "failed to start waiter thread"); + return 1; +} + diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h new file mode 100644 index 0000000..468ce5f --- /dev/null +++ b/libmultipath/waiter.h @@ -0,0 +1,20 @@ +#ifndef _WAITER_H +#define _WAITER_H + +struct event_thread { + struct dm_task *dmt; + pthread_t thread; + int event_nr; + char mapname[WWID_SIZE]; + struct vectors *vecs; + struct multipath *mpp; +}; + +struct event_thread * alloc_waiter (void); +void free_waiter (void *data); +void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs); +int start_waiter_thread (struct multipath *mpp, struct vectors *vecs); +int waiteventloop (struct event_thread *waiter); +void *waitevent (void *et); + +#endif /* _WAITER_H */ diff --git a/multipathd/main.c b/multipathd/main.c index 55a2c49..939fdd9 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -55,6 +55,8 @@ #include "uxclnt.h" #include "cli.h" #include "cli_handlers.h" +#include "lock.h" +#include "waiter.h" #define FILE_NAME_SIZE 256 #define CMDSIZE 160 @@ -62,122 +64,13 @@ #define LOG_MSG(a,b) \ if (strlen(b)) condlog(a, "%s: %s", pp->dev_t, b); -#ifdef LCKDBG -#define lock(a) \ - fprintf(stderr, "%s:%s(%i) lock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \ - pthread_mutex_lock(a) -#define unlock(a) \ - fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \ - pthread_mutex_unlock(a) -#define lock_cleanup_pop(a) \ - fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \ - pthread_cleanup_pop(1); -#else -#define lock(a) pthread_mutex_lock(a) -#define unlock(a) pthread_mutex_unlock(a) -#define lock_cleanup_pop(a) pthread_cleanup_pop(1); -#endif - pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER; /* - * structs + * global copy of vecs for use in sig handlers */ -struct vectors * gvecs; /* global copy of vecs for use in sig handlers */ - -static struct event_thread * -alloc_waiter (void) -{ - - struct event_thread * wp; - - wp = (struct event_thread *)MALLOC(sizeof(struct event_thread)); - - return wp; -} - -static void -free_waiter (void * data) -{ - struct event_thread * wp = (struct event_thread *)data; - - /* - * indicate in mpp that the wp is already freed storage - */ - lock(wp->vecs->lock); - - if (wp->mpp) - /* - * be careful, mpp may already be freed -- null if so - */ - wp->mpp->waiter = NULL; - else - condlog(3, "free_waiter, mpp freed before wp=%p,", wp); - - unlock(wp->vecs->lock); - - if (wp->dmt) - dm_task_destroy(wp->dmt); - - FREE(wp); -} - -static void -stop_waiter_thread (struct multipath * mpp, struct vectors * vecs) -{ - struct event_thread * wp = (struct event_thread *)mpp->waiter; - - if (!wp) { - condlog(3, "%s: no waiter thread", mpp->alias); - return; - } - condlog(2, "%s: stop event checker thread", wp->mapname); - pthread_kill((pthread_t)wp->thread, SIGUSR1); -} - -static void -cleanup_lock (void * data) -{ - unlock((pthread_mutex_t *)data); -} - -/* - * mpp->no_path_retry: - * -2 (QUEUE) : queue_if_no_path enabled, never turned off - * -1 (FAIL) : fail_if_no_path - * 0 (UNDEF) : nothing - * >0 : queue_if_no_path enabled, turned off after polling n times - */ -static void -update_queue_mode_del_path(struct multipath *mpp) -{ - if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) { - /* - * Enter retry mode. - * meaning of +1: retry_tick may be decremented in - * checkerloop before starting retry. - */ - mpp->stat_queueing_timeouts++; - mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1; - condlog(1, "%s: Entering recovery mode: max_retries=%d", - mpp->alias, mpp->no_path_retry); - } - condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active); -} - -static void -update_queue_mode_add_path(struct multipath *mpp) -{ - if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) { - /* come back to normal mode from retry mode */ - mpp->retry_tick = 0; - dm_queue_if_no_path(mpp->alias, 1); - condlog(2, "%s: queue_if_no_path enabled", mpp->alias); - condlog(1, "%s: Recovered to normal mode", mpp->alias); - } - condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active); -} +struct vectors * gvecs; static int need_switch_pathgroup (struct multipath * mpp, int refresh) @@ -253,228 +146,6 @@ coalesce_maps(struct vectors *vecs, vector nmpv) return 0; } -static int -update_multipath (struct vectors *vecs, char *mapname) -{ - struct multipath *mpp; - struct pathgroup *pgp; - struct path *pp; - int i, j; - int r = 1; - - mpp = find_mp_by_alias(vecs->mpvec, mapname); - - if (!mpp) - goto out; - - free_pgvec(mpp->pg, KEEP_PATHS); - mpp->pg = NULL; - - if (setup_multipath(vecs, mpp)) - goto out; /* mpp freed in setup_multipath */ - - /* - * compare checkers states with DM states - */ - vector_foreach_slot (mpp->pg, pgp, i) { - vector_foreach_slot (pgp->paths, pp, j) { - if (pp->dmstate != PSTATE_FAILED) - continue; - - if (pp->state != PATH_DOWN) { - int oldstate = pp->state; - condlog(2, "%s: mark as failed", pp->dev_t); - mpp->stat_path_failures++; - pp->state = PATH_DOWN; - if (oldstate == PATH_UP || - oldstate == PATH_GHOST) - update_queue_mode_del_path(mpp); - - /* - * if opportune, - * schedule the next check earlier - */ - if (pp->tick > conf->checkint) - pp->tick = conf->checkint; - } - } - } - r = 0; -out: - if (r) - condlog(0, "failed to update multipath"); - - return r; -} - -static sigset_t unblock_signals(void) -{ - sigset_t set, old; - - sigemptyset(&set); - sigaddset(&set, SIGHUP); - sigaddset(&set, SIGUSR1); - pthread_sigmask(SIG_UNBLOCK, &set, &old); - return old; -} - -/* - * returns the reschedule delay - * negative means *stop* - */ -static int -waiteventloop (struct event_thread * waiter) -{ - sigset_t set; - int event_nr; - int r; - - if (!waiter->event_nr) - waiter->event_nr = dm_geteventnr(waiter->mapname); - - if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) { - condlog(0, "%s: devmap event #%i dm_task_create error", - waiter->mapname, waiter->event_nr); - return 1; - } - - if (!dm_task_set_name(waiter->dmt, waiter->mapname)) { - condlog(0, "%s: devmap event #%i dm_task_set_name error", - waiter->mapname, waiter->event_nr); - dm_task_destroy(waiter->dmt); - return 1; - } - - if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt, - waiter->event_nr)) { - condlog(0, "%s: devmap event #%i dm_task_set_event_nr error", - waiter->mapname, waiter->event_nr); - dm_task_destroy(waiter->dmt); - return 1; - } - - dm_task_no_open_count(waiter->dmt); - - /* accept wait interruption */ - set = unblock_signals(); - - /* interruption spits messages */ - dm_shut_log(); - - /* wait */ - r = dm_task_run(waiter->dmt); - - /* wait is over : event or interrupt */ - pthread_sigmask(SIG_SETMASK, &set, NULL); - //dm_restore_log(); - - if (!r) /* wait interrupted by signal */ - return -1; - - dm_task_destroy(waiter->dmt); - waiter->dmt = NULL; - waiter->event_nr++; - - /* - * upon event ... - */ - while (1) { - condlog(3, "%s: devmap event #%i", - waiter->mapname, waiter->event_nr); - - /* - * event might be : - * - * 1) a table reload, which means our mpp structure is - * obsolete : refresh it through update_multipath() - * 2) a path failed by DM : mark as such through - * update_multipath() - * 3) map has gone away : stop the thread. - * 4) a path reinstate : nothing to do - * 5) a switch group : nothing to do - */ - pthread_cleanup_push(cleanup_lock, waiter->vecs->lock); - lock(waiter->vecs->lock); - r = update_multipath(waiter->vecs, waiter->mapname); - lock_cleanup_pop(waiter->vecs->lock); - - if (r) - return -1; /* stop the thread */ - - event_nr = dm_geteventnr(waiter->mapname); - - if (waiter->event_nr == event_nr) - return 1; /* upon problem reschedule 1s later */ - - waiter->event_nr = event_nr; - } - return -1; /* never reach there */ -} - -static void * -waitevent (void * et) -{ - int r; - struct event_thread *waiter; - - mlockall(MCL_CURRENT | MCL_FUTURE); - - waiter = (struct event_thread *)et; - pthread_cleanup_push(free_waiter, et); - - while (1) { - r = waiteventloop(waiter); - - if (r < 0) - break; - - sleep(r); - } - - pthread_cleanup_pop(1); - return NULL; -} - -static int -start_waiter_thread (struct multipath * mpp, struct vectors * vecs) -{ - pthread_attr_t attr; - struct event_thread * wp; - - if (!mpp) - return 0; - - if (pthread_attr_init(&attr)) - goto out; - - pthread_attr_setstacksize(&attr, 32 * 1024); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - wp = alloc_waiter(); - - if (!wp) - goto out; - - mpp->waiter = (void *)wp; - strncpy(wp->mapname, mpp->alias, WWID_SIZE); - wp->vecs = vecs; - wp->mpp = mpp; - - if (pthread_create(&wp->thread, &attr, waitevent, wp)) { - condlog(0, "%s: cannot create event checker", wp->mapname); - goto out1; - } - condlog(2, "%s: event checker started", wp->mapname); - - return 0; -out1: - free_waiter(wp); - mpp->waiter = NULL; -out: - condlog(0, "failed to start waiter thread"); - return 1; -} - static void sync_map_state(struct multipath *mpp) { -- 2.7.4