diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2022-01-14 13:50:17 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2022-01-14 13:50:17 +0900 |
commit | 28bc88e5da7ffd00fcdac1d23c729d19e646f3fd (patch) | |
tree | 6168d694321e5124e62bab14e1ab14a58ad26acf | |
parent | c0050816c16d25f8143a791d1bb74e16af67c272 (diff) | |
download | multipath-tools-28bc88e5da7ffd00fcdac1d23c729d19e646f3fd.tar.gz multipath-tools-28bc88e5da7ffd00fcdac1d23c729d19e646f3fd.tar.bz2 multipath-tools-28bc88e5da7ffd00fcdac1d23c729d19e646f3fd.zip |
Imported Upstream version 0.7.2upstream/0.7.2
57 files changed, 1441 insertions, 1274 deletions
@@ -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, ¶ms); - - if (!target_type) + if (dm_get_next_target(dmt, NULL, &start, &length, + &target_type, ¶ms) != 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 *)(¶m)); 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, ¶ms); - - if (!target_type) + if (dm_get_next_target(dmt, NULL, &start, &length, + &target_type, ¶ms) != 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 |