summaryrefslogtreecommitdiff
path: root/libmultipath
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2022-01-14 13:50:16 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2022-01-14 13:50:16 +0900
commitaa543d0c97d19f8c42b291742df51424f5b5b2c4 (patch)
tree598cdd7755478cc8adf500b4196738254900f3cb /libmultipath
parent4f76c358dbfe7a94eefbfab498e6c62bb887110d (diff)
downloadmultipath-tools-aa543d0c97d19f8c42b291742df51424f5b5b2c4.tar.gz
multipath-tools-aa543d0c97d19f8c42b291742df51424f5b5b2c4.tar.bz2
multipath-tools-aa543d0c97d19f8c42b291742df51424f5b5b2c4.zip
Imported Upstream version 0.6.4upstream/0.6.4
Diffstat (limited to 'libmultipath')
-rw-r--r--libmultipath/Makefile4
-rw-r--r--libmultipath/alias.c2
-rw-r--r--libmultipath/blacklist.c12
-rw-r--r--libmultipath/checkers.h6
-rw-r--r--libmultipath/checkers/rbd.c123
-rw-r--r--libmultipath/checkers/tur.c179
-rw-r--r--libmultipath/config.c12
-rw-r--r--libmultipath/config.h4
-rw-r--r--libmultipath/configure.c13
-rw-r--r--libmultipath/debug.c4
-rw-r--r--libmultipath/defaults.h8
-rw-r--r--libmultipath/devmapper.c55
-rw-r--r--libmultipath/devmapper.h8
-rw-r--r--libmultipath/dict.c24
-rw-r--r--libmultipath/discovery.c15
-rw-r--r--libmultipath/discovery.h1
-rw-r--r--libmultipath/dmparser.c8
-rw-r--r--libmultipath/file.c2
-rw-r--r--libmultipath/hwtable.c364
-rw-r--r--libmultipath/log.c2
-rw-r--r--libmultipath/log.h2
-rw-r--r--libmultipath/memory.c1
-rw-r--r--libmultipath/memory.h1
-rw-r--r--libmultipath/print.c161
-rw-r--r--libmultipath/prio.h3
-rw-r--r--libmultipath/prioritizers/alua.c8
-rw-r--r--libmultipath/prioritizers/const.c2
-rw-r--r--libmultipath/prioritizers/datacore.c2
-rw-r--r--libmultipath/prioritizers/iet.c2
-rw-r--r--libmultipath/prioritizers/ontap.c1
-rw-r--r--libmultipath/prioritizers/random.c2
-rw-r--r--libmultipath/prioritizers/weightedpath.c2
-rw-r--r--libmultipath/propsel.c24
-rw-r--r--libmultipath/propsel.h1
-rw-r--r--libmultipath/structs.c11
-rw-r--r--libmultipath/structs.h9
-rw-r--r--libmultipath/structs_vec.c28
-rw-r--r--libmultipath/time-util.c42
-rw-r--r--libmultipath/time-util.h13
-rw-r--r--libmultipath/uevent.c39
-rw-r--r--libmultipath/uevent.h1
-rw-r--r--libmultipath/util.c25
-rw-r--r--libmultipath/util.h1
-rw-r--r--libmultipath/uxsock.c19
-rw-r--r--libmultipath/version.h4
-rw-r--r--libmultipath/wwids.c4
46 files changed, 839 insertions, 415 deletions
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index 3a20f8e..495cebe 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -9,7 +9,7 @@ LIBS = $(DEVLIB).$(SONAME)
CFLAGS += -I$(mpathcmddir)
-LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd
+LIBDEPS += -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd
ifdef SYSTEMD
CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
@@ -47,7 +47,7 @@ endif
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o discovery.o propsel.o dict.o \
- pgpolicies.o debug.o defaults.o uevent.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
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index b86843a..12afef8 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -219,7 +219,7 @@ allocate_binding(int fd, char *wwid, int id, char *prefix)
strerror(errno));
return NULL;
}
- if (write_all(fd, buf, strlen(buf)) != strlen(buf)){
+ if (write(fd, buf, strlen(buf)) != strlen(buf)){
condlog(0, "Cannot write binding to bindings file : %s",
strerror(errno));
/* clear partial write */
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index 9687399..f6c4506 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -172,7 +172,7 @@ setup_default_blist (struct config * conf)
char * str;
int i;
- str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
+ str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]");
if (!str)
return 1;
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
@@ -184,19 +184,13 @@ setup_default_blist (struct config * conf)
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
return 1;
- str = STRDUP("^dcssblk[0-9]*");
+ str = STRDUP("^nvme");
if (!str)
return 1;
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
return 1;
- str = STRDUP("^nvme.*");
- if (!str)
- return 1;
- if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
- return 1;
-
- str = STRDUP("(SCSI_IDENT_.*|ID_WWN)");
+ str = STRDUP("(SCSI_IDENT_|ID_WWN)");
if (!str)
return 1;
if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h
index 4fb97c9..fedc330 100644
--- a/libmultipath/checkers.h
+++ b/libmultipath/checkers.h
@@ -142,4 +142,10 @@ char * checker_message (struct checker *);
void checker_clear_message (struct checker *c);
void checker_get (char *, struct checker *, char *);
+/* Functions exported by path checker dynamic libraries (.so) */
+int libcheck_check(struct checker *);
+int libcheck_init(struct checker *);
+void libcheck_free(struct checker *);
+void libcheck_repair(struct checker *);
+
#endif /* _CHECKERS_H */
diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c
index 6f1b53a..481d860 100644
--- a/libmultipath/checkers/rbd.c
+++ b/libmultipath/checkers/rbd.c
@@ -26,13 +26,16 @@
#include "checkers.h"
#include "../libmultipath/debug.h"
-#include "../libmultipath/uevent.h"
+#include "../libmultipath/util.h"
+#include "../libmultipath/time-util.h"
struct rbd_checker_context;
typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg);
#define RBD_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args);
+#define RBD_FEATURE_EXCLUSIVE_LOCK (1 << 2)
+
struct rbd_checker_context {
int rbd_bus_id;
char *client_addr;
@@ -43,6 +46,7 @@ struct rbd_checker_context {
char *username;
int remapped;
int blacklisted;
+ unsigned lock_on_read:1;
rados_t cluster;
@@ -65,8 +69,9 @@ int libcheck_init(struct checker * c)
struct udev_device *bus_dev;
struct udev *udev;
struct stat sb;
- const char *block_name, *addr, *config_info;
+ const char *block_name, *addr, *config_info, *features_str;
const char *image, *pool, *snap, *username;
+ uint64_t features = 0;
char sysfs_path[PATH_SIZE];
int ret;
@@ -75,7 +80,7 @@ int libcheck_init(struct checker * c)
return 1;
memset(ct, 0, sizeof(struct rbd_checker_context));
ct->holders = 1;
- pthread_cond_init(&ct->active, NULL);
+ pthread_cond_init_mono(&ct->active);
pthread_mutex_init(&ct->lock, NULL);
pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE);
c->context = ct;
@@ -110,8 +115,8 @@ int libcheck_init(struct checker * c)
addr = udev_device_get_sysattr_value(bus_dev, "client_addr");
if (!addr) {
- condlog(0, "Could not find client_addr in rbd sysfs. Try "
- "updating kernel");
+ condlog(0, "rbd%d: Could not find client_addr in rbd sysfs. "
+ "Try updating kernel", ct->rbd_bus_id);
goto free_dev;
}
@@ -119,10 +124,28 @@ int libcheck_init(struct checker * c)
if (!ct->client_addr)
goto free_dev;
+ features_str = udev_device_get_sysattr_value(bus_dev, "features");
+ if (!features_str)
+ goto free_addr;
+ features = strtoll(features_str, NULL, 16);
+ if (!(features & RBD_FEATURE_EXCLUSIVE_LOCK)) {
+ condlog(3, "rbd%d: Exclusive lock not set.", ct->rbd_bus_id);
+ goto free_addr;
+ }
+
config_info = udev_device_get_sysattr_value(bus_dev, "config_info");
if (!config_info)
goto free_addr;
+ if (!strstr(config_info, "noshare")) {
+ condlog(3, "rbd%d: Only nonshared clients supported.",
+ ct->rbd_bus_id);
+ goto free_addr;
+ }
+
+ if (strstr(config_info, "lock_on_read"))
+ ct->lock_on_read = 1;
+
ct->config_info = strdup(config_info);
if (!ct->config_info)
goto free_addr;
@@ -172,18 +195,20 @@ int libcheck_init(struct checker * c)
}
if (rados_create(&ct->cluster, NULL) < 0) {
- condlog(0, "Could not create rados cluster");
+ condlog(0, "rbd%d: Could not create rados cluster",
+ ct->rbd_bus_id);
goto free_snap;
}
if (rados_conf_read_file(ct->cluster, NULL) < 0) {
- condlog(0, "Could not read rados conf");
+ condlog(0, "rbd%d: Could not read rados conf", ct->rbd_bus_id);
goto shutdown_rados;
}
ret = rados_connect(ct->cluster);
if (ret < 0) {
- condlog(0, "Could not connect to rados cluster");
+ condlog(0, "rbd%d: Could not connect to rados cluster",
+ ct->rbd_bus_id);
goto shutdown_rados;
}
@@ -220,7 +245,7 @@ free_ct:
return 1;
}
-void cleanup_context(struct rbd_checker_context *ct)
+static void cleanup_context(struct rbd_checker_context *ct)
{
pthread_mutex_destroy(&ct->lock);
pthread_cond_destroy(&ct->active);
@@ -274,8 +299,7 @@ static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg)
ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0,
&blklist, &blklist_len, &stat, &stat_len);
if (ret < 0) {
- RBD_MSG(msg, "rbd checker failed: mon command failed %d",
- ret);
+ RBD_MSG(msg, "checker failed: mon command failed %d", ret);
return ret;
}
@@ -296,16 +320,15 @@ static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg)
end = strchr(addr_tok, ' ');
if (!end) {
- RBD_MSG(msg, "rbd%d checker failed: invalid blacklist %s",
- ct->rbd_bus_id, addr_tok);
+ RBD_MSG(msg, "checker failed: invalid blacklist %s",
+ addr_tok);
break;
}
*end = '\0';
if (!strcmp(addr_tok, ct->client_addr)) {
ct->blacklisted = 1;
- RBD_MSG(msg, "rbd%d checker: %s is blacklisted",
- ct->rbd_bus_id, ct->client_addr);
+ RBD_MSG(msg, "%s is blacklisted", ct->client_addr);
ret = 1;
break;
}
@@ -317,12 +340,12 @@ free_bufs:
return ret;
}
-int rbd_check(struct rbd_checker_context *ct, char *msg)
+static int rbd_check(struct rbd_checker_context *ct, char *msg)
{
if (ct->blacklisted || rbd_is_blacklisted(ct, msg) == 1)
return PATH_DOWN;
- RBD_MSG(msg, "rbd checker reports path is up");
+ RBD_MSG(msg, "checker reports path is up");
/*
* Path may have issues, but the ceph cluster is at least
* accepting IO, so we can attempt to do IO.
@@ -333,7 +356,7 @@ int rbd_check(struct rbd_checker_context *ct, char *msg)
return PATH_UP;
}
-int safe_write(int fd, const void *buf, size_t count)
+static int safe_write(int fd, const void *buf, size_t count)
{
while (count > 0) {
ssize_t r = write(fd, buf, count);
@@ -355,7 +378,7 @@ static int sysfs_write_rbd_bus(const char *which, const char *buf,
int fd;
int r;
- /* we require newer kernels so single_major should alwayws be there */
+ /* we require newer kernels so single_major should always be there */
snprintf(sysfs_path, sizeof(sysfs_path),
"/sys/bus/rbd/%s_single_major", which);
fd = open(sysfs_path, O_WRONLY);
@@ -379,7 +402,10 @@ static int rbd_remap(struct rbd_checker_context *ct)
case 0:
argv[i++] = "rbd";
argv[i++] = "map";
- argv[i++] = "-o noshare";
+ if (ct->lock_on_read)
+ argv[i++] = "-o noshare,lock_on_read";
+ else
+ argv[i++] = "-o noshare";
if (ct->username) {
argv[i++] = "--id";
argv[i++] = ct->username;
@@ -394,10 +420,12 @@ static int rbd_remap(struct rbd_checker_context *ct)
argv[i] = NULL;
ret = execvp(argv[0], argv);
- condlog(0, "Error executing rbd: %s", strerror(errno));
+ condlog(0, "rbd%d: Error executing rbd: %s", ct->rbd_bus_id,
+ strerror(errno));
exit(-1);
case -1:
- condlog(0, "fork failed: %s", strerror(errno));
+ condlog(0, "rbd%d: fork failed: %s", ct->rbd_bus_id,
+ strerror(errno));
return -1;
default:
ret = -1;
@@ -407,7 +435,8 @@ static int rbd_remap(struct rbd_checker_context *ct)
if (status == 0)
ret = 0;
else
- condlog(0, "rbd failed with %d", status);
+ condlog(0, "rbd%d: failed with %d",
+ ct->rbd_bus_id, status);
}
}
@@ -435,14 +464,14 @@ static int rbd_rm_blacklist(struct rbd_checker_context *ct)
cmd[1] = NULL;
ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0,
- NULL, 0, &stat, &stat_len);
+ NULL, NULL, &stat, &stat_len);
if (ret < 0) {
- condlog(1, "rbd%d repair failed to remove blacklist for %s %d",
+ condlog(1, "rbd%d: repair failed to remove blacklist for %s %d",
ct->rbd_bus_id, ct->client_addr, ret);
goto free_cmd;
}
- condlog(1, "rbd%d repair rm blacklist for %s",
+ condlog(1, "rbd%d: repair rm blacklist for %s",
ct->rbd_bus_id, ct->client_addr);
free(stat);
free_cmd:
@@ -461,8 +490,7 @@ static int rbd_repair(struct rbd_checker_context *ct, char *msg)
if (!ct->remapped) {
ret = rbd_remap(ct);
if (ret) {
- RBD_MSG(msg, "rbd%d repair failed to remap. Err %d",
- ct->rbd_bus_id, ret);
+ RBD_MSG(msg, "repair failed to remap. Err %d", ret);
return PATH_DOWN;
}
}
@@ -471,29 +499,28 @@ static int rbd_repair(struct rbd_checker_context *ct, char *msg)
snprintf(del, sizeof(del), "%d force", ct->rbd_bus_id);
ret = sysfs_write_rbd_remove(del, strlen(del) + 1);
if (ret) {
- RBD_MSG(msg, "rbd%d repair failed to clean up. Err %d",
- ct->rbd_bus_id, ret);
+ RBD_MSG(msg, "repair failed to clean up. Err %d", ret);
return PATH_DOWN;
}
ret = rbd_rm_blacklist(ct);
if (ret) {
- RBD_MSG(msg, "rbd%d repair could not remove blacklist entry. Err %d",
- ct->rbd_bus_id, ret);
+ RBD_MSG(msg, "repair could not remove blacklist entry. Err %d",
+ ret);
return PATH_DOWN;
}
ct->remapped = 0;
ct->blacklisted = 0;
- RBD_MSG(msg, "rbd%d has been repaired", ct->rbd_bus_id);
+ RBD_MSG(msg, "has been repaired");
return PATH_UP;
}
#define rbd_thread_cleanup_push(ct) pthread_cleanup_push(cleanup_func, ct)
#define rbd_thread_cleanup_pop(ct) pthread_cleanup_pop(1)
-void cleanup_func(void *data)
+static void cleanup_func(void *data)
{
int holders;
struct rbd_checker_context *ct = data;
@@ -506,12 +533,12 @@ void cleanup_func(void *data)
cleanup_context(ct);
}
-void *rbd_thread(void *ctx)
+static void *rbd_thread(void *ctx)
{
struct rbd_checker_context *ct = ctx;
int state;
- condlog(3, "rbd%d thread starting up", ct->rbd_bus_id);
+ condlog(3, "rbd%d: thread starting up", ct->rbd_bus_id);
ct->message[0] = '\0';
/* This thread can be canceled, so setup clean up */
@@ -527,10 +554,10 @@ void *rbd_thread(void *ctx)
/* checker done */
pthread_mutex_lock(&ct->lock);
ct->state = state;
- pthread_mutex_unlock(&ct->lock);
pthread_cond_signal(&ct->active);
+ pthread_mutex_unlock(&ct->lock);
- condlog(3, "rbd%d thead finished, state %s", ct->rbd_bus_id,
+ condlog(3, "rbd%d: thead finished, state %s", ct->rbd_bus_id,
checker_state_name(state));
rbd_thread_cleanup_pop(ct);
return ((void *)0);
@@ -538,12 +565,9 @@ void *rbd_thread(void *ctx)
static void rbd_timeout(struct timespec *tsp)
{
- struct timeval now;
-
- gettimeofday(&now, NULL);
- tsp->tv_sec = now.tv_sec;
- tsp->tv_nsec = now.tv_usec * 1000;
- tsp->tv_nsec += 1000000; /* 1 millisecond */
+ clock_gettime(CLOCK_MONOTONIC, tsp);
+ tsp->tv_nsec += 1000 * 1000; /* 1 millisecond */
+ normalize_timespec(tsp);
}
static int rbd_exec_fn(struct checker *c, thread_fn *fn)
@@ -554,22 +578,23 @@ static int rbd_exec_fn(struct checker *c, thread_fn *fn)
int rbd_status, r;
if (c->sync)
- return rbd_check(ct, c->message);
+ return fn(ct, c->message);
/*
* Async mode
*/
r = pthread_mutex_lock(&ct->lock);
if (r != 0) {
- condlog(2, "rbd%d mutex lock failed with %d", ct->rbd_bus_id,
+ condlog(2, "rbd%d: mutex lock failed with %d", ct->rbd_bus_id,
r);
- MSG(c, "rbd%d thread failed to initialize", ct->rbd_bus_id);
+ MSG(c, "rbd%d: thread failed to initialize", ct->rbd_bus_id);
return PATH_WILD;
}
if (ct->running) {
/* Check if checker is still running */
if (ct->thread) {
- condlog(3, "rbd%d thread not finished", ct->rbd_bus_id);
+ condlog(3, "rbd%d: thread not finished",
+ ct->rbd_bus_id);
rbd_status = PATH_PENDING;
} else {
/* checker done */
@@ -606,7 +631,7 @@ static int rbd_exec_fn(struct checker *c, thread_fn *fn)
if (ct->thread &&
(rbd_status == PATH_PENDING || rbd_status == PATH_UNCHECKED)) {
- condlog(3, "rbd%d thread still running",
+ condlog(3, "rbd%d: thread still running",
ct->rbd_bus_id);
ct->running = 1;
rbd_status = PATH_PENDING;
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
index c2ff5e9..92200aa 100644
--- a/libmultipath/checkers/tur.c
+++ b/libmultipath/checkers/tur.c
@@ -19,7 +19,9 @@
#include "../libmultipath/debug.h"
#include "../libmultipath/sg_include.h"
-#include "../libmultipath/uevent.h"
+#include "../libmultipath/util.h"
+#include "../libmultipath/time-util.h"
+#include "../libmultipath/util.h"
#define TUR_CMD_LEN 6
#define HEAVY_CHECK_COUNT 10
@@ -46,11 +48,23 @@ struct tur_checker_context {
char message[CHECKER_MSG_LEN];
};
-#define TUR_DEVT(c) major((c)->devt), minor((c)->devt)
+static const char *tur_devt(char *devt_buf, int size,
+ struct tur_checker_context *ct)
+{
+ dev_t devt;
+
+ pthread_mutex_lock(&ct->lock);
+ devt = ct->devt;
+ pthread_mutex_unlock(&ct->lock);
+
+ snprintf(devt_buf, size, "%d:%d", major(devt), minor(devt));
+ return devt_buf;
+}
int libcheck_init (struct checker * c)
{
struct tur_checker_context *ct;
+ pthread_mutexattr_t attr;
ct = malloc(sizeof(struct tur_checker_context));
if (!ct)
@@ -60,15 +74,18 @@ int libcheck_init (struct checker * c)
ct->state = PATH_UNCHECKED;
ct->fd = -1;
ct->holders = 1;
- pthread_cond_init(&ct->active, NULL);
- pthread_mutex_init(&ct->lock, NULL);
+ pthread_cond_init_mono(&ct->active);
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&ct->lock, &attr);
+ pthread_mutexattr_destroy(&attr);
pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE);
c->context = ct;
return 0;
}
-void cleanup_context(struct tur_checker_context *ct)
+static void cleanup_context(struct tur_checker_context *ct)
{
pthread_mutex_destroy(&ct->lock);
pthread_cond_destroy(&ct->active);
@@ -102,10 +119,17 @@ void libcheck_repair (struct checker * c)
return;
}
-#define TUR_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args);
-
-int
-tur_check(int fd, unsigned int timeout, char *msg)
+#define TUR_MSG(fmt, args...) \
+ do { \
+ char msg[CHECKER_MSG_LEN]; \
+ \
+ snprintf(msg, sizeof(msg), fmt, ##args); \
+ copy_message(cb_arg, msg); \
+ } while (0)
+
+static int
+tur_check(int fd, unsigned int timeout,
+ void (*copy_message)(void *, const char *), void *cb_arg)
{
struct sg_io_hdr io_hdr;
unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
@@ -124,7 +148,7 @@ retry:
io_hdr.timeout = timeout * 1000;
io_hdr.pack_id = 0;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
- TUR_MSG(msg, MSG_TUR_DOWN);
+ TUR_MSG(MSG_TUR_DOWN);
return PATH_DOWN;
}
if ((io_hdr.status & 0x7e) == 0x18) {
@@ -132,7 +156,7 @@ retry:
* SCSI-3 arrays might return
* reservation conflict on TUR
*/
- TUR_MSG(msg, MSG_TUR_UP);
+ TUR_MSG(MSG_TUR_UP);
return PATH_UP;
}
if (io_hdr.info & SG_INFO_OK_MASK) {
@@ -177,21 +201,21 @@ retry:
* LOGICAL UNIT NOT ACCESSIBLE,
* TARGET PORT IN STANDBY STATE
*/
- TUR_MSG(msg, MSG_TUR_GHOST);
+ TUR_MSG(MSG_TUR_GHOST);
return PATH_GHOST;
}
}
- TUR_MSG(msg, MSG_TUR_DOWN);
+ TUR_MSG(MSG_TUR_DOWN);
return PATH_DOWN;
}
- TUR_MSG(msg, MSG_TUR_UP);
+ TUR_MSG(MSG_TUR_UP);
return PATH_UP;
}
#define tur_thread_cleanup_push(ct) pthread_cleanup_push(cleanup_func, ct)
#define tur_thread_cleanup_pop(ct) pthread_cleanup_pop(1)
-void cleanup_func(void *data)
+static void cleanup_func(void *data)
{
int holders;
struct tur_checker_context *ct = data;
@@ -204,65 +228,92 @@ void cleanup_func(void *data)
cleanup_context(ct);
}
-void *tur_thread(void *ctx)
+static int tur_running(struct tur_checker_context *ct)
+{
+ pthread_t thread;
+
+ pthread_spin_lock(&ct->hldr_lock);
+ thread = ct->thread;
+ pthread_spin_unlock(&ct->hldr_lock);
+
+ return thread != 0;
+}
+
+static void copy_msg_to_tcc(void *ct_p, const char *msg)
+{
+ struct tur_checker_context *ct = ct_p;
+
+ pthread_mutex_lock(&ct->lock);
+ strlcpy(ct->message, msg, sizeof(ct->message));
+ pthread_mutex_unlock(&ct->lock);
+}
+
+static void *tur_thread(void *ctx)
{
struct tur_checker_context *ct = ctx;
int state;
+ char devt[32];
- condlog(3, "%d:%d: tur checker starting up", TUR_DEVT(ct));
+ condlog(3, "%s: tur checker starting up",
+ tur_devt(devt, sizeof(devt), ct));
- ct->message[0] = '\0';
/* This thread can be canceled, so setup clean up */
- tur_thread_cleanup_push(ct)
+ tur_thread_cleanup_push(ct);
/* TUR checker start up */
pthread_mutex_lock(&ct->lock);
ct->state = PATH_PENDING;
+ ct->message[0] = '\0';
pthread_mutex_unlock(&ct->lock);
- state = tur_check(ct->fd, ct->timeout, ct->message);
+ state = tur_check(ct->fd, ct->timeout, copy_msg_to_tcc, ct->message);
/* TUR checker done */
pthread_mutex_lock(&ct->lock);
ct->state = state;
- pthread_mutex_unlock(&ct->lock);
pthread_cond_signal(&ct->active);
+ pthread_mutex_unlock(&ct->lock);
- condlog(3, "%d:%d: tur checker finished, state %s",
- TUR_DEVT(ct), checker_state_name(state));
+ condlog(3, "%s: tur checker finished, state %s",
+ tur_devt(devt, sizeof(devt), ct), checker_state_name(state));
tur_thread_cleanup_pop(ct);
+
return ((void *)0);
}
-void tur_timeout(struct timespec *tsp)
+static void tur_timeout(struct timespec *tsp)
{
- struct timeval now;
-
- gettimeofday(&now, NULL);
- tsp->tv_sec = now.tv_sec;
- tsp->tv_nsec = now.tv_usec * 1000;
- tsp->tv_nsec += 1000000; /* 1 millisecond */
+ clock_gettime(CLOCK_MONOTONIC, tsp);
+ tsp->tv_nsec += 1000 * 1000; /* 1 millisecond */
+ normalize_timespec(tsp);
}
-void tur_set_async_timeout(struct checker *c)
+static void tur_set_async_timeout(struct checker *c)
{
struct tur_checker_context *ct = c->context;
- struct timeval now;
+ struct timespec now;
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
ct->time = now.tv_sec + c->timeout;
}
-int tur_check_async_timeout(struct checker *c)
+static int tur_check_async_timeout(struct checker *c)
{
struct tur_checker_context *ct = c->context;
- struct timeval now;
+ struct timespec now;
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
return (now.tv_sec > ct->time);
}
+static void copy_msg_to_checker(void *c_p, const char *msg)
+{
+ struct checker *c = c_p;
+
+ strlcpy(c->message, msg, sizeof(c->message));
+}
+
extern int
libcheck_check (struct checker * c)
{
@@ -271,41 +322,51 @@ libcheck_check (struct checker * c)
struct stat sb;
pthread_attr_t attr;
int tur_status, r;
+ char devt[32];
if (!ct)
return PATH_UNCHECKED;
- if (fstat(c->fd, &sb) == 0)
+ if (fstat(c->fd, &sb) == 0) {
+ pthread_mutex_lock(&ct->lock);
ct->devt = sb.st_rdev;
+ pthread_mutex_unlock(&ct->lock);
+ }
if (c->sync)
- return tur_check(c->fd, c->timeout, c->message);
+ return tur_check(c->fd, c->timeout, copy_msg_to_checker, c);
/*
* Async mode
*/
r = pthread_mutex_lock(&ct->lock);
if (r != 0) {
- condlog(2, "%d:%d: tur mutex lock failed with %d",
- TUR_DEVT(ct), r);
+ condlog(2, "%s: tur mutex lock failed with %d",
+ tur_devt(devt, sizeof(devt), ct), r);
MSG(c, MSG_TUR_FAILED);
return PATH_WILD;
}
if (ct->running) {
- /* Check if TUR checker is still running */
+ /*
+ * Check if TUR checker is still running. Hold hldr_lock
+ * around the pthread_cancel() call to avoid that
+ * pthread_cancel() gets called after the (detached) TUR
+ * thread has exited.
+ */
+ pthread_spin_lock(&ct->hldr_lock);
if (ct->thread) {
if (tur_check_async_timeout(c)) {
- condlog(3, "%d:%d: tur checker timeout",
- TUR_DEVT(ct));
+ condlog(3, "%s: tur checker timeout",
+ tur_devt(devt, sizeof(devt), ct));
pthread_cancel(ct->thread);
ct->running = 0;
MSG(c, MSG_TUR_TIMEOUT);
tur_status = PATH_TIMEOUT;
} else {
- condlog(3, "%d:%d: tur checker not finished",
- TUR_DEVT(ct));
+ condlog(3, "%s: tur checker not finished",
+ tur_devt(devt, sizeof(devt), ct));
ct->running++;
tur_status = PATH_PENDING;
}
@@ -313,16 +374,16 @@ libcheck_check (struct checker * c)
/* TUR checker done */
ct->running = 0;
tur_status = ct->state;
- strncpy(c->message, ct->message, CHECKER_MSG_LEN);
- c->message[CHECKER_MSG_LEN - 1] = '\0';
+ strlcpy(c->message, ct->message, sizeof(c->message));
}
+ pthread_spin_unlock(&ct->hldr_lock);
pthread_mutex_unlock(&ct->lock);
} else {
- if (ct->thread) {
+ if (tur_running(ct)) {
/* pthread cancel failed. continue in sync mode */
pthread_mutex_unlock(&ct->lock);
- condlog(3, "%d:%d: tur thread not responding",
- TUR_DEVT(ct));
+ condlog(3, "%s: tur thread not responding",
+ tur_devt(devt, sizeof(devt), ct));
return PATH_TIMEOUT;
}
/* Start new TUR checker */
@@ -335,27 +396,27 @@ libcheck_check (struct checker * c)
tur_set_async_timeout(c);
setup_thread_attr(&attr, 32 * 1024, 1);
r = pthread_create(&ct->thread, &attr, tur_thread, ct);
+ pthread_attr_destroy(&attr);
if (r) {
pthread_spin_lock(&ct->hldr_lock);
ct->holders--;
pthread_spin_unlock(&ct->hldr_lock);
pthread_mutex_unlock(&ct->lock);
ct->thread = 0;
- condlog(3, "%d:%d: failed to start tur thread, using"
- " sync mode", TUR_DEVT(ct));
- return tur_check(c->fd, c->timeout, c->message);
+ condlog(3, "%s: failed to start tur thread, using"
+ " sync mode", tur_devt(devt, sizeof(devt), ct));
+ return tur_check(c->fd, c->timeout,
+ copy_msg_to_checker, c);
}
- pthread_attr_destroy(&attr);
tur_timeout(&tsp);
r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp);
tur_status = ct->state;
- strncpy(c->message, ct->message,CHECKER_MSG_LEN);
- c->message[CHECKER_MSG_LEN - 1] = '\0';
+ strlcpy(c->message, ct->message, sizeof(c->message));
pthread_mutex_unlock(&ct->lock);
- if (ct->thread &&
+ if (tur_running(ct) &&
(tur_status == PATH_PENDING || tur_status == PATH_UNCHECKED)) {
- condlog(3, "%d:%d: tur checker still running",
- TUR_DEVT(ct));
+ condlog(3, "%s: tur checker still running",
+ tur_devt(devt, sizeof(devt), ct));
ct->running = 1;
tur_status = PATH_PENDING;
}
diff --git a/libmultipath/config.c b/libmultipath/config.c
index a48b8af..2d629ef 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -80,7 +80,8 @@ hwe_regmatch (struct hwentry *hwe1, struct hwentry *hwe2)
regcomp(&rre, hwe1->revision, REG_EXTENDED|REG_NOSUB))
goto out_pre;
- if ((!hwe1->vendor || !hwe2->vendor ||
+ if ((hwe2->vendor || hwe2->product || hwe2->revision) &&
+ (!hwe1->vendor || !hwe2->vendor ||
!regexec(&vre, hwe2->vendor, 0, NULL, 0)) &&
(!hwe1->product || !hwe2->product ||
!regexec(&pre, hwe2->product, 0, NULL, 0)) &&
@@ -347,6 +348,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
merge_num(deferred_remove);
merge_num(delay_watch_checks);
merge_num(delay_wait_checks);
+ merge_num(skip_kpartx);
/*
* Make sure features is consistent with
@@ -597,7 +599,7 @@ load_config (char * file)
conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
conf->features = set_default(DEFAULT_FEATURES);
- conf->flush_on_last_del = 0;
+ conf->flush_on_last_del = DEFAULT_FLUSH;
conf->attribute_flags = 0;
conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
conf->checkint = DEFAULT_CHECKINT;
@@ -606,8 +608,8 @@ load_config (char * file)
conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
conf->detect_prio = DEFAULT_DETECT_PRIO;
- conf->force_sync = 0;
- conf->partition_delim = NULL;
+ conf->force_sync = DEFAULT_FORCE_SYNC;
+ conf->partition_delim = DEFAULT_PARTITION_DELIM;
conf->processed_main_config = 0;
conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
@@ -616,6 +618,8 @@ load_config (char * file)
conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
+ conf->skip_kpartx = DEFAULT_SKIP_KPARTX;
+ conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS;
/*
* preload default hwtable
diff --git a/libmultipath/config.h b/libmultipath/config.h
index a41207a..dbdaa44 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -65,6 +65,7 @@ struct hwentry {
int deferred_remove;
int delay_watch_checks;
int delay_wait_checks;
+ int skip_kpartx;
char * bl_product;
};
@@ -91,6 +92,7 @@ struct mpentry {
int deferred_remove;
int delay_watch_checks;
int delay_wait_checks;
+ int skip_kpartx;
uid_t uid;
gid_t gid;
mode_t mode;
@@ -141,6 +143,8 @@ struct config {
int ignore_new_devs;
int delayed_reconfig;
int uev_wait_timeout;
+ int skip_kpartx;
+ int disable_changed_wwids;
unsigned int version[3];
char * multipath_dir;
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 707e6be..d428099 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -295,6 +295,7 @@ setup_map (struct multipath * mpp, char * params, int params_size)
select_deferred_remove(conf, mpp);
select_delay_watch_checks(conf, mpp);
select_delay_wait_checks(conf, mpp);
+ select_skip_kpartx(conf, mpp);
sysfs_set_scsi_tmo(mpp, conf->checkint);
put_multipath_config(conf);
@@ -641,14 +642,14 @@ domap (struct multipath * mpp, char * params, int is_daemon)
case ACT_RENAME:
conf = get_multipath_config();
r = dm_rename(mpp->alias_old, mpp->alias,
- conf->partition_delim);
+ conf->partition_delim, mpp->skip_kpartx);
put_multipath_config(conf);
break;
case ACT_FORCERENAME:
conf = get_multipath_config();
r = dm_rename(mpp->alias_old, mpp->alias,
- conf->partition_delim);
+ conf->partition_delim, mpp->skip_kpartx);
put_multipath_config(conf);
if (r)
r = dm_addmap_reload(mpp, params, 0);
@@ -808,8 +809,10 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
* at this point, we know we really got a new mp
*/
mpp = add_map_with_path(vecs, pp1, 0);
- if (!mpp)
- return 1;
+ if (!mpp) {
+ orphan_path(pp1, "failed to create multipath device");
+ continue;
+ }
if (pp1->priority == PRIO_UNDEF)
mpp->action = ACT_REJECT;
@@ -861,7 +864,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
condlog(3, "%s: domap (%u) failure "
"for create/reload map",
mpp->alias, r);
- if (r == DOMAP_FAIL) {
+ if (r == DOMAP_FAIL || is_daemon) {
condlog(2, "%s: %s map",
mpp->alias, (mpp->action == ACT_CREATE)?
"ignoring" : "removing");
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
index b2e344d..fbe171a 100644
--- a/libmultipath/debug.c
+++ b/libmultipath/debug.c
@@ -8,7 +8,7 @@
#include "log_pthread.h"
#include <sys/types.h>
#include <time.h>
-
+#include "../third-party/valgrind/drd.h"
#include "vector.h"
#include "config.h"
@@ -20,7 +20,9 @@ void dlog (int sink, int prio, const char * fmt, ...)
va_start(ap, fmt);
conf = get_multipath_config();
+ ANNOTATE_IGNORE_READS_BEGIN();
thres = (conf) ? conf->verbosity : 0;
+ ANNOTATE_IGNORE_READS_END();
put_multipath_config(conf);
if (prio <= thres) {
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index 9bf27d6..a72078f 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -28,9 +28,15 @@
#define DEFAULT_RETRIGGER_DELAY 10
#define DEFAULT_RETRIGGER_TRIES 3
#define DEFAULT_UEV_WAIT_TIMEOUT 30
-#define DEFAULT_PRIO "const"
+#define DEFAULT_PRIO PRIO_CONST
#define DEFAULT_PRIO_ARGS ""
#define DEFAULT_CHECKER TUR
+#define DEFAULT_FLUSH FLUSH_DISABLED
+#define DEFAULT_USER_FRIENDLY_NAMES USER_FRIENDLY_NAMES_OFF
+#define DEFAULT_FORCE_SYNC 0
+#define DEFAULT_PARTITION_DELIM NULL
+#define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF
+#define DEFAULT_DISABLE_CHANGED_WWIDS 0
#define DEFAULT_CHECKINT 5
#define MAX_CHECKINT(a) (a << 2)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 5eb1713..5aea5b6 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -213,8 +213,9 @@ dm_prereq (void)
static int
dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags, int deferred_remove) {
int r = 0;
- int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME ||
- task == DM_DEVICE_REMOVE));
+ int udev_wait_flag = ((need_sync || udev_flags) &&
+ (task == DM_DEVICE_RESUME ||
+ task == DM_DEVICE_REMOVE));
uint32_t cookie = 0;
struct dm_task *dmt;
@@ -266,11 +267,12 @@ dm_device_remove (const char *name, int needsync, int deferred_remove) {
static int
dm_addmap (int task, const char *target, struct multipath *mpp,
- char * params, int ro) {
+ char * params, int ro, int skip_kpartx) {
int r = 0;
struct dm_task *dmt;
char *prefixed_uuid = NULL;
uint32_t cookie = 0;
+ uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
if (!(dmt = dm_task_create (task)))
return 0;
@@ -319,8 +321,7 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
dm_task_no_open_count(dmt);
if (task == DM_DEVICE_CREATE &&
- !dm_task_set_cookie(dmt, &cookie,
- DM_UDEV_DISABLE_LIBRARY_FALLBACK))
+ !dm_task_set_cookie(dmt, &cookie, udev_flags))
goto freeout;
r = dm_task_run (dmt);
@@ -344,7 +345,8 @@ dm_addmap_create (struct multipath *mpp, char * params) {
for (ro = 0; ro <= 1; ro++) {
int err;
- if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, ro))
+ if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, ro,
+ mpp->skip_kpartx))
return 1;
/*
* DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
@@ -371,7 +373,9 @@ extern int
dm_addmap_reload (struct multipath *mpp, char *params, int flush)
{
int r;
- uint16_t udev_flags = flush ? 0 : MPATH_UDEV_RELOAD_FLAG;
+ uint16_t udev_flags = (flush ? 0 : MPATH_UDEV_RELOAD_FLAG) |
+ ((mpp->skip_kpartx == SKIP_KPARTX_ON)?
+ MPATH_UDEV_NO_KPARTX_FLAG : 0);
/*
* DM_DEVICE_RELOAD cannot wait on a cookie, as
@@ -379,12 +383,13 @@ dm_addmap_reload (struct multipath *mpp, char *params, int flush)
* DM_DEVICE_RESUME. So call DM_DEVICE_RESUME
* after each successful call to DM_DEVICE_RELOAD.
*/
- r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, ADDMAP_RW);
+ r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, ADDMAP_RW,
+ SKIP_KPARTX_OFF);
if (!r) {
if (errno != EROFS)
return 0;
r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp,
- params, ADDMAP_RO);
+ params, ADDMAP_RO, SKIP_KPARTX_OFF);
}
if (r)
r = dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, flush,
@@ -534,8 +539,8 @@ dm_get_status(char * name, char * outstatus)
int r = 1;
struct dm_task *dmt;
uint64_t start, length;
- char *target_type;
- char *status;
+ char *target_type = NULL;
+ char *status = NULL;
if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
return 1;
@@ -551,6 +556,10 @@ dm_get_status(char * name, char * outstatus)
/* Fetch 1st target */
dm_get_next_target(dmt, NULL, &start, &length,
&target_type, &status);
+ if (!status) {
+ condlog(2, "get null status.");
+ goto out;
+ }
if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
r = 0;
@@ -757,6 +766,12 @@ out:
}
static int
+has_partmap(const char *name, void *data)
+{
+ return 1;
+}
+
+static int
partmap_in_use(const char *name, void *data)
{
int part_count, *ret_count = (int *)data;
@@ -835,10 +850,16 @@ dm_suspend_and_flush_map (const char * mapname)
int s = 0, queue_if_no_path = 0;
unsigned long long mapsize;
char params[PARAMS_SIZE] = {0};
+ int udev_flags = 0;
if (!dm_is_mpath(mapname))
return 0; /* nothing to do */
+ /* if the device currently has no partitions, do not
+ run kpartx on it if you fail to delete it */
+ if (do_foreach_partmaps(mapname, has_partmap, NULL) == 0)
+ udev_flags |= MPATH_UDEV_NO_KPARTX_FLAG;
+
if (!dm_get_map(mapname, &mapsize, params)) {
if (strstr(params, "queue_if_no_path"))
queue_if_no_path = 1;
@@ -857,7 +878,7 @@ dm_suspend_and_flush_map (const char * mapname)
return 0;
}
condlog(2, "failed to remove multipath map %s", mapname);
- dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, 0);
+ dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, udev_flags);
if (queue_if_no_path)
s = dm_queue_if_no_path((char *)mapname, 1);
return 1;
@@ -1376,7 +1397,7 @@ rename_partmap (const char *name, void *data)
for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */
snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim,
name + offset);
- dm_rename(name, buff, rd->delim);
+ dm_rename(name, buff, rd->delim, SKIP_KPARTX_OFF);
condlog(4, "partition map %s renamed", name);
return 0;
}
@@ -1399,11 +1420,12 @@ dm_rename_partmaps (const char * old, char * new, char *delim)
}
int
-dm_rename (const char * old, char * new, char *delim)
+dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
{
int r = 0;
struct dm_task *dmt;
- uint32_t cookie;
+ uint32_t cookie = 0;
+ uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
if (dm_rename_partmaps(old, new, delim))
return r;
@@ -1419,8 +1441,7 @@ dm_rename (const char * old, char * new, char *delim)
dm_task_no_open_count(dmt);
- if (!dm_task_set_cookie(dmt, &cookie,
- DM_UDEV_DISABLE_LIBRARY_FALLBACK))
+ if (!dm_task_set_cookie(dmt, &cookie, udev_flags))
goto out;
r = dm_task_run(dmt);
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 442d42e..e6d1090 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -12,6 +12,12 @@
#define MPATH_UDEV_RELOAD_FLAG 0
#endif
+#ifdef DM_SUBSYSTEM_UDEV_FLAG1
+#define MPATH_UDEV_NO_KPARTX_FLAG DM_SUBSYSTEM_UDEV_FLAG1
+#else
+#define MPATH_UDEV_NO_KPARTX_FLAG 0
+#endif
+
void dm_init(int verbosity);
int dm_prereq (void);
int dm_drv_version (unsigned int * version, char * str);
@@ -46,7 +52,7 @@ int dm_remove_partmaps (const char * mapname, int need_sync,
int deferred_remove);
int dm_get_uuid(char *name, char *uuid);
int dm_get_info (char * mapname, struct dm_info ** dmi);
-int dm_rename (const char * old, char * new, char * delim);
+int dm_rename (const char * old, char * new, char * delim, int skip_kpartx);
int dm_reassign(const char * mapname);
int dm_reassign_table(const char *name, char *old, char *new);
int dm_setgeometry(struct multipath *mpp);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index e8c6804..61b6910 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -403,6 +403,18 @@ declare_def_snprint(uev_wait_timeout, print_int)
declare_def_handler(strict_timing, set_yes_no)
declare_def_snprint(strict_timing, print_yes_no)
+declare_def_handler(skip_kpartx, set_yes_no_undef)
+declare_def_snprint_defint(skip_kpartx, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(skip_kpartx, set_yes_no_undef)
+declare_ovr_snprint(skip_kpartx, print_yes_no_undef)
+declare_hw_handler(skip_kpartx, set_yes_no_undef)
+declare_hw_snprint(skip_kpartx, print_yes_no_undef)
+declare_mp_handler(skip_kpartx, set_yes_no_undef)
+declare_mp_snprint(skip_kpartx, print_yes_no_undef)
+
+declare_def_handler(disable_changed_wwids, set_yes_no)
+declare_def_snprint(disable_changed_wwids, print_yes_no)
+
static int
def_config_dir_handler(struct config *conf, vector strvec)
{
@@ -1330,7 +1342,7 @@ snprint_deprecated (struct config *conf, char * buff, int len, void * data)
#define __deprecated
/*
- * If you add or remove a keywork also update multipath/multipath.conf.5
+ * If you add or remove a keyword also update multipath/multipath.conf.5
*/
void
init_keywords(vector keywords)
@@ -1385,6 +1397,8 @@ init_keywords(vector keywords)
install_keyword("retrigger_tries", &def_retrigger_tries_handler, &snprint_def_retrigger_tries);
install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay);
install_keyword("missing_uev_wait_timeout", &def_uev_wait_timeout_handler, &snprint_def_uev_wait_timeout);
+ install_keyword("skip_kpartx", &def_skip_kpartx_handler, &snprint_def_skip_kpartx);
+ install_keyword("disable_changed_wwids", &def_disable_changed_wwids_handler, &snprint_def_disable_changed_wwids);
__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
@@ -1421,7 +1435,10 @@ init_keywords(vector keywords)
__deprecated install_keyword("product", &ble_product_handler, &snprint_bled_product);
__deprecated install_sublevel_end();
#endif
-
+/*
+ * If you add or remove a "device subsection" keyword also update
+ * multipath/multipath.conf.5 and the TEMPLATE in libmultipath/hwtable.c
+ */
install_keyword_root("devices", &devices_handler);
install_keyword_multi("device", &device_handler, NULL);
install_sublevel();
@@ -1455,6 +1472,7 @@ init_keywords(vector keywords)
install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove);
install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks);
install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks);
+ install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx);
install_sublevel_end();
install_keyword_root("overrides", &overrides_handler);
@@ -1482,6 +1500,7 @@ init_keywords(vector keywords)
install_keyword("deferred_remove", &ovr_deferred_remove_handler, &snprint_ovr_deferred_remove);
install_keyword("delay_watch_checks", &ovr_delay_watch_checks_handler, &snprint_ovr_delay_watch_checks);
install_keyword("delay_wait_checks", &ovr_delay_wait_checks_handler, &snprint_ovr_delay_wait_checks);
+ install_keyword("skip_kpartx", &ovr_skip_kpartx_handler, &snprint_ovr_skip_kpartx);
install_keyword_root("multipaths", &multipaths_handler);
install_keyword_multi("multipath", &multipath_handler, NULL);
@@ -1508,5 +1527,6 @@ init_keywords(vector keywords)
install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove);
install_keyword("delay_watch_checks", &mp_delay_watch_checks_handler, &snprint_mp_delay_watch_checks);
install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks);
+ install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx);
install_sublevel_end();
}
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index bb3116d..756344f 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1538,13 +1538,12 @@ get_prio (struct path * pp)
}
static int
-get_udev_uid(struct path * pp, char *uid_attribute)
+get_udev_uid(struct path * pp, char *uid_attribute, struct udev_device *udev)
{
ssize_t len;
const char *value;
- value = udev_device_get_property_value(pp->udev,
- uid_attribute);
+ value = udev_device_get_property_value(udev, uid_attribute);
if (!value || strlen(value) == 0)
value = getenv(uid_attribute);
if (value && strlen(value)) {
@@ -1625,8 +1624,8 @@ get_vpd_uid(struct path * pp)
return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE);
}
-static int
-get_uid (struct path * pp, int path_state)
+int
+get_uid (struct path * pp, int path_state, struct udev_device *udev)
{
char *c;
const char *origin = "unknown";
@@ -1639,7 +1638,7 @@ get_uid (struct path * pp, int path_state)
put_multipath_config(conf);
}
- if (!pp->udev) {
+ if (!udev) {
condlog(1, "%s: no udev information", pp->dev);
return 1;
}
@@ -1669,7 +1668,7 @@ get_uid (struct path * pp, int path_state)
int retrigger;
if (pp->uid_attribute) {
- len = get_udev_uid(pp, pp->uid_attribute);
+ len = get_udev_uid(pp, pp->uid_attribute, udev);
origin = "udev";
if (len <= 0)
condlog(1,
@@ -1798,7 +1797,7 @@ pathinfo (struct path *pp, struct config *conf, int mask)
}
if ((mask & DI_WWID) && !strlen(pp->wwid)) {
- get_uid(pp, path_state);
+ get_uid(pp, path_state, pp->udev);
if (!strlen(pp->wwid)) {
pp->initialized = INIT_MISSING_UDEV;
pp->tick = conf->retrigger_delay;
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index 0f5b1e6..176eac1 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -49,6 +49,7 @@ ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff,
size_t len);
int sysfs_get_asymmetric_access_state(struct path *pp,
char *buff, int buflen);
+int get_uid(struct path * pp, int path_state, struct udev_device *udev);
/*
* discovery bitmask
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 9e79ecd..87e8398 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -380,6 +380,14 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp,
strncpy(pp->wwid, mpp->wwid,
WWID_SIZE - 1);
+ /*
+ * Do not allow in-use patch to change wwid
+ */
+ else if (strcmp(pp->wwid, mpp->wwid) != 0) {
+ condlog(0, "%s: path wwid appears to have changed. Using map wwid.\n", pp->dev_t);
+ strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
+ }
+
pgp->id ^= (long)pp;
pp->pgindex = i + 1;
diff --git a/libmultipath/file.c b/libmultipath/file.c
index 74cde64..e4951c9 100644
--- a/libmultipath/file.c
+++ b/libmultipath/file.c
@@ -158,7 +158,7 @@ open_file(char *file, int *can_write, char *header)
goto fail;
/* If file is empty, write the header */
size_t len = strlen(header);
- if (write_all(fd, header, len) != len) {
+ if (write(fd, header, len) != len) {
condlog(0,
"Cannot write header to file %s : %s", file,
strerror(errno));
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index e518d6a..340035e 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -22,6 +22,9 @@
*
* Devices with a proprietary handler must also be included in
* the kernel side. Currently at drivers/scsi/scsi_dh.c
+ *
+ * Moreover, if a device needs a special treatment by the SCSI
+ * subsystem it should be included in drivers/scsi/scsi_devinfo.c
*/
static struct hwentry default_hw[] = {
/*
@@ -34,7 +37,6 @@ static struct hwentry default_hw[] = {
.vendor = "APPLE",
.product = "Xserve RAID",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
/*
* HPE
@@ -52,10 +54,9 @@ static struct hwentry default_hw[] = {
/* RA8000 / ESA12000 */
.vendor = "DEC",
.product = "HSG80",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.hwhandler = "1 hp_sw",
.pgpolicy = GROUP_BY_PRIO,
- .pgfailback = FAILBACK_UNDEF,
.checker_name = HP_SW,
.prio_name = PRIO_HP_SW,
},
@@ -64,19 +65,15 @@ static struct hwentry default_hw[] = {
.vendor = "HP",
.product = "A6189A",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 12,
},
{
/* MSA 1000/1500 and EVA 3000/5000, with old firmware */
.vendor = "(COMPAQ|HP)",
.product = "(MSA|HSV)1[01]0",
- .features = "1 queue_if_no_path",
.hwhandler = "1 hp_sw",
.pgpolicy = GROUP_BY_PRIO,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 12,
- .minio = 100,
.checker_name = HP_SW,
.prio_name = PRIO_HP_SW,
},
@@ -87,7 +84,6 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 12,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
{
@@ -97,7 +93,6 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 12,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
{
@@ -105,9 +100,7 @@ static struct hwentry default_hw[] = {
.vendor = "HP",
.product = "(MSA2[02]12fc|MSA2012i)",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 18,
- .minio = 100,
},
{
/* MSA2000 family with new firmware */
@@ -116,7 +109,6 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 18,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
{
@@ -126,7 +118,6 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 18,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
{
@@ -137,7 +128,6 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 12,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
{
@@ -145,7 +135,6 @@ static struct hwentry default_hw[] = {
.vendor = "HP",
.product = "LOGICAL VOLUME",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 12,
},
{
@@ -155,7 +144,15 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 18,
- .minio = 100,
+ .prio_name = PRIO_ALUA,
+ },
+ {
+ /* StoreVirtual 4000 family */
+ .vendor = "LEFTHAND",
+ .product = "^(P4000|iSCSIDisk)",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 18,
.prio_name = PRIO_ALUA,
},
/*
@@ -165,25 +162,36 @@ static struct hwentry default_hw[] = {
.vendor = "DDN",
.product = "SAN DataDirector",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
+ },
+ {
+ .vendor = "DDN",
+ .product = "^EF3010",
+ .pgpolicy = MULTIBUS,
+ .no_path_retry = 30,
+ },
+ {
+ .vendor = "DDN",
+ .product = "^(EF3015|S2A|SFA)",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 30,
},
/*
- * EMC
+ * Dell EMC
*/
{
/* Symmetrix / DMX / VMAX */
.vendor = "EMC",
.product = "SYMMETRIX",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 6,
},
{
- /* DGC CLARiiON CX/AX and EMC VNX */
+ /* DGC CLARiiON CX/AX / EMC VNX and Unity */
.vendor = "^DGC",
.product = "^(RAID|DISK|VRAID)",
.bl_product = "LUNZ",
- .features = "1 queue_if_no_path",
.hwhandler = "1 emc",
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
@@ -197,26 +205,26 @@ static struct hwentry default_hw[] = {
.product = "Invista",
.bl_product = "LUNZ",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 5,
},
{
.vendor = "XtremIO",
.product = "XtremApp",
- .selector = "queue-length 0",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
- /*
- * DELL
- */
{
+ /*
+ * Dell SC Series, formerly Compellent
+ *
+ * Maintainer : Sean McGinnis
+ * Mail : sean_mcginnis@dell.com
+ */
.vendor = "COMPELNT",
.product = "Compellent Vol",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = NO_PATH_RETRY_QUEUE,
},
+ /* MD Series */
{
.vendor = "DELL",
.product = "MD3000",
@@ -260,12 +268,10 @@ static struct hwentry default_hw[] = {
.vendor = "FSC",
.product = "CentricStor",
.pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
},
{
.vendor = "FUJITSU",
.product = "ETERNUS_DX(H|L|M|400|8000)",
- .features = "1 queue_if_no_path",
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 10,
@@ -276,7 +282,14 @@ static struct hwentry default_hw[] = {
.vendor = "(EUROLOGC|EuroLogc)",
.product = "FC2502",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
+ },
+ {
+ .vendor = "FUJITSU",
+ .product = "E[248]000",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 10,
+ .prio_name = PRIO_ALUA,
},
/*
* Hitachi
@@ -289,13 +302,12 @@ static struct hwentry default_hw[] = {
.vendor = "(HITACHI|HP)",
.product = "^OPEN-",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
/* AMS 2000 and HUS 100 families */
- .vendor = "HITACHI",
+ .vendor = "(HITACHI|HP)",
.product = "^DF",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.prio_name = PRIO_HDS,
@@ -310,7 +322,6 @@ static struct hwentry default_hw[] = {
.vendor = "IBM",
.product = "ProFibre 4000R",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
/* DS4300 / FAStT600 */
@@ -339,7 +350,7 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
- /* DS3200 / DS3300 / DS3400 / Boot DS */
+ /* DS3000 / DS3200 / DS3300 / DS3400 / Boot DS */
.vendor = "IBM",
.product = "^1726",
.bl_product = "Universal Xport",
@@ -443,42 +454,46 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
- /* DS4200 / FAStT200 */
+ /* FAStT200 and FAStT500 */
.vendor = "IBM",
- .product = "^3542",
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
+ .product = "^(3542|3552)",
+ .bl_product = "Universal Xport",
+ .pgpolicy = GROUP_BY_PRIO,
+ .checker_name = RDAC,
+ .features = "2 pg_init_retries 50",
+ .hwhandler = "1 rdac",
+ .prio_name = PRIO_RDAC,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 30,
},
{
/* Enterprise Storage Server / Shark family */
.vendor = "IBM",
.product = "^2105",
- .features = "1 queue_if_no_path",
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
+ .pgpolicy = MULTIBUS,
},
{
- /* DS6000 */
+ /* DS6000 / DS6800 */
.vendor = "IBM",
.product = "^1750500",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.prio_name = PRIO_ALUA,
},
{
- /* DS8000 */
+ /* DS8000 family */
.vendor = "IBM",
.product = "^2107900",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
- /* Storwize family / SAN Volume Controller / Flex System V7000 */
+ /* Storwize family / SAN Volume Controller / Flex System V7000 / FlashSystem V840/V9000 */
.vendor = "IBM",
.product = "^2145",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.prio_name = PRIO_ALUA,
@@ -488,24 +503,22 @@ static struct hwentry default_hw[] = {
.product = "S/390 DASD ECKD",
.bl_product = "S/390",
.uid_attribute = "ID_UID",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
.vendor = "IBM",
.product = "S/390 DASD FBA",
.bl_product = "S/390",
.uid_attribute = "ID_UID",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
/* Power RAID */
.vendor = "IBM",
.product = "^IPR",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.hwhandler = "1 alua",
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
@@ -518,17 +531,30 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
{
- /* XIV Storage System */
+ /* XIV Storage System / FlashSystem A9000/A9000R */
.vendor = "IBM",
.product = "2810XIV",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
+ .pgpolicy = MULTIBUS,
+ },
+ {
+ /* FlashSystem 710/720/810/820/840/900 */
+ .vendor = "IBM",
+ .product = "FlashSystem",
+ .no_path_retry = NO_PATH_RETRY_FAIL,
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .minio = 15,
+ },
+ {
+ /* DDN */
+ .vendor = "IBM",
+ .product = "^(DCS9900|2851)",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 30,
},
/*
* IBM Power Virtual SCSI Devices
@@ -540,14 +566,12 @@ static struct hwentry default_hw[] = {
.vendor = "AIX",
.product = "VDASD",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = (300 / DEFAULT_CHECKINT),
},
{
/* 3303 NVDISK */
.vendor = "IBM",
.product = "3303[ ]+NVDISK",
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = (300 / DEFAULT_CHECKINT),
},
{
@@ -571,11 +595,11 @@ static struct hwentry default_hw[] = {
*/
.vendor = "NETAPP",
.product = "LUN",
- .features = "3 queue_if_no_path pg_init_retries 50",
+ .features = "2 pg_init_retries 50",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.flush_on_last_del = FLUSH_ENABLED,
- .minio = 128,
.dev_loss = MAX_DEV_LOSS_TMO,
.prio_name = PRIO_ONTAP,
},
@@ -597,6 +621,18 @@ static struct hwentry default_hw[] = {
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 30,
},
+ {
+ /*
+ * SolidFir family
+ *
+ * Maintainer : PJ Waskiewicz
+ * Mail : pj.waskiewicz@netapp.com
+ */
+ .vendor = "SolidFir",
+ .product = "SSD SAN",
+ .pgpolicy = MULTIBUS,
+ .no_path_retry = 24,
+ },
/*
* Nexenta
*
@@ -606,11 +642,8 @@ static struct hwentry default_hw[] = {
{
.vendor = "NEXENTA",
.product = "COMSTAR",
- .features = "1 queue_if_no_path",
.pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
.no_path_retry = 30,
- .minio = 128,
},
/*
* SGI
@@ -619,11 +652,11 @@ static struct hwentry default_hw[] = {
.vendor = "SGI",
.product = "TP9100",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
+ /* Total Performance family */
.vendor = "SGI",
- .product = "TP9[345]00",
+ .product = "TP9[3457]00",
.bl_product = "Universal Xport",
.pgpolicy = GROUP_BY_PRIO,
.checker_name = RDAC,
@@ -634,7 +667,7 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
- /* InfiniteStorage ??? */
+ /* InfiniteStorage family */
.vendor = "SGI",
.product = "IS",
.bl_product = "Universal Xport",
@@ -646,6 +679,15 @@ static struct hwentry default_hw[] = {
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 30,
},
+ {
+ /* DDN */
+ .vendor = "SGI",
+ .product = "^DD[46]A-",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 30,
+ },
/*
* NEC
*/
@@ -683,8 +725,9 @@ static struct hwentry default_hw[] = {
},
/* Sun - StorageTek */
{
+ /* B210, B220, B240 and B280 */
.vendor = "STK",
- .product = "OPENstorage D280",
+ .product = "BladeCtlr",
.bl_product = "Universal Xport",
.pgpolicy = GROUP_BY_PRIO,
.checker_name = RDAC,
@@ -695,6 +738,20 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
+ /* 9176, D173, D178, D210, D220, D240 and D280 */
+ .vendor = "STK",
+ .product = "OPENstorage",
+ .bl_product = "Universal Xport",
+ .pgpolicy = GROUP_BY_PRIO,
+ .checker_name = RDAC,
+ .features = "2 pg_init_retries 50",
+ .hwhandler = "1 rdac",
+ .prio_name = PRIO_RDAC,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 30,
+ },
+ {
+ /* 6540 */
.vendor = "STK",
.product = "FLEXLINE 380",
.bl_product = "Universal Xport",
@@ -707,10 +764,10 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
+ /* 3510 / 6020 and 6120 */
.vendor = "SUN",
.product = "(StorEdge 3510|T4)",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
{
.vendor = "SUN",
@@ -725,9 +782,9 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
- /* 6140 */
+ /* 6130 / 6140 */
.vendor = "SUN",
- .product = "CSM200_R",
+ .product = "CSM[12]00_R",
.bl_product = "Universal Xport",
.pgpolicy = GROUP_BY_PRIO,
.checker_name = RDAC,
@@ -738,7 +795,7 @@ static struct hwentry default_hw[] = {
.no_path_retry = 30,
},
{
- /* 2510 / 2530 / 2540 */
+ /* 2500 / 2510 / 2530 / 2540 */
.vendor = "SUN",
.product = "LCSM100_[IEFS]",
.bl_product = "Universal Xport",
@@ -762,6 +819,15 @@ static struct hwentry default_hw[] = {
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 30,
},
+ {
+ /* ZFS Storage Appliances */
+ .vendor = "SUN",
+ .product = "(Sun Storage|ZFS Storage|COMSTAR)",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 30,
+ },
/*
* Pivot3
*
@@ -771,10 +837,16 @@ static struct hwentry default_hw[] = {
{
.vendor = "PIVOT3",
.product = "RAIGE VOLUME",
- .features = "1 queue_if_no_path",
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .minio = 100,
+ },
+ {
+ .vendor = "(NexGen|Pivot3)",
+ .product = "(TierStore|vSTAC)",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
},
/*
* Intel
@@ -782,6 +854,7 @@ static struct hwentry default_hw[] = {
{
.vendor = "(Intel|INTEL)",
.product = "Multi-Flex",
+ .bl_product = "VTrak V-LUN",
.hwhandler = "1 alua",
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
@@ -798,7 +871,6 @@ static struct hwentry default_hw[] = {
.pgpolicy = GROUP_BY_PRIO,
.pgfailback = -FAILBACK_IMMEDIATE,
.no_path_retry = 12,
- .minio = 100,
.prio_name = PRIO_ALUA,
},
/*
@@ -826,9 +898,7 @@ static struct hwentry default_hw[] = {
{
.vendor = "PURE",
.product = "FlashArray",
- .selector = "queue-length 0",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
.fast_io_fail = 10,
.dev_loss = 60,
},
@@ -840,7 +910,6 @@ static struct hwentry default_hw[] = {
.vendor = "(HUAWEI|HUASY)",
.product = "XSG1",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
},
/*
* Red Hat
@@ -862,16 +931,135 @@ static struct hwentry default_hw[] = {
.vendor = "KOVE",
.product = "XPD",
.pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
+ },
+ /*
+ * Infinidat
+ */
+ {
+ .vendor = "NFINIDAT",
+ .product = "InfiniBox",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ },
+ /*
+ * Nimble Storage
+ */
+ {
+ .vendor = "Nimble",
+ .product = "Server",
+ .hwhandler = "1 alua",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
+ },
+ /*
+ * Kaminario
+ */
+ {
+ .vendor = "KMNRIO",
+ .product = "K2",
+ .pgpolicy = MULTIBUS,
+ },
+ /*
+ * Tegile Systems
+ */
+ {
+ .vendor = "TEGILE",
+ .product = "(ZEBI-(FC|ISCSI)|INTELLIFLASH)",
+ .hwhandler = "1 alua",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 10,
+ },
+ /*
+ * Imation/Nexsan
+ */
+ {
+ /* E-Series */
+ .vendor = "NEXSAN",
+ .product = "NXS-B0",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 15,
+ },
+ {
+ /* SATABeast / SATABoy */
+ .vendor = "NEXSAN",
+ .product = "SATAB",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 15,
+ },
+ /*
+ * Xiotech
+ */
+ {
+ /* Intelligent Storage Elements family */
+ .vendor = "(XIOTECH|XIOtech)",
+ .product = "ISE",
+ .pgpolicy = MULTIBUS,
+ .no_path_retry = 12,
+ },
+ /*
+ * Violin Memory
+ */
+ {
+ /* 3000 / 6000 Series */
+ .vendor = "VIOLIN",
+ .product = "SAN ARRAY$",
+ .pgpolicy = GROUP_BY_SERIAL,
+ .no_path_retry = 30,
+ },
+ {
+ .vendor = "VIOLIN",
+ .product = "SAN ARRAY ALUA",
+ .hwhandler = "1 alua",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 30,
+ },
+ {
+ /* FSP 7000 family */
+ .vendor = "VIOLIN",
+ .product = "CONCERTO ARRAY",
+ .pgpolicy = MULTIBUS,
+ .no_path_retry = 30,
+ },
+ /*
+ * Promise Technology
+ */
+ {
+ .vendor = "Promise",
+ .product = "VTrak",
+ .bl_product = "VTrak V-LUN",
+ .pgpolicy = MULTIBUS,
+ .no_path_retry = 30,
+ },
+ /*
+ * Infortrend Technology
+ */
+ {
+ /* EonStor / ESVA */
+ .vendor = "^IFT",
+ .product = ".*",
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .prio_name = PRIO_ALUA,
+ .no_path_retry = 30,
},
#if 0
/*
* Copy this TEMPLATE to add new hardware.
*
- * Keep only mandatory and modified attributes.
+ * Keep only mandatory(.vendor and .product) and modified attributes.
* Attributes with default values must be removed.
- * Only .vendor and .product are mandatory, all other are optional.
- * .vendor, .product, .revision and .bl_product are POSIX Extended regex
+ * .vendor, .product, .revision and .bl_product are POSIX Extended regex.
*
* COMPANY_NAME
*
@@ -888,9 +1076,10 @@ static struct hwentry default_hw[] = {
.uid_attribute = "ID_SERIAL",
.selector = "service-time 0",
.checker_name = TUR,
+ .alias_prefix = "mpath",
.features = "0",
.hwhandler = "0",
- .prio_name = "const",
+ .prio_name = PRIO_CONST,
.prio_args = "",
.pgfailback = -FAILBACK_MANUAL,
.rr_weight = RR_WEIGHT_NONE,
@@ -898,6 +1087,7 @@ static struct hwentry default_hw[] = {
.minio = 1000,
.minio_rq = 1,
.flush_on_last_del = FLUSH_DISABLED,
+ .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
.fast_io_fail = 5,
.dev_loss = 600,
.retain_hwhandler = RETAIN_HWHANDLER_ON,
diff --git a/libmultipath/log.c b/libmultipath/log.c
index ab92e2a..debd36d 100644
--- a/libmultipath/log.c
+++ b/libmultipath/log.c
@@ -15,6 +15,8 @@
#define ALIGN(len, s) (((len)+(s)-1)/(s)*(s))
+struct logarea* la;
+
#if LOGDBG
static void dump_logarea (void)
{
diff --git a/libmultipath/log.h b/libmultipath/log.h
index 984f047..6551b5c 100644
--- a/libmultipath/log.h
+++ b/libmultipath/log.h
@@ -29,7 +29,7 @@ struct logarea {
char * buff;
};
-struct logarea * la;
+extern struct logarea* la;
int log_init (char * progname, int size);
void log_close (void);
diff --git a/libmultipath/memory.c b/libmultipath/memory.c
index 5441e6a..293a688 100644
--- a/libmultipath/memory.c
+++ b/libmultipath/memory.c
@@ -20,6 +20,7 @@
* Copyright (C) 2001-2005 Alexandre Cassen, <acassen@linux-vs.org>
*/
+#include <assert.h>
#include "memory.h"
/*
diff --git a/libmultipath/memory.h b/libmultipath/memory.h
index 29a75ed..a3c478e 100644
--- a/libmultipath/memory.h
+++ b/libmultipath/memory.h
@@ -27,7 +27,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
/* Local defines */
#ifdef _DEBUG_
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 94d6384..865562b 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -73,7 +73,6 @@ static int
snprint_size (char * buff, size_t len, unsigned long long size)
{
float s = (float)(size >> 1); /* start with KB */
- char fmt[6] = {};
char units[] = {'K','M','G','T','P'};
char *u = units;
@@ -81,12 +80,8 @@ snprint_size (char * buff, size_t len, unsigned long long size)
s = s / 1024;
u++;
}
- if (s < 10)
- snprintf(fmt, 6, "%%.1f%c", *u);
- else
- snprintf(fmt, 6, "%%.0f%c", *u);
- return snprintf(buff, len, fmt, s);
+ return snprintf(buff, len, "%.*f%c", s < 10, s, *u);
}
/*
@@ -250,6 +245,12 @@ snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
}
static int
+snprint_map_failures (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_uint(buff, len, mpp->stat_map_failures);
+}
+
+static int
snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
{
return snprint_str(buff, len, mpp->wwid);
@@ -624,6 +625,7 @@ struct multipath_data mpd[] = {
{'t', "dm-st", 0, snprint_dm_map_state},
{'S', "size", 0, snprint_multipath_size},
{'f', "features", 0, snprint_features},
+ {'x', "failures", 0, snprint_map_failures},
{'h', "hwhandler", 0, snprint_hwhandler},
{'A', "action", 0, snprint_action},
{'0', "path_faults", 0, snprint_path_faults},
@@ -783,7 +785,7 @@ snprint_multipath_header (char * line, int len, char * format)
struct multipath_data * data;
do {
- if (!TAIL)
+ if (TAIL <= 0)
break;
if (*f != '%') {
@@ -816,7 +818,7 @@ snprint_multipath (char * line, int len, char * format,
char buff[MAX_FIELD_LEN] = {};
do {
- if (!TAIL)
+ if (TAIL <= 0)
break;
if (*f != '%') {
@@ -850,7 +852,7 @@ snprint_path_header (char * line, int len, char * format)
struct path_data * data;
do {
- if (!TAIL)
+ if (TAIL <= 0)
break;
if (*f != '%') {
@@ -883,7 +885,7 @@ snprint_path (char * line, int len, char * format,
char buff[MAX_FIELD_LEN];
do {
- if (!TAIL)
+ if (TAIL <= 0)
break;
if (*f != '%') {
@@ -918,7 +920,7 @@ snprint_pathgroup (char * line, int len, char * format,
char buff[MAX_FIELD_LEN];
do {
- if (!TAIL)
+ if (TAIL <= 0)
break;
if (*f != '%') {
@@ -1009,11 +1011,11 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp, 1);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp,
1);
- if (fwd > len)
+ if (fwd >= len)
return len;
if (!mpp->pg)
@@ -1027,7 +1029,7 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
} else
strcpy(f, "`-+- " PRINT_PG_INDENT);
fwd += snprint_pathgroup(buff + fwd, len - fwd, fmt, pgp);
- if (fwd > len)
+ if (fwd >= len)
return len;
vector_foreach_slot (pgp->paths, pp, i) {
@@ -1040,13 +1042,14 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
else
strcpy(f, " `- " PRINT_PATH_INDENT);
fwd += snprint_path(buff + fwd, len - fwd, fmt, pp, 1);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
}
return fwd;
}
+
static int
snprint_json (char * buff, int len, int indent, char *json_str)
{
@@ -1054,7 +1057,7 @@ snprint_json (char * buff, int len, int indent, char *json_str)
for (i = 0; i < indent; i++) {
fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
}
@@ -1068,7 +1071,7 @@ snprint_json_header (char * buff, int len)
int fwd = 0;
fwd += snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_START_VERSION,
@@ -1083,7 +1086,7 @@ snprint_json_elem_footer (char * buff, int len, int indent, int last)
for (i = 0; i < indent; i++) {
fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
}
@@ -1103,50 +1106,50 @@ snprint_multipath_fields_json (char * buff, int len,
struct pathgroup *pgp;
fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
vector_foreach_slot (mpp->pg, pgp, i) {
pgp->selector = mpp->selector;
fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
vector_foreach_slot (pgp->paths, pp, j) {
fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprint_json_elem_footer(buff + fwd,
len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
- if (fwd > len)
+ if (fwd >= len)
return fwd;
}
fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprint_json_elem_footer(buff + fwd,
len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
- if (fwd > len)
+ if (fwd >= len)
return fwd;
}
fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
- if (fwd > len)
+ if (fwd >= len)
return fwd;
fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
@@ -1159,23 +1162,23 @@ snprint_multipath_map_json (char * buff, int len,
int fwd = 0;
fwd += snprint_json_header(buff, len);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_json(buff + fwd, len - fwd, 0, "\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1187,26 +1190,26 @@ snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs)
struct multipath * mpp;
fwd += snprint_json_header(buff, len);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_json(buff + fwd, len - fwd, 1, PRINT_JSON_START_MAPS);
- if (fwd > len)
+ if (fwd >= len)
return len;
vector_foreach_slot(vecs->mpvec, mpp, i) {
fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1230,16 +1233,16 @@ snprint_hwentry (struct config *conf, char * buff, int len, struct hwentry * hwe
return 0;
fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
iterate_sub_keywords(rootkw, kw, i) {
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, hwe);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1257,15 +1260,15 @@ snprint_hwtable (struct config *conf, char * buff, int len, vector hwtable)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
vector_foreach_slot (hwtable, hwe, i) {
fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1283,16 +1286,16 @@ snprint_mpentry (struct config *conf, char * buff, int len, struct mpentry * mpe
return 0;
fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
iterate_sub_keywords(rootkw, kw, i) {
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, mpe);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1310,15 +1313,15 @@ snprint_mptable (struct config *conf, char * buff, int len, vector mptable)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
vector_foreach_slot (mptable, mpe, i) {
fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1336,19 +1339,19 @@ snprint_overrides (struct config *conf, char * buff, int len, struct hwentry *ov
return 0;
fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
if (!overrides)
goto out;
iterate_sub_keywords(rootkw, kw, i) {
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, NULL);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
out:
fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1366,17 +1369,17 @@ snprint_defaults (struct config *conf, char * buff, int len)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
iterate_sub_keywords(rootkw, kw, i) {
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, NULL);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1513,7 +1516,7 @@ snprint_blacklist (struct config *conf, char * buff, int len)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
vector_foreach_slot (conf->blist_devnode, ble, i) {
@@ -1522,7 +1525,7 @@ snprint_blacklist (struct config *conf, char * buff, int len)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, ble);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
vector_foreach_slot (conf->blist_wwid, ble, i) {
@@ -1531,7 +1534,7 @@ snprint_blacklist (struct config *conf, char * buff, int len)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, ble);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
vector_foreach_slot (conf->blist_property, ble, i) {
@@ -1540,7 +1543,7 @@ snprint_blacklist (struct config *conf, char * buff, int len)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, ble);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
@@ -1549,28 +1552,28 @@ snprint_blacklist (struct config *conf, char * buff, int len)
vector_foreach_slot (conf->blist_device, bled, i) {
fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, bled);
- if (fwd > len)
+ if (fwd >= len)
return len;
kw = find_keyword(conf->keywords, rootkw->sub, "product");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, bled);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1590,7 +1593,7 @@ snprint_blacklist_except (struct config *conf, char * buff, int len)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
vector_foreach_slot (conf->elist_devnode, ele, i) {
@@ -1599,7 +1602,7 @@ snprint_blacklist_except (struct config *conf, char * buff, int len)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, ele);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
vector_foreach_slot (conf->elist_wwid, ele, i) {
@@ -1608,7 +1611,7 @@ snprint_blacklist_except (struct config *conf, char * buff, int len)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, ele);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
vector_foreach_slot (conf->elist_property, ele, i) {
@@ -1617,7 +1620,7 @@ snprint_blacklist_except (struct config *conf, char * buff, int len)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
kw, ele);
- if (fwd > len)
+ if (fwd >= len)
return len;
}
rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
@@ -1626,28 +1629,28 @@ snprint_blacklist_except (struct config *conf, char * buff, int len)
vector_foreach_slot (conf->elist_device, eled, i) {
fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, eled);
- if (fwd > len)
+ if (fwd >= len)
return len;
kw = find_keyword(conf->keywords, rootkw->sub, "product");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, eled);
- if (fwd > len)
+ if (fwd >= len)
return len;
fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
}
fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1679,7 +1682,7 @@ snprint_status (char * buff, int len, struct vectors *vecs)
fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
monitored_count, is_uevent_busy()? "True" : "False");
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
@@ -1745,17 +1748,11 @@ snprint_devices (struct config *conf, char * buff, int len, struct vectors *vecs
}
closedir(blkdir);
- if (fwd > len)
+ if (fwd >= len)
return len;
return fwd;
}
-extern int
-snprint_config (char * buff, int len)
-{
- return 0;
-}
-
/*
* stdout printing helpers
*/
diff --git a/libmultipath/prio.h b/libmultipath/prio.h
index 261105b..0193c52 100644
--- a/libmultipath/prio.h
+++ b/libmultipath/prio.h
@@ -64,4 +64,7 @@ char * prio_name (struct prio *);
char * prio_args (struct prio *);
int prio_set_args (struct prio *, char *);
+/* The only function exported by prioritizer dynamic libraries (.so) */
+int getprio(struct path *, char *, unsigned int);
+
#endif /* _PRIO_H */
diff --git a/libmultipath/prioritizers/alua.c b/libmultipath/prioritizers/alua.c
index 5636974..03d0a0e 100644
--- a/libmultipath/prioritizers/alua.c
+++ b/libmultipath/prioritizers/alua.c
@@ -31,8 +31,8 @@ static const char * aas_string[] = {
[AAS_NON_OPTIMIZED] = "active/non-optimized",
[AAS_STANDBY] = "standby",
[AAS_UNAVAILABLE] = "unavailable",
- [AAS_LBA_DEPENDENT] = "lba dependent",
- [AAS_RESERVED] = "invalid/reserved",
+ [AAS_LBA_DEPENDENT] = "logical block dependent",
+ [AAS_RESERVED] = "ARRAY BUG: invalid TPGs state!",
[AAS_OFFLINE] = "offline",
[AAS_TRANSITIONING] = "transitioning between states",
};
@@ -65,12 +65,12 @@ get_alua_info(struct path * pp, unsigned int timeout)
return -ALUA_PRIO_NOT_SUPPORTED;
return -ALUA_PRIO_RTPG_FAILED;
}
- condlog(3, "reported target port group is %i", tpg);
+ condlog(3, "%s: reported target port group is %i", pp->dev, tpg);
rc = get_asymmetric_access_state(pp->fd, tpg, timeout);
if (rc < 0)
return -ALUA_PRIO_GETAAS_FAILED;
- condlog(3, "aas = %02x [%s]%s", rc, aas_print_string(rc),
+ condlog(3, "%s: aas = %02x [%s]%s", pp->dev, rc, aas_print_string(rc),
(rc & 0x80) ? " [preferred]" : "");
return rc;
}
diff --git a/libmultipath/prioritizers/const.c b/libmultipath/prioritizers/const.c
index 9d9d003..aad6927 100644
--- a/libmultipath/prioritizers/const.c
+++ b/libmultipath/prioritizers/const.c
@@ -2,7 +2,7 @@
#include "prio.h"
-int getprio (struct path * pp, char * args)
+int getprio(struct path * pp, char * args, unsigned int timeout)
{
return 1;
}
diff --git a/libmultipath/prioritizers/datacore.c b/libmultipath/prioritizers/datacore.c
index 050a94c..36465ac 100644
--- a/libmultipath/prioritizers/datacore.c
+++ b/libmultipath/prioritizers/datacore.c
@@ -106,7 +106,7 @@ int datacore_prio (const char *dev, int sg_fd, char * args)
return 0;
}
-int getprio (struct path * pp, char * args)
+int getprio(struct path * pp, char * args, unsigned int timeout)
{
return datacore_prio(pp->dev, pp->fd, args);
}
diff --git a/libmultipath/prioritizers/iet.c b/libmultipath/prioritizers/iet.c
index aa852a0..a4ea61e 100644
--- a/libmultipath/prioritizers/iet.c
+++ b/libmultipath/prioritizers/iet.c
@@ -138,7 +138,7 @@ int iet_prio(const char *dev, char * args)
return 10;
}
-int getprio(struct path * pp, char * args)
+int getprio(struct path * pp, char * args, unsigned int timeout)
{
return iet_prio(pp->dev, args);
}
diff --git a/libmultipath/prioritizers/ontap.c b/libmultipath/prioritizers/ontap.c
index 4084c65..38495cd 100644
--- a/libmultipath/prioritizers/ontap.c
+++ b/libmultipath/prioritizers/ontap.c
@@ -17,7 +17,6 @@
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
-#include <assert.h>
#include "sg_include.h"
#include "debug.h"
diff --git a/libmultipath/prioritizers/random.c b/libmultipath/prioritizers/random.c
index c3ea3ac..4a27123 100644
--- a/libmultipath/prioritizers/random.c
+++ b/libmultipath/prioritizers/random.c
@@ -5,7 +5,7 @@
#include "prio.h"
-int getprio (struct path * pp, char * args)
+int getprio(struct path * pp, char * args, unsigned int timeout)
{
struct timeval tv;
diff --git a/libmultipath/prioritizers/weightedpath.c b/libmultipath/prioritizers/weightedpath.c
index a62b86e..34a43a8 100644
--- a/libmultipath/prioritizers/weightedpath.c
+++ b/libmultipath/prioritizers/weightedpath.c
@@ -151,7 +151,7 @@ int prio_path_weight(struct path *pp, char *prio_args)
return priority;
}
-int getprio(struct path *pp, char *args)
+int getprio(struct path *pp, char *args, unsigned int timeout)
{
return prio_path_weight(pp, args);
}
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 1625990..ec1fd92 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -137,7 +137,7 @@ select_rr_weight (struct config *conf, struct multipath * mp)
mp_set_ovr(rr_weight);
mp_set_hwe(rr_weight);
mp_set_conf(rr_weight);
- mp_set_default(rr_weight, RR_WEIGHT_NONE);
+ mp_set_default(rr_weight, DEFAULT_RR_WEIGHT);
out:
print_rr_weight(buff, 13, &mp->rr_weight);
condlog(3, "%s: rr_weight = %s %s", mp->alias, buff, origin);
@@ -228,7 +228,7 @@ want_user_friendly_names(struct config *conf, struct multipath * mp)
"(controller setting)");
do_set(user_friendly_names, conf, user_friendly_names,
"(config file setting)");
- do_default(user_friendly_names, USER_FRIENDLY_NAMES_OFF);
+ do_default(user_friendly_names, DEFAULT_USER_FRIENDLY_NAMES);
out:
condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
(user_friendly_names == USER_FRIENDLY_NAMES_ON)? "yes" : "no",
@@ -550,7 +550,7 @@ select_flush_on_last_del(struct config *conf, struct multipath *mp)
mp_set_ovr(flush_on_last_del);
mp_set_hwe(flush_on_last_del);
mp_set_conf(flush_on_last_del);
- mp_set_default(flush_on_last_del, FLUSH_DISABLED);
+ mp_set_default(flush_on_last_del, DEFAULT_FLUSH);
out:
condlog(3, "%s: flush_on_last_del = %s %s", mp->alias,
(mp->flush_on_last_del == FLUSH_ENABLED)? "yes" : "no", origin);
@@ -665,4 +665,22 @@ out:
print_delay_checks(buff, 12, &mp->delay_wait_checks);
condlog(3, "%s: delay_wait_checks = %s %s", mp->alias, buff, origin);
return 0;
+
+}
+
+extern int
+select_skip_kpartx (struct config *conf, struct multipath * mp)
+{
+ char *origin;
+
+ mp_set_mpe(skip_kpartx);
+ mp_set_ovr(skip_kpartx);
+ mp_set_hwe(skip_kpartx);
+ mp_set_conf(skip_kpartx);
+ mp_set_default(skip_kpartx, DEFAULT_SKIP_KPARTX);
+out:
+ condlog(3, "%s: skip_kpartx = %s %s", mp->alias,
+ (mp->skip_kpartx == SKIP_KPARTX_ON)? "yes" : "no",
+ origin);
+ return 0;
}
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index 5941a5f..3e6d607 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -22,3 +22,4 @@ int select_detect_prio(struct config *conf, struct path * pp);
int select_deferred_remove(struct config *conf, struct multipath *mp);
int select_delay_watch_checks (struct config *conf, struct multipath * mp);
int select_delay_wait_checks (struct config *conf, struct multipath * mp);
+int select_skip_kpartx (struct config *conf, struct multipath * mp);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index fee58e5..e4bf4c6 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -520,6 +520,17 @@ add_feature (char **f, char *n)
if (!n || *n == '0')
return 0;
+ /* default feature is null */
+ if(!*f)
+ {
+ l = asprintf(&t, "1 %s", n);
+ if(l == -1)
+ return 1;
+
+ *f = t;
+ return 0;
+ }
+
/* Check if feature is already present */
if (strstr(*f, n))
return 0;
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index cb5d532..58508f6 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -128,6 +128,12 @@ enum deferred_remove_states {
DEFERRED_REMOVE_IN_PROGRESS,
};
+enum skip_kpartx_states {
+ SKIP_KPARTX_UNDEF = YNU_UNDEF,
+ SKIP_KPARTX_OFF = YNU_NO,
+ SKIP_KPARTX_ON = YNU_YES,
+};
+
enum scsi_protocol {
SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
@@ -211,6 +217,7 @@ struct path {
int fd;
int initialized;
int retriggers;
+ int wwid_changed;
/* configlet pointers */
struct hwentry * hwe;
@@ -243,6 +250,7 @@ struct multipath {
int deferred_remove;
int delay_watch_checks;
int delay_wait_checks;
+ int skip_kpartx;
unsigned int dev_loss;
uid_t uid;
gid_t gid;
@@ -270,6 +278,7 @@ struct multipath {
unsigned int stat_map_loads;
unsigned int stat_total_queueing_time;
unsigned int stat_queueing_timeouts;
+ unsigned int stat_map_failures;
/* checkers shared data */
void * mpcontext;
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index a0c8869..e898528 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -610,19 +610,23 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset)
*/
void update_queue_mode_del_path(struct multipath *mpp)
{
- if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
- struct config *conf = get_multipath_config();
+ if (--mpp->nr_active == 0) {
+ if (mpp->no_path_retry > 0) {
+ struct config *conf = get_multipath_config();
- /*
- * 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);
- put_multipath_config(conf);
+ /*
+ * 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);
+ put_multipath_config(conf);
+ } else if (mpp->no_path_retry != NO_PATH_RETRY_QUEUE)
+ mpp->stat_map_failures++;
}
condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
}
diff --git a/libmultipath/time-util.c b/libmultipath/time-util.c
new file mode 100644
index 0000000..6d79c0e
--- /dev/null
+++ b/libmultipath/time-util.c
@@ -0,0 +1,42 @@
+#include <assert.h>
+#include <pthread.h>
+#include <time.h>
+#include "time-util.h"
+
+/* Initialize @cond as a condition variable that uses the monotonic clock */
+void pthread_cond_init_mono(pthread_cond_t *cond)
+{
+ pthread_condattr_t attr;
+ int res;
+
+ res = pthread_condattr_init(&attr);
+ assert(res == 0);
+ res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ assert(res == 0);
+ res = pthread_cond_init(cond, &attr);
+ assert(res == 0);
+ res = pthread_condattr_destroy(&attr);
+ assert(res == 0);
+}
+
+/* Ensure that 0 <= ts->tv_nsec && ts->tv_nsec < 1000 * 1000 * 1000. */
+void normalize_timespec(struct timespec *ts)
+{
+ while (ts->tv_nsec < 0) {
+ ts->tv_nsec += 1000UL * 1000 * 1000;
+ ts->tv_sec--;
+ }
+ while (ts->tv_nsec >= 1000UL * 1000 * 1000) {
+ ts->tv_nsec -= 1000UL * 1000 * 1000;
+ ts->tv_sec++;
+ }
+}
+
+/* Compute *res = *a - *b */
+void timespecsub(const struct timespec *a, const struct timespec *b,
+ struct timespec *res)
+{
+ res->tv_sec = a->tv_sec - b->tv_sec;
+ res->tv_nsec = a->tv_nsec - b->tv_nsec;
+ normalize_timespec(res);
+}
diff --git a/libmultipath/time-util.h b/libmultipath/time-util.h
new file mode 100644
index 0000000..b76d2aa
--- /dev/null
+++ b/libmultipath/time-util.h
@@ -0,0 +1,13 @@
+#ifndef _TIME_UTIL_H_
+#define _TIME_UTIL_H_
+
+#include <pthread.h>
+
+struct timespec;
+
+void pthread_cond_init_mono(pthread_cond_t *cond);
+void normalize_timespec(struct timespec *ts);
+void timespecsub(const struct timespec *a, const struct timespec *b,
+ struct timespec *res);
+
+#endif /* _TIME_UTIL_H_ */
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index 6247898..19b910f 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -37,7 +37,6 @@
#include <linux/types.h>
#include <linux/netlink.h>
#include <pthread.h>
-#include <limits.h>
#include <sys/mman.h>
#include <libudev.h>
#include <errno.h>
@@ -50,7 +49,6 @@
typedef int (uev_trigger)(struct uevent *, void * trigger_data);
-pthread_t uevq_thr;
LIST_HEAD(uevq);
pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t *uevq_lockp = &uevq_lock;
@@ -81,33 +79,6 @@ struct uevent * alloc_uevent (void)
}
void
-setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached)
-{
- if (pthread_attr_init(attr)) {
- fprintf(stderr, "can't initialize thread attr: %s\n",
- strerror(errno));
- exit(1);
- }
- if (stacksize < PTHREAD_STACK_MIN)
- stacksize = PTHREAD_STACK_MIN;
-
- if (pthread_attr_setstacksize(attr, stacksize)) {
- fprintf(stderr, "can't set thread stack size to %lu: %s\n",
- (unsigned long)stacksize, strerror(errno));
- exit(1);
- }
- if (detached && pthread_attr_setdetachstate(attr,
- PTHREAD_CREATE_DETACHED)) {
- fprintf(stderr, "can't set thread to detached: %s\n",
- strerror(errno));
- exit(1);
- }
-}
-
-/*
- * Called with uevq_lockp held
- */
-void
service_uevq(struct list_head *tmpq)
{
struct uevent *uev, *tmp;
@@ -124,15 +95,11 @@ service_uevq(struct list_head *tmpq)
}
}
-static void uevq_stop(void *arg)
+static void uevent_cleanup(void *arg)
{
struct udev *udev = arg;
- condlog(3, "Stopping uev queue");
- pthread_mutex_lock(uevq_lockp);
- my_uev_trigger = NULL;
- pthread_cond_signal(uev_condp);
- pthread_mutex_unlock(uevq_lockp);
+ condlog(3, "Releasing uevent_listen() resources");
udev_unref(udev);
}
@@ -495,7 +462,7 @@ int uevent_listen(struct udev *udev)
return 1;
}
udev_ref(udev);
- pthread_cleanup_push(uevq_stop, udev);
+ pthread_cleanup_push(uevent_cleanup, udev);
monitor = udev_monitor_new_from_netlink(udev, "udev");
if (!monitor) {
diff --git a/libmultipath/uevent.h b/libmultipath/uevent.h
index e5fdfcc..9d22dcd 100644
--- a/libmultipath/uevent.h
+++ b/libmultipath/uevent.h
@@ -27,7 +27,6 @@ struct uevent {
};
int is_uevent_busy(void);
-void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);
int uevent_listen(struct udev *udev);
int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data),
diff --git a/libmultipath/util.c b/libmultipath/util.c
index ac0d1b2..0a136b4 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -1,7 +1,10 @@
-#include <string.h>
+#include <assert.h>
#include <ctype.h>
-#include <sys/types.h>
+#include <limits.h>
+#include <pthread.h>
+#include <string.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
@@ -258,3 +261,21 @@ dev_t parse_devt(const char *dev_t)
return makedev(maj, min);
}
+
+void
+setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached)
+{
+ int ret;
+
+ ret = pthread_attr_init(attr);
+ assert(ret == 0);
+ if (stacksize < PTHREAD_STACK_MIN)
+ stacksize = PTHREAD_STACK_MIN;
+ ret = pthread_attr_setstacksize(attr, stacksize);
+ assert(ret == 0);
+ if (detached) {
+ ret = pthread_attr_setdetachstate(attr,
+ PTHREAD_CREATE_DETACHED);
+ assert(ret == 0);
+ }
+}
diff --git a/libmultipath/util.h b/libmultipath/util.h
index 8861085..f3b37ee 100644
--- a/libmultipath/util.h
+++ b/libmultipath/util.h
@@ -12,6 +12,7 @@ size_t strlcat(char *dst, const char *src, size_t size);
int devt2devname (char *, int, char *);
dev_t parse_devt(const char *dev_t);
char *convert_dev(char *dev, int is_path_device);
+void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);
#define safe_sprintf(var, format, args...) \
snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
diff --git a/libmultipath/uxsock.c b/libmultipath/uxsock.c
index 775e278..b158a56 100644
--- a/libmultipath/uxsock.c
+++ b/libmultipath/uxsock.c
@@ -81,7 +81,7 @@ size_t write_all(int fd, const void *buf, size_t len)
size_t total = 0;
while (len) {
- ssize_t n = write(fd, buf, len);
+ ssize_t n = send(fd, buf, len, MSG_NOSIGNAL);
if (n < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
@@ -116,7 +116,7 @@ ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout)
if (errno == EINTR)
continue;
return -errno;
- } else if (!pfd.revents & POLLIN)
+ } else if (!(pfd.revents & POLLIN))
continue;
n = read(fd, buf, len);
if (n < 0) {
@@ -138,20 +138,7 @@ ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout)
*/
int send_packet(int fd, const char *buf)
{
- int ret = 0;
- sigset_t set, old;
-
- /* Block SIGPIPE */
- sigemptyset(&set);
- sigaddset(&set, SIGPIPE);
- pthread_sigmask(SIG_BLOCK, &set, &old);
-
- ret = mpath_send_cmd(fd, buf);
-
- /* And unblock it again */
- pthread_sigmask(SIG_SETMASK, &old, NULL);
-
- return ret;
+ return mpath_send_cmd(fd, buf);
}
/*
diff --git a/libmultipath/version.h b/libmultipath/version.h
index dea59fe..f00476d 100644
--- a/libmultipath/version.h
+++ b/libmultipath/version.h
@@ -20,8 +20,8 @@
#ifndef _VERSION_H
#define _VERSION_H
-#define VERSION_CODE 0x000603
-#define DATE_CODE 0x080f10
+#define VERSION_CODE 0x000604
+#define DATE_CODE 0x030b10
#define PROG "multipath-tools"
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index babf149..bc70a27 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -71,7 +71,7 @@ write_out_wwid(int fd, char *wwid) {
strerror(errno));
return -1;
}
- if (write_all(fd, buf, strlen(buf)) != strlen(buf)) {
+ if (write(fd, buf, strlen(buf)) != strlen(buf)) {
condlog(0, "cannot write wwid to wwids file : %s",
strerror(errno));
if (ftruncate(fd, offset))
@@ -110,7 +110,7 @@ replace_wwids(vector mp)
goto out_file;
}
len = strlen(WWIDS_FILE_HEADER);
- if (write_all(fd, WWIDS_FILE_HEADER, len) != len) {
+ if (write(fd, WWIDS_FILE_HEADER, len) != len) {
condlog(0, "Can't write wwid file header : %s",
strerror(errno));
/* cleanup partially written header */