5bea53fe7e
Update Source to the latest upstream commit * Previous patches 0001-0006 are included in this commit * Previous patches 0007-0014 are now patches 0015-0022 Add 0001-libmultipath-fix-tur-checker-locking.patch * Fixed spinlock bug. posted upstream Add 0002-multipath-fix-DEF_TIMEOUT-use.patch * Add missing sec to ms conversion. posted upstream Add 0003-multipathd-remove-coalesce_paths-from-ev_add_map.patch * Remove unused code. posted upstream Add 0004-multipathd-remove-unused-configure-parameter.patch * Remove unused code. posted upstream Add 0005-Fix-set_no_path_retry-regression.patch * Fix issue with queueing and path addition. posted upstream Add 0006-multipathd-change-spurious-uevent-msg-priority.patch * Change message priority to Notice. posted upstream Add 0007-multipath-print-sysfs-state-in-fast-list-mode.patch * Show sysfs state correctly in fast list mode (-l). posted upstream Add 0008-libmultipath-move-remove_map-waiter-code-to-multipat.patch * Move code around. posted upstream Add 0009-move-waiter-code-from-libmultipath-to-multipathd.patch * Move code around. posted upstream Add 0010-call-start_waiter_thread-before-setup_multipath.patch * Fix race on multipath device creations. posted upstream Add 0011-libmultipath-add-helper-functions.patch * posted upstream Add 0012-multipathd-RFC-add-new-polling-dmevents-waiter-threa.patch * Add alternate method of getting dmevents, that doesn't require a thread per device. posted upstream Add 0013-libmultipath-condlog-log-to-stderr.patch * change condlog to log to stderr instead of stdout. posted upstream Add 0014-multipathd-fix-compiler-warning-for-uev_pathfail_che.patch * fix indentation issue. posted upstream
794 lines
18 KiB
Diff
794 lines
18 KiB
Diff
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
|
|
|