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
--- /dev/null
+#include <pthread.h>
+#include "lock.h"
+
+void cleanup_lock (void * data)
+{
+ unlock((pthread_mutex_t *)data);
+}
+
--- /dev/null
+#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 */
#include "debug.h"
#include "structs_vec.h"
#include "blacklist.h"
+#include "waiter.h"
struct path *
alloc_path (void)
struct mpentry * mpe;
struct hwentry * hwe;
- /* daemon store a data blob for DM event waiter threads */
+ /* threads */
void * waiter;
/* stats */
char sysfs_path[FILE_NAME_SIZE];
-#endif
+#endif /* _STRUCTS_H */
#include "config.h"
#include "propsel.h"
#include "discovery.h"
+#include "waiter.h"
/*
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);
+}
+
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 *);
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 */
--- /dev/null
+/*
+ * 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 <unistd.h>
+#include <libdevmapper.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <signal.h>
+
+#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;
+}
+
--- /dev/null
+#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 */
#include "uxclnt.h"
#include "cli.h"
#include "cli_handlers.h"
+#include "lock.h"
+#include "waiter.h"
#define FILE_NAME_SIZE 256
#define CMDSIZE 160
#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)
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)
{