summaryrefslogtreecommitdiffstats
path: root/0009-move-waiter-code-from-libmultipath-to-multipathd.patch
diff options
context:
space:
mode:
Diffstat (limited to '0009-move-waiter-code-from-libmultipath-to-multipathd.patch')
-rw-r--r--0009-move-waiter-code-from-libmultipath-to-multipathd.patch793
1 files changed, 793 insertions, 0 deletions
diff --git a/0009-move-waiter-code-from-libmultipath-to-multipathd.patch b/0009-move-waiter-code-from-libmultipath-to-multipathd.patch
new file mode 100644
index 0000000..4012267
--- /dev/null
+++ b/0009-move-waiter-code-from-libmultipath-to-multipathd.patch
@@ -0,0 +1,793 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Mon, 5 Feb 2018 18:50:45 -0600
+Subject: [PATCH] move waiter code from libmultipath to multipathd
+
+Only multipathd uses the code in waiter.[ch] and the functions that call
+it directly, so they should all live in the multipathd directory. This
+patch is simply moving the waiter.[ch] files and the functions in
+structs_vec that use them. None of the moved code has been changed.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+---
+ libmultipath/Makefile | 2 +-
+ libmultipath/structs_vec.c | 98 ---------------------
+ libmultipath/structs_vec.h | 4 +-
+ libmultipath/waiter.c | 215 ---------------------------------------------
+ libmultipath/waiter.h | 17 ----
+ multipathd/Makefile | 2 +-
+ multipathd/main.c | 96 ++++++++++++++++++++
+ multipathd/waiter.c | 215 +++++++++++++++++++++++++++++++++++++++++++++
+ multipathd/waiter.h | 17 ++++
+ 9 files changed, 332 insertions(+), 334 deletions(-)
+ delete mode 100644 libmultipath/waiter.c
+ delete mode 100644 libmultipath/waiter.h
+ create mode 100644 multipathd/waiter.c
+ create mode 100644 multipathd/waiter.h
+
+diff --git a/libmultipath/Makefile b/libmultipath/Makefile
+index 6447d8d..a1005b2 100644
+--- a/libmultipath/Makefile
++++ b/libmultipath/Makefile
+@@ -42,7 +42,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \
+ pgpolicies.o debug.o defaults.o uevent.o time-util.o \
+ switchgroup.o uxsock.o print.o alias.o log_pthread.o \
+ log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
+- lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
++ lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
+ io_err_stat.o
+
+ all: $(LIBS)
+diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
+index abf5327..77b045b 100644
+--- a/libmultipath/structs_vec.c
++++ b/libmultipath/structs_vec.c
+@@ -10,7 +10,6 @@
+ #include "structs.h"
+ #include "structs_vec.h"
+ #include "sysfs.h"
+-#include "waiter.h"
+ #include "devmapper.h"
+ #include "dmparser.h"
+ #include "propsel.h"
+@@ -107,17 +106,6 @@ void orphan_paths(vector pathvec, struct multipath *mpp)
+ }
+ }
+
+-static void
+-set_multipath_wwid (struct multipath * mpp)
+-{
+- if (strlen(mpp->wwid))
+- return;
+-
+- dm_get_uuid(mpp->alias, mpp->wwid);
+-}
+-
+-#define PURGE_VEC 1
+-
+ void
+ remove_map(struct multipath * mpp, struct vectors * vecs, int purge_vec)
+ {
+@@ -379,92 +367,6 @@ sync_map_state(struct multipath *mpp)
+ }
+ }
+
+-int
+-update_map (struct multipath *mpp, struct vectors *vecs)
+-{
+- int retries = 3;
+- char params[PARAMS_SIZE] = {0};
+-
+-retry:
+- condlog(4, "%s: updating new map", mpp->alias);
+- if (adopt_paths(vecs->pathvec, mpp)) {
+- condlog(0, "%s: failed to adopt paths for new map update",
+- mpp->alias);
+- retries = -1;
+- goto fail;
+- }
+- verify_paths(mpp, vecs);
+- mpp->action = ACT_RELOAD;
+-
+- extract_hwe_from_path(mpp);
+- if (setup_map(mpp, params, PARAMS_SIZE)) {
+- condlog(0, "%s: failed to setup new map in update", mpp->alias);
+- retries = -1;
+- goto fail;
+- }
+- if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
+- condlog(0, "%s: map_udate sleep", mpp->alias);
+- sleep(1);
+- goto retry;
+- }
+- dm_lib_release();
+-
+-fail:
+- if (setup_multipath(vecs, mpp))
+- return 1;
+-
+- sync_map_state(mpp);
+-
+- if (retries < 0)
+- condlog(0, "%s: failed reload in new map update", mpp->alias);
+- return 0;
+-}
+-
+-struct multipath *add_map_without_path (struct vectors *vecs, char *alias)
+-{
+- struct multipath * mpp = alloc_multipath();
+- struct config *conf;
+-
+- if (!mpp)
+- return NULL;
+- if (!alias) {
+- FREE(mpp);
+- return NULL;
+- }
+-
+- mpp->alias = STRDUP(alias);
+-
+- if (dm_get_info(mpp->alias, &mpp->dmi)) {
+- condlog(3, "%s: cannot access table", mpp->alias);
+- goto out;
+- }
+- set_multipath_wwid(mpp);
+- conf = get_multipath_config();
+- mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
+- put_multipath_config(conf);
+-
+- if (update_multipath_table(mpp, vecs->pathvec, 1))
+- goto out;
+- if (update_multipath_status(mpp))
+- goto out;
+-
+- if (!vector_alloc_slot(vecs->mpvec))
+- goto out;
+-
+- vector_set_slot(vecs->mpvec, mpp);
+-
+- if (update_map(mpp, vecs) != 0) /* map removed */
+- return NULL;
+-
+- if (start_waiter_thread(mpp, vecs))
+- goto out;
+-
+- return mpp;
+-out:
+- remove_map(mpp, vecs, PURGE_VEC);
+- return NULL;
+-}
+-
+ static void
+ find_existing_alias (struct multipath * mpp,
+ struct vectors *vecs)
+diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
+index d6e17bb..ceab6d9 100644
+--- a/libmultipath/structs_vec.h
++++ b/libmultipath/structs_vec.h
+@@ -26,12 +26,12 @@ int update_multipath_strings (struct multipath *mpp, vector pathvec,
+ int is_daemon);
+ void extract_hwe_from_path(struct multipath * mpp);
+
++#define PURGE_VEC 1
++
+ void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
+ void remove_maps (struct vectors * vecs);
+
+ void sync_map_state (struct multipath *);
+-int update_map (struct multipath *mpp, struct vectors *vecs);
+-struct multipath * add_map_without_path (struct vectors * vecs, char * alias);
+ struct multipath * add_map_with_path (struct vectors * vecs,
+ struct path * pp, int add_vec);
+ int update_multipath (struct vectors *vecs, char *mapname, int reset);
+diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
+deleted file mode 100644
+index cb9708b..0000000
+--- a/libmultipath/waiter.c
++++ /dev/null
+@@ -1,215 +0,0 @@
+-/*
+- * 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 <urcu.h>
+-
+-#include "vector.h"
+-#include "memory.h"
+-#include "checkers.h"
+-#include "config.h"
+-#include "structs.h"
+-#include "structs_vec.h"
+-#include "devmapper.h"
+-#include "debug.h"
+-#include "lock.h"
+-#include "waiter.h"
+-
+-pthread_attr_t waiter_attr;
+-
+-static struct event_thread *alloc_waiter (void)
+-{
+-
+- struct event_thread *wp;
+-
+- wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
+- memset(wp, 0, sizeof(struct event_thread));
+-
+- return wp;
+-}
+-
+-static void free_waiter (void *data)
+-{
+- struct event_thread *wp = (struct event_thread *)data;
+-
+- if (wp->dmt)
+- dm_task_destroy(wp->dmt);
+-
+- rcu_unregister_thread();
+- FREE(wp);
+-}
+-
+-void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+-{
+- pthread_t thread;
+-
+- if (mpp->waiter == (pthread_t)0) {
+- condlog(3, "%s: event checker thread already stopped",
+- mpp->alias);
+- return;
+- }
+- condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
+- mpp->waiter);
+- thread = mpp->waiter;
+- mpp->waiter = (pthread_t)0;
+- pthread_cancel(thread);
+- pthread_kill(thread, SIGUSR2);
+-}
+-
+-/*
+- * returns the reschedule delay
+- * negative means *stop*
+- */
+-static int waiteventloop (struct event_thread *waiter)
+-{
+- sigset_t set, oldset;
+- int event_nr;
+- int r;
+-
+- if (!waiter->event_nr)
+- waiter->event_nr = dm_geteventnr(waiter->mapname);
+-
+- if (!(waiter->dmt = libmp_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);
+- waiter->dmt = NULL;
+- 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);
+- waiter->dmt = NULL;
+- return 1;
+- }
+-
+- dm_task_no_open_count(waiter->dmt);
+-
+- /* wait */
+- sigemptyset(&set);
+- sigaddset(&set, SIGUSR2);
+- pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+-
+- pthread_testcancel();
+- r = dm_task_run(waiter->dmt);
+- pthread_testcancel();
+-
+- pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+- dm_task_destroy(waiter->dmt);
+- waiter->dmt = NULL;
+-
+- if (!r) /* wait interrupted by signal */
+- return -1;
+-
+- 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);
+- pthread_testcancel();
+- r = update_multipath(waiter->vecs, waiter->mapname, 1);
+- lock_cleanup_pop(waiter->vecs->lock);
+-
+- if (r) {
+- condlog(2, "%s: event checker exit",
+- waiter->mapname);
+- 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);
+-
+- rcu_register_thread();
+- 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)
+-{
+- struct event_thread *wp;
+-
+- if (!mpp)
+- return 0;
+-
+- wp = alloc_waiter();
+-
+- if (!wp)
+- goto out;
+-
+- strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
+- wp->vecs = vecs;
+-
+- if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
+- condlog(0, "%s: cannot create event checker", wp->mapname);
+- goto out1;
+- }
+- mpp->waiter = wp->thread;
+- condlog(2, "%s: event checker started", wp->mapname);
+-
+- return 0;
+-out1:
+- free_waiter(wp);
+- mpp->waiter = (pthread_t)0;
+-out:
+- condlog(0, "failed to start waiter thread");
+- return 1;
+-}
+diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
+deleted file mode 100644
+index 0cfae46..0000000
+--- a/libmultipath/waiter.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#ifndef _WAITER_H
+-#define _WAITER_H
+-
+-extern pthread_attr_t waiter_attr;
+-
+-struct event_thread {
+- struct dm_task *dmt;
+- pthread_t thread;
+- int event_nr;
+- char mapname[WWID_SIZE];
+- struct vectors *vecs;
+-};
+-
+-void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+-int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+-
+-#endif /* _WAITER_H */
+diff --git a/multipathd/Makefile b/multipathd/Makefile
+index e6f140b..85f29a7 100644
+--- a/multipathd/Makefile
++++ b/multipathd/Makefile
+@@ -22,7 +22,7 @@ ifdef SYSTEMD
+ endif
+ endif
+
+-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o
++OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o
+
+ EXEC = multipathd
+
+diff --git a/multipathd/main.c b/multipathd/main.c
+index 72c3c2f..94b2406 100644
+--- a/multipathd/main.c
++++ b/multipathd/main.c
+@@ -311,6 +311,102 @@ remove_maps_and_stop_waiters(struct vectors *vecs)
+ remove_maps(vecs);
+ }
+
++static void
++set_multipath_wwid (struct multipath * mpp)
++{
++ if (strlen(mpp->wwid))
++ return;
++
++ dm_get_uuid(mpp->alias, mpp->wwid);
++}
++
++static int
++update_map (struct multipath *mpp, struct vectors *vecs)
++{
++ int retries = 3;
++ char params[PARAMS_SIZE] = {0};
++
++retry:
++ condlog(4, "%s: updating new map", mpp->alias);
++ if (adopt_paths(vecs->pathvec, mpp)) {
++ condlog(0, "%s: failed to adopt paths for new map update",
++ mpp->alias);
++ retries = -1;
++ goto fail;
++ }
++ verify_paths(mpp, vecs);
++ mpp->action = ACT_RELOAD;
++
++ extract_hwe_from_path(mpp);
++ if (setup_map(mpp, params, PARAMS_SIZE)) {
++ condlog(0, "%s: failed to setup new map in update", mpp->alias);
++ retries = -1;
++ goto fail;
++ }
++ if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
++ condlog(0, "%s: map_udate sleep", mpp->alias);
++ sleep(1);
++ goto retry;
++ }
++ dm_lib_release();
++
++fail:
++ if (setup_multipath(vecs, mpp))
++ return 1;
++
++ sync_map_state(mpp);
++
++ if (retries < 0)
++ condlog(0, "%s: failed reload in new map update", mpp->alias);
++ return 0;
++}
++
++static struct multipath *
++add_map_without_path (struct vectors *vecs, char *alias)
++{
++ struct multipath * mpp = alloc_multipath();
++ struct config *conf;
++
++ if (!mpp)
++ return NULL;
++ if (!alias) {
++ FREE(mpp);
++ return NULL;
++ }
++
++ mpp->alias = STRDUP(alias);
++
++ if (dm_get_info(mpp->alias, &mpp->dmi)) {
++ condlog(3, "%s: cannot access table", mpp->alias);
++ goto out;
++ }
++ set_multipath_wwid(mpp);
++ conf = get_multipath_config();
++ mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
++ put_multipath_config(conf);
++
++ if (update_multipath_table(mpp, vecs->pathvec, 1))
++ goto out;
++ if (update_multipath_status(mpp))
++ goto out;
++
++ if (!vector_alloc_slot(vecs->mpvec))
++ goto out;
++
++ vector_set_slot(vecs->mpvec, mpp);
++
++ if (update_map(mpp, vecs) != 0) /* map removed */
++ return NULL;
++
++ if (start_waiter_thread(mpp, vecs))
++ goto out;
++
++ return mpp;
++out:
++ remove_map(mpp, vecs, PURGE_VEC);
++ return NULL;
++}
++
+ static int
+ coalesce_maps(struct vectors *vecs, vector nmpv)
+ {
+diff --git a/multipathd/waiter.c b/multipathd/waiter.c
+new file mode 100644
+index 0000000..cb9708b
+--- /dev/null
++++ b/multipathd/waiter.c
+@@ -0,0 +1,215 @@
++/*
++ * 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 <urcu.h>
++
++#include "vector.h"
++#include "memory.h"
++#include "checkers.h"
++#include "config.h"
++#include "structs.h"
++#include "structs_vec.h"
++#include "devmapper.h"
++#include "debug.h"
++#include "lock.h"
++#include "waiter.h"
++
++pthread_attr_t waiter_attr;
++
++static struct event_thread *alloc_waiter (void)
++{
++
++ struct event_thread *wp;
++
++ wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
++ memset(wp, 0, sizeof(struct event_thread));
++
++ return wp;
++}
++
++static void free_waiter (void *data)
++{
++ struct event_thread *wp = (struct event_thread *)data;
++
++ if (wp->dmt)
++ dm_task_destroy(wp->dmt);
++
++ rcu_unregister_thread();
++ FREE(wp);
++}
++
++void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
++{
++ pthread_t thread;
++
++ if (mpp->waiter == (pthread_t)0) {
++ condlog(3, "%s: event checker thread already stopped",
++ mpp->alias);
++ return;
++ }
++ condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
++ mpp->waiter);
++ thread = mpp->waiter;
++ mpp->waiter = (pthread_t)0;
++ pthread_cancel(thread);
++ pthread_kill(thread, SIGUSR2);
++}
++
++/*
++ * returns the reschedule delay
++ * negative means *stop*
++ */
++static int waiteventloop (struct event_thread *waiter)
++{
++ sigset_t set, oldset;
++ int event_nr;
++ int r;
++
++ if (!waiter->event_nr)
++ waiter->event_nr = dm_geteventnr(waiter->mapname);
++
++ if (!(waiter->dmt = libmp_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);
++ waiter->dmt = NULL;
++ 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);
++ waiter->dmt = NULL;
++ return 1;
++ }
++
++ dm_task_no_open_count(waiter->dmt);
++
++ /* wait */
++ sigemptyset(&set);
++ sigaddset(&set, SIGUSR2);
++ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
++
++ pthread_testcancel();
++ r = dm_task_run(waiter->dmt);
++ pthread_testcancel();
++
++ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
++ dm_task_destroy(waiter->dmt);
++ waiter->dmt = NULL;
++
++ if (!r) /* wait interrupted by signal */
++ return -1;
++
++ 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);
++ pthread_testcancel();
++ r = update_multipath(waiter->vecs, waiter->mapname, 1);
++ lock_cleanup_pop(waiter->vecs->lock);
++
++ if (r) {
++ condlog(2, "%s: event checker exit",
++ waiter->mapname);
++ 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);
++
++ rcu_register_thread();
++ 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)
++{
++ struct event_thread *wp;
++
++ if (!mpp)
++ return 0;
++
++ wp = alloc_waiter();
++
++ if (!wp)
++ goto out;
++
++ strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
++ wp->vecs = vecs;
++
++ if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
++ condlog(0, "%s: cannot create event checker", wp->mapname);
++ goto out1;
++ }
++ mpp->waiter = wp->thread;
++ condlog(2, "%s: event checker started", wp->mapname);
++
++ return 0;
++out1:
++ free_waiter(wp);
++ mpp->waiter = (pthread_t)0;
++out:
++ condlog(0, "failed to start waiter thread");
++ return 1;
++}
+diff --git a/multipathd/waiter.h b/multipathd/waiter.h
+new file mode 100644
+index 0000000..0cfae46
+--- /dev/null
++++ b/multipathd/waiter.h
+@@ -0,0 +1,17 @@
++#ifndef _WAITER_H
++#define _WAITER_H
++
++extern pthread_attr_t waiter_attr;
++
++struct event_thread {
++ struct dm_task *dmt;
++ pthread_t thread;
++ int event_nr;
++ char mapname[WWID_SIZE];
++ struct vectors *vecs;
++};
++
++void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
++int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
++
++#endif /* _WAITER_H */
+--
+2.7.4
+