version = %{rel_ver}.%{rel_date}
release = 1
+thisapp = %{name}-%{rel_date}
rel_ver = 0.4.9
-rel_date = 120613
+rel_date = 130222
groups = System/Base
url = http://christophe.varoqui.free.fr/
instructing the device-mapper multipath kernel module what to do.
end
-thisapp = %{name}-%{rel_date}
-
sources = %{thisapp}.tgz
build
readline-devel
end
- prepare_cmds
- # Fix hardcoded install location for udev rules.
- sed -e "s@lib/udev@usr/lib/udev@g" -i multipath/Makefile
- end
+ make_build_targets += LIB=%{lib}
# Install everything to the correct locations.
- make_install_targets +=\
+ make_install_targets += \
bindir=%{sbindir} \
syslibdir=%{libdir} \
libdir=%{libdir}/multipath \
--- /dev/null
+---
+ multipathd/multipathd.service | 1 +
+ 1 file changed, 1 insertion(+)
+
+Index: multipath-tools-130222/multipathd/multipathd.service
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.service
++++ multipath-tools-130222/multipathd/multipathd.service
+@@ -2,6 +2,7 @@
+ Description=Device-Mapper Multipath Device Controller
+ Before=iscsi.service iscsid.service lvm2-activation-early.service
+ After=syslog.target
++ConditionPathExists=/etc/multipath.conf
+ DefaultDependencies=no
+ Conflicts=shutdown.target
+
+++ /dev/null
----
- libmultipath/Makefile | 2
- libmultipath/callout.c | 217 -----------------------------------------------
- libmultipath/callout.h | 7 -
- libmultipath/discovery.c | 1
- multipathd/main.c | 1
- 5 files changed, 1 insertion(+), 227 deletions(-)
-
-Index: multipath-tools-120518/libmultipath/Makefile
-===================================================================
---- multipath-tools-120518.orig/libmultipath/Makefile
-+++ multipath-tools-120518/libmultipath/Makefile
-@@ -9,7 +9,7 @@ DEVLIB = libmultipath.so
- LIBS = $(DEVLIB).$(SONAME)
- LIBDEPS = -lpthread -ldl -ldevmapper -ludev
-
--OBJS = memory.o parser.o vector.o devmapper.o callout.o \
-+OBJS = memory.o parser.o vector.o devmapper.o \
- hwtable.o blacklist.o util.o dmparser.o config.o \
- structs.o discovery.o propsel.o dict.o \
- pgpolicies.o debug.o regex.o defaults.o uevent.o \
-Index: multipath-tools-120518/libmultipath/callout.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/callout.c
-+++ /dev/null
-@@ -1,217 +0,0 @@
--/*
-- * Source: copy of the udev package source file
-- *
-- * Copyrights of the source file apply
-- * Copyright (c) 2004 Christophe Varoqui
-- */
--#include <stdio.h>
--#include <sys/stat.h>
--#include <string.h>
--#include <unistd.h>
--#include <sys/types.h>
--#include <stdlib.h>
--#include <fcntl.h>
--#include <sys/wait.h>
--#include <errno.h>
--
--#include "checkers.h"
--#include "vector.h"
--#include "structs.h"
--#include "util.h"
--#include "debug.h"
--
--int execute_program(char *path, char *value, int len)
--{
-- int retval;
-- int count;
-- int status;
-- int fds[2], null_fd;
-- pid_t pid;
-- char *pos;
-- char arg[CALLOUT_MAX_SIZE];
-- int argc = sizeof(arg) / 2;
-- char *argv[argc + 1];
-- int i;
--
-- i = 0;
--
-- if (strchr(path, ' ')) {
-- strlcpy(arg, path, sizeof(arg));
-- pos = arg;
-- while (pos != NULL && i < argc) {
-- if (pos[0] == '\'') {
-- /* don't separate if in apostrophes */
-- pos++;
-- argv[i] = strsep(&pos, "\'");
-- while (pos[0] == ' ')
-- pos++;
-- } else {
-- argv[i] = strsep(&pos, " ");
-- }
-- i++;
-- }
-- } else {
-- argv[i++] = path;
-- }
-- argv[i] = NULL;
--
-- retval = pipe(fds);
--
-- if (retval != 0) {
-- condlog(0, "error creating pipe for callout: %s", strerror(errno));
-- return -1;
-- }
--
-- pid = fork();
--
-- switch(pid) {
-- case 0:
-- /* child */
-- close(STDOUT_FILENO);
--
-- /* dup write side of pipe to STDOUT */
-- if (dup(fds[1]) < 0)
-- return -1;
--
-- /* Ignore writes to stderr */
-- null_fd = open("/dev/null", O_WRONLY);
-- if (null_fd > 0) {
-- close(STDERR_FILENO);
-- dup(null_fd);
-- close(null_fd);
-- }
--
-- retval = execv(argv[0], argv);
-- condlog(0, "error execing %s : %s", argv[0], strerror(errno));
-- exit(-1);
-- case -1:
-- condlog(0, "fork failed: %s", strerror(errno));
-- close(fds[0]);
-- close(fds[1]);
-- return -1;
-- default:
-- /* parent reads from fds[0] */
-- close(fds[1]);
-- retval = 0;
-- i = 0;
-- while (1) {
-- count = read(fds[0], value + i, len - i-1);
-- if (count <= 0)
-- break;
--
-- i += count;
-- if (i >= len-1) {
-- condlog(0, "not enough space for response from %s", argv[0]);
-- retval = -1;
-- break;
-- }
-- }
--
-- if (count < 0) {
-- condlog(0, "no response from %s", argv[0]);
-- retval = -1;
-- }
--
-- if (i > 0 && value[i-1] == '\n')
-- i--;
-- value[i] = '\0';
--
-- wait(&status);
-- close(fds[0]);
--
-- retval = -1;
-- if (WIFEXITED(status)) {
-- status = WEXITSTATUS(status);
-- if (status == 0)
-- retval = 0;
-- else
-- condlog(0, "%s exitted with %d", argv[0], status);
-- }
-- else if (WIFSIGNALED(status))
-- condlog(0, "%s was terminated by signal %d", argv[0], WTERMSIG(status));
-- else
-- condlog(0, "%s terminated abnormally", argv[0]);
-- }
-- return retval;
--}
--
--extern int
--apply_format (char * string, char * cmd, struct path * pp)
--{
-- char * pos;
-- char * dst;
-- char * p;
-- char * q;
-- int len;
-- int myfree;
--
-- if (!string)
-- return 1;
--
-- if (!cmd)
-- return 1;
--
-- dst = cmd;
-- p = dst;
-- pos = strchr(string, '%');
-- myfree = CALLOUT_MAX_SIZE;
--
-- if (!pos) {
-- strcpy(dst, string);
-- return 0;
-- }
--
-- len = (int) (pos - string) + 1;
-- myfree -= len;
--
-- if (myfree < 2)
-- return 1;
--
-- snprintf(p, len, "%s", string);
-- p += len - 1;
-- pos++;
--
-- switch (*pos) {
-- case 'n':
-- len = strlen(pp->dev) + 1;
-- myfree -= len;
--
-- if (myfree < 2)
-- return 1;
--
-- snprintf(p, len, "%s", pp->dev);
-- for (q = p; q < p + len; q++) {
-- if (q && *q == '!')
-- *q = '/';
-- }
-- p += len - 1;
-- break;
-- case 'd':
-- len = strlen(pp->dev_t) + 1;
-- myfree -= len;
--
-- if (myfree < 2)
-- return 1;
--
-- snprintf(p, len, "%s", pp->dev_t);
-- p += len - 1;
-- break;
-- default:
-- break;
-- }
-- pos++;
--
-- if (!*pos)
-- return 0;
--
-- len = strlen(pos) + 1;
-- myfree -= len;
--
-- if (myfree < 2)
-- return 1;
--
-- snprintf(p, len, "%s", pos);
-- condlog(3, "reformated callout = %s", dst);
-- return 0;
--}
--
-Index: multipath-tools-120518/libmultipath/callout.h
-===================================================================
---- multipath-tools-120518.orig/libmultipath/callout.h
-+++ /dev/null
-@@ -1,7 +0,0 @@
--#ifndef _CALLOUT_H
--#define _CALLOUT_H
--
--int execute_program(char *, char *, int);
--int apply_format (char *, char *, struct path *);
--
--#endif /* _CALLOUT_H */
-Index: multipath-tools-120518/libmultipath/discovery.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/discovery.c
-+++ multipath-tools-120518/libmultipath/discovery.c
-@@ -20,7 +20,6 @@
- #include "structs.h"
- #include "config.h"
- #include "blacklist.h"
--#include "callout.h"
- #include "debug.h"
- #include "propsel.h"
- #include "sg_include.h"
-Index: multipath-tools-120518/multipathd/main.c
-===================================================================
---- multipath-tools-120518.orig/multipathd/main.c
-+++ multipath-tools-120518/multipathd/main.c
-@@ -35,7 +35,6 @@
- #include <hwtable.h>
- #include <defaults.h>
- #include <structs.h>
--#include <callout.h>
- #include <blacklist.h>
- #include <structs_vec.h>
- #include <dmparser.h>
+++ /dev/null
----
- libmultipath/Makefile | 2
- libmultipath/alias.c | 153 ---------------------------------------
- libmultipath/alias.h | 1
- libmultipath/configure.c | 3
- libmultipath/defaults.h | 1
- libmultipath/discovery.c | 2
- libmultipath/file.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++
- libmultipath/file.h | 11 ++
- libmultipath/wwids.c | 139 ++++++++++++++++++++++++++++++++++++
- libmultipath/wwids.h | 18 ++++
- multipath/main.c | 37 ++++++++-
- 11 files changed, 389 insertions(+), 158 deletions(-)
-
-Index: multipath-tools-120518/libmultipath/alias.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/alias.c
-+++ multipath-tools-120518/libmultipath/alias.c
-@@ -3,19 +3,16 @@
- * Copyright (c) 2005 Benjamin Marzinski, Redhat
- */
- #include <stdlib.h>
--#include <sys/types.h>
--#include <sys/stat.h>
--#include <fcntl.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <limits.h>
- #include <stdio.h>
--#include <signal.h>
-
- #include "debug.h"
- #include "uxsock.h"
- #include "alias.h"
-+#include "file.h"
-
-
- /*
-@@ -36,150 +33,6 @@
- * See the file COPYING included with this distribution for more details.
- */
-
--static int
--ensure_directories_exist(char *str, mode_t dir_mode)
--{
-- char *pathname;
-- char *end;
-- int err;
--
-- pathname = strdup(str);
-- if (!pathname){
-- condlog(0, "Cannot copy bindings file pathname : %s",
-- strerror(errno));
-- return -1;
-- }
-- end = pathname;
-- /* skip leading slashes */
-- while (end && *end && (*end == '/'))
-- end++;
--
-- while ((end = strchr(end, '/'))) {
-- /* if there is another slash, make the dir. */
-- *end = '\0';
-- err = mkdir(pathname, dir_mode);
-- if (err && errno != EEXIST) {
-- condlog(0, "Cannot make directory [%s] : %s",
-- pathname, strerror(errno));
-- free(pathname);
-- return -1;
-- }
-- if (!err)
-- condlog(3, "Created dir [%s]", pathname);
-- *end = '/';
-- end++;
-- }
-- free(pathname);
-- return 0;
--}
--
--static void
--sigalrm(int sig)
--{
-- /* do nothing */
--}
--
--static int
--lock_bindings_file(int fd)
--{
-- struct sigaction act, oldact;
-- sigset_t set, oldset;
-- struct flock lock;
-- int err;
--
-- memset(&lock, 0, sizeof(lock));
-- lock.l_type = F_WRLCK;
-- lock.l_whence = SEEK_SET;
--
-- act.sa_handler = sigalrm;
-- sigemptyset(&act.sa_mask);
-- act.sa_flags = 0;
-- sigemptyset(&set);
-- sigaddset(&set, SIGALRM);
--
-- sigaction(SIGALRM, &act, &oldact);
-- sigprocmask(SIG_UNBLOCK, &set, &oldset);
--
-- alarm(BINDINGS_FILE_TIMEOUT);
-- err = fcntl(fd, F_SETLKW, &lock);
-- alarm(0);
--
-- if (err) {
-- if (errno != EINTR)
-- condlog(0, "Cannot lock bindings file : %s",
-- strerror(errno));
-- else
-- condlog(0, "Bindings file is locked. Giving up.");
-- }
--
-- sigprocmask(SIG_SETMASK, &oldset, NULL);
-- sigaction(SIGALRM, &oldact, NULL);
-- return err;
--
--}
--
--
--static int
--open_bindings_file(char *file, int *can_write)
--{
-- int fd;
-- struct stat s;
--
-- if (ensure_directories_exist(file, 0700))
-- return -1;
-- *can_write = 1;
-- fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
-- if (fd < 0) {
-- if (errno == EROFS) {
-- *can_write = 0;
-- condlog(3, "Cannot open bindings file [%s] read/write. "
-- " trying readonly", file);
-- fd = open(file, O_RDONLY);
-- if (fd < 0) {
-- condlog(0, "Cannot open bindings file [%s] "
-- "readonly : %s", file, strerror(errno));
-- return -1;
-- }
-- }
-- else {
-- condlog(0, "Cannot open bindings file [%s] : %s", file,
-- strerror(errno));
-- return -1;
-- }
-- }
-- if (*can_write && lock_bindings_file(fd) < 0)
-- goto fail;
--
-- memset(&s, 0, sizeof(s));
-- if (fstat(fd, &s) < 0){
-- condlog(0, "Cannot stat bindings file : %s", strerror(errno));
-- goto fail;
-- }
-- if (s.st_size == 0) {
-- if (*can_write == 0)
-- goto fail;
-- /* If bindings file is empty, write the header */
-- size_t len = strlen(BINDINGS_FILE_HEADER);
-- if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) {
-- condlog(0,
-- "Cannot write header to bindings file : %s",
-- strerror(errno));
-- /* cleanup partially written header */
-- if (ftruncate(fd, 0))
-- condlog(0, "Cannot truncate the header : %s",
-- strerror(errno));
-- goto fail;
-- }
-- fsync(fd);
-- condlog(3, "Initialized new bindings file [%s]", file);
-- }
--
-- return fd;
--
--fail:
-- close(fd);
-- return -1;
--}
-
- static int
- format_devname(char *name, int id, int len, char *prefix)
-@@ -370,7 +223,7 @@ get_user_friendly_alias(char *wwid, char
- return NULL;
- }
-
-- fd = open_bindings_file(file, &can_write);
-+ fd = open_file(file, &can_write, BINDINGS_FILE_HEADER);
- if (fd < 0)
- return NULL;
-
-@@ -414,7 +267,7 @@ get_user_friendly_wwid(char *alias, char
- return NULL;
- }
-
-- fd = open_bindings_file(file, &unused);
-+ fd = open_file(file, &unused, BINDINGS_FILE_HEADER);
- if (fd < 0)
- return NULL;
-
-Index: multipath-tools-120518/libmultipath/alias.h
-===================================================================
---- multipath-tools-120518.orig/libmultipath/alias.h
-+++ multipath-tools-120518/libmultipath/alias.h
-@@ -1,4 +1,3 @@
--#define BINDINGS_FILE_TIMEOUT 30
- #define BINDINGS_FILE_HEADER \
- "# Multipath bindings, Version : 1.0\n" \
- "# NOTE: this file is automatically maintained by the multipath program.\n" \
-Index: multipath-tools-120518/libmultipath/configure.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/configure.c
-+++ multipath-tools-120518/libmultipath/configure.c
-@@ -37,6 +37,7 @@
- #include "prio.h"
- #include "util.h"
- #include "uxsock.h"
-+#include "wwids.h"
-
- extern int
- setup_map (struct multipath * mpp, char * params, int params_size)
-@@ -407,6 +408,8 @@ domap (struct multipath * mpp, char * pa
- * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
- * succeeded
- */
-+ if (mpp->action == ACT_CREATE)
-+ remember_wwid(mpp->wwid);
- if (!conf->daemon) {
- /* multipath client mode */
- dm_switchgroup(mpp->alias, mpp->bestpg);
-Index: multipath-tools-120518/libmultipath/defaults.h
-===================================================================
---- multipath-tools-120518.orig/libmultipath/defaults.h
-+++ multipath-tools-120518/libmultipath/defaults.h
-@@ -24,5 +24,6 @@
- #define DEFAULT_SOCKET "/var/run/multipathd.sock"
- #define DEFAULT_CONFIGFILE "/etc/multipath.conf"
- #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings"
-+#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
-
- char * set_default (char * str);
-Index: multipath-tools-120518/libmultipath/file.c
-===================================================================
---- /dev/null
-+++ multipath-tools-120518/libmultipath/file.c
-@@ -0,0 +1,180 @@
-+/*
-+ * Copyright (c) 2005 Christophe Varoqui
-+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
-+ */
-+#include <stdlib.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <string.h>
-+#include <limits.h>
-+#include <stdio.h>
-+#include <signal.h>
-+
-+#include "file.h"
-+#include "debug.h"
-+#include "uxsock.h"
-+
-+
-+/*
-+ * significant parts of this file were taken from iscsi-bindings.c of the
-+ * linux-iscsi project.
-+ * Copyright (C) 2002 Cisco Systems, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published
-+ * by the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * See the file COPYING included with this distribution for more details.
-+ */
-+
-+static int
-+ensure_directories_exist(char *str, mode_t dir_mode)
-+{
-+ char *pathname;
-+ char *end;
-+ int err;
-+
-+ pathname = strdup(str);
-+ if (!pathname){
-+ condlog(0, "Cannot copy file pathname %s : %s",
-+ str, strerror(errno));
-+ return -1;
-+ }
-+ end = pathname;
-+ /* skip leading slashes */
-+ while (end && *end && (*end == '/'))
-+ end++;
-+
-+ while ((end = strchr(end, '/'))) {
-+ /* if there is another slash, make the dir. */
-+ *end = '\0';
-+ err = mkdir(pathname, dir_mode);
-+ if (err && errno != EEXIST) {
-+ condlog(0, "Cannot make directory [%s] : %s",
-+ pathname, strerror(errno));
-+ free(pathname);
-+ return -1;
-+ }
-+ if (!err)
-+ condlog(3, "Created dir [%s]", pathname);
-+ *end = '/';
-+ end++;
-+ }
-+ free(pathname);
-+ return 0;
-+}
-+
-+static void
-+sigalrm(int sig)
-+{
-+ /* do nothing */
-+}
-+
-+static int
-+lock_file(int fd, char *file_name)
-+{
-+ struct sigaction act, oldact;
-+ sigset_t set, oldset;
-+ struct flock lock;
-+ int err;
-+
-+ memset(&lock, 0, sizeof(lock));
-+ lock.l_type = F_WRLCK;
-+ lock.l_whence = SEEK_SET;
-+
-+ act.sa_handler = sigalrm;
-+ sigemptyset(&act.sa_mask);
-+ act.sa_flags = 0;
-+ sigemptyset(&set);
-+ sigaddset(&set, SIGALRM);
-+
-+ sigaction(SIGALRM, &act, &oldact);
-+ sigprocmask(SIG_UNBLOCK, &set, &oldset);
-+
-+ alarm(FILE_TIMEOUT);
-+ err = fcntl(fd, F_SETLKW, &lock);
-+ alarm(0);
-+
-+ if (err) {
-+ if (errno != EINTR)
-+ condlog(0, "Cannot lock %s : %s", file_name,
-+ strerror(errno));
-+ else
-+ condlog(0, "%s is locked. Giving up.", file_name);
-+ }
-+
-+ sigprocmask(SIG_SETMASK, &oldset, NULL);
-+ sigaction(SIGALRM, &oldact, NULL);
-+ return err;
-+}
-+
-+int
-+open_file(char *file, int *can_write, char *header)
-+{
-+ int fd;
-+ struct stat s;
-+
-+ if (ensure_directories_exist(file, 0700))
-+ return -1;
-+ *can_write = 1;
-+ fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
-+ if (fd < 0) {
-+ if (errno == EROFS) {
-+ *can_write = 0;
-+ condlog(3, "Cannot open file [%s] read/write. "
-+ " trying readonly", file);
-+ fd = open(file, O_RDONLY);
-+ if (fd < 0) {
-+ condlog(0, "Cannot open file [%s] "
-+ "readonly : %s", file, strerror(errno));
-+ return -1;
-+ }
-+ }
-+ else {
-+ condlog(0, "Cannot open file [%s] : %s", file,
-+ strerror(errno));
-+ return -1;
-+ }
-+ }
-+ if (*can_write && lock_file(fd, file) < 0)
-+ goto fail;
-+
-+ memset(&s, 0, sizeof(s));
-+ if (fstat(fd, &s) < 0){
-+ condlog(0, "Cannot stat file %s : %s", file, strerror(errno));
-+ goto fail;
-+ }
-+ if (s.st_size == 0) {
-+ if (*can_write == 0)
-+ goto fail;
-+ /* If file is empty, write the header */
-+ size_t len = strlen(header);
-+ if (write_all(fd, header, len) != len) {
-+ condlog(0,
-+ "Cannot write header to file %s : %s", file,
-+ strerror(errno));
-+ /* cleanup partially written header */
-+ if (ftruncate(fd, 0))
-+ condlog(0, "Cannot truncate header : %s",
-+ strerror(errno));
-+ goto fail;
-+ }
-+ fsync(fd);
-+ condlog(3, "Initialized new file [%s]", file);
-+ }
-+
-+ return fd;
-+
-+fail:
-+ close(fd);
-+ return -1;
-+}
-Index: multipath-tools-120518/libmultipath/file.h
-===================================================================
---- /dev/null
-+++ multipath-tools-120518/libmultipath/file.h
-@@ -0,0 +1,11 @@
-+/*
-+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
-+ */
-+
-+#ifndef _FILE_H
-+#define _FILE_H
-+
-+#define FILE_TIMEOUT 30
-+int open_file(char *file, int *can_write, char *header);
-+
-+#endif /* _FILE_H */
-Index: multipath-tools-120518/multipath/main.c
-===================================================================
---- multipath-tools-120518.orig/multipath/main.c
-+++ multipath-tools-120518/multipath/main.c
-@@ -53,6 +53,7 @@
- #include <errno.h>
- #include <sys/time.h>
- #include <sys/resource.h>
-+#include <wwids.h>
- #include "dev_t.h"
-
- int logsink;
-@@ -82,7 +83,7 @@ usage (char * progname)
- {
- fprintf (stderr, VERSION_STRING);
- fprintf (stderr, "Usage:\n");
-- fprintf (stderr, " %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
-+ fprintf (stderr, " %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
- fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
- fprintf (stderr, " %s -F [-v lvl]\n", progname);
- fprintf (stderr, " %s -t\n", progname);
-@@ -95,6 +96,7 @@ usage (char * progname)
- " -ll show multipath topology (maximum info)\n" \
- " -f flush a multipath device map\n" \
- " -F flush all multipath device maps\n" \
-+ " -c check if a device should be a path in a multipath device\n" \
- " -q allow queue_if_no_path when multipathd is not running\n"\
- " -d dry run, do not create or update devmaps\n" \
- " -t dump internal hardware table\n" \
-@@ -209,6 +211,7 @@ get_dm_mpvec (vector curmp, vector pathv
-
- if (!conf->dry_run)
- reinstate_paths(mpp);
-+ remember_wwid(mpp->wwid);
- }
- return 0;
- }
-@@ -259,9 +262,13 @@ configure (void)
- * if we have a blacklisted device parameter, exit early
- */
- if (dev &&
-- (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0))
-- goto out;
--
-+ (filter_devnode(conf->blist_devnode,
-+ conf->elist_devnode, dev) > 0)) {
-+ if (conf->dry_run == 2)
-+ printf("%s is not a valid multipath device path\n",
-+ conf->dev);
-+ goto out;
-+ }
- /*
- * scope limiting must be translated into a wwid
- * failing the translation is fatal (by policy)
-@@ -277,6 +284,15 @@ configure (void)
- if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
- refwwid) > 0)
- goto out;
-+ if (conf->dry_run == 2) {
-+ if (check_wwids_file(refwwid, 0) == 0){
-+ printf("%s is a valid multipath device path\n", conf->dev);
-+ r = 0;
-+ }
-+ else
-+ printf("%s is not a valid multipath device path\n", conf->dev);
-+ goto out;
-+ }
- }
-
- /*
-@@ -412,7 +428,7 @@ main (int argc, char *argv[])
- if (load_config(DEFAULT_CONFIGFILE))
- exit(1);
-
-- while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:Brtq")) != EOF ) {
-+ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) {
- switch(arg) {
- case 1: printf("optarg : %s\n",optarg);
- break;
-@@ -434,8 +450,12 @@ main (int argc, char *argv[])
- case 'q':
- conf->allow_queueing = 1;
- break;
-+ case 'c':
-+ conf->dry_run = 2;
-+ break;
- case 'd':
-- conf->dry_run = 1;
-+ if (!conf->dry_run)
-+ conf->dry_run = 1;
- break;
- case 'f':
- conf->remove = FLUSH_ONE;
-@@ -517,6 +537,11 @@ main (int argc, char *argv[])
- }
- dm_init();
-
-+ if (conf->dry_run == 2 &&
-+ (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
-+ condlog(0, "the -c option requires a path to check");
-+ goto out;
-+ }
- if (conf->remove == FLUSH_ONE) {
- if (conf->dev_type == DEV_DEVMAP)
- r = dm_flush_map(conf->dev);
-Index: multipath-tools-120518/libmultipath/Makefile
-===================================================================
---- multipath-tools-120518.orig/libmultipath/Makefile
-+++ multipath-tools-120518/libmultipath/Makefile
-@@ -15,7 +15,7 @@ OBJS = memory.o parser.o vector.o devmap
- pgpolicies.o debug.o regex.o defaults.o uevent.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
-+ lock.o waiter.o file.o wwids.o
-
- LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h)
-
-Index: multipath-tools-120518/libmultipath/wwids.c
-===================================================================
---- /dev/null
-+++ multipath-tools-120518/libmultipath/wwids.c
-@@ -0,0 +1,139 @@
-+#include <stdlib.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <string.h>
-+#include <limits.h>
-+#include <stdio.h>
-+
-+#include "checkers.h"
-+#include "vector.h"
-+#include "structs.h"
-+#include "debug.h"
-+#include "uxsock.h"
-+#include "file.h"
-+#include "wwids.h"
-+#include "defaults.h"
-+
-+/*
-+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
-+ */
-+
-+static int
-+lookup_wwid(FILE *f, char *wwid) {
-+ int c;
-+ char buf[LINE_MAX];
-+ int count;
-+
-+ while ((c = fgetc(f)) != EOF){
-+ if (c != '/') {
-+ if (fgets(buf, LINE_MAX, f) == NULL)
-+ return 0;
-+ else
-+ continue;
-+ }
-+ count = 0;
-+ while ((c = fgetc(f)) != '/') {
-+ if (c == EOF)
-+ return 0;
-+ if (count >= WWID_SIZE - 1)
-+ goto next;
-+ if (wwid[count] == '\0')
-+ goto next;
-+ if (c != wwid[count++])
-+ goto next;
-+ }
-+ if (wwid[count] == '\0')
-+ return 1;
-+next:
-+ if (fgets(buf, LINE_MAX, f) == NULL)
-+ return 0;
-+ }
-+ return 0;
-+}
-+
-+static int
-+write_out_wwid(int fd, char *wwid) {
-+ int ret;
-+ off_t offset;
-+ char buf[WWID_SIZE + 3];
-+
-+ ret = snprintf(buf, WWID_SIZE + 3, "/%s/\n", wwid);
-+ if (ret >= (WWID_SIZE + 3) || ret < 0){
-+ condlog(0, "can't format wwid for writing (%d) : %s",
-+ ret, strerror(errno));
-+ return -1;
-+ }
-+ offset = lseek(fd, 0, SEEK_END);
-+ if (offset < 0) {
-+ condlog(0, "can't seek to the end of wwids file : %s",
-+ strerror(errno));
-+ return -1;
-+ }
-+ if (write_all(fd, buf, strlen(buf)) != strlen(buf)) {
-+ condlog(0, "cannot write wwid to wwids file : %s",
-+ strerror(errno));
-+ if (ftruncate(fd, offset))
-+ condlog(0, "cannot truncate failed wwid write : %s",
-+ strerror(errno));
-+ return -1;
-+ }
-+ return 1;
-+}
-+
-+int
-+check_wwids_file(char *wwid, int write_wwid)
-+{
-+ int fd, can_write, found, ret;
-+ FILE *f;
-+ fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER);
-+ if (fd < 0)
-+ return -1;
-+
-+ f = fdopen(fd, "r");
-+ if (!f) {
-+ condlog(0,"can't fdopen wwids file : %s", strerror(errno));
-+ close(fd);
-+ return -1;
-+ }
-+ found = lookup_wwid(f, wwid);
-+ if (found) {
-+ ret = 0;
-+ goto out;
-+ }
-+ if (!write_wwid) {
-+ ret = -1;
-+ goto out;
-+ }
-+ if (!can_write) {
-+ condlog(0, "wwids file is read-only. Can't write wwid");
-+ ret = -1;
-+ goto out;
-+ }
-+
-+ if (fflush(f) != 0) {
-+ condlog(0, "cannot fflush wwids file stream : %s",
-+ strerror(errno));
-+ ret = -1;
-+ goto out;
-+ }
-+
-+ ret = write_out_wwid(fd, wwid);
-+out:
-+ fclose(f);
-+ return ret;
-+}
-+
-+int
-+remember_wwid(char *wwid)
-+{
-+ int ret = check_wwids_file(wwid, 1);
-+ if (ret < 0){
-+ condlog(3, "failed writing wwid %s to wwids file", wwid);
-+ return -1;
-+ }
-+ if (ret == 1)
-+ condlog(3, "wrote wwid %s to wwids file", wwid);
-+ else
-+ condlog(4, "wwid %s already in wwids file", wwid);
-+ return 0;
-+}
-Index: multipath-tools-120518/libmultipath/wwids.h
-===================================================================
---- /dev/null
-+++ multipath-tools-120518/libmultipath/wwids.h
-@@ -0,0 +1,18 @@
-+/*
-+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
-+ */
-+
-+#ifndef _WWIDS_H
-+#define _WWIDS_H
-+
-+#define WWIDS_FILE_HEADER \
-+"# Multipath wwids, Version : 1.0\n" \
-+"# NOTE: This file is automatically maintained by multipath and multipathd.\n" \
-+"# You should not need to edit this file in normal circumstances.\n" \
-+"#\n" \
-+"# Valid WWIDs:\n"
-+
-+int remember_wwid(char *wwid);
-+int check_wwids_file(char *wwid, int write_wwid);
-+
-+#endif /* _WWIDS_H */
-Index: multipath-tools-120518/libmultipath/discovery.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/discovery.c
-+++ multipath-tools-120518/libmultipath/discovery.c
-@@ -810,6 +810,8 @@ get_uid (struct path * pp)
-
- memset(pp->wwid, 0, WWID_SIZE);
- value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
-+ if ((!value || strlen(value) == 0) && conf->dry_run == 2)
-+ value = getenv(pp->uid_attribute);
- if (value && strlen(value)) {
- size_t len = WWID_SIZE;
-
---
- multipath/Makefile | 6 +++---
- multipath/multipath.rules | 30 ++++++++++++++++++++++++------
- 2 files changed, 27 insertions(+), 9 deletions(-)
+ multipath/Makefile | 3 +++
+ multipath/multipath.rules | 24 ++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
-Index: multipath-tools-120613/multipath/multipath.rules
+Index: multipath-tools-130222/multipath/multipath.rules
===================================================================
---- multipath-tools-120613.orig/multipath/multipath.rules
-+++ multipath-tools-120613/multipath/multipath.rules
-@@ -1,7 +1,25 @@
--#
--# udev rules for multipathing.
--# The persistent symlinks are created with the kpartx rules
--#
+--- /dev/null
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -0,0 +1,24 @@
+# multipath wants the devmaps presented as meaninglful device names
+# so name them after their devmap name
+SUBSYSTEM!="block", GOTO="end_mpath"
-
--# socket for uevents
--SUBSYSTEM=="block", RUN+="socket:/org/kernel/dm/multipath_event"
++
+ENV{MPATH_SBIN_PATH}="/sbin"
+TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin"
+
+ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \
+ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}"
+
-+RUN+="socket:/org/kernel/dm/multipath_event"
+KERNEL!="dm-*", GOTO="end_mpath"
-+ACTION!="change", GOTO="end_mpath"
+ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10"
++ACTION!="change", GOTO="end_mpath"
+ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath"
+ENV{DM_SUSPENDED}=="1", GOTO="end_mpath"
+ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath"
-+RUN+="$env{MPATH_SBIN_PATH}/kpartx -a -p p $tempnode"
++RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode"
+LABEL="end_mpath"
-Index: multipath-tools-120613/multipath/Makefile
+Index: multipath-tools-130222/multipath/Makefile
===================================================================
---- multipath-tools-120613.orig/multipath/Makefile
-+++ multipath-tools-120613/multipath/Makefile
-@@ -21,15 +21,15 @@ $(EXEC): $(OBJS)
+--- multipath-tools-130222.orig/multipath/Makefile
++++ multipath-tools-130222/multipath/Makefile
+@@ -21,12 +21,15 @@ $(EXEC): $(OBJS)
install:
$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
-- $(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d
-- $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
+ $(INSTALL_PROGRAM) -d $(DESTDIR)/lib/udev/rules.d
+ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/lib/udev/rules.d/62-multipath.rules
$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
uninstall:
-- rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
+ rm $(DESTDIR)/lib/udev/rules.d/62-multipath.rules
rm $(DESTDIR)$(bindir)/$(EXEC)
rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
:100644 100644 21e4ad4... 06d79c0... M kpartx/Makefile
:100644 100644 32d9ef5... 25e1483... M multipathd/Makefile
Makefile.inc | 2 +-
- kpartx/Makefile | 8 ++++----
+ kpartx/Makefile | 10 +++++-----
libmpathpersist/Makefile | 7 ++-----
libmultipath/Makefile | 2 ++
multipathd/Makefile | 1 +
- 5 files changed, 10 insertions(+), 10 deletions(-)
+ 5 files changed, 11 insertions(+), 11 deletions(-)
-Index: multipath-tools-120613/Makefile.inc
+Index: multipath-tools-130222/Makefile.inc
===================================================================
---- multipath-tools-120613.orig/Makefile.inc
-+++ multipath-tools-120613/Makefile.inc
+--- multipath-tools-130222.orig/Makefile.inc
++++ multipath-tools-130222/Makefile.inc
@@ -29,7 +29,7 @@ multipathdir = $(TOPDIR)/libmultipath
mandir = $(prefix)/usr/share/man/man8
man5dir = $(prefix)/usr/share/man/man5
syslibdir = $(prefix)/$(LIB)
libdir = $(prefix)/$(LIB)/multipath
unitdir = $(prefix)/lib/systemd/system
-Index: multipath-tools-120613/kpartx/Makefile
+Index: multipath-tools-130222/kpartx/Makefile
===================================================================
---- multipath-tools-120613.orig/kpartx/Makefile
-+++ multipath-tools-120613/kpartx/Makefile
-@@ -26,10 +26,10 @@ $(EXEC): $(OBJS)
+--- multipath-tools-130222.orig/kpartx/Makefile
++++ multipath-tools-130222/kpartx/Makefile
+@@ -26,17 +26,17 @@ $(EXEC): $(OBJS)
install: $(EXEC) $(EXEC).8
$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
-Index: multipath-tools-120613/multipathd/Makefile
+ uninstall:
+ rm -f $(DESTDIR)$(bindir)/$(EXEC)
+ rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
+- rm -f $(DESTDIR)$(libudevdir)/kpartx_id
++# rm -f $(DESTDIR)$(libudevdir)/kpartx_id
+
+ clean:
+ rm -f core *.o $(EXEC) *.gz
+Index: multipath-tools-130222/multipathd/Makefile
===================================================================
---- multipath-tools-120613.orig/multipathd/Makefile
-+++ multipath-tools-120613/multipathd/Makefile
+--- multipath-tools-130222.orig/multipathd/Makefile
++++ multipath-tools-130222/multipathd/Makefile
@@ -35,6 +35,7 @@ install:
$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(unitdir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).service $(DESTDIR)$(unitdir)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
-Index: multipath-tools-120613/libmultipath/Makefile
+Index: multipath-tools-130222/libmultipath/Makefile
===================================================================
---- multipath-tools-120613.orig/libmultipath/Makefile
-+++ multipath-tools-120613/libmultipath/Makefile
+--- multipath-tools-130222.orig/libmultipath/Makefile
++++ multipath-tools-130222/libmultipath/Makefile
@@ -46,9 +46,11 @@ install:
$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
clean:
rm -f core *.a *.o *.gz *.so *.so.*
-Index: multipath-tools-120613/libmpathpersist/Makefile
+Index: multipath-tools-130222/libmpathpersist/Makefile
===================================================================
---- multipath-tools-120613.orig/libmpathpersist/Makefile
-+++ multipath-tools-120613/libmpathpersist/Makefile
+--- multipath-tools-130222.orig/libmpathpersist/Makefile
++++ multipath-tools-130222/libmpathpersist/Makefile
@@ -28,17 +28,14 @@ $(LIBS):
install: $(LIBS)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
+++ /dev/null
----
- libmultipath/dict.c | 12 ++++++++++++
- libmultipath/discovery.c | 6 +++---
- libmultipath/print.c | 2 ++
- libmultipath/structs.h | 4 +++-
- multipath/main.c | 2 +-
- multipath/multipath.conf.5 | 5 +++++
- multipathd/main.c | 35 ++++++++++++++++++++++++++++++++++-
- 7 files changed, 60 insertions(+), 6 deletions(-)
-
-Index: multipath-tools-120518/libmultipath/dict.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/dict.c
-+++ multipath-tools-120518/libmultipath/dict.c
-@@ -398,6 +398,8 @@ default_failback_handler(vector strvec)
- conf->pgfailback = -FAILBACK_MANUAL;
- else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
- conf->pgfailback = -FAILBACK_IMMEDIATE;
-+ else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-+ conf->pgfailback = -FAILBACK_FOLLOWOVER;
- else
- conf->pgfailback = atoi(buff);
-
-@@ -1053,6 +1055,8 @@ hw_failback_handler(vector strvec)
- hwe->pgfailback = -FAILBACK_MANUAL;
- else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
- hwe->pgfailback = -FAILBACK_IMMEDIATE;
-+ else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-+ hwe->pgfailback = -FAILBACK_FOLLOWOVER;
- else
- hwe->pgfailback = atoi(buff);
-
-@@ -1351,6 +1355,8 @@ mp_failback_handler(vector strvec)
- mpe->pgfailback = -FAILBACK_MANUAL;
- else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
- mpe->pgfailback = -FAILBACK_IMMEDIATE;
-+ else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-+ mpe->pgfailback = -FAILBACK_FOLLOWOVER;
- else
- mpe->pgfailback = atoi(buff);
-
-@@ -1769,6 +1775,8 @@ snprint_mp_failback (char * buff, int le
- return snprintf(buff, len, "manual");
- case -FAILBACK_IMMEDIATE:
- return snprintf(buff, len, "immediate");
-+ case -FAILBACK_FOLLOWOVER:
-+ return snprintf(buff, len, "followover");
- default:
- return snprintf(buff, len, "%i", mpe->pgfailback);
- }
-@@ -2130,6 +2138,8 @@ snprint_hw_failback (char * buff, int le
- return snprintf(buff, len, "manual");
- case -FAILBACK_IMMEDIATE:
- return snprintf(buff, len, "immediate");
-+ case -FAILBACK_FOLLOWOVER:
-+ return snprintf(buff, len, "followover");
- default:
- return snprintf(buff, len, "%i", hwe->pgfailback);
- }
-@@ -2394,6 +2404,8 @@ snprint_def_failback (char * buff, int l
- return snprintf(buff, len, "manual");
- case -FAILBACK_IMMEDIATE:
- return snprintf(buff, len, "immediate");
-+ case -FAILBACK_FOLLOWOVER:
-+ return snprintf(buff, len, "followover");
- default:
- return snprintf(buff, len, "%i", conf->pgfailback);
- }
-Index: multipath-tools-120518/libmultipath/print.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/print.c
-+++ multipath-tools-120518/libmultipath/print.c
-@@ -143,6 +143,8 @@ snprint_failback (char * buff, size_t le
- {
- if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
- return snprintf(buff, len, "immediate");
-+ if (mpp->pgfailback == -FAILBACK_FOLLOWOVER)
-+ return snprintf(buff, len, "followover");
-
- if (!mpp->failback_tick)
- return snprintf(buff, len, "-");
-Index: multipath-tools-120518/libmultipath/structs.h
-===================================================================
---- multipath-tools-120518.orig/libmultipath/structs.h
-+++ multipath-tools-120518/libmultipath/structs.h
-@@ -39,7 +39,8 @@ enum rr_weight_mode {
- enum failback_mode {
- FAILBACK_UNDEF,
- FAILBACK_MANUAL,
-- FAILBACK_IMMEDIATE
-+ FAILBACK_IMMEDIATE,
-+ FAILBACK_FOLLOWOVER
- };
-
- enum sysfs_buses {
-@@ -151,6 +152,7 @@ struct path {
- int offline;
- int state;
- int dmstate;
-+ int chkrstate;
- int failcount;
- int priority;
- int pgindex;
-Index: multipath-tools-120518/multipathd/main.c
-===================================================================
---- multipath-tools-120518.orig/multipathd/main.c
-+++ multipath-tools-120518/multipathd/main.c
-@@ -995,6 +995,32 @@ mpvec_garbage_collector (struct vectors
- }
- }
-
-+/* This is called after a path has started working again. It the multipath
-+ * device for this path uses the followover failback type, and this is the
-+ * best pathgroup, and this is the first path in the pathgroup to come back
-+ * up, then switch to this pathgroup */
-+static int
-+followover_should_failback(struct path * pp)
-+{
-+ struct pathgroup * pgp;
-+ struct path *pp1;
-+ int i;
-+
-+ if (pp->mpp->pgfailback != -FAILBACK_FOLLOWOVER ||
-+ !pp->mpp->pg || !pp->pgindex ||
-+ pp->pgindex != pp->mpp->bestpg)
-+ return 0;
-+
-+ pgp = VECTOR_SLOT(pp->mpp->pg, pp->pgindex - 1);
-+ vector_foreach_slot(pgp->paths, pp1, i) {
-+ if (pp1 == pp)
-+ continue;
-+ if (pp1->chkrstate != PATH_DOWN && pp1->chkrstate != PATH_SHAKY)
-+ return 0;
-+ }
-+ return 1;
-+}
-+
- static void
- defered_failback_tick (vector mpvec)
- {
-@@ -1092,6 +1118,8 @@ check_path (struct vectors * vecs, struc
- {
- int newstate;
- int new_path_up = 0;
-+ int chkr_new_path_up = 0;
-+ int oldchkrstate = pp->chkrstate;
-
- if (!pp->mpp)
- return;
-@@ -1130,6 +1158,7 @@ check_path (struct vectors * vecs, struc
- pp->dev);
- pp->dmstate = PSTATE_UNDEF;
- }
-+ pp->chkrstate = newstate;
- if (newstate != pp->state) {
- int oldstate = pp->state;
- pp->state = newstate;
-@@ -1182,6 +1211,9 @@ check_path (struct vectors * vecs, struc
-
- new_path_up = 1;
-
-+ if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
-+ chkr_new_path_up = 1;
-+
- /*
- * if at least one path is up in a group, and
- * the group is disabled, re-enable it
-@@ -1233,7 +1265,8 @@ check_path (struct vectors * vecs, struc
- (new_path_up || pp->mpp->failback_tick <= 0))
- pp->mpp->failback_tick =
- pp->mpp->pgfailback + 1;
-- else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE)
-+ else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE ||
-+ (chkr_new_path_up && followover_should_failback(pp)))
- switch_pathgroup(pp->mpp);
- }
- }
-Index: multipath-tools-120518/multipath/multipath.conf.5
-===================================================================
---- multipath-tools-120518.orig/multipath/multipath.conf.5
-+++ multipath-tools-120518/multipath/multipath.conf.5
-@@ -254,6 +254,11 @@ active paths.
- .B manual
- Do not perform automatic failback.
- .TP
-+.B followover
-+Only perform automatic failback when the first path of a pathgroup
-+becomes active. This keeps a node from automatically failing back when
-+another node requested the failover.
-+.TP
- .B values > 0
- deferred failback (time to defer in seconds)
- .TP
-Index: multipath-tools-120518/libmultipath/discovery.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/discovery.c
-+++ multipath-tools-120518/libmultipath/discovery.c
-@@ -878,13 +878,13 @@ pathinfo (struct path *pp, vector hwtabl
-
- if (mask & DI_CHECKER) {
- if (path_state == PATH_UP) {
-- pp->state = get_state(pp, 0);
-+ pp->chkrstate = pp->state = get_state(pp, 0);
- if (pp->state == PATH_UNCHECKED ||
- pp->state == PATH_WILD)
- goto blank;
- } else {
- condlog(3, "%s: path inaccessible", pp->dev);
-- pp->state = path_state;
-+ pp->chkrstate = pp->state = path_state;
- }
- }
-
-@@ -912,7 +912,7 @@ blank:
- * Recoverable error, for example faulty or offline path
- */
- memset(pp->wwid, 0, WWID_SIZE);
-- pp->state = PATH_DOWN;
-+ pp->chkrstate = pp->state = PATH_DOWN;
-
- return 0;
- }
-Index: multipath-tools-120518/multipath/main.c
-===================================================================
---- multipath-tools-120518.orig/multipath/main.c
-+++ multipath-tools-120518/multipath/main.c
-@@ -144,7 +144,7 @@ update_paths (struct multipath * mpp)
- /*
- * path is not in sysfs anymore
- */
-- pp->state = PATH_DOWN;
-+ pp->chkrstate = pp->state = PATH_DOWN;
- continue;
- }
- pp->mpp = mpp;
+++ /dev/null
----
- multipath/main.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-Index: multipath-tools-120518/multipath/main.c
-===================================================================
---- multipath-tools-120518.orig/multipath/main.c
-+++ multipath-tools-120518/multipath/main.c
-@@ -409,6 +409,16 @@ get_dev_type(char *dev) {
- return DEV_DEVMAP;
- }
-
-+static void
-+convert_dev(char *dev)
-+{
-+ char *ptr = strstr(dev, "cciss/");
-+ if (ptr) {
-+ ptr += 5;
-+ *ptr = '!';
-+ }
-+}
-+
- int
- main (int argc, char *argv[])
- {
-@@ -514,6 +524,8 @@ main (int argc, char *argv[])
-
- strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
- conf->dev_type = get_dev_type(conf->dev);
-+ if (conf->dev_type == DEV_DEVNODE)
-+ convert_dev(conf->dev);
- }
- conf->daemon = 0;
-
libmultipath/config.h | 1 +
2 files changed, 17 insertions(+)
-Index: multipath-tools-120518/libmultipath/config.c
+Index: multipath-tools-130222/libmultipath/config.c
===================================================================
---- multipath-tools-120518.orig/libmultipath/config.c
-+++ multipath-tools-120518/libmultipath/config.c
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
@@ -21,6 +21,7 @@
#include "defaults.h"
#include "prio.h"
static int
hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
-@@ -549,6 +550,21 @@ load_config (char * file)
+@@ -585,6 +586,21 @@ load_config (char * file)
} else {
init_keywords();
}
/*
-Index: multipath-tools-120518/libmultipath/config.h
+Index: multipath-tools-130222/libmultipath/config.h
===================================================================
---- multipath-tools-120518.orig/libmultipath/config.h
-+++ multipath-tools-120518/libmultipath/config.h
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
@@ -6,6 +6,7 @@
#define ORIGIN_DEFAULT 0
multipath/mpathconf.8 | 103 ++++++++++++++++
5 files changed, 423 insertions(+), 2 deletions(-)
-Index: multipath-tools-120613/libmultipath/config.c
+Index: multipath-tools-130222/libmultipath/config.c
===================================================================
---- multipath-tools-120613.orig/libmultipath/config.c
-+++ multipath-tools-120613/libmultipath/config.c
-@@ -553,6 +553,7 @@ load_config (char * file)
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -589,6 +589,7 @@ load_config (char * file)
condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
condlog(0, "A default multipath.conf file is located at");
condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE));
if (conf->blist_devnode == NULL) {
conf->blist_devnode = vector_alloc();
if (!conf->blist_devnode) {
-Index: multipath-tools-120613/multipath/Makefile
+Index: multipath-tools-130222/multipath/Makefile
===================================================================
---- multipath-tools-120613.orig/multipath/Makefile
-+++ multipath-tools-120613/multipath/Makefile
+--- multipath-tools-130222.orig/multipath/Makefile
++++ multipath-tools-130222/multipath/Makefile
@@ -17,22 +17,27 @@ $(EXEC): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
clean:
rm -f core *.o $(EXEC) *.gz
-Index: multipath-tools-120613/multipath/main.c
+Index: multipath-tools-130222/multipath/main.c
===================================================================
---- multipath-tools-120613.orig/multipath/main.c
-+++ multipath-tools-120613/multipath/main.c
-@@ -432,10 +432,10 @@ main (int argc, char *argv[])
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -433,10 +433,10 @@ main (int argc, char *argv[])
exit(1);
}
exit(1);
while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) {
-Index: multipath-tools-120613/multipath/mpathconf
+Index: multipath-tools-130222/multipath/mpathconf
===================================================================
--- /dev/null
-+++ multipath-tools-120613/multipath/mpathconf
++++ multipath-tools-130222/multipath/mpathconf
@@ -0,0 +1,312 @@
+#!/bin/sh
+#
+elif [ -n "$CHANGED_CONFIG" -a "$HAVE_MULTIPATHD" = 1 ]; then
+ service multipathd reload
+fi
-Index: multipath-tools-120613/multipath/mpathconf.8
+Index: multipath-tools-130222/multipath/mpathconf.8
===================================================================
--- /dev/null
-+++ multipath-tools-120613/multipath/mpathconf.8
++++ multipath-tools-130222/multipath/mpathconf.8
@@ -0,0 +1,103 @@
+.TH MPATHCONF 8 "June 2010" "" "Linux Administrator's Manual"
+.SH NAME
+++ /dev/null
----
- multipathd/multipathd.service | 1 +
- 1 file changed, 1 insertion(+)
-
-Index: multipath-tools-110916/multipathd/multipathd.service
-===================================================================
---- multipath-tools-110916.orig/multipathd/multipathd.service
-+++ multipath-tools-110916/multipathd/multipathd.service
-@@ -2,6 +2,7 @@
- Description=Device-Mapper Multipath Device Controller
- Before=iscsi.service iscsid.service
- After=syslog.target
-+ConditionPathExists=/etc/multipath.conf
-
- [Service]
- Type=forking
multipathd/main.c | 6 ++++++
9 files changed, 82 insertions(+), 1 deletion(-)
-Index: multipath-tools-120518/libmultipath/config.c
+Index: multipath-tools-130222/libmultipath/config.c
===================================================================
---- multipath-tools-120518.orig/libmultipath/config.c
-+++ multipath-tools-120518/libmultipath/config.c
-@@ -514,6 +514,7 @@ load_config (char * file)
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -547,6 +547,7 @@ load_config (char * file)
conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
conf->checkint = DEFAULT_CHECKINT;
conf->max_checkint = MAX_CHECKINT(conf->checkint);
+ conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
-
- /*
- * preload default hwtable
-Index: multipath-tools-120518/libmultipath/configure.c
+ conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
+ conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
+ conf->detect_prio = DEFAULT_DETECT_PRIO;
+Index: multipath-tools-130222/libmultipath/configure.c
===================================================================
---- multipath-tools-120518.orig/libmultipath/configure.c
-+++ multipath-tools-120518/libmultipath/configure.c
-@@ -497,6 +497,10 @@ coalesce_paths (struct vectors * vecs, v
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -508,6 +508,10 @@ coalesce_paths (struct vectors * vecs, v
memset(empty_buff, 0, WWID_SIZE);
if (force_reload) {
vector_foreach_slot (pathvec, pp1, k) {
pp1->mpp = NULL;
-@@ -526,6 +530,13 @@ coalesce_paths (struct vectors * vecs, v
+@@ -537,6 +541,13 @@ coalesce_paths (struct vectors * vecs, v
if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
continue;
/*
* at this point, we know we really got a new mp
*/
-Index: multipath-tools-120518/libmultipath/defaults.h
+Index: multipath-tools-130222/libmultipath/defaults.h
===================================================================
---- multipath-tools-120518.orig/libmultipath/defaults.h
-+++ multipath-tools-120518/libmultipath/defaults.h
+--- multipath-tools-130222.orig/libmultipath/defaults.h
++++ multipath-tools-130222/libmultipath/defaults.h
@@ -15,6 +15,7 @@
#define DEFAULT_USER_FRIENDLY_NAMES 0
#define DEFAULT_VERBOSITY 2
#define DEFAULT_REASSIGN_MAPS 1
-+#define DEFAULT_FIND_MULTIPATHS 0
-
- #define DEFAULT_CHECKINT 5
- #define MAX_CHECKINT(a) (a << 2)
-Index: multipath-tools-120518/libmultipath/dict.c
++#define DEFAULT_FIND_MULTIPATHS 0
+ #define DEFAULT_FAST_IO_FAIL 5
+ #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
+ #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
+Index: multipath-tools-130222/libmultipath/dict.c
===================================================================
---- multipath-tools-120518.orig/libmultipath/dict.c
-+++ multipath-tools-120518/libmultipath/dict.c
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
@@ -585,6 +585,27 @@ def_reservation_key_handler(vector strve
}
def_names_handler(vector strvec)
{
char * buff;
-@@ -2549,6 +2570,18 @@ snprint_def_log_checker_err (char * buff
+@@ -2700,6 +2721,18 @@ snprint_def_log_checker_err (char * buff
}
static int
snprint_def_user_friendly_names (char * buff, int len, void * data)
{
if (conf->user_friendly_names == USER_FRIENDLY_NAMES_ON)
-@@ -2646,6 +2679,7 @@ init_keywords(void)
- install_keyword("bindings_file", &bindings_file_handler, &snprint_def_bindings_file);
+@@ -2833,6 +2866,7 @@ init_keywords(void)
+ install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file);
install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err);
install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key);
+ install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths);
+ install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler);
+ install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
__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);
-Index: multipath-tools-120518/libmultipath/wwids.c
+Index: multipath-tools-130222/libmultipath/wwids.c
===================================================================
---- multipath-tools-120518.orig/libmultipath/wwids.c
-+++ multipath-tools-120518/libmultipath/wwids.c
-@@ -124,6 +124,32 @@ out:
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -125,6 +125,32 @@ out:
}
int
remember_wwid(char *wwid)
{
int ret = check_wwids_file(wwid, 1);
-Index: multipath-tools-120518/libmultipath/wwids.h
+Index: multipath-tools-130222/libmultipath/wwids.h
===================================================================
---- multipath-tools-120518.orig/libmultipath/wwids.h
-+++ multipath-tools-120518/libmultipath/wwids.h
+--- multipath-tools-130222.orig/libmultipath/wwids.h
++++ multipath-tools-130222/libmultipath/wwids.h
@@ -12,6 +12,7 @@
"#\n" \
"# Valid WWIDs:\n"
int remember_wwid(char *wwid);
int check_wwids_file(char *wwid, int write_wwid);
-Index: multipath-tools-120518/multipath/main.c
+Index: multipath-tools-130222/multipath/main.c
===================================================================
---- multipath-tools-120518.orig/multipath/main.c
-+++ multipath-tools-120518/multipath/main.c
-@@ -332,7 +332,7 @@ configure (void)
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -333,7 +333,7 @@ configure (void)
/*
* core logic entry point
*/
out:
if (refwwid)
-Index: multipath-tools-120518/multipathd/main.c
+Index: multipath-tools-130222/multipathd/main.c
===================================================================
---- multipath-tools-120518.orig/multipathd/main.c
-+++ multipath-tools-120518/multipathd/main.c
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
@@ -49,6 +49,7 @@
#include <print.h>
#include <configure.h>
#include <pgpolicies.h>
#include <uevent.h>
-@@ -473,6 +474,11 @@ rescan:
+@@ -471,6 +472,11 @@ rescan:
return 1;
}
condlog(4,"%s: creating new map", pp->dev);
if ((mpp = add_map_with_path(vecs, pp, 1))) {
mpp->action = ACT_CREATE;
-Index: multipath-tools-120518/libmultipath/config.h
+Index: multipath-tools-130222/libmultipath/config.h
===================================================================
---- multipath-tools-120518.orig/libmultipath/config.h
-+++ multipath-tools-120518/libmultipath/config.h
-@@ -104,6 +104,7 @@ struct config {
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -106,6 +106,7 @@ struct config {
unsigned int dev_loss;
int log_checker_err;
int allow_queueing;
--- /dev/null
+---
+ kpartx/dos.c | 2 --
+ kpartx/kpartx.c | 9 ++++++---
+ 2 files changed, 6 insertions(+), 5 deletions(-)
+
+Index: multipath-tools-130222/kpartx/dos.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/dos.c
++++ multipath-tools-130222/kpartx/dos.c
+@@ -98,8 +98,6 @@ read_dos_pt(int fd, struct slice all, st
+ break;
+ }
+ if (is_extended(p.sys_type)) {
+- sp[i].size = 2; /* extended partitions only get two
+- sectors mapped for LILO to install */
+ n += read_extended_partition(fd, &p, i, sp+n, ns-n);
+ }
+ }
+Index: multipath-tools-130222/kpartx/kpartx.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/kpartx.c
++++ multipath-tools-130222/kpartx/kpartx.c
+@@ -516,6 +516,7 @@ main(int argc, char **argv){
+ d = c;
+ while (c) {
+ for (j = 0; j < n; j++) {
++ uint64_t start;
+ int k = slices[j].container - 1;
+
+ if (slices[j].size == 0)
+@@ -541,9 +542,11 @@ main(int argc, char **argv){
+ }
+ strip_slash(partname);
+
+- if (safe_sprintf(params, "%s %" PRIu64,
+- device,
+- slices[j].start)) {
++ start = slices[j].start - slices[k].start;
++ if (safe_sprintf(params, "%d:%d %" PRIu64,
++ slices[k].major,
++ slices[k].minor,
++ start)) {
+ fprintf(stderr, "params too small\n");
+ exit(1);
+ }
kpartx/sun.c | 35 ---------------
5 files changed, 24 insertions(+), 177 deletions(-)
-Index: multipath-tools-120123/kpartx/bsd.c
+Index: multipath-tools-130222/kpartx/bsd.c
===================================================================
---- multipath-tools-120123.orig/kpartx/bsd.c
-+++ multipath-tools-120123/kpartx/bsd.c
+--- multipath-tools-130222.orig/kpartx/bsd.c
++++ multipath-tools-130222/kpartx/bsd.c
@@ -50,10 +50,10 @@ int
read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) {
struct bsd_disklabel *l;
- }
return n;
}
-Index: multipath-tools-120123/kpartx/dos.c
+Index: multipath-tools-130222/kpartx/dos.c
===================================================================
---- multipath-tools-120123.orig/kpartx/dos.c
-+++ multipath-tools-120123/kpartx/dos.c
+--- multipath-tools-130222.orig/kpartx/dos.c
++++ multipath-tools-130222/kpartx/dos.c
@@ -16,7 +16,7 @@ is_extended(int type) {
}
}
}
return n;
-Index: multipath-tools-120123/kpartx/kpartx.c
+Index: multipath-tools-130222/kpartx/kpartx.c
===================================================================
---- multipath-tools-120123.orig/kpartx/kpartx.c
-+++ multipath-tools-120123/kpartx/kpartx.c
-@@ -190,7 +190,7 @@ get_hotplug_device(void)
+--- multipath-tools-130222.orig/kpartx/kpartx.c
++++ multipath-tools-130222/kpartx/kpartx.c
+@@ -192,7 +192,7 @@ get_hotplug_device(void)
int
main(int argc, char **argv){
int fd = -1;
struct slice all;
struct pt *ptp;
-@@ -380,49 +380,30 @@ main(int argc, char **argv){
+@@ -381,49 +381,30 @@ main(int argc, char **argv){
else
continue;
break;
-@@ -461,16 +442,10 @@ main(int argc, char **argv){
+@@ -462,16 +443,10 @@ main(int argc, char **argv){
case ADD:
case UPDATE:
/* ADD and UPDATE share the same code that adds new partitions. */
if (safe_sprintf(partname, "%s%s%d",
mapname, delim, j+1)) {
fprintf(stderr, "partname too small\n");
-@@ -511,72 +486,6 @@ main(int argc, char **argv){
+@@ -512,72 +487,6 @@ main(int argc, char **argv){
slices[j].minor, slices[j].size,
DM_TARGET, params);
}
if (what == ADD) {
/* Skip code that removes devmappings for deleted partitions */
-Index: multipath-tools-120123/kpartx/kpartx.h
+Index: multipath-tools-130222/kpartx/kpartx.h
===================================================================
---- multipath-tools-120123.orig/kpartx/kpartx.h
-+++ multipath-tools-120123/kpartx/kpartx.h
+--- multipath-tools-130222.orig/kpartx/kpartx.h
++++ multipath-tools-130222/kpartx/kpartx.h
@@ -24,7 +24,6 @@
struct slice {
uint64_t start;
int major;
int minor;
};
-Index: multipath-tools-120123/kpartx/sun.c
+Index: multipath-tools-130222/kpartx/sun.c
===================================================================
---- multipath-tools-120123.orig/kpartx/sun.c
-+++ multipath-tools-120123/kpartx/sun.c
+--- multipath-tools-130222.orig/kpartx/sun.c
++++ multipath-tools-130222/kpartx/sun.c
@@ -62,8 +62,8 @@ int
read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
struct sun_disk_label *l;
multipathd/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
-Index: multipath-tools-120518/multipathd/main.c
+Index: multipath-tools-130222/multipathd/main.c
===================================================================
---- multipath-tools-120518.orig/multipathd/main.c
-+++ multipath-tools-120518/multipathd/main.c
-@@ -993,7 +993,8 @@ mpvec_garbage_collector (struct vectors
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -990,7 +990,8 @@ mpvec_garbage_collector (struct vectors
return;
vector_foreach_slot (vecs->mpvec, mpp, i) {
--- /dev/null
+---
+ kpartx/lopart.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/kpartx/lopart.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/lopart.c
++++ multipath-tools-130222/kpartx/lopart.c
+@@ -205,13 +205,13 @@ find_unused_loop_device (void)
+ fprintf(stderr,
+ "mount: Could not find any loop device, and, according to %s,\n"
+ " this kernel does not know about the loop device.\n"
+- " (If so, then recompile or `insmod loop.o'.)",
++ " (If so, then recompile or `modprobe loop'.)",
+ PROC_DEVICES);
+
+ else
+ fprintf(stderr,
+ "mount: Could not find any loop device. Maybe this kernel does not know\n"
+- " about the loop device (then recompile or `insmod loop.o'), or\n"
++ " about the loop device (then recompile or `modprobe loop'), or\n"
+ " maybe /dev/loop# has the wrong major number?");
+
+ } else
--- /dev/null
+---
+ Makefile.inc | 9 +++++----
+ kpartx/Makefile | 2 +-
+ libmpathpersist/Makefile | 4 ++--
+ libmultipath/Makefile | 1 +
+ libmultipath/checkers/Makefile | 2 +-
+ libmultipath/prioritizers/Makefile | 2 +-
+ multipath/Makefile | 2 +-
+ multipathd/Makefile | 5 +++--
+ 8 files changed, 15 insertions(+), 12 deletions(-)
+
+Index: multipath-tools-130222/Makefile.inc
+===================================================================
+--- multipath-tools-130222.orig/Makefile.inc
++++ multipath-tools-130222/Makefile.inc
+@@ -23,15 +23,15 @@ endif
+
+ prefix =
+ exec_prefix = $(prefix)
+-bindir = $(exec_prefix)/sbin
++bindir = $(exec_prefix)/usr/sbin
+ libudevdir = ${prefix}/lib/udev
+ multipathdir = $(TOPDIR)/libmultipath
+ mandir = $(prefix)/usr/share/man/man8
+ man5dir = $(prefix)/usr/share/man/man5
+ man3dir = $(prefix)/usr/share/man/man3
+ rcdir = $(prefix)/etc/rc.d/init.d
+-syslibdir = $(prefix)/$(LIB)
+-libdir = $(prefix)/$(LIB)/multipath
++syslibdir = $(prefix)/usr/$(LIB)
++libdir = $(prefix)/usr/$(LIB)/multipath
+ unitdir = $(prefix)/lib/systemd/system
+ mpathpersistdir = $(TOPDIR)/libmpathpersist
+
+@@ -42,8 +42,9 @@ ifndef RPM_OPT_FLAGS
+ RPM_OPT_FLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
+ endif
+
++LDFLAGS += -Wl,-z,relro
+ OPTFLAGS = $(RPM_OPT_FLAGS) -Wunused -Wstrict-prototypes
+-CFLAGS = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\"
++CFLAGS = $(OPTFLAGS) -DLIB_STRING=\"${LIB}\"
+ SHARED_FLAGS = -shared
+
+ %.o: %.c
+Index: multipath-tools-130222/multipathd/Makefile
+===================================================================
+--- multipath-tools-130222.orig/multipathd/Makefile
++++ multipath-tools-130222/multipathd/Makefile
+@@ -5,9 +5,10 @@ include ../Makefile.inc
+ #
+ # basic flags setting
+ #
+-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
++CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathpersistdir)
+ LDFLAGS += -lpthread -ldevmapper -lreadline -ludev -ldl \
+- -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist
++ -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \
++ -Wl,-z,now -pie
+
+ #
+ # debuging stuff
+Index: multipath-tools-130222/kpartx/Makefile
+===================================================================
+--- multipath-tools-130222.orig/kpartx/Makefile
++++ multipath-tools-130222/kpartx/Makefile
+@@ -4,7 +4,7 @@
+ #
+ include ../Makefile.inc
+
+-CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
++CFLAGS += -fPIC -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+
+ LIBDM_API_COOKIE = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_set_cookie' /usr/include/libdevmapper.h)
+
+Index: multipath-tools-130222/libmpathpersist/Makefile
+===================================================================
+--- multipath-tools-130222.orig/libmpathpersist/Makefile
++++ multipath-tools-130222/libmpathpersist/Makefile
+@@ -10,7 +10,7 @@ DEVLIB = libmpathpersist.so
+ LIBS = $(DEVLIB).$(SONAME)
+
+
+-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
++CFLAGS += -fPIC -I$(multipathdir) -I$(mpathpersistdir)
+ LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath
+
+ OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o
+@@ -19,7 +19,7 @@ all: $(LIBS)
+
+
+ $(LIBS):
+- $(CC) -Wall -fPIC -c $(CFLAGS) *.c
++ $(CC) -Wall -c $(CFLAGS) *.c
+ $(CC) -shared $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS)
+ ln -s $(LIBS) $(DEVLIB)
+ $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz
+Index: multipath-tools-130222/libmultipath/Makefile
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/Makefile
++++ multipath-tools-130222/libmultipath/Makefile
+@@ -8,6 +8,7 @@ SONAME=0
+ DEVLIB = libmultipath.so
+ LIBS = $(DEVLIB).$(SONAME)
+ LIBDEPS = -lpthread -ldl -ldevmapper -ludev
++CFLAGS += -fPIC
+
+ OBJS = memory.o parser.o vector.o devmapper.o \
+ hwtable.o blacklist.o util.o dmparser.o config.o \
+Index: multipath-tools-130222/libmultipath/checkers/Makefile
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers/Makefile
++++ multipath-tools-130222/libmultipath/checkers/Makefile
+@@ -14,7 +14,7 @@ LIBS= \
+ libcheckhp_sw.so \
+ libcheckrdac.so
+
+-CFLAGS += -I..
++CFLAGS += -fPIC -I..
+
+ all: $(LIBS)
+
+Index: multipath-tools-130222/libmultipath/prioritizers/Makefile
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/Makefile
++++ multipath-tools-130222/libmultipath/prioritizers/Makefile
+@@ -17,7 +17,7 @@ LIBS = \
+ libprioweightedpath.so \
+ libprioiet.so
+
+-CFLAGS += -I..
++CFLAGS += -fPIC -I..
+
+ all: $(LIBS)
+
+Index: multipath-tools-130222/multipath/Makefile
+===================================================================
+--- multipath-tools-130222.orig/multipath/Makefile
++++ multipath-tools-130222/multipath/Makefile
+@@ -6,7 +6,7 @@ include ../Makefile.inc
+
+ OBJS = main.o
+
+-CFLAGS += -I$(multipathdir)
++CFLAGS += -fPIC -I$(multipathdir)
+ LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath
+
+ EXEC = multipath
--- /dev/null
+---
+ kpartx/gpt.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-120821/kpartx/gpt.c
+===================================================================
+--- multipath-tools-120821.orig/kpartx/gpt.c
++++ multipath-tools-120821/kpartx/gpt.c
+@@ -637,6 +637,7 @@ read_gpt_pt (int fd, struct slice all, s
+ uint32_t i;
+ int n = 0;
+ int last_used_index=-1;
++ int sector_size_mul = get_sector_size(fd)/512;
+
+ if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
+ if (gpt)
+@@ -652,9 +653,11 @@ read_gpt_pt (int fd, struct slice all, s
+ sp[n].size = 0;
+ n++;
+ } else {
+- sp[n].start = __le64_to_cpu(ptes[i].starting_lba);
+- sp[n].size = __le64_to_cpu(ptes[i].ending_lba) -
+- __le64_to_cpu(ptes[i].starting_lba) + 1;
++ sp[n].start = sector_size_mul *
++ __le64_to_cpu(ptes[i].starting_lba);
++ sp[n].size = sector_size_mul *
++ (__le64_to_cpu(ptes[i].ending_lba) -
++ __le64_to_cpu(ptes[i].starting_lba) + 1);
+ last_used_index=n;
+ n++;
+ }
--- /dev/null
+---
+ libmultipath/print.c | 31 +++++++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/print.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/print.c
++++ multipath-tools-130222/libmultipath/print.c
+@@ -8,6 +8,8 @@
+ #include <sys/stat.h>
+ #include <dirent.h>
+ #include <unistd.h>
++#include <string.h>
++#include <errno.h>
+
+ #include "checkers.h"
+ #include "vector.h"
+@@ -24,6 +26,7 @@
+ #include "switchgroup.h"
+ #include "devmapper.h"
+ #include "uevent.h"
++#include "debug.h"
+
+ #define MAX(x,y) (x > y) ? x : y
+ #define TAIL (line + len - 1 - c)
+@@ -754,12 +757,32 @@ snprint_pathgroup (char * line, int len,
+ extern void
+ print_multipath_topology (struct multipath * mpp, int verbosity)
+ {
+- char buff[MAX_LINE_LEN * MAX_LINES] = {};
++ int resize;
++ char *buff = NULL;
++ char *old = NULL;
++ int len, maxlen = MAX_LINE_LEN * MAX_LINES;
+
+- memset(&buff[0], 0, MAX_LINE_LEN * MAX_LINES);
+- snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
+- mpp, verbosity);
++ buff = MALLOC(maxlen);
++ do {
++ if (!buff) {
++ if (old)
++ FREE(old);
++ condlog(0, "couldn't allocate memory for list: %s\n",
++ strerror(errno));
++ return;
++ }
++
++ len = snprint_multipath_topology(buff, maxlen, mpp, verbosity);
++ resize = (len == maxlen - 1);
++
++ if (resize) {
++ maxlen *= 2;
++ old = buff;
++ buff = REALLOC(buff, maxlen);
++ }
++ } while (resize);
+ printf("%s", buff);
++ FREE(buff);
+ }
+
+ extern int
+++ /dev/null
----
- libmultipath/devmapper.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-Index: multipath-tools-120518/libmultipath/devmapper.c
-===================================================================
---- multipath-tools-120518.orig/libmultipath/devmapper.c
-+++ multipath-tools-120518/libmultipath/devmapper.c
-@@ -1272,6 +1272,8 @@ dm_rename (char * old, char * new)
- goto out;
- if (!dm_task_run(dmt))
- goto out;
-+ if (conf->daemon)
-+ dm_task_update_nodes();
-
- r = 1;
- out:
+++ /dev/null
----
- libmultipath/config.c | 1
- libmultipath/hwtable.c | 65 -------------------------------------------------
- 2 files changed, 1 insertion(+), 65 deletions(-)
-
-Index: multipath-tools-120613/libmultipath/config.c
-===================================================================
---- multipath-tools-120613.orig/libmultipath/config.c
-+++ multipath-tools-120613/libmultipath/config.c
-@@ -515,6 +515,7 @@ load_config (char * file)
- conf->checkint = DEFAULT_CHECKINT;
- conf->max_checkint = MAX_CHECKINT(conf->checkint);
- conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
-+ conf->fast_io_fail = 5;
-
- /*
- * preload default hwtable
-Index: multipath-tools-120613/libmultipath/hwtable.c
-===================================================================
---- multipath-tools-120613.orig/libmultipath/hwtable.c
-+++ multipath-tools-120613/libmultipath/hwtable.c
-@@ -28,7 +28,6 @@ static struct hwentry default_hw[] = {
- .product = "Compellent Vol",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -50,7 +49,6 @@ static struct hwentry default_hw[] = {
- .product = "Xserve RAID ",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -72,7 +70,6 @@ static struct hwentry default_hw[] = {
- .product = "VV",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -88,7 +85,6 @@ static struct hwentry default_hw[] = {
- .product = "HSG80",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 hp_sw",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -104,7 +100,6 @@ static struct hwentry default_hw[] = {
- .product = "A6189A",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -121,7 +116,6 @@ static struct hwentry default_hw[] = {
- .product = "(MSA|HSV)1.0.*",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 hp_sw",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -137,7 +131,6 @@ static struct hwentry default_hw[] = {
- .product = "MSA VOLUME",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -153,7 +146,6 @@ static struct hwentry default_hw[] = {
- .product = "HSV1[01]1|HSV2[01]0|HSV300|HSV4[05]0",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -169,7 +161,6 @@ static struct hwentry default_hw[] = {
- .product = "MSA2[02]12fc|MSA2012i",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -185,7 +176,6 @@ static struct hwentry default_hw[] = {
- .product = "MSA2012sa|MSA23(12|24)(fc|i|sa)|MSA2000s VOLUME",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -202,7 +192,6 @@ static struct hwentry default_hw[] = {
- .product = "HSVX700",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 alua",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -219,7 +208,6 @@ static struct hwentry default_hw[] = {
- .product = "LOGICAL VOLUME.*",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -236,7 +224,6 @@ static struct hwentry default_hw[] = {
- .product = "P2000 G3 FC|P2000G3 FC/iSCSI|P2000 G3 SAS|P2000 G3 iSCSI",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -258,7 +245,6 @@ static struct hwentry default_hw[] = {
- .product = "SAN DataDirector",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -280,7 +266,6 @@ static struct hwentry default_hw[] = {
- .product = "SYMMETRIX",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -297,7 +282,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "LUNZ",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 emc",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -314,7 +298,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "LUNZ",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -336,7 +319,6 @@ static struct hwentry default_hw[] = {
- .product = "CentricStor",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -352,7 +334,6 @@ static struct hwentry default_hw[] = {
- .product = "ETERNUS_DX(L|400|8000)",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -373,7 +354,6 @@ static struct hwentry default_hw[] = {
- .product = "OPEN-.*",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -389,7 +369,6 @@ static struct hwentry default_hw[] = {
- .product = "DF.*",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -411,7 +390,6 @@ static struct hwentry default_hw[] = {
- .product = "ProFibre 4000R",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -429,7 +407,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -447,7 +424,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -465,7 +441,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -483,7 +458,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -500,7 +474,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -518,7 +491,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -536,7 +508,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -554,7 +525,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -572,7 +542,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -589,7 +558,6 @@ static struct hwentry default_hw[] = {
- .product = "^3542",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -606,7 +574,6 @@ static struct hwentry default_hw[] = {
- .product = "^2105800",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -623,7 +590,6 @@ static struct hwentry default_hw[] = {
- .product = "^2105F20",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -640,7 +606,6 @@ static struct hwentry default_hw[] = {
- .product = "^1750500",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -657,7 +622,6 @@ static struct hwentry default_hw[] = {
- .product = "^2107900",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -674,7 +638,6 @@ static struct hwentry default_hw[] = {
- .product = "^2145",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -693,7 +656,6 @@ static struct hwentry default_hw[] = {
- .uid_attribute = "ID_UID",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -712,7 +674,6 @@ static struct hwentry default_hw[] = {
- .uid_attribute = "ID_UID",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -729,7 +690,6 @@ static struct hwentry default_hw[] = {
- .product = "^IPR.*",
- .features = "1 queue_if_no_path",
- .hwhandler = "1 alua",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -746,7 +706,6 @@ static struct hwentry default_hw[] = {
- .product = "1820N00",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -763,7 +722,6 @@ static struct hwentry default_hw[] = {
- .product = "2810XIV",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = 15,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -786,7 +744,6 @@ static struct hwentry default_hw[] = {
- .product = "VDASD",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -803,7 +760,6 @@ static struct hwentry default_hw[] = {
- .product = "3303 NVDISK",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = FAILOVER,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -820,7 +776,6 @@ static struct hwentry default_hw[] = {
- .product = "NVDISK",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 alua",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -838,7 +793,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -856,7 +810,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -874,7 +827,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -892,7 +844,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -914,7 +865,6 @@ static struct hwentry default_hw[] = {
- .product = "LUN.*",
- .features = "3 queue_if_no_path pg_init_retries 50",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .flush_on_last_del = FLUSH_ENABLED,
-@@ -936,7 +886,6 @@ static struct hwentry default_hw[] = {
- .product = "COMSTAR",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -957,7 +906,6 @@ static struct hwentry default_hw[] = {
- .product = "Nseries.*",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -978,7 +926,6 @@ static struct hwentry default_hw[] = {
- .product = "Axiom.*",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1001,7 +948,6 @@ static struct hwentry default_hw[] = {
- .product = "TP9[13]00",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1018,7 +964,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1035,7 +980,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1052,7 +996,6 @@ static struct hwentry default_hw[] = {
- .product = "DISK ARRAY",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 alua",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1075,7 +1018,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1097,7 +1039,6 @@ static struct hwentry default_hw[] = {
- .product = "(StorEdge 3510|T4)",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1113,7 +1054,6 @@ static struct hwentry default_hw[] = {
- .product = "FC2502",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1135,7 +1075,6 @@ static struct hwentry default_hw[] = {
- .product = "RAIGE VOLUME",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = MULTIBUS,
- .pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1151,7 +1090,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1169,7 +1107,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1187,7 +1124,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
-@@ -1204,7 +1140,6 @@ static struct hwentry default_hw[] = {
- .bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
- .hwhandler = "1 rdac",
-- .selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
--- /dev/null
+---
+ libmultipath/discovery.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -898,7 +898,8 @@ get_state (struct path * pp, int daemon)
+ c->timeout = DEF_TIMEOUT;
+ state = checker_check(c);
+ condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
+- if (state != PATH_UP && strlen(checker_message(c)))
++ if (state != PATH_UP && state != PATH_GHOST &&
++ strlen(checker_message(c)))
+ condlog(3, "%s: checker msg is \"%s\"",
+ pp->dev, checker_message(c));
+ return state;
--- /dev/null
+---
+ libmultipath/config.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -437,6 +437,8 @@ restart:
+ merge_hwe(hwe2, hwe1);
+ if (hwe_strmatch(hwe2, hwe1) == 0) {
+ vector_del_slot(hw, i);
++ free_hwe(hwe1);
++ n -= 1;
+ /*
+ * Play safe here; we have modified
+ * the original vector so the outer
--- /dev/null
+---
+ libmpathpersist/mpath_updatepr.c | 3 ++-
+ libmultipath/uxsock.c | 4 ++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/libmpathpersist/mpath_updatepr.c
+===================================================================
+--- multipath-tools-130222.orig/libmpathpersist/mpath_updatepr.c
++++ multipath-tools-130222/libmpathpersist/mpath_updatepr.c
+@@ -14,6 +14,7 @@
+ #include <debug.h>
+ #include "memory.h"
+ #include "../libmultipath/uxsock.h"
++#include "../libmultipath/defaults.h"
+
+ unsigned long mem_allocated; /* Total memory used in Bytes */
+
+@@ -25,7 +26,7 @@ int update_prflag(char * arg1, char * ar
+ size_t len;
+ int ret = 0;
+
+- fd = ux_socket_connect("/var/run/multipathd.sock");
++ fd = ux_socket_connect(DEFAULT_SOCKET);
+ if (fd == -1) {
+ condlog (0, "ux socket connect error");
+ return 1 ;
+Index: multipath-tools-130222/libmultipath/uxsock.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/uxsock.c
++++ multipath-tools-130222/libmultipath/uxsock.c
+@@ -31,7 +31,7 @@ int ux_socket_connect(const char *name)
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+ addr.sun_path[0] = '\0';
+- len = strlen(name) + 1;
++ len = strlen(name) + 1 + sizeof(sa_family_t);
+ strncpy(&addr.sun_path[1], name, len);
+
+ fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+@@ -62,7 +62,7 @@ int ux_socket_listen(const char *name)
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+ addr.sun_path[0] = '\0';
+- len = strlen(name) + 1;
++ len = strlen(name) + 1 + sizeof(sa_family_t);
+ strncpy(&addr.sun_path[1], name, len);
+
+ if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
--- /dev/null
+---
+ libmultipath/uevent.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/uevent.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/uevent.c
++++ multipath-tools-130222/libmultipath/uevent.c
+@@ -53,8 +53,10 @@ typedef int (uev_trigger)(struct uevent
+
+ pthread_t uevq_thr;
+ LIST_HEAD(uevq);
+-pthread_mutex_t uevq_lock, *uevq_lockp = &uevq_lock;
+-pthread_cond_t uev_cond, *uev_condp = &uev_cond;
++pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER;
++pthread_mutex_t *uevq_lockp = &uevq_lock;
++pthread_cond_t uev_cond = PTHREAD_COND_INITIALIZER;
++pthread_cond_t *uev_condp = &uev_cond;
+ uev_trigger *my_uev_trigger;
+ void * my_trigger_data;
+ int servicing_uev;
+@@ -409,10 +411,6 @@ int uevent_listen(void)
+ * thereby not getting to empty the socket's receive buffer queue
+ * often enough.
+ */
+- INIT_LIST_HEAD(&uevq);
+-
+- pthread_mutex_init(uevq_lockp, NULL);
+- pthread_cond_init(uev_condp, NULL);
+ pthread_cleanup_push(uevq_stop, NULL);
+
+ monitor = udev_monitor_new_from_netlink(conf->udev, "udev");
+@@ -525,8 +523,6 @@ out:
+ if (need_failback)
+ err = failback_listen();
+ pthread_cleanup_pop(1);
+- pthread_mutex_destroy(uevq_lockp);
+- pthread_cond_destroy(uev_condp);
+ return err;
+ }
+
--- /dev/null
+---
+ multipath/multipath.rules | 2 ++
+ multipathd/multipathd.service | 1 +
+ 2 files changed, 3 insertions(+)
+
+Index: multipath-tools-130222/multipath/multipath.rules
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.rules
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -2,6 +2,8 @@
+ # so name them after their devmap name
+ SUBSYSTEM!="block", GOTO="end_mpath"
+
++IMPORT{cmdline}="nompath"
++ENV{nompath}=="?*", GOTO="end_mpath"
+ ENV{MPATH_SBIN_PATH}="/sbin"
+ TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin"
+
+Index: multipath-tools-130222/multipathd/multipathd.service
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.service
++++ multipath-tools-130222/multipathd/multipathd.service
+@@ -3,6 +3,7 @@ Description=Device-Mapper Multipath Devi
+ Before=iscsi.service iscsid.service lvm2-activation-early.service
+ After=syslog.target
+ ConditionPathExists=/etc/multipath.conf
++ConditionKernelCommandLine=!nompath
+ DefaultDependencies=no
+ Conflicts=shutdown.target
+
--- /dev/null
+---
+ multipathd/main.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -1363,6 +1363,7 @@ configure (struct vectors * vecs, int st
+
+ sync_maps_state(mpvec);
+ vector_foreach_slot(mpvec, mpp, i){
++ remember_wwid(mpp->wwid);
+ update_map_pr(mpp);
+ }
+
--- /dev/null
+---
+ libmultipath/discovery.c | 3 +
+ libmultipath/wwids.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
+ libmultipath/wwids.h | 1
+ multipath/main.c | 26 ++++++++++++--
+ multipath/multipath.8 | 5 ++
+ 5 files changed, 115 insertions(+), 6 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -53,7 +53,8 @@ store_pathinfo (vector pathvec, vector h
+ goto out;
+ }
+ pp->udev = udev_device_ref(udevice);
+- err = pathinfo(pp, hwtable, flag | DI_BLACKLIST);
++ err = pathinfo(pp, hwtable,
++ (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST));
+ if (err)
+ goto out;
+
+Index: multipath-tools-130222/libmultipath/wwids.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -82,6 +82,92 @@ write_out_wwid(int fd, char *wwid) {
+ }
+
+ int
++do_remove_wwid(int fd, char *str) {
++ char buf[4097];
++ char *ptr;
++ off_t start = 0;
++ int bytes;
++
++ while (1) {
++ if (lseek(fd, start, SEEK_SET) < 0) {
++ condlog(0, "wwid file read lseek failed : %s",
++ strerror(errno));
++ return -1;
++ }
++ bytes = read(fd, buf, 4096);
++ if (bytes < 0) {
++ if (errno == EINTR || errno == EAGAIN)
++ continue;
++ condlog(0, "failed to read from wwids file : %s",
++ strerror(errno));
++ return -1;
++ }
++ if (!bytes) /* didn't find wwid to remove */
++ return 1;
++ buf[bytes] = '\0';
++ ptr = strstr(buf, str);
++ if (ptr != NULL) {
++ condlog(3, "found '%s'", str);
++ if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) {
++ condlog(0, "write lseek failed : %s",
++ strerror(errno));
++ return -1;
++ }
++ while (1) {
++ if (write(fd, "#", 1) < 0) {
++ if (errno == EINTR || errno == EAGAIN)
++ continue;
++ condlog(0, "failed to write to wwids file : %s", strerror(errno));
++ return -1;
++ }
++ return 0;
++ }
++ }
++ ptr = strrchr(buf, '\n');
++ if (ptr == NULL) { /* shouldn't happen, assume it is EOF */
++ condlog(4, "couldn't find newline, assuming end of file");
++ return 1;
++ }
++ start = start + (ptr - buf) + 1;
++ }
++}
++
++
++int
++remove_wwid(char *wwid) {
++ int fd, len, can_write;
++ char *str;
++ int ret = -1;
++
++ len = strlen(wwid) + 4; /* two slashes the newline and a zero byte */
++ str = malloc(len);
++ if (str == NULL) {
++ condlog(0, "can't allocate memory to remove wwid : %s",
++ strerror(errno));
++ return -1;
++ }
++ if (snprintf(str, len, "/%s/\n", wwid) >= len) {
++ condlog(0, "string overflow trying to remove wwid");
++ goto out;
++ }
++ condlog(3, "removing line '%s' from wwids file", str);
++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER);
++ if (fd < 0)
++ goto out;
++ if (!can_write) {
++ condlog(0, "cannot remove wwid. wwids file is read-only");
++ goto out_file;
++ }
++ ret = do_remove_wwid(fd, str);
++
++out_file:
++ close(fd);
++out:
++ free(str);
++ return ret;
++}
++
++int
+ check_wwids_file(char *wwid, int write_wwid)
+ {
+ int fd, can_write, found, ret;
+Index: multipath-tools-130222/libmultipath/wwids.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.h
++++ multipath-tools-130222/libmultipath/wwids.h
+@@ -15,5 +15,6 @@
+ int should_multipath(struct path *pp, vector pathvec);
+ int remember_wwid(char *wwid);
+ int check_wwids_file(char *wwid, int write_wwid);
++int remove_wwid(char *wwid);
+
+ #endif /* _WWIDS_H */
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -83,7 +83,7 @@ usage (char * progname)
+ {
+ fprintf (stderr, VERSION_STRING);
+ fprintf (stderr, "Usage:\n");
+- fprintf (stderr, " %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
++ fprintf (stderr, " %s [-c|-w] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
+ fprintf (stderr, " %s -t\n", progname);
+@@ -104,6 +104,7 @@ usage (char * progname)
+ " -B treat the bindings file as read only\n" \
+ " -p policy failover|multibus|group_by_serial|group_by_prio\n" \
+ " -b fil bindings file location\n" \
++ " -w remove a device from the wwids file\n" \
+ " -p pol force all maps to specified path grouping policy :\n" \
+ " . failover one path per priority group\n" \
+ " . multibus all paths in one priority group\n" \
+@@ -212,7 +213,6 @@ get_dm_mpvec (vector curmp, vector pathv
+
+ if (!conf->dry_run)
+ reinstate_paths(mpp);
+- remember_wwid(mpp->wwid);
+ }
+ return 0;
+ }
+@@ -262,7 +262,7 @@ configure (void)
+ /*
+ * if we have a blacklisted device parameter, exit early
+ */
+- if (dev && conf->dev_type == DEV_DEVNODE &&
++ if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 &&
+ (filter_devnode(conf->blist_devnode,
+ conf->elist_devnode, dev) > 0)) {
+ if (conf->dry_run == 2)
+@@ -284,6 +284,17 @@ configure (void)
+ condlog(3, "scope is nul");
+ goto out;
+ }
++ if (conf->dry_run == 3) {
++ r = remove_wwid(refwwid);
++ if (r == 0)
++ printf("wwid '%s' removed\n", refwwid);
++ else if (r == 1) {
++ printf("wwid '%s' not in wwids file\n",
++ refwwid);
++ r = 0;
++ }
++ goto out;
++ }
+ condlog(3, "scope limited to %s", refwwid);
+ if (conf->dry_run == 2) {
+ if (check_wwids_file(refwwid, 0) == 0){
+@@ -439,7 +450,7 @@ main (int argc, char *argv[])
+ if (dm_prereq())
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtqw")) != EOF ) {
+ switch(arg) {
+ case 1: printf("optarg : %s\n",optarg);
+ break;
+@@ -504,6 +515,9 @@ main (int argc, char *argv[])
+ case 'h':
+ usage(argv[0]);
+ exit(0);
++ case 'w':
++ conf->dry_run = 3;
++ break;
+ case ':':
+ fprintf(stderr, "Missing option argument\n");
+ usage(argv[0]);
+@@ -555,6 +569,10 @@ main (int argc, char *argv[])
+ condlog(0, "the -c option requires a path to check");
+ goto out;
+ }
++ if (conf->dry_run == 3 && !conf->dev) {
++ condlog(0, "the -w option requires a device");
++ goto out;
++ }
+ if (conf->remove == FLUSH_ONE) {
+ if (conf->dev_type == DEV_DEVMAP) {
+ r = dm_suspend_and_flush_map(conf->dev);
+Index: multipath-tools-130222/multipath/multipath.8
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.8
++++ multipath-tools-130222/multipath/multipath.8
+@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco
+ .RB [\| \-b\ \c
+ .IR bindings_file \|]
+ .RB [\| \-d \|]
+-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r \|]
++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w \|]
+ .RB [\| \-p\ \c
+ .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
+ .RB [\| device \|]
+@@ -68,6 +68,9 @@ check if a block device should be a path
+ .B \-q
+ allow device tables with queue_if_no_path when multipathd is not running
+ .TP
++.B \-w
++remove the wwid for the specified device from the wwids file
++.TP
+ .BI \-p " policy"
+ force new maps to use the specified policy:
+ .RS 1.2i
--- /dev/null
+---
+ libmultipath/wwids.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ libmultipath/wwids.h | 1 +
+ multipath/main.c | 29 +++++++++++++++++++++++++++--
+ multipath/multipath.8 | 5 ++++-
+ 4 files changed, 76 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/wwids.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -82,6 +82,50 @@ write_out_wwid(int fd, char *wwid) {
+ }
+
+ int
++replace_wwids(vector mp)
++{
++ int i, fd, can_write;
++ struct multipath * mpp;
++ size_t len;
++ int ret = -1;
++
++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER);
++ if (fd < 0)
++ goto out;
++ if (!can_write) {
++ condlog(0, "cannot replace wwids. wwids file is read-only");
++ goto out_file;
++ }
++ if (ftruncate(fd, 0) < 0) {
++ condlog(0, "cannot truncate wwids file : %s", strerror(errno));
++ goto out_file;
++ }
++ len = strlen(WWIDS_FILE_HEADER);
++ if (write_all(fd, WWIDS_FILE_HEADER, len) != len) {
++ condlog(0, "Can't write wwid file header : %s",
++ strerror(errno));
++ /* cleanup partially written header */
++ if (ftruncate(fd, 0) < 0)
++ condlog(0, "Cannot truncate header : %s",
++ strerror(errno));
++ goto out_file;
++ }
++ if (!mp || !mp->allocated) {
++ ret = 0;
++ goto out_file;
++ }
++ vector_foreach_slot(mp, mpp, i) {
++ if (write_out_wwid(fd, mpp->wwid) < 0)
++ goto out_file;
++ }
++ ret = 0;
++out_file:
++ close(fd);
++out:
++ return ret;
++}
++
++int
+ do_remove_wwid(int fd, char *str) {
+ char buf[4097];
+ char *ptr;
+Index: multipath-tools-130222/libmultipath/wwids.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.h
++++ multipath-tools-130222/libmultipath/wwids.h
+@@ -16,5 +16,6 @@ int should_multipath(struct path *pp, ve
+ int remember_wwid(char *wwid);
+ int check_wwids_file(char *wwid, int write_wwid);
+ int remove_wwid(char *wwid);
++int replace_wwids(vector mp);
+
+ #endif /* _WWIDS_H */
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -83,7 +83,7 @@ usage (char * progname)
+ {
+ fprintf (stderr, VERSION_STRING);
+ fprintf (stderr, "Usage:\n");
+- fprintf (stderr, " %s [-c|-w] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
++ fprintf (stderr, " %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
+ fprintf (stderr, " %s -t\n", progname);
+@@ -105,6 +105,7 @@ usage (char * progname)
+ " -p policy failover|multibus|group_by_serial|group_by_prio\n" \
+ " -b fil bindings file location\n" \
+ " -w remove a device from the wwids file\n" \
++ " -W reset the wwids file include only the current devices\n" \
+ " -p pol force all maps to specified path grouping policy :\n" \
+ " . failover one path per priority group\n" \
+ " . multibus all paths in one priority group\n" \
+@@ -450,7 +451,7 @@ main (int argc, char *argv[])
+ if (dm_prereq())
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtqw")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtqwW")) != EOF ) {
+ switch(arg) {
+ case 1: printf("optarg : %s\n",optarg);
+ break;
+@@ -518,6 +519,9 @@ main (int argc, char *argv[])
+ case 'w':
+ conf->dry_run = 3;
+ break;
++ case 'W':
++ conf->dry_run = 4;
++ break;
+ case ':':
+ fprintf(stderr, "Missing option argument\n");
+ usage(argv[0]);
+@@ -573,6 +577,27 @@ main (int argc, char *argv[])
+ condlog(0, "the -w option requires a device");
+ goto out;
+ }
++ if (conf->dry_run == 4) {
++ struct multipath * mpp;
++ int i;
++ vector curmp;
++
++ curmp = vector_alloc();
++ if (!curmp) {
++ condlog(0, "can't allocate memory for mp list");
++ goto out;
++ }
++ if (dm_get_maps(curmp) == 0)
++ r = replace_wwids(curmp);
++ if (r == 0)
++ printf("successfully reset wwids\n");
++ vector_foreach_slot_backwards(curmp, mpp, i) {
++ vector_del_slot(curmp, i);
++ free_multipath(mpp, KEEP_PATHS);
++ }
++ vector_free(curmp);
++ goto out;
++ }
+ if (conf->remove == FLUSH_ONE) {
+ if (conf->dev_type == DEV_DEVMAP) {
+ r = dm_suspend_and_flush_map(conf->dev);
+Index: multipath-tools-130222/multipath/multipath.8
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.8
++++ multipath-tools-130222/multipath/multipath.8
+@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco
+ .RB [\| \-b\ \c
+ .IR bindings_file \|]
+ .RB [\| \-d \|]
+-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w \|]
++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w | \-W \|]
+ .RB [\| \-p\ \c
+ .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
+ .RB [\| device \|]
+@@ -71,6 +71,9 @@ allow device tables with queue_if_no_pat
+ .B \-w
+ remove the wwid for the specified device from the wwids file
+ .TP
++.B \-W
++reset the wwids file to only include the current multipath devices
++.TP
+ .BI \-p " policy"
+ force new maps to use the specified policy:
+ .RS 1.2i
--- /dev/null
+---
+ multipathd/main.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -537,7 +537,8 @@ rescan:
+ goto fail_map;
+
+ if (retries >= 0) {
+- condlog(2, "%s path added to devmap %s", pp->dev, mpp->alias);
++ condlog(2, "%s [%s]: path added to devmap %s",
++ pp->dev, pp->dev_t, mpp->alias);
+ return 0;
+ }
+ else
+@@ -642,8 +643,8 @@ ev_remove_path (struct path *pp, struct
+ }
+ sync_map_state(mpp);
+
+- condlog(2, "%s: path removed from map %s",
+- pp->dev, mpp->alias);
++ condlog(2, "%s [%s]: path removed from map %s",
++ pp->dev, pp->dev_t, mpp->alias);
+ }
+ }
+
--- /dev/null
+---
+ multipathd/main.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -1226,11 +1226,10 @@ check_path (struct vectors * vecs, struc
+ pp->checkint = 2 * pp->checkint;
+ else
+ pp->checkint = conf->max_checkint;
+-
+- pp->tick = pp->checkint;
+- condlog(4, "%s: delay next check %is",
+- pp->dev_t, pp->tick);
+ }
++ pp->tick = pp->checkint;
++ condlog(4, "%s: delay next check %is",
++ pp->dev_t, pp->tick);
+ }
+ }
+ else if (newstate == PATH_DOWN) {
--- /dev/null
+---
+ libmultipath/structs_vec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/structs_vec.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs_vec.c
++++ multipath-tools-130222/libmultipath/structs_vec.c
+@@ -106,7 +106,7 @@ orphan_paths (vector pathvec, struct mul
+ static void
+ set_multipath_wwid (struct multipath * mpp)
+ {
+- if (mpp->wwid)
++ if (strlen(mpp->wwid))
+ return;
+
+ dm_get_uuid(mpp->alias, mpp->wwid);
--- /dev/null
+---
+ libmultipath/discovery.c | 2 +-
+ multipathd/main.c | 19 ++++++++++++++++++-
+ 2 files changed, 19 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -1034,7 +1034,7 @@ pathinfo (struct path *pp, vector hwtabl
+ }
+ }
+
+- if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid))
++ if ((mask & DI_WWID) && !strlen(pp->wwid))
+ get_uid(pp);
+ if (mask & DI_BLACKLIST && mask & DI_WWID) {
+ if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -376,7 +376,7 @@ static int
+ uev_add_path (struct uevent *uev, struct vectors * vecs)
+ {
+ struct path *pp;
+- int ret;
++ int ret, i;
+
+ condlog(2, "%s: add path (uevent)", uev->kernel);
+ if (strstr(uev->kernel, "..") != NULL) {
+@@ -393,6 +393,23 @@ uev_add_path (struct uevent *uev, struct
+ uev->kernel);
+ if (pp->mpp)
+ return 0;
++ if (!strlen(pp->wwid)) {
++ udev_device_unref(pp->udev);
++ pp->udev = udev_device_ref(uev->udev);
++ ret = pathinfo(pp, conf->hwtable,
++ DI_ALL | DI_BLACKLIST);
++ if (ret == 2) {
++ i = find_slot(vecs->pathvec, (void *)pp);
++ if (i != -1)
++ vector_del_slot(vecs->pathvec, i);
++ free_path(pp);
++ return 0;
++ } else if (ret == 1) {
++ condlog(0, "%s: failed to reinitialize path",
++ uev->kernel);
++ return 1;
++ }
++ }
+ } else {
+ /*
+ * get path vital state
--- /dev/null
+---
+ libmultipath/prio.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/prio.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prio.c
++++ multipath-tools-130222/libmultipath/prio.c
+@@ -162,7 +162,10 @@ void prio_put (struct prio * dst)
+ if (!dst)
+ return;
+
+- src = prio_lookup(dst->name);
++ if (!strlen(dst->name))
++ src = NULL;
++ else
++ src = prio_lookup(dst->name);
+ memset(dst, 0x0, sizeof(struct prio));
+ free_prio(src);
+ }
--- /dev/null
+---
+ libmultipath/dict.c | 10 ++++------
+ libmultipath/structs.h | 2 +-
+ multipathd/cli.c | 3 +++
+ multipathd/cli.h | 2 ++
+ multipathd/cli_handlers.c | 18 ++++++++++++++++++
+ multipathd/cli_handlers.h | 2 ++
+ multipathd/main.c | 2 ++
+ multipathd/multipathd.init.redhat | 14 ++++++++++----
+ 8 files changed, 42 insertions(+), 11 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -438,14 +438,11 @@ def_queue_without_daemon(vector strvec)
+ if (!buff)
+ return 1;
+
+- if (!strncmp(buff, "off", 3) || !strncmp(buff, "no", 2) ||
+- !strncmp(buff, "0", 1))
+- conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
+- else if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) ||
++ if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) ||
+ !strncmp(buff, "1", 1))
+ conf->queue_without_daemon = QUE_NO_DAEMON_ON;
+ else
+- conf->queue_without_daemon = QUE_NO_DAEMON_UNDEF;
++ conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
+
+ free(buff);
+ return 0;
+@@ -2670,8 +2667,9 @@ snprint_def_queue_without_daemon (char *
+ case QUE_NO_DAEMON_OFF:
+ return snprintf(buff, len, "\"no\"");
+ case QUE_NO_DAEMON_ON:
+- case QUE_NO_DAEMON_UNDEF:
+ return snprintf(buff, len, "\"yes\"");
++ case QUE_NO_DAEMON_FORCE:
++ return snprintf(buff, len, "\"forced\"");
+ }
+ return 0;
+ }
+Index: multipath-tools-130222/libmultipath/structs.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs.h
++++ multipath-tools-130222/libmultipath/structs.h
+@@ -67,9 +67,9 @@ enum pgstates {
+ };
+
+ enum queue_without_daemon_states {
+- QUE_NO_DAEMON_UNDEF,
+ QUE_NO_DAEMON_OFF,
+ QUE_NO_DAEMON_ON,
++ QUE_NO_DAEMON_FORCE,
+ };
+
+ enum pgtimeouts {
+Index: multipath-tools-130222/multipathd/cli.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli.c
++++ multipath-tools-130222/multipathd/cli.c
+@@ -162,6 +162,7 @@ load_keys (void)
+ r += add_key(keys, "resize", RESIZE, 0);
+ r += add_key(keys, "reset", RESET, 0);
+ r += add_key(keys, "reload", RELOAD, 0);
++ r += add_key(keys, "forcequeueing", FORCEQ, 0);
+ r += add_key(keys, "disablequeueing", DISABLEQ, 0);
+ r += add_key(keys, "restorequeueing", RESTOREQ, 0);
+ r += add_key(keys, "paths", PATHS, 0);
+@@ -459,6 +460,8 @@ cli_init (void) {
+ add_handler(GETPRSTATUS+MAP, NULL);
+ add_handler(SETPRSTATUS+MAP, NULL);
+ add_handler(UNSETPRSTATUS+MAP, NULL);
++ add_handler(FORCEQ+DAEMON, NULL);
++ add_handler(RESTOREQ+DAEMON, NULL);
+
+ return 0;
+ }
+Index: multipath-tools-130222/multipathd/cli.h
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli.h
++++ multipath-tools-130222/multipathd/cli.h
+@@ -10,6 +10,7 @@ enum {
+ __RESIZE,
+ __RESET,
+ __RELOAD,
++ __FORCEQ,
+ __DISABLEQ,
+ __RESTOREQ,
+ __PATHS,
+@@ -45,6 +46,7 @@ enum {
+ #define RESIZE (1 << __RESIZE)
+ #define RESET (1 << __RESET)
+ #define RELOAD (1 << __RELOAD)
++#define FORCEQ (1 << __FORCEQ)
+ #define DISABLEQ (1 << __DISABLEQ)
+ #define RESTOREQ (1 << __RESTOREQ)
+ #define PATHS (1 << __PATHS)
+Index: multipath-tools-130222/multipathd/cli_handlers.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli_handlers.c
++++ multipath-tools-130222/multipathd/cli_handlers.c
+@@ -628,6 +628,24 @@ cli_resize(void *v, char **reply, int *l
+ }
+
+ int
++cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data)
++{
++ condlog(2, "force queue_without_daemon (operator)");
++ if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
++ conf->queue_without_daemon = QUE_NO_DAEMON_FORCE;
++ return 0;
++}
++
++int
++cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data)
++{
++ condlog(2, "restore queue_without_daemon (operator)");
++ if (conf->queue_without_daemon == QUE_NO_DAEMON_FORCE)
++ conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
++ return 0;
++}
++
++int
+ cli_restore_queueing(void *v, char **reply, int *len, void *data)
+ {
+ struct vectors * vecs = (struct vectors *)data;
+Index: multipath-tools-130222/multipathd/cli_handlers.h
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli_handlers.h
++++ multipath-tools-130222/multipathd/cli_handlers.h
+@@ -28,6 +28,8 @@ int cli_suspend(void * v, char ** reply,
+ int cli_resume(void * v, char ** reply, int * len, void * data);
+ int cli_reinstate(void * v, char ** reply, int * len, void * data);
+ int cli_fail(void * v, char ** reply, int * len, void * data);
++int cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data);
++int cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data);
+ int cli_quit(void * v, char ** reply, int * len, void * data);
+ int cli_shutdown(void * v, char ** reply, int * len, void * data);
+ int cli_reassign (void * v, char ** reply, int * len, void * data);
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -904,6 +904,8 @@ uxlsnrloop (void * ap)
+ set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus);
+ set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus);
+ set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus);
++ set_handler_callback(FORCEQ+DAEMON, cli_force_no_daemon_q);
++ set_handler_callback(RESTOREQ+DAEMON, cli_restore_no_daemon_q);
+
+ umask(077);
+ uxsock_listen(&uxsock_trigger, ap);
+Index: multipath-tools-130222/multipathd/multipathd.init.redhat
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.init.redhat
++++ multipath-tools-130222/multipathd/multipathd.init.redhat
+@@ -81,23 +81,28 @@ force_stop() {
+ echo
+ }
+
+-stop() {
++check_root() {
+ root_dev=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $1; }}' /etc/mtab)
+ dm_num=`dmsetup info -c --noheadings -o minor $root_dev 2> /dev/null`
+ if [ $? -eq 0 ]; then
+ root_dm_device="dm-$dm_num"
+ [ -d $syspath/$root_dm_device ] && teardown_slaves $syspath/$root_dm_device
+ fi
++}
+
+- force_stop
++force_queue_without_daemon() {
++ $DAEMON forcequeueing daemon
+ }
+
+ restart() {
+- stop
++ force_queue_without_daemon
++ check_root
++ force_stop
+ start
+ }
+
+ force_restart() {
++ force_queue_without_daemon
+ force_stop
+ start
+ }
+@@ -115,7 +120,8 @@ start)
+ start
+ ;;
+ stop)
+- stop
++ check_root
++ force_stop
+ ;;
+ force-stop)
+ force_stop
--- /dev/null
+---
+ kpartx/kpartx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/kpartx/kpartx.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/kpartx.c
++++ multipath-tools-130222/kpartx/kpartx.c
+@@ -348,7 +348,7 @@ main(int argc, char **argv){
+ if (delim == NULL) {
+ delim = malloc(DELIM_SIZE);
+ memset(delim, 0, DELIM_SIZE);
+- set_delimiter(device, delim);
++ set_delimiter(mapname, delim);
+ }
+
+ fd = open(device, O_RDONLY);
--- /dev/null
+---
+ multipath/mpathconf | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/multipath/mpathconf
+===================================================================
+--- multipath-tools-130222.orig/multipath/mpathconf
++++ multipath-tools-130222/multipath/mpathconf
+@@ -31,8 +31,8 @@ function usage
+ echo "Commands:"
+ echo "Enable: --enable "
+ echo "Disable: --disable"
+- echo "Set user_friendly_names (Default n): --user_friendly_names <y|n>"
+- echo "Set find_multipaths (Default n): --find_multipaths <y|n>"
++ echo "Set user_friendly_names (Default y): --user_friendly_names <y|n>"
++ echo "Set find_multipaths (Default y): --find_multipaths <y|n>"
+ echo "Load the dm-multipath modules on enable (Default y): --with_module <y|n>"
+ echo "start/stop/reload multipathd (Default n): --with_multipathd <y|n>"
+ echo ""
--- /dev/null
+This patch provides hwtable updates for NETAPP/LSI/ENGENIO E-Series arrays,
+utilizing new features to detect TPGS support, automatically.
+
+Signed-off-by: Sean Stewart <Sean.Stewart@netapp.com>
+
+---
+---
+ libmultipath/hwtable.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/hwtable.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/hwtable.c
++++ multipath-tools-130222/libmultipath/hwtable.c
+@@ -1046,9 +1046,13 @@ static struct hwentry default_hw[] = {
+ .checker_name = RDAC,
+ .prio_name = PRIO_RDAC,
+ },
+- /* LSI/Engenio/NetApp E-Series RDAC storage */
++ /* LSI/Engenio/NetApp E-Series RDAC storage
++ *
++ * Maintainer : Sean Stewart
++ * Mail : sean.stewart@netapp.com
++ */
+ {
+- .vendor = "(LSI|ENGENIO)",
++ .vendor = "(NETAPP|LSI|ENGENIO)",
+ .product = "INF-01-00",
+ .bl_product = "Universal Xport",
+ .features = "2 pg_init_retries 50",
+@@ -1056,10 +1060,12 @@ static struct hwentry default_hw[] = {
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+- .no_path_retry = 15,
++ .no_path_retry = 30,
+ .checker_name = RDAC,
+ .prio_name = PRIO_RDAC,
+ .prio_args = NULL,
++ .detect_prio = DETECT_PRIO_ON,
++ .retain_hwhandler = RETAIN_HWHANDLER_ON,
+ },
+ {
+ .vendor = "STK",
--- /dev/null
+---
+ multipath/mpathconf | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+Index: multipath-tools-130222/multipath/mpathconf
+===================================================================
+--- multipath-tools-130222.orig/multipath/mpathconf
++++ multipath-tools-130222/multipath/mpathconf
+@@ -159,7 +159,7 @@ if [ -z "$MODULE" -o "$MODULE" = "y" ];
+ fi
+
+ if [ "$MULTIPATHD" = "y" ]; then
+- if service multipathd status > /dev/null ; then
++ if /bin/systemctl status multipathd.service > /dev/null 2>&1 ; then
+ HAVE_MULTIPATHD=1
+ else
+ HAVE_MULTIPATHD=0
+@@ -210,8 +210,17 @@ if [ -n "$SHOW_STATUS" ]; then
+ echo "dm_multipath module is not loaded"
+ fi
+ fi
+- if [ -n "$HAVE_MULTIPATHD" ]; then
+- service multipathd status
++ if [ -z "$HAVE_MULTIPATHD" ]; then
++ if /bin/systemctl status multipathd.service > /dev/null 2>&1 ; then
++ HAVE_MULTIPATHD=1
++ else
++ HAVE_MULTIPATHD=0
++ fi
++ fi
++ if [ "$HAVE_MULTIPATHD" = 1 ]; then
++ echo "multipathd is running"
++ else
++ echo "multipathd is not running"
+ fi
+ exit 0
+ fi
+@@ -301,12 +310,12 @@ if [ "$ENABLE" = 1 ]; then
+ modprobe dm_multipath
+ fi
+ if [ "$HAVE_MULTIPATHD" = 0 ]; then
+- service multipathd start
++ systemctl start multipathd.service
+ fi
+ elif [ "$ENABLE" = 0 ]; then
+ if [ "$HAVE_MULTIPATHD" = 1 ]; then
+- service multipathd stop
++ systemctl stop multipathd.service
+ fi
+ elif [ -n "$CHANGED_CONFIG" -a "$HAVE_MULTIPATHD" = 1 ]; then
+- service multipathd reload
++ systemctl reload multipathd.service
+ fi
--- /dev/null
+---
+ libmultipath/print.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/print.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/print.c
++++ multipath-tools-130222/libmultipath/print.c
+@@ -422,6 +422,16 @@ snprint_path_serial (char * buff, size_t
+ }
+
+ static int
++snprint_path_mpp (char * buff, size_t len, struct path * pp)
++{
++ if (!pp->mpp)
++ return snprintf(buff, len, "[orphan]");
++ if (!pp->mpp->alias)
++ return snprintf(buff, len, "[unknown]");
++ return snprint_str(buff, len, pp->mpp->alias);
++}
++
++static int
+ snprint_path_checker (char * buff, size_t len, struct path * pp)
+ {
+ struct checker * c = &pp->checker;
+@@ -464,6 +474,7 @@ struct path_data pd[] = {
+ {'p', "pri", 0, snprint_pri},
+ {'S', "size", 0, snprint_path_size},
+ {'z', "serial", 0, snprint_path_serial},
++ {'m', "multipath", 0, snprint_path_mpp},
+ {0, NULL, 0 , NULL}
+ };
+
--- /dev/null
+---
+ multipathd/multipathd.service | 1 +
+ 1 file changed, 1 insertion(+)
+
+Index: multipath-tools-130222/multipathd/multipathd.service
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.service
++++ multipath-tools-130222/multipathd/multipathd.service
+@@ -10,6 +10,7 @@ Conflicts=shutdown.target
+ [Service]
+ Type=forking
+ PIDFile=/var/run/multipathd.pid
++ExecStartPre=/sbin/modprobe dm-multipath
+ ExecStart=/sbin/multipathd
+ ExecReload=/sbin/multipathd reconfigure
+ #ExecStop=/path/to/scrip delete-me if not necessary
--- /dev/null
+---
+ libmultipath/devmapper.c | 45 ---------------------------------------------
+ libmultipath/devmapper.h | 1 -
+ libmultipath/propsel.c | 2 --
+ 3 files changed, 48 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -917,51 +917,6 @@ out:
+ return r;
+ }
+
+-extern char *
+-dm_get_name(char *uuid)
+-{
+- struct dm_task *dmt;
+- struct dm_info info;
+- char *prefixed_uuid, *name = NULL;
+- const char *nametmp;
+-
+- dmt = dm_task_create(DM_DEVICE_INFO);
+- if (!dmt)
+- return NULL;
+-
+- prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
+- if (!prefixed_uuid) {
+- condlog(0, "cannot create prefixed uuid : %s",
+- strerror(errno));
+- goto freeout;
+- }
+- sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
+- if (!dm_task_set_uuid(dmt, prefixed_uuid))
+- goto freeout;
+-
+- if (!dm_task_run(dmt))
+- goto freeout;
+-
+- if (!dm_task_get_info(dmt, &info) || !info.exists)
+- goto freeout;
+-
+- nametmp = dm_task_get_name(dmt);
+- if (nametmp && strlen(nametmp)) {
+- name = MALLOC(strlen(nametmp) + 1);
+- if (name)
+- strcpy(name, nametmp);
+- } else {
+- condlog(2, "%s: no device-mapper name found", uuid);
+- }
+-
+-freeout:
+- if (prefixed_uuid)
+- FREE(prefixed_uuid);
+- dm_task_destroy(dmt);
+-
+- return name;
+-}
+-
+ int
+ dm_geteventnr (char *name)
+ {
+Index: multipath-tools-130222/libmultipath/devmapper.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.h
++++ multipath-tools-130222/libmultipath/devmapper.h
+@@ -40,7 +40,6 @@ int dm_remove_partmaps (const char * map
+ int dm_get_uuid(char *name, char *uuid);
+ int dm_get_info (char * mapname, struct dm_info ** dmi);
+ int dm_rename (char * old, char * new);
+-char * dm_get_name(char * uuid);
+ int dm_reassign(const char * mapname);
+ int dm_reassign_table(const char *name, char *old, char *new);
+ int dm_setgeometry(struct multipath *mpp);
+Index: multipath-tools-130222/libmultipath/propsel.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.c
++++ multipath-tools-130222/libmultipath/propsel.c
+@@ -263,8 +263,6 @@ select_alias (struct multipath * mp)
+ conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
+ }
+ if (mp->alias == NULL)
+- mp->alias = dm_get_name(mp->wwid);
+- if (mp->alias == NULL)
+ mp->alias = STRDUP(mp->wwid);
+ }
+
--- /dev/null
+---
+ libmultipath/hwtable.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+Index: multipath-tools-130222/libmultipath/hwtable.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/hwtable.c
++++ multipath-tools-130222/libmultipath/hwtable.c
+@@ -794,6 +794,7 @@ static struct hwentry default_hw[] = {
+ .prio_name = PRIO_ONTAP,
+ .prio_args = NULL,
+ .retain_hwhandler = RETAIN_HWHANDLER_ON,
++ .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
+ .detect_prio = DETECT_PRIO_ON,
+ },
+ /*
--- /dev/null
+---
+ libmultipath/propsel.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/propsel.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.c
++++ multipath-tools-130222/libmultipath/propsel.c
+@@ -384,10 +384,17 @@ select_getuid (struct path * pp)
+ void
+ detect_prio(struct path * pp)
+ {
++ int ret;
+ struct prio *p = &pp->prio;
+
+- if (get_target_port_group_support(pp->fd) > 0)
+- prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
++ if (get_target_port_group_support(pp->fd) <= 0)
++ return;
++ ret = get_target_port_group(pp->fd);
++ if (ret < 0)
++ return;
++ if (get_asymmetric_access_state(pp->fd, ret) < 0)
++ return;
++ prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
+ }
+
+ extern int
--- /dev/null
+---
+ libmultipath/alias.c | 39 ++++++++++++++++++++++++++++++---------
+ 1 file changed, 30 insertions(+), 9 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/alias.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/alias.c
++++ multipath-tools-130222/libmultipath/alias.c
+@@ -46,11 +46,11 @@ format_devname(char *name, int id, int l
+ memset(name,0, len);
+ strcpy(name, prefix);
+ for (pos = len - 1; pos >= prefix_len; pos--) {
++ id--;
+ name[pos] = 'a' + id % 26;
+ if (id < 26)
+ break;
+ id /= 26;
+- id--;
+ }
+ memmove(name + prefix_len, name + pos, len - pos);
+ name[prefix_len + len - pos] = '\0';
+@@ -66,13 +66,22 @@ scan_devname(char *alias, char *prefix)
+ if (!prefix || strncmp(alias, prefix, strlen(prefix)))
+ return -1;
+
++ if (strlen(alias) == strlen(prefix))
++ return -1;
++
++ if (strlen(alias) > strlen(prefix) + 7)
++ /* id of 'aaaaaaaa' overflows int */
++ return -1;
++
+ c = alias + strlen(prefix);
+ while (*c != '\0' && *c != ' ' && *c != '\t') {
++ if (*c < 'a' || *c > 'z')
++ return -1;
+ i = *c - 'a';
+ n = ( n * 26 ) + i;
++ if (n < 0)
++ return -1;
+ c++;
+- if (*c < 'a' || *c > 'z')
+- break;
+ n++;
+ }
+
+@@ -84,7 +93,9 @@ lookup_binding(FILE *f, char *map_wwid,
+ {
+ char buf[LINE_MAX];
+ unsigned int line_nr = 0;
+- int id = 0;
++ int id = 1;
++ int biggest_id = 1;
++ int smallest_bigger_id = INT_MAX;
+
+ *map_alias = NULL;
+
+@@ -100,8 +111,12 @@ lookup_binding(FILE *f, char *map_wwid,
+ if (!alias) /* blank line */
+ continue;
+ curr_id = scan_devname(alias, prefix);
+- if (curr_id >= id)
+- id = curr_id + 1;
++ if (curr_id == id)
++ id++;
++ if (curr_id > biggest_id)
++ biggest_id = curr_id;
++ if (curr_id > id && curr_id < smallest_bigger_id)
++ smallest_bigger_id = curr_id;
+ wwid = strtok(NULL, " \t");
+ if (!wwid){
+ condlog(3,
+@@ -116,11 +131,17 @@ lookup_binding(FILE *f, char *map_wwid,
+ if (*map_alias == NULL)
+ condlog(0, "Cannot copy alias from bindings "
+ "file : %s", strerror(errno));
+- return id;
++ return 0;
+ }
+ }
+ condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
+- return id;
++ if (id < 0) {
++ condlog(0, "no more available user_friendly_names");
++ return 0;
++ }
++ if (id < smallest_bigger_id)
++ return id;
++ return biggest_id + 1;
+ }
+
+ static int
+@@ -254,7 +275,7 @@ get_user_friendly_alias(char *wwid, char
+ return NULL;
+ }
+
+- if (!alias && can_write && !bindings_read_only)
++ if (!alias && can_write && !bindings_read_only && id)
+ alias = allocate_binding(fd, wwid, id, prefix);
+
+ fclose(f);
--- /dev/null
+---
+ libmultipath/configure.c | 7 ------
+ libmultipath/devmapper.c | 53 ++++++++++++++++++++++-------------------------
+ libmultipath/devmapper.h | 2 -
+ 3 files changed, 25 insertions(+), 37 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -384,24 +384,17 @@ domap (struct multipath * mpp, char * pa
+
+ r = dm_addmap_create(mpp, params);
+
+- if (!r)
+- r = dm_addmap_create_ro(mpp, params);
+-
+ lock_multipath(mpp, 0);
+ break;
+
+ case ACT_RELOAD:
+ r = dm_addmap_reload(mpp, params);
+- if (!r)
+- r = dm_addmap_reload_ro(mpp, params);
+ if (r)
+ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias);
+ break;
+
+ case ACT_RESIZE:
+ r = dm_addmap_reload(mpp, params);
+- if (!r)
+- r = dm_addmap_reload_ro(mpp, params);
+ if (r)
+ r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1);
+ break;
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -298,42 +298,39 @@ dm_addmap (int task, const char *target,
+ return r;
+ }
+
+-static int
+-_dm_addmap_create (struct multipath *mpp, char * params, int ro) {
+- int r;
+- r = dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro);
+- /*
+- * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
+- * Failing the second part leaves an empty map. Clean it up.
+- */
+- if (!r && dm_map_present(mpp->alias)) {
+- condlog(3, "%s: failed to load map (a path might be in use)",
+- mpp->alias);
+- dm_flush_map_nosync(mpp->alias);
++extern int
++dm_addmap_create (struct multipath *mpp, char * params) {
++ int ro;
++
++ for (ro = 0; ro <= 1; ro++) {
++ int err;
++
++ if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro))
++ return 1;
++ /*
++ * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
++ * Failing the second part leaves an empty map. Clean it up.
++ */
++ err = errno;
++ if (dm_map_present(mpp->alias)) {
++ condlog(3, "%s: failed to load map (a path might be in use)", mpp->alias);
++ dm_flush_map_nosync(mpp->alias);
++ }
++ if (err != EROFS)
++ break;
+ }
+- return r;
++ return 0;
+ }
+
+ #define ADDMAP_RW 0
+ #define ADDMAP_RO 1
+
+ extern int
+-dm_addmap_create (struct multipath *mpp, char *params) {
+- return _dm_addmap_create(mpp, params, ADDMAP_RW);
+-}
+-
+-extern int
+-dm_addmap_create_ro (struct multipath *mpp, char *params) {
+- return _dm_addmap_create(mpp, params, ADDMAP_RO);
+-}
+-
+-extern int
+ dm_addmap_reload (struct multipath *mpp, char *params) {
+- return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW);
+-}
+-
+-extern int
+-dm_addmap_reload_ro (struct multipath *mpp, char *params) {
++ if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW))
++ return 1;
++ if (errno != EROFS)
++ return 0;
+ return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO);
+ }
+
+Index: multipath-tools-130222/libmultipath/devmapper.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.h
++++ multipath-tools-130222/libmultipath/devmapper.h
+@@ -12,9 +12,7 @@ int dm_drv_version (unsigned int * versi
+ int dm_simplecmd_flush (int, const char *, int);
+ int dm_simplecmd_noflush (int, const char *);
+ int dm_addmap_create (struct multipath *mpp, char *params);
+-int dm_addmap_create_ro (struct multipath *mpp, char *params);
+ int dm_addmap_reload (struct multipath *mpp, char *params);
+-int dm_addmap_reload_ro (struct multipath *mpp, char *params);
+ int dm_map_present (const char *);
+ int dm_get_map(char *, unsigned long long *, char *);
+ int dm_get_status(char *, char *);
--- /dev/null
+---
+ libmultipath/file.c | 4 +-
+ libmultipath/lock.c | 9 ----
+ libmultipath/lock.h | 1
+ libmultipath/log_pthread.c | 22 -----------
+ libmultipath/waiter.c | 2 -
+ multipathd/cli_handlers.c | 4 +-
+ multipathd/main.c | 90 ++++++++++++++++++++-------------------------
+ multipathd/main.h | 3 +
+ multipathd/uxlsnr.c | 21 +++++++---
+ multipathd/uxlsnr.h | 3 +
+ 10 files changed, 65 insertions(+), 94 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/file.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/file.c
++++ multipath-tools-130222/libmultipath/file.c
+@@ -98,7 +98,7 @@ lock_file(int fd, char *file_name)
+ sigaddset(&set, SIGALRM);
+
+ sigaction(SIGALRM, &act, &oldact);
+- sigprocmask(SIG_UNBLOCK, &set, &oldset);
++ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+
+ alarm(FILE_TIMEOUT);
+ err = fcntl(fd, F_SETLKW, &lock);
+@@ -112,7 +112,7 @@ lock_file(int fd, char *file_name)
+ condlog(0, "%s is locked. Giving up.", file_name);
+ }
+
+- sigprocmask(SIG_SETMASK, &oldset, NULL);
++ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ sigaction(SIGALRM, &oldact, NULL);
+ return err;
+ }
+Index: multipath-tools-130222/libmultipath/lock.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/lock.c
++++ multipath-tools-130222/libmultipath/lock.c
+@@ -1,16 +1,7 @@
+ #include <pthread.h>
+-#include <signal.h>
+ #include "lock.h"
+ #include <stdio.h>
+
+-void block_signal (int signum, sigset_t *old)
+-{
+- sigset_t set;
+- sigemptyset(&set);
+- sigaddset(&set, signum);
+- pthread_sigmask(SIG_BLOCK, &set, old);
+-}
+-
+ void cleanup_lock (void * data)
+ {
+ unlock ((*(struct mutex_lock *)data));
+Index: multipath-tools-130222/libmultipath/lock.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/lock.h
++++ multipath-tools-130222/libmultipath/lock.h
+@@ -29,6 +29,5 @@ struct mutex_lock {
+ #endif
+
+ void cleanup_lock (void * data);
+-void block_signal(int signum, sigset_t *old);
+
+ #endif /* _LOCK_H */
+Index: multipath-tools-130222/libmultipath/log_pthread.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/log_pthread.c
++++ multipath-tools-130222/libmultipath/log_pthread.c
+@@ -22,26 +22,13 @@ pthread_cond_t logev_cond;
+
+ int logq_running;
+
+-static void
+-sigusr1 (int sig)
+-{
+- pthread_mutex_lock(&logq_lock);
+- log_reset("multipathd");
+- pthread_mutex_unlock(&logq_lock);
+-}
+-
+ void log_safe (int prio, const char * fmt, va_list ap)
+ {
+- sigset_t old;
+-
+ if (log_thr == (pthread_t)0) {
+ syslog(prio, fmt, ap);
+ return;
+ }
+
+- block_signal(SIGUSR1, &old);
+- block_signal(SIGHUP, NULL);
+-
+ pthread_mutex_lock(&logq_lock);
+ log_enqueue(prio, fmt, ap);
+ pthread_mutex_unlock(&logq_lock);
+@@ -49,8 +36,6 @@ void log_safe (int prio, const char * fm
+ pthread_mutex_lock(&logev_lock);
+ pthread_cond_signal(&logev_cond);
+ pthread_mutex_unlock(&logev_lock);
+-
+- pthread_sigmask(SIG_SETMASK, &old, NULL);
+ }
+
+ void log_thread_flush (void)
+@@ -81,15 +66,8 @@ static void flush_logqueue (void)
+
+ static void * log_thread (void * et)
+ {
+- struct sigaction sig;
+ int running;
+
+- sig.sa_handler = sigusr1;
+- sigemptyset(&sig.sa_mask);
+- sig.sa_flags = 0;
+- if (sigaction(SIGUSR1, &sig, NULL) < 0)
+- logdbg(stderr, "Cannot set signal handler");
+-
+ pthread_mutex_lock(&logev_lock);
+ logq_running = 1;
+ pthread_mutex_unlock(&logev_lock);
+Index: multipath-tools-130222/libmultipath/waiter.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/waiter.c
++++ multipath-tools-130222/libmultipath/waiter.c
+@@ -157,8 +157,6 @@ void *waitevent (void *et)
+ waiter = (struct event_thread *)et;
+ pthread_cleanup_push(free_waiter, et);
+
+- block_signal(SIGUSR1, NULL);
+- block_signal(SIGHUP, NULL);
+ while (1) {
+ r = waiteventloop(waiter);
+
+Index: multipath-tools-130222/multipathd/cli_handlers.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli_handlers.c
++++ multipath-tools-130222/multipathd/cli_handlers.c
+@@ -939,8 +939,8 @@ int
+ cli_shutdown (void * v, char ** reply, int * len, void * data)
+ {
+ condlog(3, "shutdown (operator)");
+-
+- return exit_daemon(0);
++ exit_daemon();
++ return 0;
+ }
+
+ int
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -17,6 +17,7 @@
+ #include <limits.h>
+ #include <linux/oom.h>
+ #include <libudev.h>
++#include <semaphore.h>
+ #include <mpath_persist.h>
+
+ /*
+@@ -52,6 +53,7 @@
+ #include <wwids.h>
+ #include <pgpolicies.h>
+ #include <uevent.h>
++#include <log.h>
+
+ #include "main.h"
+ #include "pidfile.h"
+@@ -81,13 +83,11 @@ struct mpath_event_param
+
+ unsigned int mpath_mx_alloc_len;
+
+-pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
+-pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
+-
+ int logsink;
+ enum daemon_status running_state;
+ pid_t daemon_pid;
+
++static sem_t exit_sem;
+ /*
+ * global copy of vecs for use in sig handlers
+ */
+@@ -838,9 +838,6 @@ out:
+ static void *
+ ueventloop (void * ap)
+ {
+- block_signal(SIGUSR1, NULL);
+- block_signal(SIGHUP, NULL);
+-
+ if (uevent_listen())
+ condlog(0, "error starting uevent listener");
+
+@@ -850,9 +847,6 @@ ueventloop (void * ap)
+ static void *
+ uevqloop (void * ap)
+ {
+- block_signal(SIGUSR1, NULL);
+- block_signal(SIGHUP, NULL);
+-
+ if (uevent_dispatch(&uev_trigger, ap))
+ condlog(0, "error starting uevent dispatcher");
+
+@@ -861,9 +855,6 @@ uevqloop (void * ap)
+ static void *
+ uxlsnrloop (void * ap)
+ {
+- block_signal(SIGUSR1, NULL);
+- block_signal(SIGHUP, NULL);
+-
+ if (cli_init())
+ return NULL;
+
+@@ -913,18 +904,10 @@ uxlsnrloop (void * ap)
+ return NULL;
+ }
+
+-int
+-exit_daemon (int status)
++void
++exit_daemon (void)
+ {
+- if (status != 0)
+- fprintf(stderr, "bad exit status. see daemon.log\n");
+-
+- if (running_state != DAEMON_SHUTDOWN) {
+- pthread_mutex_lock(&exit_mutex);
+- pthread_cond_signal(&exit_cond);
+- pthread_mutex_unlock(&exit_mutex);
+- }
+- return status;
++ sem_post(&exit_sem);
+ }
+
+ const char *
+@@ -1287,7 +1270,6 @@ checkerloop (void *ap)
+ struct path *pp;
+ int count = 0;
+ unsigned int i;
+- sigset_t old;
+
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+ vecs = (struct vectors *)ap;
+@@ -1301,7 +1283,6 @@ checkerloop (void *ap)
+ }
+
+ while (1) {
+- block_signal(SIGHUP, &old);
+ pthread_cleanup_push(cleanup_lock, &vecs->lock);
+ lock(vecs->lock);
+ pthread_testcancel();
+@@ -1325,7 +1306,6 @@ checkerloop (void *ap)
+ }
+
+ lock_cleanup_pop(vecs->lock);
+- pthread_sigmask(SIG_SETMASK, &old, NULL);
+ sleep(1);
+ }
+ return NULL;
+@@ -1485,36 +1465,56 @@ signal_set(int signo, void (*func) (int)
+ return (osig.sa_handler);
+ }
+
++void
++handle_signals(void)
++{
++ if (reconfig_sig && running_state == DAEMON_RUNNING) {
++ condlog(2, "reconfigure (signal)");
++ pthread_cleanup_push(cleanup_lock,
++ &gvecs->lock);
++ lock(gvecs->lock);
++ pthread_testcancel();
++ reconfigure(gvecs);
++ lock_cleanup_pop(gvecs->lock);
++ }
++ if (log_reset_sig) {
++ condlog(2, "reset log (signal)");
++ pthread_mutex_lock(&logq_lock);
++ log_reset("multipathd");
++ pthread_mutex_unlock(&logq_lock);
++ }
++ reconfig_sig = 0;
++ log_reset_sig = 0;
++}
++
+ static void
+ sighup (int sig)
+ {
+- condlog(2, "reconfigure (SIGHUP)");
+-
+- if (running_state != DAEMON_RUNNING)
+- return;
+-
+- reconfigure(gvecs);
+-
+-#ifdef _DEBUG_
+- dbg_free_final(NULL);
+-#endif
++ reconfig_sig = 1;
+ }
+
+ static void
+ sigend (int sig)
+ {
+- exit_daemon(0);
++ exit_daemon();
+ }
+
+ static void
+ sigusr1 (int sig)
+ {
+- condlog(3, "SIGUSR1 received");
++ log_reset_sig = 1;
+ }
+
+ static void
+ signal_init(void)
+ {
++ sigset_t set;
++
++ sigemptyset(&set);
++ sigaddset(&set, SIGHUP);
++ sigaddset(&set, SIGUSR1);
++ pthread_sigmask(SIG_BLOCK, &set, NULL);
++
+ signal_set(SIGHUP, sighup);
+ signal_set(SIGUSR1, sigusr1);
+ signal_set(SIGINT, sigend);
+@@ -1587,10 +1587,11 @@ child (void * param)
+ struct vectors * vecs;
+ struct multipath * mpp;
+ int i;
+- sigset_t set;
+ int rc, pid_rc;
+
+ mlockall(MCL_CURRENT | MCL_FUTURE);
++ sem_init(&exit_sem, 0, 0);
++ signal_init();
+
+ setup_thread_attr(&misc_attr, 64 * 1024, 1);
+ setup_thread_attr(&waiter_attr, 32 * 1024, 1);
+@@ -1650,7 +1651,6 @@ child (void * param)
+ if (!vecs)
+ exit(1);
+
+- signal_init();
+ setscheduler();
+ set_oom_adj();
+
+@@ -1693,25 +1693,17 @@ child (void * param)
+ }
+ pthread_attr_destroy(&misc_attr);
+
+- pthread_mutex_lock(&exit_mutex);
+ /* Startup complete, create logfile */
+ pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid);
+ /* Ignore errors, we can live without */
+
+ running_state = DAEMON_RUNNING;
+- pthread_cond_wait(&exit_cond, &exit_mutex);
+- /* Need to block these to avoid deadlocking */
+- sigemptyset(&set);
+- sigaddset(&set, SIGTERM);
+- sigaddset(&set, SIGINT);
+- pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ /*
+ * exit path
+ */
++ while(sem_wait(&exit_sem) != 0); /* Do nothing */
+ running_state = DAEMON_SHUTDOWN;
+- pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+- block_signal(SIGHUP, NULL);
+ lock(vecs->lock);
+ if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
+ vector_foreach_slot(vecs->mpvec, mpp, i)
+Index: multipath-tools-130222/multipathd/main.h
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.h
++++ multipath-tools-130222/multipathd/main.h
+@@ -16,7 +16,7 @@ struct prin_resp;
+
+ extern pid_t daemon_pid;
+
+-int exit_daemon(int);
++void exit_daemon(void);
+ const char * daemon_status(void);
+ int reconfigure (struct vectors *);
+ int ev_add_path (struct path *, struct vectors *);
+@@ -35,5 +35,6 @@ int mpath_pr_event_handle(struct path *p
+ void * mpath_pr_event_handler_fn (void * );
+ int update_map_pr(struct multipath *mpp);
+ void * mpath_pr_event_handler_fn (void * pathp );
++void handle_signals(void);
+
+ #endif /* MAIN_H */
+Index: multipath-tools-130222/multipathd/uxlsnr.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/uxlsnr.c
++++ multipath-tools-130222/multipathd/uxlsnr.c
+@@ -8,6 +8,7 @@
+ /*
+ * A simple domain socket listener
+ */
++#define _GNU_SOURCE
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+@@ -19,20 +20,21 @@
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <sys/poll.h>
+-
++#include <signal.h>
+ #include <checkers.h>
+-
+ #include <memory.h>
+ #include <debug.h>
+ #include <vector.h>
+ #include <structs.h>
++#include <structs_vec.h>
+ #include <uxsock.h>
+ #include <defaults.h>
+
++#include "main.h"
+ #include "cli.h"
+ #include "uxlsnr.h"
+
+-#define SLEEP_TIME 5000
++struct timespec sleep_time = {5, 0};
+
+ struct client {
+ int fd;
+@@ -42,6 +44,8 @@ struct client {
+ static struct client *clients;
+ static unsigned num_clients;
+ struct pollfd *polls;
++volatile sig_atomic_t reconfig_sig = 0;
++volatile sig_atomic_t log_reset_sig = 0;
+
+ /*
+ * handle a new client joining
+@@ -104,6 +108,7 @@ void * uxsock_listen(int (*uxsock_trigge
+ int rlen;
+ char *inbuf;
+ char *reply;
++ sigset_t mask;
+
+ ux_sock = ux_socket_listen(DEFAULT_SOCKET);
+
+@@ -115,7 +120,9 @@ void * uxsock_listen(int (*uxsock_trigge
+ pthread_cleanup_push(uxsock_cleanup, NULL);
+
+ polls = (struct pollfd *)MALLOC(0);
+-
++ pthread_sigmask(SIG_SETMASK, NULL, &mask);
++ sigdelset(&mask, SIGHUP);
++ sigdelset(&mask, SIGUSR1);
+ while (1) {
+ struct client *c;
+ int i, poll_count;
+@@ -132,11 +139,13 @@ void * uxsock_listen(int (*uxsock_trigge
+ }
+
+ /* most of our life is spent in this call */
+- poll_count = poll(polls, i, SLEEP_TIME);
++ poll_count = ppoll(polls, i, &sleep_time, &mask);
+
+ if (poll_count == -1) {
+- if (errno == EINTR)
++ if (errno == EINTR) {
++ handle_signals();
+ continue;
++ }
+
+ /* something went badly wrong! */
+ condlog(0, "poll");
+Index: multipath-tools-130222/multipathd/uxlsnr.h
+===================================================================
+--- multipath-tools-130222.orig/multipathd/uxlsnr.h
++++ multipath-tools-130222/multipathd/uxlsnr.h
+@@ -4,5 +4,8 @@
+ void * uxsock_listen(int (*uxsock_trigger)
+ (char *, char **, int *, void *),
+ void * trigger_data);
++
++extern volatile sig_atomic_t reconfig_sig;
++extern volatile sig_atomic_t log_reset_sig;
+ #endif
+
--- /dev/null
+---
+ libmultipath/waiter.c | 9 +++++++++
+ multipathd/main.c | 8 ++++++++
+ 2 files changed, 17 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/waiter.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/waiter.c
++++ multipath-tools-130222/libmultipath/waiter.c
+@@ -57,6 +57,7 @@ void stop_waiter_thread (struct multipat
+ thread = mpp->waiter;
+ mpp->waiter = (pthread_t)0;
+ pthread_cancel(thread);
++ pthread_kill(thread, SIGUSR2);
+ }
+
+ /*
+@@ -65,6 +66,7 @@ void stop_waiter_thread (struct multipat
+ */
+ int waiteventloop (struct event_thread *waiter)
+ {
++ sigset_t set, oldset;
+ int event_nr;
+ int r;
+
+@@ -97,8 +99,15 @@ int waiteventloop (struct event_thread *
+ dm_task_no_open_count(waiter->dmt);
+
+ /* wait */
++ sigemptyset(&set);
++ sigaddset(&set, SIGUSR2);
++ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
++
++ pthread_testcancel();
+ r = dm_task_run(waiter->dmt);
++ pthread_testcancel();
+
++ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ dm_task_destroy(waiter->dmt);
+ waiter->dmt = NULL;
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -1506,6 +1506,12 @@ sigusr1 (int sig)
+ }
+
+ static void
++sigusr2 (int sig)
++{
++ condlog(3, "SIGUSR2 received");
++}
++
++static void
+ signal_init(void)
+ {
+ sigset_t set;
+@@ -1513,10 +1519,12 @@ signal_init(void)
+ sigemptyset(&set);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGUSR1);
++ sigaddset(&set, SIGUSR2);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ signal_set(SIGHUP, sighup);
+ signal_set(SIGUSR1, sigusr1);
++ signal_set(SIGUSR2, sigusr2);
+ signal_set(SIGINT, sigend);
+ signal_set(SIGTERM, sigend);
+ signal(SIGPIPE, SIG_IGN);
--- /dev/null
+---
+ libmultipath/wwids.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/wwids.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -4,6 +4,7 @@
+ #include <string.h>
+ #include <limits.h>
+ #include <stdio.h>
++#include <sys/types.h>
+
+ #include "checkers.h"
+ #include "vector.h"
+@@ -100,6 +101,11 @@ replace_wwids(vector mp)
+ condlog(0, "cannot truncate wwids file : %s", strerror(errno));
+ goto out_file;
+ }
++ if (lseek(fd, 0, SEEK_SET) < 0) {
++ condlog(0, "cannot seek to the start of the file : %s",
++ strerror(errno));
++ goto out_file;
++ }
+ len = strlen(WWIDS_FILE_HEADER);
+ if (write_all(fd, WWIDS_FILE_HEADER, len) != len) {
+ condlog(0, "Can't write wwid file header : %s",
--- /dev/null
+---
+ multipath/multipath.conf.5 | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -136,7 +136,7 @@ per-multipath option in the configuratio
+ 1 priority group per target node name. Target node names are fetched
+ in /sys/class/fc_transport/target*/node_name.
+ .TP
+-Default value is \fImultibus\fR.
++Default value is \fIfailover\fR.
+ .RE
+ .TP
+ .B uid_attribute
+@@ -182,7 +182,7 @@ Generate a random priority between 1 and
+ Generate the path priority based on the regular expression and the
+ priority provided as argument. requires prio_args keyword.
+ .TP
+-Default value is \fBnone\fR.
++Default value is \fBconst\fR.
+ .RE
+ .TP
+ .B prio_args
+@@ -270,7 +270,7 @@ The number of IO to route to a path befo
+ the same path group. This is only for BIO based multipath. Default is
+ .I 1000
+ .TP
+-.B rr_min_io_q
++.B rr_min_io_rq
+ The number of IO requests to route to a path before switching to the
+ next in the same path group. This is only for request based multipath.
+ Default is
--- /dev/null
+---
+ multipath/Makefile | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/multipath/Makefile
+===================================================================
+--- multipath-tools-130222.orig/multipath/Makefile
++++ multipath-tools-130222/multipath/Makefile
+@@ -23,8 +23,8 @@ install:
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+ $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/
+- $(INSTALL_PROGRAM) -d $(DESTDIR)/lib/udev/rules.d
+- $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/lib/udev/rules.d/62-multipath.rules
++ $(INSTALL_PROGRAM) -d $(DESTDIR)/usr/lib/udev/rules.d
++ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
+@@ -32,7 +32,7 @@ install:
+ $(INSTALL_PROGRAM) -m 644 mpathconf.8.gz $(DESTDIR)$(mandir)
+
+ uninstall:
+- rm $(DESTDIR)/lib/udev/rules.d/62-multipath.rules
++ rm $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules
+ rm $(DESTDIR)$(bindir)/$(EXEC)
+ rm $(DESTDIR)$(bindir)/mpathconf
+ rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
--- /dev/null
+---
+ kpartx/kpartx.c | 3 +--
+ kpartx/lopart.c | 2 +-
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/kpartx/kpartx.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/kpartx.c
++++ multipath-tools-130222/kpartx/kpartx.c
+@@ -204,7 +204,6 @@ main(int argc, char **argv){
+ char * delim = NULL;
+ char *uuid = NULL;
+ char *mapname = NULL;
+- int loopro = 0;
+ int hotplug = 0;
+ int loopcreated = 0;
+ struct stat buf;
+@@ -315,7 +314,7 @@ main(int argc, char **argv){
+ if (!loopdev) {
+ loopdev = find_unused_loop_device();
+
+- if (set_loop(loopdev, device, 0, &loopro)) {
++ if (set_loop(loopdev, device, 0, &ro)) {
+ fprintf(stderr, "can't set up loop\n");
+ exit (1);
+ }
+Index: multipath-tools-130222/kpartx/lopart.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/lopart.c
++++ multipath-tools-130222/kpartx/lopart.c
+@@ -230,7 +230,7 @@ set_loop (const char *device, const char
+
+ if ((ffd = open (file, mode)) < 0) {
+
+- if (!*loopro && errno == EROFS)
++ if (!*loopro && (errno == EROFS || errno == EACCES))
+ ffd = open (file, mode = O_RDONLY);
+
+ if (ffd < 0) {
--- /dev/null
+---
+ libmultipath/dict.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -2468,16 +2468,12 @@ snprint_def_verbosity (char * buff, int
+ static int
+ snprint_def_max_polling_interval (char * buff, int len, void * data)
+ {
+- if (conf->max_checkint == MAX_CHECKINT(conf->checkint))
+- return 0;
+ return snprintf(buff, len, "%i", conf->max_checkint);
+ }
+
+ static int
+ snprint_reassign_maps (char * buff, int len, void * data)
+ {
+- if (conf->reassign_maps == DEFAULT_REASSIGN_MAPS)
+- return 0;
+ return snprintf(buff, len, "\"%s\"",
+ conf->reassign_maps?"yes":"no");
+ }
--- /dev/null
+---
+ multipath/multipath.rules | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/multipath.rules
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.rules
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -11,7 +11,7 @@ ACTION=="add", ENV{DEVTYPE}!="partition"
+ ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \
+ TEST=="/etc/multipath.conf", \
+ PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \
+- ENV{DM_MULTIPATH_DEVICE_PATH}="1"
++ ENV{DM_MULTIPATH_DEVICE_PATH}="1" ENV{ID_FS_TYPE}="mpath_member"
+
+ ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \
+ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}"
--- /dev/null
+---
+ multipath/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -311,7 +311,7 @@ configure (void)
+ /*
+ * get a path list
+ */
+- if (conf->dev)
++ if (conf->dev && !conf->list)
+ di_flag = DI_WWID;
+
+ if (conf->list > 1)
--- /dev/null
+diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
+index 7b1cb62..4b860bb 100644
+--- a/multipathd/cli_handlers.c
++++ b/multipathd/cli_handlers.c
+@@ -603,7 +603,18 @@ cli_resize(void *v, char **reply, int *len, void *data)
+ }
+
+ pgp = VECTOR_SLOT(mpp->pg, 0);
++
++ if (!pgp){
++ condlog(0, "%s: couldn't get path group. cannot resize",
++ mapname);
++ return 1;
++ }
+ pp = VECTOR_SLOT(pgp->paths, 0);
++
++ if (!pp){
++ condlog(0, "%s: couldn't get path. cannot resize", mapname);
++ return 1;
++ }
+ if (!pp->udev || sysfs_get_size(pp, &size)) {
+ condlog(0, "%s: couldn't get size for sysfs. cannot resize",
+ mapname);
--- /dev/null
+---
+ multipathd/cli_handlers.c | 3 ++-
+ multipathd/main.c | 12 ++++++------
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+Index: multipath-tools-130222/multipathd/cli_handlers.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli_handlers.c
++++ multipath-tools-130222/multipathd/cli_handlers.c
+@@ -632,7 +632,8 @@ cli_resize(void *v, char **reply, int *l
+ return 1;
+
+ dm_lib_release();
+- setup_multipath(vecs, mpp);
++ if (setup_multipath(vecs, mpp) != 0)
++ return 1;
+ sync_map_state(mpp);
+
+ return 0;
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -134,7 +134,6 @@ coalesce_maps(struct vectors *vecs, vect
+ struct multipath * ompp;
+ vector ompv = vecs->mpvec;
+ unsigned int i;
+- int j;
+
+ vector_foreach_slot (ompv, ompp, i) {
+ if (!find_mp_by_wwid(nmpv, ompp->wwid)) {
+@@ -148,16 +147,17 @@ coalesce_maps(struct vectors *vecs, vect
+ /*
+ * may be just because the device is open
+ */
++ if (setup_multipath(vecs, ompp) != 0) {
++ i--;
++ continue;
++ }
+ if (!vector_alloc_slot(nmpv))
+ return 1;
+
+ vector_set_slot(nmpv, ompp);
+- setup_multipath(vecs, ompp);
+
+- if ((j = find_slot(ompv, (void *)ompp)) != -1)
+- vector_del_slot(ompv, j);
+-
+- continue;
++ vector_del_slot(ompv, i);
++ i--;
+ }
+ else {
+ dm_lib_release();
--- /dev/null
+---
+ libmultipath/dict.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -1126,11 +1126,11 @@ hw_failback_handler(vector strvec)
+
+ buff = set_value(strvec);
+
+- if (strlen(buff) == 6 && !strcmp(buff, "\"manual\""))
++ if (strlen(buff) == 6 && !strcmp(buff, "manual"))
+ hwe->pgfailback = -FAILBACK_MANUAL;
+- else if (strlen(buff) == 9 && !strcmp(buff, "\"immediate\""))
++ else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
+ hwe->pgfailback = -FAILBACK_IMMEDIATE;
+- else if (strlen(buff) == 10 && !strcmp(buff, "\"followover\""))
++ else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
+ hwe->pgfailback = -FAILBACK_FOLLOWOVER;
+ else
+ hwe->pgfailback = atoi(buff);
--- /dev/null
+---
+ libmpathpersist/mpath_persist.c | 7 ++++---
+ libmpathpersist/mpath_persist.h | 2 +-
+ libmpathpersist/mpath_pr_ioctl.c | 5 +++--
+ libmultipath/config.c | 9 +++------
+ libmultipath/config.h | 2 +-
+ mpathpersist/Makefile | 2 +-
+ mpathpersist/main.c | 11 +++++++----
+ multipath/Makefile | 2 +-
+ multipath/main.c | 12 ++++++++----
+ multipathd/main.c | 11 ++++++++---
+ 10 files changed, 37 insertions(+), 26 deletions(-)
+
+Index: multipath-tools-130222/libmpathpersist/mpath_persist.c
+===================================================================
+--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c
++++ multipath-tools-130222/libmpathpersist/mpath_persist.c
+@@ -1,4 +1,3 @@
+-#include "mpath_persist.h"
+ #include <libdevmapper.h>
+ #include <defaults.h>
+ #include <sys/stat.h>
+@@ -8,6 +7,7 @@
+ #include <checkers.h>
+ #include <structs.h>
+ #include <structs_vec.h>
++#include <libudev.h>
+
+ #include <prio.h>
+ #include <unistd.h>
+@@ -20,6 +20,7 @@
+ #include <ctype.h>
+ #include <propsel.h>
+
++#include "mpath_persist.h"
+ #include "mpathpr.h"
+ #include "mpath_pr_ioctl.h"
+
+@@ -32,9 +33,9 @@
+
+
+ int
+-mpath_lib_init (void)
++mpath_lib_init (struct udev *udev)
+ {
+- if (load_config(DEFAULT_CONFIGFILE)){
++ if (load_config(DEFAULT_CONFIGFILE, udev)){
+ condlog(0, "Failed to initialize multipath config.");
+ return 1;
+ }
+Index: multipath-tools-130222/libmpathpersist/mpath_persist.h
+===================================================================
+--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.h
++++ multipath-tools-130222/libmpathpersist/mpath_persist.h
+@@ -174,7 +174,7 @@ struct prout_param_descriptor { /* PROU
+ *
+ * RETURNS: 0->Success, 1->Failed.
+ */
+-extern int mpath_lib_init (void );
++extern int mpath_lib_init (struct udev *udev);
+
+
+ /*
+Index: multipath-tools-130222/libmpathpersist/mpath_pr_ioctl.c
+===================================================================
+--- multipath-tools-130222.orig/libmpathpersist/mpath_pr_ioctl.c
++++ multipath-tools-130222/libmpathpersist/mpath_pr_ioctl.c
+@@ -10,8 +10,9 @@
+ #include <string.h>
+ #include <sys/ioctl.h>
+ #include <unistd.h>
+-#include "mpath_pr_ioctl.h"
+-#include <mpath_persist.h>
++#include <libudev.h>
++#include "mpath_pr_ioctl.h"
++#include <mpath_persist.h>
+
+ #include <debug.h>
+
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -467,9 +467,6 @@ free_config (struct config * conf)
+ if (conf->dev)
+ FREE(conf->dev);
+
+- if (conf->udev)
+- udev_unref(conf->udev);
+-
+ if (conf->multipath_dir)
+ FREE(conf->multipath_dir);
+
+@@ -519,12 +516,12 @@ free_config (struct config * conf)
+ }
+
+ int
+-load_config (char * file)
++load_config (char * file, struct udev *udev)
+ {
+ if (!conf)
+ conf = alloc_config();
+
+- if (!conf)
++ if (!conf || !udev)
+ return 1;
+
+ /*
+@@ -533,7 +530,7 @@ load_config (char * file)
+ if (!conf->verbosity)
+ conf->verbosity = DEFAULT_VERBOSITY;
+
+- conf->udev = udev_new();
++ conf->udev = udev;
+ dm_drv_version(conf->version, TGT_MPATH);
+ conf->dev_type = DEV_NONE;
+ conf->minio = DEFAULT_MINIO;
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -159,7 +159,7 @@ void free_mptable (vector mptable);
+
+ int store_hwe (vector hwtable, struct hwentry *);
+
+-int load_config (char * file);
++int load_config (char * file, struct udev * udev);
+ struct config * alloc_config (void);
+ void free_config (struct config * conf);
+
+Index: multipath-tools-130222/mpathpersist/main.c
+===================================================================
+--- multipath-tools-130222.orig/mpathpersist/main.c
++++ multipath-tools-130222/mpathpersist/main.c
+@@ -7,6 +7,7 @@
+ #include <vector.h>
+ #include <structs.h>
+ #include <getopt.h>
++#include <libudev.h>
+ #include <mpath_persist.h>
+ #include "main.h"
+ #include <pthread.h>
+@@ -68,7 +69,8 @@ int main (int argc, char * argv[])
+ int noisy = 0;
+ int num_transport =0;
+ void *resp = NULL;
+- struct transportid * tmp;
++ struct transportid * tmp;
++ struct udev *udev = NULL;
+
+ if (optind == argc)
+ {
+@@ -84,8 +86,8 @@ int main (int argc, char * argv[])
+ exit (1);
+ }
+
+-
+- mpath_lib_init();
++ udev = udev_new();
++ mpath_lib_init(udev);
+ memset(transportids,0,MPATH_MX_TIDS);
+
+ while (1)
+@@ -461,12 +463,13 @@ int main (int argc, char * argv[])
+ if (res < 0)
+ {
+ mpath_lib_exit();
++ udev_unref(udev);
+ return MPATH_PR_FILE_ERROR;
+ }
+
+ out :
+ mpath_lib_exit();
+-
++ udev_unref(udev);
+ return (ret >= 0) ? ret : MPATH_PR_OTHER;
+ }
+
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -27,6 +27,7 @@
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <ctype.h>
++#include <libudev.h>
+
+ #include <checkers.h>
+ #include <prio.h>
+@@ -435,6 +436,7 @@ convert_dev(char *dev)
+ int
+ main (int argc, char *argv[])
+ {
++ struct udev *udev;
+ int arg;
+ extern char *optarg;
+ extern int optind;
+@@ -445,7 +447,9 @@ main (int argc, char *argv[])
+ exit(1);
+ }
+
+- if (load_config(DEFAULT_CONFIGFILE))
++ udev = udev_new();
++
++ if (load_config(DEFAULT_CONFIGFILE, udev))
+ exit(1);
+
+ if (dm_prereq())
+@@ -560,11 +564,11 @@ main (int argc, char *argv[])
+
+ if (init_checkers()) {
+ condlog(0, "failed to initialize checkers");
+- exit(1);
++ goto out;
+ }
+ if (init_prio()) {
+ condlog(0, "failed to initialize prioritizers");
+- exit(1);
++ goto out;
+ }
+ dm_init();
+
+@@ -628,7 +632,7 @@ out:
+ */
+ free_config(conf);
+ conf = NULL;
+-
++ udev_unref(udev);
+ #ifdef _DEBUG_
+ dbg_free_final(NULL);
+ #endif
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -93,6 +93,8 @@ static sem_t exit_sem;
+ */
+ struct vectors * gvecs;
+
++struct udev * udev;
++
+ static int
+ need_switch_pathgroup (struct multipath * mpp, int refresh)
+ {
+@@ -1408,7 +1410,7 @@ reconfigure (struct vectors * vecs)
+ vecs->pathvec = NULL;
+ conf = NULL;
+
+- if (!load_config(DEFAULT_CONFIGFILE)) {
++ if (!load_config(DEFAULT_CONFIGFILE, udev)) {
+ conf->verbosity = old->verbosity;
+ conf->daemon = 1;
+ configure(vecs, 1);
+@@ -1601,6 +1603,8 @@ child (void * param)
+ sem_init(&exit_sem, 0, 0);
+ signal_init();
+
++ udev = udev_new();
++
+ setup_thread_attr(&misc_attr, 64 * 1024, 1);
+ setup_thread_attr(&waiter_attr, 32 * 1024, 1);
+
+@@ -1615,7 +1619,7 @@ child (void * param)
+ condlog(2, "--------start up--------");
+ condlog(2, "read " DEFAULT_CONFIGFILE);
+
+- if (load_config(DEFAULT_CONFIGFILE))
++ if (load_config(DEFAULT_CONFIGFILE, udev))
+ exit(1);
+
+ if (init_checkers()) {
+@@ -1765,7 +1769,8 @@ child (void * param)
+ */
+ free_config(conf);
+ conf = NULL;
+-
++ udev_unref(udev);
++ udev = NULL;
+ #ifdef _DEBUG_
+ dbg_free_final(NULL);
+ #endif
+Index: multipath-tools-130222/mpathpersist/Makefile
+===================================================================
+--- multipath-tools-130222.orig/mpathpersist/Makefile
++++ multipath-tools-130222/mpathpersist/Makefile
+@@ -5,7 +5,7 @@ include ../Makefile.inc
+ OBJS = main.o
+
+ CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
+-LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath
++LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath -ludev
+
+ EXEC = mpathpersist
+
+Index: multipath-tools-130222/multipath/Makefile
+===================================================================
+--- multipath-tools-130222.orig/multipath/Makefile
++++ multipath-tools-130222/multipath/Makefile
+@@ -7,7 +7,7 @@ include ../Makefile.inc
+ OBJS = main.o
+
+ CFLAGS += -fPIC -I$(multipathdir)
+-LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath
++LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev
+
+ EXEC = multipath
+
--- /dev/null
+---
+ libmultipath/discovery.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -799,6 +799,7 @@ path_offline (struct path * pp)
+ condlog(3, "%s: path state = %s", pp->dev, buff);
+
+ if (!strncmp(buff, "offline", 7) ||
++ !strncmp(buff, "quiesce", 7) ||
+ !strncmp(buff, "transport-offline", 17)) {
+ pp->offline = 1;
+ return PATH_DOWN;
--- /dev/null
+---
+ libmultipath/prioritizers/alua.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/prioritizers/alua.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/alua.c
++++ multipath-tools-130222/libmultipath/prioritizers/alua.c
+@@ -108,7 +108,7 @@ int getprio (struct path * pp, char * ar
+ default:
+ rc = 0;
+ }
+- if (priopath)
++ if (priopath && aas != AAS_OPTIMIZED)
+ rc += 80;
+ } else {
+ switch(-rc) {
--- /dev/null
+---
+ libmultipath/discovery.c | 109 +++++++++++++++++++++++++++++++++++++----------
+ libmultipath/sysfs.c | 86 +++++++++++++++++++++++++++++++------
+ libmultipath/sysfs.h | 2
+ 3 files changed, 161 insertions(+), 36 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -162,7 +162,6 @@ declare_sysfs_get_str(cutype);
+ declare_sysfs_get_str(vendor);
+ declare_sysfs_get_str(model);
+ declare_sysfs_get_str(rev);
+-declare_sysfs_get_str(state);
+ declare_sysfs_get_str(dev);
+
+ int
+@@ -315,9 +314,14 @@ static void
+ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
+ {
+ struct udev_device *rport_dev = NULL;
+- char value[11];
++ char value[16];
+ char rport_id[32];
++ int delay_fast_io_fail = 0;
++ int current_dev_loss = 0;
++ int ret;
+
++ if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
++ return;
+ sprintf(rport_id, "rport-%d:%d-%d",
+ pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
+ rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+@@ -330,33 +334,85 @@ sysfs_set_rport_tmo(struct multipath *mp
+ condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
+ pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
+
+- snprintf(value, 11, "%u", mpp->dev_loss);
+- if (mpp->dev_loss &&
+- sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) <= 0) {
+- if ((mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET ||
+- mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
+- && mpp->dev_loss > 600) {
+- condlog(3, "%s: limiting dev_loss_tmo to 600, since "
+- "fast_io_fail is not set", mpp->alias);
+- snprintf(value, 11, "%u", 600);
+- if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
+- value, 11) <= 0)
+- condlog(0, "%s failed to set dev_loss_tmo",
+- mpp->alias);
++ memset(value, 0, 16);
++ if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
++ ret = sysfs_attr_get_value(rport_dev, "dev_loss_tmo",
++ value, 16);
++ if (ret <= 0) {
++ condlog(0, "%s: failed to read dev_loss_tmo value, "
++ "error %d", rport_id, -ret);
+ goto out;
+ }
++ if (sscanf(value, "%u\n", ¤t_dev_loss) != 1) {
++ condlog(0, "%s: Cannot parse dev_loss_tmo "
++ "attribute '%s'", rport_id, value);
++ goto out;
++ }
++ if ((mpp->dev_loss &&
++ mpp->fast_io_fail >= (int)mpp->dev_loss) ||
++ (!mpp->dev_loss &&
++ mpp->fast_io_fail >= (int)current_dev_loss)) {
++ condlog(3, "%s: limiting fast_io_fail_tmo to %d, since "
++ "it must be less than dev_loss_tmo",
++ rport_id, mpp->dev_loss - 1);
++ if (mpp->dev_loss)
++ mpp->fast_io_fail = mpp->dev_loss - 1;
++ else
++ mpp->fast_io_fail = current_dev_loss - 1;
++ }
++ if (mpp->fast_io_fail >= (int)current_dev_loss)
++ delay_fast_io_fail = 1;
++ }
++ if (mpp->dev_loss > 600 &&
++ (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF ||
++ mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)) {
++ condlog(3, "%s: limiting dev_loss_tmo to 600, since "
++ "fast_io_fail is unset or off", rport_id);
++ mpp->dev_loss = 600;
+ }
+- if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET){
++ if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
+ if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
+ sprintf(value, "off");
+ else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
+ sprintf(value, "0");
++ else if (delay_fast_io_fail)
++ snprintf(value, 16, "%u", current_dev_loss - 1);
+ else
+- snprintf(value, 11, "%u", mpp->fast_io_fail);
+- if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
+- value, 11) <= 0) {
+- condlog(0, "%s failed to set fast_io_fail_tmo",
+- mpp->alias);
++ snprintf(value, 16, "%u", mpp->fast_io_fail);
++ ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
++ value, strlen(value));
++ if (ret <= 0) {
++ if (ret == -EBUSY)
++ condlog(3, "%s: rport blocked", rport_id);
++ else
++ condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d",
++ rport_id, value, -ret);
++ goto out;
++ }
++ }
++ if (mpp->dev_loss) {
++ snprintf(value, 16, "%u", mpp->dev_loss);
++ ret = sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
++ value, strlen(value));
++ if (ret <= 0) {
++ if (ret == -EBUSY)
++ condlog(3, "%s: rport blocked", rport_id);
++ else
++ condlog(0, "%s: failed to set dev_loss_tmo to %s, error %d",
++ rport_id, value, -ret);
++ goto out;
++ }
++ }
++ if (delay_fast_io_fail) {
++ snprintf(value, 16, "%u", mpp->fast_io_fail);
++ ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
++ value, strlen(value));
++ if (ret <= 0) {
++ if (ret == -EBUSY)
++ condlog(3, "%s: rport blocked", rport_id);
++ else
++ condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d",
++ rport_id, value, -ret);
+ }
+ }
+ out:
+@@ -394,7 +450,7 @@ sysfs_set_session_tmo(struct multipath *
+ } else {
+ snprintf(value, 11, "%u", mpp->fast_io_fail);
+ if (sysfs_attr_set_value(session_dev, "recovery_tmo",
+- value, 11)) {
++ value, 11) <= 0) {
+ condlog(3, "%s: Failed to set recovery_tmo, "
+ " error %d", pp->dev, errno);
+ }
+@@ -752,6 +808,9 @@ cciss_sysfs_pathinfo (struct path * pp)
+ static int
+ common_sysfs_pathinfo (struct path * pp)
+ {
++ if (!pp)
++ return 1;
++
+ if (!pp->udev) {
+ condlog(4, "%s: udev not initialised", pp->dev);
+ return 1;
+@@ -793,7 +852,8 @@ path_offline (struct path * pp)
+ return PATH_DOWN;
+ }
+
+- if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
++ memset(buff, 0x0, SCSI_STATE_SIZE);
++ if (sysfs_attr_get_value(parent, "state", buff, SCSI_STATE_SIZE) <= 0)
+ return PATH_DOWN;
+
+ condlog(3, "%s: path state = %s", pp->dev, buff);
+@@ -983,6 +1043,9 @@ pathinfo (struct path *pp, vector hwtabl
+ {
+ int path_state;
+
++ if (!pp)
++ return 1;
++
+ condlog(3, "%s: mask = 0x%x", pp->dev, mask);
+
+ /*
+Index: multipath-tools-130222/libmultipath/sysfs.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/sysfs.c
++++ multipath-tools-130222/libmultipath/sysfs.c
+@@ -38,7 +38,12 @@
+ #include "debug.h"
+ #include "devmapper.h"
+
+-ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
++/*
++ * When we modify an attribute value we cannot rely on libudev for now,
++ * as libudev lacks the capability to update an attribute value.
++ * So for modified attributes we need to implement our own function.
++ */
++ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
+ char * value, size_t value_len)
+ {
+ char devpath[PATH_SIZE];
+@@ -54,28 +59,83 @@ ssize_t sysfs_attr_set_value(struct udev
+ condlog(4, "open '%s'", devpath);
+ if (stat(devpath, &statbuf) != 0) {
+ condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
+- return 0;
++ return -errno;
+ }
+
+ /* skip directories */
+- if (S_ISDIR(statbuf.st_mode))
+- return 0;
++ if (S_ISDIR(statbuf.st_mode)) {
++ condlog(4, "%s is a directory", devpath);
++ return -EISDIR;
++ }
+
+ /* skip non-writeable files */
+- if ((statbuf.st_mode & S_IWUSR) == 0)
++ if ((statbuf.st_mode & S_IRUSR) == 0) {
++ condlog(4, "%s is not readable", devpath);
++ return -EPERM;
++ }
++
++ /* read attribute value */
++ fd = open(devpath, O_RDONLY);
++ if (fd < 0) {
++ condlog(4, "attribute '%s' can not be opened: %s",
++ devpath, strerror(errno));
++ return -errno;
++ }
++ size = read(fd, value, value_len);
++ if (size < 0) {
++ condlog(4, "read from %s failed: %s", devpath, strerror(errno));
++ size = -errno;
++ } else if (size == value_len) {
++ condlog(4, "overflow while reading from %s", devpath);
++ size = 0;
++ }
++
++ close(fd);
++ return size;
++}
++
++ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
++ char * value, size_t value_len)
++{
++ char devpath[PATH_SIZE];
++ struct stat statbuf;
++ int fd;
++ ssize_t size = -1;
++
++ if (!dev || !attr_name || !value || !value_len)
+ return 0;
+
++ snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
++ attr_name);
++ condlog(4, "open '%s'", devpath);
++ if (stat(devpath, &statbuf) != 0) {
++ condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
++ return -errno;
++ }
++
++ /* skip directories */
++ if (S_ISDIR(statbuf.st_mode)) {
++ condlog(4, "%s is a directory", devpath);
++ return -EISDIR;
++ }
++
++ /* skip non-writeable files */
++ if ((statbuf.st_mode & S_IWUSR) == 0) {
++ condlog(4, "%s is not writeable", devpath);
++ return -EPERM;
++ }
++
+ /* write attribute value */
+ fd = open(devpath, O_WRONLY);
+ if (fd < 0) {
+ condlog(4, "attribute '%s' can not be opened: %s",
+ devpath, strerror(errno));
+- return 0;
++ return -errno;
+ }
+ size = write(fd, value, value_len);
+ if (size < 0) {
+ condlog(4, "write to %s failed: %s", devpath, strerror(errno));
+- size = 0;
++ size = -errno;
+ } else if (size < value_len) {
+ condlog(4, "tried to write %ld to %s. Wrote %ld",
+ (long)value_len, devpath, (long)size);
+@@ -89,14 +149,14 @@ ssize_t sysfs_attr_set_value(struct udev
+ int
+ sysfs_get_size (struct path *pp, unsigned long long * size)
+ {
+- const char * attr;
++ char attr[255];
+ int r;
+
+- if (!pp->udev)
++ if (!pp->udev || !size)
+ return 1;
+
+- attr = udev_device_get_sysattr_value(pp->udev, "size");
+- if (!attr) {
++ attr[0] = '\0';
++ if (sysfs_attr_get_value(pp->udev, "size", attr, 255) == 0) {
+ condlog(3, "%s: No size attribute in sysfs", pp->dev);
+ return 1;
+ }
+@@ -104,8 +164,8 @@ sysfs_get_size (struct path *pp, unsigne
+ r = sscanf(attr, "%llu\n", size);
+
+ if (r != 1) {
+- condlog(3, "%s: Cannot parse size attribute '%s'",
+- pp->dev, attr);
++ condlog(3, "%s: Cannot parse size attribute", pp->dev);
++ *size = 0;
+ return 1;
+ }
+
+Index: multipath-tools-130222/libmultipath/sysfs.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/sysfs.h
++++ multipath-tools-130222/libmultipath/sysfs.h
+@@ -7,6 +7,8 @@
+
+ ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
+ char * value, size_t value_len);
++ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
++ char * value, size_t value_len);
+ int sysfs_get_size (struct path *pp, unsigned long long * size);
+ int sysfs_check_holders(char * check_devt, char * new_devt);
+ #endif
--- /dev/null
+---
+ libmultipath/dict.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -2562,7 +2562,7 @@ snprint_def_failback (char * buff, int l
+ if (!pgfailback)
+ pgfailback = DEFAULT_FAILBACK;
+
+- switch(conf->pgfailback) {
++ switch(pgfailback) {
+ case FAILBACK_UNDEF:
+ break;
+ case -FAILBACK_MANUAL:
--- /dev/null
+---
+ libmultipath/devmapper.c | 21 +++++++++++++++++----
+ libmultipath/devmapper.h | 2 +-
+ 2 files changed, 18 insertions(+), 5 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -363,7 +363,7 @@ out:
+ }
+
+ extern int
+-dm_get_map(char * name, unsigned long long * size, char * outparams)
++dm_get_map(const char * name, unsigned long long * size, char * outparams)
+ {
+ int r = 1;
+ struct dm_task *dmt;
+@@ -682,7 +682,9 @@ _dm_flush_map (const char * mapname, int
+ extern int
+ dm_suspend_and_flush_map (const char * mapname)
+ {
+- int s;
++ int s = 0, queue_if_no_path = 0;
++ unsigned long long mapsize;
++ char params[PARAMS_SIZE] = {0};
+
+ if (!dm_map_present(mapname))
+ return 0;
+@@ -690,8 +692,17 @@ dm_suspend_and_flush_map (const char * m
+ if (dm_type(mapname, TGT_MPATH) <= 0)
+ return 0; /* nothing to do */
+
+- s = dm_queue_if_no_path((char *)mapname, 0);
+- if (!s)
++ if (!dm_get_map(mapname, &mapsize, params)) {
++ if (strstr(params, "queue_if_no_path"))
++ queue_if_no_path = 1;
++ }
++
++ if (queue_if_no_path)
++ s = dm_queue_if_no_path((char *)mapname, 0);
++ /* Leave queue_if_no_path alone if unset failed */
++ if (s)
++ queue_if_no_path = 0;
++ else
+ s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0);
+
+ if (!dm_flush_map(mapname)) {
+@@ -700,6 +711,8 @@ dm_suspend_and_flush_map (const char * m
+ }
+ condlog(2, "failed to remove multipath map %s", mapname);
+ dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname);
++ if (queue_if_no_path)
++ s = dm_queue_if_no_path((char *)mapname, 1);
+ return 1;
+ }
+
+Index: multipath-tools-130222/libmultipath/devmapper.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.h
++++ multipath-tools-130222/libmultipath/devmapper.h
+@@ -14,7 +14,7 @@ int dm_simplecmd_noflush (int, const cha
+ int dm_addmap_create (struct multipath *mpp, char *params);
+ int dm_addmap_reload (struct multipath *mpp, char *params);
+ int dm_map_present (const char *);
+-int dm_get_map(char *, unsigned long long *, char *);
++int dm_get_map(const char *, unsigned long long *, char *);
+ int dm_get_status(char *, char *);
+ int dm_type(const char *, char *);
+ int _dm_flush_map (const char *, int);
--- /dev/null
+---
+ libmultipath/uevent.c | 17 ++++++++++++-----
+ libmultipath/uevent.h | 4 +++-
+ multipathd/main.c | 8 +++++---
+ 3 files changed, 20 insertions(+), 9 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/uevent.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/uevent.c
++++ multipath-tools-130222/libmultipath/uevent.c
+@@ -47,7 +47,6 @@
+ #include "list.h"
+ #include "uevent.h"
+ #include "vector.h"
+-#include "config.h"
+
+ typedef int (uev_trigger)(struct uevent *, void * trigger_data);
+
+@@ -127,11 +126,14 @@ service_uevq(struct list_head *tmpq)
+
+ static void uevq_stop(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);
++ udev_unref(udev);
+ }
+
+ void
+@@ -399,9 +401,9 @@ exit:
+ return 1;
+ }
+
+-int uevent_listen(void)
++int uevent_listen(struct udev *udev)
+ {
+- int err;
++ int err = 2;
+ struct udev_monitor *monitor = NULL;
+ int fd, socket_flags;
+ int need_failback = 1;
+@@ -411,9 +413,14 @@ int uevent_listen(void)
+ * thereby not getting to empty the socket's receive buffer queue
+ * often enough.
+ */
+- pthread_cleanup_push(uevq_stop, NULL);
++ if (!udev) {
++ condlog(1, "no udev context");
++ return 1;
++ }
++ udev_ref(udev);
++ pthread_cleanup_push(uevq_stop, udev);
+
+- monitor = udev_monitor_new_from_netlink(conf->udev, "udev");
++ monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (!monitor) {
+ condlog(2, "failed to create udev monitor");
+ goto out;
+Index: multipath-tools-130222/libmultipath/uevent.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/uevent.h
++++ multipath-tools-130222/libmultipath/uevent.h
+@@ -13,6 +13,8 @@
+ #define NETLINK_KOBJECT_UEVENT 15
+ #endif
+
++struct udev;
++
+ struct uevent {
+ struct list_head node;
+ struct udev_device *udev;
+@@ -27,7 +29,7 @@ struct uevent {
+ int is_uevent_busy(void);
+ void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);
+
+-int uevent_listen(void);
++int uevent_listen(struct udev *udev);
+ int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data),
+ void * trigger_data);
+ int uevent_get_major(struct uevent *uev);
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -840,7 +840,7 @@ out:
+ static void *
+ ueventloop (void * ap)
+ {
+- if (uevent_listen())
++ if (uevent_listen(udev))
+ condlog(0, "error starting uevent listener");
+
+ return NULL;
+@@ -1593,7 +1593,7 @@ static int
+ child (void * param)
+ {
+ pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr;
+- pthread_attr_t log_attr, misc_attr;
++ pthread_attr_t log_attr, misc_attr, uevent_attr;
+ struct vectors * vecs;
+ struct multipath * mpp;
+ int i;
+@@ -1606,6 +1606,7 @@ child (void * param)
+ udev = udev_new();
+
+ setup_thread_attr(&misc_attr, 64 * 1024, 1);
++ setup_thread_attr(&uevent_attr, 128 * 1024, 1);
+ setup_thread_attr(&waiter_attr, 32 * 1024, 1);
+
+ if (logsink) {
+@@ -1671,10 +1672,11 @@ child (void * param)
+ /*
+ * Start uevent listener early to catch events
+ */
+- if ((rc = pthread_create(&uevent_thr, &misc_attr, ueventloop, vecs))) {
++ if ((rc = pthread_create(&uevent_thr, &uevent_attr, ueventloop, udev))) {
+ condlog(0, "failed to create uevent thread: %d", rc);
+ exit(1);
+ }
++ pthread_attr_destroy(&uevent_attr);
+ if ((rc = pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs))) {
+ condlog(0, "failed to create cli listener: %d", rc);
+ exit(1);
--- /dev/null
+---
+ libmultipath/dict.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -2717,8 +2717,6 @@ snprint_def_log_checker_err (char * buff
+ static int
+ snprint_def_find_multipaths (char * buff, int len, void * data)
+ {
+- if (conf->find_multipaths == DEFAULT_FIND_MULTIPATHS)
+- return 0;
+ if (!conf->find_multipaths)
+ return snprintf(buff, len, "no");
+
--- /dev/null
+---
+ multipathd/main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -1735,8 +1735,9 @@ child (void * param)
+ vecs->pathvec = NULL;
+ unlock(vecs->lock);
+ /* Now all the waitevent threads will start rushing in. */
++ /* freeing vecs isn't worth the races
+ while (vecs->lock.depth > 0) {
+- sleep (1); /* This is weak. */
++ sleep (1);
+ condlog(3, "Have %d wait event checkers threads to de-alloc,"
+ " waiting...", vecs->lock.depth);
+ }
+@@ -1746,7 +1747,7 @@ child (void * param)
+ vecs->lock.mutex = NULL;
+ FREE(vecs);
+ vecs = NULL;
+-
++ */
+ cleanup_checkers();
+ cleanup_prio();
+
--- /dev/null
+---
+ kpartx/dasd.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/kpartx/dasd.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/dasd.c
++++ multipath-tools-130222/kpartx/dasd.c
+@@ -46,6 +46,8 @@ unsigned long long sectors512(unsigned l
+ return sectors * (blocksize >> 9);
+ }
+
++typedef unsigned int __attribute__((__may_alias__)) label_ints_t;
++
+ /*
+ */
+ int
+@@ -169,7 +171,7 @@ read_dasd_pt(int fd, struct slice all, s
+ /*
+ * VM style CMS1 labeled disk
+ */
+- unsigned int *label = (unsigned int *) &vlabel;
++ label_ints_t *label = (label_ints_t *) &vlabel;
+
+ blocksize = label[4];
+ if (label[14] != 0) {
--- /dev/null
+---
+ libmultipath/defaults.h | 3 -
+ libmultipath/file.c | 89 +++++++++++++++++++++++++++++++++++++++++-
+ libmultipath/file.h | 3 +
+ libmultipath/wwids.c | 7 ++-
+ multipath/main.c | 36 +++++++++++++++-
+ multipath/multipath.rules | 26 +++++++++---
+ multipathd/main.c | 4 +
+ multipathd/multipathd.service | 2
+ multipathd/pidfile.c | 3 +
+ 9 files changed, 160 insertions(+), 13 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/defaults.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/defaults.h
++++ multipath-tools-130222/libmultipath/defaults.h
+@@ -24,7 +24,8 @@
+ #define MAX_CHECKINT(a) (a << 2)
+
+ #define MAX_DEV_LOSS_TMO 0x7FFFFFFF
+-#define DEFAULT_PIDFILE "/var/run/multipathd.pid"
++#define DEFAULT_PIDFILE "/var/run/multipathd/multipathd.pid"
++#define DEFAULT_TIMESTAMP_FILE "/var/run/multipathd/timestamp"
+ #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd"
+ #define DEFAULT_CONFIGFILE "/etc/multipath.conf"
+ #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings"
+Index: multipath-tools-130222/libmultipath/file.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/file.c
++++ multipath-tools-130222/libmultipath/file.c
+@@ -12,10 +12,12 @@
+ #include <limits.h>
+ #include <stdio.h>
+ #include <signal.h>
++#include <time.h>
+
+ #include "file.h"
+ #include "debug.h"
+ #include "uxsock.h"
++#include "defaults.h"
+
+
+ /*
+@@ -36,8 +38,8 @@
+ * See the file COPYING included with this distribution for more details.
+ */
+
+-static int
+-ensure_directories_exist(char *str, mode_t dir_mode)
++int
++ensure_directories_exist(const char *str, mode_t dir_mode)
+ {
+ char *pathname;
+ char *end;
+@@ -178,3 +180,86 @@ fail:
+ close(fd);
+ return -1;
+ }
++
++/* If you can't get the timestamp, return equal to just keep using the
++ * existing value.
++ */
++int timestamp_equal(long int chk_timestamp)
++{
++ char buf[4096];
++ FILE *file;
++ long int file_timestamp;
++ int ret = 1;
++
++ if ((file = fopen(DEFAULT_TIMESTAMP_FILE, "r")) == NULL) {
++ if (errno != ENOENT)
++ condlog(2, "Cannot open timestamp file [%s]: %s",
++ DEFAULT_TIMESTAMP_FILE, strerror(errno));
++ goto out;
++ }
++ errno = 0;
++ if (fgets(buf, sizeof(buf), file) == NULL) {
++ if (errno)
++ condlog(2, "Cannot read from timestamp file: %s",
++ strerror(errno));
++ goto out;
++ }
++ if (sscanf(buf, "DM_MULTIPATH_TIMESTAMP=%ld", &file_timestamp) != 1) {
++ if (errno)
++ condlog(0, "Cannot get timestamp: %s", strerror(errno));
++ else
++ condlog(0, "invalid timestamp file [%s]: %s",
++ DEFAULT_TIMESTAMP_FILE, strerror(errno));
++ goto out;
++ }
++ if (file_timestamp != chk_timestamp) {
++ condlog(3, "timestamp has changed");
++ ret = 0;
++ }
++ else
++ condlog(3, "timestamp has not changed");
++out:
++ if (file)
++ fclose(file);
++ return ret;
++}
++
++int update_timestamp(int create)
++{
++ char buf[44];
++ time_t timestamp;
++ int fd;
++ int flags = O_WRONLY;
++ if (create)
++ flags |= O_CREAT;
++ if((fd = open(DEFAULT_TIMESTAMP_FILE, flags,
++ (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
++ if (errno == ENOENT)
++ return 0;
++ condlog(0, "Cannot open timestamp file [%s]: %s",
++ DEFAULT_TIMESTAMP_FILE, strerror(errno));
++ return 1;
++ }
++ if (ftruncate(fd, 0) < 0) {
++ condlog(0, "Cannot truncate timestamp file [%s]: %s",
++ DEFAULT_TIMESTAMP_FILE, strerror(errno));
++ goto fail;
++ }
++ if (time(×tamp) == -1) {
++ condlog(0, "Cannot get current time: %s", strerror(errno));
++ goto fail;
++ }
++ memset(buf, 0, sizeof(buf));
++ snprintf(buf, sizeof(buf)-1, "DM_MULTIPATH_TIMESTAMP=%ld\n",
++ timestamp);
++ if (write(fd, buf, strlen(buf)) != strlen(buf)) {
++ condlog(0, "Cannot write out timestamp to %s: %s",
++ DEFAULT_TIMESTAMP_FILE, strerror(errno));
++ goto fail;
++ }
++ close(fd);
++ return 0;
++fail:
++ close(fd);
++ return 1;
++}
+Index: multipath-tools-130222/libmultipath/file.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/file.h
++++ multipath-tools-130222/libmultipath/file.h
+@@ -7,5 +7,8 @@
+
+ #define FILE_TIMEOUT 30
+ int open_file(char *file, int *can_write, char *header);
++int ensure_directories_exist(const char *str, mode_t dir_mode);
++int update_timestamp(int create);
++int timestamp_equal(long int chk_timestamp);
+
+ #endif /* _FILE_H */
+Index: multipath-tools-130222/multipathd/pidfile.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/pidfile.c
++++ multipath-tools-130222/multipathd/pidfile.c
+@@ -9,6 +9,7 @@
+ #include <fcntl.h> /* for fcntl() */
+
+ #include <debug.h>
++#include <file.h>
+
+ #include "pidfile.h"
+
+@@ -18,6 +19,8 @@ int pidfile_create(const char *pidFile,
+ struct flock lock;
+ int fd, value;
+
++ if (ensure_directories_exist(pidFile, 0700))
++ return 1;
+ if((fd = open(pidFile, O_WRONLY | O_CREAT,
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
+ condlog(0, "Cannot open pidfile [%s], error was [%s]",
+Index: multipath-tools-130222/libmultipath/wwids.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -125,6 +125,7 @@ replace_wwids(vector mp)
+ goto out_file;
+ }
+ ret = 0;
++ update_timestamp(0);
+ out_file:
+ close(fd);
+ out:
+@@ -209,6 +210,8 @@ remove_wwid(char *wwid) {
+ goto out_file;
+ }
+ ret = do_remove_wwid(fd, str);
++ if (!ret)
++ update_timestamp(0);
+
+ out_file:
+ close(fd);
+@@ -294,8 +297,10 @@ remember_wwid(char *wwid)
+ condlog(3, "failed writing wwid %s to wwids file", wwid);
+ return -1;
+ }
+- if (ret == 1)
++ if (ret == 1) {
+ condlog(3, "wrote wwid %s to wwids file", wwid);
++ update_timestamp(0);
++ }
+ else
+ condlog(4, "wwid %s already in wwids file", wwid);
+ return 0;
+Index: multipath-tools-130222/multipath/multipath.rules
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.rules
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -4,18 +4,34 @@ SUBSYSTEM!="block", GOTO="end_mpath"
+
+ IMPORT{cmdline}="nompath"
+ ENV{nompath}=="?*", GOTO="end_mpath"
++ENV{DEVTYPE}=="partition", GOTO="end_mpath"
+ ENV{MPATH_SBIN_PATH}="/sbin"
+ TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin"
++TEST!="/etc/multipath.conf", GOTO="check_kpartx"
+
+-ACTION=="add", ENV{DEVTYPE}!="partition", \
+- ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \
+- TEST=="/etc/multipath.conf", \
++ACTION=="add", ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \
+ PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \
+- ENV{DM_MULTIPATH_DEVICE_PATH}="1" ENV{ID_FS_TYPE}="mpath_member"
++ ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member"
+
+-ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \
++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", \
+ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}"
+
++ACTION!="change", GOTO="update_timestamp"
++IMPORT{db}="DM_MULTIPATH_TIMESTAMP"
++IMPORT{db}="DM_MULTIPATH_DEVICE_PATH"
++# Check if the device is part of a multipath device. the -T option just keeps
++# the old result if the timestamp hasn't changed.
++PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -T $env{DM_MULTIPATH_TIMESTAMP}:$env{DM_MULTIPATH_DEVICE_PATH} -c $env{DEVNAME}", \
++ ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member", \
++ GOTO="update_timestamp"
++
++# If the device isn't part of a multipath device, clear this
++ENV{DM_MULTIPATH_DEVICE_PATH}=""
++
++LABEL="update_timestamp"
++IMPORT{file}="/run/multipathd/timestamp"
++
++LABEL="check_kpartx"
+ KERNEL!="dm-*", GOTO="end_mpath"
+ ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10"
+ ACTION!="change", GOTO="end_mpath"
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -54,6 +54,7 @@
+ #include <pgpolicies.h>
+ #include <uevent.h>
+ #include <log.h>
++#include <file.h>
+
+ #include "main.h"
+ #include "pidfile.h"
+@@ -1417,6 +1418,7 @@ reconfigure (struct vectors * vecs)
+ free_config(old);
+ retval = 0;
+ }
++ update_timestamp(0);
+
+ return retval;
+ }
+@@ -1709,6 +1711,7 @@ child (void * param)
+
+ /* Startup complete, create logfile */
+ pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid);
++ update_timestamp(1);
+ /* Ignore errors, we can live without */
+
+ running_state = DAEMON_RUNNING;
+@@ -1758,6 +1761,7 @@ child (void * param)
+ if (!pid_rc) {
+ condlog(3, "unlink pidfile");
+ unlink(DEFAULT_PIDFILE);
++ unlink(DEFAULT_TIMESTAMP_FILE);
+ }
+
+ condlog(2, "--------shut down-------");
+Index: multipath-tools-130222/multipathd/multipathd.service
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.service
++++ multipath-tools-130222/multipathd/multipathd.service
+@@ -9,7 +9,7 @@ Conflicts=shutdown.target
+
+ [Service]
+ Type=forking
+-PIDFile=/var/run/multipathd.pid
++PIDFile=/var/run/multipathd/multipathd.pid
+ ExecStartPre=/sbin/modprobe dm-multipath
+ ExecStart=/sbin/multipathd
+ ExecReload=/sbin/multipathd reconfigure
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -55,6 +55,7 @@
+ #include <sys/time.h>
+ #include <sys/resource.h>
+ #include <wwids.h>
++#include <file.h>
+ #include "dev_t.h"
+
+ int logsink;
+@@ -84,7 +85,7 @@ usage (char * progname)
+ {
+ fprintf (stderr, VERSION_STRING);
+ fprintf (stderr, "Usage:\n");
+- fprintf (stderr, " %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
++ fprintf (stderr, " %s [-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
+ fprintf (stderr, " %s -t\n", progname);
+@@ -98,6 +99,9 @@ usage (char * progname)
+ " -f flush a multipath device map\n" \
+ " -F flush all multipath device maps\n" \
+ " -c check if a device should be a path in a multipath device\n" \
++ " -T tm:val\n" \
++ " check if tm matches the multipathd timestamp. If so val is\n" \
++ " whether or not the device is a path in a multipath device\n" \
+ " -q allow queue_if_no_path when multipathd is not running\n"\
+ " -d dry run, do not create or update devmaps\n" \
+ " -t dump internal hardware table\n" \
+@@ -441,7 +445,31 @@ main (int argc, char *argv[])
+ extern char *optarg;
+ extern int optind;
+ int r = 1;
+-
++ long int timestamp = -1;
++ int valid = -1;
++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ switch(arg) {
++ case 'T':
++ if (optarg[0] == ':')
++ sscanf(optarg, ":%d", &valid);
++ else
++ sscanf(optarg, "%ld:%d", ×tamp, &valid);
++ if (timestamp_equal(timestamp))
++ return (valid != 1);
++ break;
++ case ':':
++ fprintf(stderr, "Missing option argument\n");
++ usage(argv[0]);
++ exit(1);
++ case '?':
++ fprintf(stderr, "Unknown switch: %s\n", optarg);
++ usage(argv[0]);
++ exit(1);
++ default:
++ break;
++ }
++ }
++ optind = 1;
+ if (getuid() != 0) {
+ fprintf(stderr, "need to be root\n");
+ exit(1);
+@@ -455,7 +483,7 @@ main (int argc, char *argv[])
+ if (dm_prereq())
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtqwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
+ switch(arg) {
+ case 1: printf("optarg : %s\n",optarg);
+ break;
+@@ -517,6 +545,8 @@ main (int argc, char *argv[])
+ case 't':
+ r = dump_config();
+ goto out;
++ case 'T':
++ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
--- /dev/null
+---
+ libmultipath/checkers/rdac.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/checkers/rdac.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c
++++ multipath-tools-130222/libmultipath/checkers/rdac.c
+@@ -222,10 +222,9 @@ libcheck_check (struct checker * c)
+ goto done;
+ }
+
+- /* check if controller is in service mode */
++ /* check if controller is reporting asymmetric access state of unavailable */
+ if ((inq.avtcvp & 0x10) &&
+- ((inq.asym_access_state_cur & 0x0F) == 0x3) &&
+- (inq.vendor_specific_cur == 0x7)) {
++ ((inq.asym_access_state_cur & 0x0F) == 0x3)) {
+ ret = PATH_DOWN;
+ goto done;
+ }
--- /dev/null
+---
+ kpartx/dos.c | 17 ++++++++++-------
+ kpartx/gpt.c | 20 +-------------------
+ kpartx/kpartx.c | 12 ++++++++++++
+ kpartx/kpartx.h | 8 ++++++++
+ 4 files changed, 31 insertions(+), 26 deletions(-)
+
+Index: multipath-tools-130222/kpartx/dos.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/dos.c
++++ multipath-tools-130222/kpartx/dos.c
+@@ -26,7 +26,9 @@ read_extended_partition(int fd, struct p
+ int moretodo = 1;
+ int i, n=0;
+
+- next = start = le32_to_cpu(ep->start_sect);
++ int sector_size_mul = get_sector_size(fd)/512;
++
++ next = start = sector_size_mul * le32_to_cpu(ep->start_sect);
+
+ while (moretodo) {
+ here = next;
+@@ -45,14 +47,14 @@ read_extended_partition(int fd, struct p
+ memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
+ if (is_extended(p.sys_type)) {
+ if (p.nr_sects && !moretodo) {
+- next = start + le32_to_cpu(p.start_sect);
++ next = start + sector_size_mul * le32_to_cpu(p.start_sect);
+ moretodo = 1;
+ }
+ continue;
+ }
+ if (n < ns) {
+- sp[n].start = here + le32_to_cpu(p.start_sect);
+- sp[n].size = le32_to_cpu(p.nr_sects);
++ sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect);
++ sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects);
+ n++;
+ } else {
+ fprintf(stderr,
+@@ -76,6 +78,7 @@ read_dos_pt(int fd, struct slice all, st
+ unsigned long offset = all.start;
+ int i, n=4;
+ unsigned char *bp;
++ int sector_size_mul = get_sector_size(fd)/512;
+
+ bp = (unsigned char *)getblock(fd, offset);
+ if (bp == NULL)
+@@ -89,8 +92,8 @@ read_dos_pt(int fd, struct slice all, st
+ if (is_gpt(p.sys_type))
+ return 0;
+ if (i < ns) {
+- sp[i].start = le32_to_cpu(p.start_sect);
+- sp[i].size = le32_to_cpu(p.nr_sects);
++ sp[i].start = sector_size_mul * le32_to_cpu(p.start_sect);
++ sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects);
+ } else {
+ fprintf(stderr,
+ "dos_partition: too many slices\n");
+@@ -99,7 +102,7 @@ read_dos_pt(int fd, struct slice all, st
+ if (is_extended(p.sys_type)) {
+ n += read_extended_partition(fd, &p, sp+n, ns-n);
+ /* hide the extended partition itself */
+- sp[i].size = 2;
++ sp[i].size = sector_size_mul * 2;
+ }
+ }
+ return n;
+Index: multipath-tools-130222/kpartx/gpt.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/gpt.c
++++ multipath-tools-130222/kpartx/gpt.c
+@@ -38,6 +38,7 @@
+ #include <byteswap.h>
+ #include <linux/fs.h>
+ #include "crc32.h"
++#include "kpartx.h"
+
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ # define __le16_to_cpu(x) (x)
+@@ -116,25 +117,6 @@ is_pmbr_valid(legacy_mbr *mbr)
+
+
+ /************************************************************
+- * get_sector_size
+- * Requires:
+- * - filedes is an open file descriptor, suitable for reading
+- * Modifies: nothing
+- * Returns:
+- * sector size, or 512.
+- ************************************************************/
+-static int
+-get_sector_size(int filedes)
+-{
+- int rc, sector_size = 512;
+-
+- rc = ioctl(filedes, BLKSSZGET, §or_size);
+- if (rc)
+- sector_size = 512;
+- return sector_size;
+-}
+-
+-/************************************************************
+ * _get_num_sectors
+ * Requires:
+ * - filedes is an open file descriptor, suitable for reading
+Index: multipath-tools-130222/kpartx/kpartx.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/kpartx.c
++++ multipath-tools-130222/kpartx/kpartx.c
+@@ -26,6 +26,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <stdint.h>
++#include <sys/ioctl.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <ctype.h>
+@@ -606,3 +607,14 @@ getblock (int fd, unsigned int secnr) {
+
+ return bp->block;
+ }
++
++int
++get_sector_size(int filedes)
++{
++ int rc, sector_size = 512;
++
++ rc = ioctl(filedes, BLKSSZGET, §or_size);
++ if (rc)
++ sector_size = 512;
++ return sector_size;
++}
+Index: multipath-tools-130222/kpartx/kpartx.h
+===================================================================
+--- multipath-tools-130222.orig/kpartx/kpartx.h
++++ multipath-tools-130222/kpartx/kpartx.h
+@@ -2,6 +2,7 @@
+ #define _KPARTX_H
+
+ #include <stdint.h>
++#include <sys/ioctl.h>
+
+ /*
+ * For each partition type there is a routine that takes
+@@ -18,6 +19,13 @@
+ #define safe_sprintf(var, format, args...) \
+ snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
+
++#ifndef BLKSSZGET
++#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
++#endif
++
++int
++get_sector_size(int filedes);
++
+ /*
+ * units: 512 byte sectors
+ */
--- /dev/null
+---
+ multipath/multipath.rules | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/multipath.rules
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.rules
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -13,12 +13,13 @@ ACTION=="add", ENV{DM_MULTIPATH_DEVICE_P
+ PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \
+ ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member"
+
+-ENV{DM_MULTIPATH_DEVICE_PATH}=="1", \
++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DM_MULTIPATH_WIPE_PARTS}="1", \
+ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}"
+
+ ACTION!="change", GOTO="update_timestamp"
+ IMPORT{db}="DM_MULTIPATH_TIMESTAMP"
+ IMPORT{db}="DM_MULTIPATH_DEVICE_PATH"
++IMPORT{db}="DM_MULTIPATH_WIPE_PARTS"
+ # Check if the device is part of a multipath device. the -T option just keeps
+ # the old result if the timestamp hasn't changed.
+ PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -T $env{DM_MULTIPATH_TIMESTAMP}:$env{DM_MULTIPATH_DEVICE_PATH} -c $env{DEVNAME}", \
+@@ -27,8 +28,13 @@ PROGRAM=="$env{MPATH_SBIN_PATH}/multipat
+
+ # If the device isn't part of a multipath device, clear this
+ ENV{DM_MULTIPATH_DEVICE_PATH}=""
++ENV{DM_MULTIPATH_WIPE_PARTS}=""
+
+ LABEL="update_timestamp"
++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DM_MULTIPATH_WIPE_PARTS}!="1", \
++ ENV{DM_MULTIPATH_WIPE_PARTS}="1", \
++ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}"
++
+ IMPORT{file}="/run/multipathd/timestamp"
+
+ LABEL="check_kpartx"
--- /dev/null
+---
+ multipath/multipath.rules | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/multipath.rules
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.rules
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -4,7 +4,8 @@ SUBSYSTEM!="block", GOTO="end_mpath"
+
+ IMPORT{cmdline}="nompath"
+ ENV{nompath}=="?*", GOTO="end_mpath"
+-ENV{DEVTYPE}=="partition", GOTO="end_mpath"
++ENV{DEVTYPE}=="partition", IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH", \
++ GOTO="end_mpath"
+ ENV{MPATH_SBIN_PATH}="/sbin"
+ TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin"
+ TEST!="/etc/multipath.conf", GOTO="check_kpartx"
--- /dev/null
+---
+ libmultipath/checkers/rdac.c | 91 ++++++++++++++++++++++++++++++++++++++-----
+ libmultipath/discovery.c | 2
+ 2 files changed, 81 insertions(+), 12 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/checkers/rdac.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c
++++ multipath-tools-130222/libmultipath/checkers/rdac.c
+@@ -34,6 +34,18 @@
+ #define MSG_RDAC_UP "rdac checker reports path is up"
+ #define MSG_RDAC_DOWN "rdac checker reports path is down"
+ #define MSG_RDAC_GHOST "rdac checker reports path is ghost"
++#define MSG_RDAC_DOWN_TYPE(STR) MSG_RDAC_DOWN": "STR
++
++#define RTPG_UNAVAILABLE 0x3
++#define RTPG_OFFLINE 0xE
++#define RTPG_TRANSITIONING 0xF
++
++#define RTPG_UNAVAIL_NON_RESPONSIVE 0x2
++#define RTPG_UNAVAIL_IN_RESET 0x3
++#define RTPG_UNAVAIL_CFW_DL1 0x4
++#define RTPG_UNAVAIL_CFW_DL2 0x5
++#define RTPG_UNAVAIL_QUIESCED 0x6
++#define RTPG_UNAVAIL_SERVICE_MODE 0x7
+
+ struct control_mode_page {
+ unsigned char header[8];
+@@ -199,22 +211,64 @@ struct volume_access_inq
+ char PQ_PDT;
+ char dontcare0[7];
+ char avtcvp;
+- char dontcare1;
+- char asym_access_state_cur;
++ char vol_ppp;
++ char aas_cur;
+ char vendor_specific_cur;
+- char dontcare2[36];
++ char aas_alt;
++ char vendor_specific_alt;
++ char dontcare1[34];
+ };
+
++const char
++*checker_msg_string(struct volume_access_inq *inq)
++{
++ /* lun not connected */
++ if (((inq->PQ_PDT & 0xE0) == 0x20) || (inq->PQ_PDT & 0x7f))
++ return MSG_RDAC_DOWN_TYPE("lun not connected");
++
++ /* if no tpg data is available, give the generic path down message */
++ if (!(inq->avtcvp & 0x10))
++ return MSG_RDAC_DOWN;
++
++ /* controller is booting up */
++ if (((inq->aas_cur & 0x0F) == RTPG_TRANSITIONING) &&
++ (inq->aas_alt & 0x0F) != RTPG_TRANSITIONING)
++ return MSG_RDAC_DOWN_TYPE("ctlr is in startup sequence");
++
++ /* if not unavailable, give generic message */
++ if ((inq->aas_cur & 0x0F) != RTPG_UNAVAILABLE)
++ return MSG_RDAC_DOWN;
++
++ /* target port group unavailable */
++ switch (inq->vendor_specific_cur) {
++ case RTPG_UNAVAIL_NON_RESPONSIVE:
++ return MSG_RDAC_DOWN_TYPE("non-responsive to queries");
++ case RTPG_UNAVAIL_IN_RESET:
++ return MSG_RDAC_DOWN_TYPE("ctlr held in reset");
++ case RTPG_UNAVAIL_CFW_DL1:
++ case RTPG_UNAVAIL_CFW_DL2:
++ return MSG_RDAC_DOWN_TYPE("ctlr firmware downloading");
++ case RTPG_UNAVAIL_QUIESCED:
++ return MSG_RDAC_DOWN_TYPE("ctlr quiesced by admin request");
++ case RTPG_UNAVAIL_SERVICE_MODE:
++ return MSG_RDAC_DOWN_TYPE("ctlr is in service mode");
++ default:
++ return MSG_RDAC_DOWN_TYPE("ctlr is unavailable");
++ }
++}
++
+ extern int
+ libcheck_check (struct checker * c)
+ {
+ struct volume_access_inq inq;
+- int ret;
++ int ret, inqfail;
+
++ inqfail = 0;
+ memset(&inq, 0, sizeof(struct volume_access_inq));
+ if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq),
+ c->timeout)) {
+ ret = PATH_DOWN;
++ inqfail = 1;
+ goto done;
+ } else if (((inq.PQ_PDT & 0xE0) == 0x20) || (inq.PQ_PDT & 0x7f)) {
+ /* LUN not connected*/
+@@ -222,11 +276,27 @@ libcheck_check (struct checker * c)
+ goto done;
+ }
+
+- /* check if controller is reporting asymmetric access state of unavailable */
+- if ((inq.avtcvp & 0x10) &&
+- ((inq.asym_access_state_cur & 0x0F) == 0x3)) {
+- ret = PATH_DOWN;
+- goto done;
++ /* If TPGDE bit set, evaluate TPG information */
++ if ((inq.avtcvp & 0x10)) {
++ switch (inq.aas_cur & 0x0F) {
++ /* Never use the path if it reports unavailable */
++ case RTPG_UNAVAILABLE:
++ ret = PATH_DOWN;
++ goto done;
++ /*
++ * If both controllers report transitioning, it
++ * means mode select or STPG is being processed.
++ *
++ * If this controller alone is transitioning, it's
++ * booting and we shouldn't use it yet.
++ */
++ case RTPG_TRANSITIONING:
++ if ((inq.aas_alt & 0xF) != RTPG_TRANSITIONING) {
++ ret = PATH_DOWN;
++ goto done;
++ }
++ break;
++ }
+ }
+
+ /* If owner set or ioship mode is enabled return PATH_UP always */
+@@ -238,7 +308,8 @@ libcheck_check (struct checker * c)
+ done:
+ switch (ret) {
+ case PATH_DOWN:
+- MSG(c, MSG_RDAC_DOWN);
++ MSG(c, (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") :
++ checker_msg_string(&inq));
+ break;
+ case PATH_UP:
+ MSG(c, MSG_RDAC_UP);
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -1116,8 +1116,6 @@ pathinfo (struct path *pp, vector hwtabl
+ if (!strlen(pp->wwid))
+ get_uid(pp);
+ get_prio(pp);
+- } else {
+- pp->priority = PRIO_UNDEF;
+ }
+ }
+
--- /dev/null
+---
+ libmultipath/blacklist.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/blacklist.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/blacklist.c
++++ multipath-tools-130222/libmultipath/blacklist.c
+@@ -163,7 +163,7 @@ setup_default_blist (struct config * con
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
+ return 1;
+
+- str = STRDUP("^hd[a-z]");
++ str = STRDUP("^(td|hd)[a-z]");
+ if (!str)
+ return 1;
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
--- /dev/null
+---
+ libmultipath/util.c | 22 ++++++++++++++++++++++
+ libmultipath/util.h | 1 +
+ multipath/main.c | 23 +----------------------
+ multipathd/cli_handlers.c | 18 ++++++++++++++++++
+ 4 files changed, 42 insertions(+), 22 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/util.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/util.c
++++ multipath-tools-130222/libmultipath/util.c
+@@ -236,6 +236,28 @@ skip_proc:
+ return 0;
+ }
+
++/* This function returns a pointer inside of the supplied pathname string.
++ * If is_path_device is true, it may also modify the supplied string */
++char *convert_dev(char *name, int is_path_device)
++{
++ char *ptr;
++
++ if (!name)
++ return NULL;
++ if (is_path_device) {
++ ptr = strstr(name, "cciss/");
++ if (ptr) {
++ ptr += 5;
++ *ptr = '!';
++ }
++ }
++ if (!strncmp(name, "/dev/", 5) && strlen(name) > 5)
++ ptr = name + 5;
++ else
++ ptr = name;
++ return ptr;
++}
++
+ dev_t parse_devt(const char *dev_t)
+ {
+ int maj, min;
+Index: multipath-tools-130222/libmultipath/util.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/util.h
++++ multipath-tools-130222/libmultipath/util.h
+@@ -10,6 +10,7 @@ size_t strlcat(char *dst, const char *sr
+ void remove_trailing_chars(char *path, char c);
+ int devt2devname (char *, int, char *);
+ dev_t parse_devt(const char *dev_t);
++char *convert_dev(char *dev, int is_path_device);
+
+ #define safe_sprintf(var, format, args...) \
+ snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -254,16 +254,7 @@ configure (void)
+ vecs.pathvec = pathvec;
+ vecs.mpvec = curmp;
+
+- /*
+- * dev is "/dev/" . "sysfs block dev"
+- */
+- if (conf->dev) {
+- if (!strncmp(conf->dev, "/dev/", 5) &&
+- strlen(conf->dev) > 5)
+- dev = conf->dev + 5;
+- else
+- dev = conf->dev;
+- }
++ dev = convert_dev(conf->dev, (conf->dev_type == DEV_DEVNODE));
+
+ /*
+ * if we have a blacklisted device parameter, exit early
+@@ -427,16 +418,6 @@ get_dev_type(char *dev) {
+ return DEV_DEVMAP;
+ }
+
+-static void
+-convert_dev(char *dev)
+-{
+- char *ptr = strstr(dev, "cciss/");
+- if (ptr) {
+- ptr += 5;
+- *ptr = '!';
+- }
+-}
+-
+ int
+ main (int argc, char *argv[])
+ {
+@@ -577,8 +558,6 @@ main (int argc, char *argv[])
+
+ strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
+ conf->dev_type = get_dev_type(conf->dev);
+- if (conf->dev_type == DEV_DEVNODE)
+- convert_dev(conf->dev);
+ }
+ conf->daemon = 0;
+
+Index: multipath-tools-130222/multipathd/cli_handlers.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli_handlers.c
++++ multipath-tools-130222/multipathd/cli_handlers.c
+@@ -235,6 +235,7 @@ cli_list_map_topology (void * v, char **
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
++ param = convert_dev(param, 0);
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+@@ -416,6 +417,7 @@ cli_add_path (void * v, char ** reply, i
+ struct path *pp;
+ int r;
+
++ param = convert_dev(param, 1);
+ condlog(2, "%s: add path (operator)", param);
+
+ if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
+@@ -459,6 +461,7 @@ cli_del_path (void * v, char ** reply, i
+ char * param = get_keyparam(v, PATH);
+ struct path *pp;
+
++ param = convert_dev(param, 1);
+ condlog(2, "%s: remove path (operator)", param);
+ pp = find_path_by_dev(vecs->pathvec, param);
+ if (!pp) {
+@@ -478,6 +481,7 @@ cli_add_map (void * v, char ** reply, in
+ char *alias;
+ int rc;
+
++ param = convert_dev(param, 0);
+ condlog(2, "%s: add map (operator)", param);
+
+ if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param) > 0) {
+@@ -518,6 +522,7 @@ cli_del_map (void * v, char ** reply, in
+ char *alias;
+ int rc;
+
++ param = convert_dev(param, 0);
+ condlog(2, "%s: remove map (operator)", param);
+ minor = dm_get_minor(param);
+ if (minor < 0) {
+@@ -549,6 +554,7 @@ cli_reload(void *v, char **reply, int *l
+ struct multipath *mpp;
+ int minor;
+
++ mapname = convert_dev(mapname, 0);
+ condlog(2, "%s: reload map (operator)", mapname);
+ if (sscanf(mapname, "dm-%d", &minor) == 1)
+ mpp = find_mp_by_minor(vecs->mpvec, minor);
+@@ -591,6 +597,7 @@ cli_resize(void *v, char **reply, int *l
+ struct pathgroup *pgp;
+ struct path *pp;
+
++ mapname = convert_dev(mapname, 0);
+ condlog(2, "%s: resize map (operator)", mapname);
+ if (sscanf(mapname, "dm-%d", &minor) == 1)
+ mpp = find_mp_by_minor(vecs->mpvec, minor);
+@@ -665,6 +672,7 @@ cli_restore_queueing(void *v, char **rep
+ struct multipath *mpp;
+ int minor;
+
++ mapname = convert_dev(mapname, 0);
+ condlog(2, "%s: restore map queueing (operator)", mapname);
+ if (sscanf(mapname, "dm-%d", &minor) == 1)
+ mpp = find_mp_by_minor(vecs->mpvec, minor);
+@@ -716,6 +724,7 @@ cli_disable_queueing(void *v, char **rep
+ struct multipath *mpp;
+ int minor;
+
++ mapname = convert_dev(mapname, 0);
+ condlog(2, "%s: disable map queueing (operator)", mapname);
+ if (sscanf(mapname, "dm-%d", &minor) == 1)
+ mpp = find_mp_by_minor(vecs->mpvec, minor);
+@@ -753,6 +762,7 @@ cli_switch_group(void * v, char ** reply
+ char * mapname = get_keyparam(v, MAP);
+ int groupnum = atoi(get_keyparam(v, GROUP));
+
++ mapname = convert_dev(mapname, 0);
+ condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
+
+ return dm_switchgroup(mapname, groupnum);
+@@ -775,6 +785,7 @@ cli_suspend(void * v, char ** reply, int
+ char * param = get_keyparam(v, MAP);
+ int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param);
+
++ param = convert_dev(param, 0);
+ condlog(2, "%s: suspend (operator)", param);
+
+ if (!r) /* error */
+@@ -796,6 +807,7 @@ cli_resume(void * v, char ** reply, int
+ char * param = get_keyparam(v, MAP);
+ int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param);
+
++ param = convert_dev(param, 0);
+ condlog(2, "%s: resume (operator)", param);
+
+ if (!r) /* error */
+@@ -817,6 +829,7 @@ cli_reinstate(void * v, char ** reply, i
+ char * param = get_keyparam(v, PATH);
+ struct path * pp;
+
++ param = convert_dev(param, 1);
+ pp = find_path_by_dev(vecs->pathvec, param);
+
+ if (!pp)
+@@ -837,6 +850,7 @@ cli_reassign (void * v, char ** reply, i
+ {
+ char * param = get_keyparam(v, MAP);
+
++ param = convert_dev(param, 0);
+ condlog(3, "%s: reset devices (operator)", param);
+
+ dm_reassign(param);
+@@ -851,6 +865,7 @@ cli_fail(void * v, char ** reply, int *
+ struct path * pp;
+ int r;
+
++ param = convert_dev(param, 1);
+ pp = find_path_by_dev(vecs->pathvec, param);
+
+ if (!pp)
+@@ -962,6 +977,7 @@ cli_getprstatus (void * v, char ** reply
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
++ param = convert_dev(param, 0);
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+@@ -991,6 +1007,7 @@ cli_setprstatus(void * v, char ** reply,
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
++ param = convert_dev(param, 0);
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+@@ -1013,6 +1030,7 @@ cli_unsetprstatus(void * v, char ** repl
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
++ param = convert_dev(param, 0);
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
--- /dev/null
+---
+ kpartx/lopart.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/kpartx/lopart.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/lopart.c
++++ multipath-tools-130222/kpartx/lopart.c
+@@ -32,6 +32,10 @@
+ #include "lopart.h"
+ #include "xstrncpy.h"
+
++#ifndef LOOP_CTL_GET_FREE
++#define LOOP_CTL_GET_FREE 0x4C82
++#endif
++
+ #if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
+ && !defined (__s390x__)
+ #define int2ptr(x) ((void *) ((int) x))
+@@ -140,14 +144,24 @@ find_unused_loop_device (void)
+
+ char dev[20];
+ char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
+- int i, j, fd, somedev = 0, someloop = 0, loop_known = 0;
++ int i, j, fd, first = 0, somedev = 0, someloop = 0, loop_known = 0;
+ struct stat statbuf;
+ struct loop_info loopinfo;
+ FILE *procdev;
+
++ if (stat("/dev/loop-control", &statbuf) == 0 &&
++ S_ISCHR(statbuf.st_mode)) {
++ fd = open("/dev/loop-control", O_RDWR);
++ if (fd >= 0) {
++ first = ioctl(fd, LOOP_CTL_GET_FREE);
++ close(fd);
++ }
++ if (first < 0)
++ first = 0;
++ }
+ for (j = 0; j < SIZE(loop_formats); j++) {
+
+- for(i = 0; i < 256; i++) {
++ for(i = first; i < 256; i++) {
+ sprintf(dev, loop_formats[j], i);
+
+ if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
--- /dev/null
+---
+ Makefile.inc | 2 +-
+ libmultipath/checkers/rdac.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/Makefile.inc
+===================================================================
+--- multipath-tools-130222.orig/Makefile.inc
++++ multipath-tools-130222/Makefile.inc
+@@ -39,7 +39,7 @@ GZIP = /bin/gzip -9 -c
+ INSTALL_PROGRAM = install
+
+ ifndef RPM_OPT_FLAGS
+- RPM_OPT_FLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
++ RPM_OPT_FLAGS = -O2 -g -pipe -Wformat-security -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4
+ endif
+
+ LDFLAGS += -Wl,-z,relro
+Index: multipath-tools-130222/libmultipath/checkers/rdac.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c
++++ multipath-tools-130222/libmultipath/checkers/rdac.c
+@@ -308,8 +308,8 @@ libcheck_check (struct checker * c)
+ done:
+ switch (ret) {
+ case PATH_DOWN:
+- MSG(c, (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") :
+- checker_msg_string(&inq));
++ MSG(c, "%s", (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") :
++ checker_msg_string(&inq));
+ break;
+ case PATH_UP:
+ MSG(c, MSG_RDAC_UP);
--- /dev/null
+---
+ multipath/11-dm-mpath.rules | 34 ++++++++++++++++++++++++++++++++++
+ multipath/Makefile | 2 ++
+ 2 files changed, 36 insertions(+)
+
+Index: multipath-tools-130222/multipath/11-dm-mpath.rules
+===================================================================
+--- /dev/null
++++ multipath-tools-130222/multipath/11-dm-mpath.rules
+@@ -0,0 +1,34 @@
++ACTION!="add|change", GOTO="mpath_end"
++ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="mpath_end"
++ENV{DM_UUID}!="mpath-?*", GOTO="mpath_end"
++
++# Do not initiate scanning if no path is available,
++# otherwise there would be a hang or IO error on access.
++# We'd like to avoid this, especially within udev processing.
++ENV{DM_NR_VALID_PATHS}!="?*", IMPORT{db}="DM_NR_VALID_PATHS"
++ENV{DM_NR_VALID_PATHS}=="0", ENV{DM_NOSCAN}="1"
++
++# Also skip all foreign rules if no path is available.
++# Remember the original value of DM_DISABLE_OTHER_RULES_FLAG
++# and restore it back once we have at least one path available.
++IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD"
++ENV{DM_ACTION}=="PATH_FAILED",\
++ ENV{DM_NR_VALID_PATHS}=="0",\
++ ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}=="",\
++ ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}",\
++ ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
++ENV{DM_ACTION}=="PATH_REINSTATED",\
++ ENV{DM_NR_VALID_PATHS}=="1",\
++ ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}",\
++ ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="",\
++ ENV{DM_ACTIVATION}="1"
++
++# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem.
++# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its
++# paths are lost/recovered. For any stack above the mpath device, this is not
++# something that should be reacted upon since it would be useless extra work.
++# It's exactly mpath's job to provide *seamless* device access to any of the
++# paths that are available underneath.
++ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0"
++
++LABEL="mpath_end"
+Index: multipath-tools-130222/multipath/Makefile
+===================================================================
+--- multipath-tools-130222.orig/multipath/Makefile
++++ multipath-tools-130222/multipath/Makefile
+@@ -25,6 +25,7 @@ install:
+ $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/
+ $(INSTALL_PROGRAM) -d $(DESTDIR)/usr/lib/udev/rules.d
+ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules
++ $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)/usr/lib/udev/rules.d/11-dm-mpath.rules
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
+@@ -33,6 +34,7 @@ install:
+
+ uninstall:
+ rm $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules
++ rm $(DESTDIR)/usr/lib/udev/rules.d/11-dm-mpath.rules
+ rm $(DESTDIR)$(bindir)/$(EXEC)
+ rm $(DESTDIR)$(bindir)/mpathconf
+ rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
--- /dev/null
+---
+ kpartx/devmapper.c | 4 ++--
+ kpartx/devmapper.h | 8 +++++++-
+ kpartx/kpartx.c | 6 +++---
+ libmultipath/configure.c | 4 ++--
+ libmultipath/devmapper.c | 26 ++++++++++++++------------
+ libmultipath/devmapper.h | 10 ++++++++--
+ multipathd/cli_handlers.c | 4 ++--
+ 7 files changed, 38 insertions(+), 24 deletions(-)
+
+Index: multipath-tools-130222/kpartx/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/devmapper.c
++++ multipath-tools-130222/kpartx/devmapper.c
+@@ -60,7 +60,7 @@ dm_prereq (char * str, int x, int y, int
+ }
+
+ extern int
+-dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie) {
++dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie, uint16_t udev_flags) {
+ int r = 0;
+ int udev_wait_flag = (task == DM_DEVICE_RESUME ||
+ task == DM_DEVICE_REMOVE);
+@@ -78,7 +78,7 @@ dm_simplecmd (int task, const char *name
+ if (no_flush)
+ dm_task_no_flush(dmt);
+
+- if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, (udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK))
++ if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, ((udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK) | udev_flags))
+ goto out;
+ r = dm_task_run(dmt);
+
+Index: multipath-tools-130222/kpartx/devmapper.h
+===================================================================
+--- multipath-tools-130222.orig/kpartx/devmapper.h
++++ multipath-tools-130222/kpartx/devmapper.h
+@@ -2,10 +2,16 @@
+ #define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
+ #define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
+
++#ifdef DM_SUBSYSTEM_UDEV_FLAG0
++#define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0
++#else
++#define MPATH_UDEV_RELOAD_FLAG 0
++#endif
++
+ extern int udev_sync;
+
+ int dm_prereq (char *, int, int, int);
+-int dm_simplecmd (int, const char *, int, uint32_t *);
++int dm_simplecmd (int, const char *, int, uint32_t *, uint16_t);
+ int dm_addmap (int, const char *, const char *, const char *, uint64_t,
+ int, const char *, int, mode_t, uid_t, gid_t, uint32_t *);
+ int dm_map_present (char *);
+Index: multipath-tools-130222/kpartx/kpartx.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/kpartx.c
++++ multipath-tools-130222/kpartx/kpartx.c
+@@ -421,7 +421,7 @@ main(int argc, char **argv){
+ continue;
+
+ if (!dm_simplecmd(DM_DEVICE_REMOVE, partname,
+- 0, &cookie)) {
++ 0, &cookie, 0)) {
+ r++;
+ continue;
+ }
+@@ -473,7 +473,7 @@ main(int argc, char **argv){
+ }
+ if (op == DM_DEVICE_RELOAD &&
+ !dm_simplecmd(DM_DEVICE_RESUME, partname,
+- 1, &cookie)) {
++ 1, &cookie, MPATH_UDEV_RELOAD_FLAG)) {
+ fprintf(stderr, "resume failed on %s\n",
+ partname);
+ r++;
+@@ -505,7 +505,7 @@ main(int argc, char **argv){
+ continue;
+
+ if (!dm_simplecmd(DM_DEVICE_REMOVE,
+- partname, 1, &cookie)) {
++ partname, 1, &cookie, 0)) {
+ r++;
+ continue;
+ }
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -390,13 +390,13 @@ domap (struct multipath * mpp, char * pa
+ case ACT_RELOAD:
+ r = dm_addmap_reload(mpp, params);
+ if (r)
+- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias);
++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, MPATH_UDEV_RELOAD_FLAG);
+ break;
+
+ case ACT_RESIZE:
+ r = dm_addmap_reload(mpp, params);
+ if (r)
+- r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1);
++ r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1, 0);
+ break;
+
+ case ACT_RENAME:
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -103,7 +103,9 @@ dm_lib_prereq (void)
+ {
+ char version[64];
+ int v[3];
+-#ifdef LIBDM_API_COOKIE
++#if defined(DM_SUBSYSTEM_UDEV_FLAG0)
++ int minv[3] = {1, 2, 82};
++#elif defined(LIBDM_API_COOKIE)
+ int minv[3] = {1, 2, 38};
+ #else
+ int minv[3] = {1, 2, 8};
+@@ -200,7 +202,7 @@ dm_prereq (void)
+ }
+
+ static int
+-dm_simplecmd (int task, const char *name, int no_flush, int need_sync) {
++dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags) {
+ int r = 0;
+ int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME ||
+ task == DM_DEVICE_REMOVE));
+@@ -219,7 +221,7 @@ dm_simplecmd (int task, const char *name
+ dm_task_no_flush(dmt); /* for DM_DEVICE_SUSPEND/RESUME */
+ #endif
+
+- if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
++ if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags))
+ goto out;
+ r = dm_task_run (dmt);
+
+@@ -229,13 +231,13 @@ dm_simplecmd (int task, const char *name
+ }
+
+ extern int
+-dm_simplecmd_flush (int task, const char *name, int needsync) {
+- return dm_simplecmd(task, name, 0, needsync);
++dm_simplecmd_flush (int task, const char *name, int needsync, uint16_t udev_flags) {
++ return dm_simplecmd(task, name, 0, needsync, udev_flags);
+ }
+
+ extern int
+-dm_simplecmd_noflush (int task, const char *name) {
+- return dm_simplecmd(task, name, 1, 1);
++dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags) {
++ return dm_simplecmd(task, name, 1, 1, udev_flags);
+ }
+
+ extern int
+@@ -670,7 +672,7 @@ _dm_flush_map (const char * mapname, int
+ return 1;
+ }
+
+- r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync);
++ r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync, 0);
+
+ if (r) {
+ condlog(4, "multipath map %s removed", mapname);
+@@ -703,14 +705,14 @@ dm_suspend_and_flush_map (const char * m
+ if (s)
+ queue_if_no_path = 0;
+ else
+- s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0);
++ s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0, 0);
+
+ if (!dm_flush_map(mapname)) {
+ condlog(4, "multipath map %s removed", mapname);
+ return 0;
+ }
+ condlog(2, "failed to remove multipath map %s", mapname);
+- dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname);
++ dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, 0);
+ if (queue_if_no_path)
+ s = dm_queue_if_no_path((char *)mapname, 1);
+ return 1;
+@@ -1077,7 +1079,7 @@ dm_remove_partmaps (const char * mapname
+ condlog(4, "partition map %s removed",
+ names->name);
+ dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name,
+- need_sync);
++ need_sync, 0);
+ }
+
+ next = names->next;
+@@ -1305,7 +1307,7 @@ int dm_reassign_table(const char *name,
+ condlog(3, "%s: failed to reassign targets", name);
+ goto out_reload;
+ }
+- dm_simplecmd_noflush(DM_DEVICE_RESUME, name);
++ dm_simplecmd_noflush(DM_DEVICE_RESUME, name, MPATH_UDEV_RELOAD_FLAG);
+ }
+ r = 1;
+
+Index: multipath-tools-130222/libmultipath/devmapper.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.h
++++ multipath-tools-130222/libmultipath/devmapper.h
+@@ -6,11 +6,17 @@
+ #define TGT_MPATH "multipath"
+ #define TGT_PART "linear"
+
++#ifdef DM_SUBSYSTEM_UDEV_FLAG0
++#define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0
++#else
++#define MPATH_UDEV_RELOAD_FLAG 0
++#endif
++
+ void dm_init(void);
+ int dm_prereq (void);
+ int dm_drv_version (unsigned int * version, char * str);
+-int dm_simplecmd_flush (int, const char *, int);
+-int dm_simplecmd_noflush (int, const char *);
++int dm_simplecmd_flush (int, const char *, int, uint16_t);
++int dm_simplecmd_noflush (int, const char *, uint16_t);
+ int dm_addmap_create (struct multipath *mpp, char *params);
+ int dm_addmap_reload (struct multipath *mpp, char *params);
+ int dm_map_present (const char *);
+Index: multipath-tools-130222/multipathd/cli_handlers.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/cli_handlers.c
++++ multipath-tools-130222/multipathd/cli_handlers.c
+@@ -783,7 +783,7 @@ cli_suspend(void * v, char ** reply, int
+ {
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+- int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param);
++ int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0);
+
+ param = convert_dev(param, 0);
+ condlog(2, "%s: suspend (operator)", param);
+@@ -805,7 +805,7 @@ cli_resume(void * v, char ** reply, int
+ {
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+- int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param);
++ int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0);
+
+ param = convert_dev(param, 0);
+ condlog(2, "%s: resume (operator)", param);
--- /dev/null
+---
+ libmultipath/config.c | 10 ++++++++--
+ libmultipath/config.h | 1 +
+ libmultipath/dict.c | 28 ++++++++++++++++++++++++++++
+ multipath/multipath.conf.5 | 11 +++++++++++
+ 4 files changed, 48 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -431,11 +431,16 @@ restart:
+ break;
+ j = n;
+ vector_foreach_slot_after(hw, hwe2, j) {
+- if (hwe_regmatch(hwe1, hwe2))
++ if (conf->hw_strmatch) {
++ if (hwe_strmatch(hwe2, hwe1))
++ continue;
++ }
++ else if (hwe_regmatch(hwe1, hwe2))
+ continue;
+ /* dup */
+ merge_hwe(hwe2, hwe1);
+- if (hwe_strmatch(hwe2, hwe1) == 0) {
++ if (conf->hw_strmatch ||
++ hwe_strmatch(hwe2, hwe1) == 0) {
+ vector_del_slot(hw, i);
+ free_hwe(hwe1);
+ n -= 1;
+@@ -550,6 +555,7 @@ load_config (char * file, struct udev *u
+ conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
+ conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
+ conf->detect_prio = DEFAULT_DETECT_PRIO;
++ conf->hw_strmatch = 0;
+
+ /*
+ * preload default hwtable
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -107,6 +107,7 @@ struct config {
+ int log_checker_err;
+ int allow_queueing;
+ int find_multipaths;
++ int hw_strmatch;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -693,6 +693,25 @@ def_detect_prio_handler(vector strvec)
+ return 0;
+ }
+
++static int
++def_hw_strmatch_handler(vector strvec)
++{
++ char *buff;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) ||
++ !strncmp(buff, "1", 1))
++ conf->hw_strmatch = 1;
++ else
++ conf->hw_strmatch = 0;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * blacklist block handlers
+ */
+@@ -2795,6 +2814,14 @@ snprint_def_detect_prio(char * buff, int
+ }
+
+ static int
++snprint_def_hw_strmatch(char * buff, int len, void * data)
++{
++ if (conf->hw_strmatch)
++ return snprintf(buff, len, "yes");
++ return snprintf(buff, len, "no");
++}
++
++static int
+ snprint_ble_simple (char * buff, int len, void * data)
+ {
+ struct blentry * ble = (struct blentry *)data;
+@@ -2861,6 +2888,7 @@ init_keywords(void)
+ install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths);
+ install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler);
+ install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
++ install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch);
+ __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);
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -400,6 +400,17 @@ will automatically use the
+ .I alua
+ prioritizer. If not, the prioritizer will be selected as usual. Default is
+ .I no
++.TP
++.B hw_str_match
++If set to
++.I yes
++, the vendor, product, and revision parameters of user device configs will be
++string matched against the built-in device configs to determine if they should
++modify an existing config, or create a new one. If set to
++.I no
++, the user device configs will be regular expression matched against the
++built-in configs instead. Default is
++.I no
+ .
+ .SH "blacklist section"
+ The
--- /dev/null
+---
+ multipath/mpathconf.8 | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/mpathconf.8
+===================================================================
+--- multipath-tools-130222.orig/multipath/mpathconf.8
++++ multipath-tools-130222/multipath/mpathconf.8
+@@ -86,7 +86,7 @@ If set to \fBy\fP, this runs
+ .B service multipathd start
+ to start the multipathd daemon on \fB--enable\fP,
+ .B service multipathd stop
+-to start the multipathd daemon on \fB--disable\fP, and
++to stop the multipathd daemon on \fB--disable\fP, and
+ .B service multipathd reload
+ to reconfigure multipathd on \fB--user_frindly_names\fP and
+ \fB--find_multipaths\fP.
--- /dev/null
+---
+ multipath/main.c | 19 ++++++++++++++++---
+ multipath/multipath.8 | 5 ++++-
+ 2 files changed, 20 insertions(+), 4 deletions(-)
+
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -85,7 +85,7 @@ usage (char * progname)
+ {
+ fprintf (stderr, VERSION_STRING);
+ fprintf (stderr, "Usage:\n");
+- fprintf (stderr, " %s [-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
++ fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
+ fprintf (stderr, " %s -t\n", progname);
+@@ -98,6 +98,7 @@ usage (char * progname)
+ " -ll show multipath topology (maximum info)\n" \
+ " -f flush a multipath device map\n" \
+ " -F flush all multipath device maps\n" \
++ " -a add a device wwid to the wwids file\n" \
+ " -c check if a device should be a path in a multipath device\n" \
+ " -T tm:val\n" \
+ " check if tm matches the multipathd timestamp. If so val is\n" \
+@@ -292,6 +293,15 @@ configure (void)
+ }
+ goto out;
+ }
++ if (conf->dry_run == 5) {
++ r = remember_wwid(refwwid);
++ if (r == 0)
++ printf("wwid '%s' added\n", refwwid);
++ else
++ printf("failed adding '%s' to wwids file\n",
++ refwwid);
++ goto out;
++ }
+ condlog(3, "scope limited to %s", refwwid);
+ if (conf->dry_run == 2) {
+ if (check_wwids_file(refwwid, 0) == 0){
+@@ -428,7 +438,7 @@ main (int argc, char *argv[])
+ int r = 1;
+ long int timestamp = -1;
+ int valid = -1;
+- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
+ switch(arg) {
+ case 'T':
+ if (optarg[0] == ':')
+@@ -464,7 +474,7 @@ main (int argc, char *argv[])
+ if (dm_prereq())
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
+ switch(arg) {
+ case 1: printf("optarg : %s\n",optarg);
+ break;
+@@ -537,6 +547,9 @@ main (int argc, char *argv[])
+ case 'W':
+ conf->dry_run = 4;
+ break;
++ case 'a':
++ conf->dry_run = 5;
++ break;
+ case ':':
+ fprintf(stderr, "Missing option argument\n");
+ usage(argv[0]);
+Index: multipath-tools-130222/multipath/multipath.8
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.8
++++ multipath-tools-130222/multipath/multipath.8
+@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco
+ .RB [\| \-b\ \c
+ .IR bindings_file \|]
+ .RB [\| \-d \|]
+-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w | \-W \|]
++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-w | \-W \|]
+ .RB [\| \-p\ \c
+ .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
+ .RB [\| device \|]
+@@ -68,6 +68,9 @@ check if a block device should be a path
+ .B \-q
+ allow device tables with queue_if_no_path when multipathd is not running
+ .TP
++.B \-a
++add the wwid for the specified device to the wwids file
++.TP
+ .B \-w
+ remove the wwid for the specified device from the wwids file
+ .TP
--- /dev/null
+---
+ libmultipath/wwids.c | 44 ++++++++++++++++++++++++++++++++++++++++++
+ libmultipath/wwids.h | 1
+ multipath/main.c | 12 ++++++++---
+ multipath/multipath.8 | 5 +++-
+ multipathd/multipathd.service | 1
+ 5 files changed, 59 insertions(+), 4 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/wwids.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -305,3 +305,47 @@ remember_wwid(char *wwid)
+ condlog(4, "wwid %s already in wwids file", wwid);
+ return 0;
+ }
++
++int remember_cmdline_wwid(void)
++{
++ FILE *f = NULL;
++ char buf[LINE_MAX], *next, *ptr;
++ int ret = 0;
++
++ f = fopen("/proc/cmdline", "re");
++ if (!f) {
++ condlog(0, "can't open /proc/cmdline : %s", strerror(errno));
++ return -1;
++ }
++
++ if (!fgets(buf, sizeof(buf), f)) {
++ if (ferror(f))
++ condlog(0, "read of /proc/cmdline failed : %s",
++ strerror(errno));
++ else
++ condlog(0, "couldn't read /proc/cmdline");
++ fclose(f);
++ return -1;
++ }
++ fclose(f);
++ next = buf;
++ while((ptr = strstr(next, "mpath.wwid="))) {
++ ptr += 11;
++ next = strpbrk(ptr, " \t\n");
++ if (next) {
++ *next = '\0';
++ next++;
++ }
++ if (strlen(ptr)) {
++ if (remember_wwid(ptr) != 0)
++ ret = -1;
++ }
++ else {
++ condlog(0, "empty mpath.wwid kernel command line option");
++ ret = -1;
++ }
++ if (!next)
++ break;
++ }
++ return ret;
++}
+Index: multipath-tools-130222/libmultipath/wwids.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.h
++++ multipath-tools-130222/libmultipath/wwids.h
+@@ -17,5 +17,6 @@ int remember_wwid(char *wwid);
+ int check_wwids_file(char *wwid, int write_wwid);
+ int remove_wwid(char *wwid);
+ int replace_wwids(vector mp);
++int remember_cmdline_wwid(void);
+
+ #endif /* _WWIDS_H */
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -85,7 +85,7 @@ usage (char * progname)
+ {
+ fprintf (stderr, VERSION_STRING);
+ fprintf (stderr, "Usage:\n");
+- fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
++ fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
+ fprintf (stderr, " %s -t\n", progname);
+@@ -99,6 +99,8 @@ usage (char * progname)
+ " -f flush a multipath device map\n" \
+ " -F flush all multipath device maps\n" \
+ " -a add a device wwid to the wwids file\n" \
++ " -A add devices from kernel command line mpath.wwids\n"
++ " parameters to wwids file\n" \
+ " -c check if a device should be a path in a multipath device\n" \
+ " -T tm:val\n" \
+ " check if tm matches the multipathd timestamp. If so val is\n" \
+@@ -438,7 +440,7 @@ main (int argc, char *argv[])
+ int r = 1;
+ long int timestamp = -1;
+ int valid = -1;
+- while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
+ switch(arg) {
+ case 'T':
+ if (optarg[0] == ':')
+@@ -474,7 +476,7 @@ main (int argc, char *argv[])
+ if (dm_prereq())
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
+ switch(arg) {
+ case 1: printf("optarg : %s\n",optarg);
+ break;
+@@ -538,6 +540,10 @@ main (int argc, char *argv[])
+ goto out;
+ case 'T':
+ break;
++ case 'A':
++ if (remember_cmdline_wwid() != 0)
++ exit(1);
++ exit(0);
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+Index: multipath-tools-130222/multipathd/multipathd.service
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.service
++++ multipath-tools-130222/multipathd/multipathd.service
+@@ -11,6 +11,7 @@ Conflicts=shutdown.target
+ Type=forking
+ PIDFile=/var/run/multipathd/multipathd.pid
+ ExecStartPre=/sbin/modprobe dm-multipath
++ExecStartPre=-/sbin/multipath -A
+ ExecStart=/sbin/multipathd
+ ExecReload=/sbin/multipathd reconfigure
+ #ExecStop=/path/to/scrip delete-me if not necessary
+Index: multipath-tools-130222/multipath/multipath.8
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.8
++++ multipath-tools-130222/multipath/multipath.8
+@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco
+ .RB [\| \-b\ \c
+ .IR bindings_file \|]
+ .RB [\| \-d \|]
+-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-w | \-W \|]
++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-A | \-w | \-W \|]
+ .RB [\| \-p\ \c
+ .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
+ .RB [\| device \|]
+@@ -71,6 +71,9 @@ allow device tables with queue_if_no_pat
+ .B \-a
+ add the wwid for the specified device to the wwids file
+ .TP
++.B \-A
++add wwids from any kernel command line mpath.wwid parameters to the wwids file
++.TP
+ .B \-w
+ remove the wwid for the specified device from the wwids file
+ .TP
--- /dev/null
+---
+ libmultipath/devmapper.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -1151,6 +1151,8 @@ dm_rename_partmaps (char * old, char * n
+ unsigned long long size;
+ char dev_t[32];
+ int r = 1;
++ int offset;
++ char *delim;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ return 1;
+@@ -1171,6 +1173,11 @@ dm_rename_partmaps (char * old, char * n
+ if (dm_dev_t(old, &dev_t[0], 32))
+ goto out;
+
++ if (isdigit(new[strlen(new)-1]))
++ delim = "p";
++ else
++ delim = "";
++
+ do {
+ if (
+ /*
+@@ -1198,8 +1205,9 @@ dm_rename_partmaps (char * old, char * n
+ * then it's a kpartx generated partition.
+ * Rename it.
+ */
+- snprintf(buff, PARAMS_SIZE, "%s%s",
+- new, names->name + strlen(old));
++ for (offset = strlen(old); names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do nothing */
++ snprintf(buff, PARAMS_SIZE, "%s%s%s",
++ new, delim, names->name + offset);
+ dm_rename(names->name, buff);
+ condlog(4, "partition map %s renamed",
+ names->name);
--- /dev/null
+---
+ libmultipath/checkers/tur.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/checkers/tur.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers/tur.c
++++ multipath-tools-130222/libmultipath/checkers/tur.c
+@@ -409,7 +409,6 @@ libcheck_check (struct checker * c)
+ ct->running = 0;
+ MSG(c, MSG_TUR_TIMEOUT);
+ tur_status = PATH_DOWN;
+- ct->state = PATH_UNCHECKED;
+ } else {
+ condlog(3, "%d:%d: tur checker not finished",
+ TUR_DEVT(ct));
+@@ -426,12 +425,10 @@ libcheck_check (struct checker * c)
+ pthread_mutex_unlock(&ct->lock);
+ } else {
+ if (ct->thread) {
+- /* pthread cancel failed. continue in sync mode */
+ pthread_mutex_unlock(&ct->lock);
+- condlog(3, "%d:%d: tur thread not responding, "
+- "using sync mode", TUR_DEVT(ct));
+- return tur_check(c->fd, c->timeout, c->message,
+- ct->wwid);
++ condlog(3, "%d:%d: tur thread not responding, ",
++ TUR_DEVT(ct));
++ return PATH_DOWN;
+ }
+ /* Start new TUR checker */
+ ct->state = PATH_UNCHECKED;
--- /dev/null
+---
+ libmultipath/structs_vec.c | 31 +++++++++++++++++++++++++++----
+ multipathd/main.c | 4 ++++
+ 2 files changed, 31 insertions(+), 4 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/structs_vec.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs_vec.c
++++ multipath-tools-130222/libmultipath/structs_vec.c
+@@ -280,12 +280,38 @@ update_multipath_status (struct multipat
+ return 0;
+ }
+
++void sync_paths(struct multipath *mpp, vector pathvec)
++{
++ struct path *pp;
++ struct pathgroup *pgp;
++ int found, i, j;
++
++ vector_foreach_slot (mpp->paths, pp, i) {
++ found = 0;
++ vector_foreach_slot(mpp->pg, pgp, j) {
++ if (find_slot(pgp->paths, (void *)pp) != -1) {
++ found = 1;
++ break;
++ }
++ }
++ if (!found) {
++ condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
++ vector_del_slot(mpp->paths, i--);
++ orphan_path(pp);
++ }
++ }
++ update_mpp_paths(mpp, pathvec);
++ vector_foreach_slot (mpp->paths, pp, i)
++ pp->mpp = mpp;
++}
++
+ extern int
+ update_multipath_strings (struct multipath *mpp, vector pathvec)
+ {
+ if (!mpp)
+ return 1;
+
++ update_mpp_paths(mpp, pathvec);
+ condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
+
+ free_multipath_attributes(mpp);
+@@ -294,6 +320,7 @@ update_multipath_strings (struct multipa
+
+ if (update_multipath_table(mpp, pathvec))
+ return 1;
++ sync_paths(mpp, pathvec);
+
+ if (update_multipath_status(mpp))
+ return 1;
+@@ -494,13 +521,9 @@ int update_multipath (struct vectors *ve
+ return 2;
+ }
+
+- free_pgvec(mpp->pg, KEEP_PATHS);
+- mpp->pg = NULL;
+-
+ if (__setup_multipath(vecs, mpp, reset))
+ return 1; /* mpp freed in setup_multipath */
+
+- adopt_paths(vecs->pathvec, mpp, 0);
+ /*
+ * compare checkers states with DM states
+ */
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -1152,6 +1152,10 @@ check_path (struct vectors * vecs, struc
+ pp->dev);
+ pp->dmstate = PSTATE_UNDEF;
+ }
++ /* if update_multipath_strings orphaned the path, quit early */
++ if (!pp->mpp)
++ return;
++
+ pp->chkrstate = newstate;
+ if (newstate != pp->state) {
+ int oldstate = pp->state;
--- /dev/null
+---
+ libmultipath/prioritizers/alua.c | 4 ++--
+ multipathd/multipathd.8 | 37 +++++++++++++++++++++++++++++++++----
+ 2 files changed, 35 insertions(+), 6 deletions(-)
+
+Index: multipath-tools-130222/multipathd/multipathd.8
+===================================================================
+--- multipath-tools-130222.orig/multipathd/multipathd.8
++++ multipath-tools-130222/multipathd/multipathd.8
+@@ -42,6 +42,9 @@ format wildcards.
+ .B list|show maps|multipaths
+ Show the multipath devices that the multipathd is monitoring.
+ .TP
++.B list|show daemon
++Show the current state of the multipathd daemon
++.TP
+ .B list|show maps|multipaths format $format
+ Show the status of all multipath devices that the multipathd is monitoring,
+ using a format string with multipath format wildcards.
+@@ -83,16 +86,16 @@ Add a path to the list of monitored path
+ .B remove|del path $path
+ Stop monitoring a path. $path is as listed in /sys/block (e.g. sda).
+ .TP
+-.B add map $map
++.B add map|multipath $map
+ Add a multipath device to the list of monitored devices. $map can either be a device-mapper device as listed in /sys/block (e.g. dm-0) or it can be the alias for the multipath device (e.g. mpath1) or the uid of the multipath device (e.g. 36005076303ffc56200000000000010aa).
+ .TP
+-.B remove|del map $map
++.B remove|del map|multipath $map
+ Stop monitoring a multipath device.
+ .TP
+ .B resize map|multipath $map
+ Resizes map $map to the given size
+ .TP
+-.B switch|switchgroup map $map group $group
++.B switch|switchgroup map|multipath $map group $group
+ Force a multipath device to switch to a specific path group. $group is the path group index, starting with 1.
+ .TP
+ .B reconfigure
+@@ -104,6 +107,13 @@ Sets map $map into suspend state.
+ .B resume map|multipath $map
+ Resumes map $map from suspend state.
+ .TP
++.B reset map|multipath $map
++Reassign existing device-mapper table(s) use use the multipath device, instead
++of its path devices.
++.TP
++.B reload map|multipath $map
++Reload a multipath device.
++.TP
+ .B fail path $path
+ Sets path $path into failed state.
+ .TP
+@@ -120,10 +130,29 @@ Restore queueing on all multipath device
+ Disable queuing on multipathed map $map
+ .TP
+ .B restorequeueing map|multipath $map
+-Restore queuing on multipahted map $map
++Restore queuing on multipathed map $map
++.TP
++.B forcequeueing daemon
++Forces multipathd into queue_without_daemon mode, so that no_path_retry queueing
++will not be disabled when the daemon stops
++.TP
++.B restorequeueing daemon
++Restores configured queue_without_daemon mode
++.TP
++.B map|multipath $map setprstatus
++Enable persistent reservation management on $map
++.TP
++.B map|multipath $map unsetprstatus
++Disable persistent reservation management on $map
++.TP
++.B map|multipath $map getprstatus
++Get the current persistent reservation management status of $map
+ .TP
+ .B quit|exit
+ End interactive session.
++.TP
++.B shutdown
++Stop multipathd.
+
+ .SH "SEE ALSO"
+ .BR multipath (8)
+Index: multipath-tools-130222/libmultipath/prioritizers/alua.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/alua.c
++++ multipath-tools-130222/libmultipath/prioritizers/alua.c
+@@ -119,10 +119,10 @@ int getprio (struct path * pp, char * ar
+ condlog(0, "%s: couldn't get target port group", pp->dev);
+ break;
+ case ALUA_PRIO_GETAAS_FAILED:
+- condlog(0, "%s: couln't get asymmetric access state", pp->dev);
++ condlog(0, "%s: couldn't get asymmetric access state", pp->dev);
+ break;
+ case ALUA_PRIO_TPGS_FAILED:
+- condlog(3, "%s: couln't get supported alua states", pp->dev);
++ condlog(3, "%s: couldn't get supported alua states", pp->dev);
+ break;
+ }
+ }
--- /dev/null
+---
+ libmultipath/hwtable.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/hwtable.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/hwtable.c
++++ multipath-tools-130222/libmultipath/hwtable.c
+@@ -1108,6 +1108,19 @@ static struct hwentry default_hw[] = {
+ .prio_name = PRIO_ALUA,
+ .prio_args = NULL,
+ },
++ {
++ .vendor = "DataCore",
++ .product = "Virtual Disk",
++ .features = DEFAULT_FEATURES,
++ .hwhandler = DEFAULT_HWHANDLER,
++ .pgpolicy = GROUP_BY_PRIO,
++ .pgfailback = -FAILBACK_IMMEDIATE,
++ .rr_weight = RR_WEIGHT_NONE,
++ .no_path_retry = NO_PATH_RETRY_QUEUE,
++ .checker_name = TUR,
++ .prio_name = PRIO_ALUA,
++ .prio_args = NULL,
++ },
+ /*
+ * EOL
+ */
--- /dev/null
+---
+ multipathd/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -562,7 +562,7 @@ rescan:
+ return 0;
+ }
+ else
+- return 1;
++ goto fail;
+
+ fail_map:
+ remove_map(mpp, vecs, 1);
--- /dev/null
+---
+ libmultipath/parser.c | 154 ++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 126 insertions(+), 28 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/parser.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/parser.c
++++ multipath-tools-130222/libmultipath/parser.c
+@@ -395,36 +395,57 @@ set_value(vector strvec)
+ char *alloc = NULL;
+ char *tmp;
+
+- if (!str)
++ if (!str) {
++ condlog(0, "option '%s' missing value",
++ (char *)VECTOR_SLOT(strvec, 0));
+ return NULL;
+-
++ }
+ size = strlen(str);
+- if (size == 0)
++ if (size == 0) {
++ condlog(0, "option '%s' has empty value",
++ (char *)VECTOR_SLOT(strvec, 0));
+ return NULL;
+-
+- if (*str == '"') {
+- for (i = 2; i < VECTOR_SIZE(strvec); i++) {
+- str = VECTOR_SLOT(strvec, i);
+- len += strlen(str);
+- if (!alloc)
+- alloc =
+- (char *) MALLOC(sizeof (char *) *
+- (len + 1));
+- else {
+- alloc =
+- REALLOC(alloc, sizeof (char *) * (len + 1));
+- tmp = VECTOR_SLOT(strvec, i-1);
+- if (alloc && *str != '"' && *tmp != '"')
+- strncat(alloc, " ", 1);
+- }
+-
+- if (alloc && i != VECTOR_SIZE(strvec)-1)
+- strncat(alloc, str, strlen(str));
+- }
+- } else {
+- alloc = MALLOC(sizeof (char *) * (size + 1));
++ }
++ if (*str != '"') {
++ alloc = MALLOC(sizeof (char) * (size + 1));
+ if (alloc)
+ memcpy(alloc, str, size);
++ else
++ condlog(0, "can't allocate memeory for option '%s'",
++ (char *)VECTOR_SLOT(strvec, 0));
++ return alloc;
++ }
++ /* Even empty quotes counts as a value (An empty string) */
++ alloc = (char *) MALLOC(sizeof (char));
++ if (!alloc) {
++ condlog(0, "can't allocate memeory for option '%s'",
++ (char *)VECTOR_SLOT(strvec, 0));
++ return NULL;
++ }
++ for (i = 2; i < VECTOR_SIZE(strvec); i++) {
++ str = VECTOR_SLOT(strvec, i);
++ if (!str) {
++ free(alloc);
++ condlog(0, "parse error for option '%s'",
++ (char *)VECTOR_SLOT(strvec, 0));
++ return NULL;
++ }
++ if (*str == '"')
++ break;
++ tmp = alloc;
++ /* The first +1 is for the NULL byte. The rest are for the
++ * spaces between words */
++ len += strlen(str) + 1;
++ alloc = REALLOC(alloc, sizeof (char) * len);
++ if (!alloc) {
++ FREE(tmp);
++ condlog(0, "can't allocate memeory for option '%s'",
++ (char *)VECTOR_SLOT(strvec, 0));
++ return NULL;
++ }
++ if (*alloc != '\0')
++ strncat(alloc, " ", 1);
++ strncat(alloc, str, strlen(str));
+ }
+ return alloc;
+ }
+@@ -465,6 +486,74 @@ void free_uniques(vector uniques)
+ }
+
+ int
++is_sublevel_keyword(char *str)
++{
++ return (strcmp(str, "defaults") == 0 || strcmp(str, "blacklist") == 0 ||
++ strcmp(str, "blacklist_exceptions") == 0 ||
++ strcmp(str, "devices") == 0 || strcmp(str, "devices") == 0 ||
++ strcmp(str, "device") == 0 || strcmp(str, "multipaths") == 0 ||
++ strcmp(str, "multipath") == 0);
++}
++
++int
++validate_config_strvec(vector strvec)
++{
++ char *str;
++ int i;
++
++ str = VECTOR_SLOT(strvec, 0);
++ if (str == NULL) {
++ condlog(0, "can't parse option on line %d of config file",
++ line_nr);
++ return -1;
++ }
++ if (*str == '}') {
++ if (VECTOR_SIZE(strvec) > 1)
++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr);
++ return 0;
++ }
++ if (*str == '{') {
++ condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr);
++ return -1;
++ }
++ if (is_sublevel_keyword(str)) {
++ str = VECTOR_SLOT(strvec, 1);
++ if (str == NULL)
++ condlog(0, "missing '{' on line %d of config file", line_nr);
++ else if (*str != '{')
++ condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str);
++ else if (VECTOR_SIZE(strvec) > 2)
++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
++ return 0;
++ }
++ str = VECTOR_SLOT(strvec, 1);
++ if (str == NULL) {
++ condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr);
++ return -1;
++ }
++ if (*str != '"') {
++ if (VECTOR_SIZE(strvec) > 2)
++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
++ return 0;
++ }
++ for (i = 2; i < VECTOR_SIZE(strvec); i++) {
++ str = VECTOR_SLOT(strvec, i);
++ if (str == NULL) {
++ condlog(0, "can't parse value on line %d of config file", line_nr);
++ return -1;
++ }
++ if (*str == '"') {
++ if (VECTOR_SIZE(strvec) > i + 1)
++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr);
++ return 0;
++ }
++ }
++ condlog(0, "missing closing quotes on line %d of config file",
++ line_nr);
++ return 0;
++}
++
++int
+ process_stream(vector keywords)
+ {
+ int i;
+@@ -494,11 +583,20 @@ process_stream(vector keywords)
+ if (!strvec)
+ continue;
+
++ if (validate_config_strvec(strvec) != 0) {
++ free_strvec(strvec);
++ continue;
++ }
++
+ str = VECTOR_SLOT(strvec, 0);
+
+- if (!strcmp(str, EOB) && kw_level > 0) {
+- free_strvec(strvec);
+- break;
++ if (!strcmp(str, EOB)) {
++ if (kw_level > 0) {
++ free_strvec(strvec);
++ break;
++ }
++ condlog(0, "unmatched '%s' at line %d of config file",
++ EOB, line_nr);
+ }
+
+ for (i = 0; i < VECTOR_SIZE(keywords); i++) {
--- /dev/null
+---
+ libmultipath/prio.c | 7 +++++++
+ libmultipath/prio.h | 1 +
+ libmultipath/prioritizers/alua_rtpg.c | 5 +++--
+ libmultipath/prioritizers/emc.c | 2 +-
+ libmultipath/prioritizers/hds.c | 2 +-
+ libmultipath/prioritizers/hp_sw.c | 2 +-
+ libmultipath/prioritizers/ontap.c | 4 ++--
+ libmultipath/prioritizers/rdac.c | 2 +-
+ multipath.conf.annotated | 5 +++--
+ multipath/multipath.conf.5 | 4 ++--
+ 10 files changed, 22 insertions(+), 12 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/prio.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prio.c
++++ multipath-tools-130222/libmultipath/prio.c
+@@ -10,6 +10,13 @@
+
+ static LIST_HEAD(prioritizers);
+
++unsigned int get_prio_timeout(unsigned int default_timeout)
++{
++ if (conf->checker_timeout)
++ return conf->checker_timeout * 1000;
++ return default_timeout;
++}
++
+ int init_prio (void)
+ {
+ if (!add_prio(DEFAULT_PRIO))
+Index: multipath-tools-130222/libmultipath/prio.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prio.h
++++ multipath-tools-130222/libmultipath/prio.h
+@@ -51,6 +51,7 @@ struct prio {
+ int (*getprio)(struct path *, char *);
+ };
+
++unsigned int get_prio_timeout(unsigned int default_timeout);
+ int init_prio (void);
+ void cleanup_prio (void);
+ struct prio * add_prio (char *);
+Index: multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/alua_rtpg.c
++++ multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.c
+@@ -21,6 +21,7 @@
+ #define __user
+ #include <scsi/sg.h>
+
++#include "../prio.h"
+ #include "alua_rtpg.h"
+
+ #define SENSE_BUFF_LEN 32
+@@ -134,7 +135,7 @@ do_inquiry(int fd, int evpd, unsigned in
+ hdr.dxfer_len = resplen;
+ hdr.sbp = sense;
+ hdr.mx_sb_len = sizeof(sense);
+- hdr.timeout = DEF_TIMEOUT;
++ hdr.timeout = get_prio_timeout(DEF_TIMEOUT);
+
+ if (ioctl(fd, SG_IO, &hdr) < 0) {
+ PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
+@@ -253,7 +254,7 @@ do_rtpg(int fd, void* resp, long resplen
+ hdr.dxfer_len = resplen;
+ hdr.mx_sb_len = sizeof(sense);
+ hdr.sbp = sense;
+- hdr.timeout = DEF_TIMEOUT;
++ hdr.timeout = get_prio_timeout(DEF_TIMEOUT);
+
+ if (ioctl(fd, SG_IO, &hdr) < 0)
+ return -RTPG_RTPG_FAILED;
+Index: multipath-tools-130222/libmultipath/prioritizers/emc.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/emc.c
++++ multipath-tools-130222/libmultipath/prioritizers/emc.c
+@@ -31,7 +31,7 @@ int emc_clariion_prio(const char *dev, i
+ io_hdr.dxferp = sense_buffer;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sb;
+- io_hdr.timeout = 60000;
++ io_hdr.timeout = get_prio_timeout(60000);
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ pp_emc_log(0, "sending query command failed");
+Index: multipath-tools-130222/libmultipath/prioritizers/hds.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/hds.c
++++ multipath-tools-130222/libmultipath/prioritizers/hds.c
+@@ -114,7 +114,7 @@ int hds_modular_prio (const char *dev, i
+ io_hdr.dxferp = inqBuff;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_buffer;
+- io_hdr.timeout = 2000; /* TimeOut = 2 seconds */
++ io_hdr.timeout = get_prio_timeout(2000); /* TimeOut = 2 seconds */
+
+ if (ioctl (fd, SG_IO, &io_hdr) < 0) {
+ pp_hds_log(0, "SG_IO error");
+Index: multipath-tools-130222/libmultipath/prioritizers/hp_sw.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/hp_sw.c
++++ multipath-tools-130222/libmultipath/prioritizers/hp_sw.c
+@@ -46,7 +46,7 @@ int hp_sw_prio(const char *dev, int fd)
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.cmdp = turCmdBlk;
+ io_hdr.sbp = sb;
+- io_hdr.timeout = 60000;
++ io_hdr.timeout = get_prio_timeout(60000);
+ io_hdr.pack_id = 0;
+ retry:
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+Index: multipath-tools-130222/libmultipath/prioritizers/ontap.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/ontap.c
++++ multipath-tools-130222/libmultipath/prioritizers/ontap.c
+@@ -89,7 +89,7 @@ static int send_gva(const char *dev, int
+ io_hdr.dxferp = results;
+ io_hdr.cmdp = cdb;
+ io_hdr.sbp = sb;
+- io_hdr.timeout = SG_TIMEOUT;
++ io_hdr.timeout = get_prio_timeout(SG_TIMEOUT);
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ pp_ontap_log(0, "SG_IO ioctl failed, errno=%d", errno);
+@@ -141,7 +141,7 @@ static int get_proxy(const char *dev, in
+ io_hdr.dxferp = results;
+ io_hdr.cmdp = cdb;
+ io_hdr.sbp = sb;
+- io_hdr.timeout = SG_TIMEOUT;
++ io_hdr.timeout = get_prio_timeout(SG_TIMEOUT);
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ pp_ontap_log(0, "ioctl sending inquiry command failed, "
+Index: multipath-tools-130222/libmultipath/prioritizers/rdac.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/rdac.c
++++ multipath-tools-130222/libmultipath/prioritizers/rdac.c
+@@ -31,7 +31,7 @@ int rdac_prio(const char *dev, int fd)
+ io_hdr.dxferp = sense_buffer;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sb;
+- io_hdr.timeout = 60000;
++ io_hdr.timeout = get_prio_timeout(60000);
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ pp_rdac_log(0, "sending inquiry command failed");
+Index: multipath-tools-130222/multipath.conf.annotated
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.annotated
++++ multipath-tools-130222/multipath.conf.annotated
+@@ -188,8 +188,9 @@
+ # #
+ # # name : checker_timeout
+ # # scope : multipath & multipathd
+-# # desc : The timeout to use for path checkers that issue scsi
+-# # commands with an explicit timeout, in seconds.
++# # desc : The timeout to use for path checkers and prioritizers
++# # that issue scsi commands with an explicit timeout, in
++# # seconds.
+ # # values : n > 0
+ # # default : taken from /sys/block/sd<x>/device/timeout
+ # checker_timeout 60
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -321,8 +321,8 @@ maximum number of open fds is taken from
+ if that number is greated than 1024.
+ .TP
+ .B checker_timeout
+-Specify the timeout to user for path checkers that issue scsi commands with an
+-explicit timeout, in seconds; default taken from
++Specify the timeout to use for path checkers and prioritizers that issue scsi
++commands with an explicit timeout, in seconds; default taken from
+ .I /sys/block/sd<x>/device/timeout
+ .TP
+ .B fast_io_fail_tmo
--- /dev/null
+---
+ libmultipath/config.c | 1 +
+ libmultipath/config.h | 1 +
+ libmultipath/dict.c | 33 +++++++++++++++++++++++++++++++++
+ libmultipath/discovery.c | 8 ++++++--
+ multipath.conf.annotated | 10 ++++++++++
+ multipath/multipath.conf.5 | 9 +++++++++
+ 6 files changed, 60 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -556,6 +556,7 @@ load_config (char * file, struct udev *u
+ conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
+ conf->detect_prio = DEFAULT_DETECT_PRIO;
+ conf->hw_strmatch = 0;
++ conf->force_sync = 0;
+
+ /*
+ * preload default hwtable
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -115,6 +115,7 @@ struct config {
+ int reassign_maps;
+ int retain_hwhandler;
+ int detect_prio;
++ int force_sync;
+ unsigned int version[3];
+
+ char * dev;
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -712,6 +712,29 @@ def_hw_strmatch_handler(vector strvec)
+ return 0;
+ }
+
++static int
++def_force_sync_handler(vector strvec)
++{
++ char * buff;
++
++ buff = set_value(strvec);
++
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ conf->force_sync = 0;
++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "1")))
++ conf->force_sync = 1;
++ else
++ conf->force_sync = 0;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * blacklist block handlers
+ */
+@@ -2822,6 +2845,15 @@ snprint_def_hw_strmatch(char * buff, int
+ }
+
+ static int
++snprint_def_force_sync(char * buff, int len, void * data)
++{
++ if (conf->force_sync)
++ return snprintf(buff, len, "yes");
++ else
++ return snprintf(buff, len, "no");
++}
++
++static int
+ snprint_ble_simple (char * buff, int len, void * data)
+ {
+ struct blentry * ble = (struct blentry *)data;
+@@ -2889,6 +2921,7 @@ init_keywords(void)
+ install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler);
+ install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
+ install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch);
++ install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
+ __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);
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -952,8 +952,12 @@ get_state (struct path * pp, int daemon)
+ }
+ }
+ checker_clear_message(c);
+- if (daemon)
+- checker_set_async(c);
++ if (daemon) {
++ if (conf->force_sync == 0)
++ checker_set_async(c);
++ else
++ checker_set_sync(c);
++ }
+ if (!conf->checker_timeout &&
+ (pp->bus != SYSFS_BUS_SCSI ||
+ sysfs_get_timeout(pp, &(c->timeout))))
+Index: multipath-tools-130222/multipath.conf.annotated
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.annotated
++++ multipath-tools-130222/multipath.conf.annotated
+@@ -214,6 +214,8 @@
+ # # values : n > 0
+ # # default : determined by the OS
+ # dev_loss_tmo 600
++#
++# #
+ # # name : bindings_file
+ # # scope : multipath
+ # # desc : The location of the bindings file that is used with
+@@ -222,6 +224,14 @@
+ # # default : "/var/lib/multipath/bindings"
+ # bindings_file "/etc/multipath_bindings"
+ #
++# #
++# # name : force_sync
++# # scope : multipathd
++# # desc : If set to yes, multipath will run all of the checkers in
++# # sync mode, even if the checker has an async mode.
++# # values : yes|no
++# # default : no
++# force_sync yes
+ #}
+ #
+ ##
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -411,6 +411,15 @@ modify an existing config, or create a n
+ , the user device configs will be regular expression matched against the
+ built-in configs instead. Default is
+ .I no
++.TP
++.B force_sync
++If set to
++.I yes
++, multipathd will call the path checkers in sync mode only. This means that
++only one checker will run at a time. This is useful in the case where many
++multipathd checkers running in parallel causes significant CPU pressure. The
++Default is
++.I no
+ .
+ .SH "blacklist section"
+ The
--- /dev/null
+---
+ libmultipath/configure.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++
+ libmultipath/configure.h | 2
+ libmultipath/discovery.c | 87 +++++++++++++++++
+ libmultipath/discovery.h | 2
+ libmultipath/structs.c | 84 +++++++++++++++++
+ libmultipath/structs.h | 25 ++++-
+ 6 files changed, 427 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -39,6 +39,219 @@
+ #include "uxsock.h"
+ #include "wwids.h"
+
++/* group paths in pg by host adapter
++ */
++int group_by_host_adapter(struct pathgroup *pgp, vector adapters)
++{
++ struct adapter_group *agp;
++ struct host_group *hgp;
++ struct path *pp, *pp1;
++ char adapter_name1[SLOT_NAME_SIZE];
++ char adapter_name2[SLOT_NAME_SIZE];
++ int i, j;
++ int found_hostgroup = 0;
++
++ while (VECTOR_SIZE(pgp->paths) > 0) {
++
++ pp = VECTOR_SLOT(pgp->paths, 0);
++
++ if (sysfs_get_host_adapter_name(pp, adapter_name1))
++ goto out;
++ /* create a new host adapter group
++ */
++ agp = alloc_adaptergroup();
++ if (!agp)
++ goto out;
++ agp->pgp = pgp;
++
++ strncpy(agp->adapter_name, adapter_name1, SLOT_NAME_SIZE);
++ store_adaptergroup(adapters, agp);
++
++ /* create a new host port group
++ */
++ hgp = alloc_hostgroup();
++ if (!hgp)
++ goto out;
++ if (store_hostgroup(agp->host_groups, hgp))
++ goto out;
++
++ hgp->host_no = pp->sg_id.host_no;
++ agp->num_hosts++;
++ if (store_path(hgp->paths, pp))
++ goto out;
++
++ hgp->num_paths++;
++ /* delete path from path group
++ */
++ vector_del_slot(pgp->paths, 0);
++
++ /* add all paths belonging to same host adapter
++ */
++ vector_foreach_slot(pgp->paths, pp1, i) {
++ if (sysfs_get_host_adapter_name(pp1, adapter_name2))
++ goto out;
++ if (strcmp(adapter_name1, adapter_name2) == 0) {
++ found_hostgroup = 0;
++ vector_foreach_slot(agp->host_groups, hgp, j) {
++ if (hgp->host_no == pp1->sg_id.host_no) {
++ if (store_path(hgp->paths, pp1))
++ goto out;
++ hgp->num_paths++;
++ found_hostgroup = 1;
++ break;
++ }
++ }
++ if (!found_hostgroup) {
++ /* this path belongs to new host port
++ * within this adapter
++ */
++ hgp = alloc_hostgroup();
++ if (!hgp)
++ goto out;
++
++ if (store_hostgroup(agp->host_groups, hgp))
++ goto out;
++
++ agp->num_hosts++;
++ if (store_path(hgp->paths, pp1))
++ goto out;
++
++ hgp->host_no = pp1->sg_id.host_no;
++ hgp->num_paths++;
++ }
++ /* delete paths from original path_group
++ * as they are added into adapter group now
++ */
++ vector_del_slot(pgp->paths, i);
++ i--;
++ }
++ }
++ }
++ return 0;
++
++out: /* add back paths into pg as re-ordering failed
++ */
++ vector_foreach_slot(adapters, agp, i) {
++ vector_foreach_slot(agp->host_groups, hgp, j) {
++ while (VECTOR_SIZE(hgp->paths) > 0) {
++ pp = VECTOR_SLOT(hgp->paths, 0);
++ if (store_path(pgp->paths, pp))
++ condlog(3, "failed to restore "
++ "path %s into path group",
++ pp->dev);
++ vector_del_slot(hgp->paths, 0);
++ }
++ }
++ }
++ free_adaptergroup(adapters);
++ return 1;
++}
++
++/* re-order paths in pg by alternating adapters and host ports
++ * for optimized selection
++ */
++int order_paths_in_pg_by_alt_adapters(struct pathgroup *pgp, vector adapters,
++ int total_paths)
++{
++ int next_adapter_index = 0;
++ struct adapter_group *agp;
++ struct host_group *hgp;
++ struct path *pp;
++
++ while (total_paths > 0) {
++ agp = VECTOR_SLOT(adapters, next_adapter_index);
++ if (!agp) {
++ condlog(0, "can't get adapter group %d", next_adapter_index);
++ return 1;
++ }
++
++ hgp = VECTOR_SLOT(agp->host_groups, agp->next_host_index);
++ if (!hgp) {
++ condlog(0, "can't get host group %d of adapter group %d", next_adapter_index, agp->next_host_index);
++ return 1;
++ }
++
++ if (!hgp->num_paths) {
++ agp->next_host_index++;
++ agp->next_host_index %= agp->num_hosts;
++ next_adapter_index++;
++ next_adapter_index %= VECTOR_SIZE(adapters);
++ continue;
++ }
++
++ pp = VECTOR_SLOT(hgp->paths, 0);
++
++ if (store_path(pgp->paths, pp))
++ return 1;
++
++ total_paths--;
++
++ vector_del_slot(hgp->paths, 0);
++
++ hgp->num_paths--;
++
++ agp->next_host_index++;
++ agp->next_host_index %= agp->num_hosts;
++ next_adapter_index++;
++ next_adapter_index %= VECTOR_SIZE(adapters);
++ }
++
++ /* all paths are added into path_group
++ * in crafted child order
++ */
++ return 0;
++}
++
++/* round-robin: order paths in path group to alternate
++ * between all host adapters
++ */
++int rr_optimize_path_order(struct pathgroup *pgp)
++{
++ vector adapters;
++ struct path *pp;
++ int total_paths;
++ int i;
++
++ total_paths = VECTOR_SIZE(pgp->paths);
++ vector_foreach_slot(pgp->paths, pp, i) {
++ if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
++ pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
++ pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
++ pp->sg_id.proto_id != SCSI_PROTOCOL_SRP) {
++ /* return success as default path order
++ * is maintained in path group
++ */
++ return 0;
++ }
++ }
++ adapters = vector_alloc();
++ if (!adapters)
++ return 0;
++
++ /* group paths in path group by host adapters
++ */
++ if (group_by_host_adapter(pgp, adapters)) {
++ /* already freed adapters */
++ condlog(3, "Failed to group paths by adapters");
++ return 0;
++ }
++
++ /* re-order paths in pg to alternate between adapters and host ports
++ */
++ if (order_paths_in_pg_by_alt_adapters(pgp, adapters, total_paths)) {
++ condlog(3, "Failed to re-order paths in pg by adapters "
++ "and host ports");
++ free_adaptergroup(adapters);
++ /* return failure as original paths are
++ * removed form pgp
++ */
++ return 1;
++ }
++
++ free_adaptergroup(adapters);
++ return 0;
++}
++
+ extern int
+ setup_map (struct multipath * mpp, char * params, int params_size)
+ {
+@@ -101,6 +314,22 @@ setup_map (struct multipath * mpp, char
+ */
+ mpp->bestpg = select_path_group(mpp);
+
++ /* re-order paths in all path groups in an optimized way
++ * for round-robin path selectors to get maximum throughput.
++ */
++ if (!strncmp(mpp->selector, "round-robin", 11)) {
++ vector_foreach_slot(mpp->pg, pgp, i) {
++ if (VECTOR_SIZE(pgp->paths) <= 2)
++ continue;
++ if (rr_optimize_path_order(pgp)) {
++ condlog(2, "cannot re-order paths for "
++ "optimization: %s",
++ mpp->alias);
++ return 1;
++ }
++ }
++ }
++
+ /*
+ * transform the mp->pg vector of vectors of paths
+ * into a mp->params strings to feed the device-mapper
+Index: multipath-tools-130222/libmultipath/configure.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.h
++++ multipath-tools-130222/libmultipath/configure.h
+@@ -29,4 +29,4 @@ int reinstate_paths (struct multipath *m
+ int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
+ int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid);
+ int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh);
+-
++int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name);
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -310,6 +310,93 @@ sysfs_get_tgt_nodename (struct path *pp,
+ return 1;
+ }
+
++int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name)
++{
++ int proto_id;
++
++ if (!pp || !adapter_name)
++ return 1;
++
++ proto_id = pp->sg_id.proto_id;
++
++ if (proto_id != SCSI_PROTOCOL_FCP &&
++ proto_id != SCSI_PROTOCOL_SAS &&
++ proto_id != SCSI_PROTOCOL_ISCSI &&
++ proto_id != SCSI_PROTOCOL_SRP) {
++ return 1;
++ }
++ /* iscsi doesn't have adapter info in sysfs
++ * get ip_address for grouping paths
++ */
++ if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
++ return sysfs_get_iscsi_ip_address(pp, adapter_name);
++
++ /* fetch adapter pci name for other protocols
++ */
++ return sysfs_get_host_pci_name(pp, adapter_name);
++}
++
++int sysfs_get_host_pci_name(struct path *pp, char *pci_name)
++{
++ struct udev_device *hostdev, *parent;
++ char host_name[HOST_NAME_LEN];
++ const char *driver_name, *value;
++
++ if (!pp || !pci_name)
++ return 1;
++
++ sprintf(host_name, "host%d", pp->sg_id.host_no);
++ hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
++ "scsi_host", host_name);
++ if (!hostdev)
++ return 1;
++
++ parent = udev_device_get_parent(hostdev);
++ while (parent) {
++ driver_name = udev_device_get_driver(parent);
++ if (!driver_name) {
++ parent = udev_device_get_parent(parent);
++ continue;
++ }
++ if (!strcmp(driver_name, "pcieport"))
++ break;
++ parent = udev_device_get_parent(parent);
++ }
++ if (parent) {
++ /* pci_device found
++ */
++ value = udev_device_get_sysname(parent);
++
++ strncpy(pci_name, value, SLOT_NAME_SIZE);
++ udev_device_unref(hostdev);
++ return 0;
++ }
++ udev_device_unref(hostdev);
++ return 1;
++}
++
++int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address)
++{
++ struct udev_device *hostdev;
++ char host_name[HOST_NAME_LEN];
++ const char *value;
++
++ sprintf(host_name, "host%d", pp->sg_id.host_no);
++ hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
++ "iscsi_host", host_name);
++ if (hostdev) {
++ value = udev_device_get_sysattr_value(hostdev,
++ "ipaddress");
++ if (value) {
++ strncpy(ip_address, value, SLOT_NAME_SIZE);
++ udev_device_unref(hostdev);
++ return 0;
++ } else
++ udev_device_unref(hostdev);
++ }
++ return 1;
++}
++
+ static void
+ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
+ {
+Index: multipath-tools-130222/libmultipath/discovery.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.h
++++ multipath-tools-130222/libmultipath/discovery.h
+@@ -38,6 +38,8 @@ int store_pathinfo (vector pathvec, vect
+ struct path **pp_ptr);
+ int sysfs_set_scsi_tmo (struct multipath *mpp);
+ int sysfs_get_timeout(struct path *pp, unsigned int *timeout);
++int sysfs_get_host_pci_name(struct path *pp, char *pci_name);
++int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address);
+
+ /*
+ * discovery bitmask
+Index: multipath-tools-130222/libmultipath/structs.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs.c
++++ multipath-tools-130222/libmultipath/structs.c
+@@ -18,6 +18,70 @@
+ #include "blacklist.h"
+ #include "prio.h"
+
++struct adapter_group *
++alloc_adaptergroup(void)
++{
++ struct adapter_group *agp;
++
++ agp = (struct adapter_group *)MALLOC(sizeof(struct adapter_group));
++
++ if (!agp)
++ return NULL;
++
++ agp->host_groups = vector_alloc();
++ if (!agp->host_groups) {
++ FREE(agp);
++ agp = NULL;
++ }
++ return agp;
++}
++
++void free_adaptergroup(vector adapters)
++{
++ int i;
++ struct adapter_group *agp;
++
++ vector_foreach_slot(adapters, agp, i) {
++ free_hostgroup(agp->host_groups);
++ FREE(agp);
++ }
++ vector_free(adapters);
++}
++
++void free_hostgroup(vector hostgroups)
++{
++ int i;
++ struct host_group *hgp;
++
++ if (!hostgroups)
++ return;
++
++ vector_foreach_slot(hostgroups, hgp, i) {
++ vector_free(hgp->paths);
++ FREE(hgp);
++ }
++ vector_free(hostgroups);
++}
++
++struct host_group *
++alloc_hostgroup(void)
++{
++ struct host_group *hgp;
++
++ hgp = (struct host_group *)MALLOC(sizeof(struct host_group));
++
++ if (!hgp)
++ return NULL;
++
++ hgp->paths = vector_alloc();
++
++ if (!hgp->paths) {
++ FREE(hgp);
++ hgp = NULL;
++ }
++ return hgp;
++}
++
+ struct path *
+ alloc_path (void)
+ {
+@@ -242,6 +306,26 @@ store_pathgroup (vector pgvec, struct pa
+ return 0;
+ }
+
++int
++store_hostgroup(vector hostgroupvec, struct host_group * hgp)
++{
++ if (!vector_alloc_slot(hostgroupvec))
++ return 1;
++
++ vector_set_slot(hostgroupvec, hgp);
++ return 0;
++}
++
++int
++store_adaptergroup(vector adapters, struct adapter_group * agp)
++{
++ if (!vector_alloc_slot(adapters))
++ return 1;
++
++ vector_set_slot(adapters, agp);
++ return 0;
++}
++
+ struct multipath *
+ find_mp_by_minor (vector mpvec, int minor)
+ {
+Index: multipath-tools-130222/libmultipath/structs.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs.h
++++ multipath-tools-130222/libmultipath/structs.h
+@@ -15,7 +15,8 @@
+ #define BLK_DEV_SIZE 33
+ #define PATH_SIZE 512
+ #define NAME_SIZE 512
+-
++#define HOST_NAME_LEN 8
++#define SLOT_NAME_SIZE 40
+
+ #define SCSI_VENDOR_SIZE 9
+ #define SCSI_PRODUCT_SIZE 17
+@@ -251,6 +252,20 @@ struct pathgroup {
+ char * selector;
+ };
+
++struct adapter_group {
++ char adapter_name[SLOT_NAME_SIZE];
++ struct pathgroup *pgp;
++ int num_hosts;
++ vector host_groups;
++ int next_host_index;
++};
++
++struct host_group {
++ int host_no;
++ int num_paths;
++ vector paths;
++};
++
+ struct path * alloc_path (void);
+ struct pathgroup * alloc_pathgroup (void);
+ struct multipath * alloc_multipath (void);
+@@ -263,6 +278,14 @@ void free_multipath_attributes (struct m
+ void drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths);
+ void free_multipathvec (vector mpvec, enum free_path_mode free_paths);
+
++struct adapter_group * alloc_adaptergroup(void);
++struct host_group * alloc_hostgroup(void);
++void free_adaptergroup(vector adapters);
++void free_hostgroup(vector hostgroups);
++
++int store_adaptergroup(vector adapters, struct adapter_group *agp);
++int store_hostgroup(vector hostgroupvec, struct host_group *hgp);
++
+ int store_path (vector pathvec, struct path * pp);
+ int store_pathgroup (vector pgvec, struct pathgroup * pgp);
+
--- /dev/null
+---
+ libmultipath/dict.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -43,6 +43,9 @@ def_fast_io_fail_handler(vector strvec)
+ char * buff;
+
+ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
+ if (strlen(buff) == 3 && !strcmp(buff, "off"))
+ conf->fast_io_fail = MP_FAST_IO_FAIL_OFF;
+ else if (sscanf(buff, "%d", &conf->fast_io_fail) != 1 ||
+@@ -1002,6 +1005,9 @@ hw_dev_loss_handler(vector strvec)
+ char * buff;
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+
++ if (!hwe)
++ return 1;
++
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+@@ -1021,6 +1027,9 @@ hw_pgpolicy_handler(vector strvec)
+ char * buff;
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+
++ if (!hwe)
++ return 1;
++
+ buff = set_value(strvec);
+
+ if (!buff)
--- /dev/null
+---
+ libmultipath/configure.c | 11 +++++++++++
+ libmultipath/configure.h | 1 +
+ libmultipath/devmapper.c | 3 +--
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -394,6 +394,8 @@ select_action (struct multipath * mpp, v
+ cmpp->alias, mpp->alias);
+ strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
+ mpp->action = ACT_RENAME;
++ if (force_reload)
++ mpp->action = ACT_RENAME2;
+ return;
+ }
+ mpp->action = ACT_CREATE;
+@@ -632,6 +634,15 @@ domap (struct multipath * mpp, char * pa
+ r = dm_rename(mpp->alias_old, mpp->alias);
+ break;
+
++ case ACT_RENAME2:
++ r = dm_rename(mpp->alias_old, mpp->alias);
++ if (r) {
++ r = dm_addmap_reload(mpp, params);
++ if (r)
++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, MPATH_UDEV_RELOAD_FLAG);
++ }
++ break;
++
+ default:
+ break;
+ }
+Index: multipath-tools-130222/libmultipath/configure.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.h
++++ multipath-tools-130222/libmultipath/configure.h
+@@ -18,6 +18,7 @@ enum actions {
+ ACT_RENAME,
+ ACT_CREATE,
+ ACT_RESIZE,
++ ACT_RENAME2,
+ };
+
+ #define FLUSH_ONE 1
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -565,10 +565,9 @@ dm_dev_t (const char * mapname, char * d
+ if (!dm_task_run(dmt))
+ goto out;
+
+- if (!dm_task_get_info(dmt, &info))
++ if (!dm_task_get_info(dmt, &info) || !info.exists)
+ goto out;
+
+- r = info.open_count;
+ if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
+ goto out;
+
--- /dev/null
+---
+ libmultipath/alias.c | 64 ++++++++++++++++++++++++++++++++++++++++++---
+ libmultipath/alias.h | 2 +
+ libmultipath/propsel.c | 32 +++++++++++++++-------
+ libmultipath/structs_vec.c | 15 ++++++++++
+ 4 files changed, 100 insertions(+), 13 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/alias.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/alias.c
++++ multipath-tools-130222/libmultipath/alias.c
+@@ -145,7 +145,7 @@ lookup_binding(FILE *f, char *map_wwid,
+ }
+
+ static int
+-rlookup_binding(FILE *f, char *buff, char *map_alias)
++rlookup_binding(FILE *f, char *buff, char *map_alias, char *prefix)
+ {
+ char line[LINE_MAX];
+ unsigned int line_nr = 0;
+@@ -164,7 +164,7 @@ rlookup_binding(FILE *f, char *buff, cha
+ alias = strtok(line, " \t");
+ if (!alias) /* blank line */
+ continue;
+- curr_id = scan_devname(alias, NULL); /* TBD: Why this call? */
++ curr_id = scan_devname(alias, prefix);
+ if (curr_id >= id)
+ id = curr_id + 1;
+ wwid = strtok(NULL, " \t");
+@@ -188,6 +188,11 @@ rlookup_binding(FILE *f, char *buff, cha
+ }
+ }
+ condlog(3, "No matching alias [%s] in bindings file.", map_alias);
++
++ /* Get the theoretical id for this map alias.
++ * Used by use_existing_alias
++ */
++ id = scan_devname(map_alias, prefix);
+ return id;
+ }
+
+@@ -237,6 +242,59 @@ allocate_binding(int fd, char *wwid, int
+ }
+
+ char *
++use_existing_alias (char *wwid, char *file, char *alias_old,
++ char *prefix, int bindings_read_only)
++{
++ char *alias = NULL;
++ int id = 0;
++ int fd, can_write;
++ char buff[WWID_SIZE];
++ FILE *f;
++
++ fd = open_file(file, &can_write, BINDINGS_FILE_HEADER);
++ if (fd < 0)
++ return NULL;
++
++ f = fdopen(fd, "r");
++ if (!f) {
++ condlog(0, "cannot fdopen on bindings file descriptor");
++ close(fd);
++ return NULL;
++ }
++ /* lookup the binding. if it exsists, the wwid will be in buff
++ * either way, id contains the id for the alias
++ */
++ id = rlookup_binding(f , buff, alias_old, prefix);
++ if (id < 0)
++ goto out;
++
++ if (strlen(buff) > 0) {
++ /* if buff is our wwid, it's already
++ * allocated correctly
++ */
++ if (strcmp(buff, wwid) == 0)
++ alias = STRDUP(alias_old);
++ else {
++ alias = NULL;
++ condlog(0, "alias %s already bound to wwid %s, cannot reuse",
++ alias_old, buff);
++ }
++ goto out;
++ }
++
++ /* allocate the existing alias in the bindings file */
++ if (can_write && id && !bindings_read_only) {
++ alias = allocate_binding(fd, wwid, id, prefix);
++ condlog(0, "Allocated existing binding [%s] for WWID [%s]",
++ alias, wwid);
++ }
++
++out:
++ fclose(f);
++ return alias;
++}
++
++char *
+ get_user_friendly_alias(char *wwid, char *file, char *prefix,
+ int bindings_read_only)
+ {
+@@ -305,7 +363,7 @@ get_user_friendly_wwid(char *alias, char
+ return -1;
+ }
+
+- rlookup_binding(f, buff, alias);
++ rlookup_binding(f, buff, alias, NULL);
+ if (!strlen(buff)) {
+ fclose(f);
+ return -1;
+Index: multipath-tools-130222/libmultipath/alias.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/alias.h
++++ multipath-tools-130222/libmultipath/alias.h
+@@ -10,3 +10,5 @@
+ char *get_user_friendly_alias(char *wwid, char *file, char *prefix,
+ int bindings_readonly);
+ int get_user_friendly_wwid(char *alias, char *buff, char *file);
++char *use_existing_alias (char *wwid, char *file, char *alias_old,
++ char *prefix, int bindings_read_only);
+Index: multipath-tools-130222/libmultipath/propsel.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.c
++++ multipath-tools-130222/libmultipath/propsel.c
+@@ -253,19 +253,31 @@ want_user_friendly_names(struct multipat
+ extern int
+ select_alias (struct multipath * mp)
+ {
+- if (mp->mpe && mp->mpe->alias)
++ if (mp->mpe && mp->mpe->alias) {
+ mp->alias = STRDUP(mp->mpe->alias);
+- else {
+- mp->alias = NULL;
+- if (want_user_friendly_names(mp)) {
+- select_alias_prefix(mp);
+- mp->alias = get_user_friendly_alias(mp->wwid,
+- conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
+- }
+- if (mp->alias == NULL)
+- mp->alias = STRDUP(mp->wwid);
++ goto out;
+ }
+
++ mp->alias = NULL;
++ if (!want_user_friendly_names(mp))
++ goto out;
++
++ select_alias_prefix(mp);
++
++ if (strlen(mp->alias_old) > 0) {
++ mp->alias = use_existing_alias(mp->wwid, conf->bindings_file,
++ mp->alias_old, mp->alias_prefix,
++ conf->bindings_read_only);
++ memset (mp->alias_old, 0, WWID_SIZE);
++ }
++
++ if (mp->alias == NULL)
++ mp->alias = get_user_friendly_alias(mp->wwid,
++ conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
++out:
++ if (mp->alias == NULL)
++ mp->alias = STRDUP(mp->wwid);
++
+ return mp->alias ? 0 : 1;
+ }
+
+Index: multipath-tools-130222/libmultipath/structs_vec.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs_vec.c
++++ multipath-tools-130222/libmultipath/structs_vec.c
+@@ -430,6 +430,20 @@ out:
+ return NULL;
+ }
+
++static void
++find_existing_alias (struct multipath * mpp,
++ struct vectors *vecs)
++{
++ struct multipath * mp;
++ int i;
++
++ vector_foreach_slot (vecs->mpvec, mp, i)
++ if (strcmp(mp->wwid, mpp->wwid) == 0) {
++ strncpy(mpp->alias_old, mp->alias, WWID_SIZE);
++ return;
++ }
++}
++
+ extern struct multipath *
+ add_map_with_path (struct vectors * vecs,
+ struct path * pp, int add_vec)
+@@ -443,6 +457,7 @@ add_map_with_path (struct vectors * vecs
+ mpp->hwe = pp->hwe;
+
+ strcpy(mpp->wwid, pp->wwid);
++ find_existing_alias(mpp, vecs);
+ if (select_alias(mpp))
+ goto out;
+ mpp->size = pp->size;
--- /dev/null
+---
+ libmultipath/alias.c | 31 +++++++++++++++----------------
+ libmultipath/propsel.c | 4 ++--
+ 2 files changed, 17 insertions(+), 18 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/alias.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/alias.c
++++ multipath-tools-130222/libmultipath/alias.c
+@@ -149,13 +149,11 @@ rlookup_binding(FILE *f, char *buff, cha
+ {
+ char line[LINE_MAX];
+ unsigned int line_nr = 0;
+- int id = 0;
+
+ buff[0] = '\0';
+
+ while (fgets(line, LINE_MAX, f)) {
+ char *c, *alias, *wwid;
+- int curr_id;
+
+ line_nr++;
+ c = strpbrk(line, "#\n\r");
+@@ -164,9 +162,6 @@ rlookup_binding(FILE *f, char *buff, cha
+ alias = strtok(line, " \t");
+ if (!alias) /* blank line */
+ continue;
+- curr_id = scan_devname(alias, prefix);
+- if (curr_id >= id)
+- id = curr_id + 1;
+ wwid = strtok(NULL, " \t");
+ if (!wwid){
+ condlog(3,
+@@ -184,16 +179,12 @@ rlookup_binding(FILE *f, char *buff, cha
+ "\nSetting wwid to %s", alias, wwid);
+ strncpy(buff, wwid, WWID_SIZE);
+ buff[WWID_SIZE - 1] = '\0';
+- return id;
++ return 0;
+ }
+ }
+ condlog(3, "No matching alias [%s] in bindings file.", map_alias);
+
+- /* Get the theoretical id for this map alias.
+- * Used by use_existing_alias
+- */
+- id = scan_devname(map_alias, prefix);
+- return id;
++ return -1;
+ }
+
+ static char *
+@@ -264,9 +255,7 @@ use_existing_alias (char *wwid, char *fi
+ /* lookup the binding. if it exsists, the wwid will be in buff
+ * either way, id contains the id for the alias
+ */
+- id = rlookup_binding(f , buff, alias_old, prefix);
+- if (id < 0)
+- goto out;
++ rlookup_binding(f, buff, alias_old, prefix);
+
+ if (strlen(buff) > 0) {
+ /* if buff is our wwid, it's already
+@@ -279,11 +268,21 @@ use_existing_alias (char *wwid, char *fi
+ condlog(0, "alias %s already bound to wwid %s, cannot reuse",
+ alias_old, buff);
+ }
+- goto out;
++ goto out;
+ }
+
+ /* allocate the existing alias in the bindings file */
+- if (can_write && id && !bindings_read_only) {
++ id = scan_devname(alias_old, prefix);
++ if (id <= 0)
++ goto out;
++
++ if (fflush(f) != 0) {
++ condlog(0, "cannot fflush bindings file stream : %s",
++ strerror(errno));
++ goto out;
++ }
++
++ if (can_write && !bindings_read_only) {
+ alias = allocate_binding(fd, wwid, id, prefix);
+ condlog(0, "Allocated existing binding [%s] for WWID [%s]",
+ alias, wwid);
+Index: multipath-tools-130222/libmultipath/propsel.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.c
++++ multipath-tools-130222/libmultipath/propsel.c
+@@ -263,13 +263,13 @@ select_alias (struct multipath * mp)
+ goto out;
+
+ select_alias_prefix(mp);
+-
++
+ if (strlen(mp->alias_old) > 0) {
+ mp->alias = use_existing_alias(mp->wwid, conf->bindings_file,
+ mp->alias_old, mp->alias_prefix,
+ conf->bindings_read_only);
+ memset (mp->alias_old, 0, WWID_SIZE);
+- }
++ }
+
+ if (mp->alias == NULL)
+ mp->alias = get_user_friendly_alias(mp->wwid,
--- /dev/null
+---
+ libmultipath/hwtable.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/hwtable.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/hwtable.c
++++ multipath-tools-130222/libmultipath/hwtable.c
+@@ -1121,6 +1121,19 @@ static struct hwentry default_hw[] = {
+ .prio_name = PRIO_ALUA,
+ .prio_args = NULL,
+ },
++ {
++ .vendor = "XtremIO",
++ .product = "XtremApp",
++ .features = DEFAULT_FEATURES,
++ .hwhandler = DEFAULT_HWHANDLER,
++ .selector = "queue-length 0",
++ .pgpolicy = MULTIBUS,
++ .pgfailback = -FAILBACK_IMMEDIATE,
++ .checker_name = DIRECTIO,
++ .fast_io_fail = 15,
++ .prio_name = DEFAULT_PRIO,
++ .prio_args = NULL,
++ },
+ /*
+ * EOL
+ */
--- /dev/null
+---
+ libmultipath/print.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 83 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/print.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/print.c
++++ multipath-tools-130222/libmultipath/print.c
+@@ -10,6 +10,7 @@
+ #include <unistd.h>
+ #include <string.h>
+ #include <errno.h>
++#include <libudev.h>
+
+ #include "checkers.h"
+ #include "vector.h"
+@@ -44,7 +45,7 @@
+ * information printing helpers
+ */
+ static int
+-snprint_str (char * buff, size_t len, char * str)
++snprint_str (char * buff, size_t len, const char * str)
+ {
+ return snprintf(buff, len, "%s", str);
+ }
+@@ -432,6 +433,83 @@ snprint_path_mpp (char * buff, size_t le
+ }
+
+ static int
++snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr)
++{
++ struct udev_device *host_dev = NULL;
++ char host_id[32];
++ const char *value = NULL;
++ int ret;
++
++ if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
++ return snprintf(buff, len, "[undef]");
++ sprintf(host_id, "host%d", pp->sg_id.host_no);
++ host_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_host",
++ host_id);
++ if (!host_dev) {
++ condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
++ goto out;
++ }
++ value = udev_device_get_sysattr_value(host_dev, attr);
++ if (value)
++ ret = snprint_str(buff, len, value);
++ udev_device_unref(host_dev);
++out:
++ if (!value)
++ ret = snprintf(buff, len, "[unknown]");
++ return ret;
++}
++
++static int
++snprint_host_wwnn (char * buff, size_t len, struct path * pp)
++{
++ return snprint_host_attr(buff, len, pp, "node_name");
++}
++
++static int
++snprint_host_wwpn (char * buff, size_t len, struct path * pp)
++{
++ return snprint_host_attr(buff, len, pp, "port_name");
++}
++
++static int
++snprint_tgt_wwpn (char * buff, size_t len, struct path * pp)
++{
++ struct udev_device *rport_dev = NULL;
++ char rport_id[32];
++ const char *value = NULL;
++ int ret;
++
++ if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
++ return snprintf(buff, len, "[undef]");
++ sprintf(rport_id, "rport-%d:%d-%d",
++ pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
++ rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
++ "fc_remote_ports", rport_id);
++ if (!rport_dev) {
++ condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
++ rport_id);
++ goto out;
++ }
++ value = udev_device_get_sysattr_value(rport_dev, "port_name");
++ if (value)
++ ret = snprint_str(buff, len, value);
++ udev_device_unref(rport_dev);
++out:
++ if (!value)
++ ret = snprintf(buff, len, "[unknown]");
++ return ret;
++}
++
++
++static int
++snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
++{
++ if (pp->tgt_node_name[0] == '\0')
++ return snprintf(buff, len, "[undef]");
++ return snprint_str(buff, len, pp->tgt_node_name);
++}
++
++static int
+ snprint_path_checker (char * buff, size_t len, struct path * pp)
+ {
+ struct checker * c = &pp->checker;
+@@ -475,6 +553,10 @@ struct path_data pd[] = {
+ {'S', "size", 0, snprint_path_size},
+ {'z', "serial", 0, snprint_path_serial},
+ {'m', "multipath", 0, snprint_path_mpp},
++ {'N', "host WWNN", 0, snprint_host_wwnn},
++ {'n', "target WWNN", 0, snprint_tgt_wwnn},
++ {'R', "host WWPN", 0, snprint_host_wwpn},
++ {'r', "target WWPN", 0, snprint_tgt_wwpn},
+ {0, NULL, 0 , NULL}
+ };
+
--- /dev/null
+---
+ kpartx/devmapper.c | 3 ++-
+ libmultipath/alias.c | 1 +
+ libmultipath/blacklist.c | 7 +++++++
+ libmultipath/prioritizers/iet.c | 2 ++
+ libmultipath/prioritizers/weightedpath.c | 5 ++++-
+ libmultipath/regex.c | 5 ++++-
+ libmultipath/sysfs.c | 3 ++-
+ libmultipath/util.c | 2 +-
+ 8 files changed, 23 insertions(+), 5 deletions(-)
+
+Index: multipath-tools-130222/kpartx/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/kpartx/devmapper.c
++++ multipath-tools-130222/kpartx/devmapper.c
+@@ -132,8 +132,9 @@ dm_addmap (int task, const char *name, c
+ goto addout;
+ r = dm_task_run (dmt);
+
+- addout:
++addout:
+ dm_task_destroy (dmt);
++ free(prefixed_uuid);
+
+ return r;
+ }
+Index: multipath-tools-130222/libmultipath/alias.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/alias.c
++++ multipath-tools-130222/libmultipath/alias.c
+@@ -328,6 +328,7 @@ get_user_friendly_alias(char *wwid, char
+ if (fflush(f) != 0) {
+ condlog(0, "cannot fflush bindings file stream : %s",
+ strerror(errno));
++ free(alias);
+ fclose(f);
+ return NULL;
+ }
+Index: multipath-tools-130222/libmultipath/blacklist.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/blacklist.c
++++ multipath-tools-130222/libmultipath/blacklist.c
+@@ -79,6 +79,8 @@ set_ble_device (vector blist, char * ven
+ if (regcomp(&ble->vendor_reg, vendor,
+ REG_EXTENDED|REG_NOSUB)) {
+ FREE(vendor);
++ if (product)
++ FREE(product);
+ return 1;
+ }
+ ble->vendor = vendor;
+@@ -87,6 +89,10 @@ set_ble_device (vector blist, char * ven
+ if (regcomp(&ble->product_reg, product,
+ REG_EXTENDED|REG_NOSUB)) {
+ FREE(product);
++ if (vendor) {
++ ble->vendor = NULL;
++ FREE(vendor);
++ }
+ return 1;
+ }
+ ble->product = product;
+@@ -189,6 +195,7 @@ setup_default_blist (struct config * con
+ STRDUP(hwe->bl_product),
+ ORIGIN_DEFAULT)) {
+ FREE(ble);
++ vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1);
+ return 1;
+ }
+ }
+Index: multipath-tools-130222/libmultipath/prioritizers/iet.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/iet.c
++++ multipath-tools-130222/libmultipath/prioritizers/iet.c
+@@ -109,6 +109,7 @@ int iet_prio(const char *dev, char * arg
+ ssize_t nchars = readlink(path, buffer, sizeof(buffer)-1);
+ if (nchars != -1) {
+ char *device;
++ buffer[nchars] = '\0';
+ device = find_regex(buffer,"(sd[a-z]+)");
+ // if device parsed is the right one
+ if (device!=NULL && strncmp(device, dev, strlen(device)) == 0) {
+@@ -118,6 +119,7 @@ int iet_prio(const char *dev, char * arg
+ if (ip!=NULL && strncmp(ip, preferredip, strlen(ip)) == 0) {
+ // high prio
+ free(ip);
++ free(device);
+ closedir(dir_p);
+ return 20;
+ }
+Index: multipath-tools-130222/libmultipath/prioritizers/weightedpath.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/prioritizers/weightedpath.c
++++ multipath-tools-130222/libmultipath/prioritizers/weightedpath.c
+@@ -61,8 +61,10 @@ int prio_path_weight(struct path *pp, ch
+ regex = get_next_string(&temp, split_char);
+
+ /* Return default priority if the argument is not parseable */
+- if (!regex)
++ if (!regex) {
++ FREE(arg);
+ return priority;
++ }
+
+ if (!strcmp(regex, HBTL)) {
+ sprintf(path, "%d:%d:%d:%d", pp->sg_id.host_no,
+@@ -72,6 +74,7 @@ int prio_path_weight(struct path *pp, ch
+ } else {
+ condlog(0, "%s: %s - Invalid arguments", pp->dev,
+ pp->prio.name);
++ FREE(arg);
+ return priority;
+ }
+
+Index: multipath-tools-130222/libmultipath/regex.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/regex.c
++++ multipath-tools-130222/libmultipath/regex.c
+@@ -3936,8 +3936,11 @@ int eflags;
+ regs.num_regs = nmatch;
+ regs.start = TALLOC(nmatch, regoff_t);
+ regs.end = TALLOC(nmatch, regoff_t);
+- if (regs.start == NULL || regs.end == NULL)
++ if (regs.start == NULL || regs.end == NULL) {
++ free(regs.start);
++ free(regs.end);
+ return (int) REG_NOMATCH;
++ }
+ }
+
+ /* Perform the searching operation. */
+Index: multipath-tools-130222/libmultipath/sysfs.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/sysfs.c
++++ multipath-tools-130222/libmultipath/sysfs.c
+@@ -88,7 +88,8 @@ ssize_t sysfs_attr_get_value(struct udev
+ } else if (size == value_len) {
+ condlog(4, "overflow while reading from %s", devpath);
+ size = 0;
+- }
++ } else
++ value[size] = '\0';
+
+ close(fd);
+ return size;
+Index: multipath-tools-130222/libmultipath/util.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/util.c
++++ multipath-tools-130222/libmultipath/util.c
+@@ -175,7 +175,7 @@ devt2devname (char *devname, int devname
+ sprintf(block_path,"/sys/dev/block/%u:%u", major, minor);
+ if (lstat(block_path, &statbuf) == 0) {
+ if (S_ISLNK(statbuf.st_mode) &&
+- readlink(block_path, dev, FILE_NAME_SIZE) > 0) {
++ readlink(block_path, dev, FILE_NAME_SIZE-1) > 0) {
+ char *p = strrchr(dev, '/');
+
+ if (!p) {
--- /dev/null
+---
+ libmultipath/config.h | 15 ++++++++-
+ libmultipath/configure.c | 2 -
+ libmultipath/discovery.c | 5 +--
+ multipath/main.c | 75 +++++++++++++++++++++++++----------------------
+ multipath/multipath.8 | 5 ++-
+ 5 files changed, 61 insertions(+), 41 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -23,6 +23,17 @@ enum devtypes {
+ DEV_DEVMAP
+ };
+
++enum mpath_cmds {
++ CMD_CREATE,
++ CMD_DRY_RUN,
++ CMD_LIST_SHORT,
++ CMD_LIST_LONG,
++ CMD_VALID_PATH,
++ CMD_REMOVE_WWID,
++ CMD_RESET_WWIDS,
++ CMD_ADD_WWID,
++};
++
+ struct hwentry {
+ char * vendor;
+ char * product;
+@@ -79,8 +90,7 @@ struct mpentry {
+
+ struct config {
+ int verbosity;
+- int dry_run;
+- int list;
++ enum mpath_cmds cmd;
+ int pgpolicy_flag;
+ int pgpolicy;
+ enum devtypes dev_type;
+@@ -98,6 +108,7 @@ struct config {
+ int max_fds;
+ int force_reload;
+ int queue_without_daemon;
++ int ignore_wwids;
+ int checker_timeout;
+ int daemon;
+ int flush_on_last_del;
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -85,7 +85,7 @@ usage (char * progname)
+ {
+ fprintf (stderr, VERSION_STRING);
+ fprintf (stderr, "Usage:\n");
+- fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
++ fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-T tm:val] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
+ fprintf (stderr, " %s -t\n", progname);
+@@ -109,6 +109,7 @@ usage (char * progname)
+ " -d dry run, do not create or update devmaps\n" \
+ " -t dump internal hardware table\n" \
+ " -r force devmap reload\n" \
++ " -i ignore wwids file\n" \
+ " -B treat the bindings file as read only\n" \
+ " -p policy failover|multibus|group_by_serial|group_by_prio\n" \
+ " -b fil bindings file location\n" \
+@@ -209,18 +210,19 @@ get_dm_mpvec (vector curmp, vector pathv
+ * If not in "fast list mode", we need to fetch information
+ * about them
+ */
+- if (conf->list != 1)
++ if (conf->cmd != CMD_LIST_SHORT)
+ update_paths(mpp);
+
+- if (conf->list > 1)
++ if (conf->cmd == CMD_LIST_LONG)
+ mpp->bestpg = select_path_group(mpp);
+
+ disassemble_status(status, mpp);
+
+- if (conf->list)
++ if (conf->cmd == CMD_LIST_SHORT ||
++ conf->cmd == CMD_LIST_LONG)
+ print_multipath_topology(mpp, conf->verbosity);
+
+- if (!conf->dry_run)
++ if (conf->cmd == CMD_CREATE)
+ reinstate_paths(mpp);
+ }
+ return 0;
+@@ -262,10 +264,11 @@ configure (void)
+ /*
+ * if we have a blacklisted device parameter, exit early
+ */
+- if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 &&
++ if (dev && conf->dev_type == DEV_DEVNODE &&
++ conf->cmd != CMD_REMOVE_WWID &&
+ (filter_devnode(conf->blist_devnode,
+ conf->elist_devnode, dev) > 0)) {
+- if (conf->dry_run == 2)
++ if (conf->cmd == CMD_VALID_PATH)
+ printf("%s is not a valid multipath device path\n",
+ conf->dev);
+ goto out;
+@@ -278,13 +281,13 @@ configure (void)
+ int failed = get_refwwid(conf->dev, conf->dev_type, pathvec,
+ &refwwid);
+ if (!refwwid) {
+- if (failed == 2 && conf->dry_run == 2)
++ if (failed == 2 && conf->cmd == CMD_VALID_PATH)
+ printf("%s is not a valid multipath device path\n", conf->dev);
+ else
+ condlog(3, "scope is nul");
+ goto out;
+ }
+- if (conf->dry_run == 3) {
++ if (conf->cmd == CMD_REMOVE_WWID) {
+ r = remove_wwid(refwwid);
+ if (r == 0)
+ printf("wwid '%s' removed\n", refwwid);
+@@ -295,7 +298,7 @@ configure (void)
+ }
+ goto out;
+ }
+- if (conf->dry_run == 5) {
++ if (conf->cmd == CMD_ADD_WWID) {
+ r = remember_wwid(refwwid);
+ if (r == 0)
+ printf("wwid '%s' added\n", refwwid);
+@@ -305,13 +308,13 @@ configure (void)
+ goto out;
+ }
+ condlog(3, "scope limited to %s", refwwid);
+- if (conf->dry_run == 2) {
+- if (check_wwids_file(refwwid, 0) == 0){
+- printf("%s is a valid multipath device path\n", conf->dev);
++ if (conf->cmd == CMD_VALID_PATH) {
++ if (conf->ignore_wwids ||
++ check_wwids_file(refwwid, 0) == 0)
+ r = 0;
+- }
+- else
+- printf("%s is not a valid multipath device path\n", conf->dev);
++
++ printf("%s %s a valid multipath device path\n",
++ conf->dev, r == 0 ? "is" : "is not");
+ goto out;
+ }
+ }
+@@ -319,13 +322,13 @@ configure (void)
+ /*
+ * get a path list
+ */
+- if (conf->dev && !conf->list)
++ if (conf->dev)
+ di_flag = DI_WWID;
+
+- if (conf->list > 1)
++ if (conf->cmd == CMD_LIST_LONG)
+ /* extended path info '-ll' */
+ di_flag |= DI_SYSFS | DI_CHECKER;
+- else if (conf->list)
++ else if (conf->cmd == CMD_LIST_SHORT)
+ /* minimum path info '-l' */
+ di_flag |= DI_SYSFS;
+ else
+@@ -345,7 +348,7 @@ configure (void)
+
+ filter_pathvec(pathvec, refwwid);
+
+- if (conf->list) {
++ if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) {
+ r = 0;
+ goto out;
+ }
+@@ -440,7 +443,7 @@ main (int argc, char *argv[])
+ int r = 1;
+ long int timestamp = -1;
+ int valid = -1;
+- while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BritT:qwW")) != EOF ) {
+ switch(arg) {
+ case 'T':
+ if (optarg[0] == ':')
+@@ -476,7 +479,7 @@ main (int argc, char *argv[])
+ if (dm_prereq())
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BritT:qwW")) != EOF ) {
+ switch(arg) {
+ case 1: printf("optarg : %s\n",optarg);
+ break;
+@@ -499,11 +502,11 @@ main (int argc, char *argv[])
+ conf->allow_queueing = 1;
+ break;
+ case 'c':
+- conf->dry_run = 2;
++ conf->cmd = CMD_VALID_PATH;
+ break;
+ case 'd':
+- if (!conf->dry_run)
+- conf->dry_run = 1;
++ if (conf->cmd == CMD_CREATE)
++ conf->cmd = CMD_DRY_RUN;
+ break;
+ case 'f':
+ conf->remove = FLUSH_ONE;
+@@ -512,11 +515,10 @@ main (int argc, char *argv[])
+ conf->remove = FLUSH_ALL;
+ break;
+ case 'l':
+- conf->list = 1;
+- conf->dry_run = 1;
+-
+ if (optarg && !strncmp(optarg, "l", 1))
+- conf->list++;
++ conf->cmd = CMD_LIST_LONG;
++ else
++ conf->cmd = CMD_LIST_SHORT;
+
+ break;
+ case 'M':
+@@ -535,6 +537,9 @@ main (int argc, char *argv[])
+ case 'r':
+ conf->force_reload = 1;
+ break;
++ case 'i':
++ conf->ignore_wwids = 1;
++ break;
+ case 't':
+ r = dump_config();
+ goto out;
+@@ -548,13 +553,13 @@ main (int argc, char *argv[])
+ usage(argv[0]);
+ exit(0);
+ case 'w':
+- conf->dry_run = 3;
++ conf->cmd = CMD_REMOVE_WWID;
+ break;
+ case 'W':
+- conf->dry_run = 4;
++ conf->cmd = CMD_RESET_WWIDS;
+ break;
+ case 'a':
+- conf->dry_run = 5;
++ conf->cmd = CMD_ADD_WWID;
+ break;
+ case ':':
+ fprintf(stderr, "Missing option argument\n");
+@@ -600,16 +605,16 @@ main (int argc, char *argv[])
+ }
+ dm_init();
+
+- if (conf->dry_run == 2 &&
++ if (conf->cmd == CMD_VALID_PATH &&
+ (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
+ condlog(0, "the -c option requires a path to check");
+ goto out;
+ }
+- if (conf->dry_run == 3 && !conf->dev) {
++ if (conf->cmd == CMD_REMOVE_WWID && !conf->dev) {
+ condlog(0, "the -w option requires a device");
+ goto out;
+ }
+- if (conf->dry_run == 4) {
++ if (conf->cmd == CMD_RESET_WWIDS) {
+ struct multipath * mpp;
+ int i;
+ vector curmp;
+Index: multipath-tools-130222/multipath/multipath.8
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.8
++++ multipath-tools-130222/multipath/multipath.8
+@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco
+ .RB [\| \-b\ \c
+ .IR bindings_file \|]
+ .RB [\| \-d \|]
+-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-A | \-w | \-W \|]
++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-r | \-a | \-A | \-w | \-W \|]
+ .RB [\| \-p\ \c
+ .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
+ .RB [\| device \|]
+@@ -55,6 +55,9 @@ print internal hardware table to stdout
+ .B \-r
+ force devmap reload
+ .TP
++.B \-i
++ignore wwids file when processing devices
++.TP
+ .B \-B
+ treat the bindings file as read only
+ .TP
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -580,7 +580,7 @@ domap (struct multipath * mpp, char * pa
+ /*
+ * last chance to quit before touching the devmaps
+ */
+- if (conf->dry_run && mpp->action != ACT_NOTHING) {
++ if (conf->cmd == CMD_DRY_RUN && mpp->action != ACT_NOTHING) {
+ print_multipath_topology(mpp, conf->verbosity);
+ return DOMAP_DRY;
+ }
+Index: multipath-tools-130222/libmultipath/discovery.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/discovery.c
++++ multipath-tools-130222/libmultipath/discovery.c
+@@ -54,7 +54,8 @@ store_pathinfo (vector pathvec, vector h
+ }
+ pp->udev = udev_device_ref(udevice);
+ err = pathinfo(pp, hwtable,
+- (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST));
++ (conf->cmd == CMD_REMOVE_WWID)? flag :
++ (flag | DI_BLACKLIST));
+ if (err)
+ goto out;
+
+@@ -1101,7 +1102,7 @@ get_uid (struct path * pp)
+
+ memset(pp->wwid, 0, WWID_SIZE);
+ value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
+- if ((!value || strlen(value) == 0) && conf->dry_run == 2)
++ if ((!value || strlen(value) == 0) && conf->cmd == CMD_VALID_PATH)
+ value = getenv(pp->uid_attribute);
+ if (value && strlen(value)) {
+ size_t len = WWID_SIZE;
--- /dev/null
+---
+ libmultipath/config.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ libmultipath/config.h | 1
+ libmultipath/dict.c | 38 +++++++++++++++++++++++++++++
+ 3 files changed, 102 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -113,6 +113,8 @@ find_hwe (vector hwtable, char * vendor,
+ * continuing to the generic entries
+ */
+ vector_foreach_slot_backwards (hwtable, tmp, i) {
++ if (tmp->all_devs == 1)
++ continue;
+ if (hwe_regmatch(tmp, &hwe))
+ continue;
+ ret = tmp;
+@@ -348,6 +350,62 @@ merge_hwe (struct hwentry * dst, struct
+ return 0;
+ }
+
++#define overwrite_str(s) \
++do { \
++ if (src->s) { \
++ if (dst->s) \
++ FREE(dst->s); \
++ if (!(dst->s = set_param_str(src->s))) \
++ return 1; \
++ } \
++} while(0)
++
++#define overwrite_num(s) \
++do { \
++ if (src->s) \
++ dst->s = src->s; \
++} while(0)
++
++static int
++overwrite_hwe (struct hwentry * dst, struct hwentry * src)
++{
++ overwrite_str(vendor);
++ overwrite_str(product);
++ overwrite_str(revision);
++ overwrite_str(uid_attribute);
++ overwrite_str(features);
++ overwrite_str(hwhandler);
++ overwrite_str(selector);
++ overwrite_str(checker_name);
++ overwrite_str(prio_name);
++ overwrite_str(prio_args);
++ overwrite_str(alias_prefix);
++ overwrite_str(bl_product);
++ overwrite_num(pgpolicy);
++ overwrite_num(pgfailback);
++ overwrite_num(rr_weight);
++ overwrite_num(no_path_retry);
++ overwrite_num(minio);
++ overwrite_num(minio_rq);
++ overwrite_num(pg_timeout);
++ overwrite_num(flush_on_last_del);
++ overwrite_num(fast_io_fail);
++ overwrite_num(dev_loss);
++ overwrite_num(user_friendly_names);
++ overwrite_num(retain_hwhandler);
++ overwrite_num(detect_prio);
++
++ /*
++ * Make sure features is consistent with
++ * no_path_retry
++ */
++ if (dst->no_path_retry == NO_PATH_RETRY_FAIL)
++ remove_feature(&dst->features, "queue_if_no_path");
++ else if (dst->no_path_retry != NO_PATH_RETRY_UNDEF)
++ add_feature(&dst->features, "queue_if_no_path");
++ return 0;
++}
++
+ int
+ store_hwe (vector hwtable, struct hwentry * dhwe)
+ {
+@@ -431,7 +489,11 @@ restart:
+ break;
+ j = n;
+ vector_foreach_slot_after(hw, hwe2, j) {
+- if (conf->hw_strmatch) {
++ if (hwe2->all_devs == 1) {
++ overwrite_hwe(hwe1, hwe2);
++ continue;
++ }
++ else if (conf->hw_strmatch) {
+ if (hwe_strmatch(hwe2, hwe1))
+ continue;
+ }
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -47,6 +47,7 @@ struct hwentry {
+ char * prio_args;
+ char * alias_prefix;
+
++ int all_devs;
+ int pgpolicy;
+ int pgfailback;
+ int rr_weight;
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -918,6 +918,32 @@ device_handler(vector strvec)
+ }
+
+ static int
++all_devs_handler(vector strvec)
++{
++ char * buff;
++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
++
++ if (!hwe)
++ return 1;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ hwe->all_devs = 0;
++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "1")))
++ hwe->all_devs = 1;
++ else
++ hwe->all_devs = 0;
++
++ FREE(buff);
++ return 0;
++}
++
++static int
+ vendor_handler(vector strvec)
+ {
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+@@ -2182,6 +2208,17 @@ snprint_hw_dev_loss(char * buff, int len
+ }
+
+ static int
++snprint_hw_all_devs (char *buff, int len, void *data)
++{
++ struct hwentry * hwe = (struct hwentry *)data;
++
++ if (!hwe->all_devs)
++ return 0;
++
++ return snprintf(buff, len, "yes");
++}
++
++static int
+ snprint_hw_vendor (char * buff, int len, void * data)
+ {
+ struct hwentry * hwe = (struct hwentry *)data;
+@@ -2968,6 +3005,7 @@ init_keywords(void)
+ install_keyword_root("devices", &devices_handler);
+ install_keyword_multi("device", &device_handler, NULL);
+ install_sublevel();
++ install_keyword("all_devs", &all_devs_handler, &snprint_hw_all_devs);
+ install_keyword("vendor", &vendor_handler, &snprint_hw_vendor);
+ install_keyword("product", &product_handler, &snprint_hw_product);
+ install_keyword("revision", &revision_handler, &snprint_hw_revision);
--- /dev/null
+---
+ multipath/main.c | 25 ++++++++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipath/main.c
++++ multipath-tools-130222/multipath/main.c
+@@ -198,6 +198,9 @@ get_dm_mpvec (vector curmp, vector pathv
+ continue;
+ }
+
++ if (conf->cmd == CMD_VALID_PATH)
++ continue;
++
+ dm_get_map(mpp->alias, &mpp->size, params);
+ condlog(3, "params = %s", params);
+ dm_get_status(mpp->alias, status);
+@@ -308,7 +311,13 @@ configure (void)
+ goto out;
+ }
+ condlog(3, "scope limited to %s", refwwid);
+- if (conf->cmd == CMD_VALID_PATH) {
++ /* If you are ignoring the wwids file and find_multipaths is
++ * set, you need to actually check if there are two available
++ * paths to determine if this path should be multipathed. To
++ * do this, we put off the check until after discovering all
++ * the paths */
++ if (conf->cmd == CMD_VALID_PATH &&
++ (!conf->find_multipaths || !conf->ignore_wwids)) {
+ if (conf->ignore_wwids ||
+ check_wwids_file(refwwid, 0) == 0)
+ r = 0;
+@@ -348,6 +357,20 @@ configure (void)
+
+ filter_pathvec(pathvec, refwwid);
+
++
++ if (conf->cmd == CMD_VALID_PATH) {
++ /* This only happens if find_multipaths is and
++ * ignore_wwids is set.
++ * If there is currently a multipath device matching
++ * the refwwid, or there is more than one path matching
++ * the refwwid, then the path is valid */
++ if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
++ r = 0;
++ printf("%s %s a valid multipath device path\n",
++ conf->dev, r == 0 ? "is" : "is not");
++ goto out;
++ }
++
+ if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) {
+ r = 0;
+ goto out;
--- /dev/null
+---
+ libmultipath/print.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/print.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/print.c
++++ multipath-tools-130222/libmultipath/print.c
+@@ -510,6 +510,16 @@ snprint_tgt_wwnn (char * buff, size_t le
+ }
+
+ static int
++snprint_host_adapter (char * buff, size_t len, struct path * pp)
++{
++ char adapter[SLOT_NAME_SIZE];
++
++ if (sysfs_get_host_adapter_name(pp, adapter))
++ return snprintf(buff, len, "[undef]");
++ return snprint_str(buff, len, adapter);
++}
++
++static int
+ snprint_path_checker (char * buff, size_t len, struct path * pp)
+ {
+ struct checker * c = &pp->checker;
+@@ -557,6 +567,7 @@ struct path_data pd[] = {
+ {'n', "target WWNN", 0, snprint_tgt_wwnn},
+ {'R', "host WWPN", 0, snprint_host_wwpn},
+ {'r', "target WWPN", 0, snprint_tgt_wwpn},
++ {'a', "host adapter", 0, snprint_host_adapter},
+ {0, NULL, 0 , NULL}
+ };
+
--- /dev/null
+---
+ multipath/mpathconf | 26 ++++++++++++++++++++------
+ 1 file changed, 20 insertions(+), 6 deletions(-)
+
+Index: multipath-tools-130222/multipath/mpathconf
+===================================================================
+--- multipath-tools-130222.orig/multipath/mpathconf
++++ multipath-tools-130222/multipath/mpathconf
+@@ -19,10 +19,27 @@
+
+ unset ENABLE FIND FRIENDLY MODULE MULTIPATHD HAVE_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_DEFAULTS HAVE_FRIENDLY HAVE_MULTIPATHD HAVE_MODULE SHOW_STATUS CHANGED_CONFIG
+
+-DEFAULT_CONFIGFILE="/usr/share/doc/device-mapper-multipath-0.4.9/multipath.conf"
++DEFAULT_CONFIG="# device-mapper-multipath configuration file
++
++# For a complete list of the default configuration values, run either:
++# # multipath -t
++# or
++# # multipathd show config
++
++# For a list of configuration options with descriptions, see the
++# multipath.conf man page.
++
++# For an example configuration file, see:
++# /user/share/doc/device-mapper-multipath/multipath.conf
++
++defaults {
++ user_friendly_names yes
++ find_multipaths yes
++}"
++
+ CONFIGFILE="/etc/multipath.conf"
+ MULTIPATHDIR="/etc/multipath"
+-TMPFILE=/etc/multipath/.multipath.conf.tmp
++TMPFILE="/etc/multipath/.multipath.conf.tmp"
+
+ function usage
+ {
+@@ -134,12 +151,9 @@ if [ ! -d "$MULTIPATHDIR" ]; then
+ fi
+
+ rm $TMPFILE 2> /dev/null
++echo "$DEFAULT_CONFIG" > $TMPFILE
+ if [ -f "$CONFIGFILE" ]; then
+ cp $CONFIGFILE $TMPFILE
+-elif [ -f "$DEFAULT_CONFIGFILE" ]; then
+- cp $DEFAULT_CONFIGFILE $TMPFILE
+-else
+- touch $TMPFILE
+ fi
+
+ if grep -q "^blacklist[[:space:]]*{" $TMPFILE ; then
--- /dev/null
+---
+ libmultipath/devmapper.c | 155 ++++++++++++++++++-----------------------------
+ 1 file changed, 61 insertions(+), 94 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -1006,8 +1006,9 @@ bad:
+ return NULL;
+ }
+
+-int
+-dm_remove_partmaps (const char * mapname, int need_sync)
++static int
++do_foreach_partmaps (const char * mapname, int (*partmap_func)(char *, void *),
++ void *data)
+ {
+ struct dm_task *dmt;
+ struct dm_names *names;
+@@ -1059,26 +1060,8 @@ dm_remove_partmaps (const char * mapname
+ */
+ strstr(params, dev_t)
+ ) {
+- /*
+- * then it's a kpartx generated partition.
+- * remove it.
+- */
+- /*
+- * if the opencount is 0 maybe some other
+- * partitions depend on it.
+- */
+- if (dm_get_opencount(names->name)) {
+- dm_remove_partmaps(names->name, need_sync);
+- if (dm_get_opencount(names->name)) {
+- condlog(2, "%s: map in use",
+- names->name);
+- goto out;
+- }
+- }
+- condlog(4, "partition map %s removed",
+- names->name);
+- dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name,
+- need_sync, 0);
++ if (partmap_func(names->name, data) != 0)
++ goto out;
+ }
+
+ next = names->next;
+@@ -1091,6 +1074,35 @@ out:
+ return r;
+ }
+
++struct remove_data {
++ int need_sync;
++};
++
++static int
++remove_partmap(char *name, void *data)
++{
++ struct remove_data *rd = (struct remove_data *)data;
++
++ if (dm_get_opencount(name)) {
++ dm_remove_partmaps(name, rd->need_sync);
++ if (dm_get_opencount(name)) {
++ condlog(2, "%s: map in use", name);
++ return 1;
++ }
++ }
++ condlog(4, "partition map %s removed", name);
++ dm_simplecmd_flush(DM_DEVICE_REMOVE, name,
++ rd->need_sync, 0);
++ return 0;
++}
++
++int
++dm_remove_partmaps (const char * mapname, int need_sync)
++{
++ struct remove_data rd = { need_sync };
++ return do_foreach_partmaps(mapname, remove_partmap, &rd);
++}
++
+ static struct dm_info *
+ alloc_dminfo (void)
+ {
+@@ -1140,86 +1152,41 @@ out:
+ return r;
+ }
+
+-int
+-dm_rename_partmaps (char * old, char * new)
++struct rename_data {
++ char *old;
++ char *new;
++ char *delim;
++};
++
++static int
++rename_partmap (char *name, void *data)
+ {
+- struct dm_task *dmt;
+- struct dm_names *names;
+- unsigned next = 0;
+ char buff[PARAMS_SIZE];
+- unsigned long long size;
+- char dev_t[32];
+- int r = 1;
+ int offset;
+- char *delim;
+-
+- if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+- return 1;
++ struct rename_data *rd = (struct rename_data *)data;
+
+- dm_task_no_open_count(dmt);
+-
+- if (!dm_task_run(dmt))
+- goto out;
+-
+- if (!(names = dm_task_get_names(dmt)))
+- goto out;
+-
+- if (!names->dev) {
+- r = 0; /* this is perfectly valid */
+- goto out;
+- }
++ if (strncmp(name, rd->old, strlen(rd->old)) != 0)
++ return 0;
++ 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);
++ condlog(4, "partition map %s renamed", name);
++ return 0;
++}
+
+- if (dm_dev_t(old, &dev_t[0], 32))
+- goto out;
++int
++dm_rename_partmaps (char * old, char * new)
++{
++ struct rename_data rd;
+
++ rd.old = old;
++ rd.new = new;
+ if (isdigit(new[strlen(new)-1]))
+- delim = "p";
++ rd.delim = "p";
+ else
+- delim = "";
+-
+- do {
+- if (
+- /*
+- * if devmap target is "linear"
+- */
+- (dm_type(names->name, TGT_PART) > 0) &&
+-
+- /*
+- * and the multipath mapname and the part mapname start
+- * the same
+- */
+- !strncmp(names->name, old, strlen(old)) &&
+-
+- /*
+- * and we can fetch the map table from the kernel
+- */
+- !dm_get_map(names->name, &size, &buff[0]) &&
+-
+- /*
+- * and the table maps over the multipath map
+- */
+- strstr(buff, dev_t)
+- ) {
+- /*
+- * then it's a kpartx generated partition.
+- * Rename it.
+- */
+- for (offset = strlen(old); names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do nothing */
+- snprintf(buff, PARAMS_SIZE, "%s%s%s",
+- new, delim, names->name + offset);
+- dm_rename(names->name, buff);
+- condlog(4, "partition map %s renamed",
+- names->name);
+- }
+-
+- next = names->next;
+- names = (void *) names + next;
+- } while (next);
+-
+- r = 0;
+-out:
+- dm_task_destroy (dmt);
+- return r;
++ rd.delim = "";
++ return do_foreach_partmaps(old, rename_partmap, &rd);
+ }
+
+ int
--- /dev/null
+---
+ libmultipath/Makefile | 6 ++
+ libmultipath/config.c | 3 +
+ libmultipath/config.h | 3 +
+ libmultipath/configure.c | 1
+ libmultipath/defaults.h | 1
+ libmultipath/devmapper.c | 130 +++++++++++++++++++++++++++++++++++++++------
+ libmultipath/devmapper.h | 12 ++--
+ libmultipath/dict.c | 116 +++++++++++++++++++++++++++++++++++++++-
+ libmultipath/propsel.c | 28 +++++++++
+ libmultipath/propsel.h | 1
+ libmultipath/structs.h | 8 ++
+ libmultipath/structs_vec.c | 3 -
+ multipath/multipath.conf.5 | 14 ++++
+ multipathd/main.c | 23 +++++--
+ 14 files changed, 322 insertions(+), 27 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -337,6 +337,7 @@ merge_hwe (struct hwentry * dst, struct
+ merge_num(user_friendly_names);
+ merge_num(retain_hwhandler);
+ merge_num(detect_prio);
++ merge_num(deferred_remove);
+
+ /*
+ * Make sure features is consistent with
+@@ -394,6 +395,7 @@ overwrite_hwe (struct hwentry * dst, str
+ overwrite_num(user_friendly_names);
+ overwrite_num(retain_hwhandler);
+ overwrite_num(detect_prio);
++ overwrite_num(deferred_remove);
+
+ /*
+ * Make sure features is consistent with
+@@ -617,6 +619,7 @@ load_config (char * file, struct udev *u
+ conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
+ conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
+ conf->detect_prio = DEFAULT_DETECT_PRIO;
++ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
+ conf->hw_strmatch = 0;
+ conf->force_sync = 0;
+
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -61,6 +61,7 @@ struct hwentry {
+ int user_friendly_names;
+ int retain_hwhandler;
+ int detect_prio;
++ int deferred_remove;
+ char * bl_product;
+ };
+
+@@ -84,6 +85,7 @@ struct mpentry {
+ int flush_on_last_del;
+ int attribute_flags;
+ int user_friendly_names;
++ int deferred_remove;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+@@ -128,6 +130,7 @@ struct config {
+ int retain_hwhandler;
+ int detect_prio;
+ int force_sync;
++ int deferred_remove;
+ unsigned int version[3];
+
+ char * dev;
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -290,6 +290,7 @@ setup_map (struct multipath * mpp, char
+ select_dev_loss(mpp);
+ select_reservation_key(mpp);
+ select_retain_hwhandler(mpp);
++ select_deferred_remove(mpp);
+
+ sysfs_set_scsi_tmo(mpp);
+ /*
+Index: multipath-tools-130222/libmultipath/defaults.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/defaults.h
++++ multipath-tools-130222/libmultipath/defaults.h
+@@ -19,6 +19,7 @@
+ #define DEFAULT_FAST_IO_FAIL 5
+ #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
+ #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
++#define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF
+
+ #define DEFAULT_CHECKINT 5
+ #define MAX_CHECKINT(a) (a << 2)
+Index: multipath-tools-130222/libmultipath/devmapper.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.c
++++ multipath-tools-130222/libmultipath/devmapper.c
+@@ -103,7 +103,9 @@ dm_lib_prereq (void)
+ {
+ char version[64];
+ int v[3];
+-#if defined(DM_SUBSYSTEM_UDEV_FLAG0)
++#if defined(LIBDM_API_DEFERRED)
++ int minv[3] = {1, 2, 89};
++#elif defined(DM_SUBSYSTEM_UDEV_FLAG0)
+ int minv[3] = {1, 2, 82};
+ #elif defined(LIBDM_API_COOKIE)
+ int minv[3] = {1, 2, 38};
+@@ -202,7 +204,7 @@ dm_prereq (void)
+ }
+
+ static int
+-dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags) {
++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));
+@@ -220,7 +222,10 @@ dm_simplecmd (int task, const char *name
+ if (no_flush)
+ dm_task_no_flush(dmt); /* for DM_DEVICE_SUSPEND/RESUME */
+ #endif
+-
++#ifdef LIBDM_API_DEFERRED
++ if (deferred_remove)
++ dm_task_deferred_remove(dmt);
++#endif
+ if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags))
+ goto out;
+ r = dm_task_run (dmt);
+@@ -232,12 +237,18 @@ dm_simplecmd (int task, const char *name
+
+ extern int
+ dm_simplecmd_flush (int task, const char *name, int needsync, uint16_t udev_flags) {
+- return dm_simplecmd(task, name, 0, needsync, udev_flags);
++ return dm_simplecmd(task, name, 0, needsync, udev_flags, 0);
+ }
+
+ extern int
+ dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags) {
+- return dm_simplecmd(task, name, 1, 1, udev_flags);
++ return dm_simplecmd(task, name, 1, 1, udev_flags, 0);
++}
++
++extern int
++dm_device_remove (const char *name, int needsync, int deferred_remove) {
++ return dm_simplecmd(DM_DEVICE_REMOVE, name, 0, needsync, 0,
++ deferred_remove);
+ }
+
+ extern int
+@@ -653,7 +664,7 @@ out:
+ }
+
+ extern int
+-_dm_flush_map (const char * mapname, int need_sync)
++_dm_flush_map (const char * mapname, int need_sync, int deferred_remove)
+ {
+ int r;
+
+@@ -663,23 +674,46 @@ _dm_flush_map (const char * mapname, int
+ if (dm_type(mapname, TGT_MPATH) <= 0)
+ return 0; /* nothing to do */
+
+- if (dm_remove_partmaps(mapname, need_sync))
++ if (dm_remove_partmaps(mapname, need_sync, deferred_remove))
+ return 1;
+
+- if (dm_get_opencount(mapname)) {
++ if (!deferred_remove && dm_get_opencount(mapname)) {
+ condlog(2, "%s: map in use", mapname);
+ return 1;
+ }
+
+- r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync, 0);
++ r = dm_device_remove(mapname, need_sync, deferred_remove);
+
+ if (r) {
++ if (deferred_remove && dm_map_present(mapname)) {
++ condlog(4, "multipath map %s remove deferred",
++ mapname);
++ return 2;
++ }
+ condlog(4, "multipath map %s removed", mapname);
+ return 0;
+ }
+ return 1;
+ }
+
++#ifdef LIBDM_API_DEFERRED
++
++int
++dm_flush_map_nopaths(const char * mapname, int deferred_remove)
++{
++ return _dm_flush_map(mapname, 1, deferred_remove);
++}
++
++#else
++
++int
++dm_flush_map_nopaths(const char * mapname, int deferred_remove)
++{
++ return _dm_flush_map(mapname, 1, 0);
++}
++
++#endif
++
+ extern int
+ dm_suspend_and_flush_map (const char * mapname)
+ {
+@@ -1076,6 +1110,7 @@ out:
+
+ struct remove_data {
+ int need_sync;
++ int deferred_remove;
+ };
+
+ static int
+@@ -1084,25 +1119,90 @@ remove_partmap(char *name, void *data)
+ struct remove_data *rd = (struct remove_data *)data;
+
+ if (dm_get_opencount(name)) {
+- dm_remove_partmaps(name, rd->need_sync);
+- if (dm_get_opencount(name)) {
++ dm_remove_partmaps(name, rd->need_sync, rd->deferred_remove);
++ if (!rd->deferred_remove && dm_get_opencount(name)) {
+ condlog(2, "%s: map in use", name);
+ return 1;
+ }
+ }
+ condlog(4, "partition map %s removed", name);
+- dm_simplecmd_flush(DM_DEVICE_REMOVE, name,
+- rd->need_sync, 0);
++ dm_device_remove(name, rd->need_sync, rd->deferred_remove);
+ return 0;
+ }
+
+ int
+-dm_remove_partmaps (const char * mapname, int need_sync)
++dm_remove_partmaps (const char * mapname, int need_sync, int deferred_remove)
+ {
+- struct remove_data rd = { need_sync };
++ struct remove_data rd = { need_sync, deferred_remove };
+ return do_foreach_partmaps(mapname, remove_partmap, &rd);
+ }
+
++#ifdef LIBDM_API_DEFERRED
++
++static int
++cancel_remove_partmap (char *name, void *unused)
++{
++ if (dm_message(name, "@cancel_deferred_remove") != 0)
++ condlog(0, "%s: can't cancel deferred remove: %s", name,
++ strerror(errno));
++ return 0;
++}
++
++static int
++dm_get_deferred_remove (char * mapname)
++{
++ int r = -1;
++ struct dm_task *dmt;
++ struct dm_info info;
++
++ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
++ return -1;
++
++ if (!dm_task_set_name(dmt, mapname))
++ goto out;
++
++ if (!dm_task_run(dmt))
++ goto out;
++
++ if (!dm_task_get_info(dmt, &info))
++ goto out;
++
++ r = info.deferred_remove;
++out:
++ dm_task_destroy(dmt);
++ return r;
++}
++
++int
++dm_cancel_deferred_remove (struct multipath *mpp)
++{
++ int r = 0;
++
++ if (!dm_get_deferred_remove(mpp->alias))
++ return 0;
++ if (mpp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS)
++ mpp->deferred_remove = DEFERRED_REMOVE_ON;
++
++ do_foreach_partmaps(mpp->alias, cancel_remove_partmap, NULL);
++ r = dm_message(mpp->alias, "@cancel_deferred_remove");
++ if (r)
++ condlog(0, "%s: can't cancel deferred remove: %s", mpp->alias,
++ strerror(errno));
++ else
++ condlog(2, "%s: canceled deferred remove", mpp->alias);
++ return r;
++}
++
++#else
++
++int
++dm_cancel_deferred_remove (struct multipath *mpp)
++{
++ return 0;
++}
++
++#endif
++
+ static struct dm_info *
+ alloc_dminfo (void)
+ {
+Index: multipath-tools-130222/libmultipath/devmapper.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/devmapper.h
++++ multipath-tools-130222/libmultipath/devmapper.h
+@@ -17,15 +17,18 @@ int dm_prereq (void);
+ int dm_drv_version (unsigned int * version, char * str);
+ int dm_simplecmd_flush (int, const char *, int, uint16_t);
+ int dm_simplecmd_noflush (int, const char *, uint16_t);
++int dm_device_remove (const char *, int, int);
+ int dm_addmap_create (struct multipath *mpp, char *params);
+ int dm_addmap_reload (struct multipath *mpp, char *params);
+ int dm_map_present (const char *);
+ int dm_get_map(const char *, unsigned long long *, char *);
+ int dm_get_status(char *, char *);
+ int dm_type(const char *, char *);
+-int _dm_flush_map (const char *, int);
+-#define dm_flush_map(mapname) _dm_flush_map(mapname, 1)
+-#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0)
++int _dm_flush_map (const char *, int, int);
++int dm_flush_map_nopaths(const char * mapname, int deferred_remove);
++#define dm_flush_map(mapname) _dm_flush_map(mapname, 1, 0)
++#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0, 0)
++int dm_cancel_deferred_remove(struct multipath *mpp);
+ int dm_suspend_and_flush_map(const char * mapname);
+ int dm_flush_maps (void);
+ int dm_fail_path(char * mapname, char * path);
+@@ -40,7 +43,8 @@ int dm_geteventnr (char *name);
+ int dm_get_major (char *name);
+ int dm_get_minor (char *name);
+ char * dm_mapname(int major, int minor);
+-int dm_remove_partmaps (const char * mapname, int need_sync);
++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 (char * old, char * new);
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -738,6 +738,29 @@ def_force_sync_handler(vector strvec)
+ return 0;
+ }
+
++static int
++def_deferred_remove_handler(vector strvec)
++{
++ char * buff;
++
++ buff = set_value(strvec);
++
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ conf->deferred_remove = DEFERRED_REMOVE_OFF;
++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "1")))
++ conf->deferred_remove = DEFERRED_REMOVE_ON;
++ else
++ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * blacklist block handlers
+ */
+@@ -1445,6 +1468,33 @@ hw_detect_prio_handler(vector strvec)
+ return 0;
+ }
+
++static int
++hw_deferred_remove_handler(vector strvec)
++{
++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
++ char * buff;
++
++ if (!hwe)
++ return 1;
++
++ buff = set_value(strvec);
++
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ hwe->deferred_remove = DEFERRED_REMOVE_OFF;
++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "1")))
++ hwe->deferred_remove = DEFERRED_REMOVE_ON;
++ else
++ hwe->deferred_remove = DEFERRED_REMOVE_UNDEF;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * multipaths block handlers
+ */
+@@ -1920,6 +1970,32 @@ mp_names_handler(vector strvec)
+ return 0;
+ }
+
++static int
++mp_deferred_remove_handler(vector strvec)
++{
++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
++ char * buff;
++
++ if (!mpe)
++ return 1;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
++ (strlen(buff) == 1 && strcmp(buff, "0") == 0))
++ mpe->deferred_remove = DEFERRED_REMOVE_OFF;
++ else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
++ (strlen(buff) == 1 && strcmp(buff, "1") == 0))
++ mpe->deferred_remove = DEFERRED_REMOVE_ON;
++ else
++ mpe->deferred_remove = DEFERRED_REMOVE_UNDEF;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * config file keywords printing
+ */
+@@ -2165,7 +2241,7 @@ snprint_mp_reservation_key (char * buff,
+ return snprintf(buff, len, "0x%" PRIx64, prkey);
+ }
+
+- static int
++static int
+ snprint_mp_user_friendly_names (char * buff, int len, void * data)
+ {
+ struct mpentry * mpe = (struct mpentry *)data;
+@@ -2179,6 +2255,19 @@ snprint_mp_user_friendly_names (char * b
+ }
+
+ static int
++snprint_mp_deferred_remove (char * buff, int len, void * data)
++{
++ struct mpentry * mpe = (struct mpentry *)data;
++
++ if (mpe->deferred_remove == DEFERRED_REMOVE_UNDEF)
++ return 0;
++ else if (mpe->deferred_remove == DEFERRED_REMOVE_OFF)
++ return snprintf(buff, len, "no");
++ else
++ return snprintf(buff, len, "yes");
++}
++
++static int
+ snprint_hw_fast_io_fail(char * buff, int len, void * data)
+ {
+ struct hwentry * hwe = (struct hwentry *)data;
+@@ -2507,6 +2596,19 @@ snprint_hw_retain_hwhandler_handler(char
+ }
+
+ static int
++snprint_hw_deferred_remove(char * buff, int len, void * data)
++{
++ struct hwentry * hwe = (struct hwentry *)data;
++
++ if (hwe->deferred_remove == DEFERRED_REMOVE_ON)
++ return snprintf(buff, len, "yes");
++ else if (hwe->deferred_remove == DEFERRED_REMOVE_OFF)
++ return snprintf(buff, len, "no");
++ else
++ return 0;
++}
++
++static int
+ snprint_detect_prio(char * buff, int len, void * data)
+ {
+ struct hwentry * hwe = (struct hwentry *)data;
+@@ -2900,6 +3002,15 @@ snprint_def_force_sync(char * buff, int
+ }
+
+ static int
++snprint_def_deferred_remove(char * buff, int len, void * data)
++{
++ if (conf->deferred_remove == DEFERRED_REMOVE_ON)
++ return snprintf(buff, len, "yes");
++ else
++ return snprintf(buff, len, "no");
++}
++
++static int
+ snprint_ble_simple (char * buff, int len, void * data)
+ {
+ struct blentry * ble = (struct blentry *)data;
+@@ -2968,6 +3079,7 @@ init_keywords(void)
+ install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
+ install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch);
+ install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
++ install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
+ __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);
+@@ -3032,6 +3144,7 @@ init_keywords(void)
+ install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names);
+ install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler);
+ install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio);
++ install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove);
+ install_sublevel_end();
+
+ install_keyword_root("multipaths", &multipaths_handler);
+@@ -3056,5 +3169,6 @@ init_keywords(void)
+ install_keyword("gid", &mp_gid_handler, &snprint_mp_gid);
+ install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key);
+ install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names);
++ install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove);
+ install_sublevel_end();
+ }
+Index: multipath-tools-130222/libmultipath/propsel.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.c
++++ multipath-tools-130222/libmultipath/propsel.c
+@@ -744,6 +744,34 @@ select_retain_hwhandler (struct multipat
+ }
+
+ extern int
++select_deferred_remove (struct multipath *mp)
++{
++ if (mp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) {
++ condlog(3, "%s: deferred_remove in progress", mp->alias);
++ return 0;
++ }
++ if (mp->mpe && mp->mpe->deferred_remove) {
++ mp->deferred_remove = mp->mpe->deferred_remove;
++ condlog(3, "%s: deferred_remove = %i (multipath setting)",
++ mp->alias, mp->deferred_remove);
++ return 0;
++ }
++ if (mp->hwe && mp->hwe->deferred_remove) {
++ mp->deferred_remove = mp->hwe->deferred_remove;
++ condlog(3, "%s: deferred_remove = %d (controller default)", mp->alias, mp->deferred_remove);
++ return 0;
++ }
++ if (conf->deferred_remove) {
++ mp->deferred_remove = conf->deferred_remove;
++ condlog(3, "%s: deferred_remove = %d (config file default)", mp->alias, mp->deferred_remove);
++ return 0;
++ }
++ mp->deferred_remove = DEFAULT_DEFERRED_REMOVE;
++ condlog(3, "%s: deferred_remove = %d (compiled in default)", mp->alias, mp->deferred_remove);
++ return 0;
++}
++
++extern int
+ select_detect_prio (struct path * pp)
+ {
+ if (pp->hwe && pp->hwe->detect_prio) {
+Index: multipath-tools-130222/libmultipath/propsel.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.h
++++ multipath-tools-130222/libmultipath/propsel.h
+@@ -20,3 +20,4 @@ int select_dev_loss(struct multipath *mp
+ int select_reservation_key(struct multipath *mp);
+ int select_retain_hwhandler (struct multipath * mp);
+ int select_detect_prio(struct path * pp);
++int select_deferred_remove(struct multipath *mp);
+Index: multipath-tools-130222/libmultipath/structs.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs.h
++++ multipath-tools-130222/libmultipath/structs.h
+@@ -114,6 +114,13 @@ enum detect_prio_states {
+ DETECT_PRIO_ON,
+ };
+
++enum deferred_remove_states {
++ DEFERRED_REMOVE_UNDEF,
++ DEFERRED_REMOVE_OFF,
++ DEFERRED_REMOVE_ON,
++ DEFERRED_REMOVE_IN_PROGRESS,
++};
++
+ enum scsi_protocol {
+ SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
+ SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
+@@ -207,6 +214,7 @@ struct multipath {
+ int attribute_flags;
+ int fast_io_fail;
+ int retain_hwhandler;
++ int deferred_remove;
+ unsigned int dev_loss;
+ uid_t uid;
+ gid_t gid;
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -214,19 +214,30 @@ sync_maps_state(vector mpvec)
+ }
+
+ static int
+-flush_map(struct multipath * mpp, struct vectors * vecs)
++flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
+ {
++ int r;
++
++ if (nopaths)
++ r = dm_flush_map_nopaths(mpp->alias, mpp->deferred_remove);
++ else
++ r = dm_flush_map(mpp->alias);
+ /*
+ * clear references to this map before flushing so we can ignore
+ * the spurious uevent we may generate with the dm_flush_map call below
+ */
+- if (dm_flush_map(mpp->alias)) {
++ if (r) {
+ /*
+ * May not really be an error -- if the map was already flushed
+ * from the device mapper by dmsetup(8) for instance.
+ */
+- condlog(0, "%s: can't flush", mpp->alias);
+- return 1;
++ if (r == 1)
++ condlog(0, "%s: can't flush", mpp->alias);
++ else {
++ condlog(2, "%s: devmap deferred remove", mpp->alias);
++ mpp->deferred_remove = DEFERRED_REMOVE_IN_PROGRESS;
++ }
++ return r;
+ }
+ else {
+ dm_lib_release();
+@@ -372,7 +383,7 @@ ev_remove_map (char * devname, char * al
+ mpp->alias, mpp->dmi->minor, minor);
+ return 0;
+ }
+- return flush_map(mpp, vecs);
++ return flush_map(mpp, vecs, 0);
+ }
+
+ static int
+@@ -628,7 +639,7 @@ ev_remove_path (struct path *pp, struct
+ mpp->flush_on_last_del = FLUSH_IN_PROGRESS;
+ dm_queue_if_no_path(mpp->alias, 0);
+ }
+- if (!flush_map(mpp, vecs)) {
++ if (!flush_map(mpp, vecs, 1)) {
+ condlog(2, "%s: removed map after"
+ " removing all paths",
+ alias);
+Index: multipath-tools-130222/libmultipath/structs_vec.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs_vec.c
++++ multipath-tools-130222/libmultipath/structs_vec.c
+@@ -392,6 +392,8 @@ __setup_multipath (struct vectors * vecs
+ set_no_path_retry(mpp);
+ select_pg_timeout(mpp);
+ select_flush_on_last_del(mpp);
++ if (VECTOR_SIZE(mpp->paths) != 0)
++ dm_cancel_deferred_remove(mpp);
+ }
+
+ return 0;
+@@ -565,7 +567,6 @@ int update_multipath (struct vectors *ve
+ }
+ }
+ }
+-
+ return 0;
+ }
+
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -420,6 +420,16 @@ only one checker will run at a time. Th
+ multipathd checkers running in parallel causes significant CPU pressure. The
+ Default is
+ .I no
++.TP
++.B deferred_remove
++If set to
++.I yes
++, multipathd will do a deferred remove instead of a regular remove when the
++last path device has been deleted. This means that if the multipath device is
++still in use, it will be freed when the last user closes it. If path is added
++to the multipath device before the last user closes it, the deferred remove
++will be canceled. Default is
++.I no
+ .
+ .SH "blacklist section"
+ The
+@@ -521,6 +531,8 @@ section:
+ .B features
+ .TP
+ .B reservation_key
++.TP
++.B deferred_remove
+ .RE
+ .PD
+ .LP
+@@ -611,6 +623,8 @@ section:
+ .B retain_attached_hw_handler
+ .TP
+ .B detect_prio
++.TP
++.B deferred_remove
+ .RE
+ .PD
+ .LP
+Index: multipath-tools-130222/libmultipath/Makefile
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/Makefile
++++ multipath-tools-130222/libmultipath/Makefile
+@@ -36,6 +36,12 @@ ifneq ($(strip $(LIBUDEV_API_RECVBUF)),0
+ CFLAGS += -DLIBUDEV_API_RECVBUF
+ endif
+
++LIBDM_API_DEFERRED = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_deferred_remove' /usr/include/libdevmapper.h)
++
++ifneq ($(strip $(LIBDM_API_DEFERRED)),0)
++ CFLAGS += -DLIBDM_API_DEFERRED
++endif
++
+
+ all: $(LIBS)
+
--- /dev/null
+diff -purN multipath-tools-130222.orig/multipath/multipath.rules multipath-tools-130222/multipath/multipath.rules
+--- multipath-tools-130222.orig/multipath/multipath.rules 2014-11-03 14:37:41.269413134 +0100
++++ multipath-tools-130222/multipath/multipath.rules 2014-11-03 14:38:43.694281901 +0100
+@@ -45,5 +45,5 @@ ACTION!="change", GOTO="end_mpath"
+ ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath"
+ ENV{DM_SUSPENDED}=="1", GOTO="end_mpath"
+ ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath"
+-RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode"
++ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode"
+ LABEL="end_mpath"
--- /dev/null
+---
+ multipathd/main.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -669,9 +669,8 @@ ev_remove_path (struct path *pp, struct
+ /*
+ * update our state from kernel
+ */
+- if (setup_multipath(vecs, mpp)) {
+- goto fail;
+- }
++ if (setup_multipath(vecs, mpp))
++ return 1;
+ sync_map_state(mpp);
+
+ condlog(2, "%s [%s]: path removed from map %s",
--- /dev/null
+---
+ libmultipath/config.c | 4 ++++
+ libmultipath/config.h | 1 +
+ libmultipath/configure.c | 5 ++---
+ libmultipath/dict.c | 33 +++++++++++++++++++++++++++++++++
+ libmultipath/util.c | 30 ++++++++++++++++++++++++++++++
+ libmultipath/util.h | 1 +
+ libmultipath/wwids.c | 21 ++++++++++++++-------
+ multipathd/main.c | 3 +--
+ 8 files changed, 86 insertions(+), 12 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -131,6 +131,7 @@ struct config {
+ int detect_prio;
+ int force_sync;
+ int deferred_remove;
++ int ignore_new_boot_devs;
+ unsigned int version[3];
+
+ char * dev;
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -775,9 +775,8 @@ coalesce_paths (struct vectors * vecs, v
+ if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
+ continue;
+
+- /* If find_multipaths was selected check if the path is valid */
+- if (conf->find_multipaths && !refwwid &&
+- !should_multipath(pp1, pathvec)) {
++ /* check if the path is valid */
++ if (!refwwid && !should_multipath(pp1, pathvec)) {
+ orphan_path(pp1);
+ continue;
+ }
+Index: multipath-tools-130222/libmultipath/wwids.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/wwids.c
++++ multipath-tools-130222/libmultipath/wwids.c
+@@ -15,6 +15,7 @@
+ #include "wwids.h"
+ #include "defaults.h"
+ #include "config.h"
++#include "util.h"
+
+ /*
+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
+@@ -268,15 +269,21 @@ should_multipath(struct path *pp1, vecto
+ {
+ int i;
+ struct path *pp2;
++ int ignore_new_devs = (conf->ignore_new_boot_devs && in_initrd());
++
++ if (!conf->find_multipaths && !ignore_new_devs)
++ return 1;
+
+ condlog(4, "checking if %s should be multipathed", pp1->dev);
+- vector_foreach_slot(pathvec, pp2, i) {
+- if (pp1->dev == pp2->dev)
+- continue;
+- if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) {
+- condlog(3, "found multiple paths with wwid %s, "
+- "multipathing %s", pp1->wwid, pp1->dev);
+- return 1;
++ if (!ignore_new_devs) {
++ vector_foreach_slot(pathvec, pp2, i) {
++ if (pp1->dev == pp2->dev)
++ continue;
++ if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) {
++ condlog(3, "found multiple paths with wwid %s, "
++ "multipathing %s", pp1->wwid, pp1->dev);
++ return 1;
++ }
+ }
+ }
+ if (check_wwids_file(pp1->wwid, 0) < 0) {
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -503,8 +503,7 @@ rescan:
+ return 1;
+ }
+
+- if (conf->find_multipaths &&
+- !should_multipath(pp, vecs->pathvec)) {
++ if (!should_multipath(pp, vecs->pathvec)) {
+ orphan_path(pp);
+ return 0;
+ }
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -622,6 +622,7 @@ load_config (char * file, struct udev *u
+ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
+ conf->hw_strmatch = 0;
+ conf->force_sync = 0;
++ conf->ignore_new_boot_devs = 0;
+
+ /*
+ * preload default hwtable
+@@ -732,6 +733,9 @@ load_config (char * file, struct udev *u
+ !conf->wwids_file)
+ goto out;
+
++ if (conf->ignore_new_boot_devs)
++ in_initrd();
++
+ return 0;
+ out:
+ free_config(conf);
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -761,6 +761,29 @@ def_deferred_remove_handler(vector strve
+ return 0;
+ }
+
++static int
++def_ignore_new_boot_devs_handler(vector strvec)
++{
++ char * buff;
++
++ buff = set_value(strvec);
++
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ conf->ignore_new_boot_devs = 0;
++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "1")))
++ conf->ignore_new_boot_devs = 1;
++ else
++ conf->ignore_new_boot_devs = 0;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * blacklist block handlers
+ */
+@@ -3011,6 +3034,15 @@ snprint_def_deferred_remove(char * buff,
+ }
+
+ static int
++snprint_def_ignore_new_boot_devs(char * buff, int len, void * data)
++{
++ if (conf->ignore_new_boot_devs == 1)
++ return snprintf(buff, len, "yes");
++ else
++ return snprintf(buff, len, "no");
++}
++
++static int
+ snprint_ble_simple (char * buff, int len, void * data)
+ {
+ struct blentry * ble = (struct blentry *)data;
+@@ -3080,6 +3112,7 @@ init_keywords(void)
+ install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch);
+ install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
+ install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
++ install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs);
+ __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);
+Index: multipath-tools-130222/libmultipath/util.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/util.c
++++ multipath-tools-130222/libmultipath/util.c
+@@ -3,6 +3,8 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
++#include <sys/vfs.h>
++#include <linux/magic.h>
+
+ #include "debug.h"
+ #include "memory.h"
+@@ -267,3 +269,31 @@ dev_t parse_devt(const char *dev_t)
+
+ return makedev(maj, min);
+ }
++
++/* This define was taken from systemd. src/shared/macro.h */
++#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
++
++/* This function was taken from systemd. src/shared/util.c */
++int in_initrd(void) {
++ static int saved = -1;
++ struct statfs s;
++
++ if (saved >= 0)
++ return saved;
++
++ /* We make two checks here:
++ *
++ * 1. the flag file /etc/initrd-release must exist
++ * 2. the root file system must be a memory file system
++ * The second check is extra paranoia, since misdetecting an
++ * initrd can have bad bad consequences due the initrd
++ * emptying when transititioning to the main systemd.
++ */
++
++ saved = access("/etc/initrd-release", F_OK) >= 0 &&
++ statfs("/", &s) >= 0 &&
++ (F_TYPE_EQUAL(s.f_type, TMPFS_MAGIC) ||
++ F_TYPE_EQUAL(s.f_type, RAMFS_MAGIC));
++
++ return saved;
++}
+Index: multipath-tools-130222/libmultipath/util.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/util.h
++++ multipath-tools-130222/libmultipath/util.h
+@@ -11,6 +11,7 @@ void remove_trailing_chars(char *path, c
+ int devt2devname (char *, int, char *);
+ dev_t parse_devt(const char *dev_t);
+ char *convert_dev(char *dev, int is_path_device);
++int in_initrd(void);
+
+ #define safe_sprintf(var, format, args...) \
+ snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
--- /dev/null
+---
+ multipath/multipath.rules | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipath/multipath.rules
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.rules
++++ multipath-tools-130222/multipath/multipath.rules
+@@ -45,5 +45,5 @@ ACTION!="change", GOTO="end_mpath"
+ ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath"
+ ENV{DM_SUSPENDED}=="1", GOTO="end_mpath"
+ ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath"
+-ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode"
++ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -u $tempnode"
+ LABEL="end_mpath"
--- /dev/null
+---
+ multipathd/main.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -1879,7 +1879,7 @@ main (int argc, char *argv[])
+ if (!conf)
+ exit(1);
+
+- while ((arg = getopt(argc, argv, ":dv:k::")) != EOF ) {
++ while ((arg = getopt(argc, argv, ":dv:k::B")) != EOF ) {
+ switch(arg) {
+ case 'd':
+ logsink = 0;
+@@ -1895,6 +1895,9 @@ main (int argc, char *argv[])
+ case 'k':
+ uxclnt(optarg);
+ exit(0);
++ case 'B':
++ conf->bindings_read_only = 1;
++ break;
+ default:
+ ;
+ }
--- /dev/null
+---
+ libmultipath/blacklist.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: multipath-tools-130222/libmultipath/blacklist.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/blacklist.c
++++ multipath-tools-130222/libmultipath/blacklist.c
+@@ -169,7 +169,7 @@ setup_default_blist (struct config * con
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
+ return 1;
+
+- str = STRDUP("^(td|hd)[a-z]");
++ str = STRDUP("^(td|hd|vd)[a-z]");
+ if (!str)
+ return 1;
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
--- /dev/null
+---
+ libmultipath/dict.c | 97 ----------------------------------------------------
+ 1 file changed, 97 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -473,26 +473,6 @@ def_checker_timeout_handler(vector strve
+ static int
+ def_pg_timeout_handler(vector strvec)
+ {
+- int pg_timeout;
+- char * buff;
+-
+- buff = set_value(strvec);
+-
+- if (!buff)
+- return 1;
+-
+- if (strlen(buff) == 4 && !strcmp(buff, "none"))
+- conf->pg_timeout = -PGTIMEOUT_NONE;
+- else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) {
+- if (pg_timeout == 0)
+- conf->pg_timeout = -PGTIMEOUT_NONE;
+- else
+- conf->pg_timeout = pg_timeout;
+- }
+- else
+- conf->pg_timeout = PGTIMEOUT_UNDEF;
+-
+- FREE(buff);
+ return 0;
+ }
+
+@@ -1358,30 +1338,6 @@ hw_minio_rq_handler(vector strvec)
+ static int
+ hw_pg_timeout_handler(vector strvec)
+ {
+- int pg_timeout;
+- struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+- char *buff;
+-
+- if (!hwe)
+- return 1;
+-
+- buff = set_value(strvec);
+-
+- if (!buff)
+- return 1;
+-
+- if (strlen(buff) == 4 && !strcmp(buff, "none"))
+- hwe->pg_timeout = -PGTIMEOUT_NONE;
+- else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) {
+- if (pg_timeout == 0)
+- hwe->pg_timeout = -PGTIMEOUT_NONE;
+- else
+- hwe->pg_timeout = pg_timeout;
+- }
+- else
+- hwe->pg_timeout = PGTIMEOUT_UNDEF;
+-
+- FREE(buff);
+ return 0;
+ }
+
+@@ -1819,29 +1775,6 @@ mp_minio_rq_handler(vector strvec)
+ static int
+ mp_pg_timeout_handler(vector strvec)
+ {
+- int pg_timeout;
+- struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+- char *buff;
+-
+- if (!mpe)
+- return 1;
+-
+- buff = set_value(strvec);
+-
+- if (!buff)
+- return 1;
+- if (strlen(buff) == 4 && !strcmp(buff, "none"))
+- mpe->pg_timeout = -PGTIMEOUT_NONE;
+- else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) {
+- if (pg_timeout == 0)
+- mpe->pg_timeout = -PGTIMEOUT_NONE;
+- else
+- mpe->pg_timeout = pg_timeout;
+- }
+- else
+- mpe->pg_timeout = PGTIMEOUT_UNDEF;
+-
+- FREE(buff);
+ return 0;
+ }
+
+@@ -2180,16 +2113,6 @@ snprint_mp_rr_min_io_rq (char * buff, in
+ static int
+ snprint_mp_pg_timeout (char * buff, int len, void * data)
+ {
+- struct mpentry * mpe = (struct mpentry *)data;
+-
+- switch (mpe->pg_timeout) {
+- case PGTIMEOUT_UNDEF:
+- break;
+- case -PGTIMEOUT_NONE:
+- return snprintf(buff, len, "\"none\"");
+- default:
+- return snprintf(buff, len, "%i", mpe->pg_timeout);
+- }
+ return 0;
+ }
+
+@@ -2551,19 +2474,6 @@ snprint_hw_rr_min_io_rq (char * buff, in
+ static int
+ snprint_hw_pg_timeout (char * buff, int len, void * data)
+ {
+- struct hwentry * hwe = (struct hwentry *)data;
+-
+- if (!hwe->pg_timeout)
+- return 0;
+-
+- switch (hwe->pg_timeout) {
+- case PGTIMEOUT_UNDEF:
+- break;
+- case -PGTIMEOUT_NONE:
+- return snprintf(buff, len, "\"none\"");
+- default:
+- return snprintf(buff, len, "%i", hwe->pg_timeout);
+- }
+ return 0;
+ }
+
+@@ -2895,13 +2805,6 @@ snprint_def_checker_timeout (char *buff,
+ static int
+ snprint_def_pg_timeout (char * buff, int len, void * data)
+ {
+- switch (conf->pg_timeout) {
+- case PGTIMEOUT_UNDEF:
+- case -PGTIMEOUT_NONE:
+- return snprintf(buff, len, "\"none\"");
+- default:
+- return snprintf(buff, len, "%i", conf->pg_timeout);
+- }
+ return 0;
+ }
+
--- /dev/null
+---
+ libmultipath/config.c | 56 +++++++++++++++++++++++++++++++-
+ libmultipath/config.h | 2 +
+ libmultipath/defaults.h | 1
+ libmultipath/dict.c | 69 +++++++++++++++++++++++++++++++++++----
+ libmultipath/parser.c | 78 +++++++++++++++++++++++----------------------
+ libmultipath/parser.h | 3 -
+ multipath.conf.annotated | 10 +++++
+ multipath.conf.defaults | 1
+ multipath/multipath.conf.5 | 7 ++++
+ 9 files changed, 179 insertions(+), 48 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/parser.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/parser.c
++++ multipath-tools-130222/libmultipath/parser.c
+@@ -18,6 +18,7 @@
+ */
+
+ #include <syslog.h>
++#include <errno.h>
+
+ #include "parser.h"
+ #include "memory.h"
+@@ -453,14 +454,15 @@ set_value(vector strvec)
+ /* non-recursive configuration stream handler */
+ static int kw_level = 0;
+
+-int warn_on_duplicates(vector uniques, char *str)
++int warn_on_duplicates(vector uniques, char *str, char *file)
+ {
+ char *tmp;
+ int i;
+
+ vector_foreach_slot(uniques, tmp, i) {
+ if (!strcmp(str, tmp)) {
+- condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str);
++ condlog(1, "%s line %d, duplicate keyword: %s",
++ file, line_nr, str);
+ return 0;
+ }
+ }
+@@ -496,65 +498,70 @@ is_sublevel_keyword(char *str)
+ }
+
+ int
+-validate_config_strvec(vector strvec)
++validate_config_strvec(vector strvec, char *file)
+ {
+ char *str;
+ int i;
+
+ str = VECTOR_SLOT(strvec, 0);
+ if (str == NULL) {
+- condlog(0, "can't parse option on line %d of config file",
+- line_nr);
++ condlog(0, "can't parse option on line %d of %s",
++ line_nr, file);
+ return -1;
+ }
+ if (*str == '}') {
+ if (VECTOR_SIZE(strvec) > 1)
+- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr);
++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file);
+ return 0;
+ }
+ if (*str == '{') {
+- condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr);
++ condlog(0, "invalid keyword '%s' on line %d of %s",
++ str, line_nr, file);
+ return -1;
+ }
+ if (is_sublevel_keyword(str)) {
+ str = VECTOR_SLOT(strvec, 1);
+ if (str == NULL)
+- condlog(0, "missing '{' on line %d of config file", line_nr);
++ condlog(0, "missing '{' on line %d of %s",
++ line_nr, file);
+ else if (*str != '{')
+- condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str);
++ condlog(0, "expecting '{' on line %d of %s. found '%s'",
++ line_nr, file, str);
+ else if (VECTOR_SIZE(strvec) > 2)
+- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
+ return 0;
+ }
+ str = VECTOR_SLOT(strvec, 1);
+ if (str == NULL) {
+- condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr);
++ condlog(0, "missing value for option '%s' on line %d of %s",
++ (char *)VECTOR_SLOT(strvec, 0), line_nr, file);
+ return -1;
+ }
+ if (*str != '"') {
+ if (VECTOR_SIZE(strvec) > 2)
+- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);
++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
+ return 0;
+ }
+ for (i = 2; i < VECTOR_SIZE(strvec); i++) {
+ str = VECTOR_SLOT(strvec, i);
+ if (str == NULL) {
+- condlog(0, "can't parse value on line %d of config file", line_nr);
++ condlog(0, "can't parse value on line %d of %s",
++ line_nr, file);
+ return -1;
+ }
+ if (*str == '"') {
+ if (VECTOR_SIZE(strvec) > i + 1)
+- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr);
++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
+ return 0;
+ }
+ }
+- condlog(0, "missing closing quotes on line %d of config file",
+- line_nr);
++ condlog(0, "missing closing quotes on line %d of %s",
++ line_nr, file);
+ return 0;
+ }
+
+-int
+-process_stream(vector keywords)
++static int
++process_stream(vector keywords, char *file)
+ {
+ int i;
+ int r = 0;
+@@ -583,7 +590,7 @@ process_stream(vector keywords)
+ if (!strvec)
+ continue;
+
+- if (validate_config_strvec(strvec) != 0) {
++ if (validate_config_strvec(strvec, file) != 0) {
+ free_strvec(strvec);
+ continue;
+ }
+@@ -595,8 +602,8 @@ process_stream(vector keywords)
+ free_strvec(strvec);
+ break;
+ }
+- condlog(0, "unmatched '%s' at line %d of config file",
+- EOB, line_nr);
++ condlog(0, "unmatched '%s' at line %d of %s",
++ EOB, line_nr, file);
+ }
+
+ for (i = 0; i < VECTOR_SIZE(keywords); i++) {
+@@ -604,7 +611,7 @@ process_stream(vector keywords)
+
+ if (!strcmp(keyword->string, str)) {
+ if (keyword->unique &&
+- warn_on_duplicates(uniques, str)) {
++ warn_on_duplicates(uniques, str, file)) {
+ r = 1;
+ free_strvec(strvec);
+ goto out;
+@@ -614,15 +621,15 @@ process_stream(vector keywords)
+
+ if (keyword->sub) {
+ kw_level++;
+- r += process_stream(keyword->sub);
++ r += process_stream(keyword->sub, file);
+ kw_level--;
+ }
+ break;
+ }
+ }
+ if (i >= VECTOR_SIZE(keywords))
+- condlog(1, "multipath.conf +%d, invalid keyword: %s",
+- line_nr, str);
++ condlog(1, "%s line %d, invalid keyword: %s",
++ file, line_nr, str);
+
+ free_strvec(strvec);
+ }
+@@ -646,27 +653,24 @@ int alloc_keywords(void)
+
+ /* Data initialization */
+ int
+-init_data(char *conf_file, void (*init_keywords) (void))
++process_file(char *file)
+ {
+ int r;
+
+- stream = fopen(conf_file, "r");
++ if (!keywords) {
++ condlog(0, "No keywords alocated");
++ return 1;
++ }
++ stream = fopen(file, "r");
+ if (!stream) {
+- syslog(LOG_WARNING, "Configuration file open problem");
++ condlog(0, "couldn't open configuration file '%s': %s",
++ file, strerror(errno));
+ return 1;
+ }
+
+- /* Init Keywords structure */
+- (*init_keywords) ();
+-
+-/* Dump configuration *
+- vector_dump(keywords);
+- dump_keywords(keywords, 0);
+-*/
+-
+ /* Stream handling */
+ line_nr = 0;
+- r = process_stream(keywords);
++ r = process_stream(keywords, file);
+ fclose(stream);
+ //free_keywords(keywords);
+
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -117,6 +117,8 @@ reassign_maps_handler(vector strvec)
+ static int
+ multipath_dir_handler(vector strvec)
+ {
++ if (conf->multipath_dir)
++ FREE(conf->multipath_dir);
+ conf->multipath_dir = set_value(strvec);
+
+ if (!conf->multipath_dir)
+@@ -128,6 +130,8 @@ multipath_dir_handler(vector strvec)
+ static int
+ def_selector_handler(vector strvec)
+ {
++ if (conf->selector)
++ FREE(conf->selector);
+ conf->selector = set_value(strvec);
+
+ if (!conf->selector)
+@@ -155,6 +159,8 @@ def_pgpolicy_handler(vector strvec)
+ static int
+ def_uid_attribute_handler(vector strvec)
+ {
++ if (conf->uid_attribute)
++ FREE(conf->uid_attribute);
+ conf->uid_attribute = set_value(strvec);
+
+ if (!conf->uid_attribute)
+@@ -166,6 +172,8 @@ def_uid_attribute_handler(vector strvec)
+ static int
+ def_prio_handler(vector strvec)
+ {
++ if (conf->prio_name)
++ FREE(conf->prio_name);
+ conf->prio_name = set_value(strvec);
+
+ if (!conf->prio_name)
+@@ -177,6 +185,8 @@ def_prio_handler(vector strvec)
+ static int
+ def_alias_prefix_handler(vector strvec)
+ {
++ if (conf->alias_prefix)
++ FREE(conf->alias_prefix);
+ conf->alias_prefix = set_value(strvec);
+
+ if (!conf->alias_prefix)
+@@ -188,6 +198,8 @@ def_alias_prefix_handler(vector strvec)
+ static int
+ def_prio_args_handler(vector strvec)
+ {
++ if (conf->prio_args)
++ FREE(conf->prio_args);
+ conf->prio_args = set_value(strvec);
+
+ if (!conf->prio_args)
+@@ -199,6 +211,8 @@ def_prio_args_handler(vector strvec)
+ static int
+ def_features_handler(vector strvec)
+ {
++ if (conf->features)
++ FREE(conf->features);
+ conf->features = set_value(strvec);
+
+ if (!conf->features)
+@@ -210,6 +224,8 @@ def_features_handler(vector strvec)
+ static int
+ def_path_checker_handler(vector strvec)
+ {
++ if (conf->checker_name)
++ FREE(conf->checker_name);
+ conf->checker_name = set_value(strvec);
+
+ if (!conf->checker_name)
+@@ -432,6 +448,23 @@ def_no_path_retry_handler(vector strvec)
+ return 0;
+ }
+
++
++static int
++def_config_dir_handler(vector strvec)
++{
++ /* this is only valid in the main config file */
++ if (conf->processed_main_config)
++ return 0;
++ if (conf->config_dir)
++ FREE(conf->config_dir);
++ conf->config_dir = set_value(strvec);
++
++ if (!conf->config_dir)
++ return 1;
++
++ return 0;
++}
++
+ static int
+ def_queue_without_daemon(vector strvec)
+ {
+@@ -611,6 +644,8 @@ def_names_handler(vector strvec)
+ static int
+ bindings_file_handler(vector strvec)
+ {
++ if (conf->bindings_file)
++ FREE(conf->bindings_file);
+ conf->bindings_file = set_value(strvec);
+
+ if (!conf->bindings_file)
+@@ -622,6 +657,8 @@ bindings_file_handler(vector strvec)
+ static int
+ wwids_file_handler(vector strvec)
+ {
++ if (conf->wwids_file)
++ FREE(conf->wwids_file);
+ conf->wwids_file = set_value(strvec);
+
+ if (!conf->wwids_file)
+@@ -770,9 +807,12 @@ def_ignore_new_boot_devs_handler(vector
+ static int
+ blacklist_handler(vector strvec)
+ {
+- conf->blist_devnode = vector_alloc();
+- conf->blist_wwid = vector_alloc();
+- conf->blist_device = vector_alloc();
++ if (!conf->blist_devnode)
++ conf->blist_devnode = vector_alloc();
++ if (!conf->blist_wwid)
++ conf->blist_wwid = vector_alloc();
++ if (!conf->blist_device)
++ conf->blist_device = vector_alloc();
+
+ if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device)
+ return 1;
+@@ -783,9 +823,12 @@ blacklist_handler(vector strvec)
+ static int
+ blacklist_exceptions_handler(vector strvec)
+ {
+- conf->elist_devnode = vector_alloc();
+- conf->elist_wwid = vector_alloc();
+- conf->elist_device = vector_alloc();
++ if (!conf->elist_devnode)
++ conf->elist_devnode = vector_alloc();
++ if (!conf->elist_wwid)
++ conf->elist_wwid = vector_alloc();
++ if (!conf->elist_device)
++ conf->elist_device = vector_alloc();
+
+ if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device)
+ return 1;
+@@ -1480,7 +1523,8 @@ hw_deferred_remove_handler(vector strvec
+ static int
+ multipaths_handler(vector strvec)
+ {
+- conf->mptable = vector_alloc();
++ if (!conf->mptable)
++ conf->mptable = vector_alloc();
+
+ if (!conf->mptable)
+ return 1;
+@@ -2945,6 +2989,16 @@ snprint_def_ignore_new_boot_devs(char *
+ return snprintf(buff, len, "no");
+ }
+
++
++static int
++snprint_def_config_dir (char * buff, int len, void * data)
++{
++ if (!conf->config_dir)
++ return 0;
++
++ return snprintf(buff, len, "\"%s\"", conf->config_dir);
++}
++
+ static int
+ snprint_ble_simple (char * buff, int len, void * data)
+ {
+@@ -3016,6 +3070,7 @@ init_keywords(void)
+ install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
+ install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
+ install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs);
++ install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir);
+ __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);
+Index: multipath-tools-130222/libmultipath/parser.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/parser.h
++++ multipath-tools-130222/libmultipath/parser.h
+@@ -76,9 +76,8 @@ extern int read_line(char *buf, int size
+ extern vector read_value_block(void);
+ extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
+ extern void *set_value(vector strvec);
+-extern int process_stream(vector keywords);
+ extern int alloc_keywords(void);
+-extern int init_data(char *conf_file, void (*init_keywords) (void));
++extern int process_file(char *conf_file);
+ extern struct keyword * find_keyword(vector v, char * name);
+ void set_current_keywords (vector *k);
+ int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -6,6 +6,9 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <libudev.h>
++#include <dirent.h>
++#include <limits.h>
++#include <errno.h>
+
+ #include "checkers.h"
+ #include "memory.h"
+@@ -556,6 +559,7 @@ free_config (struct config * conf)
+
+ if (conf->wwids_file)
+ FREE(conf->wwids_file);
++
+ if (conf->prio_name)
+ FREE(conf->prio_name);
+
+@@ -567,6 +571,10 @@ free_config (struct config * conf)
+
+ if (conf->checker_name)
+ FREE(conf->checker_name);
++
++ if (conf->config_dir)
++ FREE(conf->config_dir);
++
+ if (conf->reservation_key)
+ FREE(conf->reservation_key);
+
+@@ -584,6 +592,43 @@ free_config (struct config * conf)
+ FREE(conf);
+ }
+
++/* if multipath fails to process the config directory, it should continue,
++ * with just a warning message */
++static void
++process_config_dir(vector keywords, char *dir)
++{
++ struct dirent **namelist;
++ int i, n;
++ char path[LINE_MAX];
++ int old_hwtable_size;
++
++ if (dir[0] != '/') {
++ condlog(1, "config_dir '%s' must be a fully qualified path",
++ dir);
++ return;
++ }
++ n = scandir(dir, &namelist, NULL, alphasort);
++ if (n < 0) {
++ if (errno == ENOENT)
++ condlog(3, "No configuration dir '%s'", dir);
++ else
++ condlog(0, "couldn't open configuration dir '%s': %s",
++ dir, strerror(errno));
++ return;
++ }
++ for (i = 0; i < n; i++) {
++ if (!strstr(namelist[i]->d_name, ".conf"))
++ continue;
++ old_hwtable_size = VECTOR_SIZE(conf->hwtable);
++ snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
++ path[LINE_MAX-1] = '\0';
++ process_file(path);
++ if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
++ factorize_hwtable(conf->hwtable, old_hwtable_size);
++
++ }
++}
++
+ int
+ load_config (char * file, struct udev *udev)
+ {
+@@ -623,6 +668,7 @@ load_config (char * file, struct udev *u
+ conf->hw_strmatch = 0;
+ conf->force_sync = 0;
+ conf->ignore_new_boot_devs = 0;
++ conf->processed_main_config = 0;
+
+ /*
+ * preload default hwtable
+@@ -641,11 +687,12 @@ load_config (char * file, struct udev *u
+ */
+ set_current_keywords(&conf->keywords);
+ alloc_keywords();
++ init_keywords();
+ if (filepresent(file)) {
+ int builtin_hwtable_size;
+
+ builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
+- if (init_data(file, init_keywords)) {
++ if (process_file(file)) {
+ condlog(0, "error parsing config file");
+ goto out;
+ }
+@@ -658,7 +705,6 @@ load_config (char * file, struct udev *u
+ }
+
+ } else {
+- init_keywords();
+ condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
+ condlog(0, "A default multipath.conf file is located at");
+ condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE));
+@@ -677,6 +723,12 @@ load_config (char * file, struct udev *u
+ }
+ }
+
++ conf->processed_main_config = 1;
++ if (conf->config_dir == NULL)
++ conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
++ if (conf->config_dir && conf->config_dir[0] != '\0')
++ process_config_dir(conf->keywords, conf->config_dir);
++
+ /*
+ * fill the voids left in the config file
+ */
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -132,6 +132,7 @@ struct config {
+ int force_sync;
+ int deferred_remove;
+ int ignore_new_boot_devs;
++ int processed_main_config;
+ unsigned int version[3];
+
+ char * dev;
+@@ -147,6 +148,7 @@ struct config {
+ char * prio_args;
+ char * checker_name;
+ char * alias_prefix;
++ char * config_dir;
+ unsigned char * reservation_key;
+
+ vector keywords;
+Index: multipath-tools-130222/libmultipath/defaults.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/defaults.h
++++ multipath-tools-130222/libmultipath/defaults.h
+@@ -31,5 +31,6 @@
+ #define DEFAULT_CONFIGFILE "/etc/multipath.conf"
+ #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings"
+ #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
++#define DEFAULT_CONFIG_DIR "/etc/multipath/conf.d"
+
+ char * set_default (char * str);
+Index: multipath-tools-130222/multipath.conf.annotated
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.annotated
++++ multipath-tools-130222/multipath.conf.annotated
+@@ -232,6 +232,16 @@
+ # # values : yes|no
+ # # default : no
+ # force_sync yes
++#
++# #
++# # name : config_dir
++# # scope : multipath & multipathd
++# # desc : If not set to an empty string, multipath will search
++# # this directory alphabetically for files ending in ".conf"
++# # and it will read configuration information from these
++# # files, just as if it was in /etc/multipath.conf
++# # values : "" or a fully qualified pathname
++# # default : "/etc/multipath/conf.d"
+ #}
+ #
+ ##
+Index: multipath-tools-130222/multipath.conf.defaults
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.defaults
++++ multipath-tools-130222/multipath.conf.defaults
+@@ -26,6 +26,7 @@
+ # log_checker_err always
+ # retain_attached_hw_handler no
+ # detect_prio no
++# config_dir "/etc/multipath/conf.d"
+ #}
+ #blacklist {
+ # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -430,6 +430,13 @@ still in use, it will be freed when the
+ to the multipath device before the last user closes it, the deferred remove
+ will be canceled. Default is
+ .I no
++.TP
++.B config_dir
++If set to anything other than "", multipath will search this directory
++alphabetically for file ending in ".conf" and it will read configuration
++information from them, just as if it was in /etc/multipath.conf. config_dir
++must either be "" or a fully qualified directory name. Default is
++.I "/etc/multipath/conf.d"
+ .
+ .SH "blacklist section"
+ The
--- /dev/null
+---
+ libmultipath/parser.c | 103 +++-----------------------------------------------
+ libmultipath/parser.h | 6 --
+ 2 files changed, 8 insertions(+), 101 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/parser.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/parser.c
++++ multipath-tools-130222/libmultipath/parser.c
+@@ -280,8 +280,8 @@ out:
+ return NULL;
+ }
+
+-int
+-read_line(char *buf, int size)
++static int
++read_line(FILE *stream, char *buf, int size)
+ {
+ int ch;
+ int count = 0;
+@@ -297,95 +297,6 @@ read_line(char *buf, int size)
+ return (ch == EOF) ? 0 : 1;
+ }
+
+-vector
+-read_value_block(void)
+-{
+- char *buf;
+- int i;
+- char *str = NULL;
+- char *dup;
+- vector vec = NULL;
+- vector elements = vector_alloc();
+-
+- if (!elements)
+- return NULL;
+-
+- buf = (char *) MALLOC(MAXBUF);
+-
+- if (!buf) {
+- vector_free(elements);
+- return NULL;
+- }
+-
+- while (read_line(buf, MAXBUF)) {
+- vec = alloc_strvec(buf);
+- if (vec) {
+- str = VECTOR_SLOT(vec, 0);
+- if (!strcmp(str, EOB)) {
+- free_strvec(vec);
+- break;
+- }
+-
+- for (i = 0; i < VECTOR_SIZE(vec); i++) {
+- str = VECTOR_SLOT(vec, i);
+- dup = (char *) MALLOC(strlen(str) + 1);
+- if (!dup)
+- goto out;
+- memcpy(dup, str, strlen(str));
+-
+- if (!vector_alloc_slot(elements)) {
+- free_strvec(vec);
+- goto out1;
+- }
+-
+- vector_set_slot(elements, dup);
+- }
+- free_strvec(vec);
+- }
+- memset(buf, 0, MAXBUF);
+- }
+- FREE(buf);
+- return elements;
+-out1:
+- FREE(dup);
+-out:
+- FREE(buf);
+- vector_free(elements);
+- return NULL;
+-}
+-
+-int
+-alloc_value_block(vector strvec, void (*alloc_func) (vector))
+-{
+- char *buf;
+- char *str = NULL;
+- vector vec = NULL;
+-
+- buf = (char *) MALLOC(MAXBUF);
+-
+- if (!buf)
+- return 1;
+-
+- while (read_line(buf, MAXBUF)) {
+- vec = alloc_strvec(buf);
+- if (vec) {
+- str = VECTOR_SLOT(vec, 0);
+- if (!strcmp(str, EOB)) {
+- free_strvec(vec);
+- break;
+- }
+-
+- if (VECTOR_SIZE(vec))
+- (*alloc_func) (vec);
+-
+- free_strvec(vec);
+- }
+- memset(buf, 0, MAXBUF);
+- }
+- FREE(buf);
+- return 0;
+-}
+-
+ void *
+ set_value(vector strvec)
+ {
+@@ -561,7 +472,7 @@ validate_config_strvec(vector strvec, ch
+ }
+
+ static int
+-process_stream(vector keywords, char *file)
++process_stream(FILE *stream, vector keywords, char *file)
+ {
+ int i;
+ int r = 0;
+@@ -582,7 +493,7 @@ process_stream(vector keywords, char *fi
+ return 1;
+ }
+
+- while (read_line(buf, MAXBUF)) {
++ while (read_line(stream, buf, MAXBUF)) {
+ line_nr++;
+ strvec = alloc_strvec(buf);
+ memset(buf,0, MAXBUF);
+@@ -621,7 +532,8 @@ process_stream(vector keywords, char *fi
+
+ if (keyword->sub) {
+ kw_level++;
+- r += process_stream(keyword->sub, file);
++ r += process_stream(stream,
++ keyword->sub, file);
+ kw_level--;
+ }
+ break;
+@@ -656,6 +568,7 @@ int
+ process_file(char *file)
+ {
+ int r;
++ FILE *stream;
+
+ if (!keywords) {
+ condlog(0, "No keywords alocated");
+@@ -670,7 +583,7 @@ process_file(char *file)
+
+ /* Stream handling */
+ line_nr = 0;
+- r = process_stream(keywords, file);
++ r = process_stream(stream, keywords, file);
+ fclose(stream);
+ //free_keywords(keywords);
+
+Index: multipath-tools-130222/libmultipath/parser.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/parser.h
++++ multipath-tools-130222/libmultipath/parser.h
+@@ -47,9 +47,6 @@ struct keyword {
+ int unique;
+ };
+
+-/* global var exported */
+-FILE *stream;
+-
+ /* Reloading helpers */
+ #define SET_RELOAD (reload = 1)
+ #define UNSET_RELOAD (reload = 0)
+@@ -72,9 +69,6 @@ extern int _install_keyword(char *string
+ extern void dump_keywords(vector keydump, int level);
+ extern void free_keywords(vector keywords);
+ extern vector alloc_strvec(char *string);
+-extern int read_line(char *buf, int size);
+-extern vector read_value_block(void);
+-extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
+ extern void *set_value(vector strvec);
+ extern int alloc_keywords(void);
+ extern int process_file(char *conf_file);
--- /dev/null
+---
+ libmultipath/checkers.c | 3
+ libmultipath/checkers.h | 9 +
+ libmultipath/config.c | 4
+ libmultipath/config.h | 6 +
+ libmultipath/configure.c | 2
+ libmultipath/defaults.h | 1
+ libmultipath/dict.c | 204 ++++++++++++++++++++++++++++++++++++++++++++-
+ libmultipath/print.c | 2
+ libmultipath/propsel.c | 52 +++++++++++
+ libmultipath/propsel.h | 2
+ libmultipath/structs.h | 9 +
+ multipath.conf.annotated | 40 ++++++++
+ multipath.conf.defaults | 2
+ multipath/multipath.conf.5 | 27 +++++
+ multipathd/main.c | 34 ++++++-
+ 15 files changed, 388 insertions(+), 9 deletions(-)
+
+Index: multipath-tools-130222/libmultipath/config.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.h
++++ multipath-tools-130222/libmultipath/config.h
+@@ -62,6 +62,8 @@ struct hwentry {
+ int retain_hwhandler;
+ int detect_prio;
+ int deferred_remove;
++ int delay_watch_checks;
++ int delay_wait_checks;
+ char * bl_product;
+ };
+
+@@ -86,6 +88,8 @@ struct mpentry {
+ int attribute_flags;
+ int user_friendly_names;
+ int deferred_remove;
++ int delay_watch_checks;
++ int delay_wait_checks;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+@@ -133,6 +137,8 @@ struct config {
+ int deferred_remove;
+ int ignore_new_boot_devs;
+ int processed_main_config;
++ int delay_watch_checks;
++ int delay_wait_checks;
+ unsigned int version[3];
+
+ char * dev;
+Index: multipath-tools-130222/libmultipath/structs.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/structs.h
++++ multipath-tools-130222/libmultipath/structs.h
+@@ -134,6 +134,11 @@ enum scsi_protocol {
+ SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
+ };
+
++enum delay_checks_states {
++ DELAY_CHECKS_OFF = -1,
++ DELAY_CHECKS_UNDEF = 0,
++};
++
+ struct sg_id {
+ int host_no;
+ int channel;
+@@ -180,6 +185,8 @@ struct path {
+ int priority;
+ int pgindex;
+ int detect_prio;
++ int watch_checks;
++ int wait_checks;
+ char * uid_attribute;
+ struct prio prio;
+ char * prio_args;
+@@ -215,6 +222,8 @@ struct multipath {
+ int fast_io_fail;
+ int retain_hwhandler;
+ int deferred_remove;
++ int delay_watch_checks;
++ int delay_wait_checks;
+ unsigned int dev_loss;
+ uid_t uid;
+ gid_t gid;
+Index: multipath-tools-130222/libmultipath/checkers.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers.h
++++ multipath-tools-130222/libmultipath/checkers.h
+@@ -46,6 +46,14 @@
+ * PATH_PENDING:
+ * - Use: All async checkers
+ * - Description: Indicates a check IO is in flight.
++ *
++ * PATH_DELAYED:
++ * - Use: None of the checkers (returned if the path is being delayed before
++ * reintegration.
++ * - Description: If a path fails after being up for less than
++ * delay_watch_checks checks, when it comes back up again, it will not
++ * be marked as up until it has been up for delay_wait_checks checks.
++ * During this time, it is marked as "delayed"
+ */
+ enum path_check_state {
+ PATH_WILD,
+@@ -55,6 +63,7 @@ enum path_check_state {
+ PATH_SHAKY,
+ PATH_GHOST,
+ PATH_PENDING,
++ PATH_DELAYED,
+ PATH_MAX_STATE
+ };
+
+Index: multipath-tools-130222/libmultipath/configure.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/configure.c
++++ multipath-tools-130222/libmultipath/configure.c
+@@ -291,6 +291,8 @@ setup_map (struct multipath * mpp, char
+ select_reservation_key(mpp);
+ select_retain_hwhandler(mpp);
+ select_deferred_remove(mpp);
++ select_delay_watch_checks(mpp);
++ select_delay_wait_checks(mpp);
+
+ sysfs_set_scsi_tmo(mpp);
+ /*
+Index: multipath-tools-130222/libmultipath/defaults.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/defaults.h
++++ multipath-tools-130222/libmultipath/defaults.h
+@@ -20,6 +20,7 @@
+ #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
+ #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
+ #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF
++#define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF
+
+ #define DEFAULT_CHECKINT 5
+ #define MAX_CHECKINT(a) (a << 2)
+Index: multipath-tools-130222/libmultipath/dict.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/dict.c
++++ multipath-tools-130222/libmultipath/dict.c
+@@ -801,6 +801,44 @@ def_ignore_new_boot_devs_handler(vector
+ return 0;
+ }
+
++static int
++def_delay_watch_checks_handler(vector strvec)
++{
++ char * buff;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ conf->delay_watch_checks = DELAY_CHECKS_OFF;
++ else if ((conf->delay_watch_checks = atoi(buff)) < 1)
++ conf->delay_watch_checks = DELAY_CHECKS_OFF;
++
++ FREE(buff);
++ return 0;
++}
++
++static int
++def_delay_wait_checks_handler(vector strvec)
++{
++ char * buff;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ conf->delay_wait_checks = DELAY_CHECKS_OFF;
++ else if ((conf->delay_wait_checks = atoi(buff)) < 1)
++ conf->delay_wait_checks = DELAY_CHECKS_OFF;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * blacklist block handlers
+ */
+@@ -1517,6 +1555,52 @@ hw_deferred_remove_handler(vector strvec
+ return 0;
+ }
+
++static int
++hw_delay_watch_checks_handler(vector strvec)
++{
++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
++ char * buff;
++
++ if (!hwe)
++ return 1;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ hwe->delay_watch_checks = DELAY_CHECKS_OFF;
++ else if ((hwe->delay_watch_checks = atoi(buff)) < 1)
++ hwe->delay_watch_checks = DELAY_CHECKS_OFF;
++
++ FREE(buff);
++ return 0;
++}
++
++static int
++hw_delay_wait_checks_handler(vector strvec)
++{
++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
++ char * buff;
++
++ if (!hwe)
++ return 1;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ hwe->delay_wait_checks = DELAY_CHECKS_OFF;
++ else if ((hwe->delay_wait_checks = atoi(buff)) < 1)
++ hwe->delay_wait_checks = DELAY_CHECKS_OFF;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * multipaths block handlers
+ */
+@@ -1996,6 +2080,52 @@ mp_deferred_remove_handler(vector strvec
+ return 0;
+ }
+
++static int
++mp_delay_watch_checks_handler(vector strvec)
++{
++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
++ char * buff;
++
++ if (!mpe)
++ return 1;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ mpe->delay_watch_checks = DELAY_CHECKS_OFF;
++ else if ((mpe->delay_watch_checks = atoi(buff)) < 1)
++ mpe->delay_watch_checks = DELAY_CHECKS_OFF;
++
++ FREE(buff);
++ return 0;
++}
++
++static int
++mp_delay_wait_checks_handler(vector strvec)
++{
++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
++ char * buff;
++
++ if (!mpe)
++ return 1;
++
++ buff = set_value(strvec);
++ if (!buff)
++ return 1;
++
++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
++ (strlen(buff) == 1 && !strcmp(buff, "0")))
++ mpe->delay_wait_checks = DELAY_CHECKS_OFF;
++ else if ((mpe->delay_wait_checks = atoi(buff)) < 1)
++ mpe->delay_wait_checks = DELAY_CHECKS_OFF;
++
++ FREE(buff);
++ return 0;
++}
++
+ /*
+ * config file keywords printing
+ */
+@@ -2258,6 +2388,30 @@ snprint_mp_deferred_remove (char * buff,
+ }
+
+ static int
++snprint_mp_delay_watch_checks(char * buff, int len, void * data)
++{
++ struct mpentry * mpe = (struct mpentry *)data;
++
++ if (mpe->delay_watch_checks == DELAY_CHECKS_UNDEF)
++ return 0;
++ if (mpe->delay_watch_checks == DELAY_CHECKS_OFF)
++ return snprintf(buff, len, "no");
++ return snprintf(buff, len, "%d", mpe->delay_watch_checks);
++}
++
++static int
++snprint_mp_delay_wait_checks(char * buff, int len, void * data)
++{
++ struct mpentry * mpe = (struct mpentry *)data;
++
++ if (mpe->delay_wait_checks == DELAY_CHECKS_UNDEF)
++ return 0;
++ if (mpe->delay_wait_checks == DELAY_CHECKS_OFF)
++ return snprintf(buff, len, "no");
++ return snprintf(buff, len, "%d", mpe->delay_wait_checks);
++}
++
++static int
+ snprint_hw_fast_io_fail(char * buff, int len, void * data)
+ {
+ struct hwentry * hwe = (struct hwentry *)data;
+@@ -2586,6 +2740,30 @@ snprint_hw_deferred_remove(char * buff,
+ }
+
+ static int
++snprint_hw_delay_watch_checks(char * buff, int len, void * data)
++{
++ struct hwentry * hwe = (struct hwentry *)data;
++
++ if (hwe->delay_watch_checks == DELAY_CHECKS_UNDEF)
++ return 0;
++ if (hwe->delay_watch_checks == DELAY_CHECKS_OFF)
++ return snprintf(buff, len, "no");
++ return snprintf(buff, len, "%d", hwe->delay_watch_checks);
++}
++
++static int
++snprint_hw_delay_wait_checks(char * buff, int len, void * data)
++{
++ struct hwentry * hwe = (struct hwentry *)data;
++
++ if (hwe->delay_wait_checks == DELAY_CHECKS_UNDEF)
++ return 0;
++ if (hwe->delay_wait_checks == DELAY_CHECKS_OFF)
++ return snprintf(buff, len, "no");
++ return snprintf(buff, len, "%d", hwe->delay_wait_checks);
++}
++
++static int
+ snprint_detect_prio(char * buff, int len, void * data)
+ {
+ struct hwentry * hwe = (struct hwentry *)data;
+@@ -2883,7 +3061,6 @@ snprint_def_find_multipaths (char * buff
+ return snprintf(buff, len, "yes");
+ }
+
+-
+ static int
+ snprint_def_user_friendly_names (char * buff, int len, void * data)
+ {
+@@ -2989,7 +3166,6 @@ snprint_def_ignore_new_boot_devs(char *
+ return snprintf(buff, len, "no");
+ }
+
+-
+ static int
+ snprint_def_config_dir (char * buff, int len, void * data)
+ {
+@@ -3000,6 +3176,24 @@ snprint_def_config_dir (char * buff, int
+ }
+
+ static int
++snprint_def_delay_watch_checks(char * buff, int len, void * data)
++{
++ if (conf->delay_watch_checks == DELAY_CHECKS_UNDEF ||
++ conf->delay_watch_checks == DELAY_CHECKS_OFF)
++ return snprintf(buff, len, "no");
++ return snprintf(buff, len, "%d", conf->delay_watch_checks);
++}
++
++static int
++snprint_def_delay_wait_checks(char * buff, int len, void * data)
++{
++ if (conf->delay_wait_checks == DELAY_CHECKS_UNDEF ||
++ conf->delay_wait_checks == DELAY_CHECKS_OFF)
++ return snprintf(buff, len, "no");
++ return snprintf(buff, len, "%d", conf->delay_wait_checks);
++}
++
++static int
+ snprint_ble_simple (char * buff, int len, void * data)
+ {
+ struct blentry * ble = (struct blentry *)data;
+@@ -3071,6 +3265,8 @@ init_keywords(void)
+ install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
+ install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs);
+ install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir);
++ install_keyword("delay_watch_checks", &def_delay_watch_checks_handler, &snprint_def_delay_watch_checks);
++ install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks);
+ __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);
+@@ -3136,6 +3332,8 @@ init_keywords(void)
+ install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler);
+ install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio);
+ 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_sublevel_end();
+
+ install_keyword_root("multipaths", &multipaths_handler);
+@@ -3161,5 +3359,7 @@ init_keywords(void)
+ install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key);
+ install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names);
+ 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_sublevel_end();
+ }
+Index: multipath-tools-130222/libmultipath/print.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/print.c
++++ multipath-tools-130222/libmultipath/print.c
+@@ -336,6 +336,8 @@ snprint_chk_state (char * buff, size_t l
+ return snprintf(buff, len, "shaky");
+ case PATH_GHOST:
+ return snprintf(buff, len, "ghost");
++ case PATH_DELAYED:
++ return snprintf(buff, len, "delayed");
+ default:
+ return snprintf(buff, len, "undef");
+ }
+Index: multipath-tools-130222/libmultipath/propsel.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.c
++++ multipath-tools-130222/libmultipath/propsel.c
+@@ -788,3 +788,55 @@ select_detect_prio (struct path * pp)
+ condlog(3, "%s: detect_prio = %d (compiled in default)", pp->dev, pp->detect_prio);
+ return 0;
+ }
++
++extern int
++select_delay_watch_checks (struct multipath * mp)
++{
++ if (mp->mpe && mp->mpe->delay_watch_checks != DELAY_CHECKS_UNDEF) {
++ mp->delay_watch_checks = mp->mpe->delay_watch_checks;
++ condlog(3, "delay_watch_checks = %i (multipath setting)",
++ mp->delay_watch_checks);
++ return 0;
++ }
++ if (mp->hwe && mp->hwe->delay_watch_checks != DELAY_CHECKS_UNDEF) {
++ mp->delay_watch_checks = mp->hwe->delay_watch_checks;
++ condlog(3, "delay_watch_checks = %i (controler setting)",
++ mp->delay_watch_checks);
++ return 0;
++ }
++ if (conf->delay_watch_checks != DELAY_CHECKS_UNDEF) {
++ mp->delay_watch_checks = conf->delay_watch_checks;
++ condlog(3, "delay_watch_checks = %i (config file default)",
++ mp->delay_watch_checks);
++ return 0;
++ }
++ mp->delay_watch_checks = DEFAULT_DELAY_CHECKS;
++ condlog(3, "delay_watch_checks = DISABLED (internal default)");
++ return 0;
++}
++
++extern int
++select_delay_wait_checks (struct multipath * mp)
++{
++ if (mp->mpe && mp->mpe->delay_wait_checks != DELAY_CHECKS_UNDEF) {
++ mp->delay_wait_checks = mp->mpe->delay_wait_checks;
++ condlog(3, "delay_wait_checks = %i (multipath setting)",
++ mp->delay_wait_checks);
++ return 0;
++ }
++ if (mp->hwe && mp->hwe->delay_wait_checks != DELAY_CHECKS_UNDEF) {
++ mp->delay_wait_checks = mp->hwe->delay_wait_checks;
++ condlog(3, "delay_wait_checks = %i (controler setting)",
++ mp->delay_wait_checks);
++ return 0;
++ }
++ if (conf->delay_wait_checks != DELAY_CHECKS_UNDEF) {
++ mp->delay_wait_checks = conf->delay_wait_checks;
++ condlog(3, "delay_wait_checks = %i (config file default)",
++ mp->delay_wait_checks);
++ return 0;
++ }
++ mp->delay_wait_checks = DEFAULT_DELAY_CHECKS;
++ condlog(3, "delay_wait_checks = DISABLED (internal default)");
++ return 0;
++}
+Index: multipath-tools-130222/libmultipath/propsel.h
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/propsel.h
++++ multipath-tools-130222/libmultipath/propsel.h
+@@ -21,3 +21,5 @@ int select_reservation_key(struct multip
+ int select_retain_hwhandler (struct multipath * mp);
+ int select_detect_prio(struct path * pp);
+ int select_deferred_remove(struct multipath *mp);
++int select_delay_watch_checks (struct multipath * mp);
++int select_delay_wait_checks (struct multipath * mp);
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -188,7 +188,8 @@ sync_map_state(struct multipath *mpp)
+ vector_foreach_slot (mpp->pg, pgp, i){
+ vector_foreach_slot (pgp->paths, pp, j){
+ if (pp->state == PATH_UNCHECKED ||
+- pp->state == PATH_WILD)
++ pp->state == PATH_WILD ||
++ pp->state == PATH_DELAYED)
+ continue;
+ if ((pp->dmstate == PSTATE_FAILED ||
+ pp->dmstate == PSTATE_UNDEF) &&
+@@ -1165,6 +1166,16 @@ check_path (struct vectors * vecs, struc
+ if (!pp->mpp)
+ return;
+
++ if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
++ pp->wait_checks > 0) {
++ if (pp->mpp && pp->mpp->nr_active > 0) {
++ pp->state = PATH_DELAYED;
++ pp->wait_checks--;
++ return;
++ } else
++ pp->wait_checks = 0;
++ }
++
+ pp->chkrstate = newstate;
+ if (newstate != pp->state) {
+ int oldstate = pp->state;
+@@ -1182,9 +1193,14 @@ check_path (struct vectors * vecs, struc
+ * proactively fail path in the DM
+ */
+ if (oldstate == PATH_UP ||
+- oldstate == PATH_GHOST)
++ oldstate == PATH_GHOST) {
+ fail_path(pp, 1);
+- else
++ if (pp->mpp->delay_wait_checks > 0 &&
++ pp->watch_checks > 0) {
++ pp->wait_checks = pp->mpp->delay_wait_checks;
++ pp->watch_checks = 0;
++ }
++ }else
+ fail_path(pp, 0);
+
+ /*
+@@ -1211,11 +1227,15 @@ check_path (struct vectors * vecs, struc
+ * reinstate this path
+ */
+ if (oldstate != PATH_UP &&
+- oldstate != PATH_GHOST)
++ oldstate != PATH_GHOST) {
++ if (pp->mpp->delay_watch_checks > 0)
++ pp->watch_checks = pp->mpp->delay_watch_checks;
+ reinstate_path(pp, 1);
+- else
++ } else {
++ if (pp->watch_checks > 0)
++ pp->watch_checks--;
+ reinstate_path(pp, 0);
+-
++ }
+ new_path_up = 1;
+
+ if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
+@@ -1245,6 +1265,8 @@ check_path (struct vectors * vecs, struc
+ else
+ pp->checkint = conf->max_checkint;
+ }
++ if (pp->watch_checks > 0)
++ pp->watch_checks--;
+ pp->tick = pp->checkint;
+ condlog(4, "%s: delay next check %is",
+ pp->dev_t, pp->tick);
+Index: multipath-tools-130222/multipath.conf.annotated
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.annotated
++++ multipath-tools-130222/multipath.conf.annotated
+@@ -242,6 +242,30 @@
+ # # files, just as if it was in /etc/multipath.conf
+ # # values : "" or a fully qualified pathname
+ # # default : "/etc/multipath/conf.d"
++#
++# #
++# # name : delay_watch_checks
++# # scope : multipathd
++# # desc : If set to a value greater than 0, multipathd will watch
++# # paths that have recently become valid for this many
++# # checks. If they fail again while they are being watched,
++# # when they next become valid, they will not be used until
++# # they have stayed up for delay_wait_checks checks.
++# # values : no|<n> > 0
++# # default : no
++# delay_watch_checks 12
++#
++# #
++# # name : delay_wait_checks
++# # scope : multipathd
++# # desc : If set to a value greater than 0, when a device that has
++# # recently come back online fails again within
++# # delay_watch_checks checks, the next time it comes back
++# # online, it will marked and delayed, and not used until
++# # it has passed delay_wait_checks checks.
++# # values : no|<n> > 0
++# # default : no
++# delay_wait_checks 12
+ #}
+ #
+ ##
+@@ -383,6 +407,13 @@
+ # #
+ # flush_on_last_del yes
+ #
++# #
++# # name : delay_watch_checks
++# # See defualts section for information.
++#
++# #
++# # name : delay_wait_checks
++# # See defualts section for information.
+ # }
+ # multipath {
+ # wwid 1DEC_____321816758474
+@@ -566,6 +597,15 @@
+ # # before removing it from the system.
+ # # values : n > 0
+ # dev_loss_tmo 600
++#
++# #
++# # name : delay_watch_checks
++# # See defaults section for information.
++#
++# #
++# # name : delay_wait_checks
++# # See defaults section for information.
++#
+ # }
+ # device {
+ # vendor "COMPAQ "
+Index: multipath-tools-130222/multipath.conf.defaults
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.defaults
++++ multipath-tools-130222/multipath.conf.defaults
+@@ -27,6 +27,8 @@
+ # retain_attached_hw_handler no
+ # detect_prio no
+ # config_dir "/etc/multipath/conf.d"
++# delay_watch_checks no
++# delay_wait_checks no
+ #}
+ #blacklist {
+ # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
+Index: multipath-tools-130222/multipath/multipath.conf.5
+===================================================================
+--- multipath-tools-130222.orig/multipath/multipath.conf.5
++++ multipath-tools-130222/multipath/multipath.conf.5
+@@ -437,6 +437,25 @@ alphabetically for file ending in ".conf
+ information from them, just as if it was in /etc/multipath.conf. config_dir
+ must either be "" or a fully qualified directory name. Default is
+ .I "/etc/multipath/conf.d"
++.TP
++.B delay_watch_checks
++If set to a value greater than 0, multipathd will watch paths that have
++recently become valid for this many checks. If they fail again while they are
++being watched, when they next become valid, they will not be used until they
++have stayed up for
++.I delay_wait_checks
++checks. Default is
++.I no
++.TP
++.B delay_wait_checks
++If set to a value greater than 0, when a device that has recently come back
++online fails again within
++.I delay_watch_checks
++checks, the next time it comes back online, it will marked and delayed, and not
++used until it has passed
++.I delay_wait_checks
++checks. Default is
++.I no
+ .
+ .SH "blacklist section"
+ The
+@@ -540,6 +559,10 @@ section:
+ .B reservation_key
+ .TP
+ .B deferred_remove
++.TP
++.B delay_watch_checks
++.TP
++.B delay_wait_checks
+ .RE
+ .PD
+ .LP
+@@ -632,6 +655,10 @@ section:
+ .B detect_prio
+ .TP
+ .B deferred_remove
++.TP
++.B delay_watch_checks
++.TP
++.B delay_wait_checks
+ .RE
+ .PD
+ .LP
+Index: multipath-tools-130222/libmultipath/checkers.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/checkers.c
++++ multipath-tools-130222/libmultipath/checkers.c
+@@ -16,7 +16,8 @@ char *checker_state_names[] = {
+ "up",
+ "shaky",
+ "ghost",
+- "pending"
++ "pending",
++ "delayed"
+ };
+
+ static LIST_HEAD(checkers);
+Index: multipath-tools-130222/libmultipath/config.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/config.c
++++ multipath-tools-130222/libmultipath/config.c
+@@ -341,6 +341,8 @@ merge_hwe (struct hwentry * dst, struct
+ merge_num(retain_hwhandler);
+ merge_num(detect_prio);
+ merge_num(deferred_remove);
++ merge_num(delay_watch_checks);
++ merge_num(delay_wait_checks);
+
+ /*
+ * Make sure features is consistent with
+@@ -399,6 +401,8 @@ overwrite_hwe (struct hwentry * dst, str
+ overwrite_num(retain_hwhandler);
+ overwrite_num(detect_prio);
+ overwrite_num(deferred_remove);
++ overwrite_num(delay_watch_checks);
++ overwrite_num(delay_wait_checks);
+
+ /*
+ * Make sure features is consistent with
--- /dev/null
+---
+ multipathd/main.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+Index: multipath-tools-130222/multipathd/main.c
+===================================================================
+--- multipath-tools-130222.orig/multipathd/main.c
++++ multipath-tools-130222/multipathd/main.c
+@@ -310,10 +310,15 @@ ev_add_map (char * dev, char * alias, st
+ /*
+ * now we can register the map
+ */
+- if (map_present && (mpp = add_map_without_path(vecs, alias))) {
+- sync_map_state(mpp);
+- condlog(2, "%s: devmap %s registered", alias, dev);
+- return 0;
++ if (map_present) {
++ if ((mpp = add_map_without_path(vecs, alias))) {
++ sync_map_state(mpp);
++ condlog(2, "%s: devmap %s registered", alias, dev);
++ return 0;
++ } else {
++ condlog(2, "%s: uev_add_map failed", dev);
++ return 1;
++ }
+ }
+ r = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec, &refwwid);
+
--- /dev/null
+---
+ libmultipath/hwtable.c | 30 ++++++++++++++++++++++++++++++
+ multipath.conf.defaults | 26 ++++++++++++++++++++++++++
+ 2 files changed, 56 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/hwtable.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/hwtable.c
++++ multipath-tools-130222/libmultipath/hwtable.c
+@@ -772,6 +772,36 @@ static struct hwentry default_hw[] = {
+ .prio_name = PRIO_RDAC,
+ .prio_args = NULL,
+ },
++ {
++ /* DELL MD36xxi */
++ .vendor = "DELL",
++ .product = "MD36xxi",
++ .bl_product = "Universal Xport",
++ .features = "2 pg_init_retries 50",
++ .hwhandler = "1 rdac",
++ .pgpolicy = GROUP_BY_PRIO,
++ .pgfailback = -FAILBACK_IMMEDIATE,
++ .rr_weight = RR_WEIGHT_NONE,
++ .no_path_retry = 15,
++ .checker_name = RDAC,
++ .prio_name = PRIO_RDAC,
++ .prio_args = NULL,
++ },
++ {
++ /* DELL MD36xxf */
++ .vendor = "DELL",
++ .product = "MD36xxf",
++ .bl_product = "Universal Xport",
++ .features = "2 pg_init_retries 50",
++ .hwhandler = "1 rdac",
++ .pgpolicy = GROUP_BY_PRIO,
++ .pgfailback = -FAILBACK_IMMEDIATE,
++ .rr_weight = RR_WEIGHT_NONE,
++ .no_path_retry = 15,
++ .checker_name = RDAC,
++ .prio_name = PRIO_RDAC,
++ .prio_args = NULL,
++ },
+ /*
+ * NETAPP controller family
+ *
+Index: multipath-tools-130222/multipath.conf.defaults
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.defaults
++++ multipath-tools-130222/multipath.conf.defaults
+@@ -655,6 +655,32 @@
+ # no_path_retry 15
+ # }
+ # device {
++# vendor "DELL"
++# product "MD36xxi"
++# product_blacklist "Universal Xport"
++# path_grouping_policy "group_by_prio"
++# path_checker "rdac"
++# features "2 pg_init_retries 50"
++# hardware_handler "1 rdac"
++# prio "rdac"
++# failback "immediate"
++# rr_weight "uniform"
++# no_path_retry 15
++# }
++# device {
++# vendor "DELL"
++# product "MD36xxf"
++# product_blacklist "Universal Xport"
++# path_grouping_policy "group_by_prio"
++# path_checker "rdac"
++# features "2 pg_init_retries 50"
++# hardware_handler "1 rdac"
++# prio "rdac"
++# failback "immediate"
++# rr_weight "uniform"
++# no_path_retry 15
++# }
++# device {
+ # vendor "NETAPP"
+ # product "LUN.*"
+ # path_grouping_policy "group_by_prio"
--- /dev/null
+---
+ libmultipath/hwtable.c | 2 ++
+ multipath.conf.defaults | 2 ++
+ 2 files changed, 4 insertions(+)
+
+Index: multipath-tools-130222/libmultipath/hwtable.c
+===================================================================
+--- multipath-tools-130222.orig/libmultipath/hwtable.c
++++ multipath-tools-130222/libmultipath/hwtable.c
+@@ -272,6 +272,8 @@ static struct hwentry default_hw[] = {
+ .checker_name = EMC_CLARIION,
+ .prio_name = PRIO_EMC,
+ .prio_args = NULL,
++ .retain_hwhandler = RETAIN_HWHANDLER_ON,
++ .detect_prio = DETECT_PRIO_ON,
+ },
+ {
+ .vendor = "EMC",
+Index: multipath-tools-130222/multipath.conf.defaults
+===================================================================
+--- multipath-tools-130222.orig/multipath.conf.defaults
++++ multipath-tools-130222/multipath.conf.defaults
+@@ -261,6 +261,8 @@
+ # failback immediate
+ # rr_weight "uniform"
+ # no_path_retry 60
++# retain_attached_hw_handler yes
++# detect_prio yes
+ # }
+ # device {
+ # vendor "EMC"