summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2022-01-14 13:50:17 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2022-01-14 13:50:17 +0900
commit28bc88e5da7ffd00fcdac1d23c729d19e646f3fd (patch)
tree6168d694321e5124e62bab14e1ab14a58ad26acf
parentc0050816c16d25f8143a791d1bb74e16af67c272 (diff)
downloadmultipath-tools-28bc88e5da7ffd00fcdac1d23c729d19e646f3fd.tar.gz
multipath-tools-28bc88e5da7ffd00fcdac1d23c729d19e646f3fd.tar.bz2
multipath-tools-28bc88e5da7ffd00fcdac1d23c729d19e646f3fd.zip
Imported Upstream version 0.7.2upstream/0.7.2
-rw-r--r--Makefile27
-rw-r--r--Makefile.inc38
-rw-r--r--kpartx/Makefile3
-rw-r--r--kpartx/devmapper.c80
-rw-r--r--kpartx/devmapper.h2
-rw-r--r--kpartx/kpartx.c83
-rw-r--r--kpartx/kpartx.rules4
-rw-r--r--kpartx/lopart.c84
-rw-r--r--kpartx/lopart.h1
-rw-r--r--kpartx/sysmacros.h9
-rwxr-xr-xkpartx/test-kpartx254
-rw-r--r--libdmmp/Makefile15
-rw-r--r--libmpathcmd/Makefile2
-rw-r--r--libmpathpersist/Makefile2
-rw-r--r--libmpathpersist/mpath_persist.c49
-rw-r--r--libmpathpersist/mpath_persist.h9
-rw-r--r--libmpathpersist/mpath_pr_ioctl.c15
-rw-r--r--libmpathpersist/mpath_updatepr.c1
-rw-r--r--libmpathpersist/mpathpr.h2
-rw-r--r--libmultipath/Makefile2
-rw-r--r--libmultipath/checkers/Makefile5
-rw-r--r--libmultipath/config.c38
-rw-r--r--libmultipath/configure.c16
-rw-r--r--libmultipath/configure.h2
-rw-r--r--libmultipath/debug.c3
-rw-r--r--libmultipath/devmapper.c337
-rw-r--r--libmultipath/devmapper.h8
-rw-r--r--libmultipath/dict.c11
-rw-r--r--libmultipath/discovery.c130
-rw-r--r--libmultipath/dmparser.c75
-rw-r--r--libmultipath/hwtable.c154
-rw-r--r--libmultipath/print.c25
-rw-r--r--libmultipath/prio.h1
-rw-r--r--libmultipath/prioritizers/Makefile6
-rw-r--r--libmultipath/prioritizers/datacore.c10
-rw-r--r--libmultipath/prioritizers/path_latency.c257
-rw-r--r--libmultipath/propsel.c95
-rw-r--r--libmultipath/propsel.h3
-rw-r--r--libmultipath/structs.c30
-rw-r--r--libmultipath/structs.h5
-rw-r--r--libmultipath/uevent.c27
-rw-r--r--libmultipath/util.c36
-rw-r--r--libmultipath/util.h2
-rw-r--r--libmultipath/version.h4
-rw-r--r--libmultipath/waiter.c2
-rw-r--r--mpathpersist/Makefile3
-rw-r--r--mpathpersist/main.c6
-rw-r--r--mpathpersist/mpathpersist.821
-rw-r--r--multipath/Makefile4
-rw-r--r--multipath/main.c8
-rw-r--r--multipath/multipath.conf.591
-rw-r--r--multipathd/Makefile6
-rw-r--r--multipathd/cli_handlers.c45
-rw-r--r--multipathd/main.c6
-rw-r--r--multipathd/multipathd.83
-rw-r--r--third-party/valgrind/drd.h2
-rw-r--r--third-party/valgrind/valgrind.h556
57 files changed, 1441 insertions, 1274 deletions
diff --git a/Makefile b/Makefile
index cfee0d0..bfb168f 100644
--- 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 \
diff --git a/Makefile.inc b/Makefile.inc
index 8361e6c..29c290a 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -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 $@ $<
diff --git a/kpartx/Makefile b/kpartx/Makefile
index 9441a2b..7b75032 100644
--- a/kpartx/Makefile
+++ b/kpartx/Makefile
@@ -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
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
index cf6650c..4ab58ce 100644
--- a/kpartx/devmapper.c
+++ b/kpartx/devmapper.c
@@ -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);
}
diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
index 9988ec0..2e28c78 100644
--- a/kpartx/devmapper.h
+++ b/kpartx/devmapper.h
@@ -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 */
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index 58e60ff..9ba78d0 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -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)
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
index 48a4d6c..64d550d 100644
--- a/kpartx/kpartx.rules
+++ b/kpartx/kpartx.rules
@@ -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"
diff --git a/kpartx/lopart.c b/kpartx/lopart.c
index 2eb3f63..02b29e8 100644
--- a/kpartx/lopart.c
+++ b/kpartx/lopart.c
@@ -21,14 +21,16 @@
#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"
@@ -37,13 +39,6 @@
#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);
diff --git a/kpartx/lopart.h b/kpartx/lopart.h
index a512353..d3bad10 100644
--- a/kpartx/lopart.h
+++ b/kpartx/lopart.h
@@ -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
index 171b33d..0000000
--- a/kpartx/sysmacros.h
+++ /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
index 0000000..7c45cd1
--- /dev/null
+++ b/kpartx/test-kpartx
@@ -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
diff --git a/libdmmp/Makefile b/libdmmp/Makefile
index 1c5329a..cdd26ed 100644
--- a/libdmmp/Makefile
+++ b/libdmmp/Makefile
@@ -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
diff --git a/libmpathcmd/Makefile b/libmpathcmd/Makefile
index 9cda94c..4f32101 100644
--- a/libmpathcmd/Makefile
+++ b/libmpathcmd/Makefile
@@ -4,6 +4,8 @@ SONAME = 0
DEVLIB = libmpathcmd.so
LIBS = $(DEVLIB).$(SONAME)
+CFLAGS += $(LIB_CFLAGS)
+
OBJS = mpath_cmd.o
all: $(LIBS)
diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile
index 857c8d8..1b4ec16 100644
--- a/libmpathpersist/Makefile
+++ b/libmpathpersist/Makefile
@@ -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
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 982c795..aab6d95 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -34,10 +34,10 @@
#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);
+ }
}
}
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
index 79de5b5..9a84bc9 100644
--- a/libmpathpersist/mpath_persist.h
+++ b/libmpathpersist/mpath_persist.h
@@ -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);
/*
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
index 31b2fe6..29df8c6 100644
--- a/libmpathpersist/mpath_pr_ioctl.c
+++ b/libmpathpersist/mpath_pr_ioctl.c
@@ -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)
{
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
index 5af2e03..b3701b2 100644
--- a/libmpathpersist/mpath_updatepr.c
+++ b/libmpathpersist/mpath_updatepr.c
@@ -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)
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
index e6c2ded..99e641b 100644
--- a/libmpathpersist/mpathpr.h
+++ b/libmpathpersist/mpathpr.h
@@ -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;
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index 1f5ec25..b3244fc 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -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
diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile
index 4970fc0..bce6b8b 100644
--- a/libmultipath/checkers/Makefile
+++ b/libmultipath/checkers/Makefile
@@ -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
diff --git a/libmultipath/config.c b/libmultipath/config.c
index bb6619b..b21a3aa 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -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
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index b29a660..74b6f52 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -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) {
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index fb078a6..fd7f581 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -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);
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
index fbe171a..f89b264 100644
--- a/libmultipath/debug.c
+++ b/libmultipath/debug.c
@@ -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);
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 5fb9d9a..3b41a48 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -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))
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index aca4454..99a554b 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -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);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 82066f6..9dc1090 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -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)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 663c8ea..3a912d7 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -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);
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 469e60d..b647c25 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -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)
{
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index c944015..9e14ec1 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -26,6 +26,55 @@
* 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,
@@ -224,34 +275,10 @@ static struct hwentry default_hw[] = {
.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
*/
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 7c2a158..95dff90 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -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);
}
diff --git a/libmultipath/prio.h b/libmultipath/prio.h
index 0193c52..c97fe39 100644
--- a/libmultipath/prio.h
+++ b/libmultipath/prio.h
@@ -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
diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile
index 36b42e4..0c71e63 100644
--- a/libmultipath/prioritizers/Makefile
+++ b/libmultipath/prioritizers/Makefile
@@ -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 $@ $^
diff --git a/libmultipath/prioritizers/datacore.c b/libmultipath/prioritizers/datacore.c
index 36465ac..59c9816 100644
--- a/libmultipath/prioritizers/datacore.c
+++ b/libmultipath/prioritizers/datacore.c
@@ -35,10 +35,6 @@
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
index 0000000..9fc2dfc
--- /dev/null
+++ b/libmultipath/prioritizers/path_latency.c
@@ -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;
+}
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 09fe728..175fbe1 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -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,
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index 58a32f3..f8e96d8 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -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);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index e225f8b..2870467 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -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 */
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 98e13e4..8ea984d 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -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];
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index 4fbd1df..eb44da5 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -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);
diff --git a/libmultipath/util.c b/libmultipath/util.c
index b90cd8b..dff2ed3 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -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;
+}
diff --git a/libmultipath/util.h b/libmultipath/util.h
index b087e32..45291be 100644
--- a/libmultipath/util.h
+++ b/libmultipath/util.h
@@ -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)
diff --git a/libmultipath/version.h b/libmultipath/version.h
index 5d45932..777d71a 100644
--- a/libmultipath/version.h
+++ b/libmultipath/version.h
@@ -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"
diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
index 995ea1a..cb9708b 100644
--- a/libmultipath/waiter.c
+++ b/libmultipath/waiter.c
@@ -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;
diff --git a/mpathpersist/Makefile b/mpathpersist/Makefile
index 47043bb..bd1c0df 100644
--- a/mpathpersist/Makefile
+++ b/mpathpersist/Makefile
@@ -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
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
index 2e0aba3..79b89e5 100644
--- a/mpathpersist/main.c
+++ b/mpathpersist/main.c
@@ -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);
diff --git a/mpathpersist/mpathpersist.8 b/mpathpersist/mpathpersist.8
index 4b15666..a8982e6 100644
--- a/mpathpersist/mpathpersist.8
+++ b/mpathpersist/mpathpersist.8
@@ -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).
.
.
.\" ----------------------------------------------------------------------------
diff --git a/multipath/Makefile b/multipath/Makefile
index cad34bf..c85314e 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -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
diff --git a/multipath/main.c b/multipath/main.c
index 4174d43..dede017 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -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;
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 5939688..d9ac279 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -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
.
.
diff --git a/multipathd/Makefile b/multipathd/Makefile
index d57f6d5..d5782a1 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -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
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index efc12dd..b4a95e3 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -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);
diff --git a/multipathd/main.c b/multipathd/main.c
index b167cb4..4be2c57 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -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) {
diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8
index 4c765af..2615728 100644
--- a/multipathd/multipathd.8
+++ b/multipathd/multipathd.8
@@ -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
diff --git a/third-party/valgrind/drd.h b/third-party/valgrind/drd.h
index 4615e5b..d63b3dd 100644
--- a/third-party/valgrind/drd.h
+++ b/third-party/valgrind/drd.h
@@ -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
diff --git a/third-party/valgrind/valgrind.h b/third-party/valgrind/valgrind.h
index 6892007..5aed0df 100644
--- a/third-party/valgrind/valgrind.h
+++ b/third-party/valgrind/valgrind.h
@@ -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>
@@ -122,7 +122,6 @@
#undef PLAT_s390x_linux
#undef PLAT_mips32_linux
#undef PLAT_mips64_linux
-#undef PLAT_tilegx_linux
#undef PLAT_x86_solaris
#undef PLAT_amd64_solaris
@@ -160,8 +159,6 @@
# 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