diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2022-01-14 13:50:16 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2022-01-14 13:50:16 +0900 |
commit | aa543d0c97d19f8c42b291742df51424f5b5b2c4 (patch) | |
tree | 598cdd7755478cc8adf500b4196738254900f3cb /libmultipath | |
parent | 4f76c358dbfe7a94eefbfab498e6c62bb887110d (diff) | |
download | multipath-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')
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 */ |