Imported Upstream version 0.7.2 upstream/0.7.2
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:17 +0000 (13:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:17 +0000 (13:50 +0900)
57 files changed:
Makefile
Makefile.inc
kpartx/Makefile
kpartx/devmapper.c
kpartx/devmapper.h
kpartx/kpartx.c
kpartx/kpartx.rules
kpartx/lopart.c
kpartx/lopart.h
kpartx/sysmacros.h [deleted file]
kpartx/test-kpartx [new file with mode: 0755]
libdmmp/Makefile
libmpathcmd/Makefile
libmpathpersist/Makefile
libmpathpersist/mpath_persist.c
libmpathpersist/mpath_persist.h
libmpathpersist/mpath_pr_ioctl.c
libmpathpersist/mpath_updatepr.c
libmpathpersist/mpathpr.h
libmultipath/Makefile
libmultipath/checkers/Makefile
libmultipath/config.c
libmultipath/configure.c
libmultipath/configure.h
libmultipath/debug.c
libmultipath/devmapper.c
libmultipath/devmapper.h
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/dmparser.c
libmultipath/hwtable.c
libmultipath/print.c
libmultipath/prio.h
libmultipath/prioritizers/Makefile
libmultipath/prioritizers/datacore.c
libmultipath/prioritizers/path_latency.c [new file with mode: 0644]
libmultipath/propsel.c
libmultipath/propsel.h
libmultipath/structs.c
libmultipath/structs.h
libmultipath/uevent.c
libmultipath/util.c
libmultipath/util.h
libmultipath/version.h
libmultipath/waiter.c
mpathpersist/Makefile
mpathpersist/main.c
mpathpersist/mpathpersist.8
multipath/Makefile
multipath/main.c
multipath/multipath.conf.5
multipathd/Makefile
multipathd/cli_handlers.c
multipathd/main.c
multipathd/multipathd.8
third-party/valgrind/drd.h
third-party/valgrind/valgrind.h

index cfee0d070e0c70baddcae5f620928b7256bfefd0..bfb168fb172c289d62227c2a41b0d18c83028b73 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,28 +2,6 @@
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
 
-#
-# Try to supply the linux kernel headers.
-#
-ifeq ($(KRNLSRC),)
-       KRNLLIB = /lib/modules/$(shell uname -r)
-       ifeq ($(shell test -r $(KRNLLIB)/source && echo 1),1)
-               KRNLSRC = $(KRNLLIB)/source
-               KRNLOBJ = $(KRNLLIB)/build
-       else
-               KRNLSRC = $(KRNLLIB)/build
-               KRNLOBJ = $(KRNLLIB)/build
-       endif
-       export KRNLSRC
-       export KRNLOBJ
-endif
-
-ifeq ($(MULTIPATH_VERSION),)
-       VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
-else
-       VERSION = $(MULTIPATH_VERSION)
-endif
-
 BUILDDIRS = \
        libmpathcmd \
        libmultipath \
@@ -43,10 +21,7 @@ endif
 all: recurse
 
 recurse:
-       @for dir in $(BUILDDIRS); do \
-       $(MAKE) -C $$dir VERSION=$(VERSION) \
-               KRNLSRC=$(KRNLSRC) KRNLOBJ=$(KRNLOBJ) || exit $?; \
-       done
+       @for dir in $(BUILDDIRS); do $(MAKE) -C $$dir || exit $?; done
 
 recurse_clean:
        @for dir in $(BUILDDIRS); do \
index 8361e6c4866e1e95cb1ac7f5657833a1c0b48dd5..29c290a22e8f5d9ba6b21b4322ce267195fc4a6a 100644 (file)
@@ -47,6 +47,7 @@ endif
 
 prefix         =
 exec_prefix    = $(prefix)
+usr_prefix     = $(prefix)
 bindir         = $(exec_prefix)/sbin
 libudevdir     = $(prefix)/$(SYSTEMDPATH)/udev
 udevrulesdir   = $(libudevdir)/rules.d
@@ -55,6 +56,7 @@ man8dir               = $(prefix)/usr/share/man/man8
 man5dir                = $(prefix)/usr/share/man/man5
 man3dir                = $(prefix)/usr/share/man/man3
 syslibdir      = $(prefix)/$(LIB)
+usrlibdir      = $(usr_prefix)/$(LIB)
 libdir         = $(prefix)/$(LIB)/multipath
 unitdir                = $(prefix)/$(SYSTEMDPATH)/systemd/system
 mpathpersistdir        = $(TOPDIR)/libmpathpersist
@@ -62,21 +64,38 @@ mpathcmddir = $(TOPDIR)/libmpathcmd
 thirdpartydir  = $(TOPDIR)/third-party
 libdmmpdir     = $(TOPDIR)/libdmmp
 includedir     = $(prefix)/usr/include
-pkgconfdir     = $(prefix)/$(LIB)/pkgconfig
+pkgconfdir     = $(usrlibdir)/pkgconfig
 
 GZIP           = gzip -9 -c
 RM             = rm -f
 LN             = ln -sf
 INSTALL_PROGRAM        = install
 
+# $(call TEST_CC_OPTION,option,fallback)
+# Test if the C compiler supports the option.
+# Evaluates to "option" if yes, and "fallback" otherwise.
+TEST_CC_OPTION = $(shell \
+       if echo 'int main(void){return 0;}' | $(CC) -o /dev/null -c "$(1)" -xc - &>/dev/null; \
+       then \
+               echo "$(1)"; \
+       else \
+               echo "$(2)"; \
+       fi)
+
+STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
+
 OPTFLAGS       = -O2 -g -pipe -Wall -Wextra -Wformat=2 -Werror=implicit-int \
                  -Werror=implicit-function-declaration -Werror=format-security \
                  -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered \
-                 -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector-strong \
+                 -Wp,-D_FORTIFY_SOURCE=2 $(STACKPROT) \
                  --param=ssp-buffer-size=4
 
-CFLAGS         = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
+CFLAGS         = $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
+BIN_CFLAGS     = -fPIE -DPIE
+LIB_CFLAGS     = -fPIC
 SHARED_FLAGS   = -shared
+LDFLAGS                = -Wl,-z,relro -Wl,-z,now
+BIN_LDFLAGS    = -pie
 
 # Check whether a function with name $1 has been declared in header file $2.
 check_func =                                                                  \
@@ -92,5 +111,18 @@ check_func =                                                                       \
        echo "$$found"                                                         \
     )
 
+# Checker whether a file with name $1 exists
+check_file = $(shell   \
+       if [ -f "$1" ]; then \
+               found=1; \
+               status="yes"; \
+       else \
+               found=0; \
+               status="no"; \
+       fi; \
+       echo 1>&2 "Checking if $1 exists ... $$status"; \
+       echo "$$found" \
+       )
+
 %.o:   %.c
        $(CC) $(CFLAGS) -c -o $@ $<
index 9441a2ba41ee04eef952bb628331e80a03dffdf5..7b75032ef1aba00c6b443d38305352fe8d55e868 100644 (file)
@@ -3,7 +3,8 @@
 #
 include ../Makefile.inc
 
-CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+CFLAGS += $(BIN_CFLAGS) -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+LDFLAGS += $(BIN_LDFLAGS)
 
 LIBDEPS += -ldevmapper
 
index cf6650c6f7429df4f4fe4cfd27d04fd6fdf67201..4ab58ce90151cf0ba83fb4078222ef474b83c3d5 100644 (file)
@@ -8,10 +8,13 @@
 #include <libdevmapper.h>
 #include <ctype.h>
 #include <errno.h>
+#include <sys/sysmacros.h>
 #include "devmapper.h"
 
-#define UUID_PREFIX "part%d-"
-#define MAX_PREFIX_LEN 8
+#define _UUID_PREFIX "part"
+#define UUID_PREFIX _UUID_PREFIX "%d-"
+#define _UUID_PREFIX_LEN (sizeof(_UUID_PREFIX) - 1)
+#define MAX_PREFIX_LEN (_UUID_PREFIX_LEN + 4)
 #define PARAMS_SIZE 1024
 
 int dm_prereq(char * str, int x, int y, int z)
@@ -292,7 +295,7 @@ dm_devn (const char * mapname, int *major, int *minor)
        if (!dm_task_run(dmt))
                goto out;
 
-       if (!dm_task_get_info(dmt, &info))
+       if (!dm_task_get_info(dmt, &info) || info.exists == 0)
                goto out;
 
        *major = info.major;
@@ -389,10 +392,11 @@ dm_type(const char * name, char * type)
                goto out;
 
        /* Fetch 1st target */
-       dm_get_next_target(dmt, NULL, &start, &length,
-                          &target_type, &params);
-
-       if (!target_type)
+       if (dm_get_next_target(dmt, NULL, &start, &length,
+                              &target_type, &params) != NULL)
+               /* more than one target */
+               r = -1;
+       else if (!target_type)
                r = -1;
        else if (!strcmp(target_type, type))
                r = 1;
@@ -417,9 +421,13 @@ dm_compare_uuid(const char *mapuuid, const char *partname)
        if (!partuuid)
                return 1;
 
-       if (!strncmp(partuuid, "part", 4)) {
-               char *p = strstr(partuuid, "mpath-");
-               if (p && !strcmp(mapuuid, p))
+       if (!strncmp(partuuid, _UUID_PREFIX, _UUID_PREFIX_LEN)) {
+               char *p = partuuid + _UUID_PREFIX_LEN;
+               /* skip partition number */
+               while (isdigit(*p))
+                       p++;
+               if (p != partuuid + _UUID_PREFIX_LEN && *p == '-' &&
+                   !strcmp(mapuuid, p + 1))
                        r = 0;
        }
        free(partuuid);
@@ -432,6 +440,7 @@ struct remove_data {
 
 static int
 do_foreach_partmaps (const char * mapname, const char *uuid,
+                    dev_t devt,
                     int (*partmap_func)(const char *, void *),
                     void *data)
 {
@@ -443,6 +452,7 @@ do_foreach_partmaps (const char * mapname, const char *uuid,
        int major, minor;
        char dev_t[32];
        int r = 1;
+       int is_dmdev = 1;
 
        if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
                return 1;
@@ -460,15 +470,20 @@ do_foreach_partmaps (const char * mapname, const char *uuid,
                goto out;
        }
 
-       if (dm_devn(mapname, &major, &minor))
-               goto out;
+       if (dm_devn(mapname, &major, &minor) ||
+           (major != major(devt) || minor != minor(devt)))
+               /*
+                * The latter could happen if a dm device "/dev/mapper/loop0"
+                * exits while kpartx is called on "/dev/loop0".
+                */
+               is_dmdev = 0;
 
-       sprintf(dev_t, "%d:%d", major, minor);
+       sprintf(dev_t, "%d:%d", major(devt), minor(devt));
        do {
                /*
                 * skip our devmap
                 */
-               if (!strcmp(names->name, mapname))
+               if (is_dmdev && !strcmp(names->name, mapname))
                        goto next;
 
                /*
@@ -486,7 +501,7 @@ do_foreach_partmaps (const char * mapname, const char *uuid,
                /*
                 * skip if devmap target is not "linear"
                 */
-               if (!dm_type(names->name, "linear")) {
+               if (dm_type(names->name, "linear") != 1) {
                        if (rd->verbose)
                                printf("%s: is not a linear target. Not removing\n",
                                       names->name);
@@ -496,7 +511,7 @@ do_foreach_partmaps (const char * mapname, const char *uuid,
                /*
                 * skip if uuids don't match
                 */
-               if (dm_compare_uuid(uuid, names->name)) {
+               if (uuid && dm_compare_uuid(uuid, names->name)) {
                        if (rd->verbose)
                                printf("%s: is not a kpartx partition. Not removing\n",
                                       names->name);
@@ -537,37 +552,8 @@ remove_partmap(const char *name, void *data)
 }
 
 int
-dm_remove_partmaps (char * mapname, char *uuid, int verbose)
+dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose)
 {
        struct remove_data rd = { verbose };
-       return do_foreach_partmaps(mapname, uuid, remove_partmap, &rd);
-}
-
-#define FEATURE_NO_PART "no_partitions"
-
-int
-dm_no_partitions(char *mapname)
-{
-       char params[PARAMS_SIZE], *ptr;
-       int i, num_features;
-
-       if (dm_get_map(mapname, params))
-               return 0;
-
-       ptr = params;
-       num_features = strtoul(params, &ptr, 10);
-       if ((ptr == params) || num_features == 0) {
-               /* No features found, return success */
-               return 0;
-       }
-       for (i = 0; (i < num_features); i++) {
-               if (!ptr || ptr > params + strlen(params))
-                       break;
-               /* Skip whitespaces */
-               while(ptr && *ptr == ' ') ptr++;
-               if (!strncmp(ptr, FEATURE_NO_PART, strlen(FEATURE_NO_PART)))
-                       return 1;
-               ptr = strchr(ptr, ' ');
-       }
-       return 0;
+       return do_foreach_partmaps(mapname, uuid, devt, remove_partmap, &rd);
 }
index 9988ec0f825fabef25a18d1d7c0a6070bddbdf91..2e28c780fbe67042f0ff583c83ba6daafe5ae4c6 100644 (file)
@@ -18,7 +18,7 @@ char * dm_mapname(int major, int minor);
 dev_t dm_get_first_dep(char *devname);
 char * dm_mapuuid(const char *mapname);
 int dm_devn (const char * mapname, int *major, int *minor);
-int dm_remove_partmaps (char * mapname, char *uuid, int verbose);
+int dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose);
 int dm_no_partitions(char * mapname);
 
 #endif /* _KPARTX_DEVMAPPER_H */
index 58e60ffe3023453fde58d9a89e87a8a619ec25bf..9ba78d01cd2dcbcff1d3caa4f9a183b087b549b9 100644 (file)
@@ -58,7 +58,32 @@ struct pt {
 } pts[MAXTYPES];
 
 int ptct = 0;
-int udev_sync = 0;
+int udev_sync = 1;
+
+/*
+ * UUID format for partitions created on non-DM devices
+ * ${UUID_PREFIX}devnode_${MAJOR}:${MINOR}_${NONDM_UUID_SUFFIX}"
+ * where ${UUID_PREFIX} is "part${PARTNO}-" (see devmapper.c).
+ *
+ * The suffix should be sufficiently unique to avoid incidental conflicts;
+ * the value below is a base64-encoded random number.
+ * The UUID format shouldn't be changed between kpartx releases.
+ */
+#define NONDM_UUID_PREFIX "devnode"
+#define NONDM_UUID_SUFFIX "Wh5pYvM"
+
+static char *
+nondm_create_uuid(dev_t devt)
+{
+#define NONDM_UUID_BUFLEN (34 + sizeof(NONDM_UUID_PREFIX) + \
+                          sizeof(NONDM_UUID_SUFFIX))
+       static char uuid_buf[NONDM_UUID_BUFLEN];
+       snprintf(uuid_buf, sizeof(uuid_buf), "%s_%u:%u_%s",
+                NONDM_UUID_PREFIX, major(devt), minor(devt),
+                NONDM_UUID_SUFFIX);
+       uuid_buf[NONDM_UUID_BUFLEN-1] = '\0';
+       return uuid_buf;
+}
 
 static void
 addpts(char *t, ptreader f)
@@ -86,7 +111,7 @@ initpts(void)
        addpts("ps3", read_ps3_pt);
 }
 
-static char short_opts[] = "rladfgvp:t:su";
+static char short_opts[] = "rladfgvp:t:snu";
 
 /* Used in gpt.c */
 int force_gpt=0;
@@ -105,7 +130,8 @@ usage(void) {
        printf("\t-g force GUID partition table (GPT)\n");
        printf("\t-f force devmap create\n");
        printf("\t-v verbose\n");
-       printf("\t-s sync mode. Don't return until the partitions are created\n");
+       printf("\t-n nosync mode. Return before the partitions are created\n");
+       printf("\t-s sync mode. Don't return until the partitions are created. Default.\n");
        return 1;
 }
 
@@ -114,10 +140,13 @@ set_delimiter (char * device, char * delimiter)
 {
        char * p = device;
 
-       while (*(p++) != 0x0)
+       if (*p == 0x0)
+               return;
+
+       while (*(++p) != 0x0)
                continue;
 
-       if (isdigit(*(p - 2)))
+       if (isdigit(*(p - 1)))
                *delimiter = 'p';
 }
 
@@ -136,15 +165,17 @@ strip_slash (char * device)
 static int
 find_devname_offset (char * device)
 {
-       char *p, *q = NULL;
+       char *p, *q;
 
-       p = device;
+       q = p = device;
 
-       while (*p++)
+       while (*p) {
                if (*p == '/')
-                       q = p;
+                       q = p + 1;
+               p++;
+       }
 
-       return (int)(q - device) + 1;
+       return (int)(q - device);
 }
 
 static char *
@@ -291,6 +322,9 @@ main(int argc, char **argv){
                case 's':
                        udev_sync = 1;
                        break;
+               case 'n':
+                       udev_sync = 0;
+                       break;
                case 'u':
                        what = UPDATE;
                        break;
@@ -330,7 +364,13 @@ main(int argc, char **argv){
 
        if (S_ISREG (buf.st_mode)) {
                /* already looped file ? */
-               loopdev = find_loop_by_file(device);
+               char rpath[PATH_MAX];
+               if (realpath(device, rpath) == NULL) {
+                       fprintf(stderr, "Error: %s: %s\n", device,
+                               strerror(errno));
+                       exit (1);
+               }
+               loopdev = find_loop_by_file(rpath);
 
                if (!loopdev && what == DELETE)
                        exit (0);
@@ -351,6 +391,10 @@ main(int argc, char **argv){
                        exit (1);
                }
        }
+       else if (!S_ISBLK(buf.st_mode)) {
+               fprintf(stderr, "invalid device: %s\n", device);
+               exit(1);
+       }
 
        off = find_devname_offset(device);
 
@@ -360,13 +404,17 @@ main(int argc, char **argv){
                        uuid = dm_mapuuid(mapname);
        }
 
+       /*
+        * We are called for a non-DM device.
+        * Make up a fake UUID for the device, unless "-d -f" is given.
+        * This allows deletion of partitions created with older kpartx
+        * versions which didn't use the fake UUID during creation.
+        */
+       if (!uuid && !(what == DELETE && force_devmap))
+               uuid = nondm_create_uuid(buf.st_rdev);
+
        if (!mapname)
                mapname = device + off;
-       if (!force_devmap &&
-                dm_no_partitions(mapname)) {
-               /* Feature 'no_partitions' is set, return */
-               return 0;
-       }
 
        if (delim == NULL) {
                delim = malloc(DELIM_SIZE);
@@ -451,7 +499,8 @@ main(int argc, char **argv){
                        break;
 
                case DELETE:
-                       r = dm_remove_partmaps(mapname, uuid, verbose);
+                       r = dm_remove_partmaps(mapname, uuid, buf.st_rdev,
+                                              verbose);
                        if (loopdev) {
                                if (del_loop(loopdev)) {
                                        if (verbose)
index 48a4d6c2bd966d5929d29bacfb03fea4c4f16153..64d550ded049cdc00da89bc7928526bd85bce795 100644 (file)
@@ -37,9 +37,9 @@ ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", \
 # Create dm tables for partitions
 ENV{DM_ACTION}=="PATH_FAILED|PATH_REINSTATED", GOTO="kpartx_end"
 ENV{DM_NR_VALID_PATHS}=="0", GOTO="kpartx_end"
-ENV{ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1"
+ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1"
 ENV{DM_SUBSYSTEM_UDEV_FLAG1}=="1", GOTO="kpartx_end"
 ENV{DM_STATE}!="SUSPENDED", ENV{DM_UUID}=="mpath-*", \
-       RUN+="/sbin/kpartx -u -p -part /dev/$name"
+       RUN+="/sbin/kpartx -un -p -part /dev/$name"
 
 LABEL="kpartx_end"
index 2eb3f631c7eddf8379c0b083f29bfe4ec0d07ea2..02b29e8cf91d698f7a01fffb47df76aa49c0d5da 100644 (file)
 #include <fcntl.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <dirent.h>
-#include "sysmacros.h"
+#include <sys/sysmacros.h>
 #include <linux/loop.h>
+#include <limits.h>
 
 #include "lopart.h"
 #include "xstrncpy.h"
 #define LOOP_CTL_GET_FREE       0x4C82
 #endif
 
-#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
-       && !defined (__s390x__)
-#define int2ptr(x)     ((void *) ((int) x))
-#else
-#define int2ptr(x)     ((void *) ((long) x))
-#endif
-
 static char *
 xstrdup (const char *s)
 {
@@ -62,62 +57,52 @@ xstrdup (const char *s)
        return t;
 }
 
-int is_loop_device(const char *device)
-{
-       struct stat statbuf;
-       int loopmajor;
-#if 1
-       loopmajor = 7;
-#else
-       FILE *procdev;
-       char line[100], *cp;
-
-       loopmajor = 0;
-
-       if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
-
-               while (fgets (line, sizeof(line), procdev)) {
-
-                       if ((cp = strstr (line, " loop\n")) != NULL) {
-                               *cp='\0';
-                               loopmajor=atoi(line);
-                               break;
-                       }
-               }
-
-               fclose(procdev);
-       }
-#endif
-       return (loopmajor && stat(device, &statbuf) == 0 &&
-               S_ISBLK(statbuf.st_mode) &&
-               major(statbuf.st_rdev) == loopmajor);
-}
-
 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
 
 char *find_loop_by_file(const char *filename)
 {
        DIR *dir;
        struct dirent *dent;
-       char dev[64], *found = NULL;
+       char dev[64], *found = NULL, *p;
        int fd;
        struct stat statbuf;
        struct loop_info loopinfo;
+       const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
+       char path[PATH_MAX];
 
-       dir = opendir("/dev");
+       dir = opendir(VIRT_BLOCK);
        if (!dir)
                return NULL;
 
        while ((dent = readdir(dir)) != NULL) {
                if (strncmp(dent->d_name,"loop",4))
                        continue;
-               if (!strcmp(dent->d_name, "loop-control"))
+
+               if (snprintf(path, PATH_MAX, "%s/%s/dev", VIRT_BLOCK,
+                            dent->d_name) >= PATH_MAX)
                        continue;
-               sprintf(dev, "/dev/%s", dent->d_name);
 
-               fd = open (dev, O_RDONLY);
+               fd = open(path, O_RDONLY);
                if (fd < 0)
-                       break;
+                       continue;
+
+               if (read(fd, dev, sizeof(dev)) <= 0) {
+                       close(fd);
+                       continue;
+               }
+
+               close(fd);
+
+               dev[sizeof(dev)-1] = '\0';
+               p = strchr(dev, '\n');
+               if (p != NULL)
+                       *p = '\0';
+               if (snprintf(path, PATH_MAX, "/dev/block/%s", dev) >= PATH_MAX)
+                       continue;
+
+               fd = open (path, O_RDONLY);
+               if (fd < 0)
+                       continue;
 
                if (fstat (fd, &statbuf) != 0 ||
                    !S_ISBLK(statbuf.st_mode)) {
@@ -130,13 +115,12 @@ char *find_loop_by_file(const char *filename)
                        continue;
                }
 
+               close (fd);
+
                if (0 == strcmp(filename, loopinfo.lo_name)) {
-                       close (fd);
-                       found = xstrdup(dev);
+                       found = realpath(path, NULL);
                        break;
                }
-
-               close (fd);
        }
        closedir(dir);
        return found;
@@ -260,7 +244,7 @@ int set_loop(const char *device, const char *file, int offset, int *loopro)
        loopinfo.lo_encrypt_type = LO_CRYPT_NONE;
        loopinfo.lo_encrypt_key_size = 0;
 
-       if (ioctl (fd, LOOP_SET_FD, int2ptr(ffd)) < 0) {
+       if (ioctl(fd, LOOP_SET_FD, (void*)(uintptr_t)(ffd)) < 0) {
                perror ("ioctl: LOOP_SET_FD");
                close (fd);
                close (ffd);
index a512353bc58fabc07180aa9e75963b653d278593..d3bad10adf52f7a0dfbd015bb4225ffc51c799e5 100644 (file)
@@ -1,6 +1,5 @@
 extern int verbose;
 extern int set_loop (const char *, const char *, int, int *);
 extern int del_loop (const char *);
-extern int is_loop_device (const char *);
 extern char * find_unused_loop_device (void);
 extern char * find_loop_by_file (const char *);
diff --git a/kpartx/sysmacros.h b/kpartx/sysmacros.h
deleted file mode 100644 (file)
index 171b33d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* versions to be used with > 16-bit dev_t - leave unused for now */
-
-#ifndef major
-#define major(dev)     ((dev) >> 8)
-#endif
-
-#ifndef minor
-#define minor(dev)     ((dev) & 0xff)
-#endif
diff --git a/kpartx/test-kpartx b/kpartx/test-kpartx
new file mode 100755 (executable)
index 0000000..7c45cd1
--- /dev/null
@@ -0,0 +1,254 @@
+#! /bin/bash
+
+# This is a unit test program for kpartx, in particular for deleting partitions.
+#
+# The rationale is the following:
+#
+#  1) kpartx should delete all mappings it created beforehand.
+#  2) kpartx should handle partitions on dm devices and other devices
+#     (e.g. loop devices) equally well.
+#  3) kpartx should only delete "partitions", which are single-target
+#     linear mappings into a block device. Other maps should not be touched.
+#  4) kpartx should only delete mappings it created itself beforehand.
+#     In particular, it shouldn't delete LVM LVs, even if they are fully
+#     contained in the block device at hand and thus look like partitions
+#     in the first place. (For historical compatibility reasons, we allow
+#     such mappings to be deleted with the -f/--force flag).
+#  5) DM map names may be changed, thus kpartx shouldn't rely on them to
+#     check whether a mapping is a partition of a particular device. It is
+#     legal for a partition of /dev/loop0 to be named "loop0".
+
+# Note: This program tries hard to clean up, but if tests fail,
+# stale DM or loop devices may keep lurking around.
+
+# Set WORKDIR in environment to existing dir to for persistence
+# WARNING:  exisiting files will be truncated.
+# If empty, test will be done in temporary dir
+: ${WORKDIR:=}
+# Set this environment variable to test an alternative kpartx executable
+: ${KPARTX:=}
+# Options to pass to kpartx always
+: ${KPARTX_OPTS:=-s}
+# Time to wait for device nodes to appear (microseconds)
+# Waiting is only needed if "s" is not in $KPARTX_OPTS
+: ${WAIT_US:=0}
+
+# IMPORTANT: The ERR trap is essential for this program to work correctly!
+trap 'LINE=$LINENO; trap - ERR; echo "== error in $BASH_COMMAND on line $LINE ==" >&2; exit 1' ERR
+trap 'cleanup' 0
+
+CLEANUP=:
+cleanup() {
+    trap - ERR
+    trap - 0
+    if [[ $OK ]]; then
+       echo == all tests completed successfully == >&2
+    else
+       echo == step $STEP failed == >&2
+    fi
+    eval "$CLEANUP" &>/dev/null
+}
+
+push_cleanup() {
+    CLEANUP="$@;$CLEANUP"
+}
+
+pop_cleanup() {
+    # CAUTION: simplistic
+    CLEANUP=${CLEANUP#*;}
+}
+
+step() {
+    STEP="$@"
+    echo == Test step: $STEP == >&2
+}
+
+mk_partitions() {
+    parted -s $1 mklabel msdos
+    parted -s -- $1 mkpart prim ext2 1MiB -1s
+}
+
+step preparation
+
+[[ $UID -eq 0 ]]
+[[ $KPARTX ]] || {
+    if [[ -x $PWD/kpartx/kpartx ]]; then
+       KPARTX=$PWD/kpartx/kpartx
+    else
+       KPARTX=$(which kpartx)
+    fi
+}
+[[ $KPARTX ]]
+
+FILE1=kpartx1
+FILE2=kpartx2
+FILE3=kpartx3
+SIZE=$((1024*1024*1024))  # use bytes as units here
+SECTSIZ=512
+OFFS=32                # offset of linear mapping into dev, sectors
+VG=kpvg  # volume group name
+LV=kplv  # logical vol name
+LVMCONF='devices { filter = [ "a|/dev/loop.*|", r".*" ] }'
+
+OK=
+
+[[ $WORKDIR ]] || {
+    WORKDIR=$(mktemp -d /tmp/kpartx-XXXXXX)
+    push_cleanup 'rm -rf $WORKDIR'
+}
+
+push_cleanup "cd $PWD"
+cd "$WORKDIR"
+
+step "create loop devices"
+truncate -s $SIZE $FILE1
+truncate -s $SIZE $FILE2
+truncate -s $SIZE $FILE3
+
+LO1=$(losetup -f $FILE1 --show)
+push_cleanup 'losetup -d $LO1'
+LO2=$(losetup -f $FILE2 --show)
+push_cleanup 'losetup -d $LO2'
+LO3=$(losetup -f $FILE3 --show)
+push_cleanup 'losetup -d $LO3'
+
+[[ $LO1 && $LO2 && $LO3 && -b $LO1 && -b $LO2 && -b $LO3 ]]
+DEV1=$(stat -c "%t:%T" $LO1)
+DEV2=$(stat -c "%t:%T" $LO2)
+DEV3=$(stat -c "%t:%T" $LO3)
+
+usleep $WAIT_US
+
+step "create DM devices (spans)"
+# Create two linear mappings spanning two loopdevs.
+# One of them gets a pathological name colliding with
+# the loop device name.
+# These mappings must not be removed by kpartx.
+# They also serve as DM devices to test partition removal on those.
+
+TABLE="\
+0 $((SIZE/SECTSIZ-OFFS)) linear $DEV1 $OFFS
+$((SIZE/SECTSIZ-OFFS)) $((SIZE/SECTSIZ-OFFS)) linear $DEV2 $OFFS"
+
+SPAN1=kpt
+SPAN2=$(basename $LO2)
+dmsetup create $SPAN1 <<<"$TABLE"
+push_cleanup 'dmsetup remove -f $SPAN1'
+
+dmsetup create $SPAN2 <<<"$TABLE"
+push_cleanup 'dmsetup remove -f $SPAN2'
+
+usleep $WAIT_US
+[[ -b /dev/mapper/$SPAN1 ]]
+[[ -b /dev/mapper/$SPAN2 ]]
+
+step "create vg on $LO3"
+# On the 3rd loop device, we create a VG and an LV
+# The LV should not be removed by kpartx.
+pvcreate --config "$LVMCONF" -f $LO3
+vgcreate --config "$LVMCONF" $VG $LO3
+push_cleanup 'vgremove --config "$LVMCONF" -f $VG'
+lvcreate --config "$LVMCONF" -L $((SIZE/2))B -n $LV $VG
+push_cleanup 'lvremove --config "$LVMCONF" -f $VG/$LV'
+usleep $WAIT_US
+
+[[ -b /dev/mapper/$VG-$LV ]]
+
+# dmsetup table /dev/mapper/$VG-$LV
+# dmsetup info /dev/mapper/$VG-$LV
+
+step "create partitions on loop devices"
+
+mk_partitions $LO1
+mk_partitions $LO2
+
+# Test invocation of kpartx with regular file here
+LO2P1=/dev/mapper/$(basename $LO2)-foo1
+$KPARTX $KPARTX_OPTS -a -p -foo $FILE2
+push_cleanup 'dmsetup remove -f $(basename $LO2P1)'
+
+LO1P1=/dev/mapper/$(basename $LO1)-eggs1
+$KPARTX $KPARTX_OPTS -a -p -eggs $LO1
+push_cleanup 'dmsetup remove -f $(basename $LO1P1)'
+
+usleep $WAIT_US
+[[ -b $LO1P1 ]]
+[[ -b $LO2P1 ]]
+
+# dmsetup info $LO2P1
+
+# Set pathological name for partition on $LO1 (same as loop device itself)
+dmsetup rename $(basename $LO1P1) $(basename $LO1)
+LO1P1=/dev/mapper/$(basename $LO1)
+pop_cleanup
+push_cleanup 'dmsetup remove -f $(basename $LO1P1)'
+
+# dmsetup info $LO1P1
+
+step "create partitions on DM devices"
+mk_partitions /dev/mapper/$SPAN2
+
+$KPARTX $KPARTX_OPTS -a -p -bar /dev/mapper/$SPAN2
+SPAN2P1=/dev/mapper/${SPAN2}-bar1
+
+# udev rules may have created partition mappings without UUIDs
+# which aren't removed by default (if system standard kpartx doesn't
+# set the UUID). Remove them using -f
+push_cleanup '$KPARTX $KPARTX_OPTS -f -d /dev/mapper/$SPAN2'
+push_cleanup 'dmsetup remove -f $(basename $SPAN2P1)'
+
+$KPARTX $KPARTX_OPTS -a -p -spam /dev/mapper/$SPAN1
+SPAN1P1=/dev/mapper/${SPAN1}-spam1
+# see above
+push_cleanup '$KPARTX $KPARTX_OPTS -f -d /dev/mapper/$SPAN1'
+push_cleanup 'dmsetup remove -f $(basename $SPAN1P1)'
+
+usleep $WAIT_US
+[[ -b $SPAN2P1 ]]
+[[ -b $SPAN1P1 ]]
+
+step "delete partitions on DM devices"
+$KPARTX $KPARTX_OPTS -d /dev/mapper/$SPAN1 >&2
+usleep $WAIT_US
+
+[[ -b $SPAN2P1 ]]
+[[ -b $LO1P1 ]]
+[[ -b $LO2P1 ]]
+[[ ! -b $SPAN1P1 ]]
+
+$KPARTX $KPARTX_OPTS -d /dev/mapper/$SPAN2
+usleep $WAIT_US
+
+[[ -b $LO1P1 ]]
+[[ -b $LO2P1 ]]
+[[ ! -b $SPAN2P1 ]]
+
+step "delete partitions on loop devices"
+
+$KPARTX $KPARTX_OPTS -d $LO3
+
+# This will also delete the loop device
+$KPARTX $KPARTX_OPTS -d $FILE2
+$KPARTX $KPARTX_OPTS -d $LO1
+usleep $WAIT_US
+
+# ls -l /dev/mapper
+[[ ! -b $LO1P1 ]]
+pop_cleanup
+[[ ! -b $LO2P1 ]]
+pop_cleanup
+# spans should not have been removed
+[[ -b /dev/mapper/$SPAN1 ]]
+[[ -b /dev/mapper/$SPAN2 ]]
+# LVs neither
+[[ -b /dev/mapper/$VG-$LV ]]
+
+step "delete partitions on $LO3 with -f"
+
+$KPARTX $KPARTX_OPTS -f -d $LO3
+# -d -f should delete the LV, too
+[[ ! -b /dev/mapper/$VG-$LV ]]
+[[ -b /dev/mapper/$SPAN1 ]]
+[[ -b /dev/mapper/$SPAN2 ]]
+
+OK=yes
index 1c5329aae52a026ed37e7f1c9c3400c5efdc5b67..cdd26ed753fa4c6f666eee9d7d8e7a1d2ef8061c 100644 (file)
@@ -15,7 +15,7 @@ HEADERS = libdmmp/libdmmp.h
 
 OBJS = libdmmp.o libdmmp_mp.o libdmmp_pg.o libdmmp_path.o libdmmp_misc.o
 
-CFLAGS += -fvisibility=hidden -I$(libdmmpdir) -I$(mpathcmddir) \
+CFLAGS += $(LIB_CFLAGS) -fvisibility=hidden -I$(libdmmpdir) -I$(mpathcmddir) \
          $(shell pkg-config --cflags json-c)
 
 LIBDEPS += $(shell pkg-config --libs json-c) -L$(mpathcmddir) -lmpathcmd -lpthread
@@ -27,15 +27,16 @@ $(LIBS): $(OBJS)
        $(LN) $@ $(DEVLIB)
 
 install:
-       $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
+       mkdir -p $(DESTDIR)$(usrlibdir)
+       $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(usrlibdir)/$(LIBS)
        $(INSTALL_PROGRAM) -m 644 -D \
                $(HEADERS) $(DESTDIR)$(includedir)/$(HEADERS)
-       $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+       $(LN) $(LIBS) $(DESTDIR)$(usrlibdir)/$(DEVLIB)
        $(INSTALL_PROGRAM) -m 644 -D \
                $(PKGFILE).in $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
        perl -i -pe 's|__VERSION__|$(LIBDMMP_VERSION)|g' \
                $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
-       perl -i -pe 's|__LIBDIR__|$(syslibdir)|g' \
+       perl -i -pe 's|__LIBDIR__|$(usrlibdir)|g' \
                $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
        perl -i -pe 's|__INCLUDEDIR__|$(includedir)|g' \
                $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
@@ -46,9 +47,9 @@ install:
        done
 
 uninstall:
-       $(RM) $(DESTDIR)$(syslibdir)/$(LIBS)
+       $(RM) $(DESTDIR)$(usrlibdir)/$(LIBS)
        $(RM) $(DESTDIR)$(includedir)/$(HEADERS)
-       $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+       $(RM) $(DESTDIR)$(usrlibdir)/$(DEVLIB)
        @for file in $(DESTDIR)$(man3dir)/dmmp_*; do \
                $(RM) $$file; \
        done
@@ -56,7 +57,7 @@ uninstall:
 
 clean:
        $(RM) core *.a *.o *.gz *.so *.so.*
-       $(RM) docs/man/*.3.gz
+       $(RM) -r docs/man
        $(MAKE) -C test clean
 
 check: all
index 9cda94c444b0e0bb9f70d1dfdaf2a9deef6361c2..4f321017361de282536f8319e42b8f266bd1667c 100644 (file)
@@ -4,6 +4,8 @@ SONAME = 0
 DEVLIB = libmpathcmd.so
 LIBS = $(DEVLIB).$(SONAME)
 
+CFLAGS += $(LIB_CFLAGS)
+
 OBJS = mpath_cmd.o
 
 all: $(LIBS)
index 857c8d84528e0e87311518e268b37f3ed96f487c..1b4ec16a18f744a82b1386fc7e912d0d3b424a41 100644 (file)
@@ -4,7 +4,7 @@ SONAME = 0
 DEVLIB = libmpathpersist.so
 LIBS = $(DEVLIB).$(SONAME)
 
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
+CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
 
 LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \
           -L$(mpathcmddir) -lmpathcmd
index 982c79541827efef163a32cc0fb174bc37a492a7..aab6d958dc2ae824c4bc1006adef1fe60b52c0a6 100644 (file)
 
 #define __STDC_FORMAT_MACROS 1
 
-struct udev *udev;
+extern struct udev *udev;
 
 struct config *
-mpath_lib_init (struct udev *udev)
+mpath_lib_init (void)
 {
        struct config *conf;
 
@@ -481,7 +481,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
                thread[i].param.rq_type = rq_type;
                thread[i].param.paramp = paramp;
                thread[i].param.noisy = noisy;
-               thread[i].param.status = -1;
+               thread[i].param.status = MPATH_PR_SKIP;
 
                condlog (3, "THRED ID [%d] INFO]", i);
                condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
@@ -519,14 +519,17 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
                        rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param));
                        if (rc){
                                condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
+                               thread[count].param.status = MPATH_PR_THREAD_ERROR;
                        }
                        count = count + 1;
                }
        }
        for( i=0; i < active_pathcount ; i++){
-               rc = pthread_join(thread[i].id, NULL);
-               if (rc){
-                       condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
+               if (thread[i].param.status != MPATH_PR_THREAD_ERROR) {
+                       rc = pthread_join(thread[i].id, NULL);
+                       if (rc){
+                               condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
+                       }
                }
                if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
                        rollback = 1;
@@ -545,8 +548,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
        if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
                condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
                for( i=0 ; i < active_pathcount ; i++){
-                       if((thread[i].param.status == MPATH_PR_SUCCESS) &&
-                                       ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+                       if(thread[i].param.status == MPATH_PR_SUCCESS) {
                                memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8);
                                memset(&thread[i].param.paramp->sa_key, 0, 8);
                                thread[i].param.status = MPATH_PR_SUCCESS;
@@ -554,14 +556,19 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
                                                (void *)(&thread[i].param));
                                if (rc){
                                        condlog (0, "%s: failed to create thread for rollback. %d",  mpp->wwid, rc);
+                                       thread[i].param.status = MPATH_PR_THREAD_ERROR;
                                }
-                       }
+                       } else
+                               thread[i].param.status = MPATH_PR_SKIP;
                }
                for(i=0; i < active_pathcount ; i++){
-                       rc = pthread_join(thread[i].id, NULL);
-                       if (rc){
-                               condlog (3, "%s: failed to join thread while rolling back %d",
-                                               mpp->wwid, i);
+                       if (thread[i].param.status != MPATH_PR_SKIP &&
+                           thread[i].param.status != MPATH_PR_THREAD_ERROR) {
+                               rc = pthread_join(thread[i].id, NULL);
+                               if (rc){
+                                       condlog (3, "%s: failed to join thread while rolling back %d",
+                                                mpp->wwid, i);
+                               }
                        }
                }
        }
@@ -630,7 +637,7 @@ int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
        rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
        if (rc){
                condlog (3, "%s: failed to create thread %d", dev, rc);
-               return MPATH_PR_OTHER;
+               return MPATH_PR_THREAD_ERROR;
        }
        /* Free attribute and wait for the other threads */
        pthread_attr_destroy(&attr);
@@ -670,7 +677,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
                thread[i].param.rq_type = rq_type;
                thread[i].param.paramp = paramp;
                thread[i].param.noisy = noisy;
-               thread[i].param.status = -1;
+               thread[i].param.status = MPATH_PR_SKIP;
 
                condlog (3, " path count = %d", i);
                condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
@@ -695,16 +702,20 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
                        condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
                        rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
                                        (void *) (&thread[count].param));
-                       if (rc)
+                       if (rc) {
                                condlog (0, "%s: failed to create thread. %d",  mpp->wwid, rc);
+                               thread[count].param.status = MPATH_PR_THREAD_ERROR;
+                       }
                        count = count + 1;
                }
        }
        pthread_attr_destroy (&attr);
        for (i = 0; i < active_pathcount; i++){
-               rc = pthread_join (thread[i].id, NULL);
-               if (rc){
-                       condlog (1, "%s: failed to join thread.  %d",  mpp->wwid,  rc);
+               if (thread[i].param.status != MPATH_PR_THREAD_ERROR) {
+                       rc = pthread_join (thread[i].id, NULL);
+                       if (rc){
+                               condlog (1, "%s: failed to join thread.  %d",  mpp->wwid,  rc);
+                       }
                }
        }
 
index 79de5b5bcc940af0896f01e92853a030e55dadc6..9a84bc9c42f470feeb1d03411928a3bbfe0c1da6 100644 (file)
@@ -43,6 +43,7 @@ extern "C" {
 
 
 /* PR RETURN_STATUS */
+#define MPATH_PR_SKIP                  -1  /* skipping this path */
 #define MPATH_PR_SUCCESS               0
 #define MPATH_PR_SYNTAX_ERROR          1   /*  syntax error or invalid parameter */
                                            /* status for check condition */
@@ -59,7 +60,8 @@ extern "C" {
 #define MPATH_PR_RESERV_CONFLICT       11  /* Reservation conflict on the device */
 #define MPATH_PR_FILE_ERROR            12  /* file (device node) problems(e.g. not found)*/
 #define MPATH_PR_DMMP_ERROR            13  /* DMMP related error.(e.g Error in getting dm info */
-#define MPATH_PR_OTHER                 14  /*other error/warning has occurred(transport
+#define MPATH_PR_THREAD_ERROR          14  /* pthreads error (e.g. unable to create new thread) */
+#define MPATH_PR_OTHER                 15  /*other error/warning has occurred(transport
                                              or driver error) */
 
 /* PR MASK */
@@ -81,6 +83,9 @@ extern "C" {
 
 
 
+extern unsigned int mpath_mx_alloc_len;
+
+
 
 struct prin_readdescr
 {
@@ -174,7 +179,7 @@ struct prout_param_descriptor {             /* PROUT parameter descriptor */
  *
  * RETURNS: struct config ->Success, NULL->Failed.
  */
-extern struct config * mpath_lib_init (struct udev *udev);
+extern struct config * mpath_lib_init (void);
 
 
 /*
index 31b2fe6d37a14595349befb260f98585f6ba6442..29df8c6f2da1250f969fc6b63317701ab5b9eff3 100644 (file)
@@ -502,21 +502,6 @@ void mpath_reverse_uint32_byteorder(uint32_t *num)
        *num = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0));
 }
 
-void mpath_reverse_8bytes_order(char * var)
-{
-       char byte[8];
-
-       int i;
-       for(i=0 ; i < 8 ; i++ )
-       {
-               byte[i] = var[i];
-       }
-       for(i=0 ; i < 8 ; i++ )
-       {
-               var[7 - i] = byte[i];
-       }
-}
-
 void
 dumpHex(const char* str, int len, int log)
 {
index 5af2e03258e51a01da07103b93d9ba294d3d0a46..b3701b2808251c19f74204941299c09f8667bfe6 100644 (file)
@@ -15,6 +15,7 @@
 #include "mpath_cmd.h"
 #include "uxsock.h"
 #include "memory.h"
+#include "mpathpr.h"
 
 
 int update_prflag(char * arg1, char * arg2, int noisy)
index e6c2dedff52de3957cfe4244263bb2b21bc71864..99e641b7caaceb85853db8e189962eb76ed8aa86 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MPATHPR_H
 #define MPATHPR_H
 
+#include "structs.h" /* FILE_NAME_SIZE */
+
 struct prin_param {
        char dev[FILE_NAME_SIZE];
        int rq_servact;
index 1f5ec2598c3cbc42ebc0f272177b80bc288b1e0c..b3244fc738e5c670bb5396d4fab62e9d8133c147 100644 (file)
@@ -7,7 +7,7 @@ SONAME = 0
 DEVLIB = libmultipath.so
 LIBS = $(DEVLIB).$(SONAME)
 
-CFLAGS += -I$(mpathcmddir)
+CFLAGS += $(LIB_CFLAGS) -I$(mpathcmddir)
 
 LIBDEPS += -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd -lurcu
 
index 4970fc077f41f0be88a820b73e0ce26b65b93cf8..bce6b8b7be75c726db45e5df2ab754daca099953 100644 (file)
@@ -3,7 +3,7 @@
 #
 include ../../Makefile.inc
 
-CFLAGS += -I..
+CFLAGS += $(LIB_CFLAGS) -I..
 
 # If you add or remove a checker also update multipath/multipath.conf.5
 LIBS= \
@@ -14,7 +14,8 @@ LIBS= \
        libcheckemc_clariion.so \
        libcheckhp_sw.so \
        libcheckrdac.so
-ifneq ($(ENABLE_RADOS),0)
+
+ifneq ($(call check_file,/usr/include/rados/librados.h),0)
 LIBS += libcheckrbd.so
 endif
 
index bb6619b3cf9f829d44b0035fb94a45f35ab626a8..b21a3aa1597567a18cb2ae53567ecfdcfa510f16 100644 (file)
@@ -25,6 +25,7 @@
 #include "prio.h"
 #include "devmapper.h"
 #include "mpath_cmd.h"
+#include "propsel.h"
 
 static int
 hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
@@ -318,6 +319,7 @@ set_param_str(char * str)
 static int
 merge_hwe (struct hwentry * dst, struct hwentry * src)
 {
+       char id[SCSI_VENDOR_SIZE+SCSI_PRODUCT_SIZE];
        merge_str(vendor);
        merge_str(product);
        merge_str(revision);
@@ -353,15 +355,10 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
        merge_num(san_path_err_forget_rate);
        merge_num(san_path_err_recovery_time);
 
-       /*
-        * 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");
-
+       snprintf(id, sizeof(id), "%s/%s", dst->vendor, dst->product);
+       reconcile_features_with_options(id, &dst->features,
+                                       &dst->no_path_retry,
+                                       &dst->retain_hwhandler);
        return 0;
 }
 
@@ -451,6 +448,13 @@ restart:
                        break;
                j = n;
                vector_foreach_slot_after(hw, hwe2, j) {
+                       /* drop invalid device configs */
+                       if (!hwe2->vendor || !hwe2->product) {
+                               condlog(0, "device config missing vendor or product parameter");
+                               vector_del_slot(hw, j--);
+                               free_hwe(hwe2);
+                               continue;
+                       }
                        if (hwe_regmatch(hwe1, hwe2))
                                continue;
                        /* dup */
@@ -599,40 +603,24 @@ load_config (char * file)
        if (!conf->verbosity)
                conf->verbosity = DEFAULT_VERBOSITY;
 
-       conf->minio = DEFAULT_MINIO;
-       conf->minio_rq = DEFAULT_MINIO_RQ;
        get_sys_max_fds(&conf->max_fds);
        conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
        conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
        conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
-       conf->features = set_default(DEFAULT_FEATURES);
-       conf->flush_on_last_del = DEFAULT_FLUSH;
        conf->attribute_flags = 0;
        conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
        conf->checkint = DEFAULT_CHECKINT;
        conf->max_checkint = 0;
-       conf->pgfailback = DEFAULT_FAILBACK;
-       conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
-       conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
-       conf->detect_prio = DEFAULT_DETECT_PRIO;
-       conf->detect_checker = DEFAULT_DETECT_CHECKER;
        conf->force_sync = DEFAULT_FORCE_SYNC;
        conf->partition_delim = DEFAULT_PARTITION_DELIM;
        conf->processed_main_config = 0;
        conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
        conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
-       conf->uid_attribute = set_default(DEFAULT_UID_ATTRIBUTE);
        conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
        conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
        conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
-       conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
-       conf->skip_kpartx = DEFAULT_SKIP_KPARTX;
        conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS;
        conf->remove_retries = 0;
-       conf->max_sectors_kb = DEFAULT_MAX_SECTORS_KB;
-       conf->san_path_err_threshold = DEFAULT_ERR_CHECKS;
-       conf->san_path_err_forget_rate = DEFAULT_ERR_CHECKS;
-       conf->san_path_err_recovery_time = DEFAULT_ERR_CHECKS;
 
        /*
         * preload default hwtable
index b29a66002f576cf4f49a5cdda43d25dc8d520ad1..74b6f52ad6c1607aa61ce6cb49ac54022cd54f7e 100644 (file)
@@ -280,18 +280,18 @@ int setup_map(struct multipath *mpp, char *params, int params_size)
        select_pgfailback(conf, mpp);
        select_pgpolicy(conf, mpp);
        select_selector(conf, mpp);
-       select_features(conf, mpp);
        select_hwhandler(conf, mpp);
+       select_no_path_retry(conf, mpp);
+       select_retain_hwhandler(conf, mpp);
+       select_features(conf, mpp);
        select_rr_weight(conf, mpp);
        select_minio(conf, mpp);
-       select_no_path_retry(conf, mpp);
        select_mode(conf, mpp);
        select_uid(conf, mpp);
        select_gid(conf, mpp);
        select_fast_io_fail(conf, mpp);
        select_dev_loss(conf, mpp);
        select_reservation_key(conf, mpp);
-       select_retain_hwhandler(conf, mpp);
        select_deferred_remove(conf, mpp);
        select_delay_watch_checks(conf, mpp);
        select_delay_wait_checks(conf, mpp);
@@ -499,8 +499,10 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
                                cmpp->alias, mpp->alias);
                        strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE - 1);
                        mpp->action = ACT_RENAME;
-                       if (force_reload)
+                       if (force_reload) {
+                               mpp->force_udev_reload = 1;
                                mpp->action = ACT_FORCERENAME;
+                       }
                        return;
                }
                mpp->action = ACT_CREATE;
@@ -538,12 +540,14 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
                return;
        }
        if (force_reload) {
+               mpp->force_udev_reload = 1;
                mpp->action = ACT_RELOAD;
                condlog(3, "%s: set ACT_RELOAD (forced by user)",
                        mpp->alias);
                return;
        }
        if (cmpp->size != mpp->size) {
+               mpp->force_udev_reload = 1;
                mpp->action = ACT_RESIZE;
                condlog(3, "%s: set ACT_RESIZE (size change)",
                        mpp->alias);
@@ -568,7 +572,8 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
        }
 
        if (mpp->retain_hwhandler != RETAIN_HWHANDLER_UNDEF &&
-           mpp->retain_hwhandler != cmpp->retain_hwhandler) {
+           mpp->retain_hwhandler != cmpp->retain_hwhandler &&
+           get_linux_version_code() < KERNEL_VERSION(4, 3, 0)) {
                mpp->action = ACT_RELOAD;
                condlog(3, "%s: set ACT_RELOAD (retain_hwhandler change)",
                        mpp->alias);
@@ -797,6 +802,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
                 * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
                 * succeeded
                 */
+               mpp->force_udev_reload = 0;
                if (mpp->action == ACT_CREATE)
                        remember_wwid(mpp->wwid);
                if (!is_daemon) {
index fb078a614709f0456b0e996346c91b627a25f71f..fd7f581ddd0cd0b5f6d8bf178b885aa52a6018f1 100644 (file)
@@ -26,6 +26,8 @@ enum actions {
 #define FLUSH_ONE 1
 #define FLUSH_ALL 2
 
+struct vectors;
+
 int setup_map (struct multipath * mpp, char * params, int params_size );
 int domap (struct multipath * mpp, char * params, int is_daemon);
 int reinstate_paths (struct multipath *mpp);
index fbe171a91978a44b6ff5f43916de5639d1faa895..f89b26443ea516eccd62f87e5f5f152496aaff20 100644 (file)
@@ -11,6 +11,7 @@
 #include "../third-party/valgrind/drd.h"
 #include "vector.h"
 #include "config.h"
+#include "defaults.h"
 
 void dlog (int sink, int prio, const char * fmt, ...)
 {
@@ -21,7 +22,7 @@ void dlog (int sink, int prio, const char * fmt, ...)
        va_start(ap, fmt);
        conf = get_multipath_config();
        ANNOTATE_IGNORE_READS_BEGIN();
-       thres = (conf) ? conf->verbosity : 0;
+       thres = (conf) ? conf->verbosity : DEFAULT_VERBOSITY;
        ANNOTATE_IGNORE_READS_END();
        put_multipath_config(conf);
 
index 5fb9d9ace599e411d4ff748762f57621bfaf86bf..3b41a483422b0b868f1d9cac6c5aa57f8d989918 100644 (file)
@@ -21,6 +21,7 @@
 #include "memory.h"
 #include "devmapper.h"
 #include "sysfs.h"
+#include "config.h"
 
 #include "log_pthread.h"
 #include <sys/types.h>
@@ -178,7 +179,7 @@ out:
 }
 
 static int
-dm_drv_prereq (void)
+dm_drv_prereq (unsigned int *ver)
 {
        unsigned int minv[3] = {1, 0, 3};
        unsigned int version[3] = {0, 0, 0};
@@ -193,19 +194,51 @@ dm_drv_prereq (void)
        condlog(3, "DM multipath kernel driver v%u.%u.%u",
                v[0], v[1], v[2]);
 
-       if VERSION_GE(v, minv)
+       if (VERSION_GE(v, minv)) {
+               ver[0] = v[0];
+               ver[1] = v[1];
+               ver[2] = v[2];
                return 0;
+       }
 
        condlog(0, "DM multipath kernel driver must be >= v%u.%u.%u",
                minv[0], minv[1], minv[2]);
        return 1;
 }
 
-int dm_prereq(void)
+static int dm_prereq(unsigned int *v)
 {
        if (dm_lib_prereq())
                return 1;
-       return dm_drv_prereq();
+       return dm_drv_prereq(v);
+}
+
+static int libmp_dm_udev_sync = 0;
+
+void libmp_udev_set_sync_support(int on)
+{
+       libmp_dm_udev_sync = !!on;
+}
+
+void libmp_dm_init(void)
+{
+       struct config *conf;
+
+       conf = get_multipath_config();
+       dm_init(conf->verbosity);
+       if (dm_prereq(conf->version))
+               exit(1);
+       put_multipath_config(conf);
+       dm_udev_set_sync_support(libmp_dm_udev_sync);
+}
+
+struct dm_task*
+libmp_dm_task_create(int task)
+{
+       static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT;
+
+       pthread_once(&dm_initialized, libmp_dm_init);
+       return dm_task_create(task);
 }
 
 #define do_deferred(x) ((x) == DEFERRED_REMOVE_ON || (x) == DEFERRED_REMOVE_IN_PROGRESS)
@@ -219,7 +252,7 @@ dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t
        uint32_t cookie = 0;
        struct dm_task *dmt;
 
-       if (!(dmt = dm_task_create (task)))
+       if (!(dmt = libmp_dm_task_create (task)))
                return 0;
 
        if (!dm_task_set_name (dmt, name))
@@ -274,7 +307,7 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
        uint32_t cookie = 0;
        uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
 
-       if (!(dmt = dm_task_create (task)))
+       if (!(dmt = libmp_dm_task_create (task)))
                return 0;
 
        if (!dm_task_set_name (dmt, mpp->alias))
@@ -372,7 +405,8 @@ int dm_addmap_create (struct multipath *mpp, char * params)
 int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
 {
        int r = 0;
-       uint16_t udev_flags = (flush ? 0 : MPATH_UDEV_RELOAD_FLAG) |
+       uint16_t udev_flags = ((mpp->force_udev_reload)?
+                              0 : MPATH_UDEV_RELOAD_FLAG) |
                              ((mpp->skip_kpartx == SKIP_KPARTX_ON)?
                               MPATH_UDEV_NO_KPARTX_FLAG : 0) |
                              ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG);
@@ -395,19 +429,28 @@ int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
        if (r)
                r = dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush,
                                 1, udev_flags, 0);
-       return r;
+       if (r)
+               return r;
+
+       /* If the resume failed, dm will leave the device suspended, and
+        * drop the new table, so doing a second resume will try using
+        * the original table */
+       if (dm_is_suspended(mpp->alias))
+               dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush, 1,
+                            udev_flags, 0);
+       return 0;
 }
 
-int dm_map_present(const char * str)
+static int
+do_get_info(const char *name, struct dm_info *info)
 {
-       int r = 0;
+       int r = -1;
        struct dm_task *dmt;
-       struct dm_info info;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
-               return 0;
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
+               return r;
 
-       if (!dm_task_set_name(dmt, str))
+       if (!dm_task_set_name(dmt, name))
                goto out;
 
        dm_task_no_open_count(dmt);
@@ -415,16 +458,25 @@ int dm_map_present(const char * str)
        if (!dm_task_run(dmt))
                goto out;
 
-       if (!dm_task_get_info(dmt, &info))
+       if (!dm_task_get_info(dmt, info))
                goto out;
 
-       if (info.exists)
-               r = 1;
+       if (!info->exists)
+               goto out;
+
+       r = 0;
 out:
        dm_task_destroy(dmt);
        return r;
 }
 
+int dm_map_present(const char * str)
+{
+       struct dm_info info;
+
+       return (do_get_info(str, &info) == 0);
+}
+
 int dm_get_map(const char *name, unsigned long long *size, char *outparams)
 {
        int r = 1;
@@ -433,7 +485,7 @@ int dm_get_map(const char *name, unsigned long long *size, char *outparams)
        char *target_type = NULL;
        char *params = NULL;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
                return 1;
 
        if (!dm_task_set_name(dmt, name))
@@ -469,7 +521,7 @@ dm_get_prefixed_uuid(const char *name, char *uuid)
        const char *uuidtmp;
        int r = 1;
 
-       dmt = dm_task_create(DM_DEVICE_INFO);
+       dmt = libmp_dm_task_create(DM_DEVICE_INFO);
        if (!dmt)
                return 1;
 
@@ -493,42 +545,35 @@ uuidout:
 
 int dm_get_uuid(char *name, char *uuid)
 {
-       char uuidtmp[WWID_SIZE];
-
-       if (dm_get_prefixed_uuid(name, uuidtmp))
+       if (dm_get_prefixed_uuid(name, uuid))
                return 1;
 
-       if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN))
-               strcpy(uuid, uuidtmp + UUID_PREFIX_LEN);
-       else
-               strcpy(uuid, uuidtmp);
-
+       if (!strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+               memmove(uuid, uuid + UUID_PREFIX_LEN,
+                       strlen(uuid + UUID_PREFIX_LEN) + 1);
        return 0;
 }
 
-/*
- * returns:
- *    0 : if both uuids end with same suffix which starts with UUID_PREFIX
- *    1 : otherwise
- */
-int
-dm_compare_uuid(const char* mapname1, const char* mapname2)
+static int
+is_mpath_part(const char *part_name, const char *map_name)
 {
-       char *p1, *p2;
-       char uuid1[WWID_SIZE], uuid2[WWID_SIZE];
+       char *p;
+       char part_uuid[WWID_SIZE], map_uuid[WWID_SIZE];
 
-       if (dm_get_prefixed_uuid(mapname1, uuid1))
-               return 1;
+       if (dm_get_prefixed_uuid(part_name, part_uuid))
+               return 0;
 
-       if (dm_get_prefixed_uuid(mapname2, uuid2))
-               return 1;
+       if (dm_get_prefixed_uuid(map_name, map_uuid))
+               return 0;
 
-       p1 = strstr(uuid1, UUID_PREFIX);
-       p2 = strstr(uuid2, UUID_PREFIX);
-       if (p1 && p2 && !strcmp(p1, p2))
+       if (strncmp(part_uuid, "part", 4) != 0)
                return 0;
 
-       return 1;
+       p = strstr(part_uuid, UUID_PREFIX);
+       if (p && !strcmp(p, map_uuid))
+               return 1;
+
+       return 0;
 }
 
 int dm_get_status(char *name, char *outstatus)
@@ -539,7 +584,7 @@ int dm_get_status(char *name, char *outstatus)
        char *target_type = NULL;
        char *status = NULL;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
                return 1;
 
        if (!dm_task_set_name(dmt, name))
@@ -572,7 +617,7 @@ out:
  * returns:
  *    1 : match
  *    0 : no match
- *   -1 : empty map
+ *   -1 : empty map, or more than 1 target
  */
 int dm_type(const char *name, char *type)
 {
@@ -582,7 +627,7 @@ int dm_type(const char *name, char *type)
        char *target_type = NULL;
        char *params;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
                return 0;
 
        if (!dm_task_set_name(dmt, name))
@@ -594,10 +639,11 @@ int dm_type(const char *name, char *type)
                goto out;
 
        /* Fetch 1st target */
-       dm_get_next_target(dmt, NULL, &start, &length,
-                          &target_type, &params);
-
-       if (!target_type)
+       if (dm_get_next_target(dmt, NULL, &start, &length,
+                              &target_type, &params) != NULL)
+               /* multiple targets */
+               r = -1;
+       else if (!target_type)
                r = -1;
        else if (!strcmp(target_type, type))
                r = 1;
@@ -617,7 +663,7 @@ int dm_is_mpath(const char *name)
        char *params;
        const char *uuid;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
                return 0;
 
        if (!dm_task_set_name(dmt, name))
@@ -651,29 +697,15 @@ out:
 static int
 dm_dev_t (const char * mapname, char * dev_t, int len)
 {
-       int r = 1;
-       struct dm_task *dmt;
        struct dm_info info;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
-               return 0;
-
-       if (!dm_task_set_name(dmt, mapname))
-               goto out;
-
-       if (!dm_task_run(dmt))
-               goto out;
-
-       if (!dm_task_get_info(dmt, &info) || !info.exists)
-               goto out;
+       if (do_get_info(mapname, &info) != 0)
+               return 1;
 
        if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
-               goto out;
+               return 1;
 
-       r = 0;
-out:
-       dm_task_destroy(dmt);
-       return r;
+       return 0;
 }
 
 int
@@ -683,7 +715,7 @@ dm_get_opencount (const char * mapname)
        struct dm_task *dmt;
        struct dm_info info;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
                return 0;
 
        if (!dm_task_set_name(dmt, mapname))
@@ -705,59 +737,16 @@ out:
 }
 
 int
-dm_get_major (char * mapname)
-{
-       int r = -1;
-       struct dm_task *dmt;
-       struct dm_info info;
-
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
-               return 0;
-
-       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;
-
-       if (!info.exists)
-               goto out;
-
-       r = info.major;
-out:
-       dm_task_destroy(dmt);
-       return r;
-}
-
-int
-dm_get_minor (char * mapname)
+dm_get_major_minor(const char *name, int *major, int *minor)
 {
-       int r = -1;
-       struct dm_task *dmt;
        struct dm_info info;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
-               return 0;
-
-       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;
-
-       if (!info.exists)
-               goto out;
+       if (do_get_info(name, &info) != 0)
+               return -1;
 
-       r = info.minor;
-out:
-       dm_task_destroy(dmt);
-       return r;
+       *major = info.major;
+       *minor = info.minor;
+       return 0;
 }
 
 static int
@@ -884,7 +873,7 @@ int dm_flush_maps (int retries)
        struct dm_names *names;
        unsigned next = 0;
 
-       if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
+       if (!(dmt = libmp_dm_task_create (DM_DEVICE_LIST)))
                return 0;
 
        dm_task_no_open_count(dmt);
@@ -915,7 +904,7 @@ dm_message(const char * mapname, char * message)
        int r = 1;
        struct dm_task *dmt;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_TARGET_MSG)))
                return 1;
 
        if (!dm_task_set_name(dmt, mapname))
@@ -1017,7 +1006,7 @@ dm_get_maps (vector mp)
        if (!mp)
                return 1;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
                return 1;
 
        dm_task_no_open_count(dmt);
@@ -1075,31 +1064,23 @@ out:
 int
 dm_geteventnr (char *name)
 {
-       struct dm_task *dmt;
        struct dm_info info;
-       int event = -1;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+       if (do_get_info(name, &info) != 0)
                return -1;
 
-       if (!dm_task_set_name(dmt, name))
-               goto out;
-
-       dm_task_no_open_count(dmt);
-
-       if (!dm_task_run(dmt))
-               goto out;
-
-       if (!dm_task_get_info(dmt, &info))
-               goto out;
+       return info.event_nr;
+}
 
-       if (info.exists)
-               event = info.event_nr;
+int
+dm_is_suspended(const char *name)
+{
+       struct dm_info info;
 
-out:
-       dm_task_destroy(dmt);
+       if (do_get_info(name, &info) != 0)
+               return -1;
 
-       return event;
+       return info.suspended;
 }
 
 char *
@@ -1111,7 +1092,7 @@ dm_mapname(int major, int minor)
        int r;
        int loop = MAX_WAIT * LOOPS_PER_SEC;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
                return NULL;
 
        if (!dm_task_set_major(dmt, major) ||
@@ -1162,8 +1143,9 @@ do_foreach_partmaps (const char * mapname,
        unsigned long long size;
        char dev_t[32];
        int r = 1;
+       char *p;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
                return 1;
 
        dm_task_no_open_count(dmt);
@@ -1185,15 +1167,15 @@ do_foreach_partmaps (const char * mapname,
        do {
                if (
                    /*
-                    * if devmap target is "linear"
+                    * if there is only a single "linear" target
                     */
-                   (dm_type(names->name, TGT_PART) > 0) &&
+                   (dm_type(names->name, TGT_PART) == 1) &&
 
                    /*
-                    * and both uuid end with same suffix starting
-                    * at UUID_PREFIX
+                    * and the uuid of the target is a partition of the
+                    * uuid of the multipath device
                     */
-                   (!dm_compare_uuid(names->name, mapname)) &&
+                   is_mpath_part(names->name, mapname) &&
 
                    /*
                     * and we can fetch the map table from the kernel
@@ -1203,7 +1185,8 @@ do_foreach_partmaps (const char * mapname,
                    /*
                     * and the table maps over the multipath map
                     */
-                   strstr(params, dev_t)
+                   (p = strstr(params, dev_t)) &&
+                   !isdigit(*(p + strlen(dev_t)))
                   ) {
                        if (partmap_func(names->name, data) != 0)
                                goto out;
@@ -1265,26 +1248,12 @@ cancel_remove_partmap (const char *name, void *unused)
 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)))
+       if (do_get_info(mapname, &info) != 0)
                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;
+       return info.deferred_remove;
 }
 
 static int
@@ -1331,9 +1300,6 @@ alloc_dminfo (void)
 int
 dm_get_info (char * mapname, struct dm_info ** dmi)
 {
-       int r = 1;
-       struct dm_task *dmt = NULL;
-
        if (!mapname)
                return 1;
 
@@ -1343,32 +1309,13 @@ dm_get_info (char * mapname, struct dm_info ** dmi)
        if (!*dmi)
                return 1;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
-               goto out;
-
-       if (!dm_task_set_name(dmt, mapname))
-               goto out;
-
-       dm_task_no_open_count(dmt);
-
-       if (!dm_task_run(dmt))
-               goto out;
-
-       if (!dm_task_get_info(dmt, *dmi))
-               goto out;
-
-       r = 0;
-out:
-       if (r) {
+       if (do_get_info(mapname, *dmi) != 0) {
                memset(*dmi, 0, sizeof(struct dm_info));
                FREE(*dmi);
                *dmi = NULL;
+               return 1;
        }
-
-       if (dmt)
-               dm_task_destroy(dmt);
-
-       return r;
+       return 0;
 }
 
 struct rename_data {
@@ -1422,7 +1369,7 @@ dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
        if (dm_rename_partmaps(old, new, delim))
                return r;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_RENAME)))
                return r;
 
        if (!dm_task_set_name(dmt, old))
@@ -1471,7 +1418,7 @@ int dm_reassign_table(const char *name, char *old, char *new)
        char *buff;
        void *next = NULL;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
                return 0;
 
        if (!dm_task_set_name(dmt, name))
@@ -1481,7 +1428,7 @@ int dm_reassign_table(const char *name, char *old, char *new)
 
        if (!dm_task_run(dmt))
                goto out;
-       if (!(reload_dmt = dm_task_create(DM_DEVICE_RELOAD)))
+       if (!(reload_dmt = libmp_dm_task_create(DM_DEVICE_RELOAD)))
                goto out;
        if (!dm_task_set_name(reload_dmt, name))
                goto out_reload;
@@ -1545,7 +1492,7 @@ int dm_reassign(const char *mapname)
                return 1;
        }
 
-       if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) {
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_DEPS))) {
                condlog(3, "%s: couldn't make dm task", mapname);
                return 0;
        }
@@ -1603,7 +1550,7 @@ int dm_setgeometry(struct multipath *mpp)
                return 1;
        }
 
-       if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
+       if (!(dmt = libmp_dm_task_create(DM_DEVICE_SET_GEOMETRY)))
                return 0;
 
        if (!dm_task_set_name(dmt, mpp->alias))
index aca4454bd4db017aa65070ca6200ef43e6542f57..99a554b59a8dd5cb7a91a51e8c0e2bb5efb09cda 100644 (file)
@@ -25,7 +25,9 @@
 #endif
 
 void dm_init(int verbosity);
-int dm_prereq (void);
+void libmp_dm_init(void);
+void libmp_udev_set_sync_support(int on);
+struct dm_task *libmp_dm_task_create(int task);
 int dm_drv_version (unsigned int * version, char * str);
 int dm_simplecmd_flush (int, const char *, uint16_t);
 int dm_simplecmd_noflush (int, const char *, uint16_t);
@@ -52,8 +54,8 @@ int dm_enablegroup(char * mapname, int index);
 int dm_disablegroup(char * mapname, int index);
 int dm_get_maps (vector mp);
 int dm_geteventnr (char *name);
-int dm_get_major (char *name);
-int dm_get_minor (char *name);
+int dm_is_suspended(const char *name);
+int dm_get_major_minor (const char *name, int *major, int *minor);
 char * dm_mapname(int major, int minor);
 int dm_remove_partmaps (const char * mapname, int need_sync,
                        int deferred_remove);
index 82066f6781a5855d14cb4f8684bc78c859028049..9dc109040f8ae625ef3ed0ca41dc227737834b6b 100644 (file)
@@ -630,7 +630,7 @@ print_fast_io_fail(char * buff, int len, void *ptr)
 }
 
 declare_def_handler(fast_io_fail, set_fast_io_fail)
-declare_def_snprint(fast_io_fail, print_fast_io_fail)
+declare_def_snprint_defint(fast_io_fail, print_fast_io_fail, DEFAULT_FAST_IO_FAIL)
 declare_ovr_handler(fast_io_fail, set_fast_io_fail)
 declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
 declare_hw_handler(fast_io_fail, set_fast_io_fail)
@@ -1082,7 +1082,8 @@ declare_hw_snprint(delay_wait_checks, print_off_int_undef)
 declare_mp_handler(delay_wait_checks, set_off_int_undef)
 declare_mp_snprint(delay_wait_checks, print_off_int_undef)
 declare_def_handler(san_path_err_threshold, set_off_int_undef)
-declare_def_snprint(san_path_err_threshold, print_off_int_undef)
+declare_def_snprint_defint(san_path_err_threshold, print_off_int_undef,
+                          DEFAULT_ERR_CHECKS)
 declare_ovr_handler(san_path_err_threshold, set_off_int_undef)
 declare_ovr_snprint(san_path_err_threshold, print_off_int_undef)
 declare_hw_handler(san_path_err_threshold, set_off_int_undef)
@@ -1090,7 +1091,8 @@ declare_hw_snprint(san_path_err_threshold, print_off_int_undef)
 declare_mp_handler(san_path_err_threshold, set_off_int_undef)
 declare_mp_snprint(san_path_err_threshold, print_off_int_undef)
 declare_def_handler(san_path_err_forget_rate, set_off_int_undef)
-declare_def_snprint(san_path_err_forget_rate, print_off_int_undef)
+declare_def_snprint_defint(san_path_err_forget_rate, print_off_int_undef,
+                          DEFAULT_ERR_CHECKS)
 declare_ovr_handler(san_path_err_forget_rate, set_off_int_undef)
 declare_ovr_snprint(san_path_err_forget_rate, print_off_int_undef)
 declare_hw_handler(san_path_err_forget_rate, set_off_int_undef)
@@ -1098,7 +1100,8 @@ declare_hw_snprint(san_path_err_forget_rate, print_off_int_undef)
 declare_mp_handler(san_path_err_forget_rate, set_off_int_undef)
 declare_mp_snprint(san_path_err_forget_rate, print_off_int_undef)
 declare_def_handler(san_path_err_recovery_time, set_off_int_undef)
-declare_def_snprint(san_path_err_recovery_time, print_off_int_undef)
+declare_def_snprint_defint(san_path_err_recovery_time, print_off_int_undef,
+                          DEFAULT_ERR_CHECKS)
 declare_ovr_handler(san_path_err_recovery_time, set_off_int_undef)
 declare_ovr_snprint(san_path_err_recovery_time, print_off_int_undef)
 declare_hw_handler(san_path_err_recovery_time, set_off_int_undef)
index 663c8eaa85d14cd02711f6a1e24c5457cc5938e4..3a912d761e6e45d878d76327ad10212778788f1d 100644 (file)
@@ -1383,14 +1383,22 @@ path_offline (struct path * pp)
        struct udev_device * parent;
        char buff[SCSI_STATE_SIZE];
        int err;
+       const char *subsys_type;
 
-       if (pp->bus != SYSFS_BUS_SCSI)
+       if (pp->bus == SYSFS_BUS_SCSI) {
+               subsys_type = "scsi";
+       }
+       else if (pp->bus == SYSFS_BUS_NVME) {
+               subsys_type = "nvme";
+       }
+       else {
                return PATH_UP;
+       }
 
        parent = pp->udev;
        while (parent) {
                const char *subsys = udev_device_get_subsystem(parent);
-               if (subsys && !strncmp(subsys, "scsi", 4))
+               if (subsys && !strncmp(subsys, subsys_type, 4))
                        break;
                parent = udev_device_get_parent(parent);
        }
@@ -1412,15 +1420,32 @@ path_offline (struct path * pp)
 
        condlog(3, "%s: path state = %s", pp->dev, buff);
 
-       if (!strncmp(buff, "offline", 7)) {
-               pp->offline = 1;
-               return PATH_DOWN;
+       if (pp->bus == SYSFS_BUS_SCSI) {
+               if (!strncmp(buff, "offline", 7)) {
+                       pp->offline = 1;
+                       return PATH_DOWN;
+               }
+               pp->offline = 0;
+               if (!strncmp(buff, "blocked", 7) ||
+                   !strncmp(buff, "quiesce", 7))
+                       return PATH_PENDING;
+               else if (!strncmp(buff, "running", 7))
+                       return PATH_UP;
+
+       }
+       else if (pp->bus == SYSFS_BUS_NVME) {
+               if (!strncmp(buff, "dead", 4)) {
+                       pp->offline = 1;
+                       return PATH_DOWN;
+               }
+               pp->offline = 0;
+               if (!strncmp(buff, "new", 3) ||
+                   !strncmp(buff, "reconnecting", 12) ||
+                   !strncmp(buff, "resetting", 9))
+                       return PATH_PENDING;
+               else if (!strncmp(buff, "live", 4))
+                       return PATH_UP;
        }
-       pp->offline = 0;
-       if (!strncmp(buff, "blocked", 7) || !strncmp(buff, "quiesce", 7))
-               return PATH_PENDING;
-       else if (!strncmp(buff, "running", 7))
-               return PATH_UP;
 
        return PATH_DOWN;
 }
@@ -1598,6 +1623,82 @@ get_prio (struct path * pp)
        return 0;
 }
 
+/*
+ * Mangle string of length *len starting at start
+ * by removing character sequence "00" (hex for a 0 byte),
+ * starting at end, backwards.
+ * Changes the value of *len if characters were removed.
+ * Returns a pointer to the position where "end" was moved to.
+ */
+static char
+*skip_zeroes_backward(char* start, int *len, char *end)
+{
+       char *p = end;
+
+       while (p >= start + 2 && *(p - 1) == '0' && *(p - 2) == '0')
+               p -= 2;
+
+       if (p == end)
+               return p;
+
+       memmove(p, end, start + *len + 1 - end);
+       *len -= end - p;
+
+       return p;
+}
+
+/*
+ * Fix for NVME wwids looking like this:
+ * nvme.0000-3163653363666438366239656630386200-4c696e75780000000000000000000000000000000000000000000000000000000000000000000000-00000002
+ * which are encountered in some combinations of Linux NVME host and target.
+ * The '00' are hex-encoded 0-bytes which are forbidden in the serial (SN)
+ * and model (MN) fields. Discard them.
+ * If a WWID of the above type is found, sets pp->wwid and returns a value > 0.
+ * Otherwise, returns 0.
+ */
+static int
+fix_broken_nvme_wwid(struct path *pp, const char *value, int size)
+{
+       static const char _nvme[] = "nvme.";
+       int len, i;
+       char mangled[256];
+       char *p;
+
+       len = strlen(value);
+       if (len >= sizeof(mangled))
+               return 0;
+
+       /* Check that value starts with "nvme.%04x-" */
+       if (memcmp(value, _nvme, sizeof(_nvme) - 1) || value[9] != '-')
+               return 0;
+       for (i = 5; i < 9; i++)
+               if (!isxdigit(value[i]))
+                       return 0;
+
+       memcpy(mangled, value, len + 1);
+
+       /* search end of "model" part and strip trailing '00' */
+       p = memrchr(mangled, '-', len);
+       if (p == NULL)
+               return 0;
+
+       p = skip_zeroes_backward(mangled, &len, p);
+
+       /* search end of "serial" part */
+       p = memrchr(mangled, '-', p - mangled);
+       if (p == NULL || memrchr(mangled, '-', p - mangled) != mangled + 9)
+           /* We expect exactly 3 '-' in the value */
+               return 0;
+
+       p = skip_zeroes_backward(mangled, &len, p);
+       if (len >= size)
+               return 0;
+
+       memcpy(pp->wwid, mangled, len + 1);
+       condlog(2, "%s: over-long WWID shortened to %s", pp->dev, pp->wwid);
+       return len;
+}
+
 static int
 get_udev_uid(struct path * pp, char *uid_attribute, struct udev_device *udev)
 {
@@ -1608,13 +1709,14 @@ get_udev_uid(struct path * pp, char *uid_attribute, struct udev_device *udev)
        if (!value || strlen(value) == 0)
                value = getenv(uid_attribute);
        if (value && strlen(value)) {
-               if (strlen(value) + 1 > WWID_SIZE) {
+               len = strlcpy(pp->wwid, value, WWID_SIZE);
+               if (len >= WWID_SIZE) {
+                       len = fix_broken_nvme_wwid(pp, value, WWID_SIZE);
+                       if (len > 0)
+                               return len;
                        condlog(0, "%s: wwid overflow", pp->dev);
                        len = WWID_SIZE;
-               } else {
-                       len = strlen(value);
                }
-               strncpy(pp->wwid, value, len);
        } else {
                condlog(3, "%s: no %s attribute", pp->dev,
                        uid_attribute);
index 469e60d220630d9326a08a8c2d408c74a7624cf9..b647c256b89d3fff9213e1cf205c25dfdc83db7b 100644 (file)
@@ -45,6 +45,22 @@ merge_words (char ** dst, char * word, int space)
        return 0;
 }
 
+#define APPEND(p, end, args...)                                                \
+({                                                                     \
+       int ret;                                                        \
+                                                                       \
+       ret = snprintf(p, end - p, ##args);                             \
+       if (ret < 0) {                                                  \
+               condlog(0, "%s: conversion error", mp->alias);          \
+               goto err;                                               \
+       }                                                               \
+       p += ret;                                                       \
+       if (p >= end) {                                                 \
+               condlog(0, "%s: params too small", mp->alias);          \
+               goto err;                                               \
+       }                                                               \
+})
+
 /*
  * Transforms the path group vector into a proper device map string
  */
@@ -52,10 +68,10 @@ int
 assemble_map (struct multipath * mp, char * params, int len)
 {
        int i, j;
-       int shift, freechar;
        int minio;
        int nr_priority_groups, initial_pg_nr;
        char * p, * f;
+       const char *const end = params + len;
        char no_path_retry[] = "queue_if_no_path";
        char retain_hwhandler[] = "retain_attached_hw_handler";
        struct pathgroup * pgp;
@@ -63,7 +79,6 @@ assemble_map (struct multipath * mp, char * params, int len)
 
        minio = mp->minio;
        p = params;
-       freechar = len;
 
        nr_priority_groups = VECTOR_SIZE(mp->pg);
        initial_pg_nr = (nr_priority_groups ? mp->bestpg : 0);
@@ -74,41 +89,25 @@ assemble_map (struct multipath * mp, char * params, int len)
         * We have to set 'queue_if_no_path' here even
         * to avoid path failures during map reload.
         */
-       if (mp->no_path_retry == NO_PATH_RETRY_UNDEF ||
-           mp->no_path_retry == NO_PATH_RETRY_FAIL) {
+       if (mp->no_path_retry == NO_PATH_RETRY_FAIL) {
                /* remove queue_if_no_path settings */
                condlog(3, "%s: remove queue_if_no_path from '%s'",
                        mp->alias, mp->features);
                remove_feature(&f, no_path_retry);
-       } else {
+       } else if (mp->no_path_retry != NO_PATH_RETRY_UNDEF) {
                add_feature(&f, no_path_retry);
        }
-       if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON)
+       if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON &&
+           get_linux_version_code() < KERNEL_VERSION(4, 3, 0))
                add_feature(&f, retain_hwhandler);
 
-       shift = snprintf(p, freechar, "%s %s %i %i",
-                        f, mp->hwhandler,
-                        nr_priority_groups, initial_pg_nr);
-
-       FREE(f);
-
-       if (shift >= freechar) {
-               condlog(0, "%s: params too small", mp->alias);
-               return 1;
-       }
-       p += shift;
-       freechar -= shift;
+       APPEND(p, end, "%s %s %i %i", f, mp->hwhandler, nr_priority_groups,
+              initial_pg_nr);
 
        vector_foreach_slot (mp->pg, pgp, i) {
                pgp = VECTOR_SLOT(mp->pg, i);
-               shift = snprintf(p, freechar, " %s %i 1", mp->selector,
-                                VECTOR_SIZE(pgp->paths));
-               if (shift >= freechar) {
-                       condlog(0, "%s: params too small", mp->alias);
-                       return 1;
-               }
-               p += shift;
-               freechar -= shift;
+               APPEND(p, end, " %s %i 1", mp->selector,
+                      VECTOR_SIZE(pgp->paths));
 
                vector_foreach_slot (pgp->paths, pp, j) {
                        int tmp_minio = minio;
@@ -118,28 +117,24 @@ assemble_map (struct multipath * mp, char * params, int len)
                                tmp_minio = minio * pp->priority;
                        if (!strlen(pp->dev_t) ) {
                                condlog(0, "dev_t not set for '%s'", pp->dev);
-                               return 1;
+                               goto err;
                        }
-                       shift = snprintf(p, freechar, " %s %d",
-                                        pp->dev_t, tmp_minio);
-                       if (shift >= freechar) {
-                               condlog(0, "%s: params too small", mp->alias);
-                               return 1;
-                       }
-                       p += shift;
-                       freechar -= shift;
+                       APPEND(p, end, " %s %d", pp->dev_t, tmp_minio);
                }
        }
-       if (freechar < 1) {
-               condlog(0, "%s: params too small", mp->alias);
-               return 1;
-       }
-       snprintf(p, 1, "\n");
+       APPEND(p, end, "\n");
 
+       FREE(f);
        condlog(3, "%s: assembled map [%s]", mp->alias, params);
        return 0;
+
+err:
+       FREE(f);
+       return 1;
 }
 
+#undef APPEND
+
 int disassemble_map(vector pathvec, char *params, struct multipath *mpp,
                    int is_daemon)
 {
index c94401554f11a750ba4ea4e73af65526f513fd9c..9e14ec1e9efdfd47f0735c53c8d5164bd252946c 100644 (file)
  * Moreover, if a device needs a special treatment by the SCSI
  * subsystem it should be included in drivers/scsi/scsi_devinfo.c
  */
+
+#if 0
+       /*
+        * Copy this TEMPLATE to add new hardware.
+        *
+        * Keep only mandatory(.vendor and .product) and modified attributes.
+        * Attributes with default values must be removed.
+        * .vendor, .product, .revision and .bl_product are POSIX Extended regex.
+        *
+        * COMPANY_NAME
+        *
+        * Maintainer : XXX
+        * Mail : XXX
+        */
+       {
+               /* If product-ID is different from marketing name add a comment */
+               .vendor        = "VENDOR",
+               .product       = "PRODUCT",
+               .revision      = "REVISION",
+               .bl_product    = "BL_PRODUCT",
+               .pgpolicy      = FAILOVER,
+               .uid_attribute = "ID_SERIAL",
+               .selector      = "service-time 0",
+               .checker_name  = TUR,
+               .alias_prefix  = "mpath",
+               .features      = "0",
+               .hwhandler     = "0",
+               .prio_name     = PRIO_CONST,
+               .prio_args     = "",
+               .pgfailback    = -FAILBACK_MANUAL,
+               .rr_weight     = RR_WEIGHT_NONE,
+               .no_path_retry = NO_PATH_RETRY_UNDEF,
+               .minio         = 1000,
+               .minio_rq      = 1,
+               .flush_on_last_del = FLUSH_DISABLED,
+               .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
+               .fast_io_fail  = 5,
+               .dev_loss      = 600,
+               .retain_hwhandler = RETAIN_HWHANDLER_ON,
+               .detect_prio   = DETECT_PRIO_ON,
+               .detect_checker = DETECT_CHECKER_ON,
+               .deferred_remove = DEFERRED_REMOVE_OFF,
+               .delay_watch_checks = DELAY_CHECKS_OFF,
+               .delay_wait_checks = DELAY_CHECKS_OFF,
+               .skip_kpartx   = SKIP_KPARTX_OFF,
+               .max_sectors_kb = MAX_SECTORS_KB_UNDEF,
+       },
+#endif
+
 static struct hwentry default_hw[] = {
        /*
         * Apple
@@ -49,6 +98,8 @@ static struct hwentry default_hw[] = {
                .hwhandler     = "1 alua",
                .prio_name     = PRIO_ALUA,
                .no_path_retry = 18,
+               .fast_io_fail  = 10,
+               .dev_loss      = MAX_DEV_LOSS_TMO,
        },
        {
                /* RA8000 / ESA12000 */
@@ -112,9 +163,9 @@ static struct hwentry default_hw[] = {
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* MSA 1040/2040 family */
+               /* MSA 1040, 2040 and 2050 families */
                .vendor        = "HP",
-               .product       = "MSA [12]040 SA[NS]",
+               .product       = "MSA [12]0[45]0 SA[NS]",
                .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 18,
@@ -147,9 +198,9 @@ static struct hwentry default_hw[] = {
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* StoreVirtual 4000 family */
+               /* StoreVirtual 4000 and 3200 families */
                .vendor        = "LEFTHAND",
-               .product       = "^(P4000|iSCSIDisk)",
+               .product       = "(P4000|iSCSIDisk|FCDISK)",
                .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 18,
@@ -223,35 +274,11 @@ static struct hwentry default_hw[] = {
                .product       = "Compellent Vol",
                .pgpolicy      = MULTIBUS,
                .no_path_retry = NO_PATH_RETRY_QUEUE,
-       },
-               /* MD Series */
-       {
-               .vendor        = "DELL",
-               .product       = "MD3000",
-               .bl_product    = "Universal Xport",
-               .pgpolicy      = GROUP_BY_PRIO,
-               .checker_name  = RDAC,
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .prio_name     = PRIO_RDAC,
-               .pgfailback    = -FAILBACK_IMMEDIATE,
-               .no_path_retry = 30,
-       },
-       {
-               .vendor        = "DELL",
-               .product       = "(MD32xx|MD36xx)",
-               .bl_product    = "Universal Xport",
-               .pgpolicy      = GROUP_BY_PRIO,
-               .checker_name  = RDAC,
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .prio_name     = PRIO_RDAC,
-               .pgfailback    = -FAILBACK_IMMEDIATE,
-               .no_path_retry = 30,
        },
        {
+               /* MD Series */
                .vendor        = "DELL",
-               .product       = "(MD34xx|MD38xx)",
+               .product       = "^MD3",
                .bl_product    = "Universal Xport",
                .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
@@ -285,12 +312,18 @@ static struct hwentry default_hw[] = {
        },
        {
                .vendor        = "FUJITSU",
-               .product       = "E[248]000",
+               .product       = "E[234]000",
                .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 10,
                .prio_name     = PRIO_ALUA,
        },
+       {
+               .vendor        = "FUJITSU",
+               .product       = "E[68]000",
+               .pgpolicy      = MULTIBUS,
+               .no_path_retry = 10,
+       },
        /*
         * Hitachi
         *
@@ -851,7 +884,7 @@ static struct hwentry default_hw[] = {
         * Intel
         */
        {
-               .vendor        = "(Intel|INTEL)",
+               .vendor        = "(Intel|INTEL)",
                .product       = "Multi-Flex",
                .bl_product    = "VTrak V-LUN",
                .hwhandler     = "1 alua",
@@ -864,7 +897,7 @@ static struct hwentry default_hw[] = {
         * Linux-IO Target
         */
        {
-               .vendor        = "(LIO-ORG|SUSE)",
+               .vendor        = "(LIO-ORG|SUSE)",
                .product       = "RBD",
                .hwhandler     = "1 alua",
                .pgpolicy      = GROUP_BY_PRIO,
@@ -876,7 +909,7 @@ static struct hwentry default_hw[] = {
         * DataCore
         */
        {
-               .vendor        = "DataCore",
+               .vendor        = "DataCore",
                .product       = "SANmelody",
                .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = -FAILBACK_IMMEDIATE,
@@ -885,7 +918,7 @@ static struct hwentry default_hw[] = {
        },
        {
                /* SANsymphony */
-               .vendor        = "DataCore",
+               .vendor        = "DataCore",
                .product       = "Virtual Disk",
                .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = -FAILBACK_IMMEDIATE,
@@ -905,7 +938,7 @@ static struct hwentry default_hw[] = {
         */
        {
                /* OceanStor V3 */
-               .vendor        = "(HUAWEI|HUASY)",
+               .vendor        = "HUAWEI",
                .product       = "XSG1",
                .pgpolicy      = MULTIBUS,
        },
@@ -1077,59 +1110,12 @@ static struct hwentry default_hw[] = {
         * Generic NVMe devices
         */
        {
-               .vendor        = "NVME",
+               .vendor        = "NVME",
                .product       = ".*",
                .uid_attribute = "ID_WWN",
                .checker_name  = DIRECTIO,
                .retain_hwhandler = RETAIN_HWHANDLER_OFF,
        },
-#if 0
-       /*
-        * Copy this TEMPLATE to add new hardware.
-        *
-        * Keep only mandatory(.vendor and .product) and modified attributes.
-        * Attributes with default values must be removed.
-        * .vendor, .product, .revision and .bl_product are POSIX Extended regex.
-        *
-        * COMPANY_NAME
-        *
-        * Maintainer : XXX
-        * Mail : XXX
-        */
-       {
-               /* If product-ID is different from marketing name add a comment */
-               .vendor        = "VENDOR",
-               .product       = "PRODUCT",
-               .revision      = "REVISION",
-               .bl_product    = "BL_PRODUCT",
-               .pgpolicy      = FAILOVER,
-               .uid_attribute = "ID_SERIAL",
-               .selector      = "service-time 0",
-               .checker_name  = TUR,
-               .alias_prefix  = "mpath",
-               .features      = "0",
-               .hwhandler     = "0",
-               .prio_name     = PRIO_CONST,
-               .prio_args     = "",
-               .pgfailback    = -FAILBACK_MANUAL,
-               .rr_weight     = RR_WEIGHT_NONE,
-               .no_path_retry = NO_PATH_RETRY_UNDEF,
-               .minio         = 1000,
-               .minio_rq      = 1,
-               .flush_on_last_del = FLUSH_DISABLED,
-               .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
-               .fast_io_fail  = 5,
-               .dev_loss      = 600,
-               .retain_hwhandler = RETAIN_HWHANDLER_ON,
-               .detect_prio   = DETECT_PRIO_ON,
-               .detect_checker = DETECT_CHECKER_ON,
-               .deferred_remove = DEFERRED_REMOVE_OFF,
-               .delay_watch_checks = DELAY_CHECKS_OFF,
-               .delay_wait_checks = DELAY_CHECKS_OFF,
-               .skip_kpartx = SKIP_KPARTX_OFF,
-               .max_sectors_kb = MAX_SECTORS_KB_UNDEF,
-       },
-#endif
        /*
         * EOL
         */
index 7c2a1588e8188a0bb8d40d88beaff647570f3cc7..95dff90bb5be3ce53e5b813ff3ba027dd1e84e03 100644 (file)
@@ -39,9 +39,18 @@ do { \
        s = c; \
 } while (0)
 
-#define ENDLINE \
-               if (c > line) \
-                       line[c - line - 1] = '\n'
+static char *
+__endline(char *line, size_t len, char *c)
+{
+       if (c > line) {
+               if (c >= line + len)
+                       c = line + len - 1;
+               *(c - 1) = '\n';
+               *c = '\0';
+       }
+       return c;
+}
+
 #define PRINT(var, size, format, args...) \
 do { \
        fwd = snprintf(var, size, format, ##args); \
@@ -802,7 +811,7 @@ snprint_multipath_header (char * line, int len, char * format)
                PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
@@ -838,7 +847,7 @@ snprint_multipath (char * line, int len, char * format,
                buff[0] = '\0';
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
@@ -869,7 +878,7 @@ snprint_path_header (char * line, int len, char * format)
                PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
@@ -904,7 +913,7 @@ snprint_path (char * line, int len, char * format,
                        PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
@@ -938,7 +947,7 @@ snprint_pathgroup (char * line, int len, char * format,
                PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
index 0193c5249c58842777fb0e245bfa34378f5ca89d..c97fe39728b93a582fb08c029f6bfbc38caddeef 100644 (file)
@@ -29,6 +29,7 @@ struct path;
 #define PRIO_RDAC              "rdac"
 #define PRIO_WEIGHTED_PATH     "weightedpath"
 #define PRIO_SYSFS             "sysfs"
+#define PRIO_PATH_LATENCY      "path_latency"
 
 /*
  * Value used to mark the fact prio was not defined
index 36b42e4189e98772c2d47aea3c78e9060f5d7ca7..0c71e6334473c3681dbfe6ab4d701adac16e4a82 100644 (file)
@@ -3,7 +3,7 @@
 #
 include ../../Makefile.inc
 
-CFLAGS += -I..
+CFLAGS += $(LIB_CFLAGS) -I..
 
 # If you add or remove a prioritizer also update multipath/multipath.conf.5
 LIBS = \
@@ -18,6 +18,7 @@ LIBS = \
        libpriorandom.so \
        libpriordac.so \
        libprioweightedpath.so \
+       libpriopath_latency.so \
        libpriosysfs.so
 
 all: $(LIBS)
@@ -25,6 +26,9 @@ all: $(LIBS)
 libprioalua.so: alua.o alua_rtpg.o
        $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^
 
+libpriopath_latency.so: path_latency.o  ../checkers/libsg.o
+       $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lm
+
 libprio%.so: %.o
        $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^
 
index 36465ac4966214db71b7120857a3096000a25d6e..59c98164e0d73df279d05e6d289340c35c3a570c 100644 (file)
 int datacore_prio (const char *dev, int sg_fd, char * args)
 {
        int k;
-       char vendor[8];
-       char product[32];
-       char luname[32];
-       char wwpn[32];
        char sdsname[32];
        unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 };
        unsigned char inqBuff[INQ_REPLY_LEN];
@@ -95,11 +91,7 @@ int datacore_prio (const char *dev, int sg_fd, char * args)
        if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
                return 0;
 
-       snprintf(vendor, 8, "%.8s\n", inqBuffp + 8);
-       snprintf(product, 17, "%.16s", inqBuffp + 16);
-       snprintf(luname, 21, "%.19s", inqBuffp + 36);
-       snprintf(wwpn, 17, "%.16s", inqBuffp + 96);
-       snprintf(sdsname, 17, "%.16s", inqBuffp + 112);
+       snprintf(sdsname, sizeof(sdsname), "%.16s", inqBuffp + 112);
 
        if (strstr(sdsname , preferredsds))
                return 1;
diff --git a/libmultipath/prioritizers/path_latency.c b/libmultipath/prioritizers/path_latency.c
new file mode 100644 (file)
index 0000000..9fc2dfc
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * (C) Copyright HUAWEI Technology Corp. 2017, All Rights Reserved.
+ *
+ * path_latency.c
+ *
+ * Prioritizer for device mapper multipath, where the corresponding priority
+ * values of specific paths are provided by a latency algorithm. And the
+ * latency algorithm is dependent on arguments("io_num" and "base_num").
+ *
+ * The principle of the algorithm as follows:
+ * 1. By sending a certain number "io_num" of read IOs to the current path
+ *    continuously, the IOs' average latency can be calculated.
+ * 2. Max value and min value of average latency are constant. According to
+ *    the average latency of each path and the "base_num" of logarithmic
+ *    scale, the priority "rc" of each path can be provided.
+ *
+ * Author(s): Yang Feng <philip.yang@huawei.com>
+ *
+ * This file is released under the GPL version 2, or any later version.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
+#include "../checkers/libsg.h"
+
+#define pp_pl_log(prio, fmt, args...) condlog(prio, "path_latency prio: " fmt, ##args)
+
+#define MAX_IO_NUM             200
+#define MIN_IO_NUM             2
+
+#define MAX_BASE_NUM           10
+#define MIN_BASE_NUM           2
+
+#define MAX_AVG_LATENCY                100000000.      /* Unit: us */
+#define MIN_AVG_LATENCY                1.              /* Unit: us */
+
+#define DEFAULT_PRIORITY       0
+
+#define MAX_CHAR_SIZE          30
+
+#define USEC_PER_SEC           1000000LL
+#define NSEC_PER_USEC          1000LL
+
+static long long path_latency[MAX_IO_NUM];
+
+static inline long long timeval_to_us(const struct timespec *tv)
+{
+       return ((long long)tv->tv_sec * USEC_PER_SEC) +
+           (tv->tv_nsec / NSEC_PER_USEC);
+}
+
+static int do_readsector0(int fd, unsigned int timeout)
+{
+       unsigned char buf[4096];
+       unsigned char sbuf[SENSE_BUFF_LEN];
+       int ret;
+
+       ret = sg_read(fd, &buf[0], 4096, &sbuf[0], SENSE_BUFF_LEN, timeout);
+
+       return ret;
+}
+
+int check_args_valid(int io_num, int base_num)
+{
+       if ((io_num < MIN_IO_NUM) || (io_num > MAX_IO_NUM)) {
+               pp_pl_log(0, "args io_num is outside the valid range");
+               return 0;
+       }
+
+       if ((base_num < MIN_BASE_NUM) || (base_num > MAX_BASE_NUM)) {
+               pp_pl_log(0, "args base_num is outside the valid range");
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * In multipath.conf, args form: io_num|base_num. For example,
+ * args is "20|10", this function can get io_num value 20, and
+ * base_num value 10.
+ */
+static int get_ionum_and_basenum(char *args, int *ionum, int *basenum)
+{
+       char source[MAX_CHAR_SIZE];
+       char vertica = '|';
+       char *endstrbefore = NULL;
+       char *endstrafter = NULL;
+       unsigned int size = strlen(args);
+
+       if ((args == NULL) || (ionum == NULL) || (basenum == NULL)) {
+               pp_pl_log(0, "args string is NULL");
+               return 0;
+       }
+
+       if ((size < 1) || (size > MAX_CHAR_SIZE - 1)) {
+               pp_pl_log(0, "args string's size is too long");
+               return 0;
+       }
+
+       memcpy(source, args, size + 1);
+
+       if (!isdigit(source[0])) {
+               pp_pl_log(0, "invalid prio_args format: %s", source);
+               return 0;
+       }
+
+       *ionum = (int)strtoul(source, &endstrbefore, 10);
+       if (endstrbefore[0] != vertica) {
+               pp_pl_log(0, "invalid prio_args format: %s", source);
+               return 0;
+       }
+
+       if (!isdigit(endstrbefore[1])) {
+               pp_pl_log(0, "invalid prio_args format: %s", source);
+               return 0;
+       }
+
+       *basenum = (long long)strtol(&endstrbefore[1], &endstrafter, 10);
+       if (check_args_valid(*ionum, *basenum) == 0) {
+               return 0;
+       }
+
+       return 1;
+}
+
+long long calc_standard_deviation(long long *path_latency, int size,
+                                 long long avglatency)
+{
+       int index;
+       long long total = 0;
+
+       for (index = 0; index < size; index++) {
+               total +=
+                   (path_latency[index] - avglatency) * (path_latency[index] -
+                                                         avglatency);
+       }
+
+       total /= (size - 1);
+
+       return (long long)sqrt((double)total);
+}
+
+int calcPrio(double avglatency, double max_avglatency, double min_avglatency,
+            double base_num)
+{
+       double lavglatency = log(avglatency) / log(base_num);
+       double lmax_avglatency = log(max_avglatency) / log(base_num);
+       double lmin_avglatency = log(min_avglatency) / log(base_num);
+
+       if (lavglatency <= lmin_avglatency)
+               return (int)(lmax_avglatency + 1.);
+
+       if (lavglatency > lmax_avglatency)
+               return 0;
+
+       return (int)(lmax_avglatency - lavglatency + 1.);
+}
+
+/* Calc the latency interval corresponding to the average latency */
+long long calc_latency_interval(double avglatency, double max_avglatency,
+                               double min_avglatency, double base_num)
+{
+       double lavglatency = log(avglatency) / log(base_num);
+       double lmax_avglatency = log(max_avglatency) / log(base_num);
+       double lmin_avglatency = log(min_avglatency) / log(base_num);
+
+       if ((lavglatency <= lmin_avglatency)
+           || (lavglatency > lmax_avglatency))
+               return 0;       /* Invalid value */
+
+       if ((double)((int)lavglatency) == lavglatency)
+               return (long long)(avglatency - (avglatency / base_num));
+       else
+               return (long long)(pow(base_num, (double)((int)lavglatency + 1))
+                                  - pow(base_num, (double)((int)lavglatency)));
+}
+
+int getprio(struct path *pp, char *args, unsigned int timeout)
+{
+       int rc, temp;
+       int index = 0;
+       int io_num;
+       int base_num;
+       long long avglatency;
+       long long latency_interval;
+       long long standard_deviation;
+       long long toldelay = 0;
+       long long before, after;
+       struct timespec tv;
+
+       if (pp->fd < 0)
+               return -1;
+
+       if (get_ionum_and_basenum(args, &io_num, &base_num) == 0) {
+               pp_pl_log(0, "%s: get path_latency args fail", pp->dev);
+               return DEFAULT_PRIORITY;
+       }
+
+       memset(path_latency, 0, sizeof(path_latency));
+
+       temp = io_num;
+       while (temp-- > 0) {
+               (void)clock_gettime(CLOCK_MONOTONIC, &tv);
+               before = timeval_to_us(&tv);
+
+               if (do_readsector0(pp->fd, timeout) == 2) {
+                       pp_pl_log(0, "%s: path down", pp->dev);
+                       return -1;
+               }
+
+               (void)clock_gettime(CLOCK_MONOTONIC, &tv);
+               after = timeval_to_us(&tv);
+
+               path_latency[index] = after - before;
+               toldelay += path_latency[index++];
+       }
+
+       avglatency = toldelay / (long long)io_num;
+       pp_pl_log(4, "%s: average latency is (%lld us)", pp->dev, avglatency);
+
+       if (avglatency > MAX_AVG_LATENCY) {
+               pp_pl_log(0,
+                         "%s: average latency (%lld us) is outside the thresold (%lld us)",
+                         pp->dev, avglatency, (long long)MAX_AVG_LATENCY);
+               return DEFAULT_PRIORITY;
+       }
+
+       /*
+        * Min average latency and max average latency are constant, the args
+        * base_num set can change latency_interval value corresponding to
+        * avglatency and is not constant.
+        * Warn the user if latency_interval is smaller than (2 * standard_deviation),
+        * or equal.
+        */
+       standard_deviation =
+           calc_standard_deviation(path_latency, index, avglatency);
+       latency_interval =
+           calc_latency_interval(avglatency, MAX_AVG_LATENCY, MIN_AVG_LATENCY,
+                                 base_num);
+       if ((latency_interval != 0)
+           && (latency_interval <= (2 * standard_deviation)))
+               pp_pl_log(3,
+                         "%s: latency interval (%lld) according to average latency (%lld us) is smaller than "
+                         "2 * standard deviation (%lld us), or equal, args base_num (%d) needs to be set bigger value",
+                         pp->dev, latency_interval, avglatency,
+                         standard_deviation, base_num);
+
+       rc = calcPrio(avglatency, MAX_AVG_LATENCY, MIN_AVG_LATENCY, base_num);
+       return rc;
+}
index 09fe7282feb5eaf04d84a82efdbee282327682f5..175fbe1168d0395eb40714c9ccff55987a8bbc13 100644 (file)
@@ -269,6 +269,60 @@ out:
        return mp->alias ? 0 : 1;
 }
 
+void reconcile_features_with_options(const char *id, char **features, int* no_path_retry,
+                 int *retain_hwhandler)
+{
+       static const char q_i_n_p[] = "queue_if_no_path";
+       static const char r_a_h_h[] = "retain_attached_hw_handler";
+       char buff[12];
+
+       if (*features == NULL)
+               return;
+       if (id == NULL)
+               id = "UNKNOWN";
+
+       /*
+        * We only use no_path_retry internally. The "queue_if_no_path"
+        * device-mapper feature is derived from it when the map is loaded.
+        * For consistency, "queue_if_no_path" is removed from the
+        * internal libmultipath features string.
+        * For backward compatibility we allow 'features "1 queue_if_no_path"';
+        * it's translated into "no_path_retry queue" here.
+        */
+       if (strstr(*features, q_i_n_p)) {
+               condlog(0, "%s: option 'features \"1 %s\"' is deprecated, "
+                       "please use 'no_path_retry queue' instead",
+                       id, q_i_n_p);
+               if (*no_path_retry == NO_PATH_RETRY_UNDEF) {
+                       *no_path_retry = NO_PATH_RETRY_QUEUE;
+                       print_no_path_retry(buff, sizeof(buff),
+                                           no_path_retry);
+                       condlog(3, "%s: no_path_retry = %s (inherited setting from feature '%s')",
+                               id, buff, q_i_n_p);
+               };
+               /* Warn only if features string is overridden */
+               if (*no_path_retry != NO_PATH_RETRY_QUEUE) {
+                       print_no_path_retry(buff, sizeof(buff),
+                                           no_path_retry);
+                       condlog(2, "%s: ignoring feature '%s' because no_path_retry is set to '%s'",
+                               id, q_i_n_p, buff);
+               }
+               remove_feature(features, q_i_n_p);
+       }
+       if (strstr(*features, r_a_h_h)) {
+               condlog(0, "%s: option 'features \"1 %s\"' is deprecated",
+                       id, r_a_h_h);
+               if (*retain_hwhandler == RETAIN_HWHANDLER_UNDEF) {
+                       condlog(3, "%s: %s = on (inherited setting from feature '%s')",
+                               id, r_a_h_h, r_a_h_h);
+                       *retain_hwhandler = RETAIN_HWHANDLER_ON;
+               } else if (*retain_hwhandler == RETAIN_HWHANDLER_OFF)
+                       condlog(2, "%s: ignoring feature '%s' because %s is set to 'off'",
+                               id, r_a_h_h, r_a_h_h);
+               remove_feature(features, r_a_h_h);
+       }
+}
+
 int select_features(struct config *conf, struct multipath *mp)
 {
        char *origin;
@@ -280,19 +334,11 @@ int select_features(struct config *conf, struct multipath *mp)
        mp_set_default(features, DEFAULT_FEATURES);
 out:
        mp->features = STRDUP(mp->features);
-       condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
 
-       if (strstr(mp->features, "queue_if_no_path")) {
-               if (mp->no_path_retry == NO_PATH_RETRY_UNDEF)
-                       mp->no_path_retry = NO_PATH_RETRY_QUEUE;
-               else if (mp->no_path_retry == NO_PATH_RETRY_FAIL) {
-                       condlog(1, "%s: config error, overriding 'no_path_retry' value",
-                               mp->alias);
-                       mp->no_path_retry = NO_PATH_RETRY_QUEUE;
-               } else if (mp->no_path_retry != NO_PATH_RETRY_QUEUE)
-                       condlog(1, "%s: config error, ignoring 'queue_if_no_path' because no_path_retry=%d",
-                               mp->alias, mp->no_path_retry);
-       }
+       reconcile_features_with_options(mp->alias, &mp->features,
+                                       &mp->no_path_retry,
+                                       &mp->retain_hwhandler);
+       condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
        return 0;
 }
 
@@ -333,11 +379,11 @@ out:
                                pp->dev, c->timeout);
        }
        else if (sysfs_get_timeout(pp, &c->timeout) > 0)
-               condlog(3, "%s: checker timeout = %u ms (setting: kernel sysfs)",
+               condlog(3, "%s: checker timeout = %u s (setting: kernel sysfs)",
                                pp->dev, c->timeout);
        else {
                c->timeout = DEF_TIMEOUT;
-               condlog(3, "%s: checker timeout = %u ms (setting: multipath internal)",
+               condlog(3, "%s: checker timeout = %u s (setting: multipath internal)",
                                pp->dev, c->timeout);
        }
        return 0;
@@ -456,7 +502,7 @@ int select_no_path_retry(struct config *conf, struct multipath *mp)
        char buff[12];
 
        if (mp->flush_on_last_del == FLUSH_IN_PROGRESS) {
-               condlog(0, "flush_on_last_del in progress");
+               condlog(0, "%s: flush_on_last_del in progress", mp->alias);
                mp->no_path_retry = NO_PATH_RETRY_FAIL;
                return 0;
        }
@@ -469,9 +515,6 @@ out:
        if (origin)
                condlog(3, "%s: no_path_retry = %s %s", mp->alias, buff,
                        origin);
-       else if (mp->no_path_retry != NO_PATH_RETRY_UNDEF)
-               condlog(3, "%s: no_path_retry = %s (inherited setting)",
-                       mp->alias, buff);
        else
                condlog(3, "%s: no_path_retry = undef (setting: multipath internal)",
                        mp->alias);
@@ -585,7 +628,12 @@ int select_retain_hwhandler(struct config *conf, struct multipath *mp)
 
        if (!VERSION_GE(conf->version, minv_dm_retain)) {
                mp->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-               origin = "(setting: WARNING, requires kernel version >= 1.5.0)";
+               origin = "(setting: WARNING, requires kernel dm-mpath version >= 1.5.0)";
+               goto out;
+       }
+       if (get_linux_version_code() >= KERNEL_VERSION(4, 3, 0)) {
+               mp->retain_hwhandler = RETAIN_HWHANDLER_ON;
+               origin = "(setting: implied in kernel >= 4.3.0)";
                goto out;
        }
        mp_set_ovr(retain_hwhandler);
@@ -744,8 +792,7 @@ out:
        return 0;
 }
 
-extern int
-select_max_sectors_kb (struct config *conf, struct multipath * mp)
+int select_max_sectors_kb(struct config *conf, struct multipath * mp)
 {
        char *origin;
 
@@ -753,6 +800,12 @@ select_max_sectors_kb (struct config *conf, struct multipath * mp)
        mp_set_ovr(max_sectors_kb);
        mp_set_hwe(max_sectors_kb);
        mp_set_conf(max_sectors_kb);
+       mp_set_default(max_sectors_kb, DEFAULT_MAX_SECTORS_KB);
+       /*
+        * In the default case, we will not modify max_sectors_kb in sysfs
+        * (see sysfs_set_max_sectors_kb()).
+        * Don't print a log message here to avoid user confusion.
+        */
        return 0;
 out:
        condlog(3, "%s: max_sectors_kb = %i %s", mp->alias, mp->max_sectors_kb,
index 58a32f3cc25cc7e479ce58a8a8f1c04da9131f4c..f8e96d856b0fc1f2f43099692915e27d04a8d88d 100644 (file)
@@ -28,3 +28,6 @@ int select_max_sectors_kb (struct config *conf, struct multipath * mp);
 int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp);
 int select_san_path_err_threshold(struct config *conf, struct multipath *mp);
 int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp);
+void reconcile_features_with_options(const char *id, char **features,
+                                    int* no_path_retry,
+                                    int *retain_hwhandler);
index e225f8b4969d41cce6805061e2881e9476ce38a1..2870467694250d76b19e474fd5f31303388a352e 100644 (file)
@@ -513,10 +513,11 @@ void setup_feature(struct multipath *mpp, char *feature)
        }
 }
 
-int add_feature(char **f, char *n)
+int add_feature(char **f, const char *n)
 {
        int c = 0, d, l = 0;
        char *e, *p, *t;
+       const char *q;
 
        if (!f)
                return 1;
@@ -554,14 +555,14 @@ int add_feature(char **f, char *n)
        if ((c % 10) == 9)
                l++;
        c++;
-       p = n;
-       while (*p != '\0') {
-               if (*p == ' ' && p[1] != '\0' && p[1] != ' ') {
+       q = n;
+       while (*q != '\0') {
+               if (*q == ' ' && q[1] != '\0' && q[1] != ' ') {
                        if ((c % 10) == 9)
                                l++;
                        c++;
                }
-               p++;
+               q++;
        }
 
        t = MALLOC(l + 1);
@@ -601,10 +602,11 @@ int add_feature(char **f, char *n)
        return 0;
 }
 
-int remove_feature(char **f, char *o)
+int remove_feature(char **f, const char *o)
 {
        int c = 0, d, l;
        char *e, *p, *n;
+       const char *q;
 
        if (!f || !*f)
                return 1;
@@ -630,18 +632,18 @@ int remove_feature(char **f, char *o)
        /* Just spaces, return */
        if (*o == '\0')
                return 0;
-       e = o + strlen(o);
-       while (*e == ' ')
-               e--;
-       d = (int)(e - o);
+       q = o + strlen(o);
+       while (*q == ' ')
+               q--;
+       d = (int)(q - o);
 
        /* Update feature count */
        c--;
-       p = o;
-       while (p[0] != '\0') {
-               if (p[0] == ' ' && p[1] != ' ' && p[1] != '\0')
+       q = o;
+       while (q[0] != '\0') {
+               if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
                        c--;
-               p++;
+               q++;
        }
 
        /* Quick exit if all features have been removed */
index 98e13e4a731806f3c88035ad651aa3612d1a4e28..8ea984d9c223a9065ce64a2ffb4d702c7751f4e2 100644 (file)
@@ -272,6 +272,7 @@ struct multipath {
        int skip_kpartx;
        int max_sectors_kb;
        int force_readonly;
+       int force_udev_reload;
        unsigned int dev_loss;
        uid_t uid;
        gid_t gid;
@@ -368,8 +369,8 @@ int pathcountgr (struct pathgroup *, int);
 int pathcount (struct multipath *, int);
 int pathcmp (struct pathgroup *, struct pathgroup *);
 void setup_feature(struct multipath *, char *);
-int add_feature (char **, char *);
-int remove_feature (char **, char *);
+int add_feature (char **, const char *);
+int remove_feature (char **, const char *);
 
 extern char sysfs_path[PATH_SIZE];
 
index 4fbd1dfb50beebf8342f9a070291a7789eb488cc..eb44da56409aee73d6e8e6e72b68be365ed328fb 100644 (file)
@@ -143,36 +143,11 @@ uevent_need_merge(void)
        return need_merge;
 }
 
-static bool
-uevent_can_discard_by_devpath(const char *devpath)
-{
-       static const char BLOCK[] = "/block/";
-       const char *tmp = strstr(devpath, BLOCK);
-
-       if (tmp == NULL) {
-               condlog(4, "no /block/ in '%s'", devpath);
-               return true;
-       }
-       tmp += sizeof(BLOCK) - 1;
-       if (*tmp == '\0')
-               /* just ".../block/" - discard */
-               return true;
-       /*
-        * If there are more path elements after ".../block/xyz",
-        * it's a partition - discard it; but don't discard ".../block/sda/".
-        */
-       tmp = strchr(tmp, '/');
-       return tmp != NULL && *(tmp + 1) != '\0';
-}
-
 bool
 uevent_can_discard(struct uevent *uev)
 {
        struct config * conf;
 
-       if (uevent_can_discard_by_devpath(uev->devpath))
-               return true;
-
        /*
         * do not filter dm devices by devnode
         */
@@ -795,7 +770,7 @@ int uevent_listen(struct udev *udev)
                goto out;
        }
        err = udev_monitor_filter_add_match_subsystem_devtype(monitor, "block",
-                                                             NULL);
+                                                             "disk");
        if (err)
                condlog(2, "failed to create filter : %s", strerror(-err));
        err = udev_monitor_enable_receiving(monitor);
index b90cd8b0178a061e7a2ae97843f4f558df6cdbc1..dff2ed3ca53917a221443666c6facc794fa70046 100644 (file)
@@ -6,6 +6,7 @@
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <errno.h>
@@ -380,3 +381,38 @@ int systemd_service_enabled(const char *dev)
                found = systemd_service_enabled_in(dev, "/run");
        return found;
 }
+
+static int _linux_version_code;
+static pthread_once_t _lvc_initialized = PTHREAD_ONCE_INIT;
+
+/* Returns current kernel version encoded as major*65536 + minor*256 + patch,
+ * so, for example,  to check if the kernel is greater than 2.2.11:
+ *
+ *     if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> }
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Code copied from busybox (GPLv2 or later)
+ */
+static void
+_set_linux_version_code(void)
+{
+       struct utsname name;
+       char *t;
+       int i, r;
+
+       uname(&name); /* never fails */
+       t = name.release;
+       r = 0;
+       for (i = 0; i < 3; i++) {
+               t = strtok(t, ".");
+               r = r * 256 + (t ? atoi(t) : 0);
+               t = NULL;
+       }
+       _linux_version_code = r;
+}
+
+int get_linux_version_code(void)
+{
+       pthread_once(&_lvc_initialized, _set_linux_version_code);
+       return _linux_version_code;
+}
index b087e32e2aef35889f125382c536db3be6d6a585..45291be88fd87716795cd7ec08705a208c91e053 100644 (file)
@@ -15,6 +15,8 @@ char *convert_dev(char *dev, int is_path_device);
 char *parse_uid_attribute_by_attrs(char *uid_attrs, char *path_dev);
 void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);
 int systemd_service_enabled(const char *dev);
+int get_linux_version_code(void);
+#define KERNEL_VERSION(maj, min, ptc) ((((maj) * 256) + (min)) * 256 + (ptc))
 
 #define safe_sprintf(var, format, args...)     \
        snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
index 5d45932e3d765d5f2acc5b6d39d0fb247a943e83..777d71a4d12b699adb1ac738fab6246770261131 100644 (file)
@@ -20,8 +20,8 @@
 #ifndef _VERSION_H
 #define _VERSION_H
 
-#define VERSION_CODE 0x000701
-#define DATE_CODE    0x040d11
+#define VERSION_CODE 0x000702
+#define DATE_CODE    0x080511
 
 #define PROG    "multipath-tools"
 
index 995ea1adae961f9615400ccfb39c2f53c02e6c7e..cb9708b2f72c76ab13c7e4188e865f2edf414004 100644 (file)
@@ -76,7 +76,7 @@ static int waiteventloop (struct event_thread *waiter)
        if (!waiter->event_nr)
                waiter->event_nr = dm_geteventnr(waiter->mapname);
 
-       if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
+       if (!(waiter->dmt = libmp_dm_task_create(DM_DEVICE_WAITEVENT))) {
                condlog(0, "%s: devmap event #%i dm_task_create error",
                                waiter->mapname, waiter->event_nr);
                return 1;
index 47043bb5e611e0bcdeb60dce52c6c7d548536e06..bd1c0df93a12e61d4f30d525627f2351e5d9b10e 100644 (file)
@@ -1,6 +1,7 @@
 include ../Makefile.inc
 
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
+CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir)
+LDFLAGS += $(BIN_LDFLAGS)
 
 LIBDEPS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist \
           -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev
index 2e0aba3c02207f520d39acaa88846e88cbdfb622..79b89e5b035a29d62be45e1a623c138e57911ca2 100644 (file)
@@ -40,7 +40,6 @@ void mpath_print_transport_id(struct prin_fulldescr *fdesc);
 int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
 
 int logsink;
-unsigned int mpath_mx_alloc_len;
 struct config *multipath_conf;
 
 struct config *get_multipath_config(void)
@@ -57,6 +56,8 @@ void rcu_register_thread_memb(void) {}
 
 void rcu_unregister_thread_memb(void) {}
 
+struct udev *udev;
+
 int main (int argc, char * argv[])
 {
        int fd, c, res;
@@ -86,7 +87,6 @@ int main (int argc, char * argv[])
        int num_transport =0;
        void *resp = NULL;
        struct transportid * tmp;
-       struct udev *udev = NULL;
        struct config *conf;
 
        if (optind == argc)
@@ -104,7 +104,7 @@ int main (int argc, char * argv[])
        }
 
        udev = udev_new();
-       conf = mpath_lib_init(udev);
+       conf = mpath_lib_init();
        if(!conf) {
                udev_unref(udev);
                exit(1);
index 4b15666f1b56116229907673eddebe3bf259ca1f..a8982e659d6b3c00227d1abf85521eb59ed760ca 100644 (file)
@@ -34,6 +34,12 @@ attribute must be defined in the \fI/etc/multipath.conf\fR file. Otherwise the
 \fBmultipathd\fR daemon will not check for persistent reservation for newly
 discovered paths or reinstated paths.
 .
+.LP
+\fBmpathpersist\fR supports the same command-line options as the
+\fBsg_persist\fR utility.
+.
+Consult the \fBsg_persist (8)\fR manual page for an in-depth discussion of the
+various options.
 .
 .\" ----------------------------------------------------------------------------
 .SH OPTIONS
@@ -89,6 +95,10 @@ PR Out parameter 'APTPL'.
 PR In: Read Keys.
 .
 .TP
+.BI \--param-rk=\fIRK\fB|\-K " RK"
+PR Out parameter reservation key (RK is in hex, up to 8 bytes).
+.
+.TP
 .BI \--param-sark=\fISARK\fB|\-S " SARK"
 PR Out parameter service action reservation key (SARK is in hex).
 .
@@ -97,6 +107,10 @@ PR Out parameter service action reservation key (SARK is in hex).
 PR Out: Preempt.
 .
 .TP
+.B \--clear|\-C
+PR Out: Clear registrations.
+.
+.TP
 .B \--preempt-abort|\-A
 PR Out: Preempt and Abort.
 .
@@ -140,6 +154,10 @@ PR Out: Reserve.
 .BI \--transport-id=\fITIDS\fB|\-X " TIDS"
 TransportIDs can be mentioned in several forms.
 .
+.TP
+.BI \--alloc-length=\fILEN\fB|\-l " LEN"
+PR In: maximum allocation length. LEN is a decimal number between 0 and 8192.
+.
 .
 .\" ----------------------------------------------------------------------------
 .SH EXAMPLE
@@ -164,7 +182,8 @@ Read the reservation status of the /dev/mapper/mpath9 device:
 .\" ----------------------------------------------------------------------------
 .
 .BR multipath (8),
-.BR multipathd (8).
+.BR multipathd (8),
+.BR sg_persist (8).
 .
 .
 .\" ----------------------------------------------------------------------------
index cad34bfb1c88efc8afb25c079e354e6ee0cd86d3..c85314e34d4675ce62e72437726f5c8dca8fa861 100644 (file)
@@ -3,8 +3,8 @@
 #
 include ../Makefile.inc
 
-CFLAGS += -I$(multipathdir) -I$(mpathcmddir)
-
+CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir)
+LDFLAGS += $(BIN_LDFLAGS)
 LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev \
           -L$(mpathcmddir) -lmpathcmd
 
index 4174d43d348b78b1f6f57ed697fa8e5f5f678316..dede017e9202f4013385d8dfe22ac7cc36ec4c61 100644 (file)
@@ -634,12 +634,6 @@ main (int argc, char *argv[])
                exit(1);
        }
 
-       dm_init(conf->verbosity);
-       if (dm_prereq())
-               exit(1);
-       dm_drv_version(conf->version, TGT_MPATH);
-       dm_udev_set_sync_support(1);
-
        if (optind < argc) {
                dev = MALLOC(FILE_NAME_SIZE);
 
@@ -670,6 +664,8 @@ main (int argc, char *argv[])
                                conf->max_fds, strerror(errno));
        }
 
+       libmp_udev_set_sync_support(1);
+
        if (init_checkers(conf->multipath_dir)) {
                condlog(0, "failed to initialize checkers");
                goto out;
index 5939688653bb5247ace7c4d5a92589195f6451c2..d9ac279fc6aca26c7b43ef853d55e4e96c9dd6f5 100644 (file)
@@ -7,7 +7,7 @@
 .\"
 .\" ----------------------------------------------------------------------------
 .
-.TH MULTIPATH.CONF 5 2016-11-27 "Linux"
+.TH MULTIPATH.CONF 5 2017-05-11 "Linux"
 .
 .
 .\" ----------------------------------------------------------------------------
@@ -232,6 +232,8 @@ The udev attribute providing a unique path identifier.
 The default is: for SCSI devices \fBID_SERIAL\fR
 .TP
 The default is: for DASD devices \fBID_UID\fR
+.TP
+The default is: for NVME devices \fBID_WWN\fR
 .RE
 .
 .
@@ -256,7 +258,7 @@ Return a constant priority of \fI1\fR.
 .I sysfs
 Use the sysfs attributes \fIaccess_state\fR and \fIpreferred_path\fR to
 generate the path priority. This prioritizer accepts the optional prio_arg
-\fIexclusive_pref_bit\fR
+\fIexclusive_pref_bit\fR.
 .TP
 .I emc
 (Hardware-dependent)
@@ -293,15 +295,24 @@ Generate a random priority between 1 and 10.
 Generate the path priority based on the regular expression and the
 priority provided as argument. Requires prio_args keyword.
 .TP
+.I path_latency
+Generate the path priority based on a latency algorithm.
+Requires prio_args keyword.
+.TP
 .I datacore
-.\" XXX
-???. Requires prio_args keyword.
+(Hardware-dependent)
+Generate the path priority for some Datacore storage arrays. Requires prio_args
+keyword.
 .TP
 .I iet
-.\" XXX
-???. Requires prio_args keyword.
-.TP
-The default is: \fBconst\fR
+(iSCSI only)
+Generate path priority for iSCSI targets based on IP address. Requires
+prio_args keyword.
+.PP
+The default depends on the \fBdetect_prio\fR setting: If \fBdetect_prio\fR is
+\fByes\fR (default), the default priority algorithm is \fBsysfs\fR (except for
+NetAPP E-Series, where it is \fBalua\fR). If \fBdetect_prio\fR is
+\fBno\fR, the default priority algorithm is \fBconst\fR.
 .RE
 .
 .
@@ -333,6 +344,22 @@ these values can be looked up through sysfs or by running \fImultipathd show pat
 "%N:%R:%n:%r"\fR. For example: 0x200100e08ba0aea0:0x210100e08ba0aea0:.*:.* , .*:.*:iqn.2009-10.com.redhat.msp.lab.ask-06:.*
 .RE
 .TP 12
+.I path_latency
+Needs a value of the form
+\fI"<io_num>|<base_num>"\fR
+.RS
+.TP 8
+.I io_num
+The number of read IOs sent to the current path continuously, used to calculate the average path latency.
+Valid Values: Integer, [2, 200].
+.TP
+.I base_num
+The base number value of logarithmic scale, used to partition different priority ranks. Valid Values: Integer,
+[2, 10]. And Max average latency value is 100s, min average latency value is 1us.
+For example: If base_num=10, the paths will be grouped in priority groups with path latency <=1us, (1us, 10us],
+(10us, 100us], (100us, 1ms], (1ms, 10ms], (10ms, 100ms], (100ms, 1s], (1s, 10s], (10s, 100s], >100s.
+.RE
+.TP 12
 .I alua
 If \fIexclusive_pref_bit\fR is set, paths with the \fIpreferred path\fR bit
 set will always be in their own path group.
@@ -342,12 +369,12 @@ If \fIexclusive_pref_bit\fR is set, paths with the \fIpreferred path\fR bit
 set will always be in their own path group.
 .TP
 .I datacore
-.\" XXX
-\fIpreferredsds\fR ???.
+\fIpreferredsds\fR (required) denotes the preferred "SDS name" for datacore
+arrays. \fItimeout\fR (optional) is the timeout for the INQUIRY, in ms.
 .TP
 .I iet
-.\" XXX
-\fIpreferredip\fR ???.
+\fIpreferredip=...\fR (required) denotes the preferred IP address (in dotted decimal
+notation) for iSCSI targets.
 .TP
 The default is: \fB<unset>\fR
 .RE
@@ -362,27 +389,28 @@ Possible values for the feature list are:
 .TP 12
 .\" XXX
 .I queue_if_no_path
-(Superseded by \fIno_path_retry\fR) (Since ??? kernel) Queue I/O if no path is active.
-Identical to the \fIno_path_retry\fR with \fIqueue\fR value. See KNOWN ISSUES.
-.TP
-.I no_partitions
-Disable automatic partitions generation via kpartx.
+(Deprecated, superseded by \fIno_path_retry\fR) Queue I/O if no path is active.
+Identical to the \fIno_path_retry\fR with \fIqueue\fR value. If both this
+feature and \fIno_path_retry\fR are set, the latter value takes
+precedence. See KNOWN ISSUES.
 .TP
 .\" XXX
 .I pg_init_retries <times>
-(Since ??? kernel) Number of times to retry pg_init, it must be between 1 and 50.
+(Since kernel 2.6.24) Number of times to retry pg_init, it must be between 1 and 50.
 .TP
 .\" XXX
 .I pg_init_delay_msecs <msecs>
-(Since ??? kernel) Number of msecs before pg_init retry, it must be between 0 and 60000.
+(Since kernel 2.6.38) Number of msecs before pg_init retry, it must be between 0 and 60000.
 .TP
 .\" XXX
 .I queue_mode <mode>
-(Since ??? kernel) Select the the queue_mode per multipath device.
-Where <mode> can be \fIbio\fR, \fIrq\fR or \fImq\fR. Which corresponds to
-bio-based, request_fn rq-based, and blk-mq rq-based respectively.
-.TP
-The default is: \fB0\fR
+(Since kernel 4.8) Select the the queueing mode per multipath device.
+<mode> can be \fIbio\fR, \fIrq\fR or \fImq\fR, which corresponds to
+bio-based, request-based, and block-multiqueue (blk-mq) request-based,
+respectively.
+
+The default depends on the kernel parameter \fBdm_mod.use_blk_mq\fR. It is
+\fImq\fR if the latter is set, and \fIrq\fR otherwise.
 .RE
 .
 .
@@ -670,15 +698,16 @@ The default is: \fB<unset>\fR
 .
 .TP
 .B retain_attached_hw_handler
-If set to
+(Obsolete for kernels >= 4.3) If set to
 .I yes
 and the SCSI layer has already attached a hardware_handler to the device,
 multipath will not force the device to use the hardware_handler specified by
 mutipath.conf. If the SCSI layer has not attached a hardware handler,
 multipath will continue to use its configured hardware handler.
 .RS
-.TP
-The default is: \fByes\fR
+.PP
+The default is: \fByes\fR. Linux kernel 4.3 or newer always behaves as if
+\fB"retain_attached_hw_handler yes"\fR was set.
 .RE
 .
 .
@@ -1154,8 +1183,14 @@ Active/Standby mode exclusively.
 .I 1 alua
 (Hardware-dependent)
 Hardware handler for SCSI-3 ALUA compatible arrays.
-.TP
+.PP
 The default is: \fB<unset>\fR
+.PP
+\fBImportant Note:\fR Linux kernels 4.3 and newer automatically attach a device
+handler to known devices (which includes all devices supporting SCSI-3 ALUA)
+and disallow changing the handler
+afterwards. Setting \fBhardware_handler\fR for such devices on these kernels
+has no effect.
 .RE
 .
 .
index d57f6d5a16e436ba91012e99e04efde64658fd80..d5782a18316deadfdcd75cae9122f7566a693913 100644 (file)
@@ -6,9 +6,9 @@ include ../Makefile.inc
 #CFLAGS += -DLCKDBG
 #CFLAGS += -D_DEBUG_
 #CFLAGS += -DLOGDBG
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) \
-         -I$(thirdpartydir)
-
+CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) \
+         -I$(mpathcmddir) -I$(thirdpartydir)
+LDFLAGS += $(BIN_LDFLAGS)
 LIBDEPS += -ludev -ldl -L$(multipathdir) -lmultipath -L$(mpathpersistdir) \
           -lmpathpersist -L$(mpathcmddir) -lmpathcmd -lurcu -lpthread \
           -ldevmapper -lreadline
index efc12ddc5d84187e6452b00a3e26d8b76008ef60..b4a95e37705afdce0ad5b8ca30a7802d9c203d76 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * Copyright (c) 2005 Christophe Varoqui
  */
+
+#define _GNU_SOURCE
+
 #include "checkers.h"
 #include "memory.h"
 #include "vector.h"
@@ -162,10 +165,12 @@ show_maps_json (char ** r, int * len, struct vectors * vecs)
        struct multipath * mpp;
        char * c;
        char * reply;
-       unsigned int maxlen = INITIAL_REPLY_LEN *
-                       PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec);
+       unsigned int maxlen = INITIAL_REPLY_LEN;
        int again = 1;
 
+       if (VECTOR_SIZE(vecs->mpvec) > 0)
+               maxlen *= PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec);
+
        vector_foreach_slot(vecs->mpvec, mpp, i) {
                if (update_multipath(vecs, mpp->alias, 0)) {
                        return 1;
@@ -746,7 +751,7 @@ cli_add_map (void * v, char ** reply, int * len, void * data)
        char * param = get_keyparam(v, MAP);
        int major, minor;
        char dev_path[PATH_SIZE];
-       char *alias, *refwwid;
+       char *refwwid, *alias = NULL;
        int rc, count = 0;
        struct config *conf;
 
@@ -763,14 +768,12 @@ cli_add_map (void * v, char ** reply, int * len, void * data)
        }
        put_multipath_config(conf);
        do {
-               minor = dm_get_minor(param);
-               if (minor < 0)
+               if (dm_get_major_minor(param, &major, &minor) < 0)
                        condlog(2, "%s: not a device mapper table", param);
-               major = dm_get_major(param);
-               if (major < 0)
-                       condlog(2, "%s: not a device mapper table", param);
-               sprintf(dev_path, "dm-%d", minor);
-               alias = dm_mapname(major, minor);
+               else {
+                       sprintf(dev_path, "dm-%d", minor);
+                       alias = dm_mapname(major, minor);
+               }
                /*if there is no mapname found, we first create the device*/
                if (!alias && !count) {
                        condlog(2, "%s: mapname not found for %d:%d",
@@ -804,23 +807,15 @@ cli_del_map (void * v, char ** reply, int * len, void * data)
        struct vectors * vecs = (struct vectors *)data;
        char * param = get_keyparam(v, MAP);
        int major, minor;
-       char dev_path[PATH_SIZE];
        char *alias;
        int rc;
 
        param = convert_dev(param, 0);
        condlog(2, "%s: remove map (operator)", param);
-       minor = dm_get_minor(param);
-       if (minor < 0) {
+       if (dm_get_major_minor(param, &major, &minor) < 0) {
                condlog(2, "%s: not a device mapper table", param);
                return 1;
        }
-       major = dm_get_major(param);
-       if (major < 0) {
-               condlog(2, "%s: not a device mapper table", param);
-               return 1;
-       }
-       sprintf(dev_path,"dm-%d", minor);
        alias = dm_mapname(major, minor);
        if (!alias) {
                condlog(2, "%s: mapname not found for %d:%d",
@@ -870,6 +865,7 @@ int resize_map(struct multipath *mpp, unsigned long long size,
        update_mpp_paths(mpp, vecs->pathvec);
        setup_map(mpp, params, PARAMS_SIZE);
        mpp->action = ACT_RESIZE;
+       mpp->force_udev_reload = 1;
        if (domap(mpp, params, 1) <= 0) {
                condlog(0, "%s: failed to resize map : %s", mpp->alias,
                        strerror(errno));
@@ -1341,14 +1337,9 @@ cli_getprstatus (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
 
-       *reply =(char *)malloc(2);
-       *len = 2;
-       memset(*reply,0,2);
-
-
-       sprintf(*reply,"%d",mpp->prflag);
-       (*reply)[1]='\0';
-
+       *len = asprintf(reply, "%d", mpp->prflag);
+       if (*len < 0)
+               return 1;
 
        condlog(3, "%s: reply = %s", param, *reply);
 
index b167cb4c2031159150a8f764a79f4b333109017c..4be2c5796b9430836aebae940a839d66b3868aa4 100644 (file)
@@ -104,8 +104,6 @@ struct mpath_event_param
        struct multipath *mpp;
 };
 
-unsigned int mpath_mx_alloc_len;
-
 int logsink;
 int verbosity;
 int bindings_read_only;
@@ -2410,8 +2408,6 @@ child (void * param)
                conf->ignore_new_devs = ignore_new_devs;
        uxsock_timeout = conf->uxsock_timeout;
        rcu_assign_pointer(multipath_conf, conf);
-       dm_init(conf->verbosity);
-       dm_drv_version(conf->version, TGT_MPATH);
        if (init_checkers(conf->multipath_dir)) {
                condlog(0, "failed to initialize checkers");
                goto failed;
@@ -2460,7 +2456,6 @@ child (void * param)
        setscheduler();
        set_oom_adj();
 
-       dm_udev_set_sync_support(0);
 #ifdef USE_SYSTEMD
        envp = getenv("WATCHDOG_USEC");
        if (envp && sscanf(envp, "%lu", &checkint) == 1) {
@@ -2702,6 +2697,7 @@ main (int argc, char *argv[])
        pthread_cond_init_mono(&config_cond);
 
        udev = udev_new();
+       libmp_udev_set_sync_support(0);
 
        while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {
                switch(arg) {
index 4c765af68b7339c2d7118973e03a78cf9ed947da..2615728522fff1edb3a9dcae7b438f218080f289 100644 (file)
@@ -121,8 +121,7 @@ Show the current multipath topology. Same as '\fImultipath \-ll\fR'.
 .TP
 .B list|show map|multipath $map topology
 Show topology of a single multipath device specified by $map, for example
-36005076303ffc56200000000000010aa. This map could be obtained from
-'\fIlist maps\fR'.
+36005076303ffc56200000000000010aa. This map could be obtained from '\fIlist maps\fR'.
 .
 .TP
 .B list|show wildcards
index 4615e5b4c77f9252c53f31a76fcc7c8a824138c7..d63b3dd2072b56fc97a2422a7b254eec528be658 100644 (file)
@@ -12,7 +12,7 @@
   This file is part of DRD, a Valgrind tool for verification of
   multithreaded programs.
 
-  Copyright (C) 2006-2015 Bart Van Assche <bvanassche@acm.org>.
+  Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
   All rights reserved.
 
   Redistribution and use in source and binary forms, with or without
index 689200739f05dd72142907a3a87c11fb2a74be62..5aed0dfca54cd5f119a3f5c7be6dabfe20b55cf9 100644 (file)
@@ -12,7 +12,7 @@
    This file is part of Valgrind, a dynamic binary instrumentation
    framework.
 
-   Copyright (C) 2000-2015 Julian Seward.  All rights reserved.
+   Copyright (C) 2000-2017 Julian Seward.  All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
@@ -89,7 +89,7 @@
         || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
 */
 #define __VALGRIND_MAJOR__    3
-#define __VALGRIND_MINOR__    12
+#define __VALGRIND_MINOR__    13
 
 
 #include <stdarg.h>
 #undef PLAT_s390x_linux
 #undef PLAT_mips32_linux
 #undef PLAT_mips64_linux
-#undef PLAT_tilegx_linux
 #undef PLAT_x86_solaris
 #undef PLAT_amd64_solaris
 
 #  define PLAT_mips64_linux 1
 #elif defined(__linux__) && defined(__mips__) && (__mips!=64)
 #  define PLAT_mips32_linux 1
-#elif defined(__linux__) && defined(__tilegx__)
-#  define PLAT_tilegx_linux 1
 #elif defined(__sun) && defined(__i386__)
 #  define PLAT_x86_solaris 1
 #elif defined(__sun) && defined(__x86_64__)
@@ -1048,73 +1045,6 @@ typedef
 
 #endif /* PLAT_mips64_linux */
 
-/* ------------------------ tilegx-linux --------------- */
-#if defined(PLAT_tilegx_linux)
-
-typedef
-   struct {
-      unsigned long long int nraddr; /* where's the code? */
-   }
-   OrigFn;
-/*** special instruction sequence.
-     0:02b3c7ff91234fff { moveli zero, 4660 ; moveli zero, 22136 }
-     8:0091a7ff95678fff { moveli zero, 22136 ; moveli zero, 4660 }
-****/
-
-#define __SPECIAL_INSTRUCTION_PREAMBLE                             \
-   ".quad  0x02b3c7ff91234fff\n"                                   \
-   ".quad  0x0091a7ff95678fff\n"
-
-#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                           \
-   _zzq_default, _zzq_request,                                      \
-   _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)          \
-   ({ volatile unsigned long long int _zzq_args[6];                \
-      volatile unsigned long long int _zzq_result;                 \
-      _zzq_args[0] = (unsigned long long int)(_zzq_request);       \
-      _zzq_args[1] = (unsigned long long int)(_zzq_arg1);          \
-      _zzq_args[2] = (unsigned long long int)(_zzq_arg2);          \
-      _zzq_args[3] = (unsigned long long int)(_zzq_arg3);          \
-      _zzq_args[4] = (unsigned long long int)(_zzq_arg4);          \
-      _zzq_args[5] = (unsigned long long int)(_zzq_arg5);          \
-      __asm__ volatile("move r11, %1\n\t" /*default*/              \
-                       "move r12, %2\n\t" /*ptr*/                  \
-                       __SPECIAL_INSTRUCTION_PREAMBLE              \
-                       /* r11 = client_request */                  \
-                       "or r13, r13, r13\n\t"                      \
-                       "move %0, r11\n\t"     /*result*/           \
-                       : "=r" (_zzq_result)                        \
-                       : "r" (_zzq_default), "r" (&_zzq_args[0])   \
-                       : "memory", "r11", "r12");                  \
-      _zzq_result;                                                 \
-   })
-
-#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                        \
-   {  volatile OrigFn* _zzq_orig = &(_zzq_rlval);                  \
-      volatile unsigned long long int __addr;                      \
-      __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE              \
-                       /* r11 = guest_NRADDR */                    \
-                       "or r14, r14, r14\n"                        \
-                       "move %0, r11\n"                            \
-                       : "=r" (__addr)                             \
-                       :                                           \
-                       : "memory", "r11"                           \
-                       );                                          \
-      _zzq_orig->nraddr = __addr;                                  \
-   }
-
-#define VALGRIND_CALL_NOREDIR_R12                                  \
-   __SPECIAL_INSTRUCTION_PREAMBLE                                  \
-   "or r15, r15, r15\n\t"
-
-#define VALGRIND_VEX_INJECT_IR()                                   \
-   do {                                                            \
-      __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE              \
-                       "or r11, r11, r11\n\t"                      \
-                       );                                          \
-   } while (0)
-
-#endif /* PLAT_tilegx_linux */
-
 /* Insert assembly code for other platforms here... */
 
 #endif /* NVALGRIND */
@@ -2708,7 +2638,7 @@ typedef
 #define __CALLER_SAVED_REGS                                       \
    "lr", "ctr", "xer",                                            \
    "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
-   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",         \
    "r11", "r12", "r13"
 
 /* Macros to save and align the stack before making a function
@@ -3264,7 +3194,7 @@ typedef
 #define __CALLER_SAVED_REGS                                       \
    "lr", "ctr", "xer",                                            \
    "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
-   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",         \
    "r11", "r12", "r13"
 
 /* Macros to save and align the stack before making a function
@@ -6165,461 +6095,6 @@ typedef
 
 #endif /* PLAT_mips64_linux */
 
-/* ------------------------ tilegx-linux ------------------------- */
-
-#if defined(PLAT_tilegx_linux)
-
-/* These regs are trashed by the hidden call. */
-#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3", "r4", "r5", \
-    "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14",  \
-    "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22",     \
-    "r23", "r24", "r25", "r26", "r27", "r28", "r29", "lr"
-
-/* These CALL_FN_ macros assume that on tilegx-linux, sizeof(unsigned
-   long) == 8. */
-
-#define CALL_FN_W_v(lval, orig)                          \
-   do {                                                  \
-      volatile OrigFn        _orig = (orig);             \
-      volatile unsigned long _argvec[1];                 \
-      volatile unsigned long _res;                       \
-      _argvec[0] = (unsigned long)_orig.nraddr;          \
-      __asm__ volatile(                                  \
-         "addi sp, sp, -8 \n\t"                          \
-         "st_add sp, lr, -8 \n\t"                        \
-         "ld r12, %1 \n\t"  /* target->r11 */            \
-         VALGRIND_CALL_NOREDIR_R12                       \
-         "addi   sp, sp, 8\n\t"                          \
-         "ld_add lr, sp, 8 \n\t"                         \
-         "move  %0, r0 \n"                               \
-         : /*out*/   "=r" (_res)                         \
-         : /*in*/    "r" (&_argvec[0])                   \
-         : /*trash*/  "memory", __CALLER_SAVED_REGS);    \
-                                                         \
-      lval = (__typeof__(lval)) _res;                    \
-   } while (0)
-
-#define CALL_FN_W_W(lval, orig, arg1)                   \
-   do {                                                 \
-      volatile OrigFn        _orig = (orig);            \
-      volatile unsigned long _argvec[2];                \
-      volatile unsigned long _res;                      \
-      _argvec[0] = (unsigned long)_orig.nraddr;         \
-      _argvec[1] = (unsigned long)(arg1);               \
-      __asm__ volatile(                                 \
-         "addi sp, sp, -8 \n\t"                         \
-         "st_add sp, lr, -8 \n\t"                       \
-         "move r29, %1 \n\t"                            \
-         "ld_add r12, r29, 8 \n\t"  /* target->r11 */   \
-         "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */       \
-         VALGRIND_CALL_NOREDIR_R12                      \
-         "addi   sp, sp, 8\n\t"                         \
-         "ld_add lr, sp, 8 \n\t"                        \
-         "move  %0, r0\n"                               \
-         : /*out*/   "=r" (_res)                        \
-         : /*in*/    "r" (&_argvec[0])                  \
-         : /*trash*/  "memory", __CALLER_SAVED_REGS);   \
-      lval = (__typeof__(lval)) _res;                   \
-   } while (0)
-
-#define CALL_FN_W_WW(lval, orig, arg1,arg2)             \
-   do {                                                 \
-      volatile OrigFn        _orig = (orig);            \
-      volatile unsigned long _argvec[3];                \
-      volatile unsigned long _res;                      \
-      _argvec[0] = (unsigned long)_orig.nraddr;         \
-      _argvec[1] = (unsigned long)(arg1);               \
-      _argvec[2] = (unsigned long)(arg2);               \
-      __asm__ volatile(                                 \
-         "addi sp, sp, -8 \n\t"                         \
-         "st_add sp, lr, -8 \n\t"                       \
-         "move r29, %1 \n\t"                            \
-         "ld_add r12, r29, 8 \n\t"  /* target->r11 */   \
-         "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */       \
-         "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */       \
-         VALGRIND_CALL_NOREDIR_R12                      \
-         "addi   sp, sp, 8\n\t"                         \
-         "ld_add lr, sp, 8 \n\t"                        \
-         "move  %0, r0\n"                               \
-         : /*out*/   "=r" (_res)                        \
-         : /*in*/    "r" (&_argvec[0])                  \
-         : /*trash*/  "memory", __CALLER_SAVED_REGS);   \
-      lval = (__typeof__(lval)) _res;                   \
-   } while (0)
-
-#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)       \
-   do {                                                 \
-     volatile OrigFn        _orig = (orig);             \
-     volatile unsigned long _argvec[4];                 \
-     volatile unsigned long _res;                       \
-     _argvec[0] = (unsigned long)_orig.nraddr;          \
-     _argvec[1] = (unsigned long)(arg1);                \
-     _argvec[2] = (unsigned long)(arg2);                \
-     _argvec[3] = (unsigned long)(arg3);                \
-     __asm__ volatile(                                  \
-        "addi sp, sp, -8 \n\t"                          \
-        "st_add sp, lr, -8 \n\t"                        \
-        "move r29, %1 \n\t"                             \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */    \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */        \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */        \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */        \
-        VALGRIND_CALL_NOREDIR_R12                       \
-        "addi   sp, sp, 8 \n\t"                         \
-        "ld_add lr, sp, 8 \n\t"                         \
-        "move  %0, r0\n"                                \
-        : /*out*/   "=r" (_res)                         \
-        : /*in*/    "r" (&_argvec[0])                   \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);    \
-     lval = (__typeof__(lval)) _res;                    \
-   } while (0)
-
-#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
-   do {                                                 \
-      volatile OrigFn        _orig = (orig);            \
-      volatile unsigned long _argvec[5];                \
-      volatile unsigned long _res;                      \
-      _argvec[0] = (unsigned long)_orig.nraddr;         \
-      _argvec[1] = (unsigned long)(arg1);               \
-      _argvec[2] = (unsigned long)(arg2);               \
-      _argvec[3] = (unsigned long)(arg3);               \
-      _argvec[4] = (unsigned long)(arg4);               \
-      __asm__ volatile(                                 \
-         "addi sp, sp, -8 \n\t"                         \
-         "st_add sp, lr, -8 \n\t"                       \
-         "move r29, %1 \n\t"                            \
-         "ld_add r12, r29, 8 \n\t"  /* target->r11 */   \
-         "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */       \
-         "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */       \
-         "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */       \
-         "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */       \
-         VALGRIND_CALL_NOREDIR_R12                      \
-         "addi   sp, sp, 8\n\t"                         \
-         "ld_add lr, sp, 8 \n\t"                        \
-         "move  %0, r0\n"                               \
-         : /*out*/   "=r" (_res)                        \
-         : /*in*/    "r" (&_argvec[0])                  \
-         : /*trash*/  "memory", __CALLER_SAVED_REGS);   \
-      lval = (__typeof__(lval)) _res;                   \
-   } while (0)
-
-#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)      \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[6];                        \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      __asm__ volatile(                                         \
-         "addi sp, sp, -8 \n\t"                                 \
-         "st_add sp, lr, -8 \n\t"                               \
-         "move r29, %1 \n\t"                                    \
-         "ld_add r12, r29, 8 \n\t"  /* target->r11 */           \
-         "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */               \
-         "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */               \
-         "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */               \
-         "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */               \
-         "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */               \
-         VALGRIND_CALL_NOREDIR_R12                              \
-         "addi   sp, sp, 8\n\t"                                 \
-         "ld_add lr, sp, 8 \n\t"                                \
-         "move  %0, r0\n"                                       \
-         : /*out*/   "=r" (_res)                                \
-         : /*in*/    "r" (&_argvec[0])                          \
-         : /*trash*/  "memory", __CALLER_SAVED_REGS);           \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[7];                        \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      _argvec[6] = (unsigned long)(arg6);                       \
-      __asm__ volatile(                                         \
-        "addi sp, sp, -8 \n\t"                                  \
-        "st_add sp, lr, -8 \n\t"                                \
-        "move r29, %1 \n\t"                                     \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */            \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                \
-        VALGRIND_CALL_NOREDIR_R12                               \
-        "addi   sp, sp, 8\n\t"                                  \
-        "ld_add lr, sp, 8 \n\t"                                 \
-        "move  %0, r0\n"                                        \
-        : /*out*/   "=r" (_res)                                 \
-        : /*in*/    "r" (&_argvec[0])                           \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);            \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-
-#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
-                     arg7)                                      \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[8];                        \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      _argvec[6] = (unsigned long)(arg6);                       \
-      _argvec[7] = (unsigned long)(arg7);                       \
-      __asm__ volatile(                                         \
-        "addi sp, sp, -8 \n\t"                                  \
-        "st_add sp, lr, -8 \n\t"                                \
-        "move r29, %1 \n\t"                                     \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */            \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                \
-        "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */                \
-        VALGRIND_CALL_NOREDIR_R12                               \
-        "addi   sp, sp, 8\n\t"                                  \
-        "ld_add lr, sp, 8 \n\t"                                 \
-        "move  %0, r0\n"                                        \
-        : /*out*/   "=r" (_res)                                 \
-        : /*in*/    "r" (&_argvec[0])                           \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);            \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-
-#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
-                     arg7,arg8)                                 \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[9];                        \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      _argvec[6] = (unsigned long)(arg6);                       \
-      _argvec[7] = (unsigned long)(arg7);                       \
-      _argvec[8] = (unsigned long)(arg8);                       \
-      __asm__ volatile(                                         \
-        "addi sp, sp, -8 \n\t"                                  \
-        "st_add sp, lr, -8 \n\t"                                \
-        "move r29, %1 \n\t"                                     \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */            \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                \
-        "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */                \
-        "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */                \
-        VALGRIND_CALL_NOREDIR_R12                               \
-        "addi   sp, sp, 8\n\t"                                  \
-        "ld_add lr, sp, 8 \n\t"                                 \
-        "move  %0, r0\n"                                        \
-        : /*out*/   "=r" (_res)                                 \
-        : /*in*/    "r" (&_argvec[0])                           \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);            \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-
-#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
-                     arg7,arg8,arg9)                            \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[10];                       \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      _argvec[6] = (unsigned long)(arg6);                       \
-      _argvec[7] = (unsigned long)(arg7);                       \
-      _argvec[8] = (unsigned long)(arg8);                       \
-      _argvec[9] = (unsigned long)(arg9);                       \
-      __asm__ volatile(                                         \
-        "addi sp, sp, -8 \n\t"                                  \
-        "st_add sp, lr, -8 \n\t"                                \
-        "move r29, %1 \n\t"                                     \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */            \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                \
-        "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */                \
-        "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */                \
-        "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */                \
-        VALGRIND_CALL_NOREDIR_R12                               \
-        "addi   sp, sp, 8\n\t"                                  \
-        "ld_add lr, sp, 8 \n\t"                                 \
-        "move  %0, r0\n"                                        \
-        : /*out*/   "=r" (_res)                                 \
-        : /*in*/    "r" (&_argvec[0])                           \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);            \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-
-#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,        \
-                      arg7,arg8,arg9,arg10)                             \
-   do {                                                                 \
-      volatile OrigFn        _orig = (orig);                            \
-      volatile unsigned long _argvec[11];                               \
-      volatile unsigned long _res;                                      \
-      _argvec[0] = (unsigned long)_orig.nraddr;                         \
-      _argvec[1] = (unsigned long)(arg1);                               \
-      _argvec[2] = (unsigned long)(arg2);                               \
-      _argvec[3] = (unsigned long)(arg3);                               \
-      _argvec[4] = (unsigned long)(arg4);                               \
-      _argvec[5] = (unsigned long)(arg5);                               \
-      _argvec[6] = (unsigned long)(arg6);                               \
-      _argvec[7] = (unsigned long)(arg7);                               \
-      _argvec[8] = (unsigned long)(arg8);                               \
-      _argvec[9] = (unsigned long)(arg9);                               \
-      _argvec[10] = (unsigned long)(arg10);                             \
-      __asm__ volatile(                                                 \
-        "addi sp, sp, -8 \n\t"                                          \
-        "st_add sp, lr, -8 \n\t"                                        \
-        "move r29, %1 \n\t"                                             \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */                    \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                        \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                        \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                        \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                        \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                        \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                        \
-        "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */                        \
-        "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */                        \
-        "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */                        \
-        "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */                       \
-        VALGRIND_CALL_NOREDIR_R12                                       \
-        "addi   sp, sp, 8\n\t"                                          \
-        "ld_add lr, sp, 8 \n\t"                                         \
-        "move  %0, r0\n"                                                \
-        : /*out*/   "=r" (_res)                                         \
-        : /*in*/    "r" (&_argvec[0])                                   \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);                    \
-      lval = (__typeof__(lval)) _res;                                   \
-   } while (0)
-
-#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,     \
-                      arg6,arg7,arg8,arg9,arg10,                \
-                      arg11)                                    \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[12];                       \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      _argvec[6] = (unsigned long)(arg6);                       \
-      _argvec[7] = (unsigned long)(arg7);                       \
-      _argvec[8] = (unsigned long)(arg8);                       \
-      _argvec[9] = (unsigned long)(arg9);                       \
-      _argvec[10] = (unsigned long)(arg10);                     \
-      _argvec[11] = (unsigned long)(arg11);                     \
-      __asm__ volatile(                                         \
-        "addi sp, sp, -8 \n\t"                                  \
-        "st_add sp, lr, -8 \n\t"                                \
-        "move r29, %1 \n\t"                                     \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */            \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                \
-        "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */                \
-        "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */                \
-        "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */                \
-        "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */               \
-        "ld     r10, r29 \n\t"                                  \
-        "st_add sp, r10, -16 \n\t"                              \
-        VALGRIND_CALL_NOREDIR_R12                               \
-        "addi   sp, sp, 24 \n\t"                                \
-        "ld_add lr, sp, 8 \n\t"                                 \
-        "move  %0, r0\n"                                        \
-        : /*out*/   "=r" (_res)                                 \
-        : /*in*/    "r" (&_argvec[0])                           \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);            \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-
-#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,     \
-                      arg6,arg7,arg8,arg9,arg10,                \
-                      arg11,arg12)                              \
-   do {                                                         \
-      volatile OrigFn        _orig = (orig);                    \
-      volatile unsigned long _argvec[13];                       \
-      volatile unsigned long _res;                              \
-      _argvec[0] = (unsigned long)_orig.nraddr;                 \
-      _argvec[1] = (unsigned long)(arg1);                       \
-      _argvec[2] = (unsigned long)(arg2);                       \
-      _argvec[3] = (unsigned long)(arg3);                       \
-      _argvec[4] = (unsigned long)(arg4);                       \
-      _argvec[5] = (unsigned long)(arg5);                       \
-      _argvec[6] = (unsigned long)(arg6);                       \
-      _argvec[7] = (unsigned long)(arg7);                       \
-      _argvec[8] = (unsigned long)(arg8);                       \
-      _argvec[9] = (unsigned long)(arg9);                       \
-      _argvec[10] = (unsigned long)(arg10);                     \
-      _argvec[11] = (unsigned long)(arg11);                     \
-      _argvec[12] = (unsigned long)(arg12);                     \
-      __asm__ volatile(                                         \
-        "addi sp, sp, -8 \n\t"                                  \
-        "st_add sp, lr, -8 \n\t"                                \
-        "move r29, %1 \n\t"                                     \
-        "ld_add r12, r29, 8 \n\t"  /* target->r11 */            \
-        "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */                \
-        "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */                \
-        "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */                \
-        "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */                \
-        "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */                \
-        "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */                \
-        "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */                \
-        "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */                \
-        "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */                \
-        "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */               \
-        "addi r28, sp, -8 \n\t"                                 \
-        "addi sp,  sp, -24 \n\t"                                \
-        "ld_add r10, r29, 8 \n\t"                               \
-        "ld     r11, r29 \n\t"                                  \
-        "st_add r28, r10, 8 \n\t"                               \
-        "st     r28, r11 \n\t"                                  \
-        VALGRIND_CALL_NOREDIR_R12                               \
-        "addi   sp, sp, 32 \n\t"                                \
-        "ld_add lr, sp, 8 \n\t"                                 \
-        "move  %0, r0\n"                                        \
-        : /*out*/   "=r" (_res)                                 \
-        : /*in*/    "r" (&_argvec[0])                           \
-        : /*trash*/  "memory", __CALLER_SAVED_REGS);            \
-      lval = (__typeof__(lval)) _res;                           \
-   } while (0)
-#endif  /* PLAT_tilegx_linux */
-
 /* ------------------------------------------------------------------ */
 /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS.               */
 /*                                                                    */
@@ -6642,8 +6117,9 @@ typedef
 
 /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
    This enum comprises an ABI exported by Valgrind to programs
-   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
-   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+   which use client requests.  DO NOT CHANGE THE NUMERIC VALUES OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end of the most
+   relevant group. */
 typedef
    enum { VG_USERREQ__RUNNING_ON_VALGRIND  = 0x1001,
           VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
@@ -6713,8 +6189,13 @@ typedef
              Other values are not allowed. */
           VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801,
 
+          /* Some requests used for Valgrind internal, such as
+             self-test or self-hosting. */
           /* Initialise IR injection */
-          VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901
+          VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901,
+          /* Used by Inner Valgrind to inform Outer Valgrind where to
+             find the list of inner guest threads */
+          VG_USERREQ__INNER_THREADS    = 0x1902
    } Vg_ClientRequest;
 
 #if !defined(__GNUC__)
@@ -6740,6 +6221,10 @@ typedef
     VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS,  \
                                     _qzz_addr, _qzz_len, 0, 0, 0)
 
+#define VALGRIND_INNER_THREADS(_qzz_addr)                               \
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS,           \
+                                   _qzz_addr, 0, 0, 0, 0)
+
 
 /* These requests are for getting Valgrind itself to print something.
    Possibly with a backtrace.  This is a really ugly hack.  The return value
@@ -6759,7 +6244,7 @@ __inline
 VALGRIND_PRINTF(const char *format, ...)
 {
 #if defined(NVALGRIND)
-   if (format) *(volatile const char *)format;   /* avoid compiler warning */
+   (void)format;
    return 0;
 #else /* NVALGRIND */
 #if defined(_MSC_VER) || defined(__MINGW64__)
@@ -6798,7 +6283,7 @@ __inline
 VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
 {
 #if defined(NVALGRIND)
-   if (format) *(volatile const char *)format;   /* avoid compiler warning */
+   (void)format;
    return 0;
 #else /* NVALGRIND */
 #if defined(_MSC_VER) || defined(__MINGW64__)
@@ -6828,7 +6313,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
 
 
 /* These requests allow control to move from the simulated CPU to the
-   real CPU, calling an arbitary function.
+   real CPU, calling an arbitrary function.
    
    Note that the current ThreadId is inserted as the first argument.
    So this call:
@@ -7153,7 +6638,6 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
 #undef PLAT_s390x_linux
 #undef PLAT_mips32_linux
 #undef PLAT_mips64_linux
-#undef PLAT_tilegx_linux
 #undef PLAT_x86_solaris
 #undef PLAT_amd64_solaris