Imported Upstream version 0.8.9 upstream/0.8.9
authorJinWang An <jinwang.an@samsung.com>
Fri, 13 Jan 2023 06:40:25 +0000 (15:40 +0900)
committerJinWang An <jinwang.an@samsung.com>
Fri, 13 Jan 2023 06:40:25 +0000 (15:40 +0900)
71 files changed:
Makefile.inc
README.md
kpartx/Makefile
kpartx/crc32.c
kpartx/devmapper.c
kpartx/gpt.c
kpartx/kpartx.rules
libdmmp/Makefile
libdmmp/libdmmp.c
libmpathcmd/Makefile
libmpathcmd/mpath_cmd.h
libmpathpersist/Makefile
libmpathpersist/libmpathpersist.version
libmpathpersist/mpath_persist.c
libmpathpersist/mpath_persist.h
libmpathpersist/mpath_persist_int.c [new file with mode: 0644]
libmpathpersist/mpath_persist_int.h [new file with mode: 0644]
libmpathpersist/mpath_pr_ioctl.c
libmpathpersist/mpath_updatepr.c
libmpathpersist/mpathpr.h
libmpathvalid/Makefile
libmpathvalid/mpath_valid.h
libmultipath/Makefile
libmultipath/alias.c
libmultipath/checkers.c
libmultipath/checkers.h
libmultipath/checkers/directio.c
libmultipath/checkers/tur.c
libmultipath/configure.c
libmultipath/configure.h
libmultipath/devmapper.c
libmultipath/devmapper.h
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/discovery.h
libmultipath/dmparser.c
libmultipath/foreign.h
libmultipath/foreign/nvme.c
libmultipath/hwtable.c
libmultipath/libmultipath.version
libmultipath/print.c
libmultipath/prioritizers/Makefile
libmultipath/prioritizers/alua_spc3.h
libmultipath/prioritizers/path_latency.c
libmultipath/propsel.c
libmultipath/structs.c
libmultipath/structs.h
libmultipath/structs_vec.c
libmultipath/structs_vec.h
libmultipath/uevent.c
libmultipath/util.h
libmultipath/version.h
mpathpersist/Makefile
mpathpersist/main.c
multipath/Makefile
multipath/main.c
multipath/modules-load.conf [new file with mode: 0644]
multipath/multipath.conf.5
multipath/scsi_dh.conf [new file with mode: 0644]
multipathd/Makefile
multipathd/dmevents.c
multipathd/fpin.h [new file with mode: 0644]
multipathd/fpin_handlers.c [new file with mode: 0644]
multipathd/main.c
multipathd/main.h
multipathd/multipathd.8
multipathd/multipathd.service
multipathd/uxlsnr.c
tests/README.md
tests/hwtable.c
tests/strbuf.c

index b340f2a..d24da43 100644 (file)
@@ -3,18 +3,17 @@
 #
 
 #
-# Allow to force some libraries to be used statically. (Uncomment one of the
-# following lines or define the values when calling make.)
-#
-# WITH_LOCAL_LIBDM     = 1
-# WITH_LOCAL_LIBSYSFS  = 1
-#
 # Uncomment to disable libdmmp support
 # ENABLE_LIBDMMP = 0
 #
 # Uncomment to disable dmevents polling support
 # ENABLE_DMEVENTS_POLL = 0
 
+# List of scsi device handler modules to load on boot, e.g.
+# SCSI_DH_MODULES_PRELOAD := scsi_dh_alua scsi_dh_rdac
+SCSI_DH_MODULES_PRELOAD :=
+
+
 PKGCONFIG      ?= pkg-config
 
 ifeq ($(TOPDIR),)
@@ -52,12 +51,34 @@ ifndef SYSTEMDPATH
        SYSTEMDPATH=usr/lib
 endif
 
+ifndef DEVMAPPER_INCDIR
+       ifeq ($(shell $(PKGCONFIG) --modversion devmapper >/dev/null 2>&1 && echo 1), 1)
+               DEVMAPPER_INCDIR = $(shell $(PKGCONFIG) --variable=includedir devmapper)
+       else
+               DEVMAPPER_INCDIR = /usr/include
+       endif
+endif
+
+ifndef LIBUDEV_INCDIR
+       ifeq ($(shell $(PKGCONFIG) --modversion libudev >/dev/null 2>&1 && echo 1), 1)
+               LIBUDEV_INCDIR = $(shell $(PKGCONFIG) --variable=includedir libudev)
+       else
+               LIBUDEV_INCDIR = /usr/include
+       endif
+endif
+
+# Allow user to override default location.
+ifndef LINUX_HEADERS_INCDIR
+       LINUX_HEADERS_INCDIR = /usr/include
+endif
+
 prefix         =
 exec_prefix    = $(prefix)
 usr_prefix     = $(prefix)
 bindir         = $(exec_prefix)/sbin
 libudevdir     = $(prefix)/$(SYSTEMDPATH)/udev
 udevrulesdir   = $(libudevdir)/rules.d
+modulesloaddir  = $(prefix)/$(SYSTEMDPATH)/modules-load.d
 multipathdir   = $(TOPDIR)/libmultipath
 man8dir                = $(prefix)/usr/share/man/man8
 man5dir                = $(prefix)/usr/share/man/man5
@@ -75,7 +96,7 @@ nvmedir               = $(TOPDIR)/libmultipath/nvme
 includedir     = $(prefix)/usr/include
 pkgconfdir     = $(usrlibdir)/pkgconfig
 
-GZIP           = gzip -9 -c
+GZIP_PROG      = gzip -9 -c
 RM             = rm -f
 LN             = ln -sf
 INSTALL_PROGRAM        = install
@@ -138,6 +159,19 @@ check_file = $(shell \
        echo "$$found" \
        )
 
+# Check whether a file contains a variable with name $1 in header file $2
+check_var = $(shell \
+       if grep -Eq "(^|[[:blank:]])$1([[:blank:]]|=|$$)" "$2"; then \
+                found=1; \
+                status="yes"; \
+        else \
+                found=0; \
+                status="no"; \
+        fi; \
+        echo 1>&2 "Checking for ..  $1 in $2 ... $$status"; \
+        echo "$$found" \
+        )
+
 %.o:   %.c
        @echo building $@ because of $?
        $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
index b15c265..1547862 100644 (file)
--- a/README.md
+++ b/README.md
@@ -52,6 +52,62 @@ To get latest devel code:
 Github page: https://github.com/opensvc/multipath-tools
 
 
+Building multipath-tools
+========================
+
+Prerequisites: development packages of for `libdevmapper`, `libreadline`,
+`libaio`, `libudev`, `libjson-c`, `liburcu`, and `libsystemd`.
+
+To build multipath-tools, type:
+
+    make
+       make DESTDIR="/my/target/dir" install
+
+To uninstall, type:
+
+    make uninstall
+
+Customizing the build
+---------------------
+
+The following variables can be passed to the `make` command line:
+
+ * `ENABLE_LIBDMMP=0`: disable building libdmmp
+ * `ENABLE_DMEVENTS_POLL=0`: disable support for the device-mapper event
+   polling API. For use with pre-5.0 kernels that don't supprt dmevent polling
+   (but even if you don't use this option, multipath-tools will work with
+   these kernels).
+ * `SCSI_DH_MODULES_PRELOAD="(list)"`: specify a space-separated list of SCSI
+   device handler kernel modules to load early during boot. Some
+   multipath-tools functionality depends on these modules being loaded
+   early. This option causes a *modules-load.d(5)* configuration file to be
+   created, thus it depends on functionality provided by *systemd*.
+   This variable only matters for `make install`.
+
+Note: The usefulness of the preload list depends on the kernel configuration.
+It's especially useful if `scsi_mod` is builtin but `scsi_dh_alua` and
+other device handler modules are built as modules. If `scsi_mod` itself is compiled
+as a module, it might make more sense to use a module softdep for the same
+purpose.
+
+See `Makefile.inc` for additional variables to customize paths and compiler
+flags.
+
+Special Makefile targets
+------------------------
+
+The following targets are intended for developers only.
+
+ * `make test` to build and run the unit tests
+ * `make valgrind-test` to run the unit tests under valgrind
+ * `make abi` to create an XML representation of the ABI of the libraries in
+   the `abi/` subdirectory
+ * `make abi-test` to compare the ABI of a different multipath-tools version,
+   which must be stored in the `reference-abi/` subdirectory. If this test
+   fails, the ABI has changed wrt the reference.
+ * `make compile-commands.json` to create input for [clangd](https://clangd.llvm.org/).
+
+
 Add storage devices
 ===================
 
index 2906a98..e9900fb 100644 (file)
@@ -8,7 +8,7 @@ LDFLAGS += $(BIN_LDFLAGS)
 
 LIBDEPS += -ldevmapper
 
-ifneq ($(call check_func,dm_task_set_cookie,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_task_set_cookie,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_COOKIE
 endif
 
@@ -21,7 +21,6 @@ all: $(EXEC)
 
 $(EXEC): $(OBJS)
        $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
-       $(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 install: $(EXEC) $(EXEC).8
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
@@ -33,11 +32,11 @@ install: $(EXEC) $(EXEC).8
        $(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules
        $(INSTALL_PROGRAM) -m 644 del-part-nodes.rules $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
-       $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(man8dir)
 
 uninstall:
        $(RM) $(DESTDIR)$(bindir)/$(EXEC)
-       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
+       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8
        $(RM) $(DESTDIR)$(libudevdir)/kpartx_id
        $(RM) $(DESTDIR)$(libudevdir)/rules.d/11-dm-parts.rules
        $(RM) $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules
@@ -45,7 +44,7 @@ uninstall:
        $(RM) $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules
 
 clean: dep_clean
-       $(RM) core *.o $(EXEC) *.gz
+       $(RM) core *.o $(EXEC)
 
 include $(wildcard $(OBJS:.o=.d))
 
index b23a083..e688f8e 100644 (file)
@@ -342,7 +342,7 @@ uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t
  * but again the multiple of the polynomial to subtract depends only on
  * the high bits, the high 8 bits in this case.
  *
- * The multile we need in that case is the low 32 bits of a 40-bit
+ * The multiple we need in that case is the low 32 bits of a 40-bit
  * value whose high 8 bits are given, and which is a multiple of the
  * generator polynomial.  This is simply the CRC-32 of the given
  * one-byte message.
index 3efd6df..49ffd31 100644 (file)
 #define MAX_PREFIX_LEN (_UUID_PREFIX_LEN + 4)
 #define PARAMS_SIZE 1024
 
+#ifdef LIBDM_API_COOKIE
+#    define __DM_API_COOKIE_UNUSED__ /* empty */
+#else
+#    define __DM_API_COOKIE_UNUSED__ __attribute__((unused))
+#endif
+
 int dm_prereq(char * str, uint32_t x, uint32_t y, uint32_t z)
 {
        int r = 1;
@@ -55,12 +61,12 @@ out:
        return r;
 }
 
-int dm_simplecmd(int task, const char *name, int no_flush, uint16_t udev_flags)
+int dm_simplecmd(int task, const char *name, int no_flush, __DM_API_COOKIE_UNUSED__ uint16_t udev_flags)
 {
        int r = 0;
+#ifdef LIBDM_API_COOKIE
        int udev_wait_flag = (task == DM_DEVICE_RESUME ||
                              task == DM_DEVICE_REMOVE);
-#ifdef LIBDM_API_COOKIE
        uint32_t cookie = 0;
 #endif
        struct dm_task *dmt;
index f7fefb7..34a910c 100644 (file)
@@ -94,7 +94,7 @@ efi_crc32(const void *buf, unsigned long len)
  *
  * Description: Returns 1 if PMBR is valid, 0 otherwise.
  * Validity depends on two things:
- *  1) MSDOS signature is in the last two bytes of the MBR
+ *  1) MS-DOS signature is in the last two bytes of the MBR
  *  2) One partition of type 0xEE is found
  */
 static int
index d7527d7..1969dee 100644 (file)
@@ -12,6 +12,9 @@ ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="kpartx_end"
 # Create dm tables for partitions on multipath devices.
 ENV{DM_UUID}!="mpath-?*", GOTO="mpath_kpartx_end"
 
+# Ignore RAID members
+ENV{ID_FS_TYPE}=="linux_raid_member|isw_raid_member|ddf_raid_member", GOTO="mpath_kpartx_end"
+
 # DM_SUBSYSTEM_UDEV_FLAG1 is the "skip_kpartx" flag.
 # For events not generated by libdevmapper, we need to fetch it from db:
 # - "change" events with DM_ACTIVATION!="1" (e.g. partition table changes)
index de61668..00fc852 100644 (file)
@@ -21,7 +21,7 @@ CFLAGS += $(LIB_CFLAGS) -fvisibility=hidden -I$(libdmmpdir) -I$(mpathcmddir) \
 LIBDEPS += $(shell $(PKGCONFIG) --libs json-c) -L$(mpathcmddir) -lmpathcmd -lpthread
 
 all: $(LIBS) doc
-.PHONY:        doc doc.gz clean install uninstall check speed_test dep_clean
+.PHONY:        doc clean install uninstall check speed_test dep_clean
 
 $(LIBS): $(OBJS)
        $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS)
@@ -31,7 +31,7 @@ $(DEVLIB): $(LIBS)
 
 abi:    $(DEVLIB:%.so=%.abi)
 
-install:       doc.gz
+install:
        mkdir -p $(DESTDIR)$(usrlibdir)
        $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(usrlibdir)/$(LIBS)
        $(INSTALL_PROGRAM) -m 644 -D \
@@ -45,7 +45,7 @@ install:      doc.gz
                $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
        perl -i -pe 's|__INCLUDEDIR__|$(includedir)|g' \
                $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
-       $(INSTALL_PROGRAM) -m 644 -t $(DESTDIR)$(man3dir) docs/man/*.3.gz
+       $(INSTALL_PROGRAM) -m 644 -t $(DESTDIR)$(man3dir) docs/man/*.3
 
 uninstall:
        $(RM) $(DESTDIR)$(usrlibdir)/$(LIBS)
@@ -58,8 +58,7 @@ uninstall:
        $(RM) $(DESTDIR)$(pkgconfdir)/$(PKGFILE)
 
 clean: dep_clean
-       $(RM) core *.a *.o *.gz *.so *.so.* *.abi $(NV_VERSION_SCRIPT)
-       $(RM) docs/man/*.gz
+       $(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT)
        $(MAKE) -C test clean
 
 include $(wildcard $(OBJS:.o=.d))
@@ -70,13 +69,8 @@ check: all
 speed_test: all
        $(MAKE) -C test speed_test
 
-doc.gz:        doc $(patsubst %,%.gz,$(wildcard docs/man/*.3))
-
 doc: docs/man/dmmp_strerror.3
 
-docs/man/%.3.gz:       docs/man/%.3
-       gzip -c $< >$@
-
 docs/man/dmmp_strerror.3:      $(HEADERS)
        TEMPFILE=$(shell mktemp); \
        cat $^ | perl docs/doc-preclean.pl >$$TEMPFILE; \
index aafd509..0025e66 100644 (file)
@@ -26,7 +26,6 @@
 #include <libudev.h>
 #include <errno.h>
 #include <libdevmapper.h>
-#include <stdbool.h>
 #include <unistd.h>
 #include <assert.h>
 #include <json.h>
@@ -189,7 +188,7 @@ int dmmp_mpath_array_get(struct dmmp_context *ctx,
        j_token = json_tokener_new();
        if (j_token == NULL) {
                rc = DMMP_ERR_BUG;
-               _error(ctx, "BUG: json_tokener_new() retuned NULL");
+               _error(ctx, "BUG: json_tokener_new() returned NULL");
                goto out;
        }
        j_obj = json_tokener_parse_ex(j_token, j_str, strlen(j_str) + 1);
index 72cab1e..0f83fe7 100644 (file)
@@ -42,7 +42,7 @@ uninstall:
        $(RM) $(DESTDIR)$(includedir)/mpath_cmd.h
 
 clean: dep_clean
-       $(RM) core *.a *.o *.so *.so.* *.gz *.abi $(NV_VERSION_SCRIPT)
+       $(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT)
 
 include $(wildcard $(OBJS:.o=.d))
 
index ccfd35f..30838b0 100644 (file)
@@ -80,7 +80,7 @@ int mpath_disconnect(int fd);
  *     mpath_recv_reply()
  *
  * RETURNS:
- *     0 on successs, and reply will either be NULL (if there was no
+ *     0 on success, and reply will either be NULL (if there was no
  *     reply data), or point to the reply string, which must be freed by
  *     the caller. -1 on failure (with errno set).
  */
index 1e6399d..9843d96 100644 (file)
@@ -10,9 +10,9 @@ LDFLAGS += -L$(multipathdir) -L$(mpathcmddir)
 
 LIBDEPS += -lmultipath -lmpathcmd -ldevmapper -lpthread -ldl
 
-OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o
+OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o mpath_persist_int.o
 
-all: $(DEVLIB) man
+all: $(DEVLIB)
 
 $(LIBS): $(OBJS) $(VERSION_SCRIPT)
        $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \
@@ -32,10 +32,6 @@ abi:    $(LIBS:%.so.$(SONAME)=%-nv.abi)
 $(DEVLIB): $(LIBS)
        $(LN) $(LIBS) $@
 
-man:
-       $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz
-       $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz
-
 install: all
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
        $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
@@ -43,19 +39,19 @@ install: all
        $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(man3dir)
        $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(includedir)
        $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
-       $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir)
-       $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir)
+       $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_in.3 $(DESTDIR)$(man3dir)
+       $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_out.3 $(DESTDIR)$(man3dir)
        $(INSTALL_PROGRAM) -m 644 mpath_persist.h $(DESTDIR)$(includedir)
 
 uninstall:
        $(RM) $(DESTDIR)$(syslibdir)/$(LIBS)
-       $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3.gz
-       $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3.gz
+       $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3
+       $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3
        $(RM) $(DESTDIR)$(includedir)/mpath_persist.h
        $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
 
 clean: dep_clean
-       $(RM) core *.a *.o *.so *.so.* *.gz *.abi $(NV_VERSION_SCRIPT)
+       $(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT)
 
 include $(wildcard $(OBJS:.o=.d))
 
index fa312f6..a8c6aae 100644 (file)
  *
  * See libmultipath.version for general policy about version numbers.
  */
-LIBMPATHPERSIST_2.0.0 {
+LIBMPATHPERSIST_2.1.0 {
 global:
-
-       __mpath_persistent_reserve_in;
-       __mpath_persistent_reserve_out;
-       dumpHex;
-       mpath_alloc_prin_response;
+       /* public API as defined in mpath_persist.h */
+       libmpathpersist_exit;
+       libmpathpersist_init;
        mpath_lib_exit;
        mpath_lib_init;
        mpath_mx_alloc_len;
+       mpath_persistent_reserve_free_vecs;
+       __mpath_persistent_reserve_in;
        mpath_persistent_reserve_in;
        mpath_persistent_reserve_init_vecs;
+       __mpath_persistent_reserve_out;
        mpath_persistent_reserve_out;
-       mpath_persistent_reserve_free_vecs;
+local: *;
+};
+
+__LIBMPATHPERSIST_INT_1.0.0 {
+       /* Internal use by multipath-tools */
+       dumpHex;
+       mpath_alloc_prin_response;
        prin_do_scsi_ioctl;
        prout_do_scsi_ioctl;
        update_map_pr;
-
-       /* added in 1.1.0 */
-       libmpathpersist_init;
-       libmpathpersist_exit;
-
-local: *;
 };
index 3097c81..6cfcdde 100644 (file)
@@ -1,39 +1,13 @@
 #include <libdevmapper.h>
-#include "defaults.h"
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include "vector.h"
-#include "checkers.h"
-#include "structs.h"
-#include "structs_vec.h"
-#include <libudev.h>
 
-#include "prio.h"
-#include <unistd.h>
-#include "devmapper.h"
-#include "debug.h"
-#include "config.h"
-#include "switchgroup.h"
-#include "discovery.h"
-#include "configure.h"
-#include "dmparser.h"
-#include <ctype.h>
-#include "propsel.h"
 #include "util.h"
-#include "unaligned.h"
+#include "vector.h"
+#include "config.h"
+#include "debug.h"
+#include "devmapper.h"
 
 #include "mpath_persist.h"
-#include "mpathpr.h"
-#include "mpath_pr_ioctl.h"
-
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#define __STDC_FORMAT_MACROS 1
+#include "mpath_persist_int.h"
 
 extern struct udev *udev;
 
@@ -97,42 +71,6 @@ int libmpathpersist_exit(void)
        return 0;
 }
 
-int
-mpath_prin_activepath (struct multipath *mpp, int rq_servact,
-       struct prin_resp * resp, int noisy)
-{
-       int i,j, ret = MPATH_PR_DMMP_ERROR;
-       struct pathgroup *pgp = NULL;
-       struct path *pp = NULL;
-
-       vector_foreach_slot (mpp->pg, pgp, j){
-               vector_foreach_slot (pgp->paths, pp, i){
-                       if (!((pp->state == PATH_UP) ||
-                             (pp->state == PATH_GHOST))){
-                               condlog(2, "%s: %s not available. Skip.",
-                                       mpp->wwid, pp->dev);
-                               condlog(3, "%s: status = %d.",
-                                       mpp->wwid, pp->state);
-                               continue;
-                       }
-
-                       condlog(3, "%s: sending pr in command to %s ",
-                               mpp->wwid, pp->dev);
-                       ret = mpath_send_prin_activepath(pp->dev, rq_servact,
-                                                        resp, noisy);
-                       switch(ret)
-                       {
-                               case MPATH_PR_SUCCESS:
-                               case MPATH_PR_SENSE_INVALID_OP:
-                                       return ret;
-                               default:
-                                       continue;
-                       }
-               }
-       }
-       return ret;
-}
-
 static vector curmp;
 static vector pathvec;
 
@@ -182,83 +120,6 @@ int mpath_persistent_reserve_init_vecs(int verbose)
        return __mpath_persistent_reserve_init_vecs(&curmp, &pathvec, verbose);
 }
 
-static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
-                        struct multipath **pmpp)
-{
-       int ret = MPATH_PR_DMMP_ERROR;
-       struct stat info;
-       int major, minor;
-       char *alias;
-       struct multipath *mpp;
-
-       if (fstat(fd, &info) != 0){
-               condlog(0, "stat error fd=%d", fd);
-               return MPATH_PR_FILE_ERROR;
-       }
-       if(!S_ISBLK(info.st_mode)){
-               condlog(3, "Failed to get major:minor. fd=%d", fd);
-               return MPATH_PR_FILE_ERROR;
-       }
-
-       major = major(info.st_rdev);
-       minor = minor(info.st_rdev);
-       condlog(4, "Device  %d:%d", major, minor);
-
-       /* get alias from major:minor*/
-       alias = dm_mapname(major, minor);
-       if (!alias){
-               condlog(0, "%d:%d failed to get device alias.", major, minor);
-               return MPATH_PR_DMMP_ERROR;
-       }
-
-       condlog(3, "alias = %s", alias);
-
-       if (dm_map_present(alias) && dm_is_mpath(alias) != 1){
-               condlog(3, "%s: not a multipath device.", alias);
-               goto out;
-       }
-
-       /* get info of all paths from the dm device     */
-       if (get_mpvec(curmp, pathvec, alias)){
-               condlog(0, "%s: failed to get device info.", alias);
-               goto out;
-       }
-
-       mpp = find_mp_by_alias(curmp, alias);
-
-       if (!mpp) {
-               condlog(0, "%s: devmap not registered.", alias);
-               goto out;
-       }
-
-       ret = MPATH_PR_SUCCESS;
-       if (pmpp)
-               *pmpp = mpp;
-       if (palias) {
-               *palias = alias;
-               alias = NULL;
-       }
-out:
-       free(alias);
-       return ret;
-}
-
-static int do_mpath_persistent_reserve_in (vector curmp, vector pathvec,
-       int fd, int rq_servact, struct prin_resp *resp, int noisy)
-{
-       struct multipath *mpp;
-       int ret;
-
-       ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp);
-       if (ret != MPATH_PR_SUCCESS)
-               return ret;
-
-       ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy);
-
-       return ret;
-}
-
-
 int __mpath_persistent_reserve_in (int fd, int rq_servact,
        struct prin_resp *resp, int noisy)
 {
@@ -266,86 +127,6 @@ int __mpath_persistent_reserve_in (int fd, int rq_servact,
                                              resp, noisy);
 }
 
-static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
-       int rq_servact, int rq_scope, unsigned int rq_type,
-       struct prout_param_descriptor *paramp, int noisy)
-{
-       struct multipath *mpp;
-       char *alias;
-       int ret;
-       uint64_t prkey;
-       struct config *conf;
-
-       ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
-       if (ret != MPATH_PR_SUCCESS)
-               return ret;
-
-       conf = get_multipath_config();
-       select_reservation_key(conf, mpp);
-       select_all_tg_pt(conf, mpp);
-       put_multipath_config(conf);
-
-       memcpy(&prkey, paramp->sa_key, 8);
-       if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
-           (rq_servact == MPATH_PROUT_REG_IGN_SA ||
-            (rq_servact == MPATH_PROUT_REG_SA &&
-             (!get_be64(mpp->reservation_key) ||
-              memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
-               memcpy(&mpp->reservation_key, paramp->sa_key, 8);
-               if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
-                                      paramp->sa_flags)) {
-                       condlog(0, "%s: failed to set prkey for multipathd.",
-                               alias);
-                       ret = MPATH_PR_DMMP_ERROR;
-                       goto out1;
-               }
-       }
-
-       if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
-           memcmp(paramp->sa_key, &mpp->reservation_key, 8) &&
-           (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) {
-               condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
-               ret = MPATH_PR_SYNTAX_ERROR;
-               goto out1;
-       }
-
-       switch(rq_servact)
-       {
-       case MPATH_PROUT_REG_SA:
-       case MPATH_PROUT_REG_IGN_SA:
-               ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
-               break;
-       case MPATH_PROUT_RES_SA :
-       case MPATH_PROUT_PREE_SA :
-       case MPATH_PROUT_PREE_AB_SA :
-       case MPATH_PROUT_CLEAR_SA:
-               ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
-               break;
-       case MPATH_PROUT_REL_SA:
-               ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
-               break;
-       default:
-               ret = MPATH_PR_OTHER;
-               goto out1;
-       }
-
-       if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
-                               (rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
-       {
-               if (prkey == 0) {
-                       update_prflag(alias, 0);
-                       update_prkey(alias, 0);
-               } else
-                       update_prflag(alias, 1);
-       } else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) {
-               update_prflag(alias, 0);
-               update_prkey(alias, 0);
-       }
-out1:
-       free(alias);
-       return ret;
-}
-
 
 int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
        unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
@@ -384,550 +165,3 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
        __mpath_persistent_reserve_free_vecs(curmp, pathvec);
        return ret;
 }
-
-int
-get_mpvec (vector curmp, vector pathvec, char * refwwid)
-{
-       int i;
-       struct multipath *mpp;
-
-       vector_foreach_slot (curmp, mpp, i){
-               /*
-                * discard out of scope maps
-                */
-               if (!mpp->alias) {
-                       condlog(0, "%s: map with empty alias!", __func__);
-                       continue;
-               }
-
-               if (mpp->pg != NULL)
-                       /* Already seen this one */
-                       continue;
-
-               if (refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE - 1))
-                       continue;
-
-               if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
-                   update_mpp_paths(mpp, pathvec)) {
-                       condlog(1, "error parsing map %s", mpp->wwid);
-                       remove_map(mpp, pathvec, curmp);
-                       i--;
-               } else
-                       extract_hwe_from_path(mpp);
-       }
-       return MPATH_PR_SUCCESS ;
-}
-
-int mpath_send_prin_activepath (char * dev, int rq_servact,
-                               struct prin_resp * resp, int noisy)
-{
-
-       int rc;
-
-       rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
-
-       return (rc);
-}
-
-int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
-       unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
-{
-
-       int i, j, k;
-       struct pathgroup *pgp = NULL;
-       struct path *pp = NULL;
-       int rollback = 0;
-       int active_pathcount=0;
-       int rc;
-       int count=0;
-       int status = MPATH_PR_SUCCESS;
-       int all_tg_pt;
-       uint64_t sa_key = 0;
-
-       if (!mpp)
-               return MPATH_PR_DMMP_ERROR;
-
-       all_tg_pt = (mpp->all_tg_pt == ALL_TG_PT_ON ||
-                    paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK);
-       active_pathcount = count_active_paths(mpp);
-
-       if (active_pathcount == 0) {
-               condlog (0, "%s: no path available", mpp->wwid);
-               return MPATH_PR_DMMP_ERROR;
-       }
-
-       struct threadinfo thread[active_pathcount];
-       int hosts[active_pathcount];
-
-       memset(thread, 0, sizeof(thread));
-
-       /* init thread parameter */
-       for (i =0; i< active_pathcount; i++){
-               hosts[i] = -1;
-               thread[i].param.rq_servact = rq_servact;
-               thread[i].param.rq_scope = rq_scope;
-               thread[i].param.rq_type = rq_type;
-               thread[i].param.paramp = paramp;
-               thread[i].param.noisy = noisy;
-               thread[i].param.status = MPATH_PR_SKIP;
-
-               condlog (3, "THREAD ID [%d] INFO]", i);
-               condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
-               condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
-               condlog (3, "rq_type=%d ", thread[i].param.rq_type);
-               condlog (3, "rkey=");
-               condlog (3, "paramp->sa_flags =%02x ",
-                        thread[i].param.paramp->sa_flags);
-               condlog (3, "noisy=%d ", thread[i].param.noisy);
-               condlog (3, "status=%d ", thread[i].param.status);
-       }
-
-       pthread_attr_t attr;
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
-       vector_foreach_slot (mpp->pg, pgp, j){
-               vector_foreach_slot (pgp->paths, pp, i){
-                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
-                               condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
-                               continue;
-                       }
-                       if (all_tg_pt && pp->sg_id.host_no != -1) {
-                               for (k = 0; k < count; k++) {
-                                       if (pp->sg_id.host_no == hosts[k]) {
-                                               condlog(3, "%s: %s host %d matches skip.", pp->wwid, pp->dev, pp->sg_id.host_no);
-                                               break;
-                                       }
-                               }
-                               if (k < count)
-                                       continue;
-                       }
-                       strlcpy(thread[count].param.dev, pp->dev,
-                               FILE_NAME_SIZE);
-
-                       if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
-                               /*
-                                * Clearing SPEC_I_PT as transportids are already registered by now.
-                                */
-                               thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK);
-                       }
-
-                       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){
-                               condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
-                               thread[count].param.status = MPATH_PR_THREAD_ERROR;
-                       }
-                       else
-                               hosts[count] = pp->sg_id.host_no;
-                       count = count + 1;
-               }
-       }
-       for( i=0; i < count ; i++){
-               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;
-                       sa_key = get_unaligned_be64(&paramp->sa_key[0]);
-                       status = MPATH_PR_RESERV_CONFLICT ;
-               }
-               if (!rollback && (status == MPATH_PR_SUCCESS)){
-                       status = thread[i].param.status;
-               }
-       }
-       if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
-               condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
-               memcpy(&paramp->key, &paramp->sa_key, 8);
-               memset(&paramp->sa_key, 0, 8);
-               for( i=0 ; i < count ; i++){
-                       if(thread[i].param.status == MPATH_PR_SUCCESS) {
-                               rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
-                                               (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 < count ; 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);
-                               }
-                       }
-               }
-       }
-
-       pthread_attr_destroy(&attr);
-       return (status);
-}
-
-void * mpath_prout_pthread_fn(void *p)
-{
-       int ret;
-       struct prout_param * param = (struct prout_param *)p;
-
-       ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope,
-                       param->rq_type, param->paramp, param->noisy);
-       param->status = ret;
-       pthread_exit(NULL);
-}
-
-int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
-       unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
-{
-       int i,j, ret;
-       struct pathgroup *pgp = NULL;
-       struct path *pp = NULL;
-
-       vector_foreach_slot (mpp->pg, pgp, j){
-               vector_foreach_slot (pgp->paths, pp, i){
-                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
-                               condlog (1, "%s: %s path not up. Skip",
-                                        mpp->wwid, pp->dev);
-                               continue;
-                       }
-
-                       condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
-                       ret = send_prout_activepath(pp->dev, rq_servact,
-                                                   rq_scope, rq_type,
-                                                   paramp, noisy);
-                       return ret ;
-               }
-       }
-       condlog (0, "%s: no path available", mpp->wwid);
-       return MPATH_PR_DMMP_ERROR;
-}
-
-int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
-       unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
-{
-       struct prout_param param;
-       param.rq_servact = rq_servact;
-       param.rq_scope  = rq_scope;
-       param.rq_type   = rq_type;
-       param.paramp    = paramp;
-       param.noisy = noisy;
-       param.status = -1;
-
-       pthread_t thread;
-       pthread_attr_t attr;
-       int rc;
-
-       memset(&thread, 0, sizeof(thread));
-       strlcpy(param.dev, dev, FILE_NAME_SIZE);
-       /* Initialize and set thread joinable attribute */
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
-       rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
-       if (rc){
-               condlog (3, "%s: failed to create thread %d", dev, rc);
-               return MPATH_PR_THREAD_ERROR;
-       }
-       /* Free attribute and wait for the other threads */
-       pthread_attr_destroy(&attr);
-       rc = pthread_join(thread, NULL);
-
-       return (param.status);
-}
-
-int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
-       unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
-{
-       int i, j;
-       int num = 0;
-       struct pathgroup *pgp = NULL;
-       struct path *pp = NULL;
-       int active_pathcount = 0;
-       pthread_attr_t attr;
-       int rc, found = 0;
-       int count = 0;
-       int status = MPATH_PR_SUCCESS;
-       struct prin_resp resp;
-       struct prout_param_descriptor *pamp;
-       struct prin_resp *pr_buff;
-       int length;
-       struct transportid *pptr;
-
-       if (!mpp)
-               return MPATH_PR_DMMP_ERROR;
-
-       active_pathcount = count_active_paths(mpp);
-
-       if (active_pathcount == 0) {
-               condlog (0, "%s: no path available", mpp->wwid);
-               return MPATH_PR_DMMP_ERROR;
-       }
-
-       struct threadinfo thread[active_pathcount];
-       memset(thread, 0, sizeof(thread));
-       for (i = 0; i < active_pathcount; i++){
-               thread[i].param.rq_servact = rq_servact;
-               thread[i].param.rq_scope = rq_scope;
-               thread[i].param.rq_type = rq_type;
-               thread[i].param.paramp = paramp;
-               thread[i].param.noisy = noisy;
-               thread[i].param.status = MPATH_PR_SKIP;
-
-               condlog (3, " path count = %d", i);
-               condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
-               condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
-               condlog (3, "rq_type=%d ", thread[i].param.rq_type);
-               condlog (3, "noisy=%d ", thread[i].param.noisy);
-               condlog (3, "status=%d ", thread[i].param.status);
-       }
-
-       pthread_attr_init (&attr);
-       pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
-
-       vector_foreach_slot (mpp->pg, pgp, j){
-               vector_foreach_slot (pgp->paths, pp, i){
-                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
-                               condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev);
-                               continue;
-                       }
-
-                       strlcpy(thread[count].param.dev, pp->dev,
-                               FILE_NAME_SIZE);
-                       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) {
-                               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 < count; i++){
-               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);
-                       }
-               }
-       }
-
-       for (i = 0; i < count; i++){
-               /*  check thread status here and return the status */
-
-               if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
-                       status = MPATH_PR_RESERV_CONFLICT;
-               else if (status == MPATH_PR_SUCCESS
-                               && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
-                       status = thread[i].param.status;
-       }
-
-       status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
-       if (status != MPATH_PR_SUCCESS){
-               condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
-               return MPATH_PR_OTHER;
-       }
-
-       num = resp.prin_descriptor.prin_readresv.additional_length / 8;
-       if (num == 0){
-               condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
-               return MPATH_PR_SUCCESS;
-       }
-       condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid);
-
-       pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
-       if (!pr_buff){
-               condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);
-               return MPATH_PR_OTHER;
-       }
-
-       status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
-
-       if (status != MPATH_PR_SUCCESS){
-               condlog (0,  "%s: pr in read full status command failed.",  mpp->wwid);
-               goto out;
-       }
-
-       num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
-       if (0 == num){
-               goto out;
-       }
-       length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
-
-       pamp = (struct prout_param_descriptor *)malloc (length);
-       if (!pamp){
-               condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
-               goto out1;
-       }
-
-       memset(pamp, 0, length);
-
-       pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
-       if (!pamp->trnptid_list[0]){
-               condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
-               goto out1;
-       }
-
-       if (get_be64(mpp->reservation_key)){
-               memcpy (pamp->key, &mpp->reservation_key, 8);
-               condlog (3, "%s: reservation key set.", mpp->wwid);
-       }
-
-       status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
-                                    rq_scope, rq_type, pamp, noisy);
-
-       if (status) {
-               condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
-               goto out1;
-       }
-
-       pamp->num_transportid = 1;
-       pptr=pamp->trnptid_list[0];
-
-       for (i = 0; i < num; i++){
-               if (get_be64(mpp->reservation_key) &&
-                       memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
-                              &mpp->reservation_key, 8)){
-                       /*register with tarnsport id*/
-                       memset(pamp, 0, length);
-                       pamp->trnptid_list[0] = pptr;
-                       memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
-                       memcpy (pamp->sa_key,
-                                       pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
-                       pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
-                       pamp->num_transportid = 1;
-
-                       memcpy (pamp->trnptid_list[0],
-                                       &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
-                                       sizeof (struct transportid));
-                       status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
-                                       pamp, noisy);
-
-                       pamp->sa_flags = 0;
-                       memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
-                       memset (pamp->sa_key, 0, 8);
-                       pamp->num_transportid = 0;
-                       status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
-                                       pamp, noisy);
-               }
-               else
-               {
-                       if (get_be64(mpp->reservation_key))
-                               found = 1;
-               }
-
-
-       }
-
-       if (found){
-               memset (pamp, 0, length);
-               memcpy (pamp->sa_key, &mpp->reservation_key, 8);
-               memset (pamp->key, 0, 8);
-               status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
-       }
-
-
-       free(pptr);
-out1:
-       free (pamp);
-out:
-       free (pr_buff);
-       return (status);
-}
-
-void * mpath_alloc_prin_response(int prin_sa)
-{
-       void * ptr = NULL;
-       int size=0;
-       switch (prin_sa)
-       {
-               case MPATH_PRIN_RKEY_SA:
-                       size = sizeof(struct prin_readdescr);
-                       break;
-               case MPATH_PRIN_RRES_SA:
-                       size = sizeof(struct prin_resvdescr);
-                       break;
-               case MPATH_PRIN_RCAP_SA:
-                       size=sizeof(struct prin_capdescr);
-                       break;
-               case MPATH_PRIN_RFSTAT_SA:
-                       size = sizeof(struct print_fulldescr_list) +
-                               sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
-                       break;
-       }
-       if (size > 0)
-       {
-               ptr = calloc(size, 1);
-       }
-       return ptr;
-}
-
-int update_map_pr(struct multipath *mpp)
-{
-       int noisy=0;
-       struct prin_resp *resp;
-       unsigned int i;
-       int ret, isFound;
-
-       if (!get_be64(mpp->reservation_key))
-       {
-               /* Nothing to do. Assuming pr mgmt feature is disabled*/
-               condlog(4, "%s: reservation_key not set in multipath.conf",
-                       mpp->alias);
-               return MPATH_PR_SUCCESS;
-       }
-
-       resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
-       if (!resp)
-       {
-               condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
-               return MPATH_PR_OTHER;
-       }
-       ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
-
-       if (ret != MPATH_PR_SUCCESS )
-       {
-               condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
-               free(resp);
-               return  ret;
-       }
-
-       if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
-       {
-               condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias);
-               free(resp);
-               return MPATH_PR_SUCCESS;
-       }
-
-       condlog(2, "%s: Multipath  reservation_key: 0x%" PRIx64 " ", mpp->alias,
-               get_be64(mpp->reservation_key));
-
-       isFound =0;
-       for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
-       {
-               condlog(2, "%s: PR IN READKEYS[%d]  reservation key:", mpp->alias, i);
-               dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
-
-               if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
-               {
-                       condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
-                       isFound =1;
-               }
-       }
-
-       if (isFound)
-       {
-               mpp->prflag = 1;
-               condlog(2, "%s: prflag flag set.", mpp->alias );
-       }
-
-       free(resp);
-       return MPATH_PR_SUCCESS;
-}
index 9e9c0a8..0046f12 100644 (file)
@@ -77,7 +77,7 @@ extern "C" {
 #define MPATH_PROTOCOL_ID_SAS          0x06
 
 
-/*Transport ID FORMATE CODE */
+/*Transport ID FORMAT CODE */
 #define MPATH_WWUI_DEVICE_NAME         0x00    /* World wide unique initiator device name */
 #define MPATH_WWUI_PORT_IDENTIFIER     0x40    /* World wide unique initiator port identifier  */
 
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
new file mode 100644 (file)
index 0000000..e34fc32
--- /dev/null
@@ -0,0 +1,792 @@
+#include <libdevmapper.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <libudev.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "vector.h"
+#include "defaults.h"
+#include "checkers.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "prio.h"
+#include "devmapper.h"
+#include "debug.h"
+#include "config.h"
+#include "switchgroup.h"
+#include "discovery.h"
+#include "configure.h"
+#include "dmparser.h"
+#include "propsel.h"
+#include "util.h"
+#include "unaligned.h"
+
+#include "mpath_persist.h"
+#include "mpath_persist_int.h"
+#include "mpathpr.h"
+#include "mpath_pr_ioctl.h"
+
+struct prout_param {
+       char dev[FILE_NAME_SIZE];
+       int rq_servact;
+       int rq_scope;
+       unsigned int rq_type;
+       struct prout_param_descriptor  *paramp;
+       int noisy;
+       int status;
+};
+
+struct threadinfo {
+       int status;
+       pthread_t id;
+       struct prout_param param;
+};
+
+static int mpath_send_prin_activepath (char * dev, int rq_servact,
+                               struct prin_resp * resp, int noisy)
+{
+
+       int rc;
+
+       rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
+
+       return (rc);
+}
+
+static int mpath_prin_activepath (struct multipath *mpp, int rq_servact,
+       struct prin_resp * resp, int noisy)
+{
+       int i,j, ret = MPATH_PR_DMMP_ERROR;
+       struct pathgroup *pgp = NULL;
+       struct path *pp = NULL;
+
+       vector_foreach_slot (mpp->pg, pgp, j){
+               vector_foreach_slot (pgp->paths, pp, i){
+                       if (!((pp->state == PATH_UP) ||
+                             (pp->state == PATH_GHOST))){
+                               condlog(2, "%s: %s not available. Skip.",
+                                       mpp->wwid, pp->dev);
+                               condlog(3, "%s: status = %d.",
+                                       mpp->wwid, pp->state);
+                               continue;
+                       }
+
+                       condlog(3, "%s: sending pr in command to %s ",
+                               mpp->wwid, pp->dev);
+                       ret = mpath_send_prin_activepath(pp->dev, rq_servact,
+                                                        resp, noisy);
+                       switch(ret)
+                       {
+                               case MPATH_PR_SUCCESS:
+                               case MPATH_PR_SENSE_INVALID_OP:
+                                       return ret;
+                               default:
+                                       continue;
+                       }
+               }
+       }
+       return ret;
+}
+
+void *mpath_alloc_prin_response(int prin_sa)
+{
+       void * ptr = NULL;
+       int size=0;
+       switch (prin_sa)
+       {
+               case MPATH_PRIN_RKEY_SA:
+                       size = sizeof(struct prin_readdescr);
+                       break;
+               case MPATH_PRIN_RRES_SA:
+                       size = sizeof(struct prin_resvdescr);
+                       break;
+               case MPATH_PRIN_RCAP_SA:
+                       size=sizeof(struct prin_capdescr);
+                       break;
+               case MPATH_PRIN_RFSTAT_SA:
+                       size = sizeof(struct print_fulldescr_list) +
+                               sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
+                       break;
+       }
+       if (size > 0)
+       {
+               ptr = calloc(size, 1);
+       }
+       return ptr;
+}
+
+static int get_mpvec(vector curmp, vector pathvec, char *refwwid)
+{
+       int i;
+       struct multipath *mpp;
+
+       vector_foreach_slot (curmp, mpp, i){
+               /*
+                * discard out of scope maps
+                */
+               if (!mpp->alias) {
+                       condlog(0, "%s: map with empty alias!", __func__);
+                       continue;
+               }
+
+               if (mpp->pg != NULL)
+                       /* Already seen this one */
+                       continue;
+
+               if (refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE - 1))
+                       continue;
+
+               if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
+                   update_mpp_paths(mpp, pathvec)) {
+                       condlog(1, "error parsing map %s", mpp->wwid);
+                       remove_map(mpp, pathvec, curmp);
+                       i--;
+               } else
+                       extract_hwe_from_path(mpp);
+       }
+       return MPATH_PR_SUCCESS ;
+}
+
+static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
+                        struct multipath **pmpp)
+{
+       int ret = MPATH_PR_DMMP_ERROR;
+       struct stat info;
+       int major, minor;
+       char *alias;
+       struct multipath *mpp;
+
+       if (fstat(fd, &info) != 0){
+               condlog(0, "stat error fd=%d", fd);
+               return MPATH_PR_FILE_ERROR;
+       }
+       if(!S_ISBLK(info.st_mode)){
+               condlog(3, "Failed to get major:minor. fd=%d", fd);
+               return MPATH_PR_FILE_ERROR;
+       }
+
+       major = major(info.st_rdev);
+       minor = minor(info.st_rdev);
+       condlog(4, "Device  %d:%d", major, minor);
+
+       /* get alias from major:minor*/
+       alias = dm_mapname(major, minor);
+       if (!alias){
+               condlog(0, "%d:%d failed to get device alias.", major, minor);
+               return MPATH_PR_DMMP_ERROR;
+       }
+
+       condlog(3, "alias = %s", alias);
+
+       if (dm_map_present(alias) && dm_is_mpath(alias) != 1){
+               condlog(3, "%s: not a multipath device.", alias);
+               goto out;
+       }
+
+       /* get info of all paths from the dm device     */
+       if (get_mpvec(curmp, pathvec, alias)){
+               condlog(0, "%s: failed to get device info.", alias);
+               goto out;
+       }
+
+       mpp = find_mp_by_alias(curmp, alias);
+
+       if (!mpp) {
+               condlog(0, "%s: devmap not registered.", alias);
+               goto out;
+       }
+
+       ret = MPATH_PR_SUCCESS;
+       if (pmpp)
+               *pmpp = mpp;
+       if (palias) {
+               *palias = alias;
+               alias = NULL;
+       }
+out:
+       free(alias);
+       return ret;
+}
+
+int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
+                                  int fd, int rq_servact,
+                                  struct prin_resp *resp, int noisy)
+{
+       struct multipath *mpp;
+       int ret;
+
+       ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp);
+       if (ret != MPATH_PR_SUCCESS)
+               return ret;
+
+       ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy);
+
+       return ret;
+}
+
+static void *mpath_prout_pthread_fn(void *p)
+{
+       int ret;
+       struct prout_param * param = (struct prout_param *)p;
+
+       ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope,
+                       param->rq_type, param->paramp, param->noisy);
+       param->status = ret;
+       pthread_exit(NULL);
+}
+
+static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
+                          unsigned int rq_type,
+                          struct prout_param_descriptor * paramp, int noisy)
+{
+
+       int i, j, k;
+       struct pathgroup *pgp = NULL;
+       struct path *pp = NULL;
+       int rollback = 0;
+       int active_pathcount=0;
+       int rc;
+       int count=0;
+       int status = MPATH_PR_SUCCESS;
+       int all_tg_pt;
+       uint64_t sa_key = 0;
+
+       if (!mpp)
+               return MPATH_PR_DMMP_ERROR;
+
+       all_tg_pt = (mpp->all_tg_pt == ALL_TG_PT_ON ||
+                    paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK);
+       active_pathcount = count_active_paths(mpp);
+
+       if (active_pathcount == 0) {
+               condlog (0, "%s: no path available", mpp->wwid);
+               return MPATH_PR_DMMP_ERROR;
+       }
+
+       struct threadinfo thread[active_pathcount];
+       int hosts[active_pathcount];
+
+       memset(thread, 0, sizeof(thread));
+
+       /* init thread parameter */
+       for (i =0; i< active_pathcount; i++){
+               hosts[i] = -1;
+               thread[i].param.rq_servact = rq_servact;
+               thread[i].param.rq_scope = rq_scope;
+               thread[i].param.rq_type = rq_type;
+               thread[i].param.paramp = paramp;
+               thread[i].param.noisy = noisy;
+               thread[i].param.status = MPATH_PR_SKIP;
+
+               condlog (3, "THREAD ID [%d] INFO]", i);
+               condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
+               condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
+               condlog (3, "rq_type=%d ", thread[i].param.rq_type);
+               condlog (3, "rkey=");
+               condlog (3, "paramp->sa_flags =%02x ",
+                        thread[i].param.paramp->sa_flags);
+               condlog (3, "noisy=%d ", thread[i].param.noisy);
+               condlog (3, "status=%d ", thread[i].param.status);
+       }
+
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+       vector_foreach_slot (mpp->pg, pgp, j){
+               vector_foreach_slot (pgp->paths, pp, i){
+                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+                               condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
+                               continue;
+                       }
+                       if (all_tg_pt && pp->sg_id.host_no != -1) {
+                               for (k = 0; k < count; k++) {
+                                       if (pp->sg_id.host_no == hosts[k]) {
+                                               condlog(3, "%s: %s host %d matches skip.", pp->wwid, pp->dev, pp->sg_id.host_no);
+                                               break;
+                                       }
+                               }
+                               if (k < count)
+                                       continue;
+                       }
+                       strlcpy(thread[count].param.dev, pp->dev,
+                               FILE_NAME_SIZE);
+
+                       if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
+                               /*
+                                * Clearing SPEC_I_PT as transportids are already registered by now.
+                                */
+                               thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK);
+                       }
+
+                       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){
+                               condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
+                               thread[count].param.status = MPATH_PR_THREAD_ERROR;
+                       }
+                       else
+                               hosts[count] = pp->sg_id.host_no;
+                       count = count + 1;
+               }
+       }
+       for( i=0; i < count ; i++){
+               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;
+                       sa_key = get_unaligned_be64(&paramp->sa_key[0]);
+                       status = MPATH_PR_RESERV_CONFLICT ;
+               }
+               if (!rollback && (status == MPATH_PR_SUCCESS)){
+                       status = thread[i].param.status;
+               }
+       }
+       if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
+               condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
+               memcpy(&paramp->key, &paramp->sa_key, 8);
+               memset(&paramp->sa_key, 0, 8);
+               for( i=0 ; i < count ; i++){
+                       if(thread[i].param.status == MPATH_PR_SUCCESS) {
+                               rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
+                                               (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 < count ; 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);
+                               }
+                       }
+               }
+       }
+
+       pthread_attr_destroy(&attr);
+       return (status);
+}
+
+static int send_prout_activepath(char *dev, int rq_servact, int rq_scope,
+                                unsigned int rq_type,
+                                struct prout_param_descriptor * paramp, int noisy)
+{
+       struct prout_param param;
+       param.rq_servact = rq_servact;
+       param.rq_scope  = rq_scope;
+       param.rq_type   = rq_type;
+       param.paramp    = paramp;
+       param.noisy = noisy;
+       param.status = -1;
+
+       pthread_t thread;
+       pthread_attr_t attr;
+       int rc;
+
+       memset(&thread, 0, sizeof(thread));
+       strlcpy(param.dev, dev, FILE_NAME_SIZE);
+       /* Initialize and set thread joinable attribute */
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+       rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
+       if (rc){
+               condlog (3, "%s: failed to create thread %d", dev, rc);
+               return MPATH_PR_THREAD_ERROR;
+       }
+       /* Free attribute and wait for the other threads */
+       pthread_attr_destroy(&attr);
+       rc = pthread_join(thread, NULL);
+
+       return (param.status);
+}
+
+static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
+                             unsigned int rq_type,
+                             struct prout_param_descriptor* paramp, int noisy)
+{
+       int i,j, ret;
+       struct pathgroup *pgp = NULL;
+       struct path *pp = NULL;
+
+       vector_foreach_slot (mpp->pg, pgp, j){
+               vector_foreach_slot (pgp->paths, pp, i){
+                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+                               condlog (1, "%s: %s path not up. Skip",
+                                        mpp->wwid, pp->dev);
+                               continue;
+                       }
+
+                       condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
+                       ret = send_prout_activepath(pp->dev, rq_servact,
+                                                   rq_scope, rq_type,
+                                                   paramp, noisy);
+                       return ret ;
+               }
+       }
+       condlog (0, "%s: no path available", mpp->wwid);
+       return MPATH_PR_DMMP_ERROR;
+}
+
+static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
+                          unsigned int rq_type,
+                          struct prout_param_descriptor * paramp, int noisy)
+{
+       int i, j;
+       int num = 0;
+       struct pathgroup *pgp = NULL;
+       struct path *pp = NULL;
+       int active_pathcount = 0;
+       pthread_attr_t attr;
+       int rc, found = 0;
+       int count = 0;
+       int status = MPATH_PR_SUCCESS;
+       struct prin_resp resp;
+       struct prout_param_descriptor *pamp;
+       struct prin_resp *pr_buff;
+       int length;
+       struct transportid *pptr;
+
+       if (!mpp)
+               return MPATH_PR_DMMP_ERROR;
+
+       active_pathcount = count_active_paths(mpp);
+
+       if (active_pathcount == 0) {
+               condlog (0, "%s: no path available", mpp->wwid);
+               return MPATH_PR_DMMP_ERROR;
+       }
+
+       struct threadinfo thread[active_pathcount];
+       memset(thread, 0, sizeof(thread));
+       for (i = 0; i < active_pathcount; i++){
+               thread[i].param.rq_servact = rq_servact;
+               thread[i].param.rq_scope = rq_scope;
+               thread[i].param.rq_type = rq_type;
+               thread[i].param.paramp = paramp;
+               thread[i].param.noisy = noisy;
+               thread[i].param.status = MPATH_PR_SKIP;
+
+               condlog (3, " path count = %d", i);
+               condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
+               condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
+               condlog (3, "rq_type=%d ", thread[i].param.rq_type);
+               condlog (3, "noisy=%d ", thread[i].param.noisy);
+               condlog (3, "status=%d ", thread[i].param.status);
+       }
+
+       pthread_attr_init (&attr);
+       pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
+
+       vector_foreach_slot (mpp->pg, pgp, j){
+               vector_foreach_slot (pgp->paths, pp, i){
+                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+                               condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev);
+                               continue;
+                       }
+
+                       strlcpy(thread[count].param.dev, pp->dev,
+                               FILE_NAME_SIZE);
+                       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) {
+                               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 < count; i++){
+               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);
+                       }
+               }
+       }
+
+       for (i = 0; i < count; i++){
+               /*  check thread status here and return the status */
+
+               if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
+                       status = MPATH_PR_RESERV_CONFLICT;
+               else if (status == MPATH_PR_SUCCESS
+                               && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
+                       status = thread[i].param.status;
+       }
+
+       status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
+       if (status != MPATH_PR_SUCCESS){
+               condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
+               return MPATH_PR_OTHER;
+       }
+
+       num = resp.prin_descriptor.prin_readresv.additional_length / 8;
+       if (num == 0){
+               condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
+               return MPATH_PR_SUCCESS;
+       }
+       condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
+
+       pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
+       if (!pr_buff){
+               condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);
+               return MPATH_PR_OTHER;
+       }
+
+       status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
+
+       if (status != MPATH_PR_SUCCESS){
+               condlog (0,  "%s: pr in read full status command failed.",  mpp->wwid);
+               goto out;
+       }
+
+       num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
+       if (0 == num){
+               goto out;
+       }
+       length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
+
+       pamp = (struct prout_param_descriptor *)malloc (length);
+       if (!pamp){
+               condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
+               goto out1;
+       }
+
+       memset(pamp, 0, length);
+
+       pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
+       if (!pamp->trnptid_list[0]){
+               condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
+               goto out1;
+       }
+
+       if (get_be64(mpp->reservation_key)){
+               memcpy (pamp->key, &mpp->reservation_key, 8);
+               condlog (3, "%s: reservation key set.", mpp->wwid);
+       }
+
+       status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
+                                    rq_scope, rq_type, pamp, noisy);
+
+       if (status) {
+               condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
+               goto out1;
+       }
+
+       pamp->num_transportid = 1;
+       pptr=pamp->trnptid_list[0];
+
+       for (i = 0; i < num; i++){
+               if (get_be64(mpp->reservation_key) &&
+                       memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
+                              &mpp->reservation_key, 8)){
+                       /*register with tarnsport id*/
+                       memset(pamp, 0, length);
+                       pamp->trnptid_list[0] = pptr;
+                       memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
+                       memcpy (pamp->sa_key,
+                                       pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
+                       pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
+                       pamp->num_transportid = 1;
+
+                       memcpy (pamp->trnptid_list[0],
+                                       &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
+                                       sizeof (struct transportid));
+                       status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
+                                       pamp, noisy);
+
+                       pamp->sa_flags = 0;
+                       memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
+                       memset (pamp->sa_key, 0, 8);
+                       pamp->num_transportid = 0;
+                       status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
+                                       pamp, noisy);
+               }
+               else
+               {
+                       if (get_be64(mpp->reservation_key))
+                               found = 1;
+               }
+
+
+       }
+
+       if (found){
+               memset (pamp, 0, length);
+               memcpy (pamp->sa_key, &mpp->reservation_key, 8);
+               memset (pamp->key, 0, 8);
+               status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
+       }
+
+
+       free(pptr);
+out1:
+       free (pamp);
+out:
+       free (pr_buff);
+       return (status);
+}
+
+int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
+                                   int rq_servact, int rq_scope, unsigned int rq_type,
+                                   struct prout_param_descriptor *paramp, int noisy)
+{
+       struct multipath *mpp;
+       char *alias;
+       int ret;
+       uint64_t prkey;
+       struct config *conf;
+
+       ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
+       if (ret != MPATH_PR_SUCCESS)
+               return ret;
+
+       conf = get_multipath_config();
+       select_reservation_key(conf, mpp);
+       select_all_tg_pt(conf, mpp);
+       put_multipath_config(conf);
+
+       memcpy(&prkey, paramp->sa_key, 8);
+       if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
+           (rq_servact == MPATH_PROUT_REG_IGN_SA ||
+            (rq_servact == MPATH_PROUT_REG_SA &&
+             (!get_be64(mpp->reservation_key) ||
+              memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
+               memcpy(&mpp->reservation_key, paramp->sa_key, 8);
+               if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
+                                      paramp->sa_flags)) {
+                       condlog(0, "%s: failed to set prkey for multipathd.",
+                               alias);
+                       ret = MPATH_PR_DMMP_ERROR;
+                       goto out1;
+               }
+       }
+
+       if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
+           memcmp(paramp->sa_key, &mpp->reservation_key, 8) &&
+           (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) {
+               condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
+               ret = MPATH_PR_SYNTAX_ERROR;
+               goto out1;
+       }
+
+       switch(rq_servact)
+       {
+       case MPATH_PROUT_REG_SA:
+       case MPATH_PROUT_REG_IGN_SA:
+               ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+               break;
+       case MPATH_PROUT_RES_SA :
+       case MPATH_PROUT_PREE_SA :
+       case MPATH_PROUT_PREE_AB_SA :
+       case MPATH_PROUT_CLEAR_SA:
+               ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+               break;
+       case MPATH_PROUT_REL_SA:
+               ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+               break;
+       default:
+               ret = MPATH_PR_OTHER;
+               goto out1;
+       }
+
+       if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
+                               (rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
+       {
+               if (prkey == 0) {
+                       update_prflag(alias, 0);
+                       update_prkey(alias, 0);
+               } else
+                       update_prflag(alias, 1);
+       } else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) {
+               update_prflag(alias, 0);
+               update_prkey(alias, 0);
+       }
+out1:
+       free(alias);
+       return ret;
+}
+
+int update_map_pr(struct multipath *mpp)
+{
+       int noisy=0;
+       struct prin_resp *resp;
+       unsigned int i;
+       int ret, isFound;
+
+       if (!get_be64(mpp->reservation_key))
+       {
+               /* Nothing to do. Assuming pr mgmt feature is disabled*/
+               condlog(4, "%s: reservation_key not set in multipath.conf",
+                       mpp->alias);
+               return MPATH_PR_SUCCESS;
+       }
+
+       resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
+       if (!resp)
+       {
+               condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
+               return MPATH_PR_OTHER;
+       }
+       ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
+
+       if (ret != MPATH_PR_SUCCESS )
+       {
+               condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
+               free(resp);
+               return  ret;
+       }
+
+       if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
+       {
+               condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias);
+               free(resp);
+               return MPATH_PR_SUCCESS;
+       }
+
+       condlog(2, "%s: Multipath  reservation_key: 0x%" PRIx64 " ", mpp->alias,
+               get_be64(mpp->reservation_key));
+
+       isFound =0;
+       for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
+       {
+               condlog(2, "%s: PR IN READKEYS[%d]  reservation key:", mpp->alias, i);
+               dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
+
+               if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
+               {
+                       condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
+                       isFound =1;
+               }
+       }
+
+       if (isFound)
+       {
+               mpp->prflag = 1;
+               condlog(2, "%s: prflag flag set.", mpp->alias );
+       }
+
+       free(resp);
+       return MPATH_PR_SUCCESS;
+}
diff --git a/libmpathpersist/mpath_persist_int.h b/libmpathpersist/mpath_persist_int.h
new file mode 100644 (file)
index 0000000..3145753
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _MPATH_PERSIST_INT_H
+#define _MPATH_PERSIST_INT_H
+
+/*
+ * This header file contains symbols that are used by multipath-tools
+ * but aren't part of the public libmpathpersist API.
+ */
+
+void * mpath_alloc_prin_response(int prin_sa);
+int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
+                                  int fd, int rq_servact,
+                                  struct prin_resp *resp, int noisy);
+void *mpath_alloc_prin_response(int prin_sa);
+int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
+                                   int rq_servact, int rq_scope,
+                                   unsigned int rq_type,
+                                   struct prout_param_descriptor *paramp,
+                                   int noisy);
+int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy);
+int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
+                        unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
+void dumpHex(const char* , int len, int no_ascii);
+int update_map_pr(struct multipath *mpp);
+
+#endif /* _MPATH_PERSIST_INT_H */
index 126601c..093ec71 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <sys/ioctl.h>
-#include <unistd.h>
 #include <libudev.h>
 #include "mpath_pr_ioctl.h"
 #include "mpath_persist.h"
 #include "unaligned.h"
 
 #include "debug.h"
-
-#define FILE_NAME_SIZE          256
+#include "structs.h" /* FILE_NAME_SIZE */
 
 #define TIMEOUT 2000
 #define MAXRETRY 5
index bdecaa0..5824c16 100644 (file)
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
 #include <stdarg.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
index 5ea8cd6..39a7d8e 100644 (file)
@@ -1,54 +1,13 @@
 #ifndef MPATHPR_H
 #define MPATHPR_H
 
-#include "structs.h" /* FILE_NAME_SIZE */
-
-struct prin_param {
-       char dev[FILE_NAME_SIZE];
-       int rq_servact;
-       struct prin_resp *resp;
-       int noisy;
-       int status;
-};
-
-struct prout_param {
-       char dev[FILE_NAME_SIZE];
-       int rq_servact;
-       int rq_scope;
-       unsigned int rq_type;
-       struct prout_param_descriptor  *paramp;
-       int noisy;
-       int status;
-};
-
-struct threadinfo {
-       int status;
-       pthread_t id;
-       struct prout_param param;
-};
-
-int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy);
-int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
-               unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
-void * _mpath_pr_update (void *arg);
-int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy);
-int get_mpvec (vector curmp, vector pathvec, char * refwwid);
-void * mpath_prout_pthread_fn(void *p);
-void dumpHex(const char* , int len, int no_ascii);
-
-int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
-       unsigned int rq_type,  struct prout_param_descriptor * paramp, int noisy);
-int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
-       unsigned int rq_type,  struct prout_param_descriptor * paramp, int noisy);
-int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
-       unsigned int rq_type,  struct prout_param_descriptor * paramp, int noisy);
-int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
-       unsigned int rq_type,   struct prout_param_descriptor * paramp, int noisy);
+/*
+ * This header file contains symbols that are only used by
+ * libmpathpersist internally.
+ */
 
 int update_prflag(char *mapname, int set);
 int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
 #define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
-void * mpath_alloc_prin_response(int prin_sa);
-int update_map_pr(struct multipath *mpp);
 
 #endif
index dce2610..fefeb2a 100644 (file)
@@ -43,7 +43,7 @@ uninstall:
        $(RM) $(DESTDIR)$(includedir)/mpath_valid.h
 
 clean: dep_clean
-       $(RM) core *.a *.o *.so *.so.* *.gz *.abi $(NV_VERSION_SCRIPT)
+       $(RM) core *.a *.o *.so *.so.* *.abi $(NV_VERSION_SCRIPT)
 
 include $(wildcard $(OBJS:.o=.d))
 
index 63de4e1..ed06196 100644 (file)
@@ -83,7 +83,7 @@ int mpathvalid_init(int verbosity, int log_style);
 
 /*
  * DESCRIPTION:
- *     Reread the multipath configuration files and reinitalize
+ *     Reread the multipath configuration files and reinitialize
  *     the device mapper multipath configuration. This function can
  *     be called as many times as necessary.
  *
@@ -95,8 +95,8 @@ int mpathvalid_reload_config(void);
 /*
  * DESCRIPTION:
  *     Release the device mapper multipath configuration. This
- *     function must be called to cleanup resoures allocated by
- *     mpathvalid_init(). After calling this function, no futher
+ *     function must be called to cleanup resources allocated by
+ *     mpathvalid_init(). After calling this function, no further
  *     libmpathvalid functions may be called.
  *
  * RETURNS: 0 = Success, -1 = Failure
index d4af1a5..77e954a 100644 (file)
@@ -21,30 +21,35 @@ ifdef SYSTEMD
        endif
 endif
 
-ifneq ($(call check_func,dm_task_no_flush,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_task_no_flush,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_FLUSH -D_GNU_SOURCE
 endif
 
-ifneq ($(call check_func,dm_task_get_errno,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_task_get_errno,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_GET_ERRNO
 endif
 
-ifneq ($(call check_func,dm_task_set_cookie,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_task_set_cookie,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_COOKIE
 endif
 
-ifneq ($(call check_func,udev_monitor_set_receive_buffer_size,/usr/include/libudev.h),0)
+ifneq ($(call check_func,udev_monitor_set_receive_buffer_size,$(LIBUDEV_INCDIR)/libudev.h),0)
        CFLAGS += -DLIBUDEV_API_RECVBUF
 endif
 
-ifneq ($(call check_func,dm_task_deferred_remove,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_task_deferred_remove,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_DEFERRED
 endif
 
-ifneq ($(call check_func,dm_hold_control_dev,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_hold_control_dev,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_HOLD_CONTROL
 endif
 
+ifneq ($(call check_var,ELS_DTAG_LNK_INTEGRITY,$(LINUX_HEADERS_INCDIR)/scsi/fc/fc_els.h),0)
+       CFLAGS += -DFPIN_EVENT_HANDLER
+endif
+
+
 OBJS = parser.o vector.o devmapper.o callout.o \
        hwtable.o blacklist.o util.o dmparser.o config.o \
        structs.o discovery.o propsel.o dict.o \
@@ -61,7 +66,7 @@ nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h
        $(CC) $(CFLAGS) -Wno-unused-function -c -o $@ $<
 
 # there are lots of "unused parameters" in dict.c
-# because not all handler / snprint methods nees all parameters
+# because not all handler / snprint methods need all parameters
 dict.o:        dict.c
        $(CC) $(CFLAGS) -Wno-unused-parameter -c -o $@ $<
 
@@ -110,7 +115,7 @@ uninstall:
        $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
 
 clean: dep_clean
-       $(RM) core *.a *.o *.so *.so.* *.gz *.abi nvme-ioctl.c nvme-ioctl.h $(NV_VERSION_SCRIPT)
+       $(RM) core *.a *.o *.so *.so.* *.abi nvme-ioctl.c nvme-ioctl.h $(NV_VERSION_SCRIPT)
 
 include $(wildcard $(OBJS:.o=.d))
 
index 87c33af..548a118 100644 (file)
@@ -4,7 +4,6 @@
  */
 #include <stdlib.h>
 #include <errno.h>
-#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <limits.h>
@@ -19,8 +18,6 @@
 #include "checkers.h"
 #include "structs.h"
 #include "config.h"
-#include "util.h"
-#include "errno.h"
 #include "devmapper.h"
 #include "strbuf.h"
 
index ef346d7..00554d6 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/stat.h>
 #include <urcu.h>
 #include <urcu/uatomic.h>
+#include <assert.h>
 
 #include "debug.h"
 #include "checkers.h"
index f4600ed..5d25a42 100644 (file)
@@ -156,7 +156,7 @@ void checker_disable (struct checker *);
  *
  * Rationale:
  * Path checkers that do I/O may hang forever. To avoid blocking, some
- * checkers therefore use asyncronous, detached threads for checking
+ * checkers therefore use asynchronous, detached threads for checking
  * the paths. These threads may continue hanging if multipathd is stopped.
  * In this case, we can't unload the checker DSO at exit. In order to
  * avoid race conditions and crashes, the entry point of the thread
index f73cbe3..bc7b7be 100644 (file)
@@ -12,7 +12,6 @@
 #include <sys/ioctl.h>
 #include <linux/fs.h>
 #include <errno.h>
-#include <unistd.h>
 #include <libaio.h>
 
 #include "checkers.h"
@@ -23,7 +22,7 @@
 
 /* Note: This checker type relies on the fact that only one checker can be run
  * at a time, since multiple checkers share the same aio_group, and must be
- * able to modify other checker's async_reqs. If multple checkers become able
+ * able to modify other checker's async_reqs. If multiple checkers become able
  * to be run at the same time, this checker will need to add locking, and
  * probably polling on event fds, to deal with that */
 
index a4b4a21..c93e462 100644 (file)
@@ -23,7 +23,6 @@
 #include "../libmultipath/sg_include.h"
 #include "../libmultipath/util.h"
 #include "../libmultipath/time-util.h"
-#include "../libmultipath/util.h"
 
 #define TUR_CMD_LEN 6
 #define HEAVY_CHECK_COUNT       10
index 6745976..eca11ba 100644 (file)
@@ -450,12 +450,12 @@ get_udev_for_mpp(const struct multipath *mpp)
        dev_t devnum;
        struct udev_device *udd;
 
-       if (!mpp || !mpp->dmi) {
+       if (!mpp || !has_dm_info(mpp)) {
                condlog(1, "%s called with empty mpp", __func__);
                return NULL;
        }
 
-       devnum = makedev(mpp->dmi->major, mpp->dmi->minor);
+       devnum = makedev(mpp->dmi.major, mpp->dmi.minor);
        udd = udev_device_new_from_devnum(udev, 'b', devnum);
        if (!udd) {
                condlog(1, "failed to get udev device for %s", mpp->alias);
@@ -503,11 +503,8 @@ unref:
 }
 
 void
-trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
+trigger_path_udev_change(struct path *pp, bool is_mpath)
 {
-       struct pathgroup *pgp;
-       struct path *pp;
-       int i, j;
        /*
         * If a path changes from multipath to non-multipath, we must
         * synthesize an artificial "add" event, otherwise the LVM2 rules
@@ -515,6 +512,45 @@ trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
         * irritate ourselves with an "add", so use "change".
         */
        const char *action = is_mpath ? "change" : "add";
+       const char *env;
+
+       if (!pp->udev)
+               return;
+       /*
+        * Paths that are already classified as multipath
+        * members don't need another uevent.
+        */
+       env = udev_device_get_property_value(
+               pp->udev, "DM_MULTIPATH_DEVICE_PATH");
+
+       if (is_mpath && env != NULL && !strcmp(env, "1")) {
+               /*
+                * If FIND_MULTIPATHS_WAIT_UNTIL is not "0",
+                * path is in "maybe" state and timer is running
+                * Send uevent now (see multipath.rules).
+                */
+               env = udev_device_get_property_value(
+                       pp->udev, "FIND_MULTIPATHS_WAIT_UNTIL");
+               if (env == NULL || !strcmp(env, "0"))
+                       return;
+       } else if (!is_mpath &&
+                  (env == NULL || !strcmp(env, "0")))
+               return;
+
+       condlog(3, "triggering %s uevent for %s (is %smultipath member)",
+               action, pp->dev, is_mpath ? "" : "no ");
+       sysfs_attr_set_value(pp->udev, "uevent",
+                            action, strlen(action));
+       trigger_partitions_udev_change(pp->udev, action,
+                                      strlen(action));
+}
+
+void
+trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
+{
+       struct pathgroup *pgp;
+       struct path *pp;
+       int i, j;
 
        if (!mpp || !mpp->pg)
                return;
@@ -522,39 +558,8 @@ trigger_paths_udev_change(struct multipath *mpp, bool is_mpath)
        vector_foreach_slot (mpp->pg, pgp, i) {
                if (!pgp->paths)
                        continue;
-               vector_foreach_slot(pgp->paths, pp, j) {
-                       const char *env;
-
-                       if (!pp->udev)
-                               continue;
-                       /*
-                        * Paths that are already classified as multipath
-                        * members don't need another uevent.
-                        */
-                       env = udev_device_get_property_value(
-                               pp->udev, "DM_MULTIPATH_DEVICE_PATH");
-
-                       if (is_mpath && env != NULL && !strcmp(env, "1")) {
-                               /*
-                                * If FIND_MULTIPATHS_WAIT_UNTIL is not "0",
-                                * path is in "maybe" state and timer is running
-                                * Send uevent now (see multipath.rules).
-                                */
-                               env = udev_device_get_property_value(
-                                       pp->udev, "FIND_MULTIPATHS_WAIT_UNTIL");
-                               if (env == NULL || !strcmp(env, "0"))
-                                       continue;
-                       } else if (!is_mpath &&
-                                  (env == NULL || !strcmp(env, "0")))
-                               continue;
-
-                       condlog(3, "triggering %s uevent for %s (is %smultipath member)",
-                               action, pp->dev, is_mpath ? "" : "no ");
-                       sysfs_attr_set_value(pp->udev, "uevent",
-                                            action, strlen(action));
-                       trigger_partitions_udev_change(pp->udev, action,
-                                                      strlen(action));
-               }
+               vector_foreach_slot(pgp->paths, pp, j)
+                       trigger_path_udev_change(pp, is_mpath);
        }
 
        mpp->needs_paths_uevent = 0;
@@ -574,7 +579,8 @@ sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload)
                return 0;
        max_sectors_kb = mpp->max_sectors_kb;
        if (is_reload) {
-               if (!mpp->dmi && dm_get_info(mpp->alias, &mpp->dmi) != 0) {
+               if (!has_dm_info(mpp) &&
+                   dm_get_info(mpp->alias, &mpp->dmi) != 0) {
                        condlog(1, "failed to get dm info for %s", mpp->alias);
                        return 1;
                }
index efe18b7..2bf73e6 100644 (file)
@@ -56,6 +56,7 @@ int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int forc
 int get_refwwid (enum mpath_cmds cmd, const char *dev, enum devtypes dev_type,
                 vector pathvec, char **wwid);
 struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
+void trigger_path_udev_change(struct path *pp, bool is_mpath);
 void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath);
 void trigger_partitions_udev_change(struct udev_device *dev, const char *action,
                                    int len);
index c0eb335..2507f77 100644 (file)
@@ -473,14 +473,11 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
                dm_task_set_ro(dmt);
 
        if (task == DM_DEVICE_CREATE) {
-               prefixed_uuid = calloc(1, UUID_PREFIX_LEN +
-                                      strlen(mpp->wwid) + 1);
-               if (!prefixed_uuid) {
+               if (asprintf(&prefixed_uuid, UUID_PREFIX "%s", mpp->wwid) < 0) {
                        condlog(0, "cannot create prefixed uuid : %s",
                                strerror(errno));
                        goto addout;
                }
-               sprintf(prefixed_uuid, UUID_PREFIX "%s", mpp->wwid);
                if (!dm_task_set_uuid(dmt, prefixed_uuid))
                        goto freeout;
                dm_task_skip_lockfs(dmt);
@@ -611,12 +608,21 @@ int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
        return 0;
 }
 
-static int
-do_get_info(const char *name, struct dm_info *info)
+bool
+has_dm_info(const struct multipath *mpp)
+{
+       return (mpp && mpp->dmi.exists != 0);
+}
+
+int
+dm_get_info(const char *name, struct dm_info *info)
 {
        int r = -1;
        struct dm_task *dmt;
 
+       if (!name || !info)
+               return r;
+
        if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
                return r;
 
@@ -646,7 +652,7 @@ int dm_map_present(const char * str)
 {
        struct dm_info info;
 
-       return (do_get_info(str, &info) == 0);
+       return (dm_get_info(str, &info) == 0);
 }
 
 int dm_get_map(const char *name, unsigned long long *size, char **outparams)
@@ -969,7 +975,7 @@ dm_dev_t (const char * mapname, char * dev_t, int len)
 {
        struct dm_info info;
 
-       if (do_get_info(mapname, &info) != 0)
+       if (dm_get_info(mapname, &info) != 0)
                return 1;
 
        if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
@@ -1013,7 +1019,7 @@ dm_get_major_minor(const char *name, int *major, int *minor)
 {
        struct dm_info info;
 
-       if (do_get_info(name, &info) != 0)
+       if (dm_get_info(name, &info) != 0)
                return -1;
 
        *major = info.major;
@@ -1367,7 +1373,7 @@ dm_geteventnr (const char *name)
 {
        struct dm_info info;
 
-       if (do_get_info(name, &info) != 0)
+       if (dm_get_info(name, &info) != 0)
                return -1;
 
        return info.event_nr;
@@ -1378,7 +1384,7 @@ dm_is_suspended(const char *name)
 {
        struct dm_info info;
 
-       if (do_get_info(name, &info) != 0)
+       if (dm_get_info(name, &info) != 0)
                return -1;
 
        return info.suspended;
@@ -1542,7 +1548,7 @@ dm_get_deferred_remove (const char * mapname)
 {
        struct dm_info info;
 
-       if (do_get_info(mapname, &info) != 0)
+       if (dm_get_info(mapname, &info) != 0)
                return -1;
 
        return info.deferred_remove;
@@ -1583,32 +1589,6 @@ dm_cancel_deferred_remove (struct multipath *mpp __attribute__((unused)))
 
 #endif
 
-static struct dm_info *
-alloc_dminfo (void)
-{
-       return calloc(1, sizeof(struct dm_info));
-}
-
-int
-dm_get_info (const char * mapname, struct dm_info ** dmi)
-{
-       if (!mapname)
-               return 1;
-
-       if (!*dmi)
-               *dmi = alloc_dminfo();
-
-       if (!*dmi)
-               return 1;
-
-       if (do_get_info(mapname, *dmi) != 0) {
-               free(*dmi);
-               *dmi = NULL;
-               return 1;
-       }
-       return 0;
-}
-
 struct rename_data {
        const char *old;
        char *new;
index 45a676d..703f3bf 100644 (file)
@@ -70,7 +70,8 @@ char * dm_mapname(int major, int minor);
 int dm_remove_partmaps (const char * mapname, int need_sync,
                        int deferred_remove);
 int dm_get_uuid(const char *name, char *uuid, int uuid_len);
-int dm_get_info (const char * mapname, struct dm_info ** dmi);
+bool has_dm_info(const struct multipath *mpp);
+int dm_get_info (const char * mapname, struct dm_info *dmi);
 int dm_rename (const char * old, char * new, char * delim, int skip_kpartx);
 int dm_reassign(const char * mapname);
 int dm_reassign_table(const char *name, char *old, char *new);
index 7ad9f6e..2af9764 100644 (file)
@@ -512,6 +512,59 @@ snprint_def_find_multipaths(struct config *conf, struct strbuf *buff,
                         find_multipaths_optvals[conf->find_multipaths]);
 }
 
+static const char * const marginal_pathgroups_optvals[] = {
+       [MARGINAL_PATHGROUP_OFF] = "off",
+       [MARGINAL_PATHGROUP_ON] = "on",
+#ifdef FPIN_EVENT_HANDLER
+       [MARGINAL_PATHGROUP_FPIN] = "fpin",
+#endif
+};
+
+static int
+def_marginal_pathgroups_handler(struct config *conf, vector strvec,
+                           const char *file, int line_nr)
+{
+       char *buff;
+       unsigned int i;
+
+       buff = set_value(strvec);
+       if (!buff)
+               return 1;
+       for (i = MARGINAL_PATHGROUP_OFF;
+            i < ARRAY_SIZE(marginal_pathgroups_optvals); i++) {
+               if (marginal_pathgroups_optvals[i] != NULL &&
+                   !strcmp(buff, marginal_pathgroups_optvals[i])) {
+                       conf->marginal_pathgroups = i;
+                       break;
+               }
+       }
+
+       if (i >= ARRAY_SIZE(marginal_pathgroups_optvals)) {
+               if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
+                       conf->marginal_pathgroups = MARGINAL_PATHGROUP_OFF;
+               else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+                       conf->marginal_pathgroups = MARGINAL_PATHGROUP_ON;
+               /* This can only be true if FPIN_EVENT_HANDLER isn't defined,
+                * otherwise this check will have already happened above */
+               else if (strcmp(buff, "fpin") == 0)
+                       condlog(1, "%s line %d, support for \"fpin\" is not compiled in for marginal_pathgroups", file, line_nr);
+               else
+                       condlog(1, "%s line %d, invalid value for marginal_pathgroups: \"%s\"",
+                               file, line_nr, buff);
+       }
+       free(buff);
+       return 0;
+}
+
+static int
+snprint_def_marginal_pathgroups(struct config *conf, struct strbuf *buff,
+                           const void *data)
+{
+       return append_strbuf_quoted(buff,
+                        marginal_pathgroups_optvals[conf->marginal_pathgroups]);
+}
+
+
 declare_def_handler(selector, set_str)
 declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
 declare_hw_handler(selector, set_str)
@@ -1526,9 +1579,6 @@ declare_ovr_snprint(all_tg_pt, print_yes_no_undef)
 declare_hw_handler(all_tg_pt, set_yes_no_undef)
 declare_hw_snprint(all_tg_pt, print_yes_no_undef)
 
-declare_def_handler(marginal_pathgroups, set_yes_no)
-declare_def_snprint(marginal_pathgroups, print_yes_no)
-
 declare_def_handler(recheck_wwid, set_yes_no_undef)
 declare_def_snprint_defint(recheck_wwid, print_yes_no_undef, DEFAULT_RECHECK_WWID)
 declare_ovr_handler(recheck_wwid, set_yes_no_undef)
index 7d939ae..b969fba 100644 (file)
@@ -475,60 +475,33 @@ sysfs_get_tgt_nodename(struct path *pp, char *node)
        return 0;
 }
 
-int sysfs_get_host_adapter_name(const struct path *pp, char *adapter_name)
-{
-       int proto_id;
-
-       if (!pp || !adapter_name)
-               return 1;
-
-       proto_id = pp->sg_id.proto_id;
-
-       if (proto_id != SCSI_PROTOCOL_FCP &&
-           proto_id != SCSI_PROTOCOL_SAS &&
-           proto_id != SCSI_PROTOCOL_ISCSI &&
-           proto_id != SCSI_PROTOCOL_SRP) {
-               return 1;
-       }
-       /* iscsi doesn't have adapter info in sysfs
-        * get ip_address for grouping paths
-        */
-       if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
-               return sysfs_get_iscsi_ip_address(pp, adapter_name);
-
-       /* fetch adapter pci name for other protocols
-        */
-       return sysfs_get_host_pci_name(pp, adapter_name);
-}
-
-int sysfs_get_host_pci_name(const struct path *pp, char *pci_name)
+static int sysfs_get_host_bus_id(const struct path *pp, char *bus_id)
 {
        struct udev_device *hostdev, *parent;
        char host_name[HOST_NAME_LEN];
-       const char *driver_name, *value;
+       const char *driver_name, *subsystem_name, *value;
 
-       if (!pp || !pci_name)
+       if (!pp || !bus_id)
                return 1;
 
-       sprintf(host_name, "host%d", pp->sg_id.host_no);
+       snprintf(host_name, sizeof(host_name), "host%d", pp->sg_id.host_no);
        hostdev = udev_device_new_from_subsystem_sysname(udev,
                        "scsi_host", host_name);
        if (!hostdev)
                return 1;
 
-       parent = udev_device_get_parent(hostdev);
-       while (parent) {
+       for (parent = udev_device_get_parent(hostdev);
+            parent;
+            parent = udev_device_get_parent(parent)) {
                driver_name = udev_device_get_driver(parent);
-               if (!driver_name) {
-                       parent = udev_device_get_parent(parent);
-                       continue;
-               }
-               if (!strcmp(driver_name, "pcieport"))
+               subsystem_name = udev_device_get_subsystem(parent);
+               if (driver_name && !strcmp(driver_name, "pcieport"))
+                       break;
+               if (subsystem_name && !strcmp(subsystem_name, "ccw"))
                        break;
-               parent = udev_device_get_parent(parent);
        }
        if (parent) {
-               /* pci_device found
+               /* pci_device or ccw fcp device found
                 */
                value = udev_device_get_sysname(parent);
 
@@ -537,7 +510,7 @@ int sysfs_get_host_pci_name(const struct path *pp, char *pci_name)
                        return 1;
                }
 
-               strncpy(pci_name, value, SLOT_NAME_SIZE);
+               strlcpy(bus_id, value, SLOT_NAME_SIZE);
                udev_device_unref(hostdev);
                return 0;
        }
@@ -545,6 +518,32 @@ int sysfs_get_host_pci_name(const struct path *pp, char *pci_name)
        return 1;
 }
 
+int sysfs_get_host_adapter_name(const struct path *pp, char *adapter_name)
+{
+       int proto_id;
+
+       if (!pp || !adapter_name)
+               return 1;
+
+       proto_id = pp->sg_id.proto_id;
+
+       if (proto_id != SCSI_PROTOCOL_FCP &&
+           proto_id != SCSI_PROTOCOL_SAS &&
+           proto_id != SCSI_PROTOCOL_ISCSI &&
+           proto_id != SCSI_PROTOCOL_SRP) {
+               return 1;
+       }
+       /* iscsi doesn't have adapter info in sysfs
+        * get ip_address for grouping paths
+        */
+       if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
+               return sysfs_get_iscsi_ip_address(pp, adapter_name);
+
+       /* fetch adapter bus-ID for other protocols
+        */
+       return sysfs_get_host_bus_id(pp, adapter_name);
+}
+
 int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address)
 {
        struct udev_device *hostdev;
@@ -844,6 +843,7 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint)
        int i;
        unsigned int dev_loss_tmo = mpp->dev_loss;
        struct path *err_path = NULL;
+       STATIC_BITFIELD(bf, LAST_BUS_PROTOCOL_ID + 1);
 
        if (mpp->no_path_retry > 0) {
                uint64_t no_path_retry_tmo =
@@ -898,12 +898,13 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint)
                sysfs_set_eh_deadline(mpp, pp);
        }
 
-       if (err_path) {
+       if (err_path && !is_bit_set_in_bitfield(bus_protocol_id(pp), bf)) {
                STRBUF_ON_STACK(proto_buf);
 
                snprint_path_protocol(&proto_buf, err_path);
                condlog(2, "%s: setting dev_loss_tmo is unsupported for protocol %s",
                        mpp->alias, get_strbuf_str(&proto_buf));
+               set_bit_in_bitfield(bus_protocol_id(pp), bf);
        }
        return 0;
 }
@@ -2345,7 +2346,10 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
                         * Avoid any IO on the device itself.
                         * simply use the path_offline() return as its state
                         */
-                       pp->chkrstate = pp->state = path_state;
+                       if (path_state != PATH_PENDING ||
+                           pp->state == PATH_UNCHECKED ||
+                           pp->state == PATH_WILD)
+                               pp->chkrstate = pp->state = path_state;
                return PATHINFO_OK;
        }
 
index 095657b..466af34 100644 (file)
@@ -44,7 +44,6 @@ int store_pathinfo (vector pathvec, struct config *conf,
                    struct path **pp_ptr);
 int sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint);
 int sysfs_get_timeout(const struct path *pp, unsigned int *timeout);
-int sysfs_get_host_pci_name(const struct path *pp, char *pci_name);
 int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address);
 int sysfs_get_host_adapter_name(const struct path *pp,
                                char *adapter_name);
index 74c9215..50d13c0 100644 (file)
@@ -102,7 +102,7 @@ err:
 }
 
 /*
- * Caution callers: If this function encounters yet unkown path devices, it
+ * Caution callers: If this function encounters yet unknown path devices, it
  * adds them uninitialized to the mpp.
  * Call update_pathvec_from_dm() after this function to make sure
  * all data structures are in a sane state.
@@ -436,9 +436,19 @@ int disassemble_status(const char *params, struct multipath *mpp)
                free(word);
 
                /*
-                * PG Status (discarded, would be '0' anyway)
+                * Path Selector Group Arguments
                 */
-               p += get_word(p, NULL);
+               p += get_word(p, &word);
+
+               if (!word)
+                       return 1;
+
+               num_pg_args = atoi(word);
+               free(word);
+
+               /* Ignore ps group arguments */
+               for (j = 0; j < num_pg_args; j++)
+                       p += get_word(p, NULL);
 
                p += get_word(p, &word);
 
index cf8f570..f547c14 100644 (file)
@@ -42,7 +42,7 @@ struct foreign {
        /**
         * method: init(api, name)
         * Initialize foreign library, and check API compatibility
-        * return pointer to opaque internal data strucure if successful,
+        * return pointer to opaque internal data structure if successful,
         * NULL otherwise.
         *
         * @param[in] api: API version
index 499b881..838e116 100644 (file)
@@ -337,7 +337,7 @@ static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
 static int nvme_style(__attribute__((unused)) const struct gen_multipath* gm,
                      struct strbuf *buf, __attribute__((unused)) int verbosity)
 {
-       return append_strbuf_str(buf, "%%w [%%G]:%%d %%s");
+       return append_strbuf_str(buf, "%w [%G]:%d %s");
 }
 
 static const struct gen_multipath_ops nvme_map_ops = {
index c65e5e1..bd15710 100644 (file)
@@ -1039,7 +1039,7 @@ static struct hwentry default_hw[] = {
        {
                /* Linux-IO Target */
                .vendor        = "(LIO-ORG|SUSE)",
-               .product       = "RBD",
+               .product       = ".",
                .hwhandler     = "1 alua",
                .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = -FAILBACK_IMMEDIATE,
index 9c7ffa7..216f0ee 100644 (file)
@@ -31,7 +31,7 @@
  *   The new version inherits the previous ones.
  */
 
-LIBMULTIPATH_13.0.0 {
+LIBMULTIPATH_14.0.0 {
 global:
        /* symbols referenced by multipath and multipathd */
        add_foreign;
@@ -56,6 +56,7 @@ global:
        check_foreign;
        cleanup_charp;
        cleanup_lock;
+       cleanup_mutex;
        cleanup_ucharp;
        close_fd;
        coalesce_paths;
@@ -121,6 +122,7 @@ global:
        get_used_hwes;
        get_vpd_sgio;
        group_by_prio;
+       has_dm_info;
        init_checkers;
        init_config;
        init_foreign;
@@ -175,7 +177,7 @@ global:
        select_reservation_key;
        send_packet;
        set_max_fds;
-       __set_no_path_retry;
+       set_no_path_retry;
        set_path_removed;
        set_prkey;
        setup_map;
@@ -209,6 +211,7 @@ global:
        sysfs_is_multipathed;
        timespeccmp;
        timespecsub;
+       trigger_path_udev_change;
        trigger_paths_udev_change;
        truncate_strbuf;
        udev;
index 221b515..bf88f30 100644 (file)
@@ -8,7 +8,6 @@
 #include <sys/stat.h>
 #include <dirent.h>
 #include <unistd.h>
-#include <string.h>
 #include <errno.h>
 #include <assert.h>
 #include <libudev.h>
@@ -96,6 +95,7 @@
                             "            \"host_wwpn\" : \"%R\",\n" \
                             "            \"target_wwpn\" : \"%r\",\n" \
                             "            \"host_adapter\" : \"%a\",\n" \
+                            "            \"lun_hex\" : \"%L\",\n" \
                             "            \"marginal_st\" : \"%M\""
 
 #define PROGRESS_LEN  10
@@ -171,8 +171,8 @@ snprint_name (struct strbuf *buff, const struct multipath * mpp)
 static int
 snprint_sysfs (struct strbuf *buff, const struct multipath * mpp)
 {
-       if (mpp->dmi)
-               return print_strbuf(buff, "dm-%i", mpp->dmi->minor);
+       if (has_dm_info(mpp))
+               return print_strbuf(buff, "dm-%i", mpp->dmi.minor);
        else
                return append_strbuf_str(buff, "undef");
 }
@@ -180,9 +180,9 @@ snprint_sysfs (struct strbuf *buff, const struct multipath * mpp)
 static int
 snprint_ro (struct strbuf *buff, const struct multipath * mpp)
 {
-       if (!mpp->dmi)
+       if (!has_dm_info(mpp))
                return append_strbuf_str(buff, "undef");
-       if (mpp->dmi->read_only)
+       if (mpp->dmi.read_only)
                return append_strbuf_str(buff, "ro");
        else
                return append_strbuf_str(buff, "rw");
@@ -256,7 +256,9 @@ snprint_nb_paths (struct strbuf *buff, const struct multipath * mpp)
 static int
 snprint_dm_map_state (struct strbuf *buff, const struct multipath * mpp)
 {
-       if (mpp->dmi && mpp->dmi->suspended)
+       if (!has_dm_info(mpp))
+               return append_strbuf_str(buff, "undef");
+       else if (mpp->dmi.suspended)
                return append_strbuf_str(buff, "suspend");
        else
                return append_strbuf_str(buff, "active");
@@ -451,6 +453,24 @@ snprint_hcil (struct strbuf *buff, const struct path * pp)
                        pp->sg_id.lun);
 }
 
+
+static int
+snprint_path_lunhex (struct strbuf *buff, const struct path * pp)
+{
+       uint64_t lunhex = SCSI_INVALID_LUN, scsilun;
+
+       if (!pp || pp->sg_id.host_no < 0)
+               return print_strbuf(buff, "0x%016" PRIx64, lunhex);
+
+       scsilun = pp->sg_id.lun;
+       /* cf. Linux kernel function int_to_scsilun() */
+       lunhex = ((scsilun & 0x000000000000ffffULL) << 48) |
+               ((scsilun & 0x00000000ffff0000ULL) << 16) |
+               ((scsilun & 0x0000ffff00000000ULL) >> 16) |
+               ((scsilun & 0xffff000000000000ULL) >> 48);
+       return print_strbuf(buff, "0x%016" PRIx64, lunhex);
+}
+
 static int
 snprint_dev (struct strbuf *buff, const struct path * pp)
 {
@@ -734,43 +754,27 @@ snprint_path_failures(struct strbuf *buff, const struct path * pp)
 int
 snprint_path_protocol(struct strbuf *buff, const struct path * pp)
 {
-       switch (pp->bus) {
-       case SYSFS_BUS_SCSI:
-               switch (pp->sg_id.proto_id) {
-               case SCSI_PROTOCOL_FCP:
-                       return append_strbuf_str(buff, "scsi:fcp");
-               case SCSI_PROTOCOL_SPI:
-                       return append_strbuf_str(buff, "scsi:spi");
-               case SCSI_PROTOCOL_SSA:
-                       return append_strbuf_str(buff, "scsi:ssa");
-               case SCSI_PROTOCOL_SBP:
-                       return append_strbuf_str(buff, "scsi:sbp");
-               case SCSI_PROTOCOL_SRP:
-                       return append_strbuf_str(buff, "scsi:srp");
-               case SCSI_PROTOCOL_ISCSI:
-                       return append_strbuf_str(buff, "scsi:iscsi");
-               case SCSI_PROTOCOL_SAS:
-                       return append_strbuf_str(buff, "scsi:sas");
-               case SCSI_PROTOCOL_ADT:
-                       return append_strbuf_str(buff, "scsi:adt");
-               case SCSI_PROTOCOL_ATA:
-                       return append_strbuf_str(buff, "scsi:ata");
-               case SCSI_PROTOCOL_USB:
-                       return append_strbuf_str(buff, "scsi:usb");
-               case SCSI_PROTOCOL_UNSPEC:
-               default:
-                       return append_strbuf_str(buff, "scsi:unspec");
-               }
-       case SYSFS_BUS_CCW:
-               return append_strbuf_str(buff, "ccw");
-       case SYSFS_BUS_CCISS:
-               return append_strbuf_str(buff, "cciss");
-       case SYSFS_BUS_NVME:
-               return append_strbuf_str(buff, "nvme");
-       case SYSFS_BUS_UNDEF:
-       default:
-               return append_strbuf_str(buff, "undef");
-       }
+       static const char * const protocol_name[LAST_BUS_PROTOCOL_ID + 1] = {
+               [SYSFS_BUS_UNDEF] = "undef",
+               [SYSFS_BUS_CCW] = "ccw",
+               [SYSFS_BUS_CCISS] = "cciss",
+               [SYSFS_BUS_NVME] = "nvme",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_FCP] = "scsi:fcp",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SPI] = "scsi:spi",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SSA] = "scsi:ssa",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SBP] = "scsi:sbp",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SRP] = "scsi:srp",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_ISCSI] = "scsi:iscsi",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SAS] = "scsi:sas",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_ADT] = "scsi:adt",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_ATA] = "scsi:ata",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_USB] = "scsi:usb",
+               [SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC] = "scsi:unspec",
+       };
+       const char *pn = protocol_name[bus_protocol_id(pp)];
+
+       assert(pn != NULL);
+       return append_strbuf_str(buff, pn);
 }
 
 static int
@@ -842,6 +846,7 @@ static const struct path_data pd[] = {
        {'0', "failures",      snprint_path_failures},
        {'P', "protocol",      snprint_path_protocol},
        {'I', "init_st",       snprint_initialized},
+       {'L', "LUN hex",       snprint_path_lunhex},
 };
 
 static const struct pathgroup_data pgd[] = {
index 8d34ae3..16c6397 100644 (file)
@@ -23,7 +23,7 @@ LIBS = \
        libpriopath_latency.so \
        libpriosysfs.so
 
-ifneq ($(call check_file,/usr/include/linux/nvme_ioctl.h),0)
+ifneq ($(call check_file,$(LINUX_HEADERS_INCDIR)/linux/nvme_ioctl.h),0)
        LIBS += libprioana.so
        CFLAGS += -I../nvme
 endif
index f0a4bc4..08e992b 100644 (file)
@@ -286,7 +286,7 @@ struct rtpg_tp_dscr {
 struct rtpg_tpg_dscr {
        unsigned char   b0;             /* x....... = pref(ered) port        */
                                        /* .xxx.... = reserved               */
-                                       /* ....xxxx = asymetric access state */
+                                       /* ....xxxx = asymmetric access state*/
        unsigned char   b1;             /* xxx..... = reserved               */
                                        /* ...x.... = LBA dependent support  */
                                        /* ....x... = unavailable support    */
index 078226d..e155f6d 100644 (file)
@@ -284,7 +284,7 @@ int getprio(struct path *pp, char *args, unsigned int timeout)
 
        if (lg_avglatency > lg_maxavglatency) {
                pp_pl_log(2,
-                         "%s: average latency (%lld us) is outside the thresold (%lld us)",
+                         "%s: average latency (%lld us) is outside the threshold (%lld us)",
                          pp->dev, (long long)pow(base_num, lg_avglatency),
                          (long long)MAX_AVG_LATENCY);
                return DEFAULT_PRIORITY;
index a842fc3..1419ec6 100644 (file)
@@ -83,6 +83,8 @@ static const char cmdline_origin[] =
        "(setting: multipath command line [-p] flag)";
 static const char autodetect_origin[] =
        "(setting: storage device autodetected)";
+static const char fpin_marginal_path_origin[] =
+       "(setting: overridden by marginal_path_fpin)";
 static const char marginal_path_origin[] =
        "(setting: implied by marginal_path check)";
 static const char delay_watch_origin[] =
@@ -1035,9 +1037,12 @@ int select_san_path_err_threshold(struct config *conf, struct multipath *mp)
        const char *origin;
        STRBUF_ON_STACK(buff);
 
-       if (marginal_path_check_enabled(mp)) {
+       if (marginal_path_check_enabled(mp) || (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
                mp->san_path_err_threshold = NU_NO;
-               origin = marginal_path_origin;
+               if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
+                       origin = fpin_marginal_path_origin;
+               else
+                       origin = marginal_path_origin;
                goto out;
        }
        mp_set_mpe(san_path_err_threshold);
@@ -1058,9 +1063,12 @@ int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp)
        const char *origin;
        STRBUF_ON_STACK(buff);
 
-       if (marginal_path_check_enabled(mp)) {
+       if (marginal_path_check_enabled(mp) || (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
                mp->san_path_err_forget_rate = NU_NO;
-               origin = marginal_path_origin;
+               if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
+                       origin = fpin_marginal_path_origin;
+               else
+                       origin = marginal_path_origin;
                goto out;
        }
        mp_set_mpe(san_path_err_forget_rate);
@@ -1082,9 +1090,12 @@ int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp)
        const char *origin;
        STRBUF_ON_STACK(buff);
 
-       if (marginal_path_check_enabled(mp)) {
+       if (marginal_path_check_enabled(mp) || (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
                mp->san_path_err_recovery_time = NU_NO;
-               origin = marginal_path_origin;
+               if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
+                       origin = fpin_marginal_path_origin;
+               else
+                       origin = marginal_path_origin;
                goto out;
        }
        mp_set_mpe(san_path_err_recovery_time);
@@ -1106,6 +1117,12 @@ int select_marginal_path_err_sample_time(struct config *conf, struct multipath *
        const char *origin;
        STRBUF_ON_STACK(buff);
 
+       if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
+               mp->marginal_path_err_sample_time = NU_NO;
+               origin = fpin_marginal_path_origin;
+               goto out;
+       }
+
        mp_set_mpe(marginal_path_err_sample_time);
        mp_set_ovr(marginal_path_err_sample_time);
        mp_set_hwe(marginal_path_err_sample_time);
@@ -1129,6 +1146,12 @@ int select_marginal_path_err_rate_threshold(struct config *conf, struct multipat
        const char *origin;
        STRBUF_ON_STACK(buff);
 
+       if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
+               mp->marginal_path_err_rate_threshold = NU_NO;
+               origin = fpin_marginal_path_origin;
+               goto out;
+       }
+
        mp_set_mpe(marginal_path_err_rate_threshold);
        mp_set_ovr(marginal_path_err_rate_threshold);
        mp_set_hwe(marginal_path_err_rate_threshold);
@@ -1146,6 +1169,12 @@ int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multip
        const char *origin;
        STRBUF_ON_STACK(buff);
 
+       if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
+               mp->marginal_path_err_recheck_gap_time = NU_NO;
+               origin = fpin_marginal_path_origin;
+               goto out;
+       }
+
        mp_set_mpe(marginal_path_err_recheck_gap_time);
        mp_set_ovr(marginal_path_err_recheck_gap_time);
        mp_set_hwe(marginal_path_err_recheck_gap_time);
@@ -1164,6 +1193,12 @@ int select_marginal_path_double_failed_time(struct config *conf, struct multipat
        const char *origin;
        STRBUF_ON_STACK(buff);
 
+       if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) {
+               mp->marginal_path_double_failed_time = NU_NO;
+               origin = fpin_marginal_path_origin;
+               goto out;
+       }
+
        mp_set_mpe(marginal_path_double_failed_time);
        mp_set_ovr(marginal_path_double_failed_time);
        mp_set_hwe(marginal_path_double_failed_time);
index d1b8aa3..4b62da5 100644 (file)
@@ -18,6 +18,7 @@
 #include "prio.h"
 #include "prioritizers/alua_spc3.h"
 #include "dm-generic.h"
+#include "devmapper.h"
 
 struct adapter_group *
 alloc_adaptergroup(void)
@@ -278,11 +279,6 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
                mpp->alias = NULL;
        }
 
-       if (mpp->dmi) {
-               free(mpp->dmi);
-               mpp->dmi = NULL;
-       }
-
        if (!free_paths && mpp->pg) {
                struct pathgroup *pgp;
                struct path *pp;
@@ -407,10 +403,10 @@ find_mp_by_minor (const struct _vector *mpvec, unsigned int minor)
                return NULL;
 
        vector_foreach_slot (mpvec, mpp, i) {
-               if (!mpp->dmi)
+               if (!has_dm_info(mpp))
                        continue;
 
-               if (mpp->dmi->minor == minor)
+               if (mpp->dmi.minor == minor)
                        return mpp;
        }
        return NULL;
@@ -757,3 +753,13 @@ out:
 
        return 0;
 }
+
+unsigned int bus_protocol_id(const struct path *pp) {
+       if (!pp || pp->bus < 0 || pp->bus > SYSFS_BUS_SCSI)
+               return SYSFS_BUS_UNDEF;
+       if (pp->bus != SYSFS_BUS_SCSI)
+               return pp->bus;
+       if ((int)pp->sg_id.proto_id < 0 || pp->sg_id.proto_id > SCSI_PROTOCOL_UNSPEC)
+               return SYSFS_BUS_UNDEF;
+       return SYSFS_BUS_SCSI + pp->sg_id.proto_id;
+}
index c0f8929..d94f93a 100644 (file)
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <inttypes.h>
 #include <stdbool.h>
+#include <libdevmapper.h>
 
 #include "prio.h"
 #include "byteorder.h"
@@ -56,12 +57,13 @@ enum failback_mode {
        FAILBACK_FOLLOWOVER
 };
 
+/* SYSFS_BUS_SCSI should be last, see bus_protocol_id() */
 enum sysfs_buses {
        SYSFS_BUS_UNDEF,
-       SYSFS_BUS_SCSI,
        SYSFS_BUS_CCW,
        SYSFS_BUS_CCISS,
        SYSFS_BUS_NVME,
+       SYSFS_BUS_SCSI,
 };
 
 enum pathstates {
@@ -110,6 +112,12 @@ enum find_multipaths_states {
        __FIND_MULTIPATHS_LAST,
 };
 
+enum marginal_pathgroups_mode {
+       MARGINAL_PATHGROUP_OFF = YN_NO,
+       MARGINAL_PATHGROUP_ON = YN_YES,
+       MARGINAL_PATHGROUP_FPIN,
+};
+
 enum flush_states {
        FLUSH_UNDEF = YNU_UNDEF,
        FLUSH_DISABLED = YNU_NO,
@@ -174,9 +182,17 @@ enum scsi_protocol {
        SCSI_PROTOCOL_ADT = 7,  /* Media Changers */
        SCSI_PROTOCOL_ATA = 8,
        SCSI_PROTOCOL_USB = 9,  /* USB Attached SCSI (UAS), and others */
-       SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
+       SCSI_PROTOCOL_UNSPEC = 0xa, /* No specific protocol */
 };
 
+/*
+ * Linear ordering of bus/protocol
+ * This assumes that SYSFS_BUS_SCSI is last in enum sysfs_buses
+ * SCSI is the only bus type for which we distinguish protocols.
+ */
+#define LAST_BUS_PROTOCOL_ID (SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC)
+unsigned int bus_protocol_id(const struct path *pp);
+
 #define SCSI_INVALID_LUN ~0ULL
 
 enum no_undef_states {
@@ -386,7 +402,7 @@ struct multipath {
        unsigned long long size;
        vector paths;
        vector pg;
-       struct dm_info dmi;
+       struct dm_info dmi;
 
        /* configlet pointers */
        char * alias;
@@ -418,6 +434,7 @@ struct multipath {
        unsigned char prflag;
        int all_tg_pt;
        struct gen_multipath generic_mp;
+       bool fpin_must_reload;
 };
 
 static inline int marginal_path_check_enabled(const struct multipath *mpp)
index cb0ebae..6c23df8 100644 (file)
@@ -588,23 +588,22 @@ static void leave_recovery_mode(struct multipath *mpp)
        }
 }
 
-void __set_no_path_retry(struct multipath *mpp, bool check_features)
+void set_no_path_retry(struct multipath *mpp)
 {
        bool is_queueing = false; /* assign a value to make gcc happy */
 
-       check_features = check_features && mpp->features != NULL;
-       if (check_features)
+       if (mpp->features)
                is_queueing = strstr(mpp->features, "queue_if_no_path");
 
        switch (mpp->no_path_retry) {
        case NO_PATH_RETRY_UNDEF:
                break;
        case NO_PATH_RETRY_FAIL:
-               if (!check_features || is_queueing)
+               if (!mpp->features || is_queueing)
                        dm_queue_if_no_path(mpp->alias, 0);
                break;
        case NO_PATH_RETRY_QUEUE:
-               if (!check_features || !is_queueing)
+               if (!mpp->features || !is_queueing)
                        dm_queue_if_no_path(mpp->alias, 1);
                break;
        default:
@@ -613,11 +612,11 @@ void __set_no_path_retry(struct multipath *mpp, bool check_features)
                         * If in_recovery is set, leave_recovery_mode() takes
                         * care of dm_queue_if_no_path. Otherwise, do it here.
                         */
-                       if ((!check_features || !is_queueing) &&
+                       if ((!mpp->features || !is_queueing) &&
                            !mpp->in_recovery)
                                dm_queue_if_no_path(mpp->alias, 1);
                        leave_recovery_mode(mpp);
-               } else
+               } else if (pathcount(mpp, PATH_PENDING) == 0)
                        enter_recovery_mode(mpp);
                break;
        }
index d33fe98..3253f1b 100644 (file)
@@ -11,8 +11,7 @@ struct vectors {
        struct mutex_lock lock; /* defined in lock.h */
 };
 
-void __set_no_path_retry(struct multipath *mpp, bool check_features);
-#define set_no_path_retry(mpp) __set_no_path_retry(mpp, true)
+void set_no_path_retry(struct multipath *mpp);
 
 int adopt_paths (vector pathvec, struct multipath * mpp);
 void orphan_path (struct path * pp, const char *reason);
index 70ad217..29e2557 100644 (file)
@@ -41,7 +41,6 @@
 #include <sys/mman.h>
 #include <sys/time.h>
 #include <libudev.h>
-#include <errno.h>
 
 #include "debug.h"
 #include "list.h"
@@ -292,7 +291,7 @@ static bool
 uevent_can_merge(struct uevent *earlier, struct uevent *later)
 {
        /* merge paths uevents
-        * whose wwids exsit and are same
+        * whose wwids exist and are same
         * and actions are same,
         * and actions are addition or deletion
         */
index 79d9f32..5a44018 100644 (file)
@@ -82,6 +82,16 @@ struct bitfield {
        bitfield_t bits[];
 };
 
+#define STATIC_BITFIELD(name, length)                                  \
+       static struct {                                                 \
+               unsigned int len;                                       \
+               bitfield_t bits[((length) - 1) / bits_per_slot + 1];    \
+       } __static__ ## name = {                                        \
+               .len = (length),                                        \
+               .bits = { 0, },                                         \
+       }; \
+       struct bitfield *name = (struct bitfield *)& __static__ ## name
+
 struct bitfield *alloc_bitfield(unsigned int maxbit);
 
 void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len);
index e86a3cc..66c6cf3 100644 (file)
@@ -20,8 +20,8 @@
 #ifndef _VERSION_H
 #define _VERSION_H
 
-#define VERSION_CODE 0x000808
-#define DATE_CODE    0x030c15
+#define VERSION_CODE 0x000809
+#define DATE_CODE    0x100216
 
 #define PROG    "multipath-tools"
 
index 5126801..eb26970 100644 (file)
@@ -14,22 +14,21 @@ all: $(EXEC)
 
 $(EXEC): $(OBJS)
        $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) $(CFLAGS) $(LIBDEPS)
-       $(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 install:
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
        $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
-       $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(man8dir)
 
 clean: dep_clean
-       $(RM) core *.o $(EXEC) *.gz
+       $(RM) core *.o $(EXEC)
 
 include $(wildcard $(OBJS:.o=.d))
 
 uninstall:
        $(RM) $(DESTDIR)$(bindir)/$(EXEC)
-       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
+       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8
 
 dep_clean:
        $(RM) $(OBJS:.o=.d)
index 14245cc..4bdd55c 100644 (file)
@@ -10,6 +10,7 @@
 #include <getopt.h>
 #include <libudev.h>
 #include "mpath_persist.h"
+#include "mpath_persist_int.h"
 #include "main.h"
 #include "debug.h"
 #include <pthread.h>
index 0828a8f..c930499 100644 (file)
@@ -16,29 +16,36 @@ all: $(EXEC)
 
 $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
        $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
-       $(GZIP) $(EXEC).8 > $(EXEC).8.gz
-       $(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
 
 install:
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
        $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
        $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
-       $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(udevrulesdir)/56-multipath.rules
+       $(INSTALL_PROGRAM) -d $(DESTDIR)$(modulesloaddir)
+       $(INSTALL_PROGRAM) -m 644 modules-load.conf $(DESTDIR)$(modulesloaddir)/multipath.conf
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
-       $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(man8dir)
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
-       $(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5 $(DESTDIR)$(man5dir)
+ifneq ($(SCSI_DH_MODULES_PRELOAD),)
+       $(INSTALL_PROGRAM) -m 644 scsi_dh.conf $(DESTDIR)$(modulesloaddir)/scsi_dh.conf
+       for _x in $(SCSI_DH_MODULES_PRELOAD); do echo "$$_x"; done \
+           >>$(DESTDIR)$(modulesloaddir)/scsi_dh.conf
+endif
 
 uninstall:
        $(RM) $(DESTDIR)$(bindir)/$(EXEC)
        $(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
+       $(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf
+       $(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf
        $(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
-       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
-       $(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
+       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8
+       $(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5
 
 clean: dep_clean
-       $(RM) core *.o $(EXEC) *.gz
+       $(RM) core *.o $(EXEC)
 
 include $(wildcard $(OBJS:.o=.d))
 
index 0a9377e..d09f62d 100644 (file)
@@ -63,7 +63,6 @@
 #include "time-util.h"
 #include "file.h"
 #include "valid.h"
-#include "alias.h"
 
 /*
  * Return values of configure(), check_path_valid(), and main().
diff --git a/multipath/modules-load.conf b/multipath/modules-load.conf
new file mode 100644 (file)
index 0000000..b517d32
--- /dev/null
@@ -0,0 +1,3 @@
+# load dm-multipath early, both multipathd and multipath depend on it
+# (note that multipath may be called from udev rules!)
+dm-multipath
index 88d2a1d..605b46e 100644 (file)
@@ -251,7 +251,7 @@ The default is: \fBfailover\fR
 .B uid_attrs
 .
 Setting this option activates \fBmerging uevents\fR by WWID, which may improve
-uevent processing effiency. Moreover, it's an alternative method to configure
+uevent processing efficiency. Moreover, it's an alternative method to configure
 the udev properties to use for determining unique path identifiers (WWIDs).
 .RS
 .PP
@@ -587,7 +587,7 @@ and multipathd. This is equivalent to ulimit \-n. A value of \fImax\fR will set
 this to the system limit from \fI/proc/sys/fs/nr_open\fR. If this is not set, the
 maximum number of open fds is taken from the calling process. It is usually
 1024. To be safe, this should be set to the maximum number of paths plus 32,
-if that number is greated than 1024.
+if that number is greater than 1024.
 .RS
 .TP
 The default is: \fBmax\fR
@@ -830,7 +830,7 @@ The default is: \fBno\fR
 .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.conf. If the SCSI layer has not attached a hardware handler,
 multipath will continue to use its configured hardware handler.
 .RS
 .PP
@@ -1088,23 +1088,32 @@ The default is: \fBno\fR
 .
 .TP
 .B marginal_pathgroups
-If set to \fIno\fR, the \fIdelay_*_checks\fR, \fImarginal_path_*\fR, and
+If set to \fIoff\fR, the \fIdelay_*_checks\fR, \fImarginal_path_*\fR, and
 \fIsan_path_err_*\fR options will keep marginal, or \(dqshaky\(dq, paths from
 being reinstated until they have been monitored for some time. This can cause
 situations where all non-marginal paths are down, and no paths are usable
 until multipathd detects this and reinstates a marginal path. If the multipath
 device is not configured to queue IO in this case, it can cause IO errors to
 occur, even though there are marginal paths available.  However, if this
-option is set to \fIyes\fR, when one of the marginal path detecting methods
+option is set to \fIon\fR, when one of the marginal path detecting methods
 determines that a path is marginal, it will be reinstated and placed in a
-seperate pathgroup that will only be used after all the non-marginal pathgroups
-have been tried first. This prevents the possibility of IO errors occuring
+separate pathgroup that will only be used after all the non-marginal pathgroups
+have been tried first. This prevents the possibility of IO errors occurring
 while marginal paths are still usable. After the path has been monitored
 for the configured time, and is declared healthy, it will be returned to its
-normal pathgroup. See "Shaky paths detection" below for more information.
+normal pathgroup.
+If this option is set to \fIfpin\fR, multipathd will receive fpin
+notifications, set path states to "marginal" accordingly, and regroup paths
+as described for \fIon\fR. This option can't be used in combination
+with other options for "Shaky path detection" (see below). \fBNote:\fR If this
+is set to \fIfpin\fR, the \fImarginal_path_*\fR and \fIsan_path_err_*\fR
+options are implicitly set to \fIno\fP. Also, this option cannot be switched
+either to or from \fIfpin\fR on a multipathd reconfigure. multipathd must be
+restarted for the change to take effect.
+See "Shaky paths detection" below for more information.
 .RS
 .TP
-The default is: \fBno\fR
+The default is: \fBoff\fR
 .RE
 .
 .
@@ -1140,7 +1149,7 @@ device path.
 .I smart
 This differs from \fIfind_multipaths yes\fR only in
 the way it treats new devices for which only one path has been
-detected yet. When such a device is first encounted in udev rules, it is
+detected yet. When such a device is first encountered in udev rules, it is
 treated as a multipath device. multipathd waits whether additional paths with
 the same WWID appears. If that happens, it sets up a multipath map. If it
 doesn\'t happen until a
@@ -1420,7 +1429,7 @@ from later entries take precedence.
 The \fImultipath\fR subsection recognizes the following attributes:
 .TP 17
 .B wwid
-(Mandatory) World Wide Identifier. Detected multipath maps are matched agains this attribute.
+(Mandatory) World Wide Identifier. Detected multipath maps are matched against this attribute.
 Note that, unlike the \fIwwid\fR attribute in the \fIblacklist\fR section,
 this is \fBnot\fR a regular expression or a substring; WWIDs must match
 exactly inside the multipaths section.
@@ -1547,7 +1556,7 @@ device type, instead of the default "mpath".
 The vendor specific vpd page information, using the vpd page abbreviation.
 The vpd page abbreviation can be found by running \fIsg_vpd -e\fR. multipathd
 will use this information to gather device specific information that can be
-displayed with the \fI%g\fR wilcard for the \fImultipathd show maps format\fR
+displayed with the \fI%g\fR wildcard for the \fImultipathd show maps format\fR
 and \fImultipathd show paths format\fR commands. Currently only the
 \fBhp3par\fR vpd page is supported.
 .TP
@@ -1795,7 +1804,7 @@ in most scenarios. Users who want to enable uevent merging must set
 .SH "Shaky paths detection"
 .\" ----------------------------------------------------------------------------
 .
-A common problem in SAN setups is the occurence of intermittent errors: a
+A common problem in SAN setups is the occurrence of intermittent errors: a
 path is unreachable, then reachable again for a short time, disappears again,
 and so forth. This happens typically on unstable interconnects. It is
 undesirable to switch pathgroups unnecessarily on such frequent, unreliable
@@ -1841,6 +1850,13 @@ increase and the threshold is never reached. Ticks are the time between
 path checks by multipathd, which is variable and controlled by the
 \fIpolling_interval\fR and \fImax_polling_interval\fR parameters.
 .
+.TP
+.B \(dqFPIN \(dq failure tracking
+Fibre channel fabrics can notify hosts about fabric-level issues such
+as integrity failures or congestion with so-called Fabric Performance
+Impact Notifications (FPINs).On receiving the fpin notifications through ELS
+multipathd will move the affected path and port states to marginal.
+.
 .RS 8
 .LP
 This method is \fBdeprecated\fR in favor of the \(dqmarginal_path\(dq failure
diff --git a/multipath/scsi_dh.conf b/multipath/scsi_dh.conf
new file mode 100644 (file)
index 0000000..a13dd82
--- /dev/null
@@ -0,0 +1,2 @@
+# Load SCSI device handler modules for multipath early
+# This file may be empty
index 393b6cb..9a49144 100644 (file)
@@ -1,9 +1,13 @@
 include ../Makefile.inc
 
-ifneq ($(call check_func,dm_task_get_errno,/usr/include/libdevmapper.h),0)
+ifneq ($(call check_func,dm_task_get_errno,$(DEVMAPPER_INCDIR)/libdevmapper.h),0)
        CFLAGS += -DLIBDM_API_GET_ERRNO
 endif
 
+ifneq ($(call check_var,ELS_DTAG_LNK_INTEGRITY,$(LINUX_HEADERS_INCDIR)/scsi/fc/fc_els.h),0)
+       CFLAGS += -DFPIN_EVENT_HANDLER
+       FPIN_SUPPORT = 1
+endif
 #
 # debugging stuff
 #
@@ -34,13 +38,18 @@ endif
 OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \
        dmevents.o init_unwinder.o
 
+ifeq ($(FPIN_SUPPORT),1)
+OBJS += fpin_handlers.o
+endif
+
+
+
 EXEC = multipathd
 
 all : $(EXEC)
 
 $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
        $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(EXEC) $(LIBDEPS)
-       $(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 cli_handlers.o:        cli_handlers.c
        $(CC) $(CFLAGS) -Wno-unused-parameter -c -o $@ $<
@@ -54,16 +63,16 @@ ifdef SYSTEMD
        $(INSTALL_PROGRAM) -m 644 $(EXEC).socket $(DESTDIR)$(unitdir)
 endif
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
-       $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(man8dir)
 
 uninstall:
        $(RM) $(DESTDIR)$(bindir)/$(EXEC)
-       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
+       $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8
        $(RM) $(DESTDIR)$(unitdir)/$(EXEC).service
        $(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket
 
 clean: dep_clean
-       $(RM) core *.o $(EXEC) *.gz
+       $(RM) core *.o $(EXEC)
 
 include $(wildcard $(OBJS:.o=.d))
 
index f035ee7..3a85969 100644 (file)
@@ -385,7 +385,7 @@ void *wait_dmevents (__attribute__((unused)) void *unused)
 
 
        if (!waiter) {
-               condlog(0, "dmevents waiter not intialized");
+               condlog(0, "dmevents waiter not initialized");
                return NULL;
        }
 
diff --git a/multipathd/fpin.h b/multipathd/fpin.h
new file mode 100644 (file)
index 0000000..bfcc1ce
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __FPIN_H__
+#define __FPIN_H__
+
+#ifdef FPIN_EVENT_HANDLER
+void *fpin_fabric_notification_receiver(void *unused);
+void *fpin_els_li_consumer(void *data);
+void fpin_clean_marginal_dev_list(__attribute__((unused)) void *arg);
+#else
+static void *fpin_fabric_notification_receiver(__attribute__((unused))void *unused)
+{
+       return NULL;
+}
+static void *fpin_els_li_consumer(__attribute__((unused))void *data)
+{
+       return NULL;
+}
+/* fpin_clean_marginal_dev_list() is never called */
+#endif
+
+#endif
diff --git a/multipathd/fpin_handlers.c b/multipathd/fpin_handlers.c
new file mode 100644 (file)
index 0000000..aaf5655
--- /dev/null
@@ -0,0 +1,540 @@
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <libudev.h>
+#include <scsi/scsi_netlink_fc.h>
+#include <scsi/fc/fc_els.h>
+
+#include "parser.h"
+#include "vector.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "main.h"
+#include "debug.h"
+#include "util.h"
+#include "sysfs.h"
+
+#include "fpin.h"
+#include "devmapper.h"
+
+static pthread_cond_t fpin_li_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t fpin_li_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t fpin_li_marginal_dev_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static LIST_HEAD(els_marginal_list_head);
+static LIST_HEAD(fpin_li_marginal_dev_list_head);
+
+
+#define DEF_RX_BUF_SIZE        4096
+#define DEV_NAME_LEN   128
+#define FCH_EVT_LINKUP 0x2
+#define FCH_EVT_LINK_FPIN 0x501
+#define FCH_EVT_RSCN 0x5
+
+#define list_first_entry(ptr, type, member) \
+       list_entry((ptr)->next, type, member)
+
+/* max ELS frame Size */
+#define FC_PAYLOAD_MAXLEN   2048
+
+struct els_marginal_list {
+       uint32_t event_code;
+       uint16_t host_num;
+       uint16_t length;
+       char payload[FC_PAYLOAD_MAXLEN];
+       struct list_head node;
+};
+/* Structure to store the marginal devices info */
+struct marginal_dev_list {
+       char dev_t[BLK_DEV_SIZE];
+       uint32_t host_num;
+       struct list_head node;
+};
+
+static void _udev_device_unref(void *p)
+{
+       udev_device_unref(p);
+}
+
+
+/*set/unset the path state to marginal*/
+static int fpin_set_pathstate(struct path *pp, bool set)
+{
+       const char *action = set ? "set" : "unset";
+
+       if (!pp || !pp->mpp || !pp->mpp->alias)
+               return -1;
+
+       condlog(3, "\n%s: %s  marginal path %s (fpin)",
+               action, pp->mpp->alias, pp->dev_t);
+       pp->marginal = set;
+       pp->mpp->fpin_must_reload = true;
+       return 0;
+}
+
+/* This will unset marginal state of a device*/
+static void fpin_path_unsetmarginal(char *devname, struct vectors *vecs)
+{
+       struct path *pp;
+
+       pp = find_path_by_dev(vecs->pathvec, devname);
+       if (!pp)
+               pp = find_path_by_devt(vecs->pathvec, devname);
+
+       fpin_set_pathstate(pp, false);
+}
+
+/*This will set the marginal state of a device*/
+static int fpin_path_setmarginal(struct path *pp)
+{
+       return fpin_set_pathstate(pp, true);
+}
+
+/* Unsets all the devices in the list from marginal state */
+static void
+fpin_unset_marginal_dev(uint32_t host_num, struct vectors *vecs)
+{
+       struct marginal_dev_list *tmp_marg = NULL;
+       struct marginal_dev_list *marg = NULL;
+       struct multipath *mpp;
+       int ret = 0;
+       int i;
+
+       pthread_cleanup_push(cleanup_lock, &vecs->lock);
+       lock(&vecs->lock);
+       pthread_testcancel();
+
+       pthread_mutex_lock(&fpin_li_marginal_dev_mutex);
+       pthread_cleanup_push(cleanup_mutex, &fpin_li_marginal_dev_mutex);
+       pthread_testcancel();
+       if (list_empty(&fpin_li_marginal_dev_list_head)) {
+               condlog(4, "Marginal List is empty\n");
+               goto empty;
+       }
+       list_for_each_entry_safe(marg, tmp_marg, &fpin_li_marginal_dev_list_head, node) {
+               if (marg->host_num != host_num)
+                       continue;
+               condlog(4, " unsetting marginal dev: is %s %d\n",
+                               tmp_marg->dev_t, tmp_marg->host_num);
+               fpin_path_unsetmarginal(marg->dev_t, vecs);
+               list_del(&marg->node);
+               free(marg);
+       }
+empty:
+       pthread_cleanup_pop(1);
+       /* walk backwards because reload_and_sync_map() can remove mpp */
+       vector_foreach_slot_backwards(vecs->mpvec, mpp, i) {
+               if (mpp->fpin_must_reload) {
+                       ret = reload_and_sync_map(mpp, vecs, 0);
+                       if (ret == 2)
+                               condlog(2, "map removed during reload");
+                       else
+                               mpp->fpin_must_reload = false;
+               }
+       }
+       pthread_cleanup_pop(1);
+}
+
+/*
+ * On Receiving the frame from HBA driver, insert the frame into link
+ * integrity frame list which will be picked up later by consumer thread for
+ * processing.
+ */
+static int
+fpin_els_add_li_frame(struct fc_nl_event *fc_event)
+{
+       struct els_marginal_list *els_mrg = NULL;
+       int ret = 0;
+
+       if (fc_event->event_datalen > FC_PAYLOAD_MAXLEN)
+               return -EINVAL;
+
+       pthread_mutex_lock(&fpin_li_mutex);
+       pthread_cleanup_push(cleanup_mutex, &fpin_li_mutex);
+       pthread_testcancel();
+       els_mrg = calloc(1, sizeof(struct els_marginal_list));
+       if (els_mrg != NULL) {
+               els_mrg->host_num = fc_event->host_no;
+               els_mrg->event_code = fc_event->event_code;
+               els_mrg->length = fc_event->event_datalen;
+               memcpy(els_mrg->payload, &(fc_event->event_data), fc_event->event_datalen);
+               list_add_tail(&els_mrg->node, &els_marginal_list_head);
+               pthread_cond_signal(&fpin_li_cond);
+       } else
+               ret = -ENOMEM;
+       pthread_cleanup_pop(1);
+       return ret;
+
+}
+
+/*Sets the rport port_state to marginal*/
+static void fpin_set_rport_marginal(struct udev_device *rport_dev)
+{
+       sysfs_attr_set_value(rport_dev, "port_state",
+                               "Marginal", strlen("Marginal"));
+}
+
+/*Add the marginal devices info into the list*/
+static void
+fpin_add_marginal_dev_info(uint32_t host_num, char *devname)
+{
+       struct marginal_dev_list *newdev = NULL;
+
+       newdev = calloc(1, sizeof(struct marginal_dev_list));
+       if (newdev != NULL) {
+               newdev->host_num = host_num;
+               strlcpy(newdev->dev_t, devname, BLK_DEV_SIZE);
+               condlog(4, "\n%s hostno %d devname %s\n", __func__,
+                               host_num, newdev->dev_t);
+               pthread_mutex_lock(&fpin_li_marginal_dev_mutex);
+               list_add_tail(&(newdev->node),
+                               &fpin_li_marginal_dev_list_head);
+               pthread_mutex_unlock(&fpin_li_marginal_dev_mutex);
+       }
+}
+
+/*
+ * This function goes through the vecs->pathvec, and for
+ * each path, check that the host  number,
+ * the target WWPN associated with the path matches
+ * with the els wwpn and sets the path and port state to
+ * Marginal
+ */
+static int  fpin_chk_wwn_setpath_marginal(uint16_t host_num,  struct vectors *vecs,
+               uint64_t els_wwpn)
+{
+       struct path *pp;
+       struct multipath *mpp;
+       int i, k;
+       char rport_id[42];
+       const char *value = NULL;
+       struct udev_device *rport_dev = NULL;
+       uint64_t wwpn;
+       int ret = 0;
+
+       pthread_cleanup_push(cleanup_lock, &vecs->lock);
+       lock(&vecs->lock);
+       pthread_testcancel();
+
+       vector_foreach_slot(vecs->pathvec, pp, k) {
+               /* Checks the host number and also for the SCSI FCP */
+               if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num !=  pp->sg_id.host_no)
+                       continue;
+               sprintf(rport_id, "rport-%d:%d-%d",
+                               pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
+               rport_dev = udev_device_new_from_subsystem_sysname(udev,
+                               "fc_remote_ports", rport_id);
+               if (!rport_dev) {
+                       condlog(2, "%s: No fc_remote_port device for '%s'", pp->dev,
+                                       rport_id);
+                       continue;
+               }
+               pthread_cleanup_push(_udev_device_unref, rport_dev);
+               value = udev_device_get_sysattr_value(rport_dev, "port_name");
+               if (!value)
+                       goto unref;
+
+               if (value)
+                       wwpn =  strtol(value, NULL, 16);
+               /*
+                * If the port wwpn matches sets the path and port state
+                * to marginal
+                */
+               if (wwpn == els_wwpn) {
+                       ret = fpin_path_setmarginal(pp);
+                       if (ret < 0)
+                               goto unref;
+                       fpin_set_rport_marginal(rport_dev);
+                       fpin_add_marginal_dev_info(host_num, pp->dev);
+               }
+unref:
+               pthread_cleanup_pop(1);
+       }
+       /* walk backwards because reload_and_sync_map() can remove mpp */
+       vector_foreach_slot_backwards(vecs->mpvec, mpp, i) {
+               if (mpp->fpin_must_reload) {
+                       ret = reload_and_sync_map(mpp, vecs, 0);
+                       if (ret == 2)
+                               condlog(2, "map removed during reload");
+                       else
+                               mpp->fpin_must_reload = false;
+               }
+       }
+       pthread_cleanup_pop(1);
+       return ret;
+}
+
+/*
+ * This function loops around all the impacted wwns received as part of els
+ * frame and sets the associated path and port states to marginal.
+ */
+static int
+fpin_parse_li_els_setpath_marginal(uint16_t host_num, struct fc_tlv_desc *tlv,
+               struct vectors *vecs)
+{
+       uint32_t wwn_count = 0, iter = 0;
+       uint64_t wwpn;
+       struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv;
+       int count = 0;
+       int ret = 0;
+
+       /* Update the wwn to list */
+       wwn_count = be32_to_cpu(li_desc->pname_count);
+       condlog(4, "Got wwn count as %d\n", wwn_count);
+
+       for (iter = 0; iter < wwn_count; iter++) {
+               wwpn = be64_to_cpu(li_desc->pname_list[iter]);
+               ret = fpin_chk_wwn_setpath_marginal(host_num, vecs, wwpn);
+               if (ret < 0)
+                       condlog(2, "failed to set the path marginal associated with wwpn: 0x%" PRIx64 "\n", wwpn);
+
+               count++;
+       }
+       return count;
+}
+
+/*
+ * This function process the ELS frame received from HBA driver,
+ * and sets the path associated with the port wwn to marginal
+ * and also set the port state to marginal.
+ */
+static int
+fpin_process_els_frame(uint16_t host_num, char *fc_payload, struct vectors *vecs)
+{
+
+       int count = -1;
+       struct fc_els_fpin *fpin = (struct fc_els_fpin *)fc_payload;
+       struct fc_tlv_desc *tlv;
+
+       tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0];
+
+       /*
+        * Parse the els frame and set the affected paths and port
+        * state to marginal
+        */
+       count = fpin_parse_li_els_setpath_marginal(host_num, tlv, vecs);
+       if (count <= 0)
+               condlog(4, "Could not find any WWNs, ret = %d\n",
+                                       count);
+       return count;
+}
+
+/*
+ * This function process the FPIN ELS frame received from HBA driver,
+ * and push the frame to appropriate frame list. Currently we have only FPIN
+ * LI frame list.
+ */
+static int
+fpin_handle_els_frame(struct fc_nl_event *fc_event)
+{
+       int ret = -1;
+       uint32_t els_cmd;
+       struct fc_els_fpin *fpin = (struct fc_els_fpin *)&fc_event->event_data;
+       struct fc_tlv_desc *tlv;
+       uint32_t dtag;
+
+       els_cmd = (uint32_t)fc_event->event_data;
+       tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0];
+       dtag = be32_to_cpu(tlv->desc_tag);
+       condlog(4, "Got CMD in add as 0x%x fpin_cmd 0x%x dtag 0x%x\n",
+                       els_cmd, fpin->fpin_cmd, dtag);
+
+       if ((fc_event->event_code == FCH_EVT_LINK_FPIN) ||
+                       (fc_event->event_code == FCH_EVT_LINKUP) ||
+                       (fc_event->event_code == FCH_EVT_RSCN)) {
+
+               if (els_cmd == ELS_FPIN) {
+                       /*
+                        * Check the type of fpin by checking the tag info
+                        * At present we are supporting only LI events
+                        */
+                       if (dtag == ELS_DTAG_LNK_INTEGRITY) {
+                               /*Push the Payload to FPIN frame queue. */
+                               ret = fpin_els_add_li_frame(fc_event);
+                               if (ret != 0)
+                                       condlog(0, "Failed to process LI frame with error %d\n",
+                                                       ret);
+                       } else {
+                               condlog(4, "Unsupported FPIN received 0x%x\n", dtag);
+                               return ret;
+                       }
+               } else {
+                       /*Push the Payload to FPIN frame queue. */
+                       ret = fpin_els_add_li_frame(fc_event);
+                       if (ret != 0)
+                               condlog(0, "Failed to process Linkup/RSCN event with error %d evnt %d\n",
+                                               ret, fc_event->event_code);
+               }
+       } else
+               condlog(4, "Invalid command received: 0x%x\n", els_cmd);
+       return ret;
+}
+
+/*cleans the global marginal dev list*/
+void fpin_clean_marginal_dev_list(__attribute__((unused)) void *arg)
+{
+       struct marginal_dev_list *tmp_marg = NULL;
+
+       pthread_mutex_lock(&fpin_li_marginal_dev_mutex);
+       while (!list_empty(&fpin_li_marginal_dev_list_head)) {
+               tmp_marg  = list_first_entry(&fpin_li_marginal_dev_list_head,
+                               struct marginal_dev_list, node);
+               list_del(&tmp_marg->node);
+               free(tmp_marg);
+       }
+       pthread_mutex_unlock(&fpin_li_marginal_dev_mutex);
+}
+
+/* Cleans the global els  marginal list */
+static void fpin_clean_els_marginal_list(void *arg)
+{
+       struct list_head *head = (struct list_head *)arg;
+       struct els_marginal_list *els_marg;
+
+       while (!list_empty(head)) {
+               els_marg  = list_first_entry(head, struct els_marginal_list,
+                                            node);
+               list_del(&els_marg->node);
+               free(els_marg);
+       }
+}
+
+static void rcu_unregister(__attribute__((unused)) void *param)
+{
+       rcu_unregister_thread();
+}
+/*
+ * This is the FPIN ELS consumer thread. The thread sleeps on pthread cond
+ * variable unless notified by fpin_fabric_notification_receiver thread.
+ * This thread is only to process FPIN-LI ELS frames. A new thread and frame
+ * list will be added if any more ELS frames types are to be supported.
+ */
+void *fpin_els_li_consumer(void *data)
+{
+       struct list_head marginal_list_head;
+       int ret = 0;
+       uint16_t host_num;
+       struct els_marginal_list *els_marg;
+       uint32_t event_code;
+       struct vectors *vecs = (struct vectors *)data;
+
+       pthread_cleanup_push(rcu_unregister, NULL);
+       rcu_register_thread();
+       pthread_cleanup_push(fpin_clean_marginal_dev_list, NULL);
+       INIT_LIST_HEAD(&marginal_list_head);
+       pthread_cleanup_push(fpin_clean_els_marginal_list,
+                               (void *)&marginal_list_head);
+       for ( ; ; ) {
+               pthread_mutex_lock(&fpin_li_mutex);
+               pthread_cleanup_push(cleanup_mutex, &fpin_li_mutex);
+               pthread_testcancel();
+               while (list_empty(&els_marginal_list_head))
+                       pthread_cond_wait(&fpin_li_cond, &fpin_li_mutex);
+
+               if (!list_empty(&els_marginal_list_head)) {
+                       condlog(4, "Invoke List splice tail\n");
+                       list_splice_tail_init(&els_marginal_list_head, &marginal_list_head);
+               }
+               pthread_cleanup_pop(1);
+
+               while (!list_empty(&marginal_list_head)) {
+                       els_marg  = list_first_entry(&marginal_list_head,
+                                                       struct els_marginal_list, node);
+                       host_num = els_marg->host_num;
+                       event_code = els_marg->event_code;
+                       /* Now finally process FPIN LI ELS Frame */
+                       condlog(4, "Got a new Payload buffer, processing it\n");
+                       if ((event_code ==  FCH_EVT_LINKUP) || (event_code == FCH_EVT_RSCN))
+                                fpin_unset_marginal_dev(host_num, vecs);
+                       else {
+                               ret = fpin_process_els_frame(host_num, els_marg->payload, vecs);
+                               if (ret <= 0)
+                                       condlog(0, "ELS frame processing failed with ret %d\n", ret);
+                       }
+                       list_del(&els_marg->node);
+                       free(els_marg);
+
+               }
+       }
+
+       pthread_cleanup_pop(1);
+       pthread_cleanup_pop(1);
+       pthread_cleanup_pop(1);
+       return NULL;
+}
+
+static void receiver_cleanup_list(__attribute__((unused)) void *arg)
+{
+       pthread_mutex_lock(&fpin_li_mutex);
+       fpin_clean_els_marginal_list(&els_marginal_list_head);
+       pthread_mutex_unlock(&fpin_li_mutex);
+}
+
+/*
+ * Listen for ELS frames from driver. on receiving the frame payload,
+ * push the payload to a list, and notify the fpin_els_li_consumer thread to
+ * process it. Once consumer thread is notified, return to listen for more ELS
+ * frames from driver.
+ */
+void *fpin_fabric_notification_receiver(__attribute__((unused))void *unused)
+{
+       int ret;
+       long fd;
+       uint32_t els_cmd;
+       struct fc_nl_event *fc_event = NULL;
+       struct sockaddr_nl fc_local;
+       unsigned char buf[DEF_RX_BUF_SIZE] __attribute__((aligned(sizeof(uint64_t))));
+       size_t plen = 0;
+
+       pthread_cleanup_push(rcu_unregister, NULL);
+       rcu_register_thread();
+
+       pthread_cleanup_push(receiver_cleanup_list, NULL);
+       fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_SCSITRANSPORT);
+       if (fd < 0) {
+               condlog(0, "fc socket error %ld", fd);
+               return NULL;
+       }
+
+       pthread_cleanup_push(close_fd, (void *)fd);
+       memset(&fc_local, 0, sizeof(fc_local));
+       fc_local.nl_family = AF_NETLINK;
+       fc_local.nl_groups = ~0;
+       fc_local.nl_pid = getpid();
+       ret = bind(fd, (struct sockaddr *)&fc_local, sizeof(fc_local));
+       if (ret == -1) {
+               condlog(0, "fc socket bind error %d\n", ret);
+               goto out;
+       }
+       for ( ; ; ) {
+               condlog(4, "Waiting for ELS...\n");
+               ret = read(fd, buf, DEF_RX_BUF_SIZE);
+               if (ret < 0) {
+                       condlog(0, "failed to read the els frame (%d)", ret);
+                       continue;
+               }
+               condlog(4, "Got a new request %d\n", ret);
+               if (!NLMSG_OK((struct nlmsghdr *)buf, (unsigned int)ret)) {
+                       condlog(0, "bad els frame read (%d)", ret);
+                       continue;
+               }
+               /* Push the frame to appropriate frame list */
+               plen = NLMSG_PAYLOAD((struct nlmsghdr *)buf, 0);
+               fc_event = (struct fc_nl_event *)NLMSG_DATA(buf);
+               if (plen < sizeof(*fc_event)) {
+                       condlog(0, "too short (%d) to be an FC event", ret);
+                       continue;
+               }
+               els_cmd = (uint32_t)fc_event->event_data;
+               condlog(4, "Got host no as %d, event 0x%x, len %d evntnum %d evntcode %d\n",
+                               fc_event->host_no, els_cmd, fc_event->event_datalen,
+                               fc_event->event_num, fc_event->event_code);
+               fpin_handle_els_frame(fc_event);
+       }
+out:
+       pthread_cleanup_pop(1);
+       pthread_cleanup_pop(1);
+       pthread_cleanup_pop(1);
+       return NULL;
+}
index 7a57a79..f2c0b28 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/oom.h>
 #include <libudev.h>
 #include <urcu.h>
+#include "fpin.h"
 #ifdef USE_SYSTEMD
 #include <systemd/sd-daemon.h>
 #endif
 #include "prio.h"
 #include "wwids.h"
 #include "pgpolicies.h"
-#include "uevent.h"
 #include "log.h"
 #include "uxsock.h"
 #include "alias.h"
 
 #include "mpath_cmd.h"
 #include "mpath_persist.h"
+#include "mpath_persist_int.h"
 
 #include "prioritizers/alua_rtpg.h"
 
 #include "waiter.h"
 #include "dmevents.h"
 #include "io_err_stat.h"
-#include "wwids.h"
 #include "foreign.h"
 #include "../third-party/valgrind/drd.h"
 #include "init_unwinder.h"
 
-#define FILE_NAME_SIZE 256
 #define CMDSIZE 160
 #define MSG_SIZE 32
 
+int mpath_pr_event_handle(struct path *pp);
+void * mpath_pr_event_handler_fn (void * );
+
 #define LOG_MSG(lvl, pp)                                       \
 do {                                                           \
        if (pp->mpp && checker_selected(&pp->checker) &&        \
@@ -131,9 +133,11 @@ static bool __delayed_reconfig;
 pid_t daemon_pid;
 static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t config_cond;
-static pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr;
+static pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr,
+       fpin_thr, fpin_consumer_thr;
 static bool check_thr_started, uevent_thr_started, uxlsnr_thr_started,
-       uevq_thr_started, dmevent_thr_started;
+       uevq_thr_started, dmevent_thr_started, fpin_thr_started,
+       fpin_consumer_thr_started;
 static int pid_fd = -1;
 
 static inline enum daemon_status get_running_state(void)
@@ -818,6 +822,7 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
                conf = get_multipath_config();
                reassign_maps = conf->reassign_maps;
                put_multipath_config(conf);
+               dm_get_info(mpp->alias, &mpp->dmi);
                if (mpp->wait_for_udev) {
                        mpp->wait_for_udev = 0;
                        if (get_delayed_reconfig() &&
@@ -908,7 +913,7 @@ ev_remove_map (char * devname, char * alias, int minor, struct vectors * vecs)
        }
        if (strcmp(mpp->alias, alias)) {
                condlog(2, "%s: minor number mismatch (map %d, event %d)",
-                       mpp->alias, mpp->dmi->minor, minor);
+                       mpp->alias, mpp->dmi.minor, minor);
                return 1;
        }
        return flush_map(mpp, vecs, 0);
@@ -1155,6 +1160,8 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
                free_path(pp);
                return 1;
        }
+       if (mpp)
+               trigger_path_udev_change(pp, true);
        if (mpp && mpp->wait_for_udev &&
            (pathcount(mpp, PATH_UP) > 0 ||
             (pathcount(mpp, PATH_GHOST) > 0 &&
@@ -1440,6 +1447,52 @@ finish_path_init(struct path *pp, struct vectors * vecs)
 }
 
 static int
+sysfs_get_ro (struct path *pp)
+{
+       int ro;
+       char buff[3]; /* Either "0\n\0" or "1\n\0" */
+
+       if (!pp->udev)
+               return -1;
+
+       if (sysfs_attr_get_value(pp->udev, "ro", buff, sizeof(buff)) <= 0) {
+               condlog(3, "%s: Cannot read ro attribute in sysfs", pp->dev);
+               return -1;
+       }
+
+       if (sscanf(buff, "%d\n", &ro) != 1 || ro < 0 || ro > 1) {
+               condlog(3, "%s: Cannot parse ro attribute", pp->dev);
+               return -1;
+       }
+
+       return ro;
+}
+
+static bool
+needs_ro_update(struct multipath *mpp, int ro)
+{
+       struct pathgroup * pgp;
+       struct path * pp;
+       unsigned int i, j;
+
+       if (!mpp || ro < 0)
+               return false;
+       if (!has_dm_info(mpp))
+               return true;
+       if (mpp->dmi.read_only == ro)
+               return false;
+       if (ro == 1)
+               return true;
+       vector_foreach_slot (mpp->pg, pgp, i) {
+               vector_foreach_slot (pgp->paths, pp, j) {
+                       if (sysfs_get_ro(pp) == 1)
+                               return false;
+               }
+       }
+       return true;
+}
+
+static int
 uev_update_path (struct uevent *uev, struct vectors * vecs)
 {
        int ro, retval = 0, rc;
@@ -1511,7 +1564,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
                }
 
                ro = uevent_get_disk_ro(uev);
-               if (mpp && ro >= 0) {
+               if (needs_ro_update(mpp, ro)) {
                        condlog(2, "%s: update path write_protect to '%d' (uevent)", uev->kernel, ro);
 
                        if (mpp->wait_for_udev)
@@ -1549,7 +1602,7 @@ out:
 
                condlog(0, "%s: spurious uevent, path not found", uev->kernel);
        }
-       /* pp->initalized must not be INIT_PARTIAL if needs_reinit is set */
+       /* pp->initialized must not be INIT_PARTIAL if needs_reinit is set */
        if (needs_reinit)
                retval = uev_add_path(uev, vecs, 1);
        return retval;
@@ -1741,7 +1794,7 @@ uxlsnrloop (void * ap)
 
        /*
         * Wait for initial reconfiguration to finish, while
-        * hadling signals
+        * handling signals
         */
        while (wait_for_state_change_if(DAEMON_CONFIGURE, 50)
               == DAEMON_CONFIGURE)
@@ -2057,7 +2110,7 @@ static int check_path_reinstate_state(struct path * pp) {
        /*
         * This function is only called when the path state changes
         * from "bad" to "good". pp->state reflects the *previous* state.
-        * If this was "bad", we know that a failure must have occured
+        * If this was "bad", we know that a failure must have occurred
         * beforehand, and count that.
         * Note that we count path state _changes_ this way. If a path
         * remains in "bad" state, failure count is not increased.
@@ -2227,7 +2280,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
 
        /*
         * provision a next check soonest,
-        * in case we exit abnormaly from here
+        * in case we exit abnormally from here
         */
        pp->tick = checkint;
 
@@ -2797,6 +2850,7 @@ int
 reconfigure (struct vectors * vecs)
 {
        struct config * old, *conf;
+       int old_marginal_pathgroups;
 
        conf = load_config(DEFAULT_CONFIGFILE);
        if (!conf)
@@ -2826,10 +2880,20 @@ reconfigure (struct vectors * vecs)
        uxsock_timeout = conf->uxsock_timeout;
 
        old = rcu_dereference(multipath_conf);
+       old_marginal_pathgroups = old->marginal_pathgroups;
+       if ((old_marginal_pathgroups == MARGINAL_PATHGROUP_FPIN) !=
+           (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)) {
+               condlog(1, "multipathd must be restarted to turn %s fpin marginal paths",
+                       (old_marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)?
+                       "off" : "on");
+               conf->marginal_pathgroups = old_marginal_pathgroups;
+       }
        conf->sequence_nr = old->sequence_nr + 1;
        rcu_assign_pointer(multipath_conf, conf);
        call_rcu(&old->rcu, rcu_free_config);
-
+#ifdef FPIN_EVENT_HANDLER
+       fpin_clean_marginal_dev_list(NULL);
+#endif
        configure(vecs);
 
 
@@ -3048,6 +3112,11 @@ static void cleanup_threads(void)
                pthread_cancel(uevq_thr);
        if (dmevent_thr_started)
                pthread_cancel(dmevent_thr);
+       if (fpin_thr_started)
+               pthread_cancel(fpin_thr);
+       if (fpin_consumer_thr_started)
+               pthread_cancel(fpin_consumer_thr);
+
 
        if (check_thr_started)
                pthread_join(check_thr, NULL);
@@ -3059,6 +3128,11 @@ static void cleanup_threads(void)
                pthread_join(uevq_thr, NULL);
        if (dmevent_thr_started)
                pthread_join(dmevent_thr, NULL);
+       if (fpin_thr_started)
+               pthread_join(fpin_thr, NULL);
+       if (fpin_consumer_thr_started)
+               pthread_join(fpin_consumer_thr, NULL);
+
 
        /*
         * As all threads are joined now, and we're in DAEMON_SHUTDOWN
@@ -3152,6 +3226,7 @@ child (__attribute__((unused)) void *param)
        char *envp;
        enum daemon_status state;
        int exit_code = 1;
+       int fpin_marginal_paths = 0;
 
        init_unwinder();
        mlockall(MCL_CURRENT | MCL_FUTURE);
@@ -3230,7 +3305,10 @@ child (__attribute__((unused)) void *param)
 
        setscheduler();
        set_oom_adj();
-
+#ifdef FPIN_EVENT_HANDLER
+       if (conf->marginal_pathgroups == MARGINAL_PATHGROUP_FPIN)
+               fpin_marginal_paths = 1;
+#endif
        /*
         * Startup done, invalidate configuration
         */
@@ -3298,6 +3376,22 @@ child (__attribute__((unused)) void *param)
                goto failed;
        } else
                uevq_thr_started = true;
+
+       if (fpin_marginal_paths) {
+               if ((rc = pthread_create(&fpin_thr, &misc_attr,
+                       fpin_fabric_notification_receiver, NULL))) {
+                       condlog(0, "failed to create the fpin receiver thread: %d", rc);
+                       goto failed;
+               } else
+                       fpin_thr_started = true;
+
+               if ((rc = pthread_create(&fpin_consumer_thr,
+                       &misc_attr, fpin_els_li_consumer, vecs))) {
+                       condlog(0, "failed to create the fpin consumer thread thread: %d", rc);
+                       goto failed;
+               } else
+                       fpin_consumer_thr_started = true;
+       }
        pthread_attr_destroy(&misc_attr);
 
        while (1) {
index 8356b25..e8bee8e 100644 (file)
@@ -17,7 +17,7 @@ enum remove_path_result {
        REMOVE_PATH_FAILURE = 0x0, /* path could not be removed. It is still
                                    * part of the kernel map, but its state
                                    * is set to INIT_REMOVED, and it will be
-                                   * removed at the next possible occassion */
+                                   * removed at the next possible occasion */
        REMOVE_PATH_SUCCESS = 0x1, /* path was removed */
        REMOVE_PATH_DELAY = 0x2, /* path is set to be removed later. it
                                  * currently still exists and is part of the
@@ -27,9 +27,6 @@ enum remove_path_result {
                                      * because the path was also removed */
 };
 
-struct prout_param_descriptor;
-struct prin_resp;
-
 extern pid_t daemon_pid;
 extern int uxsock_timeout;
 
@@ -44,17 +41,7 @@ int ev_remove_path (struct path *, struct vectors *, int);
 int ev_add_map (char *, const char *, struct vectors *);
 int ev_remove_map (char *, char *, int, struct vectors *);
 int flush_map(struct multipath *, struct vectors *, int);
-void * mpath_alloc_prin_response(int prin_sa);
-int prin_do_scsi_ioctl(char *, int rq_servact, struct prin_resp * resp,
-                      int noisy);
-void dumpHex(const char * , int len, int no_ascii);
-int prout_do_scsi_ioctl(char * , int rq_servact, int rq_scope,
-                       unsigned int rq_type,
-                       struct prout_param_descriptor *param, int noisy);
-int mpath_pr_event_handle(struct path *pp);
-void * mpath_pr_event_handler_fn (void * );
-int update_map_pr(struct multipath *mpp);
-void * mpath_pr_event_handler_fn (void * pathp );
+
 void handle_signals(bool);
 int __setup_multipath (struct vectors * vecs, struct multipath * mpp,
                       int reset);
index 293e7f2..1e318bd 100644 (file)
@@ -82,7 +82,7 @@ multipathd. See
 .B \-w
 Since kernel 4.14 a new device-mapper event polling interface is used for updating
 multipath devices on dmevents. Use this flag to force it to use the old event
-waiting method, based on creating a seperate thread for each device.
+waiting method, based on creating a separate thread for each device.
 .
 .
 .
index 1919b38..aec62db 100644 (file)
@@ -1,12 +1,14 @@
 [Unit]
 Description=Device-Mapper Multipath Device Controller
-Before=iscsi.service iscsid.service lvm2-activation-early.service
+Before=lvm2-activation-early.service
 Before=local-fs-pre.target blk-availability.service shutdown.target
 Wants=systemd-udevd-kernel.socket
 After=systemd-udevd-kernel.socket
 After=multipathd.socket systemd-remount-fs.service
+Before=initrd-cleanup.service
 DefaultDependencies=no
 Conflicts=shutdown.target
+Conflicts=initrd-cleanup.service
 ConditionKernelCommandLine=!nompath
 ConditionKernelCommandLine=!multipath=off
 ConditionVirtualization=!container
@@ -14,8 +16,6 @@ ConditionVirtualization=!container
 [Service]
 Type=notify
 NotifyAccess=main
-LimitCORE=infinity
-ExecStartPre=-/sbin/modprobe -a scsi_dh_alua scsi_dh_emc scsi_dh_rdac dm-multipath
 ExecStart=/sbin/multipathd -d -s
 ExecReload=/sbin/multipathd reconfigure
 TasksMax=infinity
index 912ac3c..c07367f 100644 (file)
@@ -75,7 +75,7 @@ enum {
 };
 
 #define POLLFD_CHUNK (4096 / sizeof(struct pollfd))
-/* Minimum mumber of pollfds to reserve for clients */
+/* Minimum number of pollfds to reserve for clients */
 #define MIN_POLLS (POLLFD_CHUNK - POLLFDS_BASE)
 /*
  * Max number of client connections allowed
index 47c0f0b..f0d9be3 100644 (file)
@@ -38,7 +38,7 @@ device will be opened in read-only mode; you don't need to worry about data
 loss. However, the user needs to specify a device to be used. Set the
 environment variable `DIO_TEST_DEV` to the path of the device.
 Alternatively, create a file `directio_test_dev` under
-the `tests` directory containting a single line that sets this environment
+the `tests` directory containing a single line that sets this environment
 variable in Bourne Shell syntax, like this:
 
     DIO_TEST_DEV=/dev/sdc3
index 6f5766f..79bfa5f 100644 (file)
@@ -421,7 +421,7 @@ static const struct key_value vnd_boo = { _vendor, "boo" };
 static const struct key_value prd_baz = { _product, "baz" };
 static const struct key_value wwid_test = { _wwid, default_wwid };
 
-/* Regular expresssions */
+/* Regular expressions */
 static const struct key_value vnd__oo = { _vendor, ".oo" };
 static const struct key_value vnd_t_oo = { _vendor, "^.oo" };
 static const struct key_value prd_ba_ = { _product, "ba." };
@@ -603,7 +603,7 @@ static int setup_internal_nvme(void **state)
 }
 
 /*
- * Device section with a simple entry qith double quotes ('foo:"bar"')
+ * Device section with a simple entry with double quotes ('foo:"bar"')
  */
 static void test_quoted_hwe(const struct hwt_state *hwt)
 {
@@ -967,7 +967,7 @@ static int setup_string_regex_hwe_dir(void **state)
 }
 
 /*
- * Two identical device entries kv1 and kv2, trival regex ("string").
+ * Two identical device entries kv1 and kv2, trivial regex ("string").
  * Both are added to the main config file.
  * These entries are NOT merged.
  * This could happen in a large multipath.conf file.
@@ -1003,7 +1003,7 @@ static int setup_2_ident_strings_hwe(void **state)
 }
 
 /*
- * Two identical device entries kv1 and kv2, trival regex ("string").
+ * Two identical device entries kv1 and kv2, trivial regex ("string").
  * Both are added to an extra config file.
  * This could happen in a large multipath.conf file.
  *
@@ -1043,7 +1043,7 @@ static int setup_2_ident_strings_both_dir(void **state)
 }
 
 /*
- * Two identical device entries kv1 and kv2, trival regex ("string").
+ * Two identical device entries kv1 and kv2, trivial regex ("string").
  * Both are added to an extra config file.
  * An empty entry kv0 with the same string exists in the main config file.
  *
@@ -1086,7 +1086,7 @@ static int setup_2_ident_strings_both_dir_w_prev(void **state)
 }
 
 /*
- * Two identical device entries kv1 and kv2, trival regex ("string").
+ * Two identical device entries kv1 and kv2, trivial regex ("string").
  * kv1 is added to the main config file, kv2 to a config_dir file.
  * These entries are merged.
  * This case is more important as you may think, because it's equivalent
index 43a477d..f8554da 100644 (file)
@@ -9,7 +9,6 @@
 #include <stddef.h>
 #include <setjmp.h>
 #include <stdlib.h>
-#include <stdbool.h>
 #include <cmocka.h>
 #include <errno.h>
 #include "strbuf.h"