From 4728c8499369c6a3691d638ccd8c6ca997c180ef Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 02 2019 23:56:44 +0000 Subject: import device-mapper-multipath-0.4.9-130.el7 --- diff --git a/.device-mapper-multipath.metadata b/.device-mapper-multipath.metadata new file mode 100644 index 0000000..5ba5987 --- /dev/null +++ b/.device-mapper-multipath.metadata @@ -0,0 +1 @@ +b9f18e2fe72b4f48858dce1ab4148218d39056ec SOURCES/multipath-tools-130222.tgz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85a8481 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/multipath-tools-130222.tgz diff --git a/SOURCES/0001-RH-dont_start_with_no_config.patch b/SOURCES/0001-RH-dont_start_with_no_config.patch new file mode 100644 index 0000000..e894632 --- /dev/null +++ b/SOURCES/0001-RH-dont_start_with_no_config.patch @@ -0,0 +1,16 @@ +--- + multipathd/multipathd.service | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -2,6 +2,7 @@ + Description=Device-Mapper Multipath Device Controller + Before=iscsi.service iscsid.service lvm2-activation-early.service + After=syslog.target ++ConditionPathExists=/etc/multipath.conf + DefaultDependencies=no + Conflicts=shutdown.target + diff --git a/SOURCES/0002-RH-multipath.rules.patch b/SOURCES/0002-RH-multipath.rules.patch new file mode 100644 index 0000000..a910dc1 --- /dev/null +++ b/SOURCES/0002-RH-multipath.rules.patch @@ -0,0 +1,54 @@ +--- + multipath/Makefile | 3 +++ + multipath/multipath.rules | 24 ++++++++++++++++++++++++ + 2 files changed, 27 insertions(+) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- /dev/null ++++ multipath-tools-130222/multipath/multipath.rules +@@ -0,0 +1,24 @@ ++# multipath wants the devmaps presented as meaninglful device names ++# so name them after their devmap name ++SUBSYSTEM!="block", GOTO="end_mpath" ++ ++ENV{MPATH_SBIN_PATH}="/sbin" ++TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" ++ ++ACTION=="add", ENV{DEVTYPE}!="partition", \ ++ ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ ++ TEST=="/etc/multipath.conf", \ ++ PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \ ++ ENV{DM_MULTIPATH_DEVICE_PATH}="1" ++ ++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \ ++ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" ++ ++KERNEL!="dm-*", GOTO="end_mpath" ++ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10" ++ACTION!="change", GOTO="end_mpath" ++ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" ++ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" ++ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" ++RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" ++LABEL="end_mpath" +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -21,12 +21,15 @@ $(EXEC): $(OBJS) + install: + $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ $(INSTALL_PROGRAM) -d $(DESTDIR)/lib/udev/rules.d ++ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/lib/udev/rules.d/62-multipath.rules + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir) + + uninstall: ++ rm $(DESTDIR)/lib/udev/rules.d/62-multipath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) + rm $(DESTDIR)$(mandir)/$(EXEC).8.gz + rm $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz diff --git a/SOURCES/0003-RH-Make-build-system-RH-Fedora-friendly.patch b/SOURCES/0003-RH-Make-build-system-RH-Fedora-friendly.patch new file mode 100644 index 0000000..f293c80 --- /dev/null +++ b/SOURCES/0003-RH-Make-build-system-RH-Fedora-friendly.patch @@ -0,0 +1,109 @@ +From f5e11246063b07d6dce6d37d3b74662475baa981 Mon Sep 17 00:00:00 2001 +From: Fabio M. Di Nitto +Date: Thu, 15 Oct 2009 04:39:27 +0200 +Subject: [PATCH 08/12] RH: Make build system RH/Fedora friendly + +Signed-off-by: Fabio M. Di Nitto +--- +:100644 100644 7ec25d5... 06fb625... M Makefile.inc +:100644 100644 21e4ad4... 06d79c0... M kpartx/Makefile +:100644 100644 32d9ef5... 25e1483... M multipathd/Makefile + Makefile.inc | 2 +- + kpartx/Makefile | 10 +++++----- + libmpathpersist/Makefile | 7 ++----- + libmultipath/Makefile | 2 ++ + multipathd/Makefile | 1 + + 5 files changed, 11 insertions(+), 11 deletions(-) + +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -29,7 +29,7 @@ multipathdir = $(TOPDIR)/libmultipath + mandir = $(prefix)/usr/share/man/man8 + man5dir = $(prefix)/usr/share/man/man5 + man3dir = $(prefix)/usr/share/man/man3 +-rcdir = $(prefix)/etc/init.d ++rcdir = $(prefix)/etc/rc.d/init.d + syslibdir = $(prefix)/$(LIB) + libdir = $(prefix)/$(LIB)/multipath + unitdir = $(prefix)/lib/systemd/system +Index: multipath-tools-130222/kpartx/Makefile +=================================================================== +--- multipath-tools-130222.orig/kpartx/Makefile ++++ multipath-tools-130222/kpartx/Makefile +@@ -26,17 +26,17 @@ $(EXEC): $(OBJS) + install: $(EXEC) $(EXEC).8 + $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir) +- $(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir) +- $(INSTALL_PROGRAM) -m 755 kpartx_id $(DESTDIR)$(libudevdir) +- $(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d +- $(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/ ++# $(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir) ++# $(INSTALL_PROGRAM) -m 755 kpartx_id $(DESTDIR)$(libudevdir) ++# $(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d ++# $(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/ + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + + uninstall: + rm -f $(DESTDIR)$(bindir)/$(EXEC) + rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz +- rm -f $(DESTDIR)$(libudevdir)/kpartx_id ++# rm -f $(DESTDIR)$(libudevdir)/kpartx_id + + clean: + rm -f core *.o $(EXEC) *.gz +Index: multipath-tools-130222/multipathd/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipathd/Makefile ++++ multipath-tools-130222/multipathd/Makefile +@@ -35,6 +35,7 @@ install: + $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(rcdir) ++ $(INSTALL_PROGRAM) -m 755 multipathd.init.redhat $(DESTDIR)$(rcdir)/$(EXEC) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(unitdir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).service $(DESTDIR)$(unitdir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -46,9 +46,11 @@ install: + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir) ++ ln -sf $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) + + uninstall: + rm -f $(DESTDIR)$(syslibdir)/$(LIBS) ++ rm -f $(DESTDIR)$(syslibdir)/$(DEVLIB) + + clean: + rm -f core *.a *.o *.gz *.so *.so.* +Index: multipath-tools-130222/libmpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/Makefile ++++ multipath-tools-130222/libmpathpersist/Makefile +@@ -28,17 +28,14 @@ $(LIBS): + install: $(LIBS) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) +- $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(man3dir) +- $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/include/ +- $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/share/doc/mpathpersist/ +- ln -sf $(DESTDIR)$(syslibdir)/$(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ ln -sf $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) + install -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir) + install -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir) +- install -m 644 mpath_persist.h $(DESTDIR)/usr/include/ + + uninstall: + rm -f $(DESTDIR)$(syslibdir)/$(LIBS) ++ rm -f $(DESTDIR)$(syslibdir)/$(DEVLIB) + rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_in.3.gz + rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_out.3.gz + diff --git a/SOURCES/0004-RH-multipathd-blacklist-all-by-default.patch b/SOURCES/0004-RH-multipathd-blacklist-all-by-default.patch new file mode 100644 index 0000000..2dda63c --- /dev/null +++ b/SOURCES/0004-RH-multipathd-blacklist-all-by-default.patch @@ -0,0 +1,64 @@ +From 61b2002c6b2752c15b431e400cd614edc8c5b039 Mon Sep 17 00:00:00 2001 +From: Fabio M. Di Nitto +Date: Mon, 19 Oct 2009 07:05:45 +0200 +Subject: [PATCH 09/12] RH: multipathd blacklist all by default + +If there is no configuration installed on the system, blacklist +everything by default. + +BZ#528059 + +Signed-off-by: Fabio M. Di Nitto +--- +:100644 100644 e7e962e... 5aa1ab0... M libmultipath/config.c +:100644 100644 86b1320... 7e90e75... M libmultipath/config.h + libmultipath/config.c | 16 ++++++++++++++++ + libmultipath/config.h | 1 + + 2 files changed, 17 insertions(+) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -21,6 +21,7 @@ + #include "defaults.h" + #include "prio.h" + #include "devmapper.h" ++#include "version.h" + + static int + hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2) +@@ -585,6 +586,21 @@ load_config (char * file) + + } else { + init_keywords(); ++ condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); ++ condlog(0, "A default multipath.conf file is located at"); ++ condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE)); ++ if (conf->blist_devnode == NULL) { ++ conf->blist_devnode = vector_alloc(); ++ if (!conf->blist_devnode) { ++ condlog(0, "cannot allocate blacklist\n"); ++ goto out; ++ } ++ } ++ if (store_ble(conf->blist_devnode, strdup(".*"), ++ ORIGIN_NO_CONFIG)) { ++ condlog(0, "cannot store default no-config blacklist\n"); ++ goto out; ++ } + } + + /* +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -6,6 +6,7 @@ + + #define ORIGIN_DEFAULT 0 + #define ORIGIN_CONFIG 1 ++#define ORIGIN_NO_CONFIG 2 + + /* + * In kernel, fast_io_fail == 0 means immediate failure on rport delete. diff --git a/SOURCES/0005-RH-add-mpathconf.patch b/SOURCES/0005-RH-add-mpathconf.patch new file mode 100644 index 0000000..ce1b2c7 --- /dev/null +++ b/SOURCES/0005-RH-add-mpathconf.patch @@ -0,0 +1,494 @@ +--- + libmultipath/config.c | 1 + multipath/Makefile | 5 + multipath/main.c | 4 + multipath/mpathconf | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++ + multipath/mpathconf.8 | 103 ++++++++++++++++ + 5 files changed, 423 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -589,6 +589,7 @@ load_config (char * file) + condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); + condlog(0, "A default multipath.conf file is located at"); + condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE)); ++ condlog(0, "You can run /sbin/mpathconf to create or modify /etc/multipath.conf"); + if (conf->blist_devnode == NULL) { + conf->blist_devnode = vector_alloc(); + if (!conf->blist_devnode) { +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -17,22 +17,27 @@ $(EXEC): $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) + $(GZIP) $(EXEC).8 > $(EXEC).8.gz + $(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz ++ $(GZIP) mpathconf.8 > mpathconf.8.gz + + install: + $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/ + $(INSTALL_PROGRAM) -d $(DESTDIR)/lib/udev/rules.d + $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/lib/udev/rules.d/62-multipath.rules + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir) ++ $(INSTALL_PROGRAM) -m 644 mpathconf.8.gz $(DESTDIR)$(mandir) + + uninstall: + rm $(DESTDIR)/lib/udev/rules.d/62-multipath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) ++ rm $(DESTDIR)$(bindir)/mpathconf + rm $(DESTDIR)$(mandir)/$(EXEC).8.gz + rm $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz ++ rm $(DESTDIR)$(mandir)/mpathconf.8.gz + + clean: + rm -f core *.o $(EXEC) *.gz +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -433,10 +433,10 @@ main (int argc, char *argv[]) + exit(1); + } + +- if (dm_prereq()) ++ if (load_config(DEFAULT_CONFIGFILE)) + exit(1); + +- if (load_config(DEFAULT_CONFIGFILE)) ++ if (dm_prereq()) + exit(1); + + while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) { +Index: multipath-tools-130222/multipath/mpathconf +=================================================================== +--- /dev/null ++++ multipath-tools-130222/multipath/mpathconf +@@ -0,0 +1,312 @@ ++#!/bin/sh ++# ++# Copyright (C) 2010 Red Hat, Inc. All rights reserved. ++# ++# This file is part of the device-mapper-multipath package. ++# ++# This copyrighted material is made available to anyone wishing to use, ++# modify, copy, or redistribute it subject to the terms and conditions ++# of the GNU General Public License v.2. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software Foundation, ++# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++# ++# Simple editting of /etc/multipath.conf ++# This program was largely ripped off from lvmconf ++# ++ ++unset ENABLE FIND FRIENDLY MODULE MULTIPATHD HAVE_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_DEFAULTS HAVE_FRIENDLY HAVE_MULTIPATHD HAVE_MODULE SHOW_STATUS CHANGED_CONFIG ++ ++DEFAULT_CONFIGFILE="/usr/share/doc/device-mapper-multipath-0.4.9/multipath.conf" ++CONFIGFILE="/etc/multipath.conf" ++MULTIPATHDIR="/etc/multipath" ++TMPFILE=/etc/multipath/.multipath.conf.tmp ++ ++function usage ++{ ++ echo "usage: $0 " ++ echo "" ++ echo "Commands:" ++ echo "Enable: --enable " ++ echo "Disable: --disable" ++ echo "Set user_friendly_names (Default n): --user_friendly_names " ++ echo "Set find_multipaths (Default n): --find_multipaths " ++ echo "Load the dm-multipath modules on enable (Default y): --with_module " ++ echo "start/stop/reload multipathd (Default n): --with_multipathd " ++ echo "" ++} ++ ++function parse_args ++{ ++ while [ -n "$1" ]; do ++ case $1 in ++ --enable) ++ ENABLE=1 ++ shift ++ ;; ++ --disable) ++ ENABLE=0 ++ shift ++ ;; ++ --user_friendly_names) ++ if [ -n "$2" ]; then ++ FRIENDLY=$2 ++ shift 2 ++ else ++ usage ++ exit 1 ++ fi ++ ;; ++ --find_multipaths) ++ if [ -n "$2" ]; then ++ FIND=$2 ++ shift 2 ++ else ++ usage ++ exit 1 ++ fi ++ ;; ++ --with_module) ++ if [ -n "$2" ]; then ++ MODULE=$2 ++ shift 2 ++ else ++ usage ++ exit 1 ++ fi ++ ;; ++ --with_multipathd) ++ if [ -n "$2" ]; then ++ MULTIPATHD=$2 ++ shift 2 ++ else ++ usage ++ exit 1 ++ fi ++ ;; ++ *) ++ usage ++ exit ++ esac ++ done ++} ++ ++function validate_args ++{ ++ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$MODULE" ]; then ++ echo "ignoring extra parameters on disable" ++ FRIENDLY="" ++ FIND="" ++ MODULE="" ++ fi ++ if [ -n "$FRIENDLY" ] && [ "$FRIENDLY" != "y" -a "$FRIENDLY" != "n" ]; then ++ echo "--user_friendly_names must be either 'y' or 'n'" ++ exit 1 ++ fi ++ if [ -n "$FIND" ] && [ "$FIND" != "y" -a "$FIND" != "n" ]; then ++ echo "--find_multipaths must be either 'y' or 'n'" ++ exit 1 ++ fi ++ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" ]; then ++ SHOW_STATUS=1 ++ fi ++ if [ -n "$MODULE" ] && [ "$MODULE" != "y" -a "$MODULE" != "n" ]; then ++ echo "--with_module must be either 'y' or 'n'" ++ exit 1 ++ fi ++ if [ -n "$MULTIPATHD" ] && [ "$MULTIPATHD" != "y" -a "$MULTIPATHD" != "n" ]; then ++ echo "--with_multipathd must be either 'y' or 'n'" ++ exit 1 ++ fi ++} ++ ++umask 0077 ++ ++parse_args "$@" ++ ++validate_args ++ ++if [ ! -d "$MULTIPATHDIR" ]; then ++ echo "/etc/multipath/ does not exist. failing" ++ exit 1 ++fi ++ ++rm $TMPFILE 2> /dev/null ++if [ -f "$CONFIGFILE" ]; then ++ cp $CONFIGFILE $TMPFILE ++elif [ -f "$DEFAULT_CONFIGFILE" ]; then ++ cp $DEFAULT_CONFIGFILE $TMPFILE ++else ++ touch $TMPFILE ++fi ++ ++if grep -q "^blacklist[[:space:]]*{" $TMPFILE ; then ++ HAVE_BLACKLIST=1 ++fi ++ ++if grep -q "^defaults[[:space:]]*{" $TMPFILE ; then ++ HAVE_DEFAULTS=1 ++fi ++ ++if [ -z "$MODULE" -o "$MODULE" = "y" ]; then ++ if lsmod | grep -q "dm_multipath" ; then ++ HAVE_MODULE=1 ++ else ++ HAVE_MODULE=0 ++ fi ++fi ++ ++if [ "$MULTIPATHD" = "y" ]; then ++ if service multipathd status > /dev/null ; then ++ HAVE_MULTIPATHD=1 ++ else ++ HAVE_MULTIPATHD=0 ++ fi ++fi ++ ++if [ "$HAVE_BLACKLIST" = "1" ]; then ++ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode \"\.\?\*\"" ; then ++ HAVE_DISABLE=1 ++ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[#[:space:]]*devnode \"\.\?\*\"" ; then ++ HAVE_DISABLE=0 ++ fi ++fi ++ ++if [ "$HAVE_DEFAULTS" = "1" ]; then ++ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)" ; then ++ HAVE_FIND=1 ++ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(no\|0\)" ; then ++ HAVE_FIND=0 ++ fi ++ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)" ; then ++ HAVE_FRIENDLY=1 ++ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)" ; then ++ HAVE_FRIENDLY=0 ++ fi ++fi ++ ++if [ -n "$SHOW_STATUS" ]; then ++ if [ -z "$HAVE_DISABLE" -o "$HAVE_DISABLE" = 0 ]; then ++ echo "multipath is enabled" ++ else ++ echo "multipath is disabled" ++ fi ++ if [ -z "$HAVE_FIND" -o "$HAVE_FIND" = 0 ]; then ++ echo "find_multipaths is disabled" ++ else ++ echo "find_multipaths is enabled" ++ fi ++ if [ -z "$HAVE_FRIENDLY" -o "$HAVE_FRIENDLY" = 0 ]; then ++ echo "user_friendly_names is disabled" ++ else ++ echo "user_friendly_names is enabled" ++ fi ++ if [ -n "$HAVE_MODULE" ]; then ++ if [ "$HAVE_MODULE" = 1 ]; then ++ echo "dm_multipath module is loaded" ++ else ++ echo "dm_multipath module is not loaded" ++ fi ++ fi ++ if [ -n "$HAVE_MULTIPATHD" ]; then ++ service multipathd status ++ fi ++ exit 0 ++fi ++ ++if [ -z "$HAVE_BLACKLIST" ]; then ++ cat >> $TMPFILE <<- _EOF_ ++ ++blacklist { ++} ++_EOF_ ++fi ++ ++if [ -z "$HAVE_DEFAULTS" ]; then ++ cat >> $TMPFILE <<- _EOF_ ++ ++defaults { ++} ++_EOF_ ++fi ++ ++if [ "$ENABLE" = 1 ]; then ++ if [ "$HAVE_DISABLE" = 1 ]; then ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE ++ fi ++elif [ "$ENABLE" = 0 ]; then ++ if [ -z "$HAVE_DISABLE" ]; then ++ sed -i '/^blacklist[[:space:]]*{/ a\ ++ devnode "*" ++' $TMPFILE ++ elif [ "$HAVE_DISABLE" = 0 ]; then ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[#[:space:]]*devnode \"\.\?\*\"/ devnode ".*"/' $TMPFILE ++ fi ++fi ++ ++if [ "$FIND" = "n" ]; then ++ if [ "$HAVE_FIND" = 1 ]; then ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)/ find_multipaths no/' $TMPFILE ++ CHANGED_CONFIG=1 ++ fi ++elif [ "$FIND" = "y" ]; then ++ if [ -z "$HAVE_FIND" ]; then ++ sed -i '/^defaults[[:space:]]*{/ a\ ++ find_multipaths yes ++' $TMPFILE ++ CHANGED_CONFIG=1 ++ elif [ "$HAVE_FIND" = 0 ]; then ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*find_multipaths[[:space:]]*\(no\|0\)/ find_multipaths yes/' $TMPFILE ++ CHANGED_CONFIG=1 ++ fi ++fi ++ ++if [ "$FRIENDLY" = "n" ]; then ++ if [ "$HAVE_FRIENDLY" = 1 ]; then ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(yes\|1\)/ user_friendly_names no/' $TMPFILE ++ CHANGED_CONFIG=1 ++ fi ++elif [ "$FRIENDLY" = "y" ]; then ++ if [ -z "$HAVE_FRIENDLY" ]; then ++ sed -i '/^defaults[[:space:]]*{/ a\ ++ user_friendly_names yes ++' $TMPFILE ++ CHANGED_CONFIG=1 ++ elif [ "$HAVE_FRIENDLY" = 0 ]; then ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*user_friendly_names[[:space:]]*\(no\|0\)/ user_friendly_names yes/' $TMPFILE ++ CHANGED_CONFIG=1 ++ fi ++fi ++ ++if [ -f "$CONFIGFILE" ]; then ++ cp $CONFIGFILE $CONFIGFILE.old ++ if [ $? != 0 ]; then ++ echo "failed to backup old config file, $CONFIGFILE not updated" ++ exit 1 ++ fi ++fi ++ ++cp $TMPFILE $CONFIGFILE ++if [ $? != 0 ]; then ++ echo "failed to copy new config file into place, check $CONFIGFILE is still OK" ++ exit 1 ++fi ++ ++rm -f $TMPFILE ++ ++if [ "$ENABLE" = 1 ]; then ++ if [ "$HAVE_MODULE" = 0 ]; then ++ modprobe dm_multipath ++ fi ++ if [ "$HAVE_MULTIPATHD" = 0 ]; then ++ service multipathd start ++ fi ++elif [ "$ENABLE" = 0 ]; then ++ if [ "$HAVE_MULTIPATHD" = 1 ]; then ++ service multipathd stop ++ fi ++elif [ -n "$CHANGED_CONFIG" -a "$HAVE_MULTIPATHD" = 1 ]; then ++ service multipathd reload ++fi +Index: multipath-tools-130222/multipath/mpathconf.8 +=================================================================== +--- /dev/null ++++ multipath-tools-130222/multipath/mpathconf.8 +@@ -0,0 +1,103 @@ ++.TH MPATHCONF 8 "June 2010" "" "Linux Administrator's Manual" ++.SH NAME ++mpathconf - A tool for configuring device-mapper-multipath ++.SH SYNOPSIS ++.B mpathconf ++.RB [\| commands \|] ++.RB [\| options \|] ++.SH DESCRIPTION ++.B mpathconf ++is a utility that creates or modifies ++.B /etc/multipath.conf. ++It can enable or disable multipathing and configure some common options. ++.B mpathconf ++can also load the ++.B dm_multipath ++module, start and stop the ++.B multipathd ++daemon, and configure the ++.B multipathd ++service to start automatically or not. If ++.B mpathconf ++is called with no commands, it will display the current configuration. ++ ++The default options for mpathconf are ++.B --with_module ++The ++.B --with_multipathd ++option is not set by default. Enabling multipathing will load the ++.B dm_multipath ++module but it will not immediately start it. This is so ++that users can manually edit their config file if necessary, before starting ++.B multipathd. ++ ++If ++.B /etc/multipath.conf ++already exists, mpathconf will edit it. If it does not exist, mpathconf will ++use ++.B /usr/share/doc/device-mapper-multipath-0.4.9/multipath.conf ++as the starting file. This file has ++.B user_friendly_names ++set. If this file does not exist, mpathconf will create ++.B /etc/multipath.conf ++from scratch. For most users, this means that ++.B user_friendly_names ++will be set by default, unless they use the ++.B --user_friendly_names n ++command. ++.SH COMMANDS ++.TP ++.B --enable ++Removes any line that blacklists all device nodes from the ++.B /etc/multipath.conf ++blacklist section. ++.TP ++.B --disable ++Adds a line that blacklists all device nodes to the ++.B /etc/multipath.conf ++blacklist section. If no blacklist section exists, it will create one. ++.TP ++.B --user_friendly_name \fP { \fBy\fP | \fBn\fP } ++If set to \fBy\fP, this adds the line ++.B user_friendly_names yes ++to the ++.B /etc/multipath.conf ++defaults section. If set to \fBn\fP, this removes the line, if present. This ++command can be used along with any other command. ++.TP ++.B --find_multipaths\fP { \fBy\fP | \fBn\fP } ++If set to \fBy\fP, this adds the line ++.B find_multipaths yes ++to the ++.B /etc/multipath.conf ++defaults section. If set to \fBn\fP, this removes the line, if present. This ++command can be used aldong with any other command. ++.SH OPTIONS ++.TP ++.B --with_module\fP { \fBy\fP | \fBn\fP } ++If set to \fBy\fP, this runs ++.B modprobe dm_multipath ++to install the multipath modules. This option only works with the ++.B --enable ++command. This option is set to \fBy\fP by default. ++.TP ++.B --with_multipathd { \fBy\fP | \fBn\fP } ++If set to \fBy\fP, this runs ++.B service multipathd start ++to start the multipathd daemon on \fB--enable\fP, ++.B service multipathd stop ++to start the multipathd daemon on \fB--disable\fP, and ++.B service multipathd reload ++to reconfigure multipathd on \fB--user_frindly_names\fP and ++\fB--find_multipaths\fP. ++This option is set to \fBn\fP by default. ++.SH FILES ++.BR /etc/multipath.conf ++.SH "SEE ALSO" ++.BR multipath.conf (5), ++.BR modprobe (8), ++.BR multipath (8), ++.BR multipathd (8), ++.BR service (8), ++.SH AUTHOR ++Benjamin Marzinski diff --git a/SOURCES/0006-RH-add-find-multipaths.patch b/SOURCES/0006-RH-add-find-multipaths.patch new file mode 100644 index 0000000..4a0c364 --- /dev/null +++ b/SOURCES/0006-RH-add-find-multipaths.patch @@ -0,0 +1,222 @@ +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 1 + + libmultipath/configure.c | 11 +++++++++++ + libmultipath/defaults.h | 1 + + libmultipath/dict.c | 34 ++++++++++++++++++++++++++++++++++ + libmultipath/wwids.c | 26 ++++++++++++++++++++++++++ + libmultipath/wwids.h | 1 + + multipath/main.c | 2 +- + multipathd/main.c | 6 ++++++ + 9 files changed, 82 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -547,6 +547,7 @@ load_config (char * file) + conf->reassign_maps = DEFAULT_REASSIGN_MAPS; + conf->checkint = DEFAULT_CHECKINT; + conf->max_checkint = MAX_CHECKINT(conf->checkint); ++ conf->find_multipaths = DEFAULT_FIND_MULTIPATHS; + conf->fast_io_fail = DEFAULT_FAST_IO_FAIL; + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; + conf->detect_prio = DEFAULT_DETECT_PRIO; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -508,6 +508,10 @@ coalesce_paths (struct vectors * vecs, v + + memset(empty_buff, 0, WWID_SIZE); + ++ /* ignore refwwid if it's empty */ ++ if (refwwid && !strlen(refwwid)) ++ refwwid = NULL; ++ + if (force_reload) { + vector_foreach_slot (pathvec, pp1, k) { + pp1->mpp = NULL; +@@ -537,6 +541,13 @@ coalesce_paths (struct vectors * vecs, v + if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE)) + continue; + ++ /* If find_multipaths was selected check if the path is valid */ ++ if (conf->find_multipaths && !refwwid && ++ !should_multipath(pp1, pathvec)) { ++ orphan_path(pp1); ++ continue; ++ } ++ + /* + * at this point, we know we really got a new mp + */ +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -15,6 +15,7 @@ + #define DEFAULT_USER_FRIENDLY_NAMES 0 + #define DEFAULT_VERBOSITY 2 + #define DEFAULT_REASSIGN_MAPS 1 ++#define DEFAULT_FIND_MULTIPATHS 0 + #define DEFAULT_FAST_IO_FAIL 5 + #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF + #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -585,6 +585,27 @@ def_reservation_key_handler(vector strve + } + + static int ++def_find_multipaths_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->find_multipaths = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->find_multipaths = 1; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + def_names_handler(vector strvec) + { + char * buff; +@@ -2700,6 +2721,18 @@ snprint_def_log_checker_err (char * buff + } + + static int ++snprint_def_find_multipaths (char * buff, int len, void * data) ++{ ++ if (conf->find_multipaths == DEFAULT_FIND_MULTIPATHS) ++ return 0; ++ if (!conf->find_multipaths) ++ return snprintf(buff, len, "no"); ++ ++ return snprintf(buff, len, "yes"); ++} ++ ++ ++static int + snprint_def_user_friendly_names (char * buff, int len, void * data) + { + if (conf->user_friendly_names == USER_FRIENDLY_NAMES_ON) +@@ -2833,6 +2866,7 @@ init_keywords(void) + install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file); + install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err); + install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key); ++ install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths); + install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler); + install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -125,6 +125,32 @@ out: + } + + int ++should_multipath(struct path *pp1, vector pathvec) ++{ ++ int i; ++ struct path *pp2; ++ ++ condlog(4, "checking if %s should be multipathed", pp1->dev); ++ vector_foreach_slot(pathvec, pp2, i) { ++ if (pp1->dev == pp2->dev) ++ continue; ++ if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) { ++ condlog(3, "found multiple paths with wwid %s, " ++ "multipathing %s", pp1->wwid, pp1->dev); ++ return 1; ++ } ++ } ++ if (check_wwids_file(pp1->wwid, 0) < 0) { ++ condlog(3, "wwid %s not in wwids file, skipping %s", ++ pp1->wwid, pp1->dev); ++ return 0; ++ } ++ condlog(3, "found wwid %s in wwids file, multipathing %s", pp1->wwid, ++ pp1->dev); ++ return 1; ++} ++ ++int + remember_wwid(char *wwid) + { + int ret = check_wwids_file(wwid, 1); +Index: multipath-tools-130222/libmultipath/wwids.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.h ++++ multipath-tools-130222/libmultipath/wwids.h +@@ -12,6 +12,7 @@ + "#\n" \ + "# Valid WWIDs:\n" + ++int should_multipath(struct path *pp, vector pathvec); + int remember_wwid(char *wwid); + int check_wwids_file(char *wwid, int write_wwid); + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -333,7 +333,7 @@ configure (void) + /* + * core logic entry point + */ +- r = coalesce_paths(&vecs, NULL, NULL, conf->force_reload); ++ r = coalesce_paths(&vecs, NULL, refwwid, conf->force_reload); + + out: + if (refwwid) +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -471,6 +472,11 @@ rescan: + return 1; + } + ++ if (conf->find_multipaths && ++ !should_multipath(pp, vecs->pathvec)) { ++ orphan_path(pp); ++ return 0; ++ } + condlog(4,"%s: creating new map", pp->dev); + if ((mpp = add_map_with_path(vecs, pp, 1))) { + mpp->action = ACT_CREATE; +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -106,6 +106,7 @@ struct config { + unsigned int dev_loss; + int log_checker_err; + int allow_queueing; ++ int find_multipaths; + uid_t uid; + gid_t gid; + mode_t mode; diff --git a/SOURCES/0007-RH-add-hp_tur-checker.patch b/SOURCES/0007-RH-add-hp_tur-checker.patch new file mode 100644 index 0000000..bc8d73b --- /dev/null +++ b/SOURCES/0007-RH-add-hp_tur-checker.patch @@ -0,0 +1,274 @@ +--- + libmultipath/checkers.h | 3 + + libmultipath/checkers/Makefile | 4 + + libmultipath/checkers/tur.c | 123 +++++++++++++++++++++++++++++++++++++++-- + multipath.conf.annotated | 5 + + 4 files changed, 128 insertions(+), 7 deletions(-) + +Index: multipath-tools-120613/libmultipath/checkers.h +=================================================================== +--- multipath-tools-120613.orig/libmultipath/checkers.h ++++ multipath-tools-120613/libmultipath/checkers.h +@@ -60,6 +60,7 @@ enum path_check_state { + + #define DIRECTIO "directio" + #define TUR "tur" ++#define HP_TUR "hp_tur" + #define HP_SW "hp_sw" + #define RDAC "rdac" + #define EMC_CLARIION "emc_clariion" +@@ -77,6 +78,7 @@ enum path_check_state { + #define CHECKER_MSG_LEN 256 + #define CHECKER_DEV_LEN 256 + #define LIB_CHECKER_NAMELEN 256 ++#define WWID_SIZE 128 + + struct checker { + struct list_head node; +@@ -88,6 +90,7 @@ struct checker { + int disable; + char name[CHECKER_NAME_LEN]; + char message[CHECKER_MSG_LEN]; /* comm with callers */ ++ char wwid[WWID_SIZE]; /* LUN wwid */ + void * context; /* store for persistent data */ + void ** mpcontext; /* store for persistent data shared + multipath-wide. Use MALLOC if +Index: multipath-tools-120613/libmultipath/checkers/Makefile +=================================================================== +--- multipath-tools-120613.orig/libmultipath/checkers/Makefile ++++ multipath-tools-120613/libmultipath/checkers/Makefile +@@ -8,6 +8,7 @@ LIBS= \ + libcheckcciss_tur.so \ + libcheckreadsector0.so \ + libchecktur.so \ ++ libcheckhp_tur.so \ + libcheckdirectio.so \ + libcheckemc_clariion.so \ + libcheckhp_sw.so \ +@@ -23,6 +24,9 @@ libcheckdirectio.so: libsg.o directio.o + libcheck%.so: libsg.o %.o + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ + ++hp_tur.o: tur.c ++ $(CC) $(CFLAGS) -DCHECK_WWID -c -o $@ $< ++ + install: + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) + +Index: multipath-tools-120613/libmultipath/checkers/tur.c +=================================================================== +--- multipath-tools-120613.orig/libmultipath/checkers/tur.c ++++ multipath-tools-120613/libmultipath/checkers/tur.c +@@ -24,12 +24,101 @@ + #define TUR_CMD_LEN 6 + #define HEAVY_CHECK_COUNT 10 + ++#ifdef CHECK_WWID ++#define MSG_TUR_UP "HP tur checker reports path is up" ++#define MSG_TUR_DOWN "HP tur checker reports path is down" ++#define MSG_TUR_GHOST "HP tur checker reports path is in standby state" ++#define MSG_TUR_RUNNING "HP tur checker still running" ++#define MSG_TUR_TIMEOUT "HP tur checker timed out" ++#define MSG_TUR_FAILED "HP tur checker failed to initialize" ++#define EVPD 0x01 ++#define PAGE_83 0x83 ++#define INQUIRY_CMD 0x12 ++#define INQUIRY_CMDLEN 6 ++#define SCSI_INQ_BUFF_LEN 96 ++#else + #define MSG_TUR_UP "tur checker reports path is up" + #define MSG_TUR_DOWN "tur checker reports path is down" + #define MSG_TUR_GHOST "tur checker reports path is in standby state" + #define MSG_TUR_RUNNING "tur checker still running" + #define MSG_TUR_TIMEOUT "tur checker timed out" + #define MSG_TUR_FAILED "tur checker failed to initialize" ++#endif ++ ++#ifdef CHECK_WWID ++static int ++do_inq(int fd, unsigned int timeout, char * wwid) ++{ ++ int ret = -1; ++ unsigned char inq_cmd[INQUIRY_CMDLEN] = ++ {INQUIRY_CMD, EVPD, PAGE_83, 0, SCSI_INQ_BUFF_LEN, 0 }; ++ unsigned char sense_buffer[32]; ++ unsigned char resp_buffer[SCSI_INQ_BUFF_LEN]; ++ char *pbuff; ++ ++ int m,k; ++ int retry_tur = 5; ++ struct sg_io_hdr io_hdr; ++ ++retry: ++ memset(resp_buffer, 0, sizeof(resp_buffer)); ++ memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); ++ ++ io_hdr.interface_id = 'S'; ++ io_hdr.cmd_len = sizeof(inq_cmd); ++ io_hdr.mx_sb_len = sizeof(sense_buffer); ++ io_hdr.dxfer_direction = -3; // Data transfer from the device. ++ io_hdr.dxfer_len = sizeof(resp_buffer); ++ io_hdr.dxferp = (unsigned char *)resp_buffer; ++ io_hdr.cmdp = inq_cmd; ++ io_hdr.sbp = sense_buffer; ++ io_hdr.timeout = timeout; // IOCTL timeout value. ++ ++ if (ioctl(fd, SG_IO, &io_hdr) < 0) { ++ condlog(0, "SG_IO ioctl failed: %s", strerror(errno)); ++ return ret; ++ } ++ if (io_hdr.info & SG_INFO_OK_MASK){ ++ int key = 0, asc, ascq; ++ ++ if (io_hdr.host_status == DID_BUS_BUSY || ++ io_hdr.host_status == DID_ERROR || ++ io_hdr.host_status == DID_TRANSPORT_DISRUPTED) { ++ if (--retry_tur) ++ goto retry; ++ } ++ if (io_hdr.sb_len_wr > 3) { ++ if (io_hdr.sbp[0] == 0x72 || io_hdr.sbp[0] == 0x73) { ++ key = io_hdr.sbp[1] & 0x0f; ++ asc = io_hdr.sbp[2]; ++ ascq = io_hdr.sbp[3]; ++ } else if (io_hdr.sb_len_wr > 13 && ++ ((io_hdr.sbp[0] & 0x7f) == 0x70 || ++ (io_hdr.sbp[0] & 0x7f) == 0x71)) { ++ key = io_hdr.sbp[2] & 0x0f; ++ asc = io_hdr.sbp[12]; ++ ascq = io_hdr.sbp[13]; ++ } ++ } ++ if (key == 0x6) { ++ /* Unit Attention, retry */ ++ if (--retry_tur) ++ goto retry; ++ } ++ return ret; ++ } ++ ++ pbuff = (char *) resp_buffer; ++ ++ wwid[0] = '3'; ++ for (m = 8, k = 1; m < 11; ++m, k+=2) ++ sprintf(&wwid[k], "%02x", (unsigned int)pbuff[m] & 0xff); ++ for (m = 11; m < 24; ++m, k+=2) ++ sprintf(&wwid[k], "%02x", (unsigned int)pbuff[m] & 0xff); ++ ++ return (ret = 0); ++} ++#endif + + struct tur_checker_context { + dev_t devt; +@@ -43,6 +132,7 @@ struct tur_checker_context { + pthread_cond_t active; + pthread_spinlock_t hldr_lock; + int holders; ++ char wwid[WWID_SIZE]; + char message[CHECKER_MSG_LEN]; + }; + +@@ -100,12 +190,15 @@ void libcheck_free (struct checker * c) + #define TUR_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args); + + int +-tur_check(int fd, unsigned int timeout, char *msg) ++tur_check (int fd, unsigned int timeout, char *msg, char *wwid) + { + struct sg_io_hdr io_hdr; + unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 }; + unsigned char sense_buffer[32]; + int retry_tur = 5; ++#ifdef CHECK_WWID ++ char new_wwid[WWID_SIZE]; ++#endif + + retry: + memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); +@@ -179,6 +272,24 @@ tur_check(int fd, unsigned int timeout, + TUR_MSG(msg, MSG_TUR_DOWN); + return PATH_DOWN; + } ++#ifdef CHECK_WWID ++ if (!do_inq(fd, timeout, new_wwid)) { ++ ++ if(!strcmp(wwid, "\0")) { ++ strcpy(wwid, new_wwid); ++ goto up; ++ } ++ ++ if (strcmp(wwid , new_wwid)) { ++ condlog(0, ++ "hp_tur: Lun collided. new_wwid %s old_wwid %s", ++ new_wwid, wwid); ++ TUR_MSG(msg, MSG_TUR_DOWN); ++ return PATH_DOWN; ++ } ++ } ++up: ++#endif + TUR_MSG(msg, MSG_TUR_UP); + return PATH_UP; + } +@@ -215,7 +326,7 @@ void *tur_thread(void *ctx) + ct->state = PATH_PENDING; + pthread_mutex_unlock(&ct->lock); + +- state = tur_check(ct->fd, ct->timeout, ct->message); ++ state = tur_check(ct->fd, ct->timeout, ct->message, ct->wwid); + + /* TUR checker done */ + pthread_mutex_lock(&ct->lock); +@@ -275,7 +386,7 @@ libcheck_check (struct checker * c) + ct->devt = sb.st_rdev; + + if (c->sync) +- return tur_check(c->fd, c->timeout, c->message); ++ return tur_check(c->fd, c->timeout, c->message, ct->wwid); + + /* + * Async mode +@@ -319,7 +430,8 @@ libcheck_check (struct checker * c) + pthread_mutex_unlock(&ct->lock); + condlog(3, "%d:%d: tur thread not responding, " + "using sync mode", TUR_DEVT(ct)); +- return tur_check(c->fd, c->timeout, c->message); ++ return tur_check(c->fd, c->timeout, c->message, ++ ct->wwid); + } + /* Start new TUR checker */ + ct->state = PATH_UNCHECKED; +@@ -337,7 +449,8 @@ libcheck_check (struct checker * c) + ct->holders--; + condlog(3, "%d:%d: failed to start tur thread, using" + " sync mode", TUR_DEVT(ct)); +- return tur_check(c->fd, c->timeout, c->message); ++ return tur_check(c->fd, c->timeout, c->message, ++ ct->wwid); + } + pthread_attr_destroy(&attr); + tur_timeout(&tsp); +Index: multipath-tools-120613/multipath.conf.annotated +=================================================================== +--- multipath-tools-120613.orig/multipath.conf.annotated ++++ multipath-tools-120613/multipath.conf.annotated +@@ -96,7 +96,8 @@ + # # name : path_checker, checker + # # scope : multipath & multipathd + # # desc : the default method used to determine the paths' state +-# # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac|cciss_tur ++# # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac| ++# cciss_tur|hp_tur + # # default : directio + # # + # path_checker directio +@@ -493,7 +494,7 @@ + # # scope : multipathd & multipathd + # # desc : path checking algorithm to use to check path state + # # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac| +-# # cciss_tur ++# # cciss_tur|hp_tur + # # + # path_checker directio + # diff --git a/SOURCES/0008-RH-revert-partition-changes.patch b/SOURCES/0008-RH-revert-partition-changes.patch new file mode 100644 index 0000000..c563b0e --- /dev/null +++ b/SOURCES/0008-RH-revert-partition-changes.patch @@ -0,0 +1,45 @@ +--- + kpartx/dos.c | 2 -- + kpartx/kpartx.c | 9 ++++++--- + 2 files changed, 6 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/kpartx/dos.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/dos.c ++++ multipath-tools-130222/kpartx/dos.c +@@ -98,8 +98,6 @@ read_dos_pt(int fd, struct slice all, st + break; + } + if (is_extended(p.sys_type)) { +- sp[i].size = 2; /* extended partitions only get two +- sectors mapped for LILO to install */ + n += read_extended_partition(fd, &p, i, sp+n, ns-n); + } + } +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -516,6 +516,7 @@ main(int argc, char **argv){ + d = c; + while (c) { + for (j = 0; j < n; j++) { ++ uint64_t start; + int k = slices[j].container - 1; + + if (slices[j].size == 0) +@@ -541,9 +542,11 @@ main(int argc, char **argv){ + } + strip_slash(partname); + +- if (safe_sprintf(params, "%s %" PRIu64, +- device, +- slices[j].start)) { ++ start = slices[j].start - slices[k].start; ++ if (safe_sprintf(params, "%d:%d %" PRIu64, ++ slices[k].major, ++ slices[k].minor, ++ start)) { + fprintf(stderr, "params too small\n"); + exit(1); + } diff --git a/SOURCES/0009-RH-RHEL5-style-partitions.patch b/SOURCES/0009-RH-RHEL5-style-partitions.patch new file mode 100644 index 0000000..a2691bb --- /dev/null +++ b/SOURCES/0009-RH-RHEL5-style-partitions.patch @@ -0,0 +1,327 @@ +--- + kpartx/bsd.c | 35 --------------- + kpartx/dos.c | 7 +-- + kpartx/kpartx.c | 123 +++++++------------------------------------------------- + kpartx/kpartx.h | 1 + kpartx/sun.c | 35 --------------- + 5 files changed, 24 insertions(+), 177 deletions(-) + +Index: multipath-tools-130222/kpartx/bsd.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/bsd.c ++++ multipath-tools-130222/kpartx/bsd.c +@@ -50,10 +50,10 @@ int + read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) { + struct bsd_disklabel *l; + struct bsd_partition *p; +- unsigned int offset = all.start, end; ++ unsigned int offset = all.start; + int max_partitions; + char *bp; +- int n = 0, i, j; ++ int n = 0; + + bp = getblock(fd, offset+1); /* 1 sector suffices */ + if (bp == NULL) +@@ -79,36 +79,5 @@ read_bsd_pt(int fd, struct slice all, st + break; + } + } +- /* +- * Convention has it that the bsd disklabel will always have +- * the 'c' partition spanning the entire disk. +- * So we have to check for contained slices. +- */ +- for(i = 0; i < n; i++) { +- if (sp[i].size == 0) +- continue; +- +- end = sp[i].start + sp[i].size; +- for(j = 0; j < n; j ++) { +- if ( i == j ) +- continue; +- if (sp[j].size == 0) +- continue; +- +- if (sp[i].start < sp[j].start) { +- if (end > sp[j].start && +- end < sp[j].start + sp[j].size) { +- /* Invalid slice */ +- fprintf(stderr, +- "bsd_disklabel: slice %d overlaps with %d\n", i , j); +- sp[i].size = 0; +- } +- } else { +- if (end <= sp[j].start + sp[j].size) { +- sp[i].container = j + 1; +- } +- } +- } +- } + return n; + } +Index: multipath-tools-130222/kpartx/dos.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/dos.c ++++ multipath-tools-130222/kpartx/dos.c +@@ -16,7 +16,7 @@ is_extended(int type) { + } + + static int +-read_extended_partition(int fd, struct partition *ep, int en, ++read_extended_partition(int fd, struct partition *ep, + struct slice *sp, int ns) + { + struct partition p; +@@ -53,7 +53,6 @@ read_extended_partition(int fd, struct p + if (n < ns) { + sp[n].start = here + le32_to_cpu(p.start_sect); + sp[n].size = le32_to_cpu(p.nr_sects); +- sp[n].container = en + 1; + n++; + } else { + fprintf(stderr, +@@ -98,7 +97,9 @@ read_dos_pt(int fd, struct slice all, st + break; + } + if (is_extended(p.sys_type)) { +- n += read_extended_partition(fd, &p, i, sp+n, ns-n); ++ n += read_extended_partition(fd, &p, sp+n, ns-n); ++ /* hide the extended partition itself */ ++ sp[i].size = 2; + } + } + return n; +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -192,7 +192,7 @@ get_hotplug_device(void) + + int + main(int argc, char **argv){ +- int i, j, m, n, op, off, arg, c, d, ro=0; ++ int i, j, m, n, op, off, arg, ro=0; + int fd = -1; + struct slice all; + struct pt *ptp; +@@ -381,49 +381,30 @@ main(int argc, char **argv){ + else + continue; + ++ /* ++ * test for overlap, as in the case of an extended partition ++ * zero their size to avoid mapping ++ */ ++ for (j = 0; j < n; j++) { ++ for (m = j + 1; m < n; m++) { ++ if (slices[m].start > slices[j].start && ++ slices[m].start < slices[j].start + ++ slices[j].size) ++ slices[j].size = 0; ++ } ++ } ++ + switch(what) { + case LIST: +- for (j = 0, c = 0, m = 0; j < n; j++) { ++ for (j = 0; j < n; j++) { + if (slices[j].size == 0) + continue; +- if (slices[j].container > 0) { +- c++; +- continue; +- } +- +- slices[j].minor = m++; + + printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n", + mapname, delim, j+1, + slices[j].size, device, + slices[j].start); + } +- /* Loop to resolve contained slices */ +- d = c; +- while (c) { +- for (j = 0; j < n; j++) { +- uint64_t start; +- int k = slices[j].container - 1; +- +- if (slices[j].size == 0) +- continue; +- if (slices[j].minor > 0) +- continue; +- if (slices[j].container == 0) +- continue; +- slices[j].minor = m++; +- +- start = slices[j].start - slices[k].start; +- printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n", +- mapname, delim, j+1, +- slices[j].size, +- slices[k].minor, start); +- c--; +- } +- /* Terminate loop if nothing more to resolve */ +- if (d == c) +- break; +- } + + break; + +@@ -462,16 +443,10 @@ main(int argc, char **argv){ + case ADD: + case UPDATE: + /* ADD and UPDATE share the same code that adds new partitions. */ +- for (j = 0, c = 0; j < n; j++) { ++ for (j = 0; j < n; j++) { + if (slices[j].size == 0) + continue; + +- /* Skip all contained slices */ +- if (slices[j].container > 0) { +- c++; +- continue; +- } +- + if (safe_sprintf(partname, "%s%s%d", + mapname, delim, j+1)) { + fprintf(stderr, "partname too small\n"); +@@ -512,72 +487,6 @@ main(int argc, char **argv){ + slices[j].minor, slices[j].size, + DM_TARGET, params); + } +- /* Loop to resolve contained slices */ +- d = c; +- while (c) { +- for (j = 0; j < n; j++) { +- uint64_t start; +- int k = slices[j].container - 1; +- +- if (slices[j].size == 0) +- continue; +- +- /* Skip all existing slices */ +- if (slices[j].minor > 0) +- continue; +- +- /* Skip all simple slices */ +- if (slices[j].container == 0) +- continue; +- +- /* Check container slice */ +- if (slices[k].size == 0) +- fprintf(stderr, "Invalid slice %d\n", +- k); +- +- if (safe_sprintf(partname, "%s%s%d", +- mapname, delim, j+1)) { +- fprintf(stderr, "partname too small\n"); +- exit(1); +- } +- strip_slash(partname); +- +- start = slices[j].start - slices[k].start; +- if (safe_sprintf(params, "%d:%d %" PRIu64, +- slices[k].major, +- slices[k].minor, +- start)) { +- fprintf(stderr, "params too small\n"); +- exit(1); +- } +- +- op = (dm_map_present(partname) ? +- DM_DEVICE_RELOAD : DM_DEVICE_CREATE); +- +- dm_addmap(op, partname, DM_TARGET, params, +- slices[j].size, ro, uuid, j+1, +- buf.st_mode & 0777, +- buf.st_uid, buf.st_gid, +- &cookie); +- +- if (op == DM_DEVICE_RELOAD) +- dm_simplecmd(DM_DEVICE_RESUME, +- partname, 1, +- &cookie); +- +- dm_devn(partname, &slices[j].major, +- &slices[j].minor); +- +- if (verbose) +- printf("add map %s : 0 %" PRIu64 " %s %s\n", +- partname, slices[j].size, +- DM_TARGET, params); +- c--; +- } +- /* Terminate loop */ +- if (d == c) +- break; +- } + + if (what == ADD) { + /* Skip code that removes devmappings for deleted partitions */ +Index: multipath-tools-130222/kpartx/kpartx.h +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.h ++++ multipath-tools-130222/kpartx/kpartx.h +@@ -24,7 +24,6 @@ + struct slice { + uint64_t start; + uint64_t size; +- int container; + int major; + int minor; + }; +Index: multipath-tools-130222/kpartx/sun.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/sun.c ++++ multipath-tools-130222/kpartx/sun.c +@@ -62,8 +62,8 @@ int + read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) { + struct sun_disk_label *l; + struct sun_raw_part *s; +- unsigned int offset = all.start, end; +- int i, j, n; ++ unsigned int offset = all.start; ++ int i, n; + char *bp; + + bp = getblock(fd, offset); +@@ -95,37 +95,6 @@ read_sun_pt(int fd, struct slice all, st + break; + } + } +- /* +- * Convention has it that the SUN disklabel will always have +- * the 'c' partition spanning the entire disk. +- * So we have to check for contained slices. +- */ +- for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) { +- if (sp[i].size == 0) +- continue; +- +- end = sp[i].start + sp[i].size; +- for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) { +- if ( i == j ) +- continue; +- if (sp[j].size == 0) +- continue; +- +- if (sp[i].start < sp[j].start) { +- if (end > sp[j].start && +- end < sp[j].start + sp[j].size) { +- /* Invalid slice */ +- fprintf(stderr, +- "sun_disklabel: slice %d overlaps with %d\n", i , j); +- sp[i].size = 0; +- } +- } else { +- if (end <= sp[j].start + sp[j].size) { +- sp[i].container = j + 1; +- } +- } +- } +- } + return n; + } + diff --git a/SOURCES/0010-RH-dont-remove-map-on-enomem.patch b/SOURCES/0010-RH-dont-remove-map-on-enomem.patch new file mode 100644 index 0000000..1740c10 --- /dev/null +++ b/SOURCES/0010-RH-dont-remove-map-on-enomem.patch @@ -0,0 +1,18 @@ +--- + multipathd/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -990,7 +990,8 @@ mpvec_garbage_collector (struct vectors + return; + + vector_foreach_slot (vecs->mpvec, mpp, i) { +- if (mpp && mpp->alias && !dm_map_present(mpp->alias)) { ++ if (mpp && mpp->alias && !dm_map_present(mpp->alias) && ++ errno != ENOMEM) { + condlog(2, "%s: remove dead map", mpp->alias); + remove_map_and_stop_waiter(mpp, vecs, 1); + i--; diff --git a/SOURCES/0011-RH-deprecate-uid-gid-mode.patch b/SOURCES/0011-RH-deprecate-uid-gid-mode.patch new file mode 100644 index 0000000..9270d9d --- /dev/null +++ b/SOURCES/0011-RH-deprecate-uid-gid-mode.patch @@ -0,0 +1,90 @@ +--- + multipath.conf.annotated | 53 ----------------------------------------------- + multipath.conf.synthetic | 3 -- + 2 files changed, 56 deletions(-) + +Index: multipath-tools-120123/multipath.conf.annotated +=================================================================== +--- multipath-tools-120123.orig/multipath.conf.annotated ++++ multipath-tools-120123/multipath.conf.annotated +@@ -186,32 +186,6 @@ + # user_friendly_names no + # + # # +-# # name : mode +-# # scope : multipath & multipathd +-# # desc : The mode to use for the multipath device nodes, in octal. +-# # values : 0000 - 0777 +-# # default : determined by the process +-# mode 0644 +-# +-# # +-# # name : uid +-# # scope : multipath & multipathd +-# # desc : The user id to use for the multipath device nodes. You +-# # may use either the numeric or symbolic uid +-# # values : +-# # default : determined by the process +-# uid 0 +-# +-# # +-# # name : gid +-# # scope : multipath & multipathd +-# # desc : The group id to user for the multipath device nodes. You +-# # may use either the numeric or symbolic gid +-# # values : +-# # default : determined by the process +-# gid disk +-# +-# # + # # name : checker_timeout + # # scope : multipath & multipathd + # # desc : The timeout to use for path checkers that issue scsi +@@ -388,33 +362,6 @@ + # # + # flush_on_last_del yes + # +-# # +-# # name : mode +-# # scope : multipath & multipathd +-# # desc : The mode to use for the multipath device nodes, in +-# # octal. +-# # values : 0000 - 0777 +-# # default : determined by the process +-# mode 0644 +-# +-# # +-# # name : uid +-# # scope : multipath & multipathd +-# # desc : The user id to use for the multipath device nodes. +-# # You may use either the numeric or symbolic uid +-# # values : +-# # default : determined by the process +-# uid 0 +-# +-# # +-# # name : gid +-# # scope : multipath & multipathd +-# # desc : The group id to user for the multipath device nodes. +-# # You may use either the numeric or symbolic gid +-# # values : +-# # default : determined by the process +-# gid 0 +-# + # } + # multipath { + # wwid 1DEC_____321816758474 +Index: multipath-tools-120123/multipath.conf.synthetic +=================================================================== +--- multipath-tools-120123.orig/multipath.conf.synthetic ++++ multipath-tools-120123/multipath.conf.synthetic +@@ -18,9 +18,6 @@ + # no_path_retry fail + # queue_without_daemon no + # user_friendly_names no +-# mode 644 +-# uid 0 +-# gid disk + #} + #blacklist { + # wwid 26353900f02796769 diff --git a/SOURCES/0012-RH-kpartx-msg.patch b/SOURCES/0012-RH-kpartx-msg.patch new file mode 100644 index 0000000..7584c84 --- /dev/null +++ b/SOURCES/0012-RH-kpartx-msg.patch @@ -0,0 +1,24 @@ +--- + kpartx/lopart.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/kpartx/lopart.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/lopart.c ++++ multipath-tools-130222/kpartx/lopart.c +@@ -205,13 +205,13 @@ find_unused_loop_device (void) + fprintf(stderr, + "mount: Could not find any loop device, and, according to %s,\n" + " this kernel does not know about the loop device.\n" +- " (If so, then recompile or `insmod loop.o'.)", ++ " (If so, then recompile or `modprobe loop'.)", + PROC_DEVICES); + + else + fprintf(stderr, + "mount: Could not find any loop device. Maybe this kernel does not know\n" +- " about the loop device (then recompile or `insmod loop.o'), or\n" ++ " about the loop device (then recompile or `modprobe loop'), or\n" + " maybe /dev/loop# has the wrong major number?"); + + } else diff --git a/SOURCES/0013-RHBZ-883981-cleanup-rpmdiff-issues.patch b/SOURCES/0013-RHBZ-883981-cleanup-rpmdiff-issues.patch new file mode 100644 index 0000000..03bce17 --- /dev/null +++ b/SOURCES/0013-RHBZ-883981-cleanup-rpmdiff-issues.patch @@ -0,0 +1,148 @@ +--- + Makefile.inc | 9 +++++---- + kpartx/Makefile | 2 +- + libmpathpersist/Makefile | 4 ++-- + libmultipath/Makefile | 1 + + libmultipath/checkers/Makefile | 2 +- + libmultipath/prioritizers/Makefile | 2 +- + multipath/Makefile | 2 +- + multipathd/Makefile | 5 +++-- + 8 files changed, 15 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -23,15 +23,15 @@ endif + + prefix = + exec_prefix = $(prefix) +-bindir = $(exec_prefix)/sbin ++bindir = $(exec_prefix)/usr/sbin + libudevdir = ${prefix}/lib/udev + multipathdir = $(TOPDIR)/libmultipath + mandir = $(prefix)/usr/share/man/man8 + man5dir = $(prefix)/usr/share/man/man5 + man3dir = $(prefix)/usr/share/man/man3 + rcdir = $(prefix)/etc/rc.d/init.d +-syslibdir = $(prefix)/$(LIB) +-libdir = $(prefix)/$(LIB)/multipath ++syslibdir = $(prefix)/usr/$(LIB) ++libdir = $(prefix)/usr/$(LIB)/multipath + unitdir = $(prefix)/lib/systemd/system + mpathpersistdir = $(TOPDIR)/libmpathpersist + +@@ -42,8 +42,9 @@ ifndef RPM_OPT_FLAGS + RPM_OPT_FLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 + endif + ++LDFLAGS += -Wl,-z,relro + OPTFLAGS = $(RPM_OPT_FLAGS) -Wunused -Wstrict-prototypes +-CFLAGS = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\" ++CFLAGS = $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" + SHARED_FLAGS = -shared + + %.o: %.c +Index: multipath-tools-130222/multipathd/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipathd/Makefile ++++ multipath-tools-130222/multipathd/Makefile +@@ -5,9 +5,10 @@ include ../Makefile.inc + # + # basic flags setting + # +-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) ++CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathpersistdir) + LDFLAGS += -lpthread -ldevmapper -lreadline -ludev -ldl \ +- -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist ++ -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \ ++ -Wl,-z,now -pie + + # + # debuging stuff +Index: multipath-tools-130222/kpartx/Makefile +=================================================================== +--- multipath-tools-130222.orig/kpartx/Makefile ++++ multipath-tools-130222/kpartx/Makefile +@@ -4,7 +4,7 @@ + # + include ../Makefile.inc + +-CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ++CFLAGS += -fPIC -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 + + LIBDM_API_COOKIE = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_set_cookie' /usr/include/libdevmapper.h) + +Index: multipath-tools-130222/libmpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/Makefile ++++ multipath-tools-130222/libmpathpersist/Makefile +@@ -10,7 +10,7 @@ DEVLIB = libmpathpersist.so + LIBS = $(DEVLIB).$(SONAME) + + +-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) ++CFLAGS += -fPIC -I$(multipathdir) -I$(mpathpersistdir) + LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath + + OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o +@@ -19,7 +19,7 @@ all: $(LIBS) + + + $(LIBS): +- $(CC) -Wall -fPIC -c $(CFLAGS) *.c ++ $(CC) -Wall -c $(CFLAGS) *.c + $(CC) -shared $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) + ln -s $(LIBS) $(DEVLIB) + $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -8,6 +8,7 @@ SONAME=0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) + LIBDEPS = -lpthread -ldl -ldevmapper -ludev ++CFLAGS += -fPIC + + OBJS = memory.o parser.o vector.o devmapper.o \ + hwtable.o blacklist.o util.o dmparser.o config.o \ +Index: multipath-tools-130222/libmultipath/checkers/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/Makefile ++++ multipath-tools-130222/libmultipath/checkers/Makefile +@@ -14,7 +14,7 @@ LIBS= \ + libcheckhp_sw.so \ + libcheckrdac.so + +-CFLAGS += -I.. ++CFLAGS += -fPIC -I.. + + all: $(LIBS) + +Index: multipath-tools-130222/libmultipath/prioritizers/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/Makefile ++++ multipath-tools-130222/libmultipath/prioritizers/Makefile +@@ -17,7 +17,7 @@ LIBS = \ + libprioweightedpath.so \ + libprioiet.so + +-CFLAGS += -I.. ++CFLAGS += -fPIC -I.. + + all: $(LIBS) + +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -6,7 +6,7 @@ include ../Makefile.inc + + OBJS = main.o + +-CFLAGS += -I$(multipathdir) ++CFLAGS += -fPIC -I$(multipathdir) + LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath + + EXEC = multipath diff --git a/SOURCES/0014-RH-handle-other-sector-sizes.patch b/SOURCES/0014-RH-handle-other-sector-sizes.patch new file mode 100644 index 0000000..d07e0d8 --- /dev/null +++ b/SOURCES/0014-RH-handle-other-sector-sizes.patch @@ -0,0 +1,31 @@ +--- + kpartx/gpt.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +Index: multipath-tools-120821/kpartx/gpt.c +=================================================================== +--- multipath-tools-120821.orig/kpartx/gpt.c ++++ multipath-tools-120821/kpartx/gpt.c +@@ -637,6 +637,7 @@ read_gpt_pt (int fd, struct slice all, s + uint32_t i; + int n = 0; + int last_used_index=-1; ++ int sector_size_mul = get_sector_size(fd)/512; + + if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) { + if (gpt) +@@ -652,9 +653,11 @@ read_gpt_pt (int fd, struct slice all, s + sp[n].size = 0; + n++; + } else { +- sp[n].start = __le64_to_cpu(ptes[i].starting_lba); +- sp[n].size = __le64_to_cpu(ptes[i].ending_lba) - +- __le64_to_cpu(ptes[i].starting_lba) + 1; ++ sp[n].start = sector_size_mul * ++ __le64_to_cpu(ptes[i].starting_lba); ++ sp[n].size = sector_size_mul * ++ (__le64_to_cpu(ptes[i].ending_lba) - ++ __le64_to_cpu(ptes[i].starting_lba) + 1); + last_used_index=n; + n++; + } diff --git a/SOURCES/0015-RH-fix-output-buffer.patch b/SOURCES/0015-RH-fix-output-buffer.patch new file mode 100644 index 0000000..ffbbaad --- /dev/null +++ b/SOURCES/0015-RH-fix-output-buffer.patch @@ -0,0 +1,62 @@ +--- + libmultipath/print.c | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -8,6 +8,8 @@ + #include + #include + #include ++#include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -24,6 +26,7 @@ + #include "switchgroup.h" + #include "devmapper.h" + #include "uevent.h" ++#include "debug.h" + + #define MAX(x,y) (x > y) ? x : y + #define TAIL (line + len - 1 - c) +@@ -754,12 +757,32 @@ snprint_pathgroup (char * line, int len, + extern void + print_multipath_topology (struct multipath * mpp, int verbosity) + { +- char buff[MAX_LINE_LEN * MAX_LINES] = {}; ++ int resize; ++ char *buff = NULL; ++ char *old = NULL; ++ int len, maxlen = MAX_LINE_LEN * MAX_LINES; + +- memset(&buff[0], 0, MAX_LINE_LEN * MAX_LINES); +- snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES, +- mpp, verbosity); ++ buff = MALLOC(maxlen); ++ do { ++ if (!buff) { ++ if (old) ++ FREE(old); ++ condlog(0, "couldn't allocate memory for list: %s\n", ++ strerror(errno)); ++ return; ++ } ++ ++ len = snprint_multipath_topology(buff, maxlen, mpp, verbosity); ++ resize = (len == maxlen - 1); ++ ++ if (resize) { ++ maxlen *= 2; ++ old = buff; ++ buff = REALLOC(buff, maxlen); ++ } ++ } while (resize); + printf("%s", buff); ++ FREE(buff); + } + + extern int diff --git a/SOURCES/0016-RH-dont-print-ghost-messages.patch b/SOURCES/0016-RH-dont-print-ghost-messages.patch new file mode 100644 index 0000000..3387424 --- /dev/null +++ b/SOURCES/0016-RH-dont-print-ghost-messages.patch @@ -0,0 +1,18 @@ +--- + libmultipath/discovery.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -898,7 +898,8 @@ get_state (struct path * pp, int daemon) + c->timeout = DEF_TIMEOUT; + state = checker_check(c); + condlog(3, "%s: state = %s", pp->dev, checker_state_name(state)); +- if (state != PATH_UP && strlen(checker_message(c))) ++ if (state != PATH_UP && state != PATH_GHOST && ++ strlen(checker_message(c))) + condlog(3, "%s: checker msg is \"%s\"", + pp->dev, checker_message(c)); + return state; diff --git a/SOURCES/0018-RH-fix-factorize.patch b/SOURCES/0018-RH-fix-factorize.patch new file mode 100644 index 0000000..1dfcab5 --- /dev/null +++ b/SOURCES/0018-RH-fix-factorize.patch @@ -0,0 +1,17 @@ +--- + libmultipath/config.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -437,6 +437,8 @@ restart: + merge_hwe(hwe2, hwe1); + if (hwe_strmatch(hwe2, hwe1) == 0) { + vector_del_slot(hw, i); ++ free_hwe(hwe1); ++ n -= 1; + /* + * Play safe here; we have modified + * the original vector so the outer diff --git a/SOURCES/0019-RH-fix-sockets.patch b/SOURCES/0019-RH-fix-sockets.patch new file mode 100644 index 0000000..8639e20 --- /dev/null +++ b/SOURCES/0019-RH-fix-sockets.patch @@ -0,0 +1,48 @@ +--- + libmpathpersist/mpath_updatepr.c | 3 ++- + libmultipath/uxsock.c | 4 ++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_updatepr.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_updatepr.c ++++ multipath-tools-130222/libmpathpersist/mpath_updatepr.c +@@ -14,6 +14,7 @@ + #include + #include "memory.h" + #include "../libmultipath/uxsock.h" ++#include "../libmultipath/defaults.h" + + unsigned long mem_allocated; /* Total memory used in Bytes */ + +@@ -25,7 +26,7 @@ int update_prflag(char * arg1, char * ar + size_t len; + int ret = 0; + +- fd = ux_socket_connect("/var/run/multipathd.sock"); ++ fd = ux_socket_connect(DEFAULT_SOCKET); + if (fd == -1) { + condlog (0, "ux socket connect error"); + return 1 ; +Index: multipath-tools-130222/libmultipath/uxsock.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uxsock.c ++++ multipath-tools-130222/libmultipath/uxsock.c +@@ -31,7 +31,7 @@ int ux_socket_connect(const char *name) + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + addr.sun_path[0] = '\0'; +- len = strlen(name) + 1; ++ len = strlen(name) + 1 + sizeof(sa_family_t); + strncpy(&addr.sun_path[1], name, len); + + fd = socket(AF_LOCAL, SOCK_STREAM, 0); +@@ -62,7 +62,7 @@ int ux_socket_listen(const char *name) + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + addr.sun_path[0] = '\0'; +- len = strlen(name) + 1; ++ len = strlen(name) + 1 + sizeof(sa_family_t); + strncpy(&addr.sun_path[1], name, len); + + if (bind(fd, (struct sockaddr *)&addr, len) == -1) { diff --git a/SOURCES/0020-RHBZ-907360-static-pthread-init.patch b/SOURCES/0020-RHBZ-907360-static-pthread-init.patch new file mode 100644 index 0000000..bafa5ce --- /dev/null +++ b/SOURCES/0020-RHBZ-907360-static-pthread-init.patch @@ -0,0 +1,41 @@ +--- + libmultipath/uevent.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +Index: multipath-tools-130222/libmultipath/uevent.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.c ++++ multipath-tools-130222/libmultipath/uevent.c +@@ -53,8 +53,10 @@ typedef int (uev_trigger)(struct uevent + + pthread_t uevq_thr; + LIST_HEAD(uevq); +-pthread_mutex_t uevq_lock, *uevq_lockp = &uevq_lock; +-pthread_cond_t uev_cond, *uev_condp = &uev_cond; ++pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER; ++pthread_mutex_t *uevq_lockp = &uevq_lock; ++pthread_cond_t uev_cond = PTHREAD_COND_INITIALIZER; ++pthread_cond_t *uev_condp = &uev_cond; + uev_trigger *my_uev_trigger; + void * my_trigger_data; + int servicing_uev; +@@ -409,10 +411,6 @@ int uevent_listen(void) + * thereby not getting to empty the socket's receive buffer queue + * often enough. + */ +- INIT_LIST_HEAD(&uevq); +- +- pthread_mutex_init(uevq_lockp, NULL); +- pthread_cond_init(uev_condp, NULL); + pthread_cleanup_push(uevq_stop, NULL); + + monitor = udev_monitor_new_from_netlink(conf->udev, "udev"); +@@ -525,8 +523,6 @@ out: + if (need_failback) + err = failback_listen(); + pthread_cleanup_pop(1); +- pthread_mutex_destroy(uevq_lockp); +- pthread_cond_destroy(uev_condp); + return err; + } + diff --git a/SOURCES/0021-RHBZ-919119-respect-kernel-cmdline.patch b/SOURCES/0021-RHBZ-919119-respect-kernel-cmdline.patch new file mode 100644 index 0000000..cea1e48 --- /dev/null +++ b/SOURCES/0021-RHBZ-919119-respect-kernel-cmdline.patch @@ -0,0 +1,30 @@ +--- + multipath/multipath.rules | 2 ++ + multipathd/multipathd.service | 1 + + 2 files changed, 3 insertions(+) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -2,6 +2,8 @@ + # so name them after their devmap name + SUBSYSTEM!="block", GOTO="end_mpath" + ++IMPORT{cmdline}="nompath" ++ENV{nompath}=="?*", GOTO="end_mpath" + ENV{MPATH_SBIN_PATH}="/sbin" + TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" + +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -3,6 +3,7 @@ Description=Device-Mapper Multipath Devi + Before=iscsi.service iscsid.service lvm2-activation-early.service + After=syslog.target + ConditionPathExists=/etc/multipath.conf ++ConditionKernelCommandLine=!nompath + DefaultDependencies=no + Conflicts=shutdown.target + diff --git a/SOURCES/0022-RH-multipathd-check-wwids.patch b/SOURCES/0022-RH-multipathd-check-wwids.patch new file mode 100644 index 0000000..b6e8f42 --- /dev/null +++ b/SOURCES/0022-RH-multipathd-check-wwids.patch @@ -0,0 +1,16 @@ +--- + multipathd/main.c | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1363,6 +1363,7 @@ configure (struct vectors * vecs, int st + + sync_maps_state(mpvec); + vector_foreach_slot(mpvec, mpp, i){ ++ remember_wwid(mpp->wwid); + update_map_pr(mpp); + } + diff --git a/SOURCES/0023-RH-multipath-wipe-wwid.patch b/SOURCES/0023-RH-multipath-wipe-wwid.patch new file mode 100644 index 0000000..6de04bf --- /dev/null +++ b/SOURCES/0023-RH-multipath-wipe-wwid.patch @@ -0,0 +1,239 @@ +--- + libmultipath/discovery.c | 3 + + libmultipath/wwids.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/wwids.h | 1 + multipath/main.c | 26 ++++++++++++-- + multipath/multipath.8 | 5 ++ + 5 files changed, 115 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -53,7 +53,8 @@ store_pathinfo (vector pathvec, vector h + goto out; + } + pp->udev = udev_device_ref(udevice); +- err = pathinfo(pp, hwtable, flag | DI_BLACKLIST); ++ err = pathinfo(pp, hwtable, ++ (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST)); + if (err) + goto out; + +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -82,6 +82,92 @@ write_out_wwid(int fd, char *wwid) { + } + + int ++do_remove_wwid(int fd, char *str) { ++ char buf[4097]; ++ char *ptr; ++ off_t start = 0; ++ int bytes; ++ ++ while (1) { ++ if (lseek(fd, start, SEEK_SET) < 0) { ++ condlog(0, "wwid file read lseek failed : %s", ++ strerror(errno)); ++ return -1; ++ } ++ bytes = read(fd, buf, 4096); ++ if (bytes < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ condlog(0, "failed to read from wwids file : %s", ++ strerror(errno)); ++ return -1; ++ } ++ if (!bytes) /* didn't find wwid to remove */ ++ return 1; ++ buf[bytes] = '\0'; ++ ptr = strstr(buf, str); ++ if (ptr != NULL) { ++ condlog(3, "found '%s'", str); ++ if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) { ++ condlog(0, "write lseek failed : %s", ++ strerror(errno)); ++ return -1; ++ } ++ while (1) { ++ if (write(fd, "#", 1) < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ condlog(0, "failed to write to wwids file : %s", strerror(errno)); ++ return -1; ++ } ++ return 0; ++ } ++ } ++ ptr = strrchr(buf, '\n'); ++ if (ptr == NULL) { /* shouldn't happen, assume it is EOF */ ++ condlog(4, "couldn't find newline, assuming end of file"); ++ return 1; ++ } ++ start = start + (ptr - buf) + 1; ++ } ++} ++ ++ ++int ++remove_wwid(char *wwid) { ++ int fd, len, can_write; ++ char *str; ++ int ret = -1; ++ ++ len = strlen(wwid) + 4; /* two slashes the newline and a zero byte */ ++ str = malloc(len); ++ if (str == NULL) { ++ condlog(0, "can't allocate memory to remove wwid : %s", ++ strerror(errno)); ++ return -1; ++ } ++ if (snprintf(str, len, "/%s/\n", wwid) >= len) { ++ condlog(0, "string overflow trying to remove wwid"); ++ goto out; ++ } ++ condlog(3, "removing line '%s' from wwids file", str); ++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); ++ if (fd < 0) ++ goto out; ++ if (!can_write) { ++ condlog(0, "cannot remove wwid. wwids file is read-only"); ++ goto out_file; ++ } ++ ret = do_remove_wwid(fd, str); ++ ++out_file: ++ close(fd); ++out: ++ free(str); ++ return ret; ++} ++ ++int + check_wwids_file(char *wwid, int write_wwid) + { + int fd, can_write, found, ret; +Index: multipath-tools-130222/libmultipath/wwids.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.h ++++ multipath-tools-130222/libmultipath/wwids.h +@@ -15,5 +15,6 @@ + int should_multipath(struct path *pp, vector pathvec); + int remember_wwid(char *wwid); + int check_wwids_file(char *wwid, int write_wwid); ++int remove_wwid(char *wwid); + + #endif /* _WWIDS_H */ +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -83,7 +83,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); ++ fprintf (stderr, " %s [-c|-w] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); +@@ -104,6 +104,7 @@ usage (char * progname) + " -B treat the bindings file as read only\n" \ + " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ + " -b fil bindings file location\n" \ ++ " -w remove a device from the wwids file\n" \ + " -p pol force all maps to specified path grouping policy :\n" \ + " . failover one path per priority group\n" \ + " . multibus all paths in one priority group\n" \ +@@ -212,7 +213,6 @@ get_dm_mpvec (vector curmp, vector pathv + + if (!conf->dry_run) + reinstate_paths(mpp); +- remember_wwid(mpp->wwid); + } + return 0; + } +@@ -262,7 +262,7 @@ configure (void) + /* + * if we have a blacklisted device parameter, exit early + */ +- if (dev && conf->dev_type == DEV_DEVNODE && ++ if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 && + (filter_devnode(conf->blist_devnode, + conf->elist_devnode, dev) > 0)) { + if (conf->dry_run == 2) +@@ -284,6 +284,17 @@ configure (void) + condlog(3, "scope is nul"); + goto out; + } ++ if (conf->dry_run == 3) { ++ r = remove_wwid(refwwid); ++ if (r == 0) ++ printf("wwid '%s' removed\n", refwwid); ++ else if (r == 1) { ++ printf("wwid '%s' not in wwids file\n", ++ refwwid); ++ r = 0; ++ } ++ goto out; ++ } + condlog(3, "scope limited to %s", refwwid); + if (conf->dry_run == 2) { + if (check_wwids_file(refwwid, 0) == 0){ +@@ -439,7 +450,7 @@ main (int argc, char *argv[]) + if (dm_prereq()) + exit(1); + +- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtqw")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -504,6 +515,9 @@ main (int argc, char *argv[]) + case 'h': + usage(argv[0]); + exit(0); ++ case 'w': ++ conf->dry_run = 3; ++ break; + case ':': + fprintf(stderr, "Missing option argument\n"); + usage(argv[0]); +@@ -555,6 +569,10 @@ main (int argc, char *argv[]) + condlog(0, "the -c option requires a path to check"); + goto out; + } ++ if (conf->dry_run == 3 && !conf->dev) { ++ condlog(0, "the -w option requires a device"); ++ goto out; ++ } + if (conf->remove == FLUSH_ONE) { + if (conf->dev_type == DEV_DEVMAP) { + r = dm_suspend_and_flush_map(conf->dev); +Index: multipath-tools-130222/multipath/multipath.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.8 ++++ multipath-tools-130222/multipath/multipath.8 +@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco + .RB [\| \-b\ \c + .IR bindings_file \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -68,6 +68,9 @@ check if a block device should be a path + .B \-q + allow device tables with queue_if_no_path when multipathd is not running + .TP ++.B \-w ++remove the wwid for the specified device from the wwids file ++.TP + .BI \-p " policy" + force new maps to use the specified policy: + .RS 1.2i diff --git a/SOURCES/0024-RH-multipath-wipe-wwids.patch b/SOURCES/0024-RH-multipath-wipe-wwids.patch new file mode 100644 index 0000000..b91836c --- /dev/null +++ b/SOURCES/0024-RH-multipath-wipe-wwids.patch @@ -0,0 +1,164 @@ +--- + libmultipath/wwids.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/wwids.h | 1 + + multipath/main.c | 29 +++++++++++++++++++++++++++-- + multipath/multipath.8 | 5 ++++- + 4 files changed, 76 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -82,6 +82,50 @@ write_out_wwid(int fd, char *wwid) { + } + + int ++replace_wwids(vector mp) ++{ ++ int i, fd, can_write; ++ struct multipath * mpp; ++ size_t len; ++ int ret = -1; ++ ++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); ++ if (fd < 0) ++ goto out; ++ if (!can_write) { ++ condlog(0, "cannot replace wwids. wwids file is read-only"); ++ goto out_file; ++ } ++ if (ftruncate(fd, 0) < 0) { ++ condlog(0, "cannot truncate wwids file : %s", strerror(errno)); ++ goto out_file; ++ } ++ len = strlen(WWIDS_FILE_HEADER); ++ if (write_all(fd, WWIDS_FILE_HEADER, len) != len) { ++ condlog(0, "Can't write wwid file header : %s", ++ strerror(errno)); ++ /* cleanup partially written header */ ++ if (ftruncate(fd, 0) < 0) ++ condlog(0, "Cannot truncate header : %s", ++ strerror(errno)); ++ goto out_file; ++ } ++ if (!mp || !mp->allocated) { ++ ret = 0; ++ goto out_file; ++ } ++ vector_foreach_slot(mp, mpp, i) { ++ if (write_out_wwid(fd, mpp->wwid) < 0) ++ goto out_file; ++ } ++ ret = 0; ++out_file: ++ close(fd); ++out: ++ return ret; ++} ++ ++int + do_remove_wwid(int fd, char *str) { + char buf[4097]; + char *ptr; +Index: multipath-tools-130222/libmultipath/wwids.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.h ++++ multipath-tools-130222/libmultipath/wwids.h +@@ -16,5 +16,6 @@ int should_multipath(struct path *pp, ve + int remember_wwid(char *wwid); + int check_wwids_file(char *wwid, int write_wwid); + int remove_wwid(char *wwid); ++int replace_wwids(vector mp); + + #endif /* _WWIDS_H */ +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -83,7 +83,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-c|-w] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); ++ fprintf (stderr, " %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); +@@ -105,6 +105,7 @@ usage (char * progname) + " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ + " -b fil bindings file location\n" \ + " -w remove a device from the wwids file\n" \ ++ " -W reset the wwids file include only the current devices\n" \ + " -p pol force all maps to specified path grouping policy :\n" \ + " . failover one path per priority group\n" \ + " . multibus all paths in one priority group\n" \ +@@ -450,7 +451,7 @@ main (int argc, char *argv[]) + if (dm_prereq()) + exit(1); + +- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtqw")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtqwW")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -518,6 +519,9 @@ main (int argc, char *argv[]) + case 'w': + conf->dry_run = 3; + break; ++ case 'W': ++ conf->dry_run = 4; ++ break; + case ':': + fprintf(stderr, "Missing option argument\n"); + usage(argv[0]); +@@ -573,6 +577,27 @@ main (int argc, char *argv[]) + condlog(0, "the -w option requires a device"); + goto out; + } ++ if (conf->dry_run == 4) { ++ struct multipath * mpp; ++ int i; ++ vector curmp; ++ ++ curmp = vector_alloc(); ++ if (!curmp) { ++ condlog(0, "can't allocate memory for mp list"); ++ goto out; ++ } ++ if (dm_get_maps(curmp) == 0) ++ r = replace_wwids(curmp); ++ if (r == 0) ++ printf("successfully reset wwids\n"); ++ vector_foreach_slot_backwards(curmp, mpp, i) { ++ vector_del_slot(curmp, i); ++ free_multipath(mpp, KEEP_PATHS); ++ } ++ vector_free(curmp); ++ goto out; ++ } + if (conf->remove == FLUSH_ONE) { + if (conf->dev_type == DEV_DEVMAP) { + r = dm_suspend_and_flush_map(conf->dev); +Index: multipath-tools-130222/multipath/multipath.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.8 ++++ multipath-tools-130222/multipath/multipath.8 +@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco + .RB [\| \-b\ \c + .IR bindings_file \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w | \-W \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -71,6 +71,9 @@ allow device tables with queue_if_no_pat + .B \-w + remove the wwid for the specified device from the wwids file + .TP ++.B \-W ++reset the wwids file to only include the current multipath devices ++.TP + .BI \-p " policy" + force new maps to use the specified policy: + .RS 1.2i diff --git a/SOURCES/0025-UPBZ-916668_add_maj_min.patch b/SOURCES/0025-UPBZ-916668_add_maj_min.patch new file mode 100644 index 0000000..615533d --- /dev/null +++ b/SOURCES/0025-UPBZ-916668_add_maj_min.patch @@ -0,0 +1,29 @@ +--- + multipathd/main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -537,7 +537,8 @@ rescan: + goto fail_map; + + if (retries >= 0) { +- condlog(2, "%s path added to devmap %s", pp->dev, mpp->alias); ++ condlog(2, "%s [%s]: path added to devmap %s", ++ pp->dev, pp->dev_t, mpp->alias); + return 0; + } + else +@@ -642,8 +643,8 @@ ev_remove_path (struct path *pp, struct + } + sync_map_state(mpp); + +- condlog(2, "%s: path removed from map %s", +- pp->dev, mpp->alias); ++ condlog(2, "%s [%s]: path removed from map %s", ++ pp->dev, pp->dev_t, mpp->alias); + } + } + diff --git a/SOURCES/0026-fix-checker-time.patch b/SOURCES/0026-fix-checker-time.patch new file mode 100644 index 0000000..e05ef58 --- /dev/null +++ b/SOURCES/0026-fix-checker-time.patch @@ -0,0 +1,23 @@ +--- + multipathd/main.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1226,11 +1226,10 @@ check_path (struct vectors * vecs, struc + pp->checkint = 2 * pp->checkint; + else + pp->checkint = conf->max_checkint; +- +- pp->tick = pp->checkint; +- condlog(4, "%s: delay next check %is", +- pp->dev_t, pp->tick); + } ++ pp->tick = pp->checkint; ++ condlog(4, "%s: delay next check %is", ++ pp->dev_t, pp->tick); + } + } + else if (newstate == PATH_DOWN) { diff --git a/SOURCES/0027-RH-get-wwid.patch b/SOURCES/0027-RH-get-wwid.patch new file mode 100644 index 0000000..04217b4 --- /dev/null +++ b/SOURCES/0027-RH-get-wwid.patch @@ -0,0 +1,17 @@ +--- + libmultipath/structs_vec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -106,7 +106,7 @@ orphan_paths (vector pathvec, struct mul + static void + set_multipath_wwid (struct multipath * mpp) + { +- if (mpp->wwid) ++ if (strlen(mpp->wwid)) + return; + + dm_get_uuid(mpp->alias, mpp->wwid); diff --git a/SOURCES/0028-RHBZ-929078-refresh-udev-dev.patch b/SOURCES/0028-RHBZ-929078-refresh-udev-dev.patch new file mode 100644 index 0000000..c14ddb5 --- /dev/null +++ b/SOURCES/0028-RHBZ-929078-refresh-udev-dev.patch @@ -0,0 +1,55 @@ +--- + libmultipath/discovery.c | 2 +- + multipathd/main.c | 19 ++++++++++++++++++- + 2 files changed, 19 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1034,7 +1034,7 @@ pathinfo (struct path *pp, vector hwtabl + } + } + +- if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid)) ++ if ((mask & DI_WWID) && !strlen(pp->wwid)) + get_uid(pp); + if (mask & DI_BLACKLIST && mask & DI_WWID) { + if (filter_wwid(conf->blist_wwid, conf->elist_wwid, +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -376,7 +376,7 @@ static int + uev_add_path (struct uevent *uev, struct vectors * vecs) + { + struct path *pp; +- int ret; ++ int ret, i; + + condlog(2, "%s: add path (uevent)", uev->kernel); + if (strstr(uev->kernel, "..") != NULL) { +@@ -393,6 +393,23 @@ uev_add_path (struct uevent *uev, struct + uev->kernel); + if (pp->mpp) + return 0; ++ if (!strlen(pp->wwid)) { ++ udev_device_unref(pp->udev); ++ pp->udev = udev_device_ref(uev->udev); ++ ret = pathinfo(pp, conf->hwtable, ++ DI_ALL | DI_BLACKLIST); ++ if (ret == 2) { ++ i = find_slot(vecs->pathvec, (void *)pp); ++ if (i != -1) ++ vector_del_slot(vecs->pathvec, i); ++ free_path(pp); ++ return 0; ++ } else if (ret == 1) { ++ condlog(0, "%s: failed to reinitialize path", ++ uev->kernel); ++ return 1; ++ } ++ } + } else { + /* + * get path vital state diff --git a/SOURCES/0029-RH-no-prio-put-msg.patch b/SOURCES/0029-RH-no-prio-put-msg.patch new file mode 100644 index 0000000..6ebdae0 --- /dev/null +++ b/SOURCES/0029-RH-no-prio-put-msg.patch @@ -0,0 +1,20 @@ +--- + libmultipath/prio.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/prio.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prio.c ++++ multipath-tools-130222/libmultipath/prio.c +@@ -162,7 +162,10 @@ void prio_put (struct prio * dst) + if (!dst) + return; + +- src = prio_lookup(dst->name); ++ if (!strlen(dst->name)) ++ src = NULL; ++ else ++ src = prio_lookup(dst->name); + memset(dst, 0x0, sizeof(struct prio)); + free_prio(src); + } diff --git a/SOURCES/0030-RHBZ-916528-override-queue-no-daemon.patch b/SOURCES/0030-RHBZ-916528-override-queue-no-daemon.patch new file mode 100644 index 0000000..e663ded --- /dev/null +++ b/SOURCES/0030-RHBZ-916528-override-queue-no-daemon.patch @@ -0,0 +1,200 @@ +--- + libmultipath/dict.c | 10 ++++------ + libmultipath/structs.h | 2 +- + multipathd/cli.c | 3 +++ + multipathd/cli.h | 2 ++ + multipathd/cli_handlers.c | 18 ++++++++++++++++++ + multipathd/cli_handlers.h | 2 ++ + multipathd/main.c | 2 ++ + multipathd/multipathd.init.redhat | 14 ++++++++++---- + 8 files changed, 42 insertions(+), 11 deletions(-) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -438,14 +438,11 @@ def_queue_without_daemon(vector strvec) + if (!buff) + return 1; + +- if (!strncmp(buff, "off", 3) || !strncmp(buff, "no", 2) || +- !strncmp(buff, "0", 1)) +- conf->queue_without_daemon = QUE_NO_DAEMON_OFF; +- else if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) || ++ if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) || + !strncmp(buff, "1", 1)) + conf->queue_without_daemon = QUE_NO_DAEMON_ON; + else +- conf->queue_without_daemon = QUE_NO_DAEMON_UNDEF; ++ conf->queue_without_daemon = QUE_NO_DAEMON_OFF; + + free(buff); + return 0; +@@ -2670,8 +2667,9 @@ snprint_def_queue_without_daemon (char * + case QUE_NO_DAEMON_OFF: + return snprintf(buff, len, "\"no\""); + case QUE_NO_DAEMON_ON: +- case QUE_NO_DAEMON_UNDEF: + return snprintf(buff, len, "\"yes\""); ++ case QUE_NO_DAEMON_FORCE: ++ return snprintf(buff, len, "\"forced\""); + } + return 0; + } +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -67,9 +67,9 @@ enum pgstates { + }; + + enum queue_without_daemon_states { +- QUE_NO_DAEMON_UNDEF, + QUE_NO_DAEMON_OFF, + QUE_NO_DAEMON_ON, ++ QUE_NO_DAEMON_FORCE, + }; + + enum pgtimeouts { +Index: multipath-tools-130222/multipathd/cli.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.c ++++ multipath-tools-130222/multipathd/cli.c +@@ -162,6 +162,7 @@ load_keys (void) + r += add_key(keys, "resize", RESIZE, 0); + r += add_key(keys, "reset", RESET, 0); + r += add_key(keys, "reload", RELOAD, 0); ++ r += add_key(keys, "forcequeueing", FORCEQ, 0); + r += add_key(keys, "disablequeueing", DISABLEQ, 0); + r += add_key(keys, "restorequeueing", RESTOREQ, 0); + r += add_key(keys, "paths", PATHS, 0); +@@ -459,6 +460,8 @@ cli_init (void) { + add_handler(GETPRSTATUS+MAP, NULL); + add_handler(SETPRSTATUS+MAP, NULL); + add_handler(UNSETPRSTATUS+MAP, NULL); ++ add_handler(FORCEQ+DAEMON, NULL); ++ add_handler(RESTOREQ+DAEMON, NULL); + + return 0; + } +Index: multipath-tools-130222/multipathd/cli.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.h ++++ multipath-tools-130222/multipathd/cli.h +@@ -10,6 +10,7 @@ enum { + __RESIZE, + __RESET, + __RELOAD, ++ __FORCEQ, + __DISABLEQ, + __RESTOREQ, + __PATHS, +@@ -45,6 +46,7 @@ enum { + #define RESIZE (1 << __RESIZE) + #define RESET (1 << __RESET) + #define RELOAD (1 << __RELOAD) ++#define FORCEQ (1 << __FORCEQ) + #define DISABLEQ (1 << __DISABLEQ) + #define RESTOREQ (1 << __RESTOREQ) + #define PATHS (1 << __PATHS) +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -628,6 +628,24 @@ cli_resize(void *v, char **reply, int *l + } + + int ++cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data) ++{ ++ condlog(2, "force queue_without_daemon (operator)"); ++ if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF) ++ conf->queue_without_daemon = QUE_NO_DAEMON_FORCE; ++ return 0; ++} ++ ++int ++cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data) ++{ ++ condlog(2, "restore queue_without_daemon (operator)"); ++ if (conf->queue_without_daemon == QUE_NO_DAEMON_FORCE) ++ conf->queue_without_daemon = QUE_NO_DAEMON_OFF; ++ return 0; ++} ++ ++int + cli_restore_queueing(void *v, char **reply, int *len, void *data) + { + struct vectors * vecs = (struct vectors *)data; +Index: multipath-tools-130222/multipathd/cli_handlers.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.h ++++ multipath-tools-130222/multipathd/cli_handlers.h +@@ -28,6 +28,8 @@ int cli_suspend(void * v, char ** reply, + int cli_resume(void * v, char ** reply, int * len, void * data); + int cli_reinstate(void * v, char ** reply, int * len, void * data); + int cli_fail(void * v, char ** reply, int * len, void * data); ++int cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data); ++int cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data); + int cli_quit(void * v, char ** reply, int * len, void * data); + int cli_shutdown(void * v, char ** reply, int * len, void * data); + int cli_reassign (void * v, char ** reply, int * len, void * data); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -904,6 +904,8 @@ uxlsnrloop (void * ap) + set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus); + set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus); + set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus); ++ set_handler_callback(FORCEQ+DAEMON, cli_force_no_daemon_q); ++ set_handler_callback(RESTOREQ+DAEMON, cli_restore_no_daemon_q); + + umask(077); + uxsock_listen(&uxsock_trigger, ap); +Index: multipath-tools-130222/multipathd/multipathd.init.redhat +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.init.redhat ++++ multipath-tools-130222/multipathd/multipathd.init.redhat +@@ -81,23 +81,28 @@ force_stop() { + echo + } + +-stop() { ++check_root() { + root_dev=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $1; }}' /etc/mtab) + dm_num=`dmsetup info -c --noheadings -o minor $root_dev 2> /dev/null` + if [ $? -eq 0 ]; then + root_dm_device="dm-$dm_num" + [ -d $syspath/$root_dm_device ] && teardown_slaves $syspath/$root_dm_device + fi ++} + +- force_stop ++force_queue_without_daemon() { ++ $DAEMON forcequeueing daemon + } + + restart() { +- stop ++ force_queue_without_daemon ++ check_root ++ force_stop + start + } + + force_restart() { ++ force_queue_without_daemon + force_stop + start + } +@@ -115,7 +120,8 @@ start) + start + ;; + stop) +- stop ++ check_root ++ force_stop + ;; + force-stop) + force_stop diff --git a/SOURCES/0031-RHBZ-957188-kpartx-use-dm-name.patch b/SOURCES/0031-RHBZ-957188-kpartx-use-dm-name.patch new file mode 100644 index 0000000..282c517 --- /dev/null +++ b/SOURCES/0031-RHBZ-957188-kpartx-use-dm-name.patch @@ -0,0 +1,17 @@ +--- + kpartx/kpartx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -348,7 +348,7 @@ main(int argc, char **argv){ + if (delim == NULL) { + delim = malloc(DELIM_SIZE); + memset(delim, 0, DELIM_SIZE); +- set_delimiter(device, delim); ++ set_delimiter(mapname, delim); + } + + fd = open(device, O_RDONLY); diff --git a/SOURCES/0032-RHBZ-956464-mpathconf-defaults.patch b/SOURCES/0032-RHBZ-956464-mpathconf-defaults.patch new file mode 100644 index 0000000..d63c32e --- /dev/null +++ b/SOURCES/0032-RHBZ-956464-mpathconf-defaults.patch @@ -0,0 +1,19 @@ +--- + multipath/mpathconf | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/multipath/mpathconf +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf ++++ multipath-tools-130222/multipath/mpathconf +@@ -31,8 +31,8 @@ function usage + echo "Commands:" + echo "Enable: --enable " + echo "Disable: --disable" +- echo "Set user_friendly_names (Default n): --user_friendly_names " +- echo "Set find_multipaths (Default n): --find_multipaths " ++ echo "Set user_friendly_names (Default y): --user_friendly_names " ++ echo "Set find_multipaths (Default y): --find_multipaths " + echo "Load the dm-multipath modules on enable (Default y): --with_module " + echo "start/stop/reload multipathd (Default n): --with_multipathd " + echo "" diff --git a/SOURCES/0033-RHBZ-829963-e-series-conf.patch b/SOURCES/0033-RHBZ-829963-e-series-conf.patch new file mode 100644 index 0000000..d8fc119 --- /dev/null +++ b/SOURCES/0033-RHBZ-829963-e-series-conf.patch @@ -0,0 +1,44 @@ +This patch provides hwtable updates for NETAPP/LSI/ENGENIO E-Series arrays, +utilizing new features to detect TPGS support, automatically. + +Signed-off-by: Sean Stewart + +--- +--- + libmultipath/hwtable.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1046,9 +1046,13 @@ static struct hwentry default_hw[] = { + .checker_name = RDAC, + .prio_name = PRIO_RDAC, + }, +- /* LSI/Engenio/NetApp E-Series RDAC storage */ ++ /* LSI/Engenio/NetApp E-Series RDAC storage ++ * ++ * Maintainer : Sean Stewart ++ * Mail : sean.stewart@netapp.com ++ */ + { +- .vendor = "(LSI|ENGENIO)", ++ .vendor = "(NETAPP|LSI|ENGENIO)", + .product = "INF-01-00", + .bl_product = "Universal Xport", + .features = "2 pg_init_retries 50", +@@ -1056,10 +1060,12 @@ static struct hwentry default_hw[] = { + .pgpolicy = GROUP_BY_PRIO, + .pgfailback = -FAILBACK_IMMEDIATE, + .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, ++ .no_path_retry = 30, + .checker_name = RDAC, + .prio_name = PRIO_RDAC, + .prio_args = NULL, ++ .detect_prio = DETECT_PRIO_ON, ++ .retain_hwhandler = RETAIN_HWHANDLER_ON, + }, + { + .vendor = "STK", diff --git a/SOURCES/0034-RHBZ-851416-mpathconf-display.patch b/SOURCES/0034-RHBZ-851416-mpathconf-display.patch new file mode 100644 index 0000000..e9e00ce --- /dev/null +++ b/SOURCES/0034-RHBZ-851416-mpathconf-display.patch @@ -0,0 +1,53 @@ +--- + multipath/mpathconf | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/multipath/mpathconf +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf ++++ multipath-tools-130222/multipath/mpathconf +@@ -159,7 +159,7 @@ if [ -z "$MODULE" -o "$MODULE" = "y" ]; + fi + + if [ "$MULTIPATHD" = "y" ]; then +- if service multipathd status > /dev/null ; then ++ if /bin/systemctl status multipathd.service > /dev/null 2>&1 ; then + HAVE_MULTIPATHD=1 + else + HAVE_MULTIPATHD=0 +@@ -210,8 +210,17 @@ if [ -n "$SHOW_STATUS" ]; then + echo "dm_multipath module is not loaded" + fi + fi +- if [ -n "$HAVE_MULTIPATHD" ]; then +- service multipathd status ++ if [ -z "$HAVE_MULTIPATHD" ]; then ++ if /bin/systemctl status multipathd.service > /dev/null 2>&1 ; then ++ HAVE_MULTIPATHD=1 ++ else ++ HAVE_MULTIPATHD=0 ++ fi ++ fi ++ if [ "$HAVE_MULTIPATHD" = 1 ]; then ++ echo "multipathd is running" ++ else ++ echo "multipathd is not running" + fi + exit 0 + fi +@@ -301,12 +310,12 @@ if [ "$ENABLE" = 1 ]; then + modprobe dm_multipath + fi + if [ "$HAVE_MULTIPATHD" = 0 ]; then +- service multipathd start ++ systemctl start multipathd.service + fi + elif [ "$ENABLE" = 0 ]; then + if [ "$HAVE_MULTIPATHD" = 1 ]; then +- service multipathd stop ++ systemctl stop multipathd.service + fi + elif [ -n "$CHANGED_CONFIG" -a "$HAVE_MULTIPATHD" = 1 ]; then +- service multipathd reload ++ systemctl reload multipathd.service + fi diff --git a/SOURCES/0035-RHBZ-891921-list-mpp.patch b/SOURCES/0035-RHBZ-891921-list-mpp.patch new file mode 100644 index 0000000..b0bb7a2 --- /dev/null +++ b/SOURCES/0035-RHBZ-891921-list-mpp.patch @@ -0,0 +1,33 @@ +--- + libmultipath/print.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -422,6 +422,16 @@ snprint_path_serial (char * buff, size_t + } + + static int ++snprint_path_mpp (char * buff, size_t len, struct path * pp) ++{ ++ if (!pp->mpp) ++ return snprintf(buff, len, "[orphan]"); ++ if (!pp->mpp->alias) ++ return snprintf(buff, len, "[unknown]"); ++ return snprint_str(buff, len, pp->mpp->alias); ++} ++ ++static int + snprint_path_checker (char * buff, size_t len, struct path * pp) + { + struct checker * c = &pp->checker; +@@ -464,6 +474,7 @@ struct path_data pd[] = { + {'p', "pri", 0, snprint_pri}, + {'S', "size", 0, snprint_path_size}, + {'z', "serial", 0, snprint_path_serial}, ++ {'m', "multipath", 0, snprint_path_mpp}, + {0, NULL, 0 , NULL} + }; + diff --git a/SOURCES/0036-RHBZ-949239-load-multipath-module.patch b/SOURCES/0036-RHBZ-949239-load-multipath-module.patch new file mode 100644 index 0000000..04a6f68 --- /dev/null +++ b/SOURCES/0036-RHBZ-949239-load-multipath-module.patch @@ -0,0 +1,16 @@ +--- + multipathd/multipathd.service | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -10,6 +10,7 @@ Conflicts=shutdown.target + [Service] + Type=forking + PIDFile=/var/run/multipathd.pid ++ExecStartPre=/sbin/modprobe dm-multipath + ExecStart=/sbin/multipathd + ExecReload=/sbin/multipathd reconfigure + #ExecStop=/path/to/scrip delete-me if not necessary diff --git a/SOURCES/0037-RHBZ-768873-fix-rename.patch b/SOURCES/0037-RHBZ-768873-fix-rename.patch new file mode 100644 index 0000000..7e05bd0 --- /dev/null +++ b/SOURCES/0037-RHBZ-768873-fix-rename.patch @@ -0,0 +1,87 @@ +--- + libmultipath/devmapper.c | 45 --------------------------------------------- + libmultipath/devmapper.h | 1 - + libmultipath/propsel.c | 2 -- + 3 files changed, 48 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -917,51 +917,6 @@ out: + return r; + } + +-extern char * +-dm_get_name(char *uuid) +-{ +- struct dm_task *dmt; +- struct dm_info info; +- char *prefixed_uuid, *name = NULL; +- const char *nametmp; +- +- dmt = dm_task_create(DM_DEVICE_INFO); +- if (!dmt) +- return NULL; +- +- prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1); +- if (!prefixed_uuid) { +- condlog(0, "cannot create prefixed uuid : %s", +- strerror(errno)); +- goto freeout; +- } +- sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid); +- if (!dm_task_set_uuid(dmt, prefixed_uuid)) +- goto freeout; +- +- if (!dm_task_run(dmt)) +- goto freeout; +- +- if (!dm_task_get_info(dmt, &info) || !info.exists) +- goto freeout; +- +- nametmp = dm_task_get_name(dmt); +- if (nametmp && strlen(nametmp)) { +- name = MALLOC(strlen(nametmp) + 1); +- if (name) +- strcpy(name, nametmp); +- } else { +- condlog(2, "%s: no device-mapper name found", uuid); +- } +- +-freeout: +- if (prefixed_uuid) +- FREE(prefixed_uuid); +- dm_task_destroy(dmt); +- +- return name; +-} +- + int + dm_geteventnr (char *name) + { +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -40,7 +40,6 @@ int dm_remove_partmaps (const char * map + int dm_get_uuid(char *name, char *uuid); + int dm_get_info (char * mapname, struct dm_info ** dmi); + int dm_rename (char * old, char * new); +-char * dm_get_name(char * uuid); + int dm_reassign(const char * mapname); + int dm_reassign_table(const char *name, char *old, char *new); + int dm_setgeometry(struct multipath *mpp); +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -263,8 +263,6 @@ select_alias (struct multipath * mp) + conf->bindings_file, mp->alias_prefix, conf->bindings_read_only); + } + if (mp->alias == NULL) +- mp->alias = dm_get_name(mp->wwid); +- if (mp->alias == NULL) + mp->alias = STRDUP(mp->wwid); + } + diff --git a/SOURCES/0038-RHBZ-799860-netapp-config.patch b/SOURCES/0038-RHBZ-799860-netapp-config.patch new file mode 100644 index 0000000..3b91f9b --- /dev/null +++ b/SOURCES/0038-RHBZ-799860-netapp-config.patch @@ -0,0 +1,16 @@ +--- + libmultipath/hwtable.c | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -794,6 +794,7 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ONTAP, + .prio_args = NULL, + .retain_hwhandler = RETAIN_HWHANDLER_ON, ++ .user_friendly_names = USER_FRIENDLY_NAMES_OFF, + .detect_prio = DETECT_PRIO_ON, + }, + /* diff --git a/SOURCES/0039-RH-detect-prio-fix.patch b/SOURCES/0039-RH-detect-prio-fix.patch new file mode 100644 index 0000000..941a570 --- /dev/null +++ b/SOURCES/0039-RH-detect-prio-fix.patch @@ -0,0 +1,28 @@ +--- + libmultipath/propsel.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -384,10 +384,17 @@ select_getuid (struct path * pp) + void + detect_prio(struct path * pp) + { ++ int ret; + struct prio *p = &pp->prio; + +- if (get_target_port_group_support(pp->fd) > 0) +- prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS); ++ if (get_target_port_group_support(pp->fd) <= 0) ++ return; ++ ret = get_target_port_group(pp->fd); ++ if (ret < 0) ++ return; ++ if (get_asymmetric_access_state(pp->fd, ret) < 0) ++ return; ++ prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS); + } + + extern int diff --git a/SOURCES/0040-RH-bindings-fix.patch b/SOURCES/0040-RH-bindings-fix.patch new file mode 100644 index 0000000..c56f352 --- /dev/null +++ b/SOURCES/0040-RH-bindings-fix.patch @@ -0,0 +1,101 @@ +--- + libmultipath/alias.c | 39 ++++++++++++++++++++++++++++++--------- + 1 file changed, 30 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/libmultipath/alias.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.c ++++ multipath-tools-130222/libmultipath/alias.c +@@ -46,11 +46,11 @@ format_devname(char *name, int id, int l + memset(name,0, len); + strcpy(name, prefix); + for (pos = len - 1; pos >= prefix_len; pos--) { ++ id--; + name[pos] = 'a' + id % 26; + if (id < 26) + break; + id /= 26; +- id--; + } + memmove(name + prefix_len, name + pos, len - pos); + name[prefix_len + len - pos] = '\0'; +@@ -66,13 +66,22 @@ scan_devname(char *alias, char *prefix) + if (!prefix || strncmp(alias, prefix, strlen(prefix))) + return -1; + ++ if (strlen(alias) == strlen(prefix)) ++ return -1; ++ ++ if (strlen(alias) > strlen(prefix) + 7) ++ /* id of 'aaaaaaaa' overflows int */ ++ return -1; ++ + c = alias + strlen(prefix); + while (*c != '\0' && *c != ' ' && *c != '\t') { ++ if (*c < 'a' || *c > 'z') ++ return -1; + i = *c - 'a'; + n = ( n * 26 ) + i; ++ if (n < 0) ++ return -1; + c++; +- if (*c < 'a' || *c > 'z') +- break; + n++; + } + +@@ -84,7 +93,9 @@ lookup_binding(FILE *f, char *map_wwid, + { + char buf[LINE_MAX]; + unsigned int line_nr = 0; +- int id = 0; ++ int id = 1; ++ int biggest_id = 1; ++ int smallest_bigger_id = INT_MAX; + + *map_alias = NULL; + +@@ -100,8 +111,12 @@ lookup_binding(FILE *f, char *map_wwid, + if (!alias) /* blank line */ + continue; + curr_id = scan_devname(alias, prefix); +- if (curr_id >= id) +- id = curr_id + 1; ++ if (curr_id == id) ++ id++; ++ if (curr_id > biggest_id) ++ biggest_id = curr_id; ++ if (curr_id > id && curr_id < smallest_bigger_id) ++ smallest_bigger_id = curr_id; + wwid = strtok(NULL, " \t"); + if (!wwid){ + condlog(3, +@@ -116,11 +131,17 @@ lookup_binding(FILE *f, char *map_wwid, + if (*map_alias == NULL) + condlog(0, "Cannot copy alias from bindings " + "file : %s", strerror(errno)); +- return id; ++ return 0; + } + } + condlog(3, "No matching wwid [%s] in bindings file.", map_wwid); +- return id; ++ if (id < 0) { ++ condlog(0, "no more available user_friendly_names"); ++ return 0; ++ } ++ if (id < smallest_bigger_id) ++ return id; ++ return biggest_id + 1; + } + + static int +@@ -254,7 +275,7 @@ get_user_friendly_alias(char *wwid, char + return NULL; + } + +- if (!alias && can_write && !bindings_read_only) ++ if (!alias && can_write && !bindings_read_only && id) + alias = allocate_binding(fd, wwid, id, prefix); + + fclose(f); diff --git a/SOURCES/0041-RH-check-for-erofs.patch b/SOURCES/0041-RH-check-for-erofs.patch new file mode 100644 index 0000000..d29d78d --- /dev/null +++ b/SOURCES/0041-RH-check-for-erofs.patch @@ -0,0 +1,121 @@ +--- + libmultipath/configure.c | 7 ------ + libmultipath/devmapper.c | 53 ++++++++++++++++++++++------------------------- + libmultipath/devmapper.h | 2 - + 3 files changed, 25 insertions(+), 37 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -384,24 +384,17 @@ domap (struct multipath * mpp, char * pa + + r = dm_addmap_create(mpp, params); + +- if (!r) +- r = dm_addmap_create_ro(mpp, params); +- + lock_multipath(mpp, 0); + break; + + case ACT_RELOAD: + r = dm_addmap_reload(mpp, params); +- if (!r) +- r = dm_addmap_reload_ro(mpp, params); + if (r) + r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias); + break; + + case ACT_RESIZE: + r = dm_addmap_reload(mpp, params); +- if (!r) +- r = dm_addmap_reload_ro(mpp, params); + if (r) + r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1); + break; +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -298,42 +298,39 @@ dm_addmap (int task, const char *target, + return r; + } + +-static int +-_dm_addmap_create (struct multipath *mpp, char * params, int ro) { +- int r; +- r = dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro); +- /* +- * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD. +- * Failing the second part leaves an empty map. Clean it up. +- */ +- if (!r && dm_map_present(mpp->alias)) { +- condlog(3, "%s: failed to load map (a path might be in use)", +- mpp->alias); +- dm_flush_map_nosync(mpp->alias); ++extern int ++dm_addmap_create (struct multipath *mpp, char * params) { ++ int ro; ++ ++ for (ro = 0; ro <= 1; ro++) { ++ int err; ++ ++ if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro)) ++ return 1; ++ /* ++ * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD. ++ * Failing the second part leaves an empty map. Clean it up. ++ */ ++ err = errno; ++ if (dm_map_present(mpp->alias)) { ++ condlog(3, "%s: failed to load map (a path might be in use)", mpp->alias); ++ dm_flush_map_nosync(mpp->alias); ++ } ++ if (err != EROFS) ++ break; + } +- return r; ++ return 0; + } + + #define ADDMAP_RW 0 + #define ADDMAP_RO 1 + + extern int +-dm_addmap_create (struct multipath *mpp, char *params) { +- return _dm_addmap_create(mpp, params, ADDMAP_RW); +-} +- +-extern int +-dm_addmap_create_ro (struct multipath *mpp, char *params) { +- return _dm_addmap_create(mpp, params, ADDMAP_RO); +-} +- +-extern int + dm_addmap_reload (struct multipath *mpp, char *params) { +- return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW); +-} +- +-extern int +-dm_addmap_reload_ro (struct multipath *mpp, char *params) { ++ if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW)) ++ return 1; ++ if (errno != EROFS) ++ return 0; + return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO); + } + +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -12,9 +12,7 @@ int dm_drv_version (unsigned int * versi + int dm_simplecmd_flush (int, const char *, int); + int dm_simplecmd_noflush (int, const char *); + int dm_addmap_create (struct multipath *mpp, char *params); +-int dm_addmap_create_ro (struct multipath *mpp, char *params); + int dm_addmap_reload (struct multipath *mpp, char *params); +-int dm_addmap_reload_ro (struct multipath *mpp, char *params); + int dm_map_present (const char *); + int dm_get_map(char *, unsigned long long *, char *); + int dm_get_status(char *, char *); diff --git a/SOURCES/0042-UP-fix-signal-handling.patch b/SOURCES/0042-UP-fix-signal-handling.patch new file mode 100644 index 0000000..4b4b40b --- /dev/null +++ b/SOURCES/0042-UP-fix-signal-handling.patch @@ -0,0 +1,493 @@ +--- + libmultipath/file.c | 4 +- + libmultipath/lock.c | 9 ---- + libmultipath/lock.h | 1 + libmultipath/log_pthread.c | 22 ----------- + libmultipath/waiter.c | 2 - + multipathd/cli_handlers.c | 4 +- + multipathd/main.c | 90 ++++++++++++++++++++------------------------- + multipathd/main.h | 3 + + multipathd/uxlsnr.c | 21 +++++++--- + multipathd/uxlsnr.h | 3 + + 10 files changed, 65 insertions(+), 94 deletions(-) + +Index: multipath-tools-130222/libmultipath/file.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/file.c ++++ multipath-tools-130222/libmultipath/file.c +@@ -98,7 +98,7 @@ lock_file(int fd, char *file_name) + sigaddset(&set, SIGALRM); + + sigaction(SIGALRM, &act, &oldact); +- sigprocmask(SIG_UNBLOCK, &set, &oldset); ++ pthread_sigmask(SIG_UNBLOCK, &set, &oldset); + + alarm(FILE_TIMEOUT); + err = fcntl(fd, F_SETLKW, &lock); +@@ -112,7 +112,7 @@ lock_file(int fd, char *file_name) + condlog(0, "%s is locked. Giving up.", file_name); + } + +- sigprocmask(SIG_SETMASK, &oldset, NULL); ++ pthread_sigmask(SIG_SETMASK, &oldset, NULL); + sigaction(SIGALRM, &oldact, NULL); + return err; + } +Index: multipath-tools-130222/libmultipath/lock.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/lock.c ++++ multipath-tools-130222/libmultipath/lock.c +@@ -1,16 +1,7 @@ + #include +-#include + #include "lock.h" + #include + +-void block_signal (int signum, sigset_t *old) +-{ +- sigset_t set; +- sigemptyset(&set); +- sigaddset(&set, signum); +- pthread_sigmask(SIG_BLOCK, &set, old); +-} +- + void cleanup_lock (void * data) + { + unlock ((*(struct mutex_lock *)data)); +Index: multipath-tools-130222/libmultipath/lock.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/lock.h ++++ multipath-tools-130222/libmultipath/lock.h +@@ -29,6 +29,5 @@ struct mutex_lock { + #endif + + void cleanup_lock (void * data); +-void block_signal(int signum, sigset_t *old); + + #endif /* _LOCK_H */ +Index: multipath-tools-130222/libmultipath/log_pthread.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/log_pthread.c ++++ multipath-tools-130222/libmultipath/log_pthread.c +@@ -22,26 +22,13 @@ pthread_cond_t logev_cond; + + int logq_running; + +-static void +-sigusr1 (int sig) +-{ +- pthread_mutex_lock(&logq_lock); +- log_reset("multipathd"); +- pthread_mutex_unlock(&logq_lock); +-} +- + void log_safe (int prio, const char * fmt, va_list ap) + { +- sigset_t old; +- + if (log_thr == (pthread_t)0) { + syslog(prio, fmt, ap); + return; + } + +- block_signal(SIGUSR1, &old); +- block_signal(SIGHUP, NULL); +- + pthread_mutex_lock(&logq_lock); + log_enqueue(prio, fmt, ap); + pthread_mutex_unlock(&logq_lock); +@@ -49,8 +36,6 @@ void log_safe (int prio, const char * fm + pthread_mutex_lock(&logev_lock); + pthread_cond_signal(&logev_cond); + pthread_mutex_unlock(&logev_lock); +- +- pthread_sigmask(SIG_SETMASK, &old, NULL); + } + + void log_thread_flush (void) +@@ -81,15 +66,8 @@ static void flush_logqueue (void) + + static void * log_thread (void * et) + { +- struct sigaction sig; + int running; + +- sig.sa_handler = sigusr1; +- sigemptyset(&sig.sa_mask); +- sig.sa_flags = 0; +- if (sigaction(SIGUSR1, &sig, NULL) < 0) +- logdbg(stderr, "Cannot set signal handler"); +- + pthread_mutex_lock(&logev_lock); + logq_running = 1; + pthread_mutex_unlock(&logev_lock); +Index: multipath-tools-130222/libmultipath/waiter.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/waiter.c ++++ multipath-tools-130222/libmultipath/waiter.c +@@ -157,8 +157,6 @@ void *waitevent (void *et) + waiter = (struct event_thread *)et; + pthread_cleanup_push(free_waiter, et); + +- block_signal(SIGUSR1, NULL); +- block_signal(SIGHUP, NULL); + while (1) { + r = waiteventloop(waiter); + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -939,8 +939,8 @@ int + cli_shutdown (void * v, char ** reply, int * len, void * data) + { + condlog(3, "shutdown (operator)"); +- +- return exit_daemon(0); ++ exit_daemon(); ++ return 0; + } + + int +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -52,6 +53,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "pidfile.h" +@@ -81,13 +83,11 @@ struct mpath_event_param + + unsigned int mpath_mx_alloc_len; + +-pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER; +-pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER; +- + int logsink; + enum daemon_status running_state; + pid_t daemon_pid; + ++static sem_t exit_sem; + /* + * global copy of vecs for use in sig handlers + */ +@@ -838,9 +838,6 @@ out: + static void * + ueventloop (void * ap) + { +- block_signal(SIGUSR1, NULL); +- block_signal(SIGHUP, NULL); +- + if (uevent_listen()) + condlog(0, "error starting uevent listener"); + +@@ -850,9 +847,6 @@ ueventloop (void * ap) + static void * + uevqloop (void * ap) + { +- block_signal(SIGUSR1, NULL); +- block_signal(SIGHUP, NULL); +- + if (uevent_dispatch(&uev_trigger, ap)) + condlog(0, "error starting uevent dispatcher"); + +@@ -861,9 +855,6 @@ uevqloop (void * ap) + static void * + uxlsnrloop (void * ap) + { +- block_signal(SIGUSR1, NULL); +- block_signal(SIGHUP, NULL); +- + if (cli_init()) + return NULL; + +@@ -913,18 +904,10 @@ uxlsnrloop (void * ap) + return NULL; + } + +-int +-exit_daemon (int status) ++void ++exit_daemon (void) + { +- if (status != 0) +- fprintf(stderr, "bad exit status. see daemon.log\n"); +- +- if (running_state != DAEMON_SHUTDOWN) { +- pthread_mutex_lock(&exit_mutex); +- pthread_cond_signal(&exit_cond); +- pthread_mutex_unlock(&exit_mutex); +- } +- return status; ++ sem_post(&exit_sem); + } + + const char * +@@ -1287,7 +1270,6 @@ checkerloop (void *ap) + struct path *pp; + int count = 0; + unsigned int i; +- sigset_t old; + + mlockall(MCL_CURRENT | MCL_FUTURE); + vecs = (struct vectors *)ap; +@@ -1301,7 +1283,6 @@ checkerloop (void *ap) + } + + while (1) { +- block_signal(SIGHUP, &old); + pthread_cleanup_push(cleanup_lock, &vecs->lock); + lock(vecs->lock); + pthread_testcancel(); +@@ -1325,7 +1306,6 @@ checkerloop (void *ap) + } + + lock_cleanup_pop(vecs->lock); +- pthread_sigmask(SIG_SETMASK, &old, NULL); + sleep(1); + } + return NULL; +@@ -1485,36 +1465,56 @@ signal_set(int signo, void (*func) (int) + return (osig.sa_handler); + } + ++void ++handle_signals(void) ++{ ++ if (reconfig_sig && running_state == DAEMON_RUNNING) { ++ condlog(2, "reconfigure (signal)"); ++ pthread_cleanup_push(cleanup_lock, ++ &gvecs->lock); ++ lock(gvecs->lock); ++ pthread_testcancel(); ++ reconfigure(gvecs); ++ lock_cleanup_pop(gvecs->lock); ++ } ++ if (log_reset_sig) { ++ condlog(2, "reset log (signal)"); ++ pthread_mutex_lock(&logq_lock); ++ log_reset("multipathd"); ++ pthread_mutex_unlock(&logq_lock); ++ } ++ reconfig_sig = 0; ++ log_reset_sig = 0; ++} ++ + static void + sighup (int sig) + { +- condlog(2, "reconfigure (SIGHUP)"); +- +- if (running_state != DAEMON_RUNNING) +- return; +- +- reconfigure(gvecs); +- +-#ifdef _DEBUG_ +- dbg_free_final(NULL); +-#endif ++ reconfig_sig = 1; + } + + static void + sigend (int sig) + { +- exit_daemon(0); ++ exit_daemon(); + } + + static void + sigusr1 (int sig) + { +- condlog(3, "SIGUSR1 received"); ++ log_reset_sig = 1; + } + + static void + signal_init(void) + { ++ sigset_t set; ++ ++ sigemptyset(&set); ++ sigaddset(&set, SIGHUP); ++ sigaddset(&set, SIGUSR1); ++ pthread_sigmask(SIG_BLOCK, &set, NULL); ++ + signal_set(SIGHUP, sighup); + signal_set(SIGUSR1, sigusr1); + signal_set(SIGINT, sigend); +@@ -1587,10 +1587,11 @@ child (void * param) + struct vectors * vecs; + struct multipath * mpp; + int i; +- sigset_t set; + int rc, pid_rc; + + mlockall(MCL_CURRENT | MCL_FUTURE); ++ sem_init(&exit_sem, 0, 0); ++ signal_init(); + + setup_thread_attr(&misc_attr, 64 * 1024, 1); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); +@@ -1650,7 +1651,6 @@ child (void * param) + if (!vecs) + exit(1); + +- signal_init(); + setscheduler(); + set_oom_adj(); + +@@ -1693,25 +1693,17 @@ child (void * param) + } + pthread_attr_destroy(&misc_attr); + +- pthread_mutex_lock(&exit_mutex); + /* Startup complete, create logfile */ + pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid); + /* Ignore errors, we can live without */ + + running_state = DAEMON_RUNNING; +- pthread_cond_wait(&exit_cond, &exit_mutex); +- /* Need to block these to avoid deadlocking */ +- sigemptyset(&set); +- sigaddset(&set, SIGTERM); +- sigaddset(&set, SIGINT); +- pthread_sigmask(SIG_BLOCK, &set, NULL); + + /* + * exit path + */ ++ while(sem_wait(&exit_sem) != 0); /* Do nothing */ + running_state = DAEMON_SHUTDOWN; +- pthread_sigmask(SIG_UNBLOCK, &set, NULL); +- block_signal(SIGHUP, NULL); + lock(vecs->lock); + if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF) + vector_foreach_slot(vecs->mpvec, mpp, i) +Index: multipath-tools-130222/multipathd/main.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.h ++++ multipath-tools-130222/multipathd/main.h +@@ -16,7 +16,7 @@ struct prin_resp; + + extern pid_t daemon_pid; + +-int exit_daemon(int); ++void exit_daemon(void); + const char * daemon_status(void); + int reconfigure (struct vectors *); + int ev_add_path (struct path *, struct vectors *); +@@ -35,5 +35,6 @@ int mpath_pr_event_handle(struct path *p + void * mpath_pr_event_handler_fn (void * ); + int update_map_pr(struct multipath *mpp); + void * mpath_pr_event_handler_fn (void * pathp ); ++void handle_signals(void); + + #endif /* MAIN_H */ +Index: multipath-tools-130222/multipathd/uxlsnr.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxlsnr.c ++++ multipath-tools-130222/multipathd/uxlsnr.c +@@ -8,6 +8,7 @@ + /* + * A simple domain socket listener + */ ++#define _GNU_SOURCE + #include + #include + #include +@@ -19,20 +20,21 @@ + #include + #include + #include +- ++#include + #include +- + #include + #include + #include + #include ++#include + #include + #include + ++#include "main.h" + #include "cli.h" + #include "uxlsnr.h" + +-#define SLEEP_TIME 5000 ++struct timespec sleep_time = {5, 0}; + + struct client { + int fd; +@@ -42,6 +44,8 @@ struct client { + static struct client *clients; + static unsigned num_clients; + struct pollfd *polls; ++volatile sig_atomic_t reconfig_sig = 0; ++volatile sig_atomic_t log_reset_sig = 0; + + /* + * handle a new client joining +@@ -104,6 +108,7 @@ void * uxsock_listen(int (*uxsock_trigge + int rlen; + char *inbuf; + char *reply; ++ sigset_t mask; + + ux_sock = ux_socket_listen(DEFAULT_SOCKET); + +@@ -115,7 +120,9 @@ void * uxsock_listen(int (*uxsock_trigge + pthread_cleanup_push(uxsock_cleanup, NULL); + + polls = (struct pollfd *)MALLOC(0); +- ++ pthread_sigmask(SIG_SETMASK, NULL, &mask); ++ sigdelset(&mask, SIGHUP); ++ sigdelset(&mask, SIGUSR1); + while (1) { + struct client *c; + int i, poll_count; +@@ -132,11 +139,13 @@ void * uxsock_listen(int (*uxsock_trigge + } + + /* most of our life is spent in this call */ +- poll_count = poll(polls, i, SLEEP_TIME); ++ poll_count = ppoll(polls, i, &sleep_time, &mask); + + if (poll_count == -1) { +- if (errno == EINTR) ++ if (errno == EINTR) { ++ handle_signals(); + continue; ++ } + + /* something went badly wrong! */ + condlog(0, "poll"); +Index: multipath-tools-130222/multipathd/uxlsnr.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxlsnr.h ++++ multipath-tools-130222/multipathd/uxlsnr.h +@@ -4,5 +4,8 @@ + void * uxsock_listen(int (*uxsock_trigger) + (char *, char **, int *, void *), + void * trigger_data); ++ ++extern volatile sig_atomic_t reconfig_sig; ++extern volatile sig_atomic_t log_reset_sig; + #endif + diff --git a/SOURCES/0043-RH-signal-waiter.patch b/SOURCES/0043-RH-signal-waiter.patch new file mode 100644 index 0000000..a1a63ea --- /dev/null +++ b/SOURCES/0043-RH-signal-waiter.patch @@ -0,0 +1,71 @@ +--- + libmultipath/waiter.c | 9 +++++++++ + multipathd/main.c | 8 ++++++++ + 2 files changed, 17 insertions(+) + +Index: multipath-tools-130222/libmultipath/waiter.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/waiter.c ++++ multipath-tools-130222/libmultipath/waiter.c +@@ -57,6 +57,7 @@ void stop_waiter_thread (struct multipat + thread = mpp->waiter; + mpp->waiter = (pthread_t)0; + pthread_cancel(thread); ++ pthread_kill(thread, SIGUSR2); + } + + /* +@@ -65,6 +66,7 @@ void stop_waiter_thread (struct multipat + */ + int waiteventloop (struct event_thread *waiter) + { ++ sigset_t set, oldset; + int event_nr; + int r; + +@@ -97,8 +99,15 @@ int waiteventloop (struct event_thread * + dm_task_no_open_count(waiter->dmt); + + /* wait */ ++ sigemptyset(&set); ++ sigaddset(&set, SIGUSR2); ++ pthread_sigmask(SIG_UNBLOCK, &set, &oldset); ++ ++ pthread_testcancel(); + r = dm_task_run(waiter->dmt); ++ pthread_testcancel(); + ++ pthread_sigmask(SIG_SETMASK, &oldset, NULL); + dm_task_destroy(waiter->dmt); + waiter->dmt = NULL; + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1506,6 +1506,12 @@ sigusr1 (int sig) + } + + static void ++sigusr2 (int sig) ++{ ++ condlog(3, "SIGUSR2 received"); ++} ++ ++static void + signal_init(void) + { + sigset_t set; +@@ -1513,10 +1519,12 @@ signal_init(void) + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGUSR1); ++ sigaddset(&set, SIGUSR2); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + signal_set(SIGHUP, sighup); + signal_set(SIGUSR1, sigusr1); ++ signal_set(SIGUSR2, sigusr2); + signal_set(SIGINT, sigend); + signal_set(SIGTERM, sigend); + signal(SIGPIPE, SIG_IGN); diff --git a/SOURCES/0044-RHBZ-976688-fix-wipe-wwids.patch b/SOURCES/0044-RHBZ-976688-fix-wipe-wwids.patch new file mode 100644 index 0000000..6f70574 --- /dev/null +++ b/SOURCES/0044-RHBZ-976688-fix-wipe-wwids.patch @@ -0,0 +1,28 @@ +--- + libmultipath/wwids.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -100,6 +101,11 @@ replace_wwids(vector mp) + condlog(0, "cannot truncate wwids file : %s", strerror(errno)); + goto out_file; + } ++ if (lseek(fd, 0, SEEK_SET) < 0) { ++ condlog(0, "cannot seek to the start of the file : %s", ++ strerror(errno)); ++ goto out_file; ++ } + len = strlen(WWIDS_FILE_HEADER); + if (write_all(fd, WWIDS_FILE_HEADER, len) != len) { + condlog(0, "Can't write wwid file header : %s", diff --git a/SOURCES/0045-RHBZ-977297-man-page-fix.patch b/SOURCES/0045-RHBZ-977297-man-page-fix.patch new file mode 100644 index 0000000..3ede0ce --- /dev/null +++ b/SOURCES/0045-RHBZ-977297-man-page-fix.patch @@ -0,0 +1,35 @@ +--- + multipath/multipath.conf.5 | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -136,7 +136,7 @@ per-multipath option in the configuratio + 1 priority group per target node name. Target node names are fetched + in /sys/class/fc_transport/target*/node_name. + .TP +-Default value is \fImultibus\fR. ++Default value is \fIfailover\fR. + .RE + .TP + .B uid_attribute +@@ -182,7 +182,7 @@ Generate a random priority between 1 and + Generate the path priority based on the regular expression and the + priority provided as argument. requires prio_args keyword. + .TP +-Default value is \fBnone\fR. ++Default value is \fBconst\fR. + .RE + .TP + .B prio_args +@@ -270,7 +270,7 @@ The number of IO to route to a path befo + the same path group. This is only for BIO based multipath. Default is + .I 1000 + .TP +-.B rr_min_io_q ++.B rr_min_io_rq + The number of IO requests to route to a path before switching to the + next in the same path group. This is only for request based multipath. + Default is diff --git a/SOURCES/0046-RHBZ-883981-move-udev-rules.patch b/SOURCES/0046-RHBZ-883981-move-udev-rules.patch new file mode 100644 index 0000000..4e5bc85 --- /dev/null +++ b/SOURCES/0046-RHBZ-883981-move-udev-rules.patch @@ -0,0 +1,28 @@ +--- + multipath/Makefile | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -23,8 +23,8 @@ install: + $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/ +- $(INSTALL_PROGRAM) -d $(DESTDIR)/lib/udev/rules.d +- $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/lib/udev/rules.d/62-multipath.rules ++ $(INSTALL_PROGRAM) -d $(DESTDIR)/usr/lib/udev/rules.d ++ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir) +@@ -32,7 +32,7 @@ install: + $(INSTALL_PROGRAM) -m 644 mpathconf.8.gz $(DESTDIR)$(mandir) + + uninstall: +- rm $(DESTDIR)/lib/udev/rules.d/62-multipath.rules ++ rm $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) + rm $(DESTDIR)$(bindir)/mpathconf + rm $(DESTDIR)$(mandir)/$(EXEC).8.gz diff --git a/SOURCES/0047-RHBZ-kpartx-read-only-loop-devs.patch b/SOURCES/0047-RHBZ-kpartx-read-only-loop-devs.patch new file mode 100644 index 0000000..ed79e22 --- /dev/null +++ b/SOURCES/0047-RHBZ-kpartx-read-only-loop-devs.patch @@ -0,0 +1,39 @@ +--- + kpartx/kpartx.c | 3 +-- + kpartx/lopart.c | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -204,7 +204,6 @@ main(int argc, char **argv){ + char * delim = NULL; + char *uuid = NULL; + char *mapname = NULL; +- int loopro = 0; + int hotplug = 0; + int loopcreated = 0; + struct stat buf; +@@ -315,7 +314,7 @@ main(int argc, char **argv){ + if (!loopdev) { + loopdev = find_unused_loop_device(); + +- if (set_loop(loopdev, device, 0, &loopro)) { ++ if (set_loop(loopdev, device, 0, &ro)) { + fprintf(stderr, "can't set up loop\n"); + exit (1); + } +Index: multipath-tools-130222/kpartx/lopart.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/lopart.c ++++ multipath-tools-130222/kpartx/lopart.c +@@ -230,7 +230,7 @@ set_loop (const char *device, const char + + if ((ffd = open (file, mode)) < 0) { + +- if (!*loopro && errno == EROFS) ++ if (!*loopro && (errno == EROFS || errno == EACCES)) + ffd = open (file, mode = O_RDONLY); + + if (ffd < 0) { diff --git a/SOURCES/0048-RH-print-defaults.patch b/SOURCES/0048-RH-print-defaults.patch new file mode 100644 index 0000000..be1ce57 --- /dev/null +++ b/SOURCES/0048-RH-print-defaults.patch @@ -0,0 +1,25 @@ +--- + libmultipath/dict.c | 4 ---- + 1 file changed, 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -2468,16 +2468,12 @@ snprint_def_verbosity (char * buff, int + static int + snprint_def_max_polling_interval (char * buff, int len, void * data) + { +- if (conf->max_checkint == MAX_CHECKINT(conf->checkint)) +- return 0; + return snprintf(buff, len, "%i", conf->max_checkint); + } + + static int + snprint_reassign_maps (char * buff, int len, void * data) + { +- if (conf->reassign_maps == DEFAULT_REASSIGN_MAPS) +- return 0; + return snprintf(buff, len, "\"%s\"", + conf->reassign_maps?"yes":"no"); + } diff --git a/SOURCES/0049-RH-remove-ID_FS_TYPE.patch b/SOURCES/0049-RH-remove-ID_FS_TYPE.patch new file mode 100644 index 0000000..732f50f --- /dev/null +++ b/SOURCES/0049-RH-remove-ID_FS_TYPE.patch @@ -0,0 +1,17 @@ +--- + multipath/multipath.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -11,7 +11,7 @@ ACTION=="add", ENV{DEVTYPE}!="partition" + ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ + TEST=="/etc/multipath.conf", \ + PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \ +- ENV{DM_MULTIPATH_DEVICE_PATH}="1" ++ ENV{DM_MULTIPATH_DEVICE_PATH}="1" ENV{ID_FS_TYPE}="mpath_member" + + ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \ + RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" diff --git a/SOURCES/0050-RH-listing-speedup.patch b/SOURCES/0050-RH-listing-speedup.patch new file mode 100644 index 0000000..4742634 --- /dev/null +++ b/SOURCES/0050-RH-listing-speedup.patch @@ -0,0 +1,17 @@ +--- + multipath/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -311,7 +311,7 @@ configure (void) + /* + * get a path list + */ +- if (conf->dev) ++ if (conf->dev && !conf->list) + di_flag = DI_WWID; + + if (conf->list > 1) diff --git a/SOURCES/0051-UP-fix-cli-resize.patch b/SOURCES/0051-UP-fix-cli-resize.patch new file mode 100644 index 0000000..f278607 --- /dev/null +++ b/SOURCES/0051-UP-fix-cli-resize.patch @@ -0,0 +1,23 @@ +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 7b1cb62..4b860bb 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -603,7 +603,18 @@ cli_resize(void *v, char **reply, int *len, void *data) + } + + pgp = VECTOR_SLOT(mpp->pg, 0); ++ ++ if (!pgp){ ++ condlog(0, "%s: couldn't get path group. cannot resize", ++ mapname); ++ return 1; ++ } + pp = VECTOR_SLOT(pgp->paths, 0); ++ ++ if (!pp){ ++ condlog(0, "%s: couldn't get path. cannot resize", mapname); ++ return 1; ++ } + if (!pp->udev || sysfs_get_size(pp, &size)) { + condlog(0, "%s: couldn't get size for sysfs. cannot resize", + mapname); diff --git a/SOURCES/0052-RH-fix-bad-derefs.patch b/SOURCES/0052-RH-fix-bad-derefs.patch new file mode 100644 index 0000000..db5f1db --- /dev/null +++ b/SOURCES/0052-RH-fix-bad-derefs.patch @@ -0,0 +1,54 @@ +--- + multipathd/cli_handlers.c | 3 ++- + multipathd/main.c | 12 ++++++------ + 2 files changed, 8 insertions(+), 7 deletions(-) + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -632,7 +632,8 @@ cli_resize(void *v, char **reply, int *l + return 1; + + dm_lib_release(); +- setup_multipath(vecs, mpp); ++ if (setup_multipath(vecs, mpp) != 0) ++ return 1; + sync_map_state(mpp); + + return 0; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -134,7 +134,6 @@ coalesce_maps(struct vectors *vecs, vect + struct multipath * ompp; + vector ompv = vecs->mpvec; + unsigned int i; +- int j; + + vector_foreach_slot (ompv, ompp, i) { + if (!find_mp_by_wwid(nmpv, ompp->wwid)) { +@@ -148,16 +147,17 @@ coalesce_maps(struct vectors *vecs, vect + /* + * may be just because the device is open + */ ++ if (setup_multipath(vecs, ompp) != 0) { ++ i--; ++ continue; ++ } + if (!vector_alloc_slot(nmpv)) + return 1; + + vector_set_slot(nmpv, ompp); +- setup_multipath(vecs, ompp); + +- if ((j = find_slot(ompv, (void *)ompp)) != -1) +- vector_del_slot(ompv, j); +- +- continue; ++ vector_del_slot(ompv, i); ++ i--; + } + else { + dm_lib_release(); diff --git a/SOURCES/0053-UP-fix-failback.patch b/SOURCES/0053-UP-fix-failback.patch new file mode 100644 index 0000000..936655d --- /dev/null +++ b/SOURCES/0053-UP-fix-failback.patch @@ -0,0 +1,23 @@ +--- + libmultipath/dict.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -1126,11 +1126,11 @@ hw_failback_handler(vector strvec) + + buff = set_value(strvec); + +- if (strlen(buff) == 6 && !strcmp(buff, "\"manual\"")) ++ if (strlen(buff) == 6 && !strcmp(buff, "manual")) + hwe->pgfailback = -FAILBACK_MANUAL; +- else if (strlen(buff) == 9 && !strcmp(buff, "\"immediate\"")) ++ else if (strlen(buff) == 9 && !strcmp(buff, "immediate")) + hwe->pgfailback = -FAILBACK_IMMEDIATE; +- else if (strlen(buff) == 10 && !strcmp(buff, "\"followover\"")) ++ else if (strlen(buff) == 10 && !strcmp(buff, "followover")) + hwe->pgfailback = -FAILBACK_FOLLOWOVER; + else + hwe->pgfailback = atoi(buff); diff --git a/SOURCES/0054-UP-keep-udev-ref.patch b/SOURCES/0054-UP-keep-udev-ref.patch new file mode 100644 index 0000000..e42d716 --- /dev/null +++ b/SOURCES/0054-UP-keep-udev-ref.patch @@ -0,0 +1,308 @@ +--- + libmpathpersist/mpath_persist.c | 7 ++++--- + libmpathpersist/mpath_persist.h | 2 +- + libmpathpersist/mpath_pr_ioctl.c | 5 +++-- + libmultipath/config.c | 9 +++------ + libmultipath/config.h | 2 +- + mpathpersist/Makefile | 2 +- + mpathpersist/main.c | 11 +++++++---- + multipath/Makefile | 2 +- + multipath/main.c | 12 ++++++++---- + multipathd/main.c | 11 ++++++++--- + 10 files changed, 37 insertions(+), 26 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -1,4 +1,3 @@ +-#include "mpath_persist.h" + #include + #include + #include +@@ -8,6 +7,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -20,6 +20,7 @@ + #include + #include + ++#include "mpath_persist.h" + #include "mpathpr.h" + #include "mpath_pr_ioctl.h" + +@@ -32,9 +33,9 @@ + + + int +-mpath_lib_init (void) ++mpath_lib_init (struct udev *udev) + { +- if (load_config(DEFAULT_CONFIGFILE)){ ++ if (load_config(DEFAULT_CONFIGFILE, udev)){ + condlog(0, "Failed to initialize multipath config."); + return 1; + } +Index: multipath-tools-130222/libmpathpersist/mpath_persist.h +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.h ++++ multipath-tools-130222/libmpathpersist/mpath_persist.h +@@ -174,7 +174,7 @@ struct prout_param_descriptor { /* PROU + * + * RETURNS: 0->Success, 1->Failed. + */ +-extern int mpath_lib_init (void ); ++extern int mpath_lib_init (struct udev *udev); + + + /* +Index: multipath-tools-130222/libmpathpersist/mpath_pr_ioctl.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_pr_ioctl.c ++++ multipath-tools-130222/libmpathpersist/mpath_pr_ioctl.c +@@ -10,8 +10,9 @@ + #include + #include + #include +-#include "mpath_pr_ioctl.h" +-#include ++#include ++#include "mpath_pr_ioctl.h" ++#include + + #include + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -467,9 +467,6 @@ free_config (struct config * conf) + if (conf->dev) + FREE(conf->dev); + +- if (conf->udev) +- udev_unref(conf->udev); +- + if (conf->multipath_dir) + FREE(conf->multipath_dir); + +@@ -519,12 +516,12 @@ free_config (struct config * conf) + } + + int +-load_config (char * file) ++load_config (char * file, struct udev *udev) + { + if (!conf) + conf = alloc_config(); + +- if (!conf) ++ if (!conf || !udev) + return 1; + + /* +@@ -533,7 +530,7 @@ load_config (char * file) + if (!conf->verbosity) + conf->verbosity = DEFAULT_VERBOSITY; + +- conf->udev = udev_new(); ++ conf->udev = udev; + dm_drv_version(conf->version, TGT_MPATH); + conf->dev_type = DEV_NONE; + conf->minio = DEFAULT_MINIO; +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -159,7 +159,7 @@ void free_mptable (vector mptable); + + int store_hwe (vector hwtable, struct hwentry *); + +-int load_config (char * file); ++int load_config (char * file, struct udev * udev); + struct config * alloc_config (void); + void free_config (struct config * conf); + +Index: multipath-tools-130222/mpathpersist/main.c +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.c ++++ multipath-tools-130222/mpathpersist/main.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include "main.h" + #include +@@ -68,7 +69,8 @@ int main (int argc, char * argv[]) + int noisy = 0; + int num_transport =0; + void *resp = NULL; +- struct transportid * tmp; ++ struct transportid * tmp; ++ struct udev *udev = NULL; + + if (optind == argc) + { +@@ -84,8 +86,8 @@ int main (int argc, char * argv[]) + exit (1); + } + +- +- mpath_lib_init(); ++ udev = udev_new(); ++ mpath_lib_init(udev); + memset(transportids,0,MPATH_MX_TIDS); + + while (1) +@@ -461,12 +463,13 @@ int main (int argc, char * argv[]) + if (res < 0) + { + mpath_lib_exit(); ++ udev_unref(udev); + return MPATH_PR_FILE_ERROR; + } + + out : + mpath_lib_exit(); +- ++ udev_unref(udev); + return (ret >= 0) ? ret : MPATH_PR_OTHER; + } + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -435,6 +436,7 @@ convert_dev(char *dev) + int + main (int argc, char *argv[]) + { ++ struct udev *udev; + int arg; + extern char *optarg; + extern int optind; +@@ -445,7 +447,9 @@ main (int argc, char *argv[]) + exit(1); + } + +- if (load_config(DEFAULT_CONFIGFILE)) ++ udev = udev_new(); ++ ++ if (load_config(DEFAULT_CONFIGFILE, udev)) + exit(1); + + if (dm_prereq()) +@@ -560,11 +564,11 @@ main (int argc, char *argv[]) + + if (init_checkers()) { + condlog(0, "failed to initialize checkers"); +- exit(1); ++ goto out; + } + if (init_prio()) { + condlog(0, "failed to initialize prioritizers"); +- exit(1); ++ goto out; + } + dm_init(); + +@@ -628,7 +632,7 @@ out: + */ + free_config(conf); + conf = NULL; +- ++ udev_unref(udev); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -93,6 +93,8 @@ static sem_t exit_sem; + */ + struct vectors * gvecs; + ++struct udev * udev; ++ + static int + need_switch_pathgroup (struct multipath * mpp, int refresh) + { +@@ -1408,7 +1410,7 @@ reconfigure (struct vectors * vecs) + vecs->pathvec = NULL; + conf = NULL; + +- if (!load_config(DEFAULT_CONFIGFILE)) { ++ if (!load_config(DEFAULT_CONFIGFILE, udev)) { + conf->verbosity = old->verbosity; + conf->daemon = 1; + configure(vecs, 1); +@@ -1601,6 +1603,8 @@ child (void * param) + sem_init(&exit_sem, 0, 0); + signal_init(); + ++ udev = udev_new(); ++ + setup_thread_attr(&misc_attr, 64 * 1024, 1); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); + +@@ -1615,7 +1619,7 @@ child (void * param) + condlog(2, "--------start up--------"); + condlog(2, "read " DEFAULT_CONFIGFILE); + +- if (load_config(DEFAULT_CONFIGFILE)) ++ if (load_config(DEFAULT_CONFIGFILE, udev)) + exit(1); + + if (init_checkers()) { +@@ -1765,7 +1769,8 @@ child (void * param) + */ + free_config(conf); + conf = NULL; +- ++ udev_unref(udev); ++ udev = NULL; + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +Index: multipath-tools-130222/mpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/Makefile ++++ multipath-tools-130222/mpathpersist/Makefile +@@ -5,7 +5,7 @@ include ../Makefile.inc + OBJS = main.o + + CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) +-LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath ++LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath -ludev + + EXEC = mpathpersist + +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -7,7 +7,7 @@ include ../Makefile.inc + OBJS = main.o + + CFLAGS += -fPIC -I$(multipathdir) +-LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath ++LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev + + EXEC = multipath + diff --git a/SOURCES/0055-UP-handle-quiesced-paths.patch b/SOURCES/0055-UP-handle-quiesced-paths.patch new file mode 100644 index 0000000..0556a61 --- /dev/null +++ b/SOURCES/0055-UP-handle-quiesced-paths.patch @@ -0,0 +1,16 @@ +--- + libmultipath/discovery.c | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -799,6 +799,7 @@ path_offline (struct path * pp) + condlog(3, "%s: path state = %s", pp->dev, buff); + + if (!strncmp(buff, "offline", 7) || ++ !strncmp(buff, "quiesce", 7) || + !strncmp(buff, "transport-offline", 17)) { + pp->offline = 1; + return PATH_DOWN; diff --git a/SOURCES/0056-UP-alua-prio-fix.patch b/SOURCES/0056-UP-alua-prio-fix.patch new file mode 100644 index 0000000..0ac41ab --- /dev/null +++ b/SOURCES/0056-UP-alua-prio-fix.patch @@ -0,0 +1,17 @@ +--- + libmultipath/prioritizers/alua.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/prioritizers/alua.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua.c ++++ multipath-tools-130222/libmultipath/prioritizers/alua.c +@@ -108,7 +108,7 @@ int getprio (struct path * pp, char * ar + default: + rc = 0; + } +- if (priopath) ++ if (priopath && aas != AAS_OPTIMIZED) + rc += 80; + } else { + switch(-rc) { diff --git a/SOURCES/0057-UP-fix-tmo.patch b/SOURCES/0057-UP-fix-tmo.patch new file mode 100644 index 0000000..0bfc46b --- /dev/null +++ b/SOURCES/0057-UP-fix-tmo.patch @@ -0,0 +1,329 @@ +--- + libmultipath/discovery.c | 109 +++++++++++++++++++++++++++++++++++++---------- + libmultipath/sysfs.c | 86 +++++++++++++++++++++++++++++++------ + libmultipath/sysfs.h | 2 + 3 files changed, 161 insertions(+), 36 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -162,7 +162,6 @@ declare_sysfs_get_str(cutype); + declare_sysfs_get_str(vendor); + declare_sysfs_get_str(model); + declare_sysfs_get_str(rev); +-declare_sysfs_get_str(state); + declare_sysfs_get_str(dev); + + int +@@ -315,9 +314,14 @@ static void + sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + { + struct udev_device *rport_dev = NULL; +- char value[11]; ++ char value[16]; + char rport_id[32]; ++ int delay_fast_io_fail = 0; ++ int current_dev_loss = 0; ++ int ret; + ++ if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ return; + sprintf(rport_id, "rport-%d:%d-%d", + pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id); + rport_dev = udev_device_new_from_subsystem_sysname(conf->udev, +@@ -330,33 +334,85 @@ sysfs_set_rport_tmo(struct multipath *mp + condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no, + pp->sg_id.channel, pp->sg_id.scsi_id, rport_id); + +- snprintf(value, 11, "%u", mpp->dev_loss); +- if (mpp->dev_loss && +- sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) <= 0) { +- if ((mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET || +- mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) +- && mpp->dev_loss > 600) { +- condlog(3, "%s: limiting dev_loss_tmo to 600, since " +- "fast_io_fail is not set", mpp->alias); +- snprintf(value, 11, "%u", 600); +- if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo", +- value, 11) <= 0) +- condlog(0, "%s failed to set dev_loss_tmo", +- mpp->alias); ++ memset(value, 0, 16); ++ if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) { ++ ret = sysfs_attr_get_value(rport_dev, "dev_loss_tmo", ++ value, 16); ++ if (ret <= 0) { ++ condlog(0, "%s: failed to read dev_loss_tmo value, " ++ "error %d", rport_id, -ret); + goto out; + } ++ if (sscanf(value, "%u\n", ¤t_dev_loss) != 1) { ++ condlog(0, "%s: Cannot parse dev_loss_tmo " ++ "attribute '%s'", rport_id, value); ++ goto out; ++ } ++ if ((mpp->dev_loss && ++ mpp->fast_io_fail >= (int)mpp->dev_loss) || ++ (!mpp->dev_loss && ++ mpp->fast_io_fail >= (int)current_dev_loss)) { ++ condlog(3, "%s: limiting fast_io_fail_tmo to %d, since " ++ "it must be less than dev_loss_tmo", ++ rport_id, mpp->dev_loss - 1); ++ if (mpp->dev_loss) ++ mpp->fast_io_fail = mpp->dev_loss - 1; ++ else ++ mpp->fast_io_fail = current_dev_loss - 1; ++ } ++ if (mpp->fast_io_fail >= (int)current_dev_loss) ++ delay_fast_io_fail = 1; ++ } ++ if (mpp->dev_loss > 600 && ++ (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF || ++ mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)) { ++ condlog(3, "%s: limiting dev_loss_tmo to 600, since " ++ "fast_io_fail is unset or off", rport_id); ++ mpp->dev_loss = 600; + } +- if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET){ ++ if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) { + if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) + sprintf(value, "off"); + else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO) + sprintf(value, "0"); ++ else if (delay_fast_io_fail) ++ snprintf(value, 16, "%u", current_dev_loss - 1); + else +- snprintf(value, 11, "%u", mpp->fast_io_fail); +- if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo", +- value, 11) <= 0) { +- condlog(0, "%s failed to set fast_io_fail_tmo", +- mpp->alias); ++ snprintf(value, 16, "%u", mpp->fast_io_fail); ++ ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo", ++ value, strlen(value)); ++ if (ret <= 0) { ++ if (ret == -EBUSY) ++ condlog(3, "%s: rport blocked", rport_id); ++ else ++ condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d", ++ rport_id, value, -ret); ++ goto out; ++ } ++ } ++ if (mpp->dev_loss) { ++ snprintf(value, 16, "%u", mpp->dev_loss); ++ ret = sysfs_attr_set_value(rport_dev, "dev_loss_tmo", ++ value, strlen(value)); ++ if (ret <= 0) { ++ if (ret == -EBUSY) ++ condlog(3, "%s: rport blocked", rport_id); ++ else ++ condlog(0, "%s: failed to set dev_loss_tmo to %s, error %d", ++ rport_id, value, -ret); ++ goto out; ++ } ++ } ++ if (delay_fast_io_fail) { ++ snprintf(value, 16, "%u", mpp->fast_io_fail); ++ ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo", ++ value, strlen(value)); ++ if (ret <= 0) { ++ if (ret == -EBUSY) ++ condlog(3, "%s: rport blocked", rport_id); ++ else ++ condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d", ++ rport_id, value, -ret); + } + } + out: +@@ -394,7 +450,7 @@ sysfs_set_session_tmo(struct multipath * + } else { + snprintf(value, 11, "%u", mpp->fast_io_fail); + if (sysfs_attr_set_value(session_dev, "recovery_tmo", +- value, 11)) { ++ value, 11) <= 0) { + condlog(3, "%s: Failed to set recovery_tmo, " + " error %d", pp->dev, errno); + } +@@ -752,6 +808,9 @@ cciss_sysfs_pathinfo (struct path * pp) + static int + common_sysfs_pathinfo (struct path * pp) + { ++ if (!pp) ++ return 1; ++ + if (!pp->udev) { + condlog(4, "%s: udev not initialised", pp->dev); + return 1; +@@ -793,7 +852,8 @@ path_offline (struct path * pp) + return PATH_DOWN; + } + +- if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE)) ++ memset(buff, 0x0, SCSI_STATE_SIZE); ++ if (sysfs_attr_get_value(parent, "state", buff, SCSI_STATE_SIZE) <= 0) + return PATH_DOWN; + + condlog(3, "%s: path state = %s", pp->dev, buff); +@@ -983,6 +1043,9 @@ pathinfo (struct path *pp, vector hwtabl + { + int path_state; + ++ if (!pp) ++ return 1; ++ + condlog(3, "%s: mask = 0x%x", pp->dev, mask); + + /* +Index: multipath-tools-130222/libmultipath/sysfs.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/sysfs.c ++++ multipath-tools-130222/libmultipath/sysfs.c +@@ -38,7 +38,12 @@ + #include "debug.h" + #include "devmapper.h" + +-ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, ++/* ++ * When we modify an attribute value we cannot rely on libudev for now, ++ * as libudev lacks the capability to update an attribute value. ++ * So for modified attributes we need to implement our own function. ++ */ ++ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name, + char * value, size_t value_len) + { + char devpath[PATH_SIZE]; +@@ -54,28 +59,83 @@ ssize_t sysfs_attr_set_value(struct udev + condlog(4, "open '%s'", devpath); + if (stat(devpath, &statbuf) != 0) { + condlog(4, "stat '%s' failed: %s", devpath, strerror(errno)); +- return 0; ++ return -errno; + } + + /* skip directories */ +- if (S_ISDIR(statbuf.st_mode)) +- return 0; ++ if (S_ISDIR(statbuf.st_mode)) { ++ condlog(4, "%s is a directory", devpath); ++ return -EISDIR; ++ } + + /* skip non-writeable files */ +- if ((statbuf.st_mode & S_IWUSR) == 0) ++ if ((statbuf.st_mode & S_IRUSR) == 0) { ++ condlog(4, "%s is not readable", devpath); ++ return -EPERM; ++ } ++ ++ /* read attribute value */ ++ fd = open(devpath, O_RDONLY); ++ if (fd < 0) { ++ condlog(4, "attribute '%s' can not be opened: %s", ++ devpath, strerror(errno)); ++ return -errno; ++ } ++ size = read(fd, value, value_len); ++ if (size < 0) { ++ condlog(4, "read from %s failed: %s", devpath, strerror(errno)); ++ size = -errno; ++ } else if (size == value_len) { ++ condlog(4, "overflow while reading from %s", devpath); ++ size = 0; ++ } ++ ++ close(fd); ++ return size; ++} ++ ++ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, ++ char * value, size_t value_len) ++{ ++ char devpath[PATH_SIZE]; ++ struct stat statbuf; ++ int fd; ++ ssize_t size = -1; ++ ++ if (!dev || !attr_name || !value || !value_len) + return 0; + ++ snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev), ++ attr_name); ++ condlog(4, "open '%s'", devpath); ++ if (stat(devpath, &statbuf) != 0) { ++ condlog(4, "stat '%s' failed: %s", devpath, strerror(errno)); ++ return -errno; ++ } ++ ++ /* skip directories */ ++ if (S_ISDIR(statbuf.st_mode)) { ++ condlog(4, "%s is a directory", devpath); ++ return -EISDIR; ++ } ++ ++ /* skip non-writeable files */ ++ if ((statbuf.st_mode & S_IWUSR) == 0) { ++ condlog(4, "%s is not writeable", devpath); ++ return -EPERM; ++ } ++ + /* write attribute value */ + fd = open(devpath, O_WRONLY); + if (fd < 0) { + condlog(4, "attribute '%s' can not be opened: %s", + devpath, strerror(errno)); +- return 0; ++ return -errno; + } + size = write(fd, value, value_len); + if (size < 0) { + condlog(4, "write to %s failed: %s", devpath, strerror(errno)); +- size = 0; ++ size = -errno; + } else if (size < value_len) { + condlog(4, "tried to write %ld to %s. Wrote %ld", + (long)value_len, devpath, (long)size); +@@ -89,14 +149,14 @@ ssize_t sysfs_attr_set_value(struct udev + int + sysfs_get_size (struct path *pp, unsigned long long * size) + { +- const char * attr; ++ char attr[255]; + int r; + +- if (!pp->udev) ++ if (!pp->udev || !size) + return 1; + +- attr = udev_device_get_sysattr_value(pp->udev, "size"); +- if (!attr) { ++ attr[0] = '\0'; ++ if (sysfs_attr_get_value(pp->udev, "size", attr, 255) == 0) { + condlog(3, "%s: No size attribute in sysfs", pp->dev); + return 1; + } +@@ -104,8 +164,8 @@ sysfs_get_size (struct path *pp, unsigne + r = sscanf(attr, "%llu\n", size); + + if (r != 1) { +- condlog(3, "%s: Cannot parse size attribute '%s'", +- pp->dev, attr); ++ condlog(3, "%s: Cannot parse size attribute", pp->dev); ++ *size = 0; + return 1; + } + +Index: multipath-tools-130222/libmultipath/sysfs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/sysfs.h ++++ multipath-tools-130222/libmultipath/sysfs.h +@@ -7,6 +7,8 @@ + + ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, + char * value, size_t value_len); ++ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name, ++ char * value, size_t value_len); + int sysfs_get_size (struct path *pp, unsigned long long * size); + int sysfs_check_holders(char * check_devt, char * new_devt); + #endif diff --git a/SOURCES/0058-UP-fix-failback.patch b/SOURCES/0058-UP-fix-failback.patch new file mode 100644 index 0000000..d1fbaeb --- /dev/null +++ b/SOURCES/0058-UP-fix-failback.patch @@ -0,0 +1,17 @@ +--- + libmultipath/dict.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -2562,7 +2562,7 @@ snprint_def_failback (char * buff, int l + if (!pgfailback) + pgfailback = DEFAULT_FAILBACK; + +- switch(conf->pgfailback) { ++ switch(pgfailback) { + case FAILBACK_UNDEF: + break; + case -FAILBACK_MANUAL: diff --git a/SOURCES/0059-UP-flush-failure-queueing.patch b/SOURCES/0059-UP-flush-failure-queueing.patch new file mode 100644 index 0000000..f72f314 --- /dev/null +++ b/SOURCES/0059-UP-flush-failure-queueing.patch @@ -0,0 +1,71 @@ +--- + libmultipath/devmapper.c | 21 +++++++++++++++++---- + libmultipath/devmapper.h | 2 +- + 2 files changed, 18 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -363,7 +363,7 @@ out: + } + + extern int +-dm_get_map(char * name, unsigned long long * size, char * outparams) ++dm_get_map(const char * name, unsigned long long * size, char * outparams) + { + int r = 1; + struct dm_task *dmt; +@@ -682,7 +682,9 @@ _dm_flush_map (const char * mapname, int + extern int + dm_suspend_and_flush_map (const char * mapname) + { +- int s; ++ int s = 0, queue_if_no_path = 0; ++ unsigned long long mapsize; ++ char params[PARAMS_SIZE] = {0}; + + if (!dm_map_present(mapname)) + return 0; +@@ -690,8 +692,17 @@ dm_suspend_and_flush_map (const char * m + if (dm_type(mapname, TGT_MPATH) <= 0) + return 0; /* nothing to do */ + +- s = dm_queue_if_no_path((char *)mapname, 0); +- if (!s) ++ if (!dm_get_map(mapname, &mapsize, params)) { ++ if (strstr(params, "queue_if_no_path")) ++ queue_if_no_path = 1; ++ } ++ ++ if (queue_if_no_path) ++ s = dm_queue_if_no_path((char *)mapname, 0); ++ /* Leave queue_if_no_path alone if unset failed */ ++ if (s) ++ queue_if_no_path = 0; ++ else + s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0); + + if (!dm_flush_map(mapname)) { +@@ -700,6 +711,8 @@ dm_suspend_and_flush_map (const char * m + } + condlog(2, "failed to remove multipath map %s", mapname); + dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname); ++ if (queue_if_no_path) ++ s = dm_queue_if_no_path((char *)mapname, 1); + return 1; + } + +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -14,7 +14,7 @@ int dm_simplecmd_noflush (int, const cha + int dm_addmap_create (struct multipath *mpp, char *params); + int dm_addmap_reload (struct multipath *mpp, char *params); + int dm_map_present (const char *); +-int dm_get_map(char *, unsigned long long *, char *); ++int dm_get_map(const char *, unsigned long long *, char *); + int dm_get_status(char *, char *); + int dm_type(const char *, char *); + int _dm_flush_map (const char *, int); diff --git a/SOURCES/0060-UP-uevent-loop-udev.patch b/SOURCES/0060-UP-uevent-loop-udev.patch new file mode 100644 index 0000000..88fc005 --- /dev/null +++ b/SOURCES/0060-UP-uevent-loop-udev.patch @@ -0,0 +1,127 @@ +--- + libmultipath/uevent.c | 17 ++++++++++++----- + libmultipath/uevent.h | 4 +++- + multipathd/main.c | 8 +++++--- + 3 files changed, 20 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/libmultipath/uevent.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.c ++++ multipath-tools-130222/libmultipath/uevent.c +@@ -47,7 +47,6 @@ + #include "list.h" + #include "uevent.h" + #include "vector.h" +-#include "config.h" + + typedef int (uev_trigger)(struct uevent *, void * trigger_data); + +@@ -127,11 +126,14 @@ service_uevq(struct list_head *tmpq) + + static void uevq_stop(void *arg) + { ++ struct udev *udev = arg; ++ + condlog(3, "Stopping uev queue"); + pthread_mutex_lock(uevq_lockp); + my_uev_trigger = NULL; + pthread_cond_signal(uev_condp); + pthread_mutex_unlock(uevq_lockp); ++ udev_unref(udev); + } + + void +@@ -399,9 +401,9 @@ exit: + return 1; + } + +-int uevent_listen(void) ++int uevent_listen(struct udev *udev) + { +- int err; ++ int err = 2; + struct udev_monitor *monitor = NULL; + int fd, socket_flags; + int need_failback = 1; +@@ -411,9 +413,14 @@ int uevent_listen(void) + * thereby not getting to empty the socket's receive buffer queue + * often enough. + */ +- pthread_cleanup_push(uevq_stop, NULL); ++ if (!udev) { ++ condlog(1, "no udev context"); ++ return 1; ++ } ++ udev_ref(udev); ++ pthread_cleanup_push(uevq_stop, udev); + +- monitor = udev_monitor_new_from_netlink(conf->udev, "udev"); ++ monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!monitor) { + condlog(2, "failed to create udev monitor"); + goto out; +Index: multipath-tools-130222/libmultipath/uevent.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.h ++++ multipath-tools-130222/libmultipath/uevent.h +@@ -13,6 +13,8 @@ + #define NETLINK_KOBJECT_UEVENT 15 + #endif + ++struct udev; ++ + struct uevent { + struct list_head node; + struct udev_device *udev; +@@ -27,7 +29,7 @@ struct uevent { + int is_uevent_busy(void); + void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached); + +-int uevent_listen(void); ++int uevent_listen(struct udev *udev); + int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data), + void * trigger_data); + int uevent_get_major(struct uevent *uev); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -840,7 +840,7 @@ out: + static void * + ueventloop (void * ap) + { +- if (uevent_listen()) ++ if (uevent_listen(udev)) + condlog(0, "error starting uevent listener"); + + return NULL; +@@ -1593,7 +1593,7 @@ static int + child (void * param) + { + pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr; +- pthread_attr_t log_attr, misc_attr; ++ pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; + struct multipath * mpp; + int i; +@@ -1606,6 +1606,7 @@ child (void * param) + udev = udev_new(); + + setup_thread_attr(&misc_attr, 64 * 1024, 1); ++ setup_thread_attr(&uevent_attr, 128 * 1024, 1); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); + + if (logsink) { +@@ -1671,10 +1672,11 @@ child (void * param) + /* + * Start uevent listener early to catch events + */ +- if ((rc = pthread_create(&uevent_thr, &misc_attr, ueventloop, vecs))) { ++ if ((rc = pthread_create(&uevent_thr, &uevent_attr, ueventloop, udev))) { + condlog(0, "failed to create uevent thread: %d", rc); + exit(1); + } ++ pthread_attr_destroy(&uevent_attr); + if ((rc = pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs))) { + condlog(0, "failed to create cli listener: %d", rc); + exit(1); diff --git a/SOURCES/0061-RH-display-find-mpaths.patch b/SOURCES/0061-RH-display-find-mpaths.patch new file mode 100644 index 0000000..05c63f0 --- /dev/null +++ b/SOURCES/0061-RH-display-find-mpaths.patch @@ -0,0 +1,17 @@ +--- + libmultipath/dict.c | 2 -- + 1 file changed, 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -2717,8 +2717,6 @@ snprint_def_log_checker_err (char * buff + static int + snprint_def_find_multipaths (char * buff, int len, void * data) + { +- if (conf->find_multipaths == DEFAULT_FIND_MULTIPATHS) +- return 0; + if (!conf->find_multipaths) + return snprintf(buff, len, "no"); + diff --git a/SOURCES/0062-RH-dont-free-vecs.patch b/SOURCES/0062-RH-dont-free-vecs.patch new file mode 100644 index 0000000..f1c3217 --- /dev/null +++ b/SOURCES/0062-RH-dont-free-vecs.patch @@ -0,0 +1,28 @@ +--- + multipathd/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1735,8 +1735,9 @@ child (void * param) + vecs->pathvec = NULL; + unlock(vecs->lock); + /* Now all the waitevent threads will start rushing in. */ ++ /* freeing vecs isn't worth the races + while (vecs->lock.depth > 0) { +- sleep (1); /* This is weak. */ ++ sleep (1); + condlog(3, "Have %d wait event checkers threads to de-alloc," + " waiting...", vecs->lock.depth); + } +@@ -1746,7 +1747,7 @@ child (void * param) + vecs->lock.mutex = NULL; + FREE(vecs); + vecs = NULL; +- ++ */ + cleanup_checkers(); + cleanup_prio(); + diff --git a/SOURCES/0063-RH-fix-warning.patch b/SOURCES/0063-RH-fix-warning.patch new file mode 100644 index 0000000..7db8056 --- /dev/null +++ b/SOURCES/0063-RH-fix-warning.patch @@ -0,0 +1,26 @@ +--- + kpartx/dasd.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/kpartx/dasd.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/dasd.c ++++ multipath-tools-130222/kpartx/dasd.c +@@ -46,6 +46,8 @@ unsigned long long sectors512(unsigned l + return sectors * (blocksize >> 9); + } + ++typedef unsigned int __attribute__((__may_alias__)) label_ints_t; ++ + /* + */ + int +@@ -169,7 +171,7 @@ read_dasd_pt(int fd, struct slice all, s + /* + * VM style CMS1 labeled disk + */ +- unsigned int *label = (unsigned int *) &vlabel; ++ label_ints_t *label = (label_ints_t *) &vlabel; + + blocksize = label[4]; + if (label[14] != 0) { diff --git a/SOURCES/0064-RHBZ-1010040-fix-ID_FS-attrs.patch b/SOURCES/0064-RHBZ-1010040-fix-ID_FS-attrs.patch new file mode 100644 index 0000000..cb59a85 --- /dev/null +++ b/SOURCES/0064-RHBZ-1010040-fix-ID_FS-attrs.patch @@ -0,0 +1,383 @@ +--- + libmultipath/defaults.h | 3 - + libmultipath/file.c | 89 +++++++++++++++++++++++++++++++++++++++++- + libmultipath/file.h | 3 + + libmultipath/wwids.c | 7 ++- + multipath/main.c | 36 +++++++++++++++- + multipath/multipath.rules | 26 +++++++++--- + multipathd/main.c | 4 + + multipathd/multipathd.service | 2 + multipathd/pidfile.c | 3 + + 9 files changed, 160 insertions(+), 13 deletions(-) + +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -24,7 +24,8 @@ + #define MAX_CHECKINT(a) (a << 2) + + #define MAX_DEV_LOSS_TMO 0x7FFFFFFF +-#define DEFAULT_PIDFILE "/var/run/multipathd.pid" ++#define DEFAULT_PIDFILE "/var/run/multipathd/multipathd.pid" ++#define DEFAULT_TIMESTAMP_FILE "/var/run/multipathd/timestamp" + #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" + #define DEFAULT_CONFIGFILE "/etc/multipath.conf" + #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" +Index: multipath-tools-130222/libmultipath/file.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/file.c ++++ multipath-tools-130222/libmultipath/file.c +@@ -12,10 +12,12 @@ + #include + #include + #include ++#include + + #include "file.h" + #include "debug.h" + #include "uxsock.h" ++#include "defaults.h" + + + /* +@@ -36,8 +38,8 @@ + * See the file COPYING included with this distribution for more details. + */ + +-static int +-ensure_directories_exist(char *str, mode_t dir_mode) ++int ++ensure_directories_exist(const char *str, mode_t dir_mode) + { + char *pathname; + char *end; +@@ -178,3 +180,86 @@ fail: + close(fd); + return -1; + } ++ ++/* If you can't get the timestamp, return equal to just keep using the ++ * existing value. ++ */ ++int timestamp_equal(long int chk_timestamp) ++{ ++ char buf[4096]; ++ FILE *file; ++ long int file_timestamp; ++ int ret = 1; ++ ++ if ((file = fopen(DEFAULT_TIMESTAMP_FILE, "r")) == NULL) { ++ if (errno != ENOENT) ++ condlog(2, "Cannot open timestamp file [%s]: %s", ++ DEFAULT_TIMESTAMP_FILE, strerror(errno)); ++ goto out; ++ } ++ errno = 0; ++ if (fgets(buf, sizeof(buf), file) == NULL) { ++ if (errno) ++ condlog(2, "Cannot read from timestamp file: %s", ++ strerror(errno)); ++ goto out; ++ } ++ if (sscanf(buf, "DM_MULTIPATH_TIMESTAMP=%ld", &file_timestamp) != 1) { ++ if (errno) ++ condlog(0, "Cannot get timestamp: %s", strerror(errno)); ++ else ++ condlog(0, "invalid timestamp file [%s]: %s", ++ DEFAULT_TIMESTAMP_FILE, strerror(errno)); ++ goto out; ++ } ++ if (file_timestamp != chk_timestamp) { ++ condlog(3, "timestamp has changed"); ++ ret = 0; ++ } ++ else ++ condlog(3, "timestamp has not changed"); ++out: ++ if (file) ++ fclose(file); ++ return ret; ++} ++ ++int update_timestamp(int create) ++{ ++ char buf[44]; ++ time_t timestamp; ++ int fd; ++ int flags = O_WRONLY; ++ if (create) ++ flags |= O_CREAT; ++ if((fd = open(DEFAULT_TIMESTAMP_FILE, flags, ++ (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { ++ if (errno == ENOENT) ++ return 0; ++ condlog(0, "Cannot open timestamp file [%s]: %s", ++ DEFAULT_TIMESTAMP_FILE, strerror(errno)); ++ return 1; ++ } ++ if (ftruncate(fd, 0) < 0) { ++ condlog(0, "Cannot truncate timestamp file [%s]: %s", ++ DEFAULT_TIMESTAMP_FILE, strerror(errno)); ++ goto fail; ++ } ++ if (time(×tamp) == -1) { ++ condlog(0, "Cannot get current time: %s", strerror(errno)); ++ goto fail; ++ } ++ memset(buf, 0, sizeof(buf)); ++ snprintf(buf, sizeof(buf)-1, "DM_MULTIPATH_TIMESTAMP=%ld\n", ++ timestamp); ++ if (write(fd, buf, strlen(buf)) != strlen(buf)) { ++ condlog(0, "Cannot write out timestamp to %s: %s", ++ DEFAULT_TIMESTAMP_FILE, strerror(errno)); ++ goto fail; ++ } ++ close(fd); ++ return 0; ++fail: ++ close(fd); ++ return 1; ++} +Index: multipath-tools-130222/libmultipath/file.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/file.h ++++ multipath-tools-130222/libmultipath/file.h +@@ -7,5 +7,8 @@ + + #define FILE_TIMEOUT 30 + int open_file(char *file, int *can_write, char *header); ++int ensure_directories_exist(const char *str, mode_t dir_mode); ++int update_timestamp(int create); ++int timestamp_equal(long int chk_timestamp); + + #endif /* _FILE_H */ +Index: multipath-tools-130222/multipathd/pidfile.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/pidfile.c ++++ multipath-tools-130222/multipathd/pidfile.c +@@ -9,6 +9,7 @@ + #include /* for fcntl() */ + + #include ++#include + + #include "pidfile.h" + +@@ -18,6 +19,8 @@ int pidfile_create(const char *pidFile, + struct flock lock; + int fd, value; + ++ if (ensure_directories_exist(pidFile, 0700)) ++ return 1; + if((fd = open(pidFile, O_WRONLY | O_CREAT, + (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { + condlog(0, "Cannot open pidfile [%s], error was [%s]", +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -125,6 +125,7 @@ replace_wwids(vector mp) + goto out_file; + } + ret = 0; ++ update_timestamp(0); + out_file: + close(fd); + out: +@@ -209,6 +210,8 @@ remove_wwid(char *wwid) { + goto out_file; + } + ret = do_remove_wwid(fd, str); ++ if (!ret) ++ update_timestamp(0); + + out_file: + close(fd); +@@ -294,8 +297,10 @@ remember_wwid(char *wwid) + condlog(3, "failed writing wwid %s to wwids file", wwid); + return -1; + } +- if (ret == 1) ++ if (ret == 1) { + condlog(3, "wrote wwid %s to wwids file", wwid); ++ update_timestamp(0); ++ } + else + condlog(4, "wwid %s already in wwids file", wwid); + return 0; +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -4,18 +4,34 @@ SUBSYSTEM!="block", GOTO="end_mpath" + + IMPORT{cmdline}="nompath" + ENV{nompath}=="?*", GOTO="end_mpath" ++ENV{DEVTYPE}=="partition", GOTO="end_mpath" + ENV{MPATH_SBIN_PATH}="/sbin" + TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" ++TEST!="/etc/multipath.conf", GOTO="check_kpartx" + +-ACTION=="add", ENV{DEVTYPE}!="partition", \ +- ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ +- TEST=="/etc/multipath.conf", \ ++ACTION=="add", ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ + PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \ +- ENV{DM_MULTIPATH_DEVICE_PATH}="1" ENV{ID_FS_TYPE}="mpath_member" ++ ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member" + +-ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \ ++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", \ + RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" + ++ACTION!="change", GOTO="update_timestamp" ++IMPORT{db}="DM_MULTIPATH_TIMESTAMP" ++IMPORT{db}="DM_MULTIPATH_DEVICE_PATH" ++# Check if the device is part of a multipath device. the -T option just keeps ++# the old result if the timestamp hasn't changed. ++PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -T $env{DM_MULTIPATH_TIMESTAMP}:$env{DM_MULTIPATH_DEVICE_PATH} -c $env{DEVNAME}", \ ++ ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member", \ ++ GOTO="update_timestamp" ++ ++# If the device isn't part of a multipath device, clear this ++ENV{DM_MULTIPATH_DEVICE_PATH}="" ++ ++LABEL="update_timestamp" ++IMPORT{file}="/run/multipathd/timestamp" ++ ++LABEL="check_kpartx" + KERNEL!="dm-*", GOTO="end_mpath" + ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10" + ACTION!="change", GOTO="end_mpath" +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -54,6 +54,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "pidfile.h" +@@ -1417,6 +1418,7 @@ reconfigure (struct vectors * vecs) + free_config(old); + retval = 0; + } ++ update_timestamp(0); + + return retval; + } +@@ -1709,6 +1711,7 @@ child (void * param) + + /* Startup complete, create logfile */ + pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid); ++ update_timestamp(1); + /* Ignore errors, we can live without */ + + running_state = DAEMON_RUNNING; +@@ -1758,6 +1761,7 @@ child (void * param) + if (!pid_rc) { + condlog(3, "unlink pidfile"); + unlink(DEFAULT_PIDFILE); ++ unlink(DEFAULT_TIMESTAMP_FILE); + } + + condlog(2, "--------shut down-------"); +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -9,7 +9,7 @@ Conflicts=shutdown.target + + [Service] + Type=forking +-PIDFile=/var/run/multipathd.pid ++PIDFile=/var/run/multipathd/multipathd.pid + ExecStartPre=/sbin/modprobe dm-multipath + ExecStart=/sbin/multipathd + ExecReload=/sbin/multipathd reconfigure +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + #include "dev_t.h" + + int logsink; +@@ -84,7 +85,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); ++ fprintf (stderr, " %s [-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); +@@ -98,6 +99,9 @@ usage (char * progname) + " -f flush a multipath device map\n" \ + " -F flush all multipath device maps\n" \ + " -c check if a device should be a path in a multipath device\n" \ ++ " -T tm:val\n" \ ++ " check if tm matches the multipathd timestamp. If so val is\n" \ ++ " whether or not the device is a path in a multipath device\n" \ + " -q allow queue_if_no_path when multipathd is not running\n"\ + " -d dry run, do not create or update devmaps\n" \ + " -t dump internal hardware table\n" \ +@@ -441,7 +445,31 @@ main (int argc, char *argv[]) + extern char *optarg; + extern int optind; + int r = 1; +- ++ long int timestamp = -1; ++ int valid = -1; ++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ switch(arg) { ++ case 'T': ++ if (optarg[0] == ':') ++ sscanf(optarg, ":%d", &valid); ++ else ++ sscanf(optarg, "%ld:%d", ×tamp, &valid); ++ if (timestamp_equal(timestamp)) ++ return (valid != 1); ++ break; ++ case ':': ++ fprintf(stderr, "Missing option argument\n"); ++ usage(argv[0]); ++ exit(1); ++ case '?': ++ fprintf(stderr, "Unknown switch: %s\n", optarg); ++ usage(argv[0]); ++ exit(1); ++ default: ++ break; ++ } ++ } ++ optind = 1; + if (getuid() != 0) { + fprintf(stderr, "need to be root\n"); + exit(1); +@@ -455,7 +483,7 @@ main (int argc, char *argv[]) + if (dm_prereq()) + exit(1); + +- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtqwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -517,6 +545,8 @@ main (int argc, char *argv[]) + case 't': + r = dump_config(); + goto out; ++ case 'T': ++ break; + case 'h': + usage(argv[0]); + exit(0); diff --git a/SOURCES/0065-UPBZ-995538-fail-rdac-on-unavailable.patch b/SOURCES/0065-UPBZ-995538-fail-rdac-on-unavailable.patch new file mode 100644 index 0000000..ca72b61 --- /dev/null +++ b/SOURCES/0065-UPBZ-995538-fail-rdac-on-unavailable.patch @@ -0,0 +1,21 @@ +--- + libmultipath/checkers/rdac.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/checkers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c ++++ multipath-tools-130222/libmultipath/checkers/rdac.c +@@ -222,10 +222,9 @@ libcheck_check (struct checker * c) + goto done; + } + +- /* check if controller is in service mode */ ++ /* check if controller is reporting asymmetric access state of unavailable */ + if ((inq.avtcvp & 0x10) && +- ((inq.asym_access_state_cur & 0x0F) == 0x3) && +- (inq.vendor_specific_cur == 0x7)) { ++ ((inq.asym_access_state_cur & 0x0F) == 0x3)) { + ret = PATH_DOWN; + goto done; + } diff --git a/SOURCES/0066-UP-dos-4k-partition-fix.patch b/SOURCES/0066-UP-dos-4k-partition-fix.patch new file mode 100644 index 0000000..a2d1b44 --- /dev/null +++ b/SOURCES/0066-UP-dos-4k-partition-fix.patch @@ -0,0 +1,159 @@ +--- + kpartx/dos.c | 17 ++++++++++------- + kpartx/gpt.c | 20 +------------------- + kpartx/kpartx.c | 12 ++++++++++++ + kpartx/kpartx.h | 8 ++++++++ + 4 files changed, 31 insertions(+), 26 deletions(-) + +Index: multipath-tools-130222/kpartx/dos.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/dos.c ++++ multipath-tools-130222/kpartx/dos.c +@@ -26,7 +26,9 @@ read_extended_partition(int fd, struct p + int moretodo = 1; + int i, n=0; + +- next = start = le32_to_cpu(ep->start_sect); ++ int sector_size_mul = get_sector_size(fd)/512; ++ ++ next = start = sector_size_mul * le32_to_cpu(ep->start_sect); + + while (moretodo) { + here = next; +@@ -45,14 +47,14 @@ read_extended_partition(int fd, struct p + memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); + if (is_extended(p.sys_type)) { + if (p.nr_sects && !moretodo) { +- next = start + le32_to_cpu(p.start_sect); ++ next = start + sector_size_mul * le32_to_cpu(p.start_sect); + moretodo = 1; + } + continue; + } + if (n < ns) { +- sp[n].start = here + le32_to_cpu(p.start_sect); +- sp[n].size = le32_to_cpu(p.nr_sects); ++ sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect); ++ sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects); + n++; + } else { + fprintf(stderr, +@@ -76,6 +78,7 @@ read_dos_pt(int fd, struct slice all, st + unsigned long offset = all.start; + int i, n=4; + unsigned char *bp; ++ int sector_size_mul = get_sector_size(fd)/512; + + bp = (unsigned char *)getblock(fd, offset); + if (bp == NULL) +@@ -89,8 +92,8 @@ read_dos_pt(int fd, struct slice all, st + if (is_gpt(p.sys_type)) + return 0; + if (i < ns) { +- sp[i].start = le32_to_cpu(p.start_sect); +- sp[i].size = le32_to_cpu(p.nr_sects); ++ sp[i].start = sector_size_mul * le32_to_cpu(p.start_sect); ++ sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects); + } else { + fprintf(stderr, + "dos_partition: too many slices\n"); +@@ -99,7 +102,7 @@ read_dos_pt(int fd, struct slice all, st + if (is_extended(p.sys_type)) { + n += read_extended_partition(fd, &p, sp+n, ns-n); + /* hide the extended partition itself */ +- sp[i].size = 2; ++ sp[i].size = sector_size_mul * 2; + } + } + return n; +Index: multipath-tools-130222/kpartx/gpt.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/gpt.c ++++ multipath-tools-130222/kpartx/gpt.c +@@ -38,6 +38,7 @@ + #include + #include + #include "crc32.h" ++#include "kpartx.h" + + #if BYTE_ORDER == LITTLE_ENDIAN + # define __le16_to_cpu(x) (x) +@@ -116,25 +117,6 @@ is_pmbr_valid(legacy_mbr *mbr) + + + /************************************************************ +- * get_sector_size +- * Requires: +- * - filedes is an open file descriptor, suitable for reading +- * Modifies: nothing +- * Returns: +- * sector size, or 512. +- ************************************************************/ +-static int +-get_sector_size(int filedes) +-{ +- int rc, sector_size = 512; +- +- rc = ioctl(filedes, BLKSSZGET, §or_size); +- if (rc) +- sector_size = 512; +- return sector_size; +-} +- +-/************************************************************ + * _get_num_sectors + * Requires: + * - filedes is an open file descriptor, suitable for reading +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -606,3 +607,14 @@ getblock (int fd, unsigned int secnr) { + + return bp->block; + } ++ ++int ++get_sector_size(int filedes) ++{ ++ int rc, sector_size = 512; ++ ++ rc = ioctl(filedes, BLKSSZGET, §or_size); ++ if (rc) ++ sector_size = 512; ++ return sector_size; ++} +Index: multipath-tools-130222/kpartx/kpartx.h +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.h ++++ multipath-tools-130222/kpartx/kpartx.h +@@ -2,6 +2,7 @@ + #define _KPARTX_H + + #include ++#include + + /* + * For each partition type there is a routine that takes +@@ -18,6 +19,13 @@ + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) + ++#ifndef BLKSSZGET ++#define BLKSSZGET _IO(0x12,104) /* get block device sector size */ ++#endif ++ ++int ++get_sector_size(int filedes); ++ + /* + * units: 512 byte sectors + */ diff --git a/SOURCES/0067-RHBZ-1022899-fix-udev-partition-handling.patch b/SOURCES/0067-RHBZ-1022899-fix-udev-partition-handling.patch new file mode 100644 index 0000000..6f0a3d8 --- /dev/null +++ b/SOURCES/0067-RHBZ-1022899-fix-udev-partition-handling.patch @@ -0,0 +1,37 @@ +--- + multipath/multipath.rules | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -13,12 +13,13 @@ ACTION=="add", ENV{DM_MULTIPATH_DEVICE_P + PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \ + ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member" + +-ENV{DM_MULTIPATH_DEVICE_PATH}=="1", \ ++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DM_MULTIPATH_WIPE_PARTS}="1", \ + RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" + + ACTION!="change", GOTO="update_timestamp" + IMPORT{db}="DM_MULTIPATH_TIMESTAMP" + IMPORT{db}="DM_MULTIPATH_DEVICE_PATH" ++IMPORT{db}="DM_MULTIPATH_WIPE_PARTS" + # Check if the device is part of a multipath device. the -T option just keeps + # the old result if the timestamp hasn't changed. + PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -T $env{DM_MULTIPATH_TIMESTAMP}:$env{DM_MULTIPATH_DEVICE_PATH} -c $env{DEVNAME}", \ +@@ -27,8 +28,13 @@ PROGRAM=="$env{MPATH_SBIN_PATH}/multipat + + # If the device isn't part of a multipath device, clear this + ENV{DM_MULTIPATH_DEVICE_PATH}="" ++ENV{DM_MULTIPATH_WIPE_PARTS}="" + + LABEL="update_timestamp" ++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DM_MULTIPATH_WIPE_PARTS}!="1", \ ++ ENV{DM_MULTIPATH_WIPE_PARTS}="1", \ ++ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" ++ + IMPORT{file}="/run/multipathd/timestamp" + + LABEL="check_kpartx" diff --git a/SOURCES/0068-RHBZ-1034578-label-partition-devices.patch b/SOURCES/0068-RHBZ-1034578-label-partition-devices.patch new file mode 100644 index 0000000..e8008f7 --- /dev/null +++ b/SOURCES/0068-RHBZ-1034578-label-partition-devices.patch @@ -0,0 +1,18 @@ +--- + multipath/multipath.rules | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -4,7 +4,8 @@ SUBSYSTEM!="block", GOTO="end_mpath" + + IMPORT{cmdline}="nompath" + ENV{nompath}=="?*", GOTO="end_mpath" +-ENV{DEVTYPE}=="partition", GOTO="end_mpath" ++ENV{DEVTYPE}=="partition", IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH", \ ++ GOTO="end_mpath" + ENV{MPATH_SBIN_PATH}="/sbin" + TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" + TEST!="/etc/multipath.conf", GOTO="check_kpartx" diff --git a/SOURCES/0069-UPBZ-1033791-improve-rdac-checker.patch b/SOURCES/0069-UPBZ-1033791-improve-rdac-checker.patch new file mode 100644 index 0000000..c838f29 --- /dev/null +++ b/SOURCES/0069-UPBZ-1033791-improve-rdac-checker.patch @@ -0,0 +1,153 @@ +--- + libmultipath/checkers/rdac.c | 91 ++++++++++++++++++++++++++++++++++++++----- + libmultipath/discovery.c | 2 + 2 files changed, 81 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/libmultipath/checkers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c ++++ multipath-tools-130222/libmultipath/checkers/rdac.c +@@ -34,6 +34,18 @@ + #define MSG_RDAC_UP "rdac checker reports path is up" + #define MSG_RDAC_DOWN "rdac checker reports path is down" + #define MSG_RDAC_GHOST "rdac checker reports path is ghost" ++#define MSG_RDAC_DOWN_TYPE(STR) MSG_RDAC_DOWN": "STR ++ ++#define RTPG_UNAVAILABLE 0x3 ++#define RTPG_OFFLINE 0xE ++#define RTPG_TRANSITIONING 0xF ++ ++#define RTPG_UNAVAIL_NON_RESPONSIVE 0x2 ++#define RTPG_UNAVAIL_IN_RESET 0x3 ++#define RTPG_UNAVAIL_CFW_DL1 0x4 ++#define RTPG_UNAVAIL_CFW_DL2 0x5 ++#define RTPG_UNAVAIL_QUIESCED 0x6 ++#define RTPG_UNAVAIL_SERVICE_MODE 0x7 + + struct control_mode_page { + unsigned char header[8]; +@@ -199,22 +211,64 @@ struct volume_access_inq + char PQ_PDT; + char dontcare0[7]; + char avtcvp; +- char dontcare1; +- char asym_access_state_cur; ++ char vol_ppp; ++ char aas_cur; + char vendor_specific_cur; +- char dontcare2[36]; ++ char aas_alt; ++ char vendor_specific_alt; ++ char dontcare1[34]; + }; + ++const char ++*checker_msg_string(struct volume_access_inq *inq) ++{ ++ /* lun not connected */ ++ if (((inq->PQ_PDT & 0xE0) == 0x20) || (inq->PQ_PDT & 0x7f)) ++ return MSG_RDAC_DOWN_TYPE("lun not connected"); ++ ++ /* if no tpg data is available, give the generic path down message */ ++ if (!(inq->avtcvp & 0x10)) ++ return MSG_RDAC_DOWN; ++ ++ /* controller is booting up */ ++ if (((inq->aas_cur & 0x0F) == RTPG_TRANSITIONING) && ++ (inq->aas_alt & 0x0F) != RTPG_TRANSITIONING) ++ return MSG_RDAC_DOWN_TYPE("ctlr is in startup sequence"); ++ ++ /* if not unavailable, give generic message */ ++ if ((inq->aas_cur & 0x0F) != RTPG_UNAVAILABLE) ++ return MSG_RDAC_DOWN; ++ ++ /* target port group unavailable */ ++ switch (inq->vendor_specific_cur) { ++ case RTPG_UNAVAIL_NON_RESPONSIVE: ++ return MSG_RDAC_DOWN_TYPE("non-responsive to queries"); ++ case RTPG_UNAVAIL_IN_RESET: ++ return MSG_RDAC_DOWN_TYPE("ctlr held in reset"); ++ case RTPG_UNAVAIL_CFW_DL1: ++ case RTPG_UNAVAIL_CFW_DL2: ++ return MSG_RDAC_DOWN_TYPE("ctlr firmware downloading"); ++ case RTPG_UNAVAIL_QUIESCED: ++ return MSG_RDAC_DOWN_TYPE("ctlr quiesced by admin request"); ++ case RTPG_UNAVAIL_SERVICE_MODE: ++ return MSG_RDAC_DOWN_TYPE("ctlr is in service mode"); ++ default: ++ return MSG_RDAC_DOWN_TYPE("ctlr is unavailable"); ++ } ++} ++ + extern int + libcheck_check (struct checker * c) + { + struct volume_access_inq inq; +- int ret; ++ int ret, inqfail; + ++ inqfail = 0; + memset(&inq, 0, sizeof(struct volume_access_inq)); + if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq), + c->timeout)) { + ret = PATH_DOWN; ++ inqfail = 1; + goto done; + } else if (((inq.PQ_PDT & 0xE0) == 0x20) || (inq.PQ_PDT & 0x7f)) { + /* LUN not connected*/ +@@ -222,11 +276,27 @@ libcheck_check (struct checker * c) + goto done; + } + +- /* check if controller is reporting asymmetric access state of unavailable */ +- if ((inq.avtcvp & 0x10) && +- ((inq.asym_access_state_cur & 0x0F) == 0x3)) { +- ret = PATH_DOWN; +- goto done; ++ /* If TPGDE bit set, evaluate TPG information */ ++ if ((inq.avtcvp & 0x10)) { ++ switch (inq.aas_cur & 0x0F) { ++ /* Never use the path if it reports unavailable */ ++ case RTPG_UNAVAILABLE: ++ ret = PATH_DOWN; ++ goto done; ++ /* ++ * If both controllers report transitioning, it ++ * means mode select or STPG is being processed. ++ * ++ * If this controller alone is transitioning, it's ++ * booting and we shouldn't use it yet. ++ */ ++ case RTPG_TRANSITIONING: ++ if ((inq.aas_alt & 0xF) != RTPG_TRANSITIONING) { ++ ret = PATH_DOWN; ++ goto done; ++ } ++ break; ++ } + } + + /* If owner set or ioship mode is enabled return PATH_UP always */ +@@ -238,7 +308,8 @@ libcheck_check (struct checker * c) + done: + switch (ret) { + case PATH_DOWN: +- MSG(c, MSG_RDAC_DOWN); ++ MSG(c, (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") : ++ checker_msg_string(&inq)); + break; + case PATH_UP: + MSG(c, MSG_RDAC_UP); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1116,8 +1116,6 @@ pathinfo (struct path *pp, vector hwtabl + if (!strlen(pp->wwid)) + get_uid(pp); + get_prio(pp); +- } else { +- pp->priority = PRIO_UNDEF; + } + } + diff --git a/SOURCES/0070-RHBZ-1036503-blacklist-td-devs.patch b/SOURCES/0070-RHBZ-1036503-blacklist-td-devs.patch new file mode 100644 index 0000000..ffcae46 --- /dev/null +++ b/SOURCES/0070-RHBZ-1036503-blacklist-td-devs.patch @@ -0,0 +1,17 @@ +--- + libmultipath/blacklist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/blacklist.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.c ++++ multipath-tools-130222/libmultipath/blacklist.c +@@ -163,7 +163,7 @@ setup_default_blist (struct config * con + if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) + return 1; + +- str = STRDUP("^hd[a-z]"); ++ str = STRDUP("^(td|hd)[a-z]"); + if (!str) + return 1; + if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) diff --git a/SOURCES/0071-RHBZ-1031546-strip-dev.patch b/SOURCES/0071-RHBZ-1031546-strip-dev.patch new file mode 100644 index 0000000..64118c2 --- /dev/null +++ b/SOURCES/0071-RHBZ-1031546-strip-dev.patch @@ -0,0 +1,248 @@ +--- + libmultipath/util.c | 22 ++++++++++++++++++++++ + libmultipath/util.h | 1 + + multipath/main.c | 23 +---------------------- + multipathd/cli_handlers.c | 18 ++++++++++++++++++ + 4 files changed, 42 insertions(+), 22 deletions(-) + +Index: multipath-tools-130222/libmultipath/util.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.c ++++ multipath-tools-130222/libmultipath/util.c +@@ -236,6 +236,28 @@ skip_proc: + return 0; + } + ++/* This function returns a pointer inside of the supplied pathname string. ++ * If is_path_device is true, it may also modify the supplied string */ ++char *convert_dev(char *name, int is_path_device) ++{ ++ char *ptr; ++ ++ if (!name) ++ return NULL; ++ if (is_path_device) { ++ ptr = strstr(name, "cciss/"); ++ if (ptr) { ++ ptr += 5; ++ *ptr = '!'; ++ } ++ } ++ if (!strncmp(name, "/dev/", 5) && strlen(name) > 5) ++ ptr = name + 5; ++ else ++ ptr = name; ++ return ptr; ++} ++ + dev_t parse_devt(const char *dev_t) + { + int maj, min; +Index: multipath-tools-130222/libmultipath/util.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.h ++++ multipath-tools-130222/libmultipath/util.h +@@ -10,6 +10,7 @@ size_t strlcat(char *dst, const char *sr + void remove_trailing_chars(char *path, char c); + int devt2devname (char *, int, char *); + dev_t parse_devt(const char *dev_t); ++char *convert_dev(char *dev, int is_path_device); + + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -254,16 +254,7 @@ configure (void) + vecs.pathvec = pathvec; + vecs.mpvec = curmp; + +- /* +- * dev is "/dev/" . "sysfs block dev" +- */ +- if (conf->dev) { +- if (!strncmp(conf->dev, "/dev/", 5) && +- strlen(conf->dev) > 5) +- dev = conf->dev + 5; +- else +- dev = conf->dev; +- } ++ dev = convert_dev(conf->dev, (conf->dev_type == DEV_DEVNODE)); + + /* + * if we have a blacklisted device parameter, exit early +@@ -427,16 +418,6 @@ get_dev_type(char *dev) { + return DEV_DEVMAP; + } + +-static void +-convert_dev(char *dev) +-{ +- char *ptr = strstr(dev, "cciss/"); +- if (ptr) { +- ptr += 5; +- *ptr = '!'; +- } +-} +- + int + main (int argc, char *argv[]) + { +@@ -577,8 +558,6 @@ main (int argc, char *argv[]) + + strncpy(conf->dev, argv[optind], FILE_NAME_SIZE); + conf->dev_type = get_dev_type(conf->dev); +- if (conf->dev_type == DEV_DEVNODE) +- convert_dev(conf->dev); + } + conf->daemon = 0; + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -235,6 +235,7 @@ cli_list_map_topology (void * v, char ** + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); + ++ param = convert_dev(param, 0); + get_path_layout(vecs->pathvec, 0); + mpp = find_mp_by_str(vecs->mpvec, param); + +@@ -416,6 +417,7 @@ cli_add_path (void * v, char ** reply, i + struct path *pp; + int r; + ++ param = convert_dev(param, 1); + condlog(2, "%s: add path (operator)", param); + + if (filter_devnode(conf->blist_devnode, conf->elist_devnode, +@@ -459,6 +461,7 @@ cli_del_path (void * v, char ** reply, i + char * param = get_keyparam(v, PATH); + struct path *pp; + ++ param = convert_dev(param, 1); + condlog(2, "%s: remove path (operator)", param); + pp = find_path_by_dev(vecs->pathvec, param); + if (!pp) { +@@ -478,6 +481,7 @@ cli_add_map (void * v, char ** reply, in + char *alias; + int rc; + ++ param = convert_dev(param, 0); + condlog(2, "%s: add map (operator)", param); + + if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param) > 0) { +@@ -518,6 +522,7 @@ cli_del_map (void * v, char ** reply, in + char *alias; + int rc; + ++ param = convert_dev(param, 0); + condlog(2, "%s: remove map (operator)", param); + minor = dm_get_minor(param); + if (minor < 0) { +@@ -549,6 +554,7 @@ cli_reload(void *v, char **reply, int *l + struct multipath *mpp; + int minor; + ++ mapname = convert_dev(mapname, 0); + condlog(2, "%s: reload map (operator)", mapname); + if (sscanf(mapname, "dm-%d", &minor) == 1) + mpp = find_mp_by_minor(vecs->mpvec, minor); +@@ -591,6 +597,7 @@ cli_resize(void *v, char **reply, int *l + struct pathgroup *pgp; + struct path *pp; + ++ mapname = convert_dev(mapname, 0); + condlog(2, "%s: resize map (operator)", mapname); + if (sscanf(mapname, "dm-%d", &minor) == 1) + mpp = find_mp_by_minor(vecs->mpvec, minor); +@@ -665,6 +672,7 @@ cli_restore_queueing(void *v, char **rep + struct multipath *mpp; + int minor; + ++ mapname = convert_dev(mapname, 0); + condlog(2, "%s: restore map queueing (operator)", mapname); + if (sscanf(mapname, "dm-%d", &minor) == 1) + mpp = find_mp_by_minor(vecs->mpvec, minor); +@@ -716,6 +724,7 @@ cli_disable_queueing(void *v, char **rep + struct multipath *mpp; + int minor; + ++ mapname = convert_dev(mapname, 0); + condlog(2, "%s: disable map queueing (operator)", mapname); + if (sscanf(mapname, "dm-%d", &minor) == 1) + mpp = find_mp_by_minor(vecs->mpvec, minor); +@@ -753,6 +762,7 @@ cli_switch_group(void * v, char ** reply + char * mapname = get_keyparam(v, MAP); + int groupnum = atoi(get_keyparam(v, GROUP)); + ++ mapname = convert_dev(mapname, 0); + condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum); + + return dm_switchgroup(mapname, groupnum); +@@ -775,6 +785,7 @@ cli_suspend(void * v, char ** reply, int + char * param = get_keyparam(v, MAP); + int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param); + ++ param = convert_dev(param, 0); + condlog(2, "%s: suspend (operator)", param); + + if (!r) /* error */ +@@ -796,6 +807,7 @@ cli_resume(void * v, char ** reply, int + char * param = get_keyparam(v, MAP); + int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param); + ++ param = convert_dev(param, 0); + condlog(2, "%s: resume (operator)", param); + + if (!r) /* error */ +@@ -817,6 +829,7 @@ cli_reinstate(void * v, char ** reply, i + char * param = get_keyparam(v, PATH); + struct path * pp; + ++ param = convert_dev(param, 1); + pp = find_path_by_dev(vecs->pathvec, param); + + if (!pp) +@@ -837,6 +850,7 @@ cli_reassign (void * v, char ** reply, i + { + char * param = get_keyparam(v, MAP); + ++ param = convert_dev(param, 0); + condlog(3, "%s: reset devices (operator)", param); + + dm_reassign(param); +@@ -851,6 +865,7 @@ cli_fail(void * v, char ** reply, int * + struct path * pp; + int r; + ++ param = convert_dev(param, 1); + pp = find_path_by_dev(vecs->pathvec, param); + + if (!pp) +@@ -962,6 +977,7 @@ cli_getprstatus (void * v, char ** reply + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); + ++ param = convert_dev(param, 0); + get_path_layout(vecs->pathvec, 0); + mpp = find_mp_by_str(vecs->mpvec, param); + +@@ -991,6 +1007,7 @@ cli_setprstatus(void * v, char ** reply, + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); + ++ param = convert_dev(param, 0); + get_path_layout(vecs->pathvec, 0); + mpp = find_mp_by_str(vecs->mpvec, param); + +@@ -1013,6 +1030,7 @@ cli_unsetprstatus(void * v, char ** repl + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); + ++ param = convert_dev(param, 0); + get_path_layout(vecs->pathvec, 0); + mpp = find_mp_by_str(vecs->mpvec, param); + diff --git a/SOURCES/0072-RHBZ-1039199-check-loop-control.patch b/SOURCES/0072-RHBZ-1039199-check-loop-control.patch new file mode 100644 index 0000000..21bd0c3 --- /dev/null +++ b/SOURCES/0072-RHBZ-1039199-check-loop-control.patch @@ -0,0 +1,46 @@ +--- + kpartx/lopart.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/kpartx/lopart.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/lopart.c ++++ multipath-tools-130222/kpartx/lopart.c +@@ -32,6 +32,10 @@ + #include "lopart.h" + #include "xstrncpy.h" + ++#ifndef LOOP_CTL_GET_FREE ++#define LOOP_CTL_GET_FREE 0x4C82 ++#endif ++ + #if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \ + && !defined (__s390x__) + #define int2ptr(x) ((void *) ((int) x)) +@@ -140,14 +144,24 @@ find_unused_loop_device (void) + + char dev[20]; + char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; +- int i, j, fd, somedev = 0, someloop = 0, loop_known = 0; ++ int i, j, fd, first = 0, somedev = 0, someloop = 0, loop_known = 0; + struct stat statbuf; + struct loop_info loopinfo; + FILE *procdev; + ++ if (stat("/dev/loop-control", &statbuf) == 0 && ++ S_ISCHR(statbuf.st_mode)) { ++ fd = open("/dev/loop-control", O_RDWR); ++ if (fd >= 0) { ++ first = ioctl(fd, LOOP_CTL_GET_FREE); ++ close(fd); ++ } ++ if (first < 0) ++ first = 0; ++ } + for (j = 0; j < SIZE(loop_formats); j++) { + +- for(i = 0; i < 256; i++) { ++ for(i = first; i < 256; i++) { + sprintf(dev, loop_formats[j], i); + + if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { diff --git a/SOURCES/0073-RH-update-build-flags.patch b/SOURCES/0073-RH-update-build-flags.patch new file mode 100644 index 0000000..3ab72d0 --- /dev/null +++ b/SOURCES/0073-RH-update-build-flags.patch @@ -0,0 +1,33 @@ +--- + Makefile.inc | 2 +- + libmultipath/checkers/rdac.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -39,7 +39,7 @@ GZIP = /bin/gzip -9 -c + INSTALL_PROGRAM = install + + ifndef RPM_OPT_FLAGS +- RPM_OPT_FLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 ++ RPM_OPT_FLAGS = -O2 -g -pipe -Wformat-security -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 + endif + + LDFLAGS += -Wl,-z,relro +Index: multipath-tools-130222/libmultipath/checkers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c ++++ multipath-tools-130222/libmultipath/checkers/rdac.c +@@ -308,8 +308,8 @@ libcheck_check (struct checker * c) + done: + switch (ret) { + case PATH_DOWN: +- MSG(c, (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") : +- checker_msg_string(&inq)); ++ MSG(c, "%s", (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") : ++ checker_msg_string(&inq)); + break; + case PATH_UP: + MSG(c, MSG_RDAC_UP); diff --git a/SOURCES/0074-RHBZ-1056976-dm-mpath-rules.patch b/SOURCES/0074-RHBZ-1056976-dm-mpath-rules.patch new file mode 100644 index 0000000..9f6c880 --- /dev/null +++ b/SOURCES/0074-RHBZ-1056976-dm-mpath-rules.patch @@ -0,0 +1,64 @@ +--- + multipath/11-dm-mpath.rules | 34 ++++++++++++++++++++++++++++++++++ + multipath/Makefile | 2 ++ + 2 files changed, 36 insertions(+) + +Index: multipath-tools-130222/multipath/11-dm-mpath.rules +=================================================================== +--- /dev/null ++++ multipath-tools-130222/multipath/11-dm-mpath.rules +@@ -0,0 +1,34 @@ ++ACTION!="add|change", GOTO="mpath_end" ++ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="mpath_end" ++ENV{DM_UUID}!="mpath-?*", GOTO="mpath_end" ++ ++# Do not initiate scanning if no path is available, ++# otherwise there would be a hang or IO error on access. ++# We'd like to avoid this, especially within udev processing. ++ENV{DM_NR_VALID_PATHS}!="?*", IMPORT{db}="DM_NR_VALID_PATHS" ++ENV{DM_NR_VALID_PATHS}=="0", ENV{DM_NOSCAN}="1" ++ ++# Also skip all foreign rules if no path is available. ++# Remember the original value of DM_DISABLE_OTHER_RULES_FLAG ++# and restore it back once we have at least one path available. ++IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD" ++ENV{DM_ACTION}=="PATH_FAILED",\ ++ ENV{DM_NR_VALID_PATHS}=="0",\ ++ ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}=="",\ ++ ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}",\ ++ ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" ++ENV{DM_ACTION}=="PATH_REINSTATED",\ ++ ENV{DM_NR_VALID_PATHS}=="1",\ ++ ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}",\ ++ ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="",\ ++ ENV{DM_ACTIVATION}="1" ++ ++# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem. ++# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its ++# paths are lost/recovered. For any stack above the mpath device, this is not ++# something that should be reacted upon since it would be useless extra work. ++# It's exactly mpath's job to provide *seamless* device access to any of the ++# paths that are available underneath. ++ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0" ++ ++LABEL="mpath_end" +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -25,6 +25,7 @@ install: + $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/ + $(INSTALL_PROGRAM) -d $(DESTDIR)/usr/lib/udev/rules.d + $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules ++ $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)/usr/lib/udev/rules.d/11-dm-mpath.rules + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir) +@@ -33,6 +34,7 @@ install: + + uninstall: + rm $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules ++ rm $(DESTDIR)/usr/lib/udev/rules.d/11-dm-mpath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) + rm $(DESTDIR)$(bindir)/mpathconf + rm $(DESTDIR)$(mandir)/$(EXEC).8.gz diff --git a/SOURCES/0075-RHBZ-1056976-reload-flag.patch b/SOURCES/0075-RHBZ-1056976-reload-flag.patch new file mode 100644 index 0000000..ee2cdee --- /dev/null +++ b/SOURCES/0075-RHBZ-1056976-reload-flag.patch @@ -0,0 +1,246 @@ +--- + kpartx/devmapper.c | 4 ++-- + kpartx/devmapper.h | 8 +++++++- + kpartx/kpartx.c | 6 +++--- + libmultipath/configure.c | 4 ++-- + libmultipath/devmapper.c | 26 ++++++++++++++------------ + libmultipath/devmapper.h | 10 ++++++++-- + multipathd/cli_handlers.c | 4 ++-- + 7 files changed, 38 insertions(+), 24 deletions(-) + +Index: multipath-tools-130222/kpartx/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.c ++++ multipath-tools-130222/kpartx/devmapper.c +@@ -60,7 +60,7 @@ dm_prereq (char * str, int x, int y, int + } + + extern int +-dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie) { ++dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie, uint16_t udev_flags) { + int r = 0; + int udev_wait_flag = (task == DM_DEVICE_RESUME || + task == DM_DEVICE_REMOVE); +@@ -78,7 +78,7 @@ dm_simplecmd (int task, const char *name + if (no_flush) + dm_task_no_flush(dmt); + +- if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, (udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK)) ++ if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, ((udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK) | udev_flags)) + goto out; + r = dm_task_run(dmt); + +Index: multipath-tools-130222/kpartx/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.h ++++ multipath-tools-130222/kpartx/devmapper.h +@@ -2,10 +2,16 @@ + #define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00)) + #define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12)) + ++#ifdef DM_SUBSYSTEM_UDEV_FLAG0 ++#define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0 ++#else ++#define MPATH_UDEV_RELOAD_FLAG 0 ++#endif ++ + extern int udev_sync; + + int dm_prereq (char *, int, int, int); +-int dm_simplecmd (int, const char *, int, uint32_t *); ++int dm_simplecmd (int, const char *, int, uint32_t *, uint16_t); + int dm_addmap (int, const char *, const char *, const char *, uint64_t, + int, const char *, int, mode_t, uid_t, gid_t, uint32_t *); + int dm_map_present (char *); +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -421,7 +421,7 @@ main(int argc, char **argv){ + continue; + + if (!dm_simplecmd(DM_DEVICE_REMOVE, partname, +- 0, &cookie)) { ++ 0, &cookie, 0)) { + r++; + continue; + } +@@ -473,7 +473,7 @@ main(int argc, char **argv){ + } + if (op == DM_DEVICE_RELOAD && + !dm_simplecmd(DM_DEVICE_RESUME, partname, +- 1, &cookie)) { ++ 1, &cookie, MPATH_UDEV_RELOAD_FLAG)) { + fprintf(stderr, "resume failed on %s\n", + partname); + r++; +@@ -505,7 +505,7 @@ main(int argc, char **argv){ + continue; + + if (!dm_simplecmd(DM_DEVICE_REMOVE, +- partname, 1, &cookie)) { ++ partname, 1, &cookie, 0)) { + r++; + continue; + } +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -390,13 +390,13 @@ domap (struct multipath * mpp, char * pa + case ACT_RELOAD: + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, MPATH_UDEV_RELOAD_FLAG); + break; + + case ACT_RESIZE: + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1); ++ r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1, 0); + break; + + case ACT_RENAME: +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -103,7 +103,9 @@ dm_lib_prereq (void) + { + char version[64]; + int v[3]; +-#ifdef LIBDM_API_COOKIE ++#if defined(DM_SUBSYSTEM_UDEV_FLAG0) ++ int minv[3] = {1, 2, 82}; ++#elif defined(LIBDM_API_COOKIE) + int minv[3] = {1, 2, 38}; + #else + int minv[3] = {1, 2, 8}; +@@ -200,7 +202,7 @@ dm_prereq (void) + } + + static int +-dm_simplecmd (int task, const char *name, int no_flush, int need_sync) { ++dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags) { + int r = 0; + int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME || + task == DM_DEVICE_REMOVE)); +@@ -219,7 +221,7 @@ dm_simplecmd (int task, const char *name + dm_task_no_flush(dmt); /* for DM_DEVICE_SUSPEND/RESUME */ + #endif + +- if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) ++ if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags)) + goto out; + r = dm_task_run (dmt); + +@@ -229,13 +231,13 @@ dm_simplecmd (int task, const char *name + } + + extern int +-dm_simplecmd_flush (int task, const char *name, int needsync) { +- return dm_simplecmd(task, name, 0, needsync); ++dm_simplecmd_flush (int task, const char *name, int needsync, uint16_t udev_flags) { ++ return dm_simplecmd(task, name, 0, needsync, udev_flags); + } + + extern int +-dm_simplecmd_noflush (int task, const char *name) { +- return dm_simplecmd(task, name, 1, 1); ++dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags) { ++ return dm_simplecmd(task, name, 1, 1, udev_flags); + } + + extern int +@@ -670,7 +672,7 @@ _dm_flush_map (const char * mapname, int + return 1; + } + +- r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync); ++ r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync, 0); + + if (r) { + condlog(4, "multipath map %s removed", mapname); +@@ -703,14 +705,14 @@ dm_suspend_and_flush_map (const char * m + if (s) + queue_if_no_path = 0; + else +- s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0); ++ s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0, 0); + + if (!dm_flush_map(mapname)) { + condlog(4, "multipath map %s removed", mapname); + return 0; + } + condlog(2, "failed to remove multipath map %s", mapname); +- dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname); ++ dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, 0); + if (queue_if_no_path) + s = dm_queue_if_no_path((char *)mapname, 1); + return 1; +@@ -1077,7 +1079,7 @@ dm_remove_partmaps (const char * mapname + condlog(4, "partition map %s removed", + names->name); + dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name, +- need_sync); ++ need_sync, 0); + } + + next = names->next; +@@ -1305,7 +1307,7 @@ int dm_reassign_table(const char *name, + condlog(3, "%s: failed to reassign targets", name); + goto out_reload; + } +- dm_simplecmd_noflush(DM_DEVICE_RESUME, name); ++ dm_simplecmd_noflush(DM_DEVICE_RESUME, name, MPATH_UDEV_RELOAD_FLAG); + } + r = 1; + +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -6,11 +6,17 @@ + #define TGT_MPATH "multipath" + #define TGT_PART "linear" + ++#ifdef DM_SUBSYSTEM_UDEV_FLAG0 ++#define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0 ++#else ++#define MPATH_UDEV_RELOAD_FLAG 0 ++#endif ++ + void dm_init(void); + int dm_prereq (void); + int dm_drv_version (unsigned int * version, char * str); +-int dm_simplecmd_flush (int, const char *, int); +-int dm_simplecmd_noflush (int, const char *); ++int dm_simplecmd_flush (int, const char *, int, uint16_t); ++int dm_simplecmd_noflush (int, const char *, uint16_t); + int dm_addmap_create (struct multipath *mpp, char *params); + int dm_addmap_reload (struct multipath *mpp, char *params); + int dm_map_present (const char *); +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -783,7 +783,7 @@ cli_suspend(void * v, char ** reply, int + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); +- int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param); ++ int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0); + + param = convert_dev(param, 0); + condlog(2, "%s: suspend (operator)", param); +@@ -805,7 +805,7 @@ cli_resume(void * v, char ** reply, int + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); +- int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param); ++ int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0); + + param = convert_dev(param, 0); + condlog(2, "%s: resume (operator)", param); diff --git a/SOURCES/0076-RHBZ-1056686-add-hw_str_match.patch b/SOURCES/0076-RHBZ-1056686-add-hw_str_match.patch new file mode 100644 index 0000000..dc9aca6 --- /dev/null +++ b/SOURCES/0076-RHBZ-1056686-add-hw_str_match.patch @@ -0,0 +1,125 @@ +--- + libmultipath/config.c | 10 ++++++++-- + libmultipath/config.h | 1 + + libmultipath/dict.c | 28 ++++++++++++++++++++++++++++ + multipath/multipath.conf.5 | 11 +++++++++++ + 4 files changed, 48 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -431,11 +431,16 @@ restart: + break; + j = n; + vector_foreach_slot_after(hw, hwe2, j) { +- if (hwe_regmatch(hwe1, hwe2)) ++ if (conf->hw_strmatch) { ++ if (hwe_strmatch(hwe2, hwe1)) ++ continue; ++ } ++ else if (hwe_regmatch(hwe1, hwe2)) + continue; + /* dup */ + merge_hwe(hwe2, hwe1); +- if (hwe_strmatch(hwe2, hwe1) == 0) { ++ if (conf->hw_strmatch || ++ hwe_strmatch(hwe2, hwe1) == 0) { + vector_del_slot(hw, i); + free_hwe(hwe1); + n -= 1; +@@ -550,6 +555,7 @@ load_config (char * file, struct udev *u + conf->fast_io_fail = DEFAULT_FAST_IO_FAIL; + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; + conf->detect_prio = DEFAULT_DETECT_PRIO; ++ conf->hw_strmatch = 0; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -107,6 +107,7 @@ struct config { + int log_checker_err; + int allow_queueing; + int find_multipaths; ++ int hw_strmatch; + uid_t uid; + gid_t gid; + mode_t mode; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -693,6 +693,25 @@ def_detect_prio_handler(vector strvec) + return 0; + } + ++static int ++def_hw_strmatch_handler(vector strvec) ++{ ++ char *buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) || ++ !strncmp(buff, "1", 1)) ++ conf->hw_strmatch = 1; ++ else ++ conf->hw_strmatch = 0; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -2795,6 +2814,14 @@ snprint_def_detect_prio(char * buff, int + } + + static int ++snprint_def_hw_strmatch(char * buff, int len, void * data) ++{ ++ if (conf->hw_strmatch) ++ return snprintf(buff, len, "yes"); ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -2861,6 +2888,7 @@ init_keywords(void) + install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths); + install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler); + install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio); ++ install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -400,6 +400,17 @@ will automatically use the + .I alua + prioritizer. If not, the prioritizer will be selected as usual. Default is + .I no ++.TP ++.B hw_str_match ++If set to ++.I yes ++, the vendor, product, and revision parameters of user device configs will be ++string matched against the built-in device configs to determine if they should ++modify an existing config, or create a new one. If set to ++.I no ++, the user device configs will be regular expression matched against the ++built-in configs instead. Default is ++.I no + . + .SH "blacklist section" + The diff --git a/SOURCES/0077-RHBZ-1054806-mpathconf-always-reload.patch b/SOURCES/0077-RHBZ-1054806-mpathconf-always-reload.patch new file mode 100644 index 0000000..467da8a --- /dev/null +++ b/SOURCES/0077-RHBZ-1054806-mpathconf-always-reload.patch @@ -0,0 +1,16 @@ +--- + multipath/mpathconf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/mpathconf +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf ++++ multipath-tools-130222/multipath/mpathconf +@@ -316,6 +316,6 @@ elif [ "$ENABLE" = 0 ]; then + if [ "$HAVE_MULTIPATHD" = 1 ]; then + systemctl stop multipathd.service + fi +-elif [ -n "$CHANGED_CONFIG" -a "$HAVE_MULTIPATHD" = 1 ]; then ++elif [ "$HAVE_MULTIPATHD" = 1 ]; then + systemctl reload multipathd.service + fi diff --git a/SOURCES/0078-RHBZ-1054044-fix-mpathconf-manpage.patch b/SOURCES/0078-RHBZ-1054044-fix-mpathconf-manpage.patch new file mode 100644 index 0000000..b06b410 --- /dev/null +++ b/SOURCES/0078-RHBZ-1054044-fix-mpathconf-manpage.patch @@ -0,0 +1,17 @@ +--- + multipath/mpathconf.8 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/mpathconf.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf.8 ++++ multipath-tools-130222/multipath/mpathconf.8 +@@ -86,7 +86,7 @@ If set to \fBy\fP, this runs + .B service multipathd start + to start the multipathd daemon on \fB--enable\fP, + .B service multipathd stop +-to start the multipathd daemon on \fB--disable\fP, and ++to stop the multipathd daemon on \fB--disable\fP, and + .B service multipathd reload + to reconfigure multipathd on \fB--user_frindly_names\fP and + \fB--find_multipaths\fP. diff --git a/SOURCES/0079-RHBZ-1070581-add-wwid-option.patch b/SOURCES/0079-RHBZ-1070581-add-wwid-option.patch new file mode 100644 index 0000000..e967a51 --- /dev/null +++ b/SOURCES/0079-RHBZ-1070581-add-wwid-option.patch @@ -0,0 +1,93 @@ +--- + multipath/main.c | 19 ++++++++++++++++--- + multipath/multipath.8 | 5 ++++- + 2 files changed, 20 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -85,7 +85,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); ++ fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); +@@ -98,6 +98,7 @@ usage (char * progname) + " -ll show multipath topology (maximum info)\n" \ + " -f flush a multipath device map\n" \ + " -F flush all multipath device maps\n" \ ++ " -a add a device wwid to the wwids file\n" \ + " -c check if a device should be a path in a multipath device\n" \ + " -T tm:val\n" \ + " check if tm matches the multipathd timestamp. If so val is\n" \ +@@ -292,6 +293,15 @@ configure (void) + } + goto out; + } ++ if (conf->dry_run == 5) { ++ r = remember_wwid(refwwid); ++ if (r == 0) ++ printf("wwid '%s' added\n", refwwid); ++ else ++ printf("failed adding '%s' to wwids file\n", ++ refwwid); ++ goto out; ++ } + condlog(3, "scope limited to %s", refwwid); + if (conf->dry_run == 2) { + if (check_wwids_file(refwwid, 0) == 0){ +@@ -428,7 +438,7 @@ main (int argc, char *argv[]) + int r = 1; + long int timestamp = -1; + int valid = -1; +- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { + switch(arg) { + case 'T': + if (optarg[0] == ':') +@@ -464,7 +474,7 @@ main (int argc, char *argv[]) + if (dm_prereq()) + exit(1); + +- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -537,6 +547,9 @@ main (int argc, char *argv[]) + case 'W': + conf->dry_run = 4; + break; ++ case 'a': ++ conf->dry_run = 5; ++ break; + case ':': + fprintf(stderr, "Missing option argument\n"); + usage(argv[0]); +Index: multipath-tools-130222/multipath/multipath.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.8 ++++ multipath-tools-130222/multipath/multipath.8 +@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco + .RB [\| \-b\ \c + .IR bindings_file \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w | \-W \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-w | \-W \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -68,6 +68,9 @@ check if a block device should be a path + .B \-q + allow device tables with queue_if_no_path when multipathd is not running + .TP ++.B \-a ++add the wwid for the specified device to the wwids file ++.TP + .B \-w + remove the wwid for the specified device from the wwids file + .TP diff --git a/SOURCES/0080-RHBZ-1075796-cmdline-wwid.patch b/SOURCES/0080-RHBZ-1075796-cmdline-wwid.patch new file mode 100644 index 0000000..f943aa3 --- /dev/null +++ b/SOURCES/0080-RHBZ-1075796-cmdline-wwid.patch @@ -0,0 +1,157 @@ +--- + libmultipath/wwids.c | 44 ++++++++++++++++++++++++++++++++++++++++++ + libmultipath/wwids.h | 1 + multipath/main.c | 12 ++++++++--- + multipath/multipath.8 | 5 +++- + multipathd/multipathd.service | 1 + 5 files changed, 59 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -305,3 +305,47 @@ remember_wwid(char *wwid) + condlog(4, "wwid %s already in wwids file", wwid); + return 0; + } ++ ++int remember_cmdline_wwid(void) ++{ ++ FILE *f = NULL; ++ char buf[LINE_MAX], *next, *ptr; ++ int ret = 0; ++ ++ f = fopen("/proc/cmdline", "re"); ++ if (!f) { ++ condlog(0, "can't open /proc/cmdline : %s", strerror(errno)); ++ return -1; ++ } ++ ++ if (!fgets(buf, sizeof(buf), f)) { ++ if (ferror(f)) ++ condlog(0, "read of /proc/cmdline failed : %s", ++ strerror(errno)); ++ else ++ condlog(0, "couldn't read /proc/cmdline"); ++ fclose(f); ++ return -1; ++ } ++ fclose(f); ++ next = buf; ++ while((ptr = strstr(next, "mpath.wwid="))) { ++ ptr += 11; ++ next = strpbrk(ptr, " \t\n"); ++ if (next) { ++ *next = '\0'; ++ next++; ++ } ++ if (strlen(ptr)) { ++ if (remember_wwid(ptr) != 0) ++ ret = -1; ++ } ++ else { ++ condlog(0, "empty mpath.wwid kernel command line option"); ++ ret = -1; ++ } ++ if (!next) ++ break; ++ } ++ return ret; ++} +Index: multipath-tools-130222/libmultipath/wwids.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.h ++++ multipath-tools-130222/libmultipath/wwids.h +@@ -17,5 +17,6 @@ int remember_wwid(char *wwid); + int check_wwids_file(char *wwid, int write_wwid); + int remove_wwid(char *wwid); + int replace_wwids(vector mp); ++int remember_cmdline_wwid(void); + + #endif /* _WWIDS_H */ +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -85,7 +85,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); ++ fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); +@@ -99,6 +99,8 @@ usage (char * progname) + " -f flush a multipath device map\n" \ + " -F flush all multipath device maps\n" \ + " -a add a device wwid to the wwids file\n" \ ++ " -A add devices from kernel command line mpath.wwids\n" ++ " parameters to wwids file\n" \ + " -c check if a device should be a path in a multipath device\n" \ + " -T tm:val\n" \ + " check if tm matches the multipathd timestamp. If so val is\n" \ +@@ -438,7 +440,7 @@ main (int argc, char *argv[]) + int r = 1; + long int timestamp = -1; + int valid = -1; +- while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { + switch(arg) { + case 'T': + if (optarg[0] == ':') +@@ -474,7 +476,7 @@ main (int argc, char *argv[]) + if (dm_prereq()) + exit(1); + +- while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -538,6 +540,10 @@ main (int argc, char *argv[]) + goto out; + case 'T': + break; ++ case 'A': ++ if (remember_cmdline_wwid() != 0) ++ exit(1); ++ exit(0); + case 'h': + usage(argv[0]); + exit(0); +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -11,6 +11,7 @@ Conflicts=shutdown.target + Type=forking + PIDFile=/var/run/multipathd/multipathd.pid + ExecStartPre=/sbin/modprobe dm-multipath ++ExecStartPre=-/sbin/multipath -A + ExecStart=/sbin/multipathd + ExecReload=/sbin/multipathd reconfigure + #ExecStop=/path/to/scrip delete-me if not necessary +Index: multipath-tools-130222/multipath/multipath.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.8 ++++ multipath-tools-130222/multipath/multipath.8 +@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco + .RB [\| \-b\ \c + .IR bindings_file \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-w | \-W \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-A | \-w | \-W \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -71,6 +71,9 @@ allow device tables with queue_if_no_pat + .B \-a + add the wwid for the specified device to the wwids file + .TP ++.B \-A ++add wwids from any kernel command line mpath.wwid parameters to the wwids file ++.TP + .B \-w + remove the wwid for the specified device from the wwids file + .TP diff --git a/SOURCES/0081-RHBZ-1066264-check-prefix-on-rename.patch b/SOURCES/0081-RHBZ-1066264-check-prefix-on-rename.patch new file mode 100644 index 0000000..791f32e --- /dev/null +++ b/SOURCES/0081-RHBZ-1066264-check-prefix-on-rename.patch @@ -0,0 +1,41 @@ +--- + libmultipath/devmapper.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -1151,6 +1151,8 @@ dm_rename_partmaps (char * old, char * n + unsigned long long size; + char dev_t[32]; + int r = 1; ++ int offset; ++ char *delim; + + if (!(dmt = dm_task_create(DM_DEVICE_LIST))) + return 1; +@@ -1171,6 +1173,11 @@ dm_rename_partmaps (char * old, char * n + if (dm_dev_t(old, &dev_t[0], 32)) + goto out; + ++ if (isdigit(new[strlen(new)-1])) ++ delim = "p"; ++ else ++ delim = ""; ++ + do { + if ( + /* +@@ -1198,8 +1205,9 @@ dm_rename_partmaps (char * old, char * n + * then it's a kpartx generated partition. + * Rename it. + */ +- snprintf(buff, PARAMS_SIZE, "%s%s", +- new, names->name + strlen(old)); ++ for (offset = strlen(old); names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do nothing */ ++ snprintf(buff, PARAMS_SIZE, "%s%s%s", ++ new, delim, names->name + offset); + dm_rename(names->name, buff); + condlog(4, "partition map %s renamed", + names->name); diff --git a/SOURCES/0082-UPBZ-1109995-no-sync-turs-on-pthread_cancel.patch b/SOURCES/0082-UPBZ-1109995-no-sync-turs-on-pthread_cancel.patch new file mode 100644 index 0000000..9a1bd34 --- /dev/null +++ b/SOURCES/0082-UPBZ-1109995-no-sync-turs-on-pthread_cancel.patch @@ -0,0 +1,32 @@ +--- + libmultipath/checkers/tur.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/libmultipath/checkers/tur.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/tur.c ++++ multipath-tools-130222/libmultipath/checkers/tur.c +@@ -409,7 +409,6 @@ libcheck_check (struct checker * c) + ct->running = 0; + MSG(c, MSG_TUR_TIMEOUT); + tur_status = PATH_DOWN; +- ct->state = PATH_UNCHECKED; + } else { + condlog(3, "%d:%d: tur checker not finished", + TUR_DEVT(ct)); +@@ -426,12 +425,10 @@ libcheck_check (struct checker * c) + pthread_mutex_unlock(&ct->lock); + } else { + if (ct->thread) { +- /* pthread cancel failed. continue in sync mode */ + pthread_mutex_unlock(&ct->lock); +- condlog(3, "%d:%d: tur thread not responding, " +- "using sync mode", TUR_DEVT(ct)); +- return tur_check(c->fd, c->timeout, c->message, +- ct->wwid); ++ condlog(3, "%d:%d: tur thread not responding, ", ++ TUR_DEVT(ct)); ++ return PATH_DOWN; + } + /* Start new TUR checker */ + ct->state = PATH_UNCHECKED; diff --git a/SOURCES/0083-RHBZ-1080055-orphan-paths-on-reload.patch b/SOURCES/0083-RHBZ-1080055-orphan-paths-on-reload.patch new file mode 100644 index 0000000..8eaee74 --- /dev/null +++ b/SOURCES/0083-RHBZ-1080055-orphan-paths-on-reload.patch @@ -0,0 +1,85 @@ +--- + libmultipath/structs_vec.c | 31 +++++++++++++++++++++++++++---- + multipathd/main.c | 4 ++++ + 2 files changed, 31 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -280,12 +280,38 @@ update_multipath_status (struct multipat + return 0; + } + ++void sync_paths(struct multipath *mpp, vector pathvec) ++{ ++ struct path *pp; ++ struct pathgroup *pgp; ++ int found, i, j; ++ ++ vector_foreach_slot (mpp->paths, pp, i) { ++ found = 0; ++ vector_foreach_slot(mpp->pg, pgp, j) { ++ if (find_slot(pgp->paths, (void *)pp) != -1) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ condlog(3, "%s dropped path %s", mpp->alias, pp->dev); ++ vector_del_slot(mpp->paths, i--); ++ orphan_path(pp); ++ } ++ } ++ update_mpp_paths(mpp, pathvec); ++ vector_foreach_slot (mpp->paths, pp, i) ++ pp->mpp = mpp; ++} ++ + extern int + update_multipath_strings (struct multipath *mpp, vector pathvec) + { + if (!mpp) + return 1; + ++ update_mpp_paths(mpp, pathvec); + condlog(4, "%s: %s", mpp->alias, __FUNCTION__); + + free_multipath_attributes(mpp); +@@ -294,6 +320,7 @@ update_multipath_strings (struct multipa + + if (update_multipath_table(mpp, pathvec)) + return 1; ++ sync_paths(mpp, pathvec); + + if (update_multipath_status(mpp)) + return 1; +@@ -494,13 +521,9 @@ int update_multipath (struct vectors *ve + return 2; + } + +- free_pgvec(mpp->pg, KEEP_PATHS); +- mpp->pg = NULL; +- + if (__setup_multipath(vecs, mpp, reset)) + return 1; /* mpp freed in setup_multipath */ + +- adopt_paths(vecs->pathvec, mpp, 0); + /* + * compare checkers states with DM states + */ +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1152,6 +1152,10 @@ check_path (struct vectors * vecs, struc + pp->dev); + pp->dmstate = PSTATE_UNDEF; + } ++ /* if update_multipath_strings orphaned the path, quit early */ ++ if (!pp->mpp) ++ return; ++ + pp->chkrstate = newstate; + if (newstate != pp->state) { + int oldstate = pp->state; diff --git a/SOURCES/0084-RHBZ-1110000-multipath-man.patch b/SOURCES/0084-RHBZ-1110000-multipath-man.patch new file mode 100644 index 0000000..4ea422a --- /dev/null +++ b/SOURCES/0084-RHBZ-1110000-multipath-man.patch @@ -0,0 +1,101 @@ +--- + libmultipath/prioritizers/alua.c | 4 ++-- + multipathd/multipathd.8 | 37 +++++++++++++++++++++++++++++++++---- + 2 files changed, 35 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/multipathd/multipathd.8 +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.8 ++++ multipath-tools-130222/multipathd/multipathd.8 +@@ -42,6 +42,9 @@ format wildcards. + .B list|show maps|multipaths + Show the multipath devices that the multipathd is monitoring. + .TP ++.B list|show daemon ++Show the current state of the multipathd daemon ++.TP + .B list|show maps|multipaths format $format + Show the status of all multipath devices that the multipathd is monitoring, + using a format string with multipath format wildcards. +@@ -83,16 +86,16 @@ Add a path to the list of monitored path + .B remove|del path $path + Stop monitoring a path. $path is as listed in /sys/block (e.g. sda). + .TP +-.B add map $map ++.B add map|multipath $map + Add a multipath device to the list of monitored devices. $map can either be a device-mapper device as listed in /sys/block (e.g. dm-0) or it can be the alias for the multipath device (e.g. mpath1) or the uid of the multipath device (e.g. 36005076303ffc56200000000000010aa). + .TP +-.B remove|del map $map ++.B remove|del map|multipath $map + Stop monitoring a multipath device. + .TP + .B resize map|multipath $map + Resizes map $map to the given size + .TP +-.B switch|switchgroup map $map group $group ++.B switch|switchgroup map|multipath $map group $group + Force a multipath device to switch to a specific path group. $group is the path group index, starting with 1. + .TP + .B reconfigure +@@ -104,6 +107,13 @@ Sets map $map into suspend state. + .B resume map|multipath $map + Resumes map $map from suspend state. + .TP ++.B reset map|multipath $map ++Reassign existing device-mapper table(s) use use the multipath device, instead ++of its path devices. ++.TP ++.B reload map|multipath $map ++Reload a multipath device. ++.TP + .B fail path $path + Sets path $path into failed state. + .TP +@@ -120,10 +130,29 @@ Restore queueing on all multipath device + Disable queuing on multipathed map $map + .TP + .B restorequeueing map|multipath $map +-Restore queuing on multipahted map $map ++Restore queuing on multipathed map $map ++.TP ++.B forcequeueing daemon ++Forces multipathd into queue_without_daemon mode, so that no_path_retry queueing ++will not be disabled when the daemon stops ++.TP ++.B restorequeueing daemon ++Restores configured queue_without_daemon mode ++.TP ++.B map|multipath $map setprstatus ++Enable persistent reservation management on $map ++.TP ++.B map|multipath $map unsetprstatus ++Disable persistent reservation management on $map ++.TP ++.B map|multipath $map getprstatus ++Get the current persistent reservation management status of $map + .TP + .B quit|exit + End interactive session. ++.TP ++.B shutdown ++Stop multipathd. + + .SH "SEE ALSO" + .BR multipath (8) +Index: multipath-tools-130222/libmultipath/prioritizers/alua.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua.c ++++ multipath-tools-130222/libmultipath/prioritizers/alua.c +@@ -119,10 +119,10 @@ int getprio (struct path * pp, char * ar + condlog(0, "%s: couldn't get target port group", pp->dev); + break; + case ALUA_PRIO_GETAAS_FAILED: +- condlog(0, "%s: couln't get asymmetric access state", pp->dev); ++ condlog(0, "%s: couldn't get asymmetric access state", pp->dev); + break; + case ALUA_PRIO_TPGS_FAILED: +- condlog(3, "%s: couln't get supported alua states", pp->dev); ++ condlog(3, "%s: couldn't get supported alua states", pp->dev); + break; + } + } diff --git a/SOURCES/0085-UPBZ-1110006-datacore-config.patch b/SOURCES/0085-UPBZ-1110006-datacore-config.patch new file mode 100644 index 0000000..cedb5e3 --- /dev/null +++ b/SOURCES/0085-UPBZ-1110006-datacore-config.patch @@ -0,0 +1,28 @@ +--- + libmultipath/hwtable.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1108,6 +1108,19 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .prio_args = NULL, + }, ++ { ++ .vendor = "DataCore", ++ .product = "Virtual Disk", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = NO_PATH_RETRY_QUEUE, ++ .checker_name = TUR, ++ .prio_name = PRIO_ALUA, ++ .prio_args = NULL, ++ }, + /* + * EOL + */ diff --git a/SOURCES/0086-RHBZ-1110007-orphan-path-on-failed-add.patch b/SOURCES/0086-RHBZ-1110007-orphan-path-on-failed-add.patch new file mode 100644 index 0000000..0d6aa58 --- /dev/null +++ b/SOURCES/0086-RHBZ-1110007-orphan-path-on-failed-add.patch @@ -0,0 +1,17 @@ +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -562,7 +562,7 @@ rescan: + return 0; + } + else +- return 1; ++ goto fail; + + fail_map: + remove_map(mpp, vecs, 1); diff --git a/SOURCES/0087-RHBZ-1110013-config-error-checking.patch b/SOURCES/0087-RHBZ-1110013-config-error-checking.patch new file mode 100644 index 0000000..c774bc5 --- /dev/null +++ b/SOURCES/0087-RHBZ-1110013-config-error-checking.patch @@ -0,0 +1,190 @@ +--- + libmultipath/parser.c | 154 ++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 126 insertions(+), 28 deletions(-) + +Index: multipath-tools-130222/libmultipath/parser.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/parser.c ++++ multipath-tools-130222/libmultipath/parser.c +@@ -395,36 +395,57 @@ set_value(vector strvec) + char *alloc = NULL; + char *tmp; + +- if (!str) ++ if (!str) { ++ condlog(0, "option '%s' missing value", ++ (char *)VECTOR_SLOT(strvec, 0)); + return NULL; +- ++ } + size = strlen(str); +- if (size == 0) ++ if (size == 0) { ++ condlog(0, "option '%s' has empty value", ++ (char *)VECTOR_SLOT(strvec, 0)); + return NULL; +- +- if (*str == '"') { +- for (i = 2; i < VECTOR_SIZE(strvec); i++) { +- str = VECTOR_SLOT(strvec, i); +- len += strlen(str); +- if (!alloc) +- alloc = +- (char *) MALLOC(sizeof (char *) * +- (len + 1)); +- else { +- alloc = +- REALLOC(alloc, sizeof (char *) * (len + 1)); +- tmp = VECTOR_SLOT(strvec, i-1); +- if (alloc && *str != '"' && *tmp != '"') +- strncat(alloc, " ", 1); +- } +- +- if (alloc && i != VECTOR_SIZE(strvec)-1) +- strncat(alloc, str, strlen(str)); +- } +- } else { +- alloc = MALLOC(sizeof (char *) * (size + 1)); ++ } ++ if (*str != '"') { ++ alloc = MALLOC(sizeof (char) * (size + 1)); + if (alloc) + memcpy(alloc, str, size); ++ else ++ condlog(0, "can't allocate memeory for option '%s'", ++ (char *)VECTOR_SLOT(strvec, 0)); ++ return alloc; ++ } ++ /* Even empty quotes counts as a value (An empty string) */ ++ alloc = (char *) MALLOC(sizeof (char)); ++ if (!alloc) { ++ condlog(0, "can't allocate memeory for option '%s'", ++ (char *)VECTOR_SLOT(strvec, 0)); ++ return NULL; ++ } ++ for (i = 2; i < VECTOR_SIZE(strvec); i++) { ++ str = VECTOR_SLOT(strvec, i); ++ if (!str) { ++ free(alloc); ++ condlog(0, "parse error for option '%s'", ++ (char *)VECTOR_SLOT(strvec, 0)); ++ return NULL; ++ } ++ if (*str == '"') ++ break; ++ tmp = alloc; ++ /* The first +1 is for the NULL byte. The rest are for the ++ * spaces between words */ ++ len += strlen(str) + 1; ++ alloc = REALLOC(alloc, sizeof (char) * len); ++ if (!alloc) { ++ FREE(tmp); ++ condlog(0, "can't allocate memeory for option '%s'", ++ (char *)VECTOR_SLOT(strvec, 0)); ++ return NULL; ++ } ++ if (*alloc != '\0') ++ strncat(alloc, " ", 1); ++ strncat(alloc, str, strlen(str)); + } + return alloc; + } +@@ -465,6 +486,74 @@ void free_uniques(vector uniques) + } + + int ++is_sublevel_keyword(char *str) ++{ ++ return (strcmp(str, "defaults") == 0 || strcmp(str, "blacklist") == 0 || ++ strcmp(str, "blacklist_exceptions") == 0 || ++ strcmp(str, "devices") == 0 || strcmp(str, "devices") == 0 || ++ strcmp(str, "device") == 0 || strcmp(str, "multipaths") == 0 || ++ strcmp(str, "multipath") == 0); ++} ++ ++int ++validate_config_strvec(vector strvec) ++{ ++ char *str; ++ int i; ++ ++ str = VECTOR_SLOT(strvec, 0); ++ if (str == NULL) { ++ condlog(0, "can't parse option on line %d of config file", ++ line_nr); ++ return -1; ++ } ++ if (*str == '}') { ++ if (VECTOR_SIZE(strvec) > 1) ++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr); ++ return 0; ++ } ++ if (*str == '{') { ++ condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr); ++ return -1; ++ } ++ if (is_sublevel_keyword(str)) { ++ str = VECTOR_SLOT(strvec, 1); ++ if (str == NULL) ++ condlog(0, "missing '{' on line %d of config file", line_nr); ++ else if (*str != '{') ++ condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str); ++ else if (VECTOR_SIZE(strvec) > 2) ++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr); ++ return 0; ++ } ++ str = VECTOR_SLOT(strvec, 1); ++ if (str == NULL) { ++ condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr); ++ return -1; ++ } ++ if (*str != '"') { ++ if (VECTOR_SIZE(strvec) > 2) ++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr); ++ return 0; ++ } ++ for (i = 2; i < VECTOR_SIZE(strvec); i++) { ++ str = VECTOR_SLOT(strvec, i); ++ if (str == NULL) { ++ condlog(0, "can't parse value on line %d of config file", line_nr); ++ return -1; ++ } ++ if (*str == '"') { ++ if (VECTOR_SIZE(strvec) > i + 1) ++ condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr); ++ return 0; ++ } ++ } ++ condlog(0, "missing closing quotes on line %d of config file", ++ line_nr); ++ return 0; ++} ++ ++int + process_stream(vector keywords) + { + int i; +@@ -494,11 +583,20 @@ process_stream(vector keywords) + if (!strvec) + continue; + ++ if (validate_config_strvec(strvec) != 0) { ++ free_strvec(strvec); ++ continue; ++ } ++ + str = VECTOR_SLOT(strvec, 0); + +- if (!strcmp(str, EOB) && kw_level > 0) { +- free_strvec(strvec); +- break; ++ if (!strcmp(str, EOB)) { ++ if (kw_level > 0) { ++ free_strvec(strvec); ++ break; ++ } ++ condlog(0, "unmatched '%s' at line %d of config file", ++ EOB, line_nr); + } + + for (i = 0; i < VECTOR_SIZE(keywords); i++) { diff --git a/SOURCES/0088-RHBZ-1069811-configurable-prio-timeout.patch b/SOURCES/0088-RHBZ-1069811-configurable-prio-timeout.patch new file mode 100644 index 0000000..60f374b --- /dev/null +++ b/SOURCES/0088-RHBZ-1069811-configurable-prio-timeout.patch @@ -0,0 +1,178 @@ +--- + libmultipath/prio.c | 7 +++++++ + libmultipath/prio.h | 1 + + libmultipath/prioritizers/alua_rtpg.c | 5 +++-- + libmultipath/prioritizers/emc.c | 2 +- + libmultipath/prioritizers/hds.c | 2 +- + libmultipath/prioritizers/hp_sw.c | 2 +- + libmultipath/prioritizers/ontap.c | 4 ++-- + libmultipath/prioritizers/rdac.c | 2 +- + multipath.conf.annotated | 5 +++-- + multipath/multipath.conf.5 | 4 ++-- + 10 files changed, 22 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/libmultipath/prio.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prio.c ++++ multipath-tools-130222/libmultipath/prio.c +@@ -10,6 +10,13 @@ + + static LIST_HEAD(prioritizers); + ++unsigned int get_prio_timeout(unsigned int default_timeout) ++{ ++ if (conf->checker_timeout) ++ return conf->checker_timeout * 1000; ++ return default_timeout; ++} ++ + int init_prio (void) + { + if (!add_prio(DEFAULT_PRIO)) +Index: multipath-tools-130222/libmultipath/prio.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prio.h ++++ multipath-tools-130222/libmultipath/prio.h +@@ -51,6 +51,7 @@ struct prio { + int (*getprio)(struct path *, char *); + }; + ++unsigned int get_prio_timeout(unsigned int default_timeout); + int init_prio (void); + void cleanup_prio (void); + struct prio * add_prio (char *); +Index: multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua_rtpg.c ++++ multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.c +@@ -21,6 +21,7 @@ + #define __user + #include + ++#include "../prio.h" + #include "alua_rtpg.h" + + #define SENSE_BUFF_LEN 32 +@@ -134,7 +135,7 @@ do_inquiry(int fd, int evpd, unsigned in + hdr.dxfer_len = resplen; + hdr.sbp = sense; + hdr.mx_sb_len = sizeof(sense); +- hdr.timeout = DEF_TIMEOUT; ++ hdr.timeout = get_prio_timeout(DEF_TIMEOUT); + + if (ioctl(fd, SG_IO, &hdr) < 0) { + PRINT_DEBUG("do_inquiry: IOCTL failed!\n"); +@@ -253,7 +254,7 @@ do_rtpg(int fd, void* resp, long resplen + hdr.dxfer_len = resplen; + hdr.mx_sb_len = sizeof(sense); + hdr.sbp = sense; +- hdr.timeout = DEF_TIMEOUT; ++ hdr.timeout = get_prio_timeout(DEF_TIMEOUT); + + if (ioctl(fd, SG_IO, &hdr) < 0) + return -RTPG_RTPG_FAILED; +Index: multipath-tools-130222/libmultipath/prioritizers/emc.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/emc.c ++++ multipath-tools-130222/libmultipath/prioritizers/emc.c +@@ -31,7 +31,7 @@ int emc_clariion_prio(const char *dev, i + io_hdr.dxferp = sense_buffer; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sb; +- io_hdr.timeout = 60000; ++ io_hdr.timeout = get_prio_timeout(60000); + io_hdr.pack_id = 0; + if (ioctl(fd, SG_IO, &io_hdr) < 0) { + pp_emc_log(0, "sending query command failed"); +Index: multipath-tools-130222/libmultipath/prioritizers/hds.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/hds.c ++++ multipath-tools-130222/libmultipath/prioritizers/hds.c +@@ -114,7 +114,7 @@ int hds_modular_prio (const char *dev, i + io_hdr.dxferp = inqBuff; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_buffer; +- io_hdr.timeout = 2000; /* TimeOut = 2 seconds */ ++ io_hdr.timeout = get_prio_timeout(2000); /* TimeOut = 2 seconds */ + + if (ioctl (fd, SG_IO, &io_hdr) < 0) { + pp_hds_log(0, "SG_IO error"); +Index: multipath-tools-130222/libmultipath/prioritizers/hp_sw.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/hp_sw.c ++++ multipath-tools-130222/libmultipath/prioritizers/hp_sw.c +@@ -46,7 +46,7 @@ int hp_sw_prio(const char *dev, int fd) + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sb; +- io_hdr.timeout = 60000; ++ io_hdr.timeout = get_prio_timeout(60000); + io_hdr.pack_id = 0; + retry: + if (ioctl(fd, SG_IO, &io_hdr) < 0) { +Index: multipath-tools-130222/libmultipath/prioritizers/ontap.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/ontap.c ++++ multipath-tools-130222/libmultipath/prioritizers/ontap.c +@@ -89,7 +89,7 @@ static int send_gva(const char *dev, int + io_hdr.dxferp = results; + io_hdr.cmdp = cdb; + io_hdr.sbp = sb; +- io_hdr.timeout = SG_TIMEOUT; ++ io_hdr.timeout = get_prio_timeout(SG_TIMEOUT); + io_hdr.pack_id = 0; + if (ioctl(fd, SG_IO, &io_hdr) < 0) { + pp_ontap_log(0, "SG_IO ioctl failed, errno=%d", errno); +@@ -141,7 +141,7 @@ static int get_proxy(const char *dev, in + io_hdr.dxferp = results; + io_hdr.cmdp = cdb; + io_hdr.sbp = sb; +- io_hdr.timeout = SG_TIMEOUT; ++ io_hdr.timeout = get_prio_timeout(SG_TIMEOUT); + io_hdr.pack_id = 0; + if (ioctl(fd, SG_IO, &io_hdr) < 0) { + pp_ontap_log(0, "ioctl sending inquiry command failed, " +Index: multipath-tools-130222/libmultipath/prioritizers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/rdac.c ++++ multipath-tools-130222/libmultipath/prioritizers/rdac.c +@@ -31,7 +31,7 @@ int rdac_prio(const char *dev, int fd) + io_hdr.dxferp = sense_buffer; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sb; +- io_hdr.timeout = 60000; ++ io_hdr.timeout = get_prio_timeout(60000); + io_hdr.pack_id = 0; + if (ioctl(fd, SG_IO, &io_hdr) < 0) { + pp_rdac_log(0, "sending inquiry command failed"); +Index: multipath-tools-130222/multipath.conf.annotated +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.annotated ++++ multipath-tools-130222/multipath.conf.annotated +@@ -188,8 +188,9 @@ + # # + # # name : checker_timeout + # # scope : multipath & multipathd +-# # desc : The timeout to use for path checkers that issue scsi +-# # commands with an explicit timeout, in seconds. ++# # desc : The timeout to use for path checkers and prioritizers ++# # that issue scsi commands with an explicit timeout, in ++# # seconds. + # # values : n > 0 + # # default : taken from /sys/block/sd/device/timeout + # checker_timeout 60 +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -321,8 +321,8 @@ maximum number of open fds is taken from + if that number is greated than 1024. + .TP + .B checker_timeout +-Specify the timeout to user for path checkers that issue scsi commands with an +-explicit timeout, in seconds; default taken from ++Specify the timeout to use for path checkers and prioritizers that issue scsi ++commands with an explicit timeout, in seconds; default taken from + .I /sys/block/sd/device/timeout + .TP + .B fast_io_fail_tmo diff --git a/SOURCES/0089-RHBZ-1110016-add-noasync-option.patch b/SOURCES/0089-RHBZ-1110016-add-noasync-option.patch new file mode 100644 index 0000000..2651c0e --- /dev/null +++ b/SOURCES/0089-RHBZ-1110016-add-noasync-option.patch @@ -0,0 +1,158 @@ +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 1 + + libmultipath/dict.c | 33 +++++++++++++++++++++++++++++++++ + libmultipath/discovery.c | 8 ++++++-- + multipath.conf.annotated | 10 ++++++++++ + multipath/multipath.conf.5 | 9 +++++++++ + 6 files changed, 60 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -556,6 +556,7 @@ load_config (char * file, struct udev *u + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; + conf->detect_prio = DEFAULT_DETECT_PRIO; + conf->hw_strmatch = 0; ++ conf->force_sync = 0; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -115,6 +115,7 @@ struct config { + int reassign_maps; + int retain_hwhandler; + int detect_prio; ++ int force_sync; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -712,6 +712,29 @@ def_hw_strmatch_handler(vector strvec) + return 0; + } + ++static int ++def_force_sync_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->force_sync = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->force_sync = 1; ++ else ++ conf->force_sync = 0; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -2822,6 +2845,15 @@ snprint_def_hw_strmatch(char * buff, int + } + + static int ++snprint_def_force_sync(char * buff, int len, void * data) ++{ ++ if (conf->force_sync) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -2889,6 +2921,7 @@ init_keywords(void) + install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler); + install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio); + install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch); ++ install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -952,8 +952,12 @@ get_state (struct path * pp, int daemon) + } + } + checker_clear_message(c); +- if (daemon) +- checker_set_async(c); ++ if (daemon) { ++ if (conf->force_sync == 0) ++ checker_set_async(c); ++ else ++ checker_set_sync(c); ++ } + if (!conf->checker_timeout && + (pp->bus != SYSFS_BUS_SCSI || + sysfs_get_timeout(pp, &(c->timeout)))) +Index: multipath-tools-130222/multipath.conf.annotated +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.annotated ++++ multipath-tools-130222/multipath.conf.annotated +@@ -214,6 +214,8 @@ + # # values : n > 0 + # # default : determined by the OS + # dev_loss_tmo 600 ++# ++# # + # # name : bindings_file + # # scope : multipath + # # desc : The location of the bindings file that is used with +@@ -222,6 +224,14 @@ + # # default : "/var/lib/multipath/bindings" + # bindings_file "/etc/multipath_bindings" + # ++# # ++# # name : force_sync ++# # scope : multipathd ++# # desc : If set to yes, multipath will run all of the checkers in ++# # sync mode, even if the checker has an async mode. ++# # values : yes|no ++# # default : no ++# force_sync yes + #} + # + ## +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -411,6 +411,15 @@ modify an existing config, or create a n + , the user device configs will be regular expression matched against the + built-in configs instead. Default is + .I no ++.TP ++.B force_sync ++If set to ++.I yes ++, multipathd will call the path checkers in sync mode only. This means that ++only one checker will run at a time. This is useful in the case where many ++multipathd checkers running in parallel causes significant CPU pressure. The ++Default is ++.I no + . + .SH "blacklist section" + The diff --git a/SOURCES/0090-UPBZ-1080038-reorder-paths-for-round-robin.patch b/SOURCES/0090-UPBZ-1080038-reorder-paths-for-round-robin.patch new file mode 100644 index 0000000..44f8407 --- /dev/null +++ b/SOURCES/0090-UPBZ-1080038-reorder-paths-for-round-robin.patch @@ -0,0 +1,529 @@ +--- + libmultipath/configure.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/configure.h | 2 + libmultipath/discovery.c | 87 +++++++++++++++++ + libmultipath/discovery.h | 2 + libmultipath/structs.c | 84 +++++++++++++++++ + libmultipath/structs.h | 25 ++++- + 6 files changed, 427 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -39,6 +39,219 @@ + #include "uxsock.h" + #include "wwids.h" + ++/* group paths in pg by host adapter ++ */ ++int group_by_host_adapter(struct pathgroup *pgp, vector adapters) ++{ ++ struct adapter_group *agp; ++ struct host_group *hgp; ++ struct path *pp, *pp1; ++ char adapter_name1[SLOT_NAME_SIZE]; ++ char adapter_name2[SLOT_NAME_SIZE]; ++ int i, j; ++ int found_hostgroup = 0; ++ ++ while (VECTOR_SIZE(pgp->paths) > 0) { ++ ++ pp = VECTOR_SLOT(pgp->paths, 0); ++ ++ if (sysfs_get_host_adapter_name(pp, adapter_name1)) ++ goto out; ++ /* create a new host adapter group ++ */ ++ agp = alloc_adaptergroup(); ++ if (!agp) ++ goto out; ++ agp->pgp = pgp; ++ ++ strncpy(agp->adapter_name, adapter_name1, SLOT_NAME_SIZE); ++ store_adaptergroup(adapters, agp); ++ ++ /* create a new host port group ++ */ ++ hgp = alloc_hostgroup(); ++ if (!hgp) ++ goto out; ++ if (store_hostgroup(agp->host_groups, hgp)) ++ goto out; ++ ++ hgp->host_no = pp->sg_id.host_no; ++ agp->num_hosts++; ++ if (store_path(hgp->paths, pp)) ++ goto out; ++ ++ hgp->num_paths++; ++ /* delete path from path group ++ */ ++ vector_del_slot(pgp->paths, 0); ++ ++ /* add all paths belonging to same host adapter ++ */ ++ vector_foreach_slot(pgp->paths, pp1, i) { ++ if (sysfs_get_host_adapter_name(pp1, adapter_name2)) ++ goto out; ++ if (strcmp(adapter_name1, adapter_name2) == 0) { ++ found_hostgroup = 0; ++ vector_foreach_slot(agp->host_groups, hgp, j) { ++ if (hgp->host_no == pp1->sg_id.host_no) { ++ if (store_path(hgp->paths, pp1)) ++ goto out; ++ hgp->num_paths++; ++ found_hostgroup = 1; ++ break; ++ } ++ } ++ if (!found_hostgroup) { ++ /* this path belongs to new host port ++ * within this adapter ++ */ ++ hgp = alloc_hostgroup(); ++ if (!hgp) ++ goto out; ++ ++ if (store_hostgroup(agp->host_groups, hgp)) ++ goto out; ++ ++ agp->num_hosts++; ++ if (store_path(hgp->paths, pp1)) ++ goto out; ++ ++ hgp->host_no = pp1->sg_id.host_no; ++ hgp->num_paths++; ++ } ++ /* delete paths from original path_group ++ * as they are added into adapter group now ++ */ ++ vector_del_slot(pgp->paths, i); ++ i--; ++ } ++ } ++ } ++ return 0; ++ ++out: /* add back paths into pg as re-ordering failed ++ */ ++ vector_foreach_slot(adapters, agp, i) { ++ vector_foreach_slot(agp->host_groups, hgp, j) { ++ while (VECTOR_SIZE(hgp->paths) > 0) { ++ pp = VECTOR_SLOT(hgp->paths, 0); ++ if (store_path(pgp->paths, pp)) ++ condlog(3, "failed to restore " ++ "path %s into path group", ++ pp->dev); ++ vector_del_slot(hgp->paths, 0); ++ } ++ } ++ } ++ free_adaptergroup(adapters); ++ return 1; ++} ++ ++/* re-order paths in pg by alternating adapters and host ports ++ * for optimized selection ++ */ ++int order_paths_in_pg_by_alt_adapters(struct pathgroup *pgp, vector adapters, ++ int total_paths) ++{ ++ int next_adapter_index = 0; ++ struct adapter_group *agp; ++ struct host_group *hgp; ++ struct path *pp; ++ ++ while (total_paths > 0) { ++ agp = VECTOR_SLOT(adapters, next_adapter_index); ++ if (!agp) { ++ condlog(0, "can't get adapter group %d", next_adapter_index); ++ return 1; ++ } ++ ++ hgp = VECTOR_SLOT(agp->host_groups, agp->next_host_index); ++ if (!hgp) { ++ condlog(0, "can't get host group %d of adapter group %d", next_adapter_index, agp->next_host_index); ++ return 1; ++ } ++ ++ if (!hgp->num_paths) { ++ agp->next_host_index++; ++ agp->next_host_index %= agp->num_hosts; ++ next_adapter_index++; ++ next_adapter_index %= VECTOR_SIZE(adapters); ++ continue; ++ } ++ ++ pp = VECTOR_SLOT(hgp->paths, 0); ++ ++ if (store_path(pgp->paths, pp)) ++ return 1; ++ ++ total_paths--; ++ ++ vector_del_slot(hgp->paths, 0); ++ ++ hgp->num_paths--; ++ ++ agp->next_host_index++; ++ agp->next_host_index %= agp->num_hosts; ++ next_adapter_index++; ++ next_adapter_index %= VECTOR_SIZE(adapters); ++ } ++ ++ /* all paths are added into path_group ++ * in crafted child order ++ */ ++ return 0; ++} ++ ++/* round-robin: order paths in path group to alternate ++ * between all host adapters ++ */ ++int rr_optimize_path_order(struct pathgroup *pgp) ++{ ++ vector adapters; ++ struct path *pp; ++ int total_paths; ++ int i; ++ ++ total_paths = VECTOR_SIZE(pgp->paths); ++ vector_foreach_slot(pgp->paths, pp, i) { ++ if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP && ++ pp->sg_id.proto_id != SCSI_PROTOCOL_SAS && ++ pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI && ++ pp->sg_id.proto_id != SCSI_PROTOCOL_SRP) { ++ /* return success as default path order ++ * is maintained in path group ++ */ ++ return 0; ++ } ++ } ++ adapters = vector_alloc(); ++ if (!adapters) ++ return 0; ++ ++ /* group paths in path group by host adapters ++ */ ++ if (group_by_host_adapter(pgp, adapters)) { ++ /* already freed adapters */ ++ condlog(3, "Failed to group paths by adapters"); ++ return 0; ++ } ++ ++ /* re-order paths in pg to alternate between adapters and host ports ++ */ ++ if (order_paths_in_pg_by_alt_adapters(pgp, adapters, total_paths)) { ++ condlog(3, "Failed to re-order paths in pg by adapters " ++ "and host ports"); ++ free_adaptergroup(adapters); ++ /* return failure as original paths are ++ * removed form pgp ++ */ ++ return 1; ++ } ++ ++ free_adaptergroup(adapters); ++ return 0; ++} ++ + extern int + setup_map (struct multipath * mpp, char * params, int params_size) + { +@@ -101,6 +314,22 @@ setup_map (struct multipath * mpp, char + */ + mpp->bestpg = select_path_group(mpp); + ++ /* re-order paths in all path groups in an optimized way ++ * for round-robin path selectors to get maximum throughput. ++ */ ++ if (!strncmp(mpp->selector, "round-robin", 11)) { ++ vector_foreach_slot(mpp->pg, pgp, i) { ++ if (VECTOR_SIZE(pgp->paths) <= 2) ++ continue; ++ if (rr_optimize_path_order(pgp)) { ++ condlog(2, "cannot re-order paths for " ++ "optimization: %s", ++ mpp->alias); ++ return 1; ++ } ++ } ++ } ++ + /* + * transform the mp->pg vector of vectors of paths + * into a mp->params strings to feed the device-mapper +Index: multipath-tools-130222/libmultipath/configure.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.h ++++ multipath-tools-130222/libmultipath/configure.h +@@ -29,4 +29,4 @@ int reinstate_paths (struct multipath *m + int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload); + int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid); + int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh); +- ++int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -310,6 +310,93 @@ sysfs_get_tgt_nodename (struct path *pp, + return 1; + } + ++int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name) ++{ ++ int proto_id; ++ ++ if (!pp || !adapter_name) ++ return 1; ++ ++ proto_id = pp->sg_id.proto_id; ++ ++ if (proto_id != SCSI_PROTOCOL_FCP && ++ proto_id != SCSI_PROTOCOL_SAS && ++ proto_id != SCSI_PROTOCOL_ISCSI && ++ proto_id != SCSI_PROTOCOL_SRP) { ++ return 1; ++ } ++ /* iscsi doesn't have adapter info in sysfs ++ * get ip_address for grouping paths ++ */ ++ if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI) ++ return sysfs_get_iscsi_ip_address(pp, adapter_name); ++ ++ /* fetch adapter pci name for other protocols ++ */ ++ return sysfs_get_host_pci_name(pp, adapter_name); ++} ++ ++int sysfs_get_host_pci_name(struct path *pp, char *pci_name) ++{ ++ struct udev_device *hostdev, *parent; ++ char host_name[HOST_NAME_LEN]; ++ const char *driver_name, *value; ++ ++ if (!pp || !pci_name) ++ return 1; ++ ++ sprintf(host_name, "host%d", pp->sg_id.host_no); ++ hostdev = udev_device_new_from_subsystem_sysname(conf->udev, ++ "scsi_host", host_name); ++ if (!hostdev) ++ return 1; ++ ++ parent = udev_device_get_parent(hostdev); ++ while (parent) { ++ driver_name = udev_device_get_driver(parent); ++ if (!driver_name) { ++ parent = udev_device_get_parent(parent); ++ continue; ++ } ++ if (!strcmp(driver_name, "pcieport")) ++ break; ++ parent = udev_device_get_parent(parent); ++ } ++ if (parent) { ++ /* pci_device found ++ */ ++ value = udev_device_get_sysname(parent); ++ ++ strncpy(pci_name, value, SLOT_NAME_SIZE); ++ udev_device_unref(hostdev); ++ return 0; ++ } ++ udev_device_unref(hostdev); ++ return 1; ++} ++ ++int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address) ++{ ++ struct udev_device *hostdev; ++ char host_name[HOST_NAME_LEN]; ++ const char *value; ++ ++ sprintf(host_name, "host%d", pp->sg_id.host_no); ++ hostdev = udev_device_new_from_subsystem_sysname(conf->udev, ++ "iscsi_host", host_name); ++ if (hostdev) { ++ value = udev_device_get_sysattr_value(hostdev, ++ "ipaddress"); ++ if (value) { ++ strncpy(ip_address, value, SLOT_NAME_SIZE); ++ udev_device_unref(hostdev); ++ return 0; ++ } else ++ udev_device_unref(hostdev); ++ } ++ return 1; ++} ++ + static void + sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + { +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -38,6 +38,8 @@ int store_pathinfo (vector pathvec, vect + struct path **pp_ptr); + int sysfs_set_scsi_tmo (struct multipath *mpp); + int sysfs_get_timeout(struct path *pp, unsigned int *timeout); ++int sysfs_get_host_pci_name(struct path *pp, char *pci_name); ++int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address); + + /* + * discovery bitmask +Index: multipath-tools-130222/libmultipath/structs.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.c ++++ multipath-tools-130222/libmultipath/structs.c +@@ -18,6 +18,70 @@ + #include "blacklist.h" + #include "prio.h" + ++struct adapter_group * ++alloc_adaptergroup(void) ++{ ++ struct adapter_group *agp; ++ ++ agp = (struct adapter_group *)MALLOC(sizeof(struct adapter_group)); ++ ++ if (!agp) ++ return NULL; ++ ++ agp->host_groups = vector_alloc(); ++ if (!agp->host_groups) { ++ FREE(agp); ++ agp = NULL; ++ } ++ return agp; ++} ++ ++void free_adaptergroup(vector adapters) ++{ ++ int i; ++ struct adapter_group *agp; ++ ++ vector_foreach_slot(adapters, agp, i) { ++ free_hostgroup(agp->host_groups); ++ FREE(agp); ++ } ++ vector_free(adapters); ++} ++ ++void free_hostgroup(vector hostgroups) ++{ ++ int i; ++ struct host_group *hgp; ++ ++ if (!hostgroups) ++ return; ++ ++ vector_foreach_slot(hostgroups, hgp, i) { ++ vector_free(hgp->paths); ++ FREE(hgp); ++ } ++ vector_free(hostgroups); ++} ++ ++struct host_group * ++alloc_hostgroup(void) ++{ ++ struct host_group *hgp; ++ ++ hgp = (struct host_group *)MALLOC(sizeof(struct host_group)); ++ ++ if (!hgp) ++ return NULL; ++ ++ hgp->paths = vector_alloc(); ++ ++ if (!hgp->paths) { ++ FREE(hgp); ++ hgp = NULL; ++ } ++ return hgp; ++} ++ + struct path * + alloc_path (void) + { +@@ -242,6 +306,26 @@ store_pathgroup (vector pgvec, struct pa + return 0; + } + ++int ++store_hostgroup(vector hostgroupvec, struct host_group * hgp) ++{ ++ if (!vector_alloc_slot(hostgroupvec)) ++ return 1; ++ ++ vector_set_slot(hostgroupvec, hgp); ++ return 0; ++} ++ ++int ++store_adaptergroup(vector adapters, struct adapter_group * agp) ++{ ++ if (!vector_alloc_slot(adapters)) ++ return 1; ++ ++ vector_set_slot(adapters, agp); ++ return 0; ++} ++ + struct multipath * + find_mp_by_minor (vector mpvec, int minor) + { +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -15,7 +15,8 @@ + #define BLK_DEV_SIZE 33 + #define PATH_SIZE 512 + #define NAME_SIZE 512 +- ++#define HOST_NAME_LEN 8 ++#define SLOT_NAME_SIZE 40 + + #define SCSI_VENDOR_SIZE 9 + #define SCSI_PRODUCT_SIZE 17 +@@ -251,6 +252,20 @@ struct pathgroup { + char * selector; + }; + ++struct adapter_group { ++ char adapter_name[SLOT_NAME_SIZE]; ++ struct pathgroup *pgp; ++ int num_hosts; ++ vector host_groups; ++ int next_host_index; ++}; ++ ++struct host_group { ++ int host_no; ++ int num_paths; ++ vector paths; ++}; ++ + struct path * alloc_path (void); + struct pathgroup * alloc_pathgroup (void); + struct multipath * alloc_multipath (void); +@@ -263,6 +278,14 @@ void free_multipath_attributes (struct m + void drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths); + void free_multipathvec (vector mpvec, enum free_path_mode free_paths); + ++struct adapter_group * alloc_adaptergroup(void); ++struct host_group * alloc_hostgroup(void); ++void free_adaptergroup(vector adapters); ++void free_hostgroup(vector hostgroups); ++ ++int store_adaptergroup(vector adapters, struct adapter_group *agp); ++int store_hostgroup(vector hostgroupvec, struct host_group *hgp); ++ + int store_path (vector pathvec, struct path * pp); + int store_pathgroup (vector pgvec, struct pathgroup * pgp); + diff --git a/SOURCES/0091-RHBZ-1069584-fix-empty-values-fast-io-fail-and-dev-loss.patch b/SOURCES/0091-RHBZ-1069584-fix-empty-values-fast-io-fail-and-dev-loss.patch new file mode 100644 index 0000000..d164de1 --- /dev/null +++ b/SOURCES/0091-RHBZ-1069584-fix-empty-values-fast-io-fail-and-dev-loss.patch @@ -0,0 +1,38 @@ +--- + libmultipath/dict.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -43,6 +43,9 @@ def_fast_io_fail_handler(vector strvec) + char * buff; + + buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ + if (strlen(buff) == 3 && !strcmp(buff, "off")) + conf->fast_io_fail = MP_FAST_IO_FAIL_OFF; + else if (sscanf(buff, "%d", &conf->fast_io_fail) != 1 || +@@ -1002,6 +1005,9 @@ hw_dev_loss_handler(vector strvec) + char * buff; + struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); + ++ if (!hwe) ++ return 1; ++ + buff = set_value(strvec); + if (!buff) + return 1; +@@ -1021,6 +1027,9 @@ hw_pgpolicy_handler(vector strvec) + char * buff; + struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); + ++ if (!hwe) ++ return 1; ++ + buff = set_value(strvec); + + if (!buff) diff --git a/SOURCES/0092-UPBZ-1104605-reload-on-rename.patch b/SOURCES/0092-UPBZ-1104605-reload-on-rename.patch new file mode 100644 index 0000000..465257c --- /dev/null +++ b/SOURCES/0092-UPBZ-1104605-reload-on-rename.patch @@ -0,0 +1,63 @@ +--- + libmultipath/configure.c | 11 +++++++++++ + libmultipath/configure.h | 1 + + libmultipath/devmapper.c | 3 +-- + 3 files changed, 13 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -394,6 +394,8 @@ select_action (struct multipath * mpp, v + cmpp->alias, mpp->alias); + strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE); + mpp->action = ACT_RENAME; ++ if (force_reload) ++ mpp->action = ACT_RENAME2; + return; + } + mpp->action = ACT_CREATE; +@@ -632,6 +634,15 @@ domap (struct multipath * mpp, char * pa + r = dm_rename(mpp->alias_old, mpp->alias); + break; + ++ case ACT_RENAME2: ++ r = dm_rename(mpp->alias_old, mpp->alias); ++ if (r) { ++ r = dm_addmap_reload(mpp, params); ++ if (r) ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, MPATH_UDEV_RELOAD_FLAG); ++ } ++ break; ++ + default: + break; + } +Index: multipath-tools-130222/libmultipath/configure.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.h ++++ multipath-tools-130222/libmultipath/configure.h +@@ -18,6 +18,7 @@ enum actions { + ACT_RENAME, + ACT_CREATE, + ACT_RESIZE, ++ ACT_RENAME2, + }; + + #define FLUSH_ONE 1 +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -565,10 +565,9 @@ dm_dev_t (const char * mapname, char * d + if (!dm_task_run(dmt)) + goto out; + +- if (!dm_task_get_info(dmt, &info)) ++ if (!dm_task_get_info(dmt, &info) || !info.exists) + goto out; + +- r = info.open_count; + if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len) + goto out; + diff --git a/SOURCES/0093-UPBZ-1086825-user-friendly-name-remap.patch b/SOURCES/0093-UPBZ-1086825-user-friendly-name-remap.patch new file mode 100644 index 0000000..ab5abbd --- /dev/null +++ b/SOURCES/0093-UPBZ-1086825-user-friendly-name-remap.patch @@ -0,0 +1,199 @@ +--- + libmultipath/alias.c | 64 ++++++++++++++++++++++++++++++++++++++++++--- + libmultipath/alias.h | 2 + + libmultipath/propsel.c | 32 +++++++++++++++------- + libmultipath/structs_vec.c | 15 ++++++++++ + 4 files changed, 100 insertions(+), 13 deletions(-) + +Index: multipath-tools-130222/libmultipath/alias.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.c ++++ multipath-tools-130222/libmultipath/alias.c +@@ -145,7 +145,7 @@ lookup_binding(FILE *f, char *map_wwid, + } + + static int +-rlookup_binding(FILE *f, char *buff, char *map_alias) ++rlookup_binding(FILE *f, char *buff, char *map_alias, char *prefix) + { + char line[LINE_MAX]; + unsigned int line_nr = 0; +@@ -164,7 +164,7 @@ rlookup_binding(FILE *f, char *buff, cha + alias = strtok(line, " \t"); + if (!alias) /* blank line */ + continue; +- curr_id = scan_devname(alias, NULL); /* TBD: Why this call? */ ++ curr_id = scan_devname(alias, prefix); + if (curr_id >= id) + id = curr_id + 1; + wwid = strtok(NULL, " \t"); +@@ -188,6 +188,11 @@ rlookup_binding(FILE *f, char *buff, cha + } + } + condlog(3, "No matching alias [%s] in bindings file.", map_alias); ++ ++ /* Get the theoretical id for this map alias. ++ * Used by use_existing_alias ++ */ ++ id = scan_devname(map_alias, prefix); + return id; + } + +@@ -237,6 +242,59 @@ allocate_binding(int fd, char *wwid, int + } + + char * ++use_existing_alias (char *wwid, char *file, char *alias_old, ++ char *prefix, int bindings_read_only) ++{ ++ char *alias = NULL; ++ int id = 0; ++ int fd, can_write; ++ char buff[WWID_SIZE]; ++ FILE *f; ++ ++ fd = open_file(file, &can_write, BINDINGS_FILE_HEADER); ++ if (fd < 0) ++ return NULL; ++ ++ f = fdopen(fd, "r"); ++ if (!f) { ++ condlog(0, "cannot fdopen on bindings file descriptor"); ++ close(fd); ++ return NULL; ++ } ++ /* lookup the binding. if it exsists, the wwid will be in buff ++ * either way, id contains the id for the alias ++ */ ++ id = rlookup_binding(f , buff, alias_old, prefix); ++ if (id < 0) ++ goto out; ++ ++ if (strlen(buff) > 0) { ++ /* if buff is our wwid, it's already ++ * allocated correctly ++ */ ++ if (strcmp(buff, wwid) == 0) ++ alias = STRDUP(alias_old); ++ else { ++ alias = NULL; ++ condlog(0, "alias %s already bound to wwid %s, cannot reuse", ++ alias_old, buff); ++ } ++ goto out; ++ } ++ ++ /* allocate the existing alias in the bindings file */ ++ if (can_write && id && !bindings_read_only) { ++ alias = allocate_binding(fd, wwid, id, prefix); ++ condlog(0, "Allocated existing binding [%s] for WWID [%s]", ++ alias, wwid); ++ } ++ ++out: ++ fclose(f); ++ return alias; ++} ++ ++char * + get_user_friendly_alias(char *wwid, char *file, char *prefix, + int bindings_read_only) + { +@@ -305,7 +363,7 @@ get_user_friendly_wwid(char *alias, char + return -1; + } + +- rlookup_binding(f, buff, alias); ++ rlookup_binding(f, buff, alias, NULL); + if (!strlen(buff)) { + fclose(f); + return -1; +Index: multipath-tools-130222/libmultipath/alias.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.h ++++ multipath-tools-130222/libmultipath/alias.h +@@ -10,3 +10,5 @@ + char *get_user_friendly_alias(char *wwid, char *file, char *prefix, + int bindings_readonly); + int get_user_friendly_wwid(char *alias, char *buff, char *file); ++char *use_existing_alias (char *wwid, char *file, char *alias_old, ++ char *prefix, int bindings_read_only); +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -253,19 +253,31 @@ want_user_friendly_names(struct multipat + extern int + select_alias (struct multipath * mp) + { +- if (mp->mpe && mp->mpe->alias) ++ if (mp->mpe && mp->mpe->alias) { + mp->alias = STRDUP(mp->mpe->alias); +- else { +- mp->alias = NULL; +- if (want_user_friendly_names(mp)) { +- select_alias_prefix(mp); +- mp->alias = get_user_friendly_alias(mp->wwid, +- conf->bindings_file, mp->alias_prefix, conf->bindings_read_only); +- } +- if (mp->alias == NULL) +- mp->alias = STRDUP(mp->wwid); ++ goto out; + } + ++ mp->alias = NULL; ++ if (!want_user_friendly_names(mp)) ++ goto out; ++ ++ select_alias_prefix(mp); ++ ++ if (strlen(mp->alias_old) > 0) { ++ mp->alias = use_existing_alias(mp->wwid, conf->bindings_file, ++ mp->alias_old, mp->alias_prefix, ++ conf->bindings_read_only); ++ memset (mp->alias_old, 0, WWID_SIZE); ++ } ++ ++ if (mp->alias == NULL) ++ mp->alias = get_user_friendly_alias(mp->wwid, ++ conf->bindings_file, mp->alias_prefix, conf->bindings_read_only); ++out: ++ if (mp->alias == NULL) ++ mp->alias = STRDUP(mp->wwid); ++ + return mp->alias ? 0 : 1; + } + +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -430,6 +430,20 @@ out: + return NULL; + } + ++static void ++find_existing_alias (struct multipath * mpp, ++ struct vectors *vecs) ++{ ++ struct multipath * mp; ++ int i; ++ ++ vector_foreach_slot (vecs->mpvec, mp, i) ++ if (strcmp(mp->wwid, mpp->wwid) == 0) { ++ strncpy(mpp->alias_old, mp->alias, WWID_SIZE); ++ return; ++ } ++} ++ + extern struct multipath * + add_map_with_path (struct vectors * vecs, + struct path * pp, int add_vec) +@@ -443,6 +457,7 @@ add_map_with_path (struct vectors * vecs + mpp->hwe = pp->hwe; + + strcpy(mpp->wwid, pp->wwid); ++ find_existing_alias(mpp, vecs); + if (select_alias(mpp)) + goto out; + mpp->size = pp->size; diff --git a/SOURCES/0094-RHBZ-1086825-cleanup-remap.patch b/SOURCES/0094-RHBZ-1086825-cleanup-remap.patch new file mode 100644 index 0000000..7d85c2d --- /dev/null +++ b/SOURCES/0094-RHBZ-1086825-cleanup-remap.patch @@ -0,0 +1,107 @@ +--- + libmultipath/alias.c | 31 +++++++++++++++---------------- + libmultipath/propsel.c | 4 ++-- + 2 files changed, 17 insertions(+), 18 deletions(-) + +Index: multipath-tools-130222/libmultipath/alias.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.c ++++ multipath-tools-130222/libmultipath/alias.c +@@ -149,13 +149,11 @@ rlookup_binding(FILE *f, char *buff, cha + { + char line[LINE_MAX]; + unsigned int line_nr = 0; +- int id = 0; + + buff[0] = '\0'; + + while (fgets(line, LINE_MAX, f)) { + char *c, *alias, *wwid; +- int curr_id; + + line_nr++; + c = strpbrk(line, "#\n\r"); +@@ -164,9 +162,6 @@ rlookup_binding(FILE *f, char *buff, cha + alias = strtok(line, " \t"); + if (!alias) /* blank line */ + continue; +- curr_id = scan_devname(alias, prefix); +- if (curr_id >= id) +- id = curr_id + 1; + wwid = strtok(NULL, " \t"); + if (!wwid){ + condlog(3, +@@ -184,16 +179,12 @@ rlookup_binding(FILE *f, char *buff, cha + "\nSetting wwid to %s", alias, wwid); + strncpy(buff, wwid, WWID_SIZE); + buff[WWID_SIZE - 1] = '\0'; +- return id; ++ return 0; + } + } + condlog(3, "No matching alias [%s] in bindings file.", map_alias); + +- /* Get the theoretical id for this map alias. +- * Used by use_existing_alias +- */ +- id = scan_devname(map_alias, prefix); +- return id; ++ return -1; + } + + static char * +@@ -264,9 +255,7 @@ use_existing_alias (char *wwid, char *fi + /* lookup the binding. if it exsists, the wwid will be in buff + * either way, id contains the id for the alias + */ +- id = rlookup_binding(f , buff, alias_old, prefix); +- if (id < 0) +- goto out; ++ rlookup_binding(f, buff, alias_old, prefix); + + if (strlen(buff) > 0) { + /* if buff is our wwid, it's already +@@ -279,11 +268,21 @@ use_existing_alias (char *wwid, char *fi + condlog(0, "alias %s already bound to wwid %s, cannot reuse", + alias_old, buff); + } +- goto out; ++ goto out; + } + + /* allocate the existing alias in the bindings file */ +- if (can_write && id && !bindings_read_only) { ++ id = scan_devname(alias_old, prefix); ++ if (id <= 0) ++ goto out; ++ ++ if (fflush(f) != 0) { ++ condlog(0, "cannot fflush bindings file stream : %s", ++ strerror(errno)); ++ goto out; ++ } ++ ++ if (can_write && !bindings_read_only) { + alias = allocate_binding(fd, wwid, id, prefix); + condlog(0, "Allocated existing binding [%s] for WWID [%s]", + alias, wwid); +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -263,13 +263,13 @@ select_alias (struct multipath * mp) + goto out; + + select_alias_prefix(mp); +- ++ + if (strlen(mp->alias_old) > 0) { + mp->alias = use_existing_alias(mp->wwid, conf->bindings_file, + mp->alias_old, mp->alias_prefix, + conf->bindings_read_only); + memset (mp->alias_old, 0, WWID_SIZE); +- } ++ } + + if (mp->alias == NULL) + mp->alias = get_user_friendly_alias(mp->wwid, diff --git a/SOURCES/0095-RHBZ-1127944-xtremIO-config.patch b/SOURCES/0095-RHBZ-1127944-xtremIO-config.patch new file mode 100644 index 0000000..6807cbc --- /dev/null +++ b/SOURCES/0095-RHBZ-1127944-xtremIO-config.patch @@ -0,0 +1,28 @@ +--- + libmultipath/hwtable.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1121,6 +1121,19 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .prio_args = NULL, + }, ++ { ++ .vendor = "XtremIO", ++ .product = "XtremApp", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .selector = "queue-length 0", ++ .pgpolicy = MULTIBUS, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .checker_name = DIRECTIO, ++ .fast_io_fail = 15, ++ .prio_name = DEFAULT_PRIO, ++ .prio_args = NULL, ++ }, + /* + * EOL + */ diff --git a/SOURCES/0096-RHBZ-979474-new-wildcards.patch b/SOURCES/0096-RHBZ-979474-new-wildcards.patch new file mode 100644 index 0000000..9025efe --- /dev/null +++ b/SOURCES/0096-RHBZ-979474-new-wildcards.patch @@ -0,0 +1,120 @@ +--- + libmultipath/print.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 83 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -44,7 +45,7 @@ + * information printing helpers + */ + static int +-snprint_str (char * buff, size_t len, char * str) ++snprint_str (char * buff, size_t len, const char * str) + { + return snprintf(buff, len, "%s", str); + } +@@ -432,6 +433,83 @@ snprint_path_mpp (char * buff, size_t le + } + + static int ++snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr) ++{ ++ struct udev_device *host_dev = NULL; ++ char host_id[32]; ++ const char *value = NULL; ++ int ret; ++ ++ if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP) ++ return snprintf(buff, len, "[undef]"); ++ sprintf(host_id, "host%d", pp->sg_id.host_no); ++ host_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_host", ++ host_id); ++ if (!host_dev) { ++ condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id); ++ goto out; ++ } ++ value = udev_device_get_sysattr_value(host_dev, attr); ++ if (value) ++ ret = snprint_str(buff, len, value); ++ udev_device_unref(host_dev); ++out: ++ if (!value) ++ ret = snprintf(buff, len, "[unknown]"); ++ return ret; ++} ++ ++static int ++snprint_host_wwnn (char * buff, size_t len, struct path * pp) ++{ ++ return snprint_host_attr(buff, len, pp, "node_name"); ++} ++ ++static int ++snprint_host_wwpn (char * buff, size_t len, struct path * pp) ++{ ++ return snprint_host_attr(buff, len, pp, "port_name"); ++} ++ ++static int ++snprint_tgt_wwpn (char * buff, size_t len, struct path * pp) ++{ ++ struct udev_device *rport_dev = NULL; ++ char rport_id[32]; ++ const char *value = NULL; ++ int ret; ++ ++ if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP) ++ return snprintf(buff, len, "[undef]"); ++ sprintf(rport_id, "rport-%d:%d-%d", ++ pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id); ++ rport_dev = udev_device_new_from_subsystem_sysname(conf->udev, ++ "fc_remote_ports", rport_id); ++ if (!rport_dev) { ++ condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev, ++ rport_id); ++ goto out; ++ } ++ value = udev_device_get_sysattr_value(rport_dev, "port_name"); ++ if (value) ++ ret = snprint_str(buff, len, value); ++ udev_device_unref(rport_dev); ++out: ++ if (!value) ++ ret = snprintf(buff, len, "[unknown]"); ++ return ret; ++} ++ ++ ++static int ++snprint_tgt_wwnn (char * buff, size_t len, struct path * pp) ++{ ++ if (pp->tgt_node_name[0] == '\0') ++ return snprintf(buff, len, "[undef]"); ++ return snprint_str(buff, len, pp->tgt_node_name); ++} ++ ++static int + snprint_path_checker (char * buff, size_t len, struct path * pp) + { + struct checker * c = &pp->checker; +@@ -475,6 +553,10 @@ struct path_data pd[] = { + {'S', "size", 0, snprint_path_size}, + {'z', "serial", 0, snprint_path_serial}, + {'m', "multipath", 0, snprint_path_mpp}, ++ {'N', "host WWNN", 0, snprint_host_wwnn}, ++ {'n', "target WWNN", 0, snprint_tgt_wwnn}, ++ {'R', "host WWPN", 0, snprint_host_wwpn}, ++ {'r', "target WWPN", 0, snprint_tgt_wwpn}, + {0, NULL, 0 , NULL} + }; + diff --git a/SOURCES/0097-RH-fix-coverity-errors.patch b/SOURCES/0097-RH-fix-coverity-errors.patch new file mode 100644 index 0000000..8ce0e87 --- /dev/null +++ b/SOURCES/0097-RH-fix-coverity-errors.patch @@ -0,0 +1,158 @@ +--- + kpartx/devmapper.c | 3 ++- + libmultipath/alias.c | 1 + + libmultipath/blacklist.c | 7 +++++++ + libmultipath/prioritizers/iet.c | 2 ++ + libmultipath/prioritizers/weightedpath.c | 5 ++++- + libmultipath/regex.c | 5 ++++- + libmultipath/sysfs.c | 3 ++- + libmultipath/util.c | 2 +- + 8 files changed, 23 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/kpartx/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.c ++++ multipath-tools-130222/kpartx/devmapper.c +@@ -132,8 +132,9 @@ dm_addmap (int task, const char *name, c + goto addout; + r = dm_task_run (dmt); + +- addout: ++addout: + dm_task_destroy (dmt); ++ free(prefixed_uuid); + + return r; + } +Index: multipath-tools-130222/libmultipath/alias.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.c ++++ multipath-tools-130222/libmultipath/alias.c +@@ -328,6 +328,7 @@ get_user_friendly_alias(char *wwid, char + if (fflush(f) != 0) { + condlog(0, "cannot fflush bindings file stream : %s", + strerror(errno)); ++ free(alias); + fclose(f); + return NULL; + } +Index: multipath-tools-130222/libmultipath/blacklist.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.c ++++ multipath-tools-130222/libmultipath/blacklist.c +@@ -79,6 +79,8 @@ set_ble_device (vector blist, char * ven + if (regcomp(&ble->vendor_reg, vendor, + REG_EXTENDED|REG_NOSUB)) { + FREE(vendor); ++ if (product) ++ FREE(product); + return 1; + } + ble->vendor = vendor; +@@ -87,6 +89,10 @@ set_ble_device (vector blist, char * ven + if (regcomp(&ble->product_reg, product, + REG_EXTENDED|REG_NOSUB)) { + FREE(product); ++ if (vendor) { ++ ble->vendor = NULL; ++ FREE(vendor); ++ } + return 1; + } + ble->product = product; +@@ -189,6 +195,7 @@ setup_default_blist (struct config * con + STRDUP(hwe->bl_product), + ORIGIN_DEFAULT)) { + FREE(ble); ++ vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1); + return 1; + } + } +Index: multipath-tools-130222/libmultipath/prioritizers/iet.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/iet.c ++++ multipath-tools-130222/libmultipath/prioritizers/iet.c +@@ -109,6 +109,7 @@ int iet_prio(const char *dev, char * arg + ssize_t nchars = readlink(path, buffer, sizeof(buffer)-1); + if (nchars != -1) { + char *device; ++ buffer[nchars] = '\0'; + device = find_regex(buffer,"(sd[a-z]+)"); + // if device parsed is the right one + if (device!=NULL && strncmp(device, dev, strlen(device)) == 0) { +@@ -118,6 +119,7 @@ int iet_prio(const char *dev, char * arg + if (ip!=NULL && strncmp(ip, preferredip, strlen(ip)) == 0) { + // high prio + free(ip); ++ free(device); + closedir(dir_p); + return 20; + } +Index: multipath-tools-130222/libmultipath/prioritizers/weightedpath.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/weightedpath.c ++++ multipath-tools-130222/libmultipath/prioritizers/weightedpath.c +@@ -61,8 +61,10 @@ int prio_path_weight(struct path *pp, ch + regex = get_next_string(&temp, split_char); + + /* Return default priority if the argument is not parseable */ +- if (!regex) ++ if (!regex) { ++ FREE(arg); + return priority; ++ } + + if (!strcmp(regex, HBTL)) { + sprintf(path, "%d:%d:%d:%d", pp->sg_id.host_no, +@@ -72,6 +74,7 @@ int prio_path_weight(struct path *pp, ch + } else { + condlog(0, "%s: %s - Invalid arguments", pp->dev, + pp->prio.name); ++ FREE(arg); + return priority; + } + +Index: multipath-tools-130222/libmultipath/regex.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/regex.c ++++ multipath-tools-130222/libmultipath/regex.c +@@ -3936,8 +3936,11 @@ int eflags; + regs.num_regs = nmatch; + regs.start = TALLOC(nmatch, regoff_t); + regs.end = TALLOC(nmatch, regoff_t); +- if (regs.start == NULL || regs.end == NULL) ++ if (regs.start == NULL || regs.end == NULL) { ++ free(regs.start); ++ free(regs.end); + return (int) REG_NOMATCH; ++ } + } + + /* Perform the searching operation. */ +Index: multipath-tools-130222/libmultipath/sysfs.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/sysfs.c ++++ multipath-tools-130222/libmultipath/sysfs.c +@@ -88,7 +88,8 @@ ssize_t sysfs_attr_get_value(struct udev + } else if (size == value_len) { + condlog(4, "overflow while reading from %s", devpath); + size = 0; +- } ++ } else ++ value[size] = '\0'; + + close(fd); + return size; +Index: multipath-tools-130222/libmultipath/util.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.c ++++ multipath-tools-130222/libmultipath/util.c +@@ -175,7 +175,7 @@ devt2devname (char *devname, int devname + sprintf(block_path,"/sys/dev/block/%u:%u", major, minor); + if (lstat(block_path, &statbuf) == 0) { + if (S_ISLNK(statbuf.st_mode) && +- readlink(block_path, dev, FILE_NAME_SIZE) > 0) { ++ readlink(block_path, dev, FILE_NAME_SIZE-1) > 0) { + char *p = strrchr(dev, '/'); + + if (!p) { diff --git a/SOURCES/0098-UPBZ-1067171-mutipath-i.patch b/SOURCES/0098-UPBZ-1067171-mutipath-i.patch new file mode 100644 index 0000000..cf41863 --- /dev/null +++ b/SOURCES/0098-UPBZ-1067171-mutipath-i.patch @@ -0,0 +1,332 @@ +--- + libmultipath/config.h | 15 ++++++++- + libmultipath/configure.c | 2 - + libmultipath/discovery.c | 5 +-- + multipath/main.c | 75 +++++++++++++++++++++++++---------------------- + multipath/multipath.8 | 5 ++- + 5 files changed, 61 insertions(+), 41 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -23,6 +23,17 @@ enum devtypes { + DEV_DEVMAP + }; + ++enum mpath_cmds { ++ CMD_CREATE, ++ CMD_DRY_RUN, ++ CMD_LIST_SHORT, ++ CMD_LIST_LONG, ++ CMD_VALID_PATH, ++ CMD_REMOVE_WWID, ++ CMD_RESET_WWIDS, ++ CMD_ADD_WWID, ++}; ++ + struct hwentry { + char * vendor; + char * product; +@@ -79,8 +90,7 @@ struct mpentry { + + struct config { + int verbosity; +- int dry_run; +- int list; ++ enum mpath_cmds cmd; + int pgpolicy_flag; + int pgpolicy; + enum devtypes dev_type; +@@ -98,6 +108,7 @@ struct config { + int max_fds; + int force_reload; + int queue_without_daemon; ++ int ignore_wwids; + int checker_timeout; + int daemon; + int flush_on_last_del; +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -85,7 +85,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); ++ fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-T tm:val] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); +@@ -109,6 +109,7 @@ usage (char * progname) + " -d dry run, do not create or update devmaps\n" \ + " -t dump internal hardware table\n" \ + " -r force devmap reload\n" \ ++ " -i ignore wwids file\n" \ + " -B treat the bindings file as read only\n" \ + " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ + " -b fil bindings file location\n" \ +@@ -209,18 +210,19 @@ get_dm_mpvec (vector curmp, vector pathv + * If not in "fast list mode", we need to fetch information + * about them + */ +- if (conf->list != 1) ++ if (conf->cmd != CMD_LIST_SHORT) + update_paths(mpp); + +- if (conf->list > 1) ++ if (conf->cmd == CMD_LIST_LONG) + mpp->bestpg = select_path_group(mpp); + + disassemble_status(status, mpp); + +- if (conf->list) ++ if (conf->cmd == CMD_LIST_SHORT || ++ conf->cmd == CMD_LIST_LONG) + print_multipath_topology(mpp, conf->verbosity); + +- if (!conf->dry_run) ++ if (conf->cmd == CMD_CREATE) + reinstate_paths(mpp); + } + return 0; +@@ -262,10 +264,11 @@ configure (void) + /* + * if we have a blacklisted device parameter, exit early + */ +- if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 && ++ if (dev && conf->dev_type == DEV_DEVNODE && ++ conf->cmd != CMD_REMOVE_WWID && + (filter_devnode(conf->blist_devnode, + conf->elist_devnode, dev) > 0)) { +- if (conf->dry_run == 2) ++ if (conf->cmd == CMD_VALID_PATH) + printf("%s is not a valid multipath device path\n", + conf->dev); + goto out; +@@ -278,13 +281,13 @@ configure (void) + int failed = get_refwwid(conf->dev, conf->dev_type, pathvec, + &refwwid); + if (!refwwid) { +- if (failed == 2 && conf->dry_run == 2) ++ if (failed == 2 && conf->cmd == CMD_VALID_PATH) + printf("%s is not a valid multipath device path\n", conf->dev); + else + condlog(3, "scope is nul"); + goto out; + } +- if (conf->dry_run == 3) { ++ if (conf->cmd == CMD_REMOVE_WWID) { + r = remove_wwid(refwwid); + if (r == 0) + printf("wwid '%s' removed\n", refwwid); +@@ -295,7 +298,7 @@ configure (void) + } + goto out; + } +- if (conf->dry_run == 5) { ++ if (conf->cmd == CMD_ADD_WWID) { + r = remember_wwid(refwwid); + if (r == 0) + printf("wwid '%s' added\n", refwwid); +@@ -305,13 +308,13 @@ configure (void) + goto out; + } + condlog(3, "scope limited to %s", refwwid); +- if (conf->dry_run == 2) { +- if (check_wwids_file(refwwid, 0) == 0){ +- printf("%s is a valid multipath device path\n", conf->dev); ++ if (conf->cmd == CMD_VALID_PATH) { ++ if (conf->ignore_wwids || ++ check_wwids_file(refwwid, 0) == 0) + r = 0; +- } +- else +- printf("%s is not a valid multipath device path\n", conf->dev); ++ ++ printf("%s %s a valid multipath device path\n", ++ conf->dev, r == 0 ? "is" : "is not"); + goto out; + } + } +@@ -319,13 +322,13 @@ configure (void) + /* + * get a path list + */ +- if (conf->dev && !conf->list) ++ if (conf->dev) + di_flag = DI_WWID; + +- if (conf->list > 1) ++ if (conf->cmd == CMD_LIST_LONG) + /* extended path info '-ll' */ + di_flag |= DI_SYSFS | DI_CHECKER; +- else if (conf->list) ++ else if (conf->cmd == CMD_LIST_SHORT) + /* minimum path info '-l' */ + di_flag |= DI_SYSFS; + else +@@ -345,7 +348,7 @@ configure (void) + + filter_pathvec(pathvec, refwwid); + +- if (conf->list) { ++ if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) { + r = 0; + goto out; + } +@@ -440,7 +443,7 @@ main (int argc, char *argv[]) + int r = 1; + long int timestamp = -1; + int valid = -1; +- while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BritT:qwW")) != EOF ) { + switch(arg) { + case 'T': + if (optarg[0] == ':') +@@ -476,7 +479,7 @@ main (int argc, char *argv[]) + if (dm_prereq()) + exit(1); + +- while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":aAdchl::FfM:v:p:b:BritT:qwW")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -499,11 +502,11 @@ main (int argc, char *argv[]) + conf->allow_queueing = 1; + break; + case 'c': +- conf->dry_run = 2; ++ conf->cmd = CMD_VALID_PATH; + break; + case 'd': +- if (!conf->dry_run) +- conf->dry_run = 1; ++ if (conf->cmd == CMD_CREATE) ++ conf->cmd = CMD_DRY_RUN; + break; + case 'f': + conf->remove = FLUSH_ONE; +@@ -512,11 +515,10 @@ main (int argc, char *argv[]) + conf->remove = FLUSH_ALL; + break; + case 'l': +- conf->list = 1; +- conf->dry_run = 1; +- + if (optarg && !strncmp(optarg, "l", 1)) +- conf->list++; ++ conf->cmd = CMD_LIST_LONG; ++ else ++ conf->cmd = CMD_LIST_SHORT; + + break; + case 'M': +@@ -535,6 +537,9 @@ main (int argc, char *argv[]) + case 'r': + conf->force_reload = 1; + break; ++ case 'i': ++ conf->ignore_wwids = 1; ++ break; + case 't': + r = dump_config(); + goto out; +@@ -548,13 +553,13 @@ main (int argc, char *argv[]) + usage(argv[0]); + exit(0); + case 'w': +- conf->dry_run = 3; ++ conf->cmd = CMD_REMOVE_WWID; + break; + case 'W': +- conf->dry_run = 4; ++ conf->cmd = CMD_RESET_WWIDS; + break; + case 'a': +- conf->dry_run = 5; ++ conf->cmd = CMD_ADD_WWID; + break; + case ':': + fprintf(stderr, "Missing option argument\n"); +@@ -600,16 +605,16 @@ main (int argc, char *argv[]) + } + dm_init(); + +- if (conf->dry_run == 2 && ++ if (conf->cmd == CMD_VALID_PATH && + (!conf->dev || conf->dev_type == DEV_DEVMAP)) { + condlog(0, "the -c option requires a path to check"); + goto out; + } +- if (conf->dry_run == 3 && !conf->dev) { ++ if (conf->cmd == CMD_REMOVE_WWID && !conf->dev) { + condlog(0, "the -w option requires a device"); + goto out; + } +- if (conf->dry_run == 4) { ++ if (conf->cmd == CMD_RESET_WWIDS) { + struct multipath * mpp; + int i; + vector curmp; +Index: multipath-tools-130222/multipath/multipath.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.8 ++++ multipath-tools-130222/multipath/multipath.8 +@@ -8,7 +8,7 @@ multipath \- Device mapper target autoco + .RB [\| \-b\ \c + .IR bindings_file \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-a | \-A | \-w | \-W \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-r | \-a | \-A | \-w | \-W \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -55,6 +55,9 @@ print internal hardware table to stdout + .B \-r + force devmap reload + .TP ++.B \-i ++ignore wwids file when processing devices ++.TP + .B \-B + treat the bindings file as read only + .TP +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -580,7 +580,7 @@ domap (struct multipath * mpp, char * pa + /* + * last chance to quit before touching the devmaps + */ +- if (conf->dry_run && mpp->action != ACT_NOTHING) { ++ if (conf->cmd == CMD_DRY_RUN && mpp->action != ACT_NOTHING) { + print_multipath_topology(mpp, conf->verbosity); + return DOMAP_DRY; + } +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -54,7 +54,8 @@ store_pathinfo (vector pathvec, vector h + } + pp->udev = udev_device_ref(udevice); + err = pathinfo(pp, hwtable, +- (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST)); ++ (conf->cmd == CMD_REMOVE_WWID)? flag : ++ (flag | DI_BLACKLIST)); + if (err) + goto out; + +@@ -1101,7 +1102,7 @@ get_uid (struct path * pp) + + memset(pp->wwid, 0, WWID_SIZE); + value = udev_device_get_property_value(pp->udev, pp->uid_attribute); +- if ((!value || strlen(value) == 0) && conf->dry_run == 2) ++ if ((!value || strlen(value) == 0) && conf->cmd == CMD_VALID_PATH) + value = getenv(pp->uid_attribute); + if (value && strlen(value)) { + size_t len = WWID_SIZE; diff --git a/SOURCES/0099-RH-add-all-devs.patch b/SOURCES/0099-RH-add-all-devs.patch new file mode 100644 index 0000000..aca6d4c --- /dev/null +++ b/SOURCES/0099-RH-add-all-devs.patch @@ -0,0 +1,170 @@ +--- + libmultipath/config.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- + libmultipath/config.h | 1 + libmultipath/dict.c | 38 +++++++++++++++++++++++++++++ + 3 files changed, 102 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -113,6 +113,8 @@ find_hwe (vector hwtable, char * vendor, + * continuing to the generic entries + */ + vector_foreach_slot_backwards (hwtable, tmp, i) { ++ if (tmp->all_devs == 1) ++ continue; + if (hwe_regmatch(tmp, &hwe)) + continue; + ret = tmp; +@@ -348,6 +350,62 @@ merge_hwe (struct hwentry * dst, struct + return 0; + } + ++#define overwrite_str(s) \ ++do { \ ++ if (src->s) { \ ++ if (dst->s) \ ++ FREE(dst->s); \ ++ if (!(dst->s = set_param_str(src->s))) \ ++ return 1; \ ++ } \ ++} while(0) ++ ++#define overwrite_num(s) \ ++do { \ ++ if (src->s) \ ++ dst->s = src->s; \ ++} while(0) ++ ++static int ++overwrite_hwe (struct hwentry * dst, struct hwentry * src) ++{ ++ overwrite_str(vendor); ++ overwrite_str(product); ++ overwrite_str(revision); ++ overwrite_str(uid_attribute); ++ overwrite_str(features); ++ overwrite_str(hwhandler); ++ overwrite_str(selector); ++ overwrite_str(checker_name); ++ overwrite_str(prio_name); ++ overwrite_str(prio_args); ++ overwrite_str(alias_prefix); ++ overwrite_str(bl_product); ++ overwrite_num(pgpolicy); ++ overwrite_num(pgfailback); ++ overwrite_num(rr_weight); ++ overwrite_num(no_path_retry); ++ overwrite_num(minio); ++ overwrite_num(minio_rq); ++ overwrite_num(pg_timeout); ++ overwrite_num(flush_on_last_del); ++ overwrite_num(fast_io_fail); ++ overwrite_num(dev_loss); ++ overwrite_num(user_friendly_names); ++ overwrite_num(retain_hwhandler); ++ overwrite_num(detect_prio); ++ ++ /* ++ * Make sure features is consistent with ++ * no_path_retry ++ */ ++ if (dst->no_path_retry == NO_PATH_RETRY_FAIL) ++ remove_feature(&dst->features, "queue_if_no_path"); ++ else if (dst->no_path_retry != NO_PATH_RETRY_UNDEF) ++ add_feature(&dst->features, "queue_if_no_path"); ++ return 0; ++} ++ + int + store_hwe (vector hwtable, struct hwentry * dhwe) + { +@@ -431,7 +489,11 @@ restart: + break; + j = n; + vector_foreach_slot_after(hw, hwe2, j) { +- if (conf->hw_strmatch) { ++ if (hwe2->all_devs == 1) { ++ overwrite_hwe(hwe1, hwe2); ++ continue; ++ } ++ else if (conf->hw_strmatch) { + if (hwe_strmatch(hwe2, hwe1)) + continue; + } +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -47,6 +47,7 @@ struct hwentry { + char * prio_args; + char * alias_prefix; + ++ int all_devs; + int pgpolicy; + int pgfailback; + int rr_weight; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -918,6 +918,32 @@ device_handler(vector strvec) + } + + static int ++all_devs_handler(vector strvec) ++{ ++ char * buff; ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->all_devs = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->all_devs = 1; ++ else ++ hwe->all_devs = 0; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + vendor_handler(vector strvec) + { + struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); +@@ -2182,6 +2208,17 @@ snprint_hw_dev_loss(char * buff, int len + } + + static int ++snprint_hw_all_devs (char *buff, int len, void *data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (!hwe->all_devs) ++ return 0; ++ ++ return snprintf(buff, len, "yes"); ++} ++ ++static int + snprint_hw_vendor (char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2968,6 +3005,7 @@ init_keywords(void) + install_keyword_root("devices", &devices_handler); + install_keyword_multi("device", &device_handler, NULL); + install_sublevel(); ++ install_keyword("all_devs", &all_devs_handler, &snprint_hw_all_devs); + install_keyword("vendor", &vendor_handler, &snprint_hw_vendor); + install_keyword("product", &product_handler, &snprint_hw_product); + install_keyword("revision", &revision_handler, &snprint_hw_revision); diff --git a/SOURCES/0100-RHBZ-1067171-multipath-i-update.patch b/SOURCES/0100-RHBZ-1067171-multipath-i-update.patch new file mode 100644 index 0000000..9a67e7a --- /dev/null +++ b/SOURCES/0100-RHBZ-1067171-multipath-i-update.patch @@ -0,0 +1,54 @@ +--- + multipath/main.c | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -198,6 +198,9 @@ get_dm_mpvec (vector curmp, vector pathv + continue; + } + ++ if (conf->cmd == CMD_VALID_PATH) ++ continue; ++ + dm_get_map(mpp->alias, &mpp->size, params); + condlog(3, "params = %s", params); + dm_get_status(mpp->alias, status); +@@ -308,7 +311,13 @@ configure (void) + goto out; + } + condlog(3, "scope limited to %s", refwwid); +- if (conf->cmd == CMD_VALID_PATH) { ++ /* If you are ignoring the wwids file and find_multipaths is ++ * set, you need to actually check if there are two available ++ * paths to determine if this path should be multipathed. To ++ * do this, we put off the check until after discovering all ++ * the paths */ ++ if (conf->cmd == CMD_VALID_PATH && ++ (!conf->find_multipaths || !conf->ignore_wwids)) { + if (conf->ignore_wwids || + check_wwids_file(refwwid, 0) == 0) + r = 0; +@@ -348,6 +357,20 @@ configure (void) + + filter_pathvec(pathvec, refwwid); + ++ ++ if (conf->cmd == CMD_VALID_PATH) { ++ /* This only happens if find_multipaths is and ++ * ignore_wwids is set. ++ * If there is currently a multipath device matching ++ * the refwwid, or there is more than one path matching ++ * the refwwid, then the path is valid */ ++ if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1) ++ r = 0; ++ printf("%s %s a valid multipath device path\n", ++ conf->dev, r == 0 ? "is" : "is not"); ++ goto out; ++ } ++ + if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) { + r = 0; + goto out; diff --git a/SOURCES/0101-RH-cleanup-partmaps-code.patch b/SOURCES/0101-RH-cleanup-partmaps-code.patch new file mode 100644 index 0000000..57fb402 --- /dev/null +++ b/SOURCES/0101-RH-cleanup-partmaps-code.patch @@ -0,0 +1,199 @@ +--- + libmultipath/devmapper.c | 155 ++++++++++++++++++----------------------------- + 1 file changed, 61 insertions(+), 94 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -1006,8 +1006,9 @@ bad: + return NULL; + } + +-int +-dm_remove_partmaps (const char * mapname, int need_sync) ++static int ++do_foreach_partmaps (const char * mapname, int (*partmap_func)(char *, void *), ++ void *data) + { + struct dm_task *dmt; + struct dm_names *names; +@@ -1059,26 +1060,8 @@ dm_remove_partmaps (const char * mapname + */ + strstr(params, dev_t) + ) { +- /* +- * then it's a kpartx generated partition. +- * remove it. +- */ +- /* +- * if the opencount is 0 maybe some other +- * partitions depend on it. +- */ +- if (dm_get_opencount(names->name)) { +- dm_remove_partmaps(names->name, need_sync); +- if (dm_get_opencount(names->name)) { +- condlog(2, "%s: map in use", +- names->name); +- goto out; +- } +- } +- condlog(4, "partition map %s removed", +- names->name); +- dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name, +- need_sync, 0); ++ if (partmap_func(names->name, data) != 0) ++ goto out; + } + + next = names->next; +@@ -1091,6 +1074,35 @@ out: + return r; + } + ++struct remove_data { ++ int need_sync; ++}; ++ ++static int ++remove_partmap(char *name, void *data) ++{ ++ struct remove_data *rd = (struct remove_data *)data; ++ ++ if (dm_get_opencount(name)) { ++ dm_remove_partmaps(name, rd->need_sync); ++ if (dm_get_opencount(name)) { ++ condlog(2, "%s: map in use", name); ++ return 1; ++ } ++ } ++ condlog(4, "partition map %s removed", name); ++ dm_simplecmd_flush(DM_DEVICE_REMOVE, name, ++ rd->need_sync, 0); ++ return 0; ++} ++ ++int ++dm_remove_partmaps (const char * mapname, int need_sync) ++{ ++ struct remove_data rd = { need_sync }; ++ return do_foreach_partmaps(mapname, remove_partmap, &rd); ++} ++ + static struct dm_info * + alloc_dminfo (void) + { +@@ -1140,86 +1152,41 @@ out: + return r; + } + +-int +-dm_rename_partmaps (char * old, char * new) ++struct rename_data { ++ char *old; ++ char *new; ++ char *delim; ++}; ++ ++static int ++rename_partmap (char *name, void *data) + { +- struct dm_task *dmt; +- struct dm_names *names; +- unsigned next = 0; + char buff[PARAMS_SIZE]; +- unsigned long long size; +- char dev_t[32]; +- int r = 1; + int offset; +- char *delim; +- +- if (!(dmt = dm_task_create(DM_DEVICE_LIST))) +- return 1; ++ struct rename_data *rd = (struct rename_data *)data; + +- dm_task_no_open_count(dmt); +- +- if (!dm_task_run(dmt)) +- goto out; +- +- if (!(names = dm_task_get_names(dmt))) +- goto out; +- +- if (!names->dev) { +- r = 0; /* this is perfectly valid */ +- goto out; +- } ++ if (strncmp(name, rd->old, strlen(rd->old)) != 0) ++ return 0; ++ for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */ ++ snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim, ++ name + offset); ++ dm_rename(name, buff); ++ condlog(4, "partition map %s renamed", name); ++ return 0; ++} + +- if (dm_dev_t(old, &dev_t[0], 32)) +- goto out; ++int ++dm_rename_partmaps (char * old, char * new) ++{ ++ struct rename_data rd; + ++ rd.old = old; ++ rd.new = new; + if (isdigit(new[strlen(new)-1])) +- delim = "p"; ++ rd.delim = "p"; + else +- delim = ""; +- +- do { +- if ( +- /* +- * if devmap target is "linear" +- */ +- (dm_type(names->name, TGT_PART) > 0) && +- +- /* +- * and the multipath mapname and the part mapname start +- * the same +- */ +- !strncmp(names->name, old, strlen(old)) && +- +- /* +- * and we can fetch the map table from the kernel +- */ +- !dm_get_map(names->name, &size, &buff[0]) && +- +- /* +- * and the table maps over the multipath map +- */ +- strstr(buff, dev_t) +- ) { +- /* +- * then it's a kpartx generated partition. +- * Rename it. +- */ +- for (offset = strlen(old); names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do nothing */ +- snprintf(buff, PARAMS_SIZE, "%s%s%s", +- new, delim, names->name + offset); +- dm_rename(names->name, buff); +- condlog(4, "partition map %s renamed", +- names->name); +- } +- +- next = names->next; +- names = (void *) names + next; +- } while (next); +- +- r = 0; +-out: +- dm_task_destroy (dmt); +- return r; ++ rd.delim = ""; ++ return do_foreach_partmaps(old, rename_partmap, &rd); + } + + int diff --git a/SOURCES/0102-RHBZ-631009-deferred-remove.patch b/SOURCES/0102-RHBZ-631009-deferred-remove.patch new file mode 100644 index 0000000..9e40337 --- /dev/null +++ b/SOURCES/0102-RHBZ-631009-deferred-remove.patch @@ -0,0 +1,764 @@ +--- + libmultipath/Makefile | 6 + + libmultipath/config.c | 3 + libmultipath/config.h | 3 + libmultipath/configure.c | 1 + libmultipath/defaults.h | 1 + libmultipath/devmapper.c | 142 ++++++++++++++++++++++++++++++++++++++++----- + libmultipath/devmapper.h | 11 ++- + libmultipath/dict.c | 116 ++++++++++++++++++++++++++++++++++++ + libmultipath/propsel.c | 28 ++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 8 ++ + libmultipath/structs_vec.c | 3 + multipath/multipath.conf.5 | 14 ++++ + multipathd/main.c | 23 +++++-- + 14 files changed, 333 insertions(+), 27 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -337,6 +337,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(user_friendly_names); + merge_num(retain_hwhandler); + merge_num(detect_prio); ++ merge_num(deferred_remove); + + /* + * Make sure features is consistent with +@@ -394,6 +395,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(user_friendly_names); + overwrite_num(retain_hwhandler); + overwrite_num(detect_prio); ++ overwrite_num(deferred_remove); + + /* + * Make sure features is consistent with +@@ -617,6 +619,7 @@ load_config (char * file, struct udev *u + conf->fast_io_fail = DEFAULT_FAST_IO_FAIL; + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; + conf->detect_prio = DEFAULT_DETECT_PRIO; ++ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE; + conf->hw_strmatch = 0; + conf->force_sync = 0; + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -61,6 +61,7 @@ struct hwentry { + int user_friendly_names; + int retain_hwhandler; + int detect_prio; ++ int deferred_remove; + char * bl_product; + }; + +@@ -84,6 +85,7 @@ struct mpentry { + int flush_on_last_del; + int attribute_flags; + int user_friendly_names; ++ int deferred_remove; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -128,6 +130,7 @@ struct config { + int retain_hwhandler; + int detect_prio; + int force_sync; ++ int deferred_remove; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -290,6 +290,7 @@ setup_map (struct multipath * mpp, char + select_dev_loss(mpp); + select_reservation_key(mpp); + select_retain_hwhandler(mpp); ++ select_deferred_remove(mpp); + + sysfs_set_scsi_tmo(mpp); + /* +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -19,6 +19,7 @@ + #define DEFAULT_FAST_IO_FAIL 5 + #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF + #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF ++#define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -32,6 +32,8 @@ + #define UUID_PREFIX "mpath-" + #define UUID_PREFIX_LEN 6 + ++static int dm_cancel_remove_partmaps(const char * mapname); ++ + #ifndef LIBDM_API_COOKIE + static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a) + { +@@ -103,7 +105,9 @@ dm_lib_prereq (void) + { + char version[64]; + int v[3]; +-#if defined(DM_SUBSYSTEM_UDEV_FLAG0) ++#if defined(LIBDM_API_DEFERRED) ++ int minv[3] = {1, 2, 89}; ++#elif defined(DM_SUBSYSTEM_UDEV_FLAG0) + int minv[3] = {1, 2, 82}; + #elif defined(LIBDM_API_COOKIE) + int minv[3] = {1, 2, 38}; +@@ -201,8 +205,10 @@ dm_prereq (void) + return dm_drv_prereq(); + } + ++#define do_deferred(x) ((x) == DEFERRED_REMOVE_ON || (x) == DEFERRED_REMOVE_IN_PROGRESS) ++ + static int +-dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags) { ++dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags, int deferred_remove) { + int r = 0; + int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME || + task == DM_DEVICE_REMOVE)); +@@ -220,7 +226,10 @@ dm_simplecmd (int task, const char *name + if (no_flush) + dm_task_no_flush(dmt); /* for DM_DEVICE_SUSPEND/RESUME */ + #endif +- ++#ifdef LIBDM_API_DEFERRED ++ if (do_deferred(deferred_remove)) ++ dm_task_deferred_remove(dmt); ++#endif + if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags)) + goto out; + r = dm_task_run (dmt); +@@ -232,12 +241,18 @@ dm_simplecmd (int task, const char *name + + extern int + dm_simplecmd_flush (int task, const char *name, int needsync, uint16_t udev_flags) { +- return dm_simplecmd(task, name, 0, needsync, udev_flags); ++ return dm_simplecmd(task, name, 0, needsync, udev_flags, 0); + } + + extern int + dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags) { +- return dm_simplecmd(task, name, 1, 1, udev_flags); ++ return dm_simplecmd(task, name, 1, 1, udev_flags, 0); ++} ++ ++static int ++dm_device_remove (const char *name, int needsync, int deferred_remove) { ++ return dm_simplecmd(DM_DEVICE_REMOVE, name, 0, needsync, 0, ++ deferred_remove); + } + + extern int +@@ -653,7 +668,7 @@ out: + } + + extern int +-_dm_flush_map (const char * mapname, int need_sync) ++_dm_flush_map (const char * mapname, int need_sync, int deferred_remove) + { + int r; + +@@ -663,23 +678,46 @@ _dm_flush_map (const char * mapname, int + if (dm_type(mapname, TGT_MPATH) <= 0) + return 0; /* nothing to do */ + +- if (dm_remove_partmaps(mapname, need_sync)) ++ if (dm_remove_partmaps(mapname, need_sync, deferred_remove)) + return 1; + +- if (dm_get_opencount(mapname)) { ++ if (!do_deferred(deferred_remove) && dm_get_opencount(mapname)) { + condlog(2, "%s: map in use", mapname); + return 1; + } + +- r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync, 0); ++ r = dm_device_remove(mapname, need_sync, deferred_remove); + + if (r) { ++ if (do_deferred(deferred_remove) && dm_map_present(mapname)) { ++ condlog(4, "multipath map %s remove deferred", ++ mapname); ++ return 2; ++ } + condlog(4, "multipath map %s removed", mapname); + return 0; + } + return 1; + } + ++#ifdef LIBDM_API_DEFERRED ++ ++int ++dm_flush_map_nopaths(const char * mapname, int deferred_remove) ++{ ++ return _dm_flush_map(mapname, 1, deferred_remove); ++} ++ ++#else ++ ++int ++dm_flush_map_nopaths(const char * mapname, int deferred_remove) ++{ ++ return _dm_flush_map(mapname, 1, 0); ++} ++ ++#endif ++ + extern int + dm_suspend_and_flush_map (const char * mapname) + { +@@ -1076,6 +1114,7 @@ out: + + struct remove_data { + int need_sync; ++ int deferred_remove; + }; + + static int +@@ -1084,25 +1123,98 @@ remove_partmap(char *name, void *data) + struct remove_data *rd = (struct remove_data *)data; + + if (dm_get_opencount(name)) { +- dm_remove_partmaps(name, rd->need_sync); +- if (dm_get_opencount(name)) { ++ dm_remove_partmaps(name, rd->need_sync, rd->deferred_remove); ++ if (!do_deferred(rd->deferred_remove) && ++ dm_get_opencount(name)) { + condlog(2, "%s: map in use", name); + return 1; + } + } + condlog(4, "partition map %s removed", name); +- dm_simplecmd_flush(DM_DEVICE_REMOVE, name, +- rd->need_sync, 0); ++ dm_device_remove(name, rd->need_sync, rd->deferred_remove); + return 0; + } + + int +-dm_remove_partmaps (const char * mapname, int need_sync) ++dm_remove_partmaps (const char * mapname, int need_sync, int deferred_remove) + { +- struct remove_data rd = { need_sync }; ++ struct remove_data rd = { need_sync, deferred_remove }; + return do_foreach_partmaps(mapname, remove_partmap, &rd); + } + ++#ifdef LIBDM_API_DEFERRED ++ ++static int ++cancel_remove_partmap (char *name, void *unused) ++{ ++ if (dm_get_opencount(name)) ++ dm_cancel_remove_partmaps(name); ++ if (dm_message(name, "@cancel_deferred_remove") != 0) ++ condlog(0, "%s: can't cancel deferred remove: %s", name, ++ strerror(errno)); ++ return 0; ++} ++ ++static int ++dm_get_deferred_remove (char * mapname) ++{ ++ int r = -1; ++ struct dm_task *dmt; ++ struct dm_info info; ++ ++ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ return -1; ++ ++ if (!dm_task_set_name(dmt, mapname)) ++ goto out; ++ ++ if (!dm_task_run(dmt)) ++ goto out; ++ ++ if (!dm_task_get_info(dmt, &info)) ++ goto out; ++ ++ r = info.deferred_remove; ++out: ++ dm_task_destroy(dmt); ++ return r; ++} ++ ++static int ++dm_cancel_remove_partmaps(const char * mapname) { ++ return do_foreach_partmaps(mapname, cancel_remove_partmap, NULL); ++} ++ ++int ++dm_cancel_deferred_remove (struct multipath *mpp) ++{ ++ int r = 0; ++ ++ if (!dm_get_deferred_remove(mpp->alias)) ++ return 0; ++ if (mpp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) ++ mpp->deferred_remove = DEFERRED_REMOVE_ON; ++ ++ dm_cancel_remove_partmaps(mpp->alias); ++ r = dm_message(mpp->alias, "@cancel_deferred_remove"); ++ if (r) ++ condlog(0, "%s: can't cancel deferred remove: %s", mpp->alias, ++ strerror(errno)); ++ else ++ condlog(2, "%s: canceled deferred remove", mpp->alias); ++ return r; ++} ++ ++#else ++ ++int ++dm_cancel_deferred_remove (struct multipath *mpp) ++{ ++ return 0; ++} ++ ++#endif ++ + static struct dm_info * + alloc_dminfo (void) + { +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -23,9 +23,11 @@ int dm_map_present (const char *); + int dm_get_map(const char *, unsigned long long *, char *); + int dm_get_status(char *, char *); + int dm_type(const char *, char *); +-int _dm_flush_map (const char *, int); +-#define dm_flush_map(mapname) _dm_flush_map(mapname, 1) +-#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0) ++int _dm_flush_map (const char *, int, int); ++int dm_flush_map_nopaths(const char * mapname, int deferred_remove); ++#define dm_flush_map(mapname) _dm_flush_map(mapname, 1, 0) ++#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0, 0) ++int dm_cancel_deferred_remove(struct multipath *mpp); + int dm_suspend_and_flush_map(const char * mapname); + int dm_flush_maps (void); + int dm_fail_path(char * mapname, char * path); +@@ -40,7 +42,8 @@ int dm_geteventnr (char *name); + int dm_get_major (char *name); + int dm_get_minor (char *name); + char * dm_mapname(int major, int minor); +-int dm_remove_partmaps (const char * mapname, int need_sync); ++int dm_remove_partmaps (const char * mapname, int need_sync, ++ int deferred_remove); + int dm_get_uuid(char *name, char *uuid); + int dm_get_info (char * mapname, struct dm_info ** dmi); + int dm_rename (char * old, char * new); +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -738,6 +738,29 @@ def_force_sync_handler(vector strvec) + return 0; + } + ++static int ++def_deferred_remove_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->deferred_remove = DEFERRED_REMOVE_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->deferred_remove = DEFERRED_REMOVE_ON; ++ else ++ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1445,6 +1468,33 @@ hw_detect_prio_handler(vector strvec) + return 0; + } + ++static int ++hw_deferred_remove_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->deferred_remove = DEFERRED_REMOVE_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->deferred_remove = DEFERRED_REMOVE_ON; ++ else ++ hwe->deferred_remove = DEFERRED_REMOVE_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -1920,6 +1970,32 @@ mp_names_handler(vector strvec) + return 0; + } + ++static int ++mp_deferred_remove_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "0") == 0)) ++ mpe->deferred_remove = DEFERRED_REMOVE_OFF; ++ else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "1") == 0)) ++ mpe->deferred_remove = DEFERRED_REMOVE_ON; ++ else ++ mpe->deferred_remove = DEFERRED_REMOVE_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2165,7 +2241,7 @@ snprint_mp_reservation_key (char * buff, + return snprintf(buff, len, "0x%" PRIx64, prkey); + } + +- static int ++static int + snprint_mp_user_friendly_names (char * buff, int len, void * data) + { + struct mpentry * mpe = (struct mpentry *)data; +@@ -2179,6 +2255,19 @@ snprint_mp_user_friendly_names (char * b + } + + static int ++snprint_mp_deferred_remove (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->deferred_remove == DEFERRED_REMOVE_UNDEF) ++ return 0; ++ else if (mpe->deferred_remove == DEFERRED_REMOVE_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "yes"); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2507,6 +2596,19 @@ snprint_hw_retain_hwhandler_handler(char + } + + static int ++snprint_hw_deferred_remove(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->deferred_remove == DEFERRED_REMOVE_ON) ++ return snprintf(buff, len, "yes"); ++ else if (hwe->deferred_remove == DEFERRED_REMOVE_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return 0; ++} ++ ++static int + snprint_detect_prio(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2900,6 +3002,15 @@ snprint_def_force_sync(char * buff, int + } + + static int ++snprint_def_deferred_remove(char * buff, int len, void * data) ++{ ++ if (conf->deferred_remove == DEFERRED_REMOVE_ON) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -2968,6 +3079,7 @@ init_keywords(void) + install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio); + install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch); + install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); ++ install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -3032,6 +3144,7 @@ init_keywords(void) + install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names); + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler); + install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio); ++ install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove); + install_sublevel_end(); + + install_keyword_root("multipaths", &multipaths_handler); +@@ -3056,5 +3169,6 @@ init_keywords(void) + install_keyword("gid", &mp_gid_handler, &snprint_mp_gid); + install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key); + install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names); ++ install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -744,6 +744,34 @@ select_retain_hwhandler (struct multipat + } + + extern int ++select_deferred_remove (struct multipath *mp) ++{ ++ if (mp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) { ++ condlog(3, "%s: deferred_remove in progress", mp->alias); ++ return 0; ++ } ++ if (mp->mpe && mp->mpe->deferred_remove) { ++ mp->deferred_remove = mp->mpe->deferred_remove; ++ condlog(3, "%s: deferred_remove = %i (multipath setting)", ++ mp->alias, mp->deferred_remove); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->deferred_remove) { ++ mp->deferred_remove = mp->hwe->deferred_remove; ++ condlog(3, "%s: deferred_remove = %d (controller default)", mp->alias, mp->deferred_remove); ++ return 0; ++ } ++ if (conf->deferred_remove) { ++ mp->deferred_remove = conf->deferred_remove; ++ condlog(3, "%s: deferred_remove = %d (config file default)", mp->alias, mp->deferred_remove); ++ return 0; ++ } ++ mp->deferred_remove = DEFAULT_DEFERRED_REMOVE; ++ condlog(3, "%s: deferred_remove = %d (compiled in default)", mp->alias, mp->deferred_remove); ++ return 0; ++} ++ ++extern int + select_detect_prio (struct path * pp) + { + if (pp->hwe && pp->hwe->detect_prio) { +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -20,3 +20,4 @@ int select_dev_loss(struct multipath *mp + int select_reservation_key(struct multipath *mp); + int select_retain_hwhandler (struct multipath * mp); + int select_detect_prio(struct path * pp); ++int select_deferred_remove(struct multipath *mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -114,6 +114,13 @@ enum detect_prio_states { + DETECT_PRIO_ON, + }; + ++enum deferred_remove_states { ++ DEFERRED_REMOVE_UNDEF, ++ DEFERRED_REMOVE_OFF, ++ DEFERRED_REMOVE_ON, ++ DEFERRED_REMOVE_IN_PROGRESS, ++}; ++ + enum scsi_protocol { + SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ + SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ +@@ -207,6 +214,7 @@ struct multipath { + int attribute_flags; + int fast_io_fail; + int retain_hwhandler; ++ int deferred_remove; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -214,19 +214,30 @@ sync_maps_state(vector mpvec) + } + + static int +-flush_map(struct multipath * mpp, struct vectors * vecs) ++flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths) + { ++ int r; ++ ++ if (nopaths) ++ r = dm_flush_map_nopaths(mpp->alias, mpp->deferred_remove); ++ else ++ r = dm_flush_map(mpp->alias); + /* + * clear references to this map before flushing so we can ignore + * the spurious uevent we may generate with the dm_flush_map call below + */ +- if (dm_flush_map(mpp->alias)) { ++ if (r) { + /* + * May not really be an error -- if the map was already flushed + * from the device mapper by dmsetup(8) for instance. + */ +- condlog(0, "%s: can't flush", mpp->alias); +- return 1; ++ if (r == 1) ++ condlog(0, "%s: can't flush", mpp->alias); ++ else { ++ condlog(2, "%s: devmap deferred remove", mpp->alias); ++ mpp->deferred_remove = DEFERRED_REMOVE_IN_PROGRESS; ++ } ++ return r; + } + else { + dm_lib_release(); +@@ -372,7 +383,7 @@ ev_remove_map (char * devname, char * al + mpp->alias, mpp->dmi->minor, minor); + return 0; + } +- return flush_map(mpp, vecs); ++ return flush_map(mpp, vecs, 0); + } + + static int +@@ -628,7 +639,7 @@ ev_remove_path (struct path *pp, struct + mpp->flush_on_last_del = FLUSH_IN_PROGRESS; + dm_queue_if_no_path(mpp->alias, 0); + } +- if (!flush_map(mpp, vecs)) { ++ if (!flush_map(mpp, vecs, 1)) { + condlog(2, "%s: removed map after" + " removing all paths", + alias); +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -392,6 +392,8 @@ __setup_multipath (struct vectors * vecs + set_no_path_retry(mpp); + select_pg_timeout(mpp); + select_flush_on_last_del(mpp); ++ if (VECTOR_SIZE(mpp->paths) != 0) ++ dm_cancel_deferred_remove(mpp); + } + + return 0; +@@ -565,7 +567,6 @@ int update_multipath (struct vectors *ve + } + } + } +- + return 0; + } + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -420,6 +420,16 @@ only one checker will run at a time. Th + multipathd checkers running in parallel causes significant CPU pressure. The + Default is + .I no ++.TP ++.B deferred_remove ++If set to ++.I yes ++, multipathd will do a deferred remove instead of a regular remove when the ++last path device has been deleted. This means that if the multipath device is ++still in use, it will be freed when the last user closes it. If path is added ++to the multipath device before the last user closes it, the deferred remove ++will be canceled. Default is ++.I no + . + .SH "blacklist section" + The +@@ -521,6 +531,8 @@ section: + .B features + .TP + .B reservation_key ++.TP ++.B deferred_remove + .RE + .PD + .LP +@@ -611,6 +623,8 @@ section: + .B retain_attached_hw_handler + .TP + .B detect_prio ++.TP ++.B deferred_remove + .RE + .PD + .LP +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -36,6 +36,12 @@ ifneq ($(strip $(LIBUDEV_API_RECVBUF)),0 + CFLAGS += -DLIBUDEV_API_RECVBUF + endif + ++LIBDM_API_DEFERRED = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_deferred_remove' /usr/include/libdevmapper.h) ++ ++ifneq ($(strip $(LIBDM_API_DEFERRED)),0) ++ CFLAGS += -DLIBDM_API_DEFERRED ++endif ++ + + all: $(LIBS) + diff --git a/SOURCES/0103-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch b/SOURCES/0103-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch new file mode 100644 index 0000000..8c793bb --- /dev/null +++ b/SOURCES/0103-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch @@ -0,0 +1,10 @@ +diff -purN multipath-tools-130222.orig/multipath/multipath.rules multipath-tools-130222/multipath/multipath.rules +--- multipath-tools-130222.orig/multipath/multipath.rules 2014-11-03 14:37:41.269413134 +0100 ++++ multipath-tools-130222/multipath/multipath.rules 2014-11-03 14:38:43.694281901 +0100 +@@ -45,5 +45,5 @@ ACTION!="change", GOTO="end_mpath" + ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" +-RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" ++ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" + LABEL="end_mpath" diff --git a/SOURCES/0104-RHBZ-1159337-fix-double-free.patch b/SOURCES/0104-RHBZ-1159337-fix-double-free.patch new file mode 100644 index 0000000..cbe4d1e --- /dev/null +++ b/SOURCES/0104-RHBZ-1159337-fix-double-free.patch @@ -0,0 +1,20 @@ +--- + multipathd/main.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -669,9 +669,8 @@ ev_remove_path (struct path *pp, struct + /* + * update our state from kernel + */ +- if (setup_multipath(vecs, mpp)) { +- goto fail; +- } ++ if (setup_multipath(vecs, mpp)) ++ return 1; + sync_map_state(mpp); + + condlog(2, "%s [%s]: path removed from map %s", diff --git a/SOURCES/0105-RHBZ-1180032-find-multipaths-man.patch b/SOURCES/0105-RHBZ-1180032-find-multipaths-man.patch new file mode 100644 index 0000000..c5e6bcf --- /dev/null +++ b/SOURCES/0105-RHBZ-1180032-find-multipaths-man.patch @@ -0,0 +1,37 @@ +--- + multipath/multipath.conf.5 | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -84,6 +84,28 @@ directory where the dynamic shared objec + dependent, commonly + .I /lib/multipath + .TP ++.B find_multipaths ++If set to ++.I yes ++, instead of trying to create a multipath device for every non-blacklisted ++path, multipath will only create a device if one of three condidions are ++met. ++.I 1 ++There are at least two non-blacklisted paths with the same wwid, ++.I 2 ++the user manually forces the creation, by specifying a device with the multipath ++command, or ++.I 3 ++a path has the same WWID as a multipath device that was previously created ++while find_multipaths was set (even if that multipath device doesn't currently ++exist). ++Whenever a multipath device is created with find_multipaths set, multipath will ++remeber the WWID of the device, so that it will automatically create the ++device again, as soon as it sees a path with that WWID. This should allow most ++users to have multipath automatically choose the correct paths to make into ++multipath devices, without having to edit the blacklist; Default is ++.I no ++.TP + .B verbosity + default verbosity. Higher values increase the verbosity level. Valid + levels are between 0 and 6; default is diff --git a/SOURCES/0106-RHBZ-1169935-no-new-devs.patch b/SOURCES/0106-RHBZ-1169935-no-new-devs.patch new file mode 100644 index 0000000..99ae35a --- /dev/null +++ b/SOURCES/0106-RHBZ-1169935-no-new-devs.patch @@ -0,0 +1,231 @@ +--- + libmultipath/config.c | 4 ++++ + libmultipath/config.h | 1 + + libmultipath/configure.c | 5 ++--- + libmultipath/dict.c | 33 +++++++++++++++++++++++++++++++++ + libmultipath/util.c | 30 ++++++++++++++++++++++++++++++ + libmultipath/util.h | 1 + + libmultipath/wwids.c | 21 ++++++++++++++------- + multipathd/main.c | 3 +-- + 8 files changed, 86 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -131,6 +131,7 @@ struct config { + int detect_prio; + int force_sync; + int deferred_remove; ++ int ignore_new_boot_devs; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -775,9 +775,8 @@ coalesce_paths (struct vectors * vecs, v + if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE)) + continue; + +- /* If find_multipaths was selected check if the path is valid */ +- if (conf->find_multipaths && !refwwid && +- !should_multipath(pp1, pathvec)) { ++ /* check if the path is valid */ ++ if (!refwwid && !should_multipath(pp1, pathvec)) { + orphan_path(pp1); + continue; + } +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -15,6 +15,7 @@ + #include "wwids.h" + #include "defaults.h" + #include "config.h" ++#include "util.h" + + /* + * Copyright (c) 2010 Benjamin Marzinski, Redhat +@@ -268,15 +269,21 @@ should_multipath(struct path *pp1, vecto + { + int i; + struct path *pp2; ++ int ignore_new_devs = (conf->ignore_new_boot_devs && in_initrd()); ++ ++ if (!conf->find_multipaths && !ignore_new_devs) ++ return 1; + + condlog(4, "checking if %s should be multipathed", pp1->dev); +- vector_foreach_slot(pathvec, pp2, i) { +- if (pp1->dev == pp2->dev) +- continue; +- if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) { +- condlog(3, "found multiple paths with wwid %s, " +- "multipathing %s", pp1->wwid, pp1->dev); +- return 1; ++ if (!ignore_new_devs) { ++ vector_foreach_slot(pathvec, pp2, i) { ++ if (pp1->dev == pp2->dev) ++ continue; ++ if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) { ++ condlog(3, "found multiple paths with wwid %s, " ++ "multipathing %s", pp1->wwid, pp1->dev); ++ return 1; ++ } + } + } + if (check_wwids_file(pp1->wwid, 0) < 0) { +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -503,8 +503,7 @@ rescan: + return 1; + } + +- if (conf->find_multipaths && +- !should_multipath(pp, vecs->pathvec)) { ++ if (!should_multipath(pp, vecs->pathvec)) { + orphan_path(pp); + return 0; + } +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -622,6 +622,7 @@ load_config (char * file, struct udev *u + conf->deferred_remove = DEFAULT_DEFERRED_REMOVE; + conf->hw_strmatch = 0; + conf->force_sync = 0; ++ conf->ignore_new_boot_devs = 0; + + /* + * preload default hwtable +@@ -732,6 +733,9 @@ load_config (char * file, struct udev *u + !conf->wwids_file) + goto out; + ++ if (conf->ignore_new_boot_devs) ++ in_initrd(); ++ + return 0; + out: + free_config(conf); +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -761,6 +761,29 @@ def_deferred_remove_handler(vector strve + return 0; + } + ++static int ++def_ignore_new_boot_devs_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->ignore_new_boot_devs = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->ignore_new_boot_devs = 1; ++ else ++ conf->ignore_new_boot_devs = 0; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -3011,6 +3034,15 @@ snprint_def_deferred_remove(char * buff, + } + + static int ++snprint_def_ignore_new_boot_devs(char * buff, int len, void * data) ++{ ++ if (conf->ignore_new_boot_devs == 1) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3080,6 +3112,7 @@ init_keywords(void) + install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch); + install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); + install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); ++ install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/libmultipath/util.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.c ++++ multipath-tools-130222/libmultipath/util.c +@@ -3,6 +3,8 @@ + #include + #include + #include ++#include ++#include + + #include "debug.h" + #include "memory.h" +@@ -267,3 +269,31 @@ dev_t parse_devt(const char *dev_t) + + return makedev(maj, min); + } ++ ++/* This define was taken from systemd. src/shared/macro.h */ ++#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) ++ ++/* This function was taken from systemd. src/shared/util.c */ ++int in_initrd(void) { ++ static int saved = -1; ++ struct statfs s; ++ ++ if (saved >= 0) ++ return saved; ++ ++ /* We make two checks here: ++ * ++ * 1. the flag file /etc/initrd-release must exist ++ * 2. the root file system must be a memory file system ++ * The second check is extra paranoia, since misdetecting an ++ * initrd can have bad bad consequences due the initrd ++ * emptying when transititioning to the main systemd. ++ */ ++ ++ saved = access("/etc/initrd-release", F_OK) >= 0 && ++ statfs("/", &s) >= 0 && ++ (F_TYPE_EQUAL(s.f_type, TMPFS_MAGIC) || ++ F_TYPE_EQUAL(s.f_type, RAMFS_MAGIC)); ++ ++ return saved; ++} +Index: multipath-tools-130222/libmultipath/util.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.h ++++ multipath-tools-130222/libmultipath/util.h +@@ -11,6 +11,7 @@ void remove_trailing_chars(char *path, c + int devt2devname (char *, int, char *); + dev_t parse_devt(const char *dev_t); + char *convert_dev(char *dev, int is_path_device); ++int in_initrd(void); + + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) diff --git a/SOURCES/0107-RH-adapter-name-wildcard.patch b/SOURCES/0107-RH-adapter-name-wildcard.patch new file mode 100644 index 0000000..3c67de5 --- /dev/null +++ b/SOURCES/0107-RH-adapter-name-wildcard.patch @@ -0,0 +1,33 @@ +--- + libmultipath/print.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -510,6 +510,16 @@ snprint_tgt_wwnn (char * buff, size_t le + } + + static int ++snprint_host_adapter (char * buff, size_t len, struct path * pp) ++{ ++ char adapter[SLOT_NAME_SIZE]; ++ ++ if (sysfs_get_host_adapter_name(pp, adapter)) ++ return snprintf(buff, len, "[undef]"); ++ return snprint_str(buff, len, adapter); ++} ++ ++static int + snprint_path_checker (char * buff, size_t len, struct path * pp) + { + struct checker * c = &pp->checker; +@@ -557,6 +567,7 @@ struct path_data pd[] = { + {'n', "target WWNN", 0, snprint_tgt_wwnn}, + {'R', "host WWPN", 0, snprint_host_wwpn}, + {'r', "target WWPN", 0, snprint_tgt_wwpn}, ++ {'a', "host adapter", 0, snprint_host_adapter}, + {0, NULL, 0 , NULL} + }; + diff --git a/SOURCES/0108-RHBZ-1153832-kpartx-remove-devs.patch b/SOURCES/0108-RHBZ-1153832-kpartx-remove-devs.patch new file mode 100644 index 0000000..f02551a --- /dev/null +++ b/SOURCES/0108-RHBZ-1153832-kpartx-remove-devs.patch @@ -0,0 +1,15 @@ +--- + multipath/multipath.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -45,5 +45,5 @@ ACTION!="change", GOTO="end_mpath" + ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" +-ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode" ++ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -u $tempnode" + LABEL="end_mpath" diff --git a/SOURCES/0109-RH-read-only-bindings.patch b/SOURCES/0109-RH-read-only-bindings.patch new file mode 100644 index 0000000..c08120f --- /dev/null +++ b/SOURCES/0109-RH-read-only-bindings.patch @@ -0,0 +1,27 @@ +--- + multipathd/main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1879,7 +1879,7 @@ main (int argc, char *argv[]) + if (!conf) + exit(1); + +- while ((arg = getopt(argc, argv, ":dv:k::")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dv:k::B")) != EOF ) { + switch(arg) { + case 'd': + logsink = 0; +@@ -1895,6 +1895,9 @@ main (int argc, char *argv[]) + case 'k': + uxclnt(optarg); + exit(0); ++ case 'B': ++ conf->bindings_read_only = 1; ++ break; + default: + ; + } diff --git a/SOURCES/0110-RHBZ-blacklist-vd-devs.patch b/SOURCES/0110-RHBZ-blacklist-vd-devs.patch new file mode 100644 index 0000000..af52d0d --- /dev/null +++ b/SOURCES/0110-RHBZ-blacklist-vd-devs.patch @@ -0,0 +1,17 @@ +--- + libmultipath/blacklist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/blacklist.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.c ++++ multipath-tools-130222/libmultipath/blacklist.c +@@ -169,7 +169,7 @@ setup_default_blist (struct config * con + if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) + return 1; + +- str = STRDUP("^(td|hd)[a-z]"); ++ str = STRDUP("^(td|hd|vd)[a-z]"); + if (!str) + return 1; + if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) diff --git a/SOURCES/0111-RH-dont-show-pg-timeout.patch b/SOURCES/0111-RH-dont-show-pg-timeout.patch new file mode 100644 index 0000000..f545cc5 --- /dev/null +++ b/SOURCES/0111-RH-dont-show-pg-timeout.patch @@ -0,0 +1,147 @@ +--- + libmultipath/dict.c | 97 ---------------------------------------------------- + 1 file changed, 97 deletions(-) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -473,26 +473,6 @@ def_checker_timeout_handler(vector strve + static int + def_pg_timeout_handler(vector strvec) + { +- int pg_timeout; +- char * buff; +- +- buff = set_value(strvec); +- +- if (!buff) +- return 1; +- +- if (strlen(buff) == 4 && !strcmp(buff, "none")) +- conf->pg_timeout = -PGTIMEOUT_NONE; +- else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) { +- if (pg_timeout == 0) +- conf->pg_timeout = -PGTIMEOUT_NONE; +- else +- conf->pg_timeout = pg_timeout; +- } +- else +- conf->pg_timeout = PGTIMEOUT_UNDEF; +- +- FREE(buff); + return 0; + } + +@@ -1358,30 +1338,6 @@ hw_minio_rq_handler(vector strvec) + static int + hw_pg_timeout_handler(vector strvec) + { +- int pg_timeout; +- struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); +- char *buff; +- +- if (!hwe) +- return 1; +- +- buff = set_value(strvec); +- +- if (!buff) +- return 1; +- +- if (strlen(buff) == 4 && !strcmp(buff, "none")) +- hwe->pg_timeout = -PGTIMEOUT_NONE; +- else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) { +- if (pg_timeout == 0) +- hwe->pg_timeout = -PGTIMEOUT_NONE; +- else +- hwe->pg_timeout = pg_timeout; +- } +- else +- hwe->pg_timeout = PGTIMEOUT_UNDEF; +- +- FREE(buff); + return 0; + } + +@@ -1819,29 +1775,6 @@ mp_minio_rq_handler(vector strvec) + static int + mp_pg_timeout_handler(vector strvec) + { +- int pg_timeout; +- struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); +- char *buff; +- +- if (!mpe) +- return 1; +- +- buff = set_value(strvec); +- +- if (!buff) +- return 1; +- if (strlen(buff) == 4 && !strcmp(buff, "none")) +- mpe->pg_timeout = -PGTIMEOUT_NONE; +- else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) { +- if (pg_timeout == 0) +- mpe->pg_timeout = -PGTIMEOUT_NONE; +- else +- mpe->pg_timeout = pg_timeout; +- } +- else +- mpe->pg_timeout = PGTIMEOUT_UNDEF; +- +- FREE(buff); + return 0; + } + +@@ -2180,16 +2113,6 @@ snprint_mp_rr_min_io_rq (char * buff, in + static int + snprint_mp_pg_timeout (char * buff, int len, void * data) + { +- struct mpentry * mpe = (struct mpentry *)data; +- +- switch (mpe->pg_timeout) { +- case PGTIMEOUT_UNDEF: +- break; +- case -PGTIMEOUT_NONE: +- return snprintf(buff, len, "\"none\""); +- default: +- return snprintf(buff, len, "%i", mpe->pg_timeout); +- } + return 0; + } + +@@ -2551,19 +2474,6 @@ snprint_hw_rr_min_io_rq (char * buff, in + static int + snprint_hw_pg_timeout (char * buff, int len, void * data) + { +- struct hwentry * hwe = (struct hwentry *)data; +- +- if (!hwe->pg_timeout) +- return 0; +- +- switch (hwe->pg_timeout) { +- case PGTIMEOUT_UNDEF: +- break; +- case -PGTIMEOUT_NONE: +- return snprintf(buff, len, "\"none\""); +- default: +- return snprintf(buff, len, "%i", hwe->pg_timeout); +- } + return 0; + } + +@@ -2895,13 +2805,6 @@ snprint_def_checker_timeout (char *buff, + static int + snprint_def_pg_timeout (char * buff, int len, void * data) + { +- switch (conf->pg_timeout) { +- case PGTIMEOUT_UNDEF: +- case -PGTIMEOUT_NONE: +- return snprintf(buff, len, "\"none\""); +- default: +- return snprintf(buff, len, "%i", conf->pg_timeout); +- } + return 0; + } + diff --git a/SOURCES/0112-RHBZ-1194917-add-config_dir-option.patch b/SOURCES/0112-RHBZ-1194917-add-config_dir-option.patch new file mode 100644 index 0000000..6cc07e7 --- /dev/null +++ b/SOURCES/0112-RHBZ-1194917-add-config_dir-option.patch @@ -0,0 +1,616 @@ +--- + libmultipath/config.c | 56 +++++++++++++++++++++++++++++++- + libmultipath/config.h | 2 + + libmultipath/defaults.h | 1 + libmultipath/dict.c | 69 +++++++++++++++++++++++++++++++++++---- + libmultipath/parser.c | 78 +++++++++++++++++++++++---------------------- + libmultipath/parser.h | 3 - + multipath.conf.annotated | 10 +++++ + multipath.conf.defaults | 1 + multipath/multipath.conf.5 | 7 ++++ + 9 files changed, 179 insertions(+), 48 deletions(-) + +Index: multipath-tools-130222/libmultipath/parser.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/parser.c ++++ multipath-tools-130222/libmultipath/parser.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + + #include "parser.h" + #include "memory.h" +@@ -453,14 +454,15 @@ set_value(vector strvec) + /* non-recursive configuration stream handler */ + static int kw_level = 0; + +-int warn_on_duplicates(vector uniques, char *str) ++int warn_on_duplicates(vector uniques, char *str, char *file) + { + char *tmp; + int i; + + vector_foreach_slot(uniques, tmp, i) { + if (!strcmp(str, tmp)) { +- condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str); ++ condlog(1, "%s line %d, duplicate keyword: %s", ++ file, line_nr, str); + return 0; + } + } +@@ -496,65 +498,70 @@ is_sublevel_keyword(char *str) + } + + int +-validate_config_strvec(vector strvec) ++validate_config_strvec(vector strvec, char *file) + { + char *str; + int i; + + str = VECTOR_SLOT(strvec, 0); + if (str == NULL) { +- condlog(0, "can't parse option on line %d of config file", +- line_nr); ++ condlog(0, "can't parse option on line %d of %s", ++ line_nr, file); + return -1; + } + if (*str == '}') { + if (VECTOR_SIZE(strvec) > 1) +- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr); ++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file); + return 0; + } + if (*str == '{') { +- condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr); ++ condlog(0, "invalid keyword '%s' on line %d of %s", ++ str, line_nr, file); + return -1; + } + if (is_sublevel_keyword(str)) { + str = VECTOR_SLOT(strvec, 1); + if (str == NULL) +- condlog(0, "missing '{' on line %d of config file", line_nr); ++ condlog(0, "missing '{' on line %d of %s", ++ line_nr, file); + else if (*str != '{') +- condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str); ++ condlog(0, "expecting '{' on line %d of %s. found '%s'", ++ line_nr, file, str); + else if (VECTOR_SIZE(strvec) > 2) +- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr); ++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file); + return 0; + } + str = VECTOR_SLOT(strvec, 1); + if (str == NULL) { +- condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr); ++ condlog(0, "missing value for option '%s' on line %d of %s", ++ (char *)VECTOR_SLOT(strvec, 0), line_nr, file); + return -1; + } + if (*str != '"') { + if (VECTOR_SIZE(strvec) > 2) +- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr); ++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file); + return 0; + } + for (i = 2; i < VECTOR_SIZE(strvec); i++) { + str = VECTOR_SLOT(strvec, i); + if (str == NULL) { +- condlog(0, "can't parse value on line %d of config file", line_nr); ++ condlog(0, "can't parse value on line %d of %s", ++ line_nr, file); + return -1; + } + if (*str == '"') { + if (VECTOR_SIZE(strvec) > i + 1) +- condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr); ++ condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file); + return 0; + } + } +- condlog(0, "missing closing quotes on line %d of config file", +- line_nr); ++ condlog(0, "missing closing quotes on line %d of %s", ++ line_nr, file); + return 0; + } + +-int +-process_stream(vector keywords) ++static int ++process_stream(vector keywords, char *file) + { + int i; + int r = 0; +@@ -583,7 +590,7 @@ process_stream(vector keywords) + if (!strvec) + continue; + +- if (validate_config_strvec(strvec) != 0) { ++ if (validate_config_strvec(strvec, file) != 0) { + free_strvec(strvec); + continue; + } +@@ -595,8 +602,8 @@ process_stream(vector keywords) + free_strvec(strvec); + break; + } +- condlog(0, "unmatched '%s' at line %d of config file", +- EOB, line_nr); ++ condlog(0, "unmatched '%s' at line %d of %s", ++ EOB, line_nr, file); + } + + for (i = 0; i < VECTOR_SIZE(keywords); i++) { +@@ -604,7 +611,7 @@ process_stream(vector keywords) + + if (!strcmp(keyword->string, str)) { + if (keyword->unique && +- warn_on_duplicates(uniques, str)) { ++ warn_on_duplicates(uniques, str, file)) { + r = 1; + free_strvec(strvec); + goto out; +@@ -614,15 +621,15 @@ process_stream(vector keywords) + + if (keyword->sub) { + kw_level++; +- r += process_stream(keyword->sub); ++ r += process_stream(keyword->sub, file); + kw_level--; + } + break; + } + } + if (i >= VECTOR_SIZE(keywords)) +- condlog(1, "multipath.conf +%d, invalid keyword: %s", +- line_nr, str); ++ condlog(1, "%s line %d, invalid keyword: %s", ++ file, line_nr, str); + + free_strvec(strvec); + } +@@ -646,27 +653,24 @@ int alloc_keywords(void) + + /* Data initialization */ + int +-init_data(char *conf_file, void (*init_keywords) (void)) ++process_file(char *file) + { + int r; + +- stream = fopen(conf_file, "r"); ++ if (!keywords) { ++ condlog(0, "No keywords alocated"); ++ return 1; ++ } ++ stream = fopen(file, "r"); + if (!stream) { +- syslog(LOG_WARNING, "Configuration file open problem"); ++ condlog(0, "couldn't open configuration file '%s': %s", ++ file, strerror(errno)); + return 1; + } + +- /* Init Keywords structure */ +- (*init_keywords) (); +- +-/* Dump configuration * +- vector_dump(keywords); +- dump_keywords(keywords, 0); +-*/ +- + /* Stream handling */ + line_nr = 0; +- r = process_stream(keywords); ++ r = process_stream(keywords, file); + fclose(stream); + //free_keywords(keywords); + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -117,6 +117,8 @@ reassign_maps_handler(vector strvec) + static int + multipath_dir_handler(vector strvec) + { ++ if (conf->multipath_dir) ++ FREE(conf->multipath_dir); + conf->multipath_dir = set_value(strvec); + + if (!conf->multipath_dir) +@@ -128,6 +130,8 @@ multipath_dir_handler(vector strvec) + static int + def_selector_handler(vector strvec) + { ++ if (conf->selector) ++ FREE(conf->selector); + conf->selector = set_value(strvec); + + if (!conf->selector) +@@ -155,6 +159,8 @@ def_pgpolicy_handler(vector strvec) + static int + def_uid_attribute_handler(vector strvec) + { ++ if (conf->uid_attribute) ++ FREE(conf->uid_attribute); + conf->uid_attribute = set_value(strvec); + + if (!conf->uid_attribute) +@@ -166,6 +172,8 @@ def_uid_attribute_handler(vector strvec) + static int + def_prio_handler(vector strvec) + { ++ if (conf->prio_name) ++ FREE(conf->prio_name); + conf->prio_name = set_value(strvec); + + if (!conf->prio_name) +@@ -177,6 +185,8 @@ def_prio_handler(vector strvec) + static int + def_alias_prefix_handler(vector strvec) + { ++ if (conf->alias_prefix) ++ FREE(conf->alias_prefix); + conf->alias_prefix = set_value(strvec); + + if (!conf->alias_prefix) +@@ -188,6 +198,8 @@ def_alias_prefix_handler(vector strvec) + static int + def_prio_args_handler(vector strvec) + { ++ if (conf->prio_args) ++ FREE(conf->prio_args); + conf->prio_args = set_value(strvec); + + if (!conf->prio_args) +@@ -199,6 +211,8 @@ def_prio_args_handler(vector strvec) + static int + def_features_handler(vector strvec) + { ++ if (conf->features) ++ FREE(conf->features); + conf->features = set_value(strvec); + + if (!conf->features) +@@ -210,6 +224,8 @@ def_features_handler(vector strvec) + static int + def_path_checker_handler(vector strvec) + { ++ if (conf->checker_name) ++ FREE(conf->checker_name); + conf->checker_name = set_value(strvec); + + if (!conf->checker_name) +@@ -432,6 +448,23 @@ def_no_path_retry_handler(vector strvec) + return 0; + } + ++ ++static int ++def_config_dir_handler(vector strvec) ++{ ++ /* this is only valid in the main config file */ ++ if (conf->processed_main_config) ++ return 0; ++ if (conf->config_dir) ++ FREE(conf->config_dir); ++ conf->config_dir = set_value(strvec); ++ ++ if (!conf->config_dir) ++ return 1; ++ ++ return 0; ++} ++ + static int + def_queue_without_daemon(vector strvec) + { +@@ -611,6 +644,8 @@ def_names_handler(vector strvec) + static int + bindings_file_handler(vector strvec) + { ++ if (conf->bindings_file) ++ FREE(conf->bindings_file); + conf->bindings_file = set_value(strvec); + + if (!conf->bindings_file) +@@ -622,6 +657,8 @@ bindings_file_handler(vector strvec) + static int + wwids_file_handler(vector strvec) + { ++ if (conf->wwids_file) ++ FREE(conf->wwids_file); + conf->wwids_file = set_value(strvec); + + if (!conf->wwids_file) +@@ -770,9 +807,12 @@ def_ignore_new_boot_devs_handler(vector + static int + blacklist_handler(vector strvec) + { +- conf->blist_devnode = vector_alloc(); +- conf->blist_wwid = vector_alloc(); +- conf->blist_device = vector_alloc(); ++ if (!conf->blist_devnode) ++ conf->blist_devnode = vector_alloc(); ++ if (!conf->blist_wwid) ++ conf->blist_wwid = vector_alloc(); ++ if (!conf->blist_device) ++ conf->blist_device = vector_alloc(); + + if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device) + return 1; +@@ -783,9 +823,12 @@ blacklist_handler(vector strvec) + static int + blacklist_exceptions_handler(vector strvec) + { +- conf->elist_devnode = vector_alloc(); +- conf->elist_wwid = vector_alloc(); +- conf->elist_device = vector_alloc(); ++ if (!conf->elist_devnode) ++ conf->elist_devnode = vector_alloc(); ++ if (!conf->elist_wwid) ++ conf->elist_wwid = vector_alloc(); ++ if (!conf->elist_device) ++ conf->elist_device = vector_alloc(); + + if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device) + return 1; +@@ -1480,7 +1523,8 @@ hw_deferred_remove_handler(vector strvec + static int + multipaths_handler(vector strvec) + { +- conf->mptable = vector_alloc(); ++ if (!conf->mptable) ++ conf->mptable = vector_alloc(); + + if (!conf->mptable) + return 1; +@@ -2945,6 +2989,16 @@ snprint_def_ignore_new_boot_devs(char * + return snprintf(buff, len, "no"); + } + ++ ++static int ++snprint_def_config_dir (char * buff, int len, void * data) ++{ ++ if (!conf->config_dir) ++ return 0; ++ ++ return snprintf(buff, len, "\"%s\"", conf->config_dir); ++} ++ + static int + snprint_ble_simple (char * buff, int len, void * data) + { +@@ -3016,6 +3070,7 @@ init_keywords(void) + install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); + install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); + install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs); ++ install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/libmultipath/parser.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/parser.h ++++ multipath-tools-130222/libmultipath/parser.h +@@ -76,9 +76,8 @@ extern int read_line(char *buf, int size + extern vector read_value_block(void); + extern int alloc_value_block(vector strvec, void (*alloc_func) (vector)); + extern void *set_value(vector strvec); +-extern int process_stream(vector keywords); + extern int alloc_keywords(void); +-extern int init_data(char *conf_file, void (*init_keywords) (void)); ++extern int process_file(char *conf_file); + extern struct keyword * find_keyword(vector v, char * name); + void set_current_keywords (vector *k); + int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -6,6 +6,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "checkers.h" + #include "memory.h" +@@ -556,6 +559,7 @@ free_config (struct config * conf) + + if (conf->wwids_file) + FREE(conf->wwids_file); ++ + if (conf->prio_name) + FREE(conf->prio_name); + +@@ -567,6 +571,10 @@ free_config (struct config * conf) + + if (conf->checker_name) + FREE(conf->checker_name); ++ ++ if (conf->config_dir) ++ FREE(conf->config_dir); ++ + if (conf->reservation_key) + FREE(conf->reservation_key); + +@@ -584,6 +592,43 @@ free_config (struct config * conf) + FREE(conf); + } + ++/* if multipath fails to process the config directory, it should continue, ++ * with just a warning message */ ++static void ++process_config_dir(vector keywords, char *dir) ++{ ++ struct dirent **namelist; ++ int i, n; ++ char path[LINE_MAX]; ++ int old_hwtable_size; ++ ++ if (dir[0] != '/') { ++ condlog(1, "config_dir '%s' must be a fully qualified path", ++ dir); ++ return; ++ } ++ n = scandir(dir, &namelist, NULL, alphasort); ++ if (n < 0) { ++ if (errno == ENOENT) ++ condlog(3, "No configuration dir '%s'", dir); ++ else ++ condlog(0, "couldn't open configuration dir '%s': %s", ++ dir, strerror(errno)); ++ return; ++ } ++ for (i = 0; i < n; i++) { ++ if (!strstr(namelist[i]->d_name, ".conf")) ++ continue; ++ old_hwtable_size = VECTOR_SIZE(conf->hwtable); ++ snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name); ++ path[LINE_MAX-1] = '\0'; ++ process_file(path); ++ if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size) ++ factorize_hwtable(conf->hwtable, old_hwtable_size); ++ ++ } ++} ++ + int + load_config (char * file, struct udev *udev) + { +@@ -623,6 +668,7 @@ load_config (char * file, struct udev *u + conf->hw_strmatch = 0; + conf->force_sync = 0; + conf->ignore_new_boot_devs = 0; ++ conf->processed_main_config = 0; + + /* + * preload default hwtable +@@ -641,11 +687,12 @@ load_config (char * file, struct udev *u + */ + set_current_keywords(&conf->keywords); + alloc_keywords(); ++ init_keywords(); + if (filepresent(file)) { + int builtin_hwtable_size; + + builtin_hwtable_size = VECTOR_SIZE(conf->hwtable); +- if (init_data(file, init_keywords)) { ++ if (process_file(file)) { + condlog(0, "error parsing config file"); + goto out; + } +@@ -658,7 +705,6 @@ load_config (char * file, struct udev *u + } + + } else { +- init_keywords(); + condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); + condlog(0, "A default multipath.conf file is located at"); + condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE)); +@@ -677,6 +723,12 @@ load_config (char * file, struct udev *u + } + } + ++ conf->processed_main_config = 1; ++ if (conf->config_dir == NULL) ++ conf->config_dir = set_default(DEFAULT_CONFIG_DIR); ++ if (conf->config_dir && conf->config_dir[0] != '\0') ++ process_config_dir(conf->keywords, conf->config_dir); ++ + /* + * fill the voids left in the config file + */ +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -132,6 +132,7 @@ struct config { + int force_sync; + int deferred_remove; + int ignore_new_boot_devs; ++ int processed_main_config; + unsigned int version[3]; + + char * dev; +@@ -147,6 +148,7 @@ struct config { + char * prio_args; + char * checker_name; + char * alias_prefix; ++ char * config_dir; + unsigned char * reservation_key; + + vector keywords; +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -31,5 +31,6 @@ + #define DEFAULT_CONFIGFILE "/etc/multipath.conf" + #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" + #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" ++#define DEFAULT_CONFIG_DIR "/etc/multipath/conf.d" + + char * set_default (char * str); +Index: multipath-tools-130222/multipath.conf.annotated +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.annotated ++++ multipath-tools-130222/multipath.conf.annotated +@@ -232,6 +232,16 @@ + # # values : yes|no + # # default : no + # force_sync yes ++# ++# # ++# # name : config_dir ++# # scope : multipath & multipathd ++# # desc : If not set to an empty string, multipath will search ++# # this directory alphabetically for files ending in ".conf" ++# # and it will read configuration information from these ++# # files, just as if it was in /etc/multipath.conf ++# # values : "" or a fully qualified pathname ++# # default : "/etc/multipath/conf.d" + #} + # + ## +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -26,6 +26,7 @@ + # log_checker_err always + # retain_attached_hw_handler no + # detect_prio no ++# config_dir "/etc/multipath/conf.d" + #} + #blacklist { + # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -452,6 +452,13 @@ still in use, it will be freed when the + to the multipath device before the last user closes it, the deferred remove + will be canceled. Default is + .I no ++.TP ++.B config_dir ++If set to anything other than "", multipath will search this directory ++alphabetically for file ending in ".conf" and it will read configuration ++information from them, just as if it was in /etc/multipath.conf. config_dir ++must either be "" or a fully qualified directory name. Default is ++.I "/etc/multipath/conf.d" + . + .SH "blacklist section" + The diff --git a/SOURCES/0113-RHBZ-1194917-cleanup.patch b/SOURCES/0113-RHBZ-1194917-cleanup.patch new file mode 100644 index 0000000..cf95c98 --- /dev/null +++ b/SOURCES/0113-RHBZ-1194917-cleanup.patch @@ -0,0 +1,185 @@ +--- + libmultipath/parser.c | 103 +++----------------------------------------------- + libmultipath/parser.h | 6 -- + 2 files changed, 8 insertions(+), 101 deletions(-) + +Index: multipath-tools-130222/libmultipath/parser.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/parser.c ++++ multipath-tools-130222/libmultipath/parser.c +@@ -280,8 +280,8 @@ out: + return NULL; + } + +-int +-read_line(char *buf, int size) ++static int ++read_line(FILE *stream, char *buf, int size) + { + int ch; + int count = 0; +@@ -297,95 +297,6 @@ read_line(char *buf, int size) + return (ch == EOF) ? 0 : 1; + } + +-vector +-read_value_block(void) +-{ +- char *buf; +- int i; +- char *str = NULL; +- char *dup; +- vector vec = NULL; +- vector elements = vector_alloc(); +- +- if (!elements) +- return NULL; +- +- buf = (char *) MALLOC(MAXBUF); +- +- if (!buf) { +- vector_free(elements); +- return NULL; +- } +- +- while (read_line(buf, MAXBUF)) { +- vec = alloc_strvec(buf); +- if (vec) { +- str = VECTOR_SLOT(vec, 0); +- if (!strcmp(str, EOB)) { +- free_strvec(vec); +- break; +- } +- +- for (i = 0; i < VECTOR_SIZE(vec); i++) { +- str = VECTOR_SLOT(vec, i); +- dup = (char *) MALLOC(strlen(str) + 1); +- if (!dup) +- goto out; +- memcpy(dup, str, strlen(str)); +- +- if (!vector_alloc_slot(elements)) { +- free_strvec(vec); +- goto out1; +- } +- +- vector_set_slot(elements, dup); +- } +- free_strvec(vec); +- } +- memset(buf, 0, MAXBUF); +- } +- FREE(buf); +- return elements; +-out1: +- FREE(dup); +-out: +- FREE(buf); +- vector_free(elements); +- return NULL; +-} +- +-int +-alloc_value_block(vector strvec, void (*alloc_func) (vector)) +-{ +- char *buf; +- char *str = NULL; +- vector vec = NULL; +- +- buf = (char *) MALLOC(MAXBUF); +- +- if (!buf) +- return 1; +- +- while (read_line(buf, MAXBUF)) { +- vec = alloc_strvec(buf); +- if (vec) { +- str = VECTOR_SLOT(vec, 0); +- if (!strcmp(str, EOB)) { +- free_strvec(vec); +- break; +- } +- +- if (VECTOR_SIZE(vec)) +- (*alloc_func) (vec); +- +- free_strvec(vec); +- } +- memset(buf, 0, MAXBUF); +- } +- FREE(buf); +- return 0; +-} +- + void * + set_value(vector strvec) + { +@@ -561,7 +472,7 @@ validate_config_strvec(vector strvec, ch + } + + static int +-process_stream(vector keywords, char *file) ++process_stream(FILE *stream, vector keywords, char *file) + { + int i; + int r = 0; +@@ -582,7 +493,7 @@ process_stream(vector keywords, char *fi + return 1; + } + +- while (read_line(buf, MAXBUF)) { ++ while (read_line(stream, buf, MAXBUF)) { + line_nr++; + strvec = alloc_strvec(buf); + memset(buf,0, MAXBUF); +@@ -621,7 +532,8 @@ process_stream(vector keywords, char *fi + + if (keyword->sub) { + kw_level++; +- r += process_stream(keyword->sub, file); ++ r += process_stream(stream, ++ keyword->sub, file); + kw_level--; + } + break; +@@ -656,6 +568,7 @@ int + process_file(char *file) + { + int r; ++ FILE *stream; + + if (!keywords) { + condlog(0, "No keywords alocated"); +@@ -670,7 +583,7 @@ process_file(char *file) + + /* Stream handling */ + line_nr = 0; +- r = process_stream(keywords, file); ++ r = process_stream(stream, keywords, file); + fclose(stream); + //free_keywords(keywords); + +Index: multipath-tools-130222/libmultipath/parser.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/parser.h ++++ multipath-tools-130222/libmultipath/parser.h +@@ -47,9 +47,6 @@ struct keyword { + int unique; + }; + +-/* global var exported */ +-FILE *stream; +- + /* Reloading helpers */ + #define SET_RELOAD (reload = 1) + #define UNSET_RELOAD (reload = 0) +@@ -72,9 +69,6 @@ extern int _install_keyword(char *string + extern void dump_keywords(vector keydump, int level); + extern void free_keywords(vector keywords); + extern vector alloc_strvec(char *string); +-extern int read_line(char *buf, int size); +-extern vector read_value_block(void); +-extern int alloc_value_block(vector strvec, void (*alloc_func) (vector)); + extern void *set_value(vector strvec); + extern int alloc_keywords(void); + extern int process_file(char *conf_file); diff --git a/SOURCES/0114-RHBZ-1196394-delayed-reintegration.patch b/SOURCES/0114-RHBZ-1196394-delayed-reintegration.patch new file mode 100644 index 0000000..b0647a5 --- /dev/null +++ b/SOURCES/0114-RHBZ-1196394-delayed-reintegration.patch @@ -0,0 +1,744 @@ +--- + libmultipath/checkers.c | 3 + libmultipath/checkers.h | 9 + + libmultipath/config.c | 4 + libmultipath/config.h | 6 + + libmultipath/configure.c | 2 + libmultipath/defaults.h | 1 + libmultipath/dict.c | 204 ++++++++++++++++++++++++++++++++++++++++++++- + libmultipath/print.c | 2 + libmultipath/propsel.c | 52 +++++++++++ + libmultipath/propsel.h | 2 + libmultipath/structs.h | 9 + + multipath.conf.annotated | 40 ++++++++ + multipath.conf.defaults | 2 + multipath/multipath.conf.5 | 27 +++++ + multipathd/main.c | 34 ++++++- + 15 files changed, 388 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -62,6 +62,8 @@ struct hwentry { + int retain_hwhandler; + int detect_prio; + int deferred_remove; ++ int delay_watch_checks; ++ int delay_wait_checks; + char * bl_product; + }; + +@@ -86,6 +88,8 @@ struct mpentry { + int attribute_flags; + int user_friendly_names; + int deferred_remove; ++ int delay_watch_checks; ++ int delay_wait_checks; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -133,6 +137,8 @@ struct config { + int deferred_remove; + int ignore_new_boot_devs; + int processed_main_config; ++ int delay_watch_checks; ++ int delay_wait_checks; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -134,6 +134,11 @@ enum scsi_protocol { + SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */ + }; + ++enum delay_checks_states { ++ DELAY_CHECKS_OFF = -1, ++ DELAY_CHECKS_UNDEF = 0, ++}; ++ + struct sg_id { + int host_no; + int channel; +@@ -180,6 +185,8 @@ struct path { + int priority; + int pgindex; + int detect_prio; ++ int watch_checks; ++ int wait_checks; + char * uid_attribute; + struct prio prio; + char * prio_args; +@@ -215,6 +222,8 @@ struct multipath { + int fast_io_fail; + int retain_hwhandler; + int deferred_remove; ++ int delay_watch_checks; ++ int delay_wait_checks; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/libmultipath/checkers.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.h ++++ multipath-tools-130222/libmultipath/checkers.h +@@ -46,6 +46,14 @@ + * PATH_PENDING: + * - Use: All async checkers + * - Description: Indicates a check IO is in flight. ++ * ++ * PATH_DELAYED: ++ * - Use: None of the checkers (returned if the path is being delayed before ++ * reintegration. ++ * - Description: If a path fails after being up for less than ++ * delay_watch_checks checks, when it comes back up again, it will not ++ * be marked as up until it has been up for delay_wait_checks checks. ++ * During this time, it is marked as "delayed" + */ + enum path_check_state { + PATH_WILD, +@@ -55,6 +63,7 @@ enum path_check_state { + PATH_SHAKY, + PATH_GHOST, + PATH_PENDING, ++ PATH_DELAYED, + PATH_MAX_STATE + }; + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -291,6 +291,8 @@ setup_map (struct multipath * mpp, char + select_reservation_key(mpp); + select_retain_hwhandler(mpp); + select_deferred_remove(mpp); ++ select_delay_watch_checks(mpp); ++ select_delay_wait_checks(mpp); + + sysfs_set_scsi_tmo(mpp); + /* +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -20,6 +20,7 @@ + #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF + #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF + #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF ++#define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -801,6 +801,44 @@ def_ignore_new_boot_devs_handler(vector + return 0; + } + ++static int ++def_delay_watch_checks_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->delay_watch_checks = DELAY_CHECKS_OFF; ++ else if ((conf->delay_watch_checks = atoi(buff)) < 1) ++ conf->delay_watch_checks = DELAY_CHECKS_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++def_delay_wait_checks_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->delay_wait_checks = DELAY_CHECKS_OFF; ++ else if ((conf->delay_wait_checks = atoi(buff)) < 1) ++ conf->delay_wait_checks = DELAY_CHECKS_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1517,6 +1555,52 @@ hw_deferred_remove_handler(vector strvec + return 0; + } + ++static int ++hw_delay_watch_checks_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->delay_watch_checks = DELAY_CHECKS_OFF; ++ else if ((hwe->delay_watch_checks = atoi(buff)) < 1) ++ hwe->delay_watch_checks = DELAY_CHECKS_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++hw_delay_wait_checks_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->delay_wait_checks = DELAY_CHECKS_OFF; ++ else if ((hwe->delay_wait_checks = atoi(buff)) < 1) ++ hwe->delay_wait_checks = DELAY_CHECKS_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -1996,6 +2080,52 @@ mp_deferred_remove_handler(vector strvec + return 0; + } + ++static int ++mp_delay_watch_checks_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->delay_watch_checks = DELAY_CHECKS_OFF; ++ else if ((mpe->delay_watch_checks = atoi(buff)) < 1) ++ mpe->delay_watch_checks = DELAY_CHECKS_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++mp_delay_wait_checks_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->delay_wait_checks = DELAY_CHECKS_OFF; ++ else if ((mpe->delay_wait_checks = atoi(buff)) < 1) ++ mpe->delay_wait_checks = DELAY_CHECKS_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2258,6 +2388,30 @@ snprint_mp_deferred_remove (char * buff, + } + + static int ++snprint_mp_delay_watch_checks(char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->delay_watch_checks == DELAY_CHECKS_UNDEF) ++ return 0; ++ if (mpe->delay_watch_checks == DELAY_CHECKS_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", mpe->delay_watch_checks); ++} ++ ++static int ++snprint_mp_delay_wait_checks(char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->delay_wait_checks == DELAY_CHECKS_UNDEF) ++ return 0; ++ if (mpe->delay_wait_checks == DELAY_CHECKS_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", mpe->delay_wait_checks); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2586,6 +2740,30 @@ snprint_hw_deferred_remove(char * buff, + } + + static int ++snprint_hw_delay_watch_checks(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->delay_watch_checks == DELAY_CHECKS_UNDEF) ++ return 0; ++ if (hwe->delay_watch_checks == DELAY_CHECKS_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", hwe->delay_watch_checks); ++} ++ ++static int ++snprint_hw_delay_wait_checks(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->delay_wait_checks == DELAY_CHECKS_UNDEF) ++ return 0; ++ if (hwe->delay_wait_checks == DELAY_CHECKS_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", hwe->delay_wait_checks); ++} ++ ++static int + snprint_detect_prio(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2883,7 +3061,6 @@ snprint_def_find_multipaths (char * buff + return snprintf(buff, len, "yes"); + } + +- + static int + snprint_def_user_friendly_names (char * buff, int len, void * data) + { +@@ -2989,7 +3166,6 @@ snprint_def_ignore_new_boot_devs(char * + return snprintf(buff, len, "no"); + } + +- + static int + snprint_def_config_dir (char * buff, int len, void * data) + { +@@ -3000,6 +3176,24 @@ snprint_def_config_dir (char * buff, int + } + + static int ++snprint_def_delay_watch_checks(char * buff, int len, void * data) ++{ ++ if (conf->delay_watch_checks == DELAY_CHECKS_UNDEF || ++ conf->delay_watch_checks == DELAY_CHECKS_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", conf->delay_watch_checks); ++} ++ ++static int ++snprint_def_delay_wait_checks(char * buff, int len, void * data) ++{ ++ if (conf->delay_wait_checks == DELAY_CHECKS_UNDEF || ++ conf->delay_wait_checks == DELAY_CHECKS_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", conf->delay_wait_checks); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3071,6 +3265,8 @@ init_keywords(void) + install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); + install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs); + install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir); ++ install_keyword("delay_watch_checks", &def_delay_watch_checks_handler, &snprint_def_delay_watch_checks); ++ install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -3136,6 +3332,8 @@ init_keywords(void) + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler); + install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio); + install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove); ++ install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks); ++ install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks); + install_sublevel_end(); + + install_keyword_root("multipaths", &multipaths_handler); +@@ -3161,5 +3359,7 @@ init_keywords(void) + install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key); + install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names); + install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove); ++ install_keyword("delay_watch_checks", &mp_delay_watch_checks_handler, &snprint_mp_delay_watch_checks); ++ install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -336,6 +336,8 @@ snprint_chk_state (char * buff, size_t l + return snprintf(buff, len, "shaky"); + case PATH_GHOST: + return snprintf(buff, len, "ghost"); ++ case PATH_DELAYED: ++ return snprintf(buff, len, "delayed"); + default: + return snprintf(buff, len, "undef"); + } +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -788,3 +788,55 @@ select_detect_prio (struct path * pp) + condlog(3, "%s: detect_prio = %d (compiled in default)", pp->dev, pp->detect_prio); + return 0; + } ++ ++extern int ++select_delay_watch_checks (struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->delay_watch_checks != DELAY_CHECKS_UNDEF) { ++ mp->delay_watch_checks = mp->mpe->delay_watch_checks; ++ condlog(3, "delay_watch_checks = %i (multipath setting)", ++ mp->delay_watch_checks); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->delay_watch_checks != DELAY_CHECKS_UNDEF) { ++ mp->delay_watch_checks = mp->hwe->delay_watch_checks; ++ condlog(3, "delay_watch_checks = %i (controler setting)", ++ mp->delay_watch_checks); ++ return 0; ++ } ++ if (conf->delay_watch_checks != DELAY_CHECKS_UNDEF) { ++ mp->delay_watch_checks = conf->delay_watch_checks; ++ condlog(3, "delay_watch_checks = %i (config file default)", ++ mp->delay_watch_checks); ++ return 0; ++ } ++ mp->delay_watch_checks = DEFAULT_DELAY_CHECKS; ++ condlog(3, "delay_watch_checks = DISABLED (internal default)"); ++ return 0; ++} ++ ++extern int ++select_delay_wait_checks (struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->delay_wait_checks != DELAY_CHECKS_UNDEF) { ++ mp->delay_wait_checks = mp->mpe->delay_wait_checks; ++ condlog(3, "delay_wait_checks = %i (multipath setting)", ++ mp->delay_wait_checks); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->delay_wait_checks != DELAY_CHECKS_UNDEF) { ++ mp->delay_wait_checks = mp->hwe->delay_wait_checks; ++ condlog(3, "delay_wait_checks = %i (controler setting)", ++ mp->delay_wait_checks); ++ return 0; ++ } ++ if (conf->delay_wait_checks != DELAY_CHECKS_UNDEF) { ++ mp->delay_wait_checks = conf->delay_wait_checks; ++ condlog(3, "delay_wait_checks = %i (config file default)", ++ mp->delay_wait_checks); ++ return 0; ++ } ++ mp->delay_wait_checks = DEFAULT_DELAY_CHECKS; ++ condlog(3, "delay_wait_checks = DISABLED (internal default)"); ++ return 0; ++} +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -21,3 +21,5 @@ int select_reservation_key(struct multip + int select_retain_hwhandler (struct multipath * mp); + int select_detect_prio(struct path * pp); + int select_deferred_remove(struct multipath *mp); ++int select_delay_watch_checks (struct multipath * mp); ++int select_delay_wait_checks (struct multipath * mp); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -188,7 +188,8 @@ sync_map_state(struct multipath *mpp) + vector_foreach_slot (mpp->pg, pgp, i){ + vector_foreach_slot (pgp->paths, pp, j){ + if (pp->state == PATH_UNCHECKED || +- pp->state == PATH_WILD) ++ pp->state == PATH_WILD || ++ pp->state == PATH_DELAYED) + continue; + if ((pp->dmstate == PSTATE_FAILED || + pp->dmstate == PSTATE_UNDEF) && +@@ -1165,6 +1166,16 @@ check_path (struct vectors * vecs, struc + if (!pp->mpp) + return; + ++ if ((newstate == PATH_UP || newstate == PATH_GHOST) && ++ pp->wait_checks > 0) { ++ if (pp->mpp && pp->mpp->nr_active > 0) { ++ pp->state = PATH_DELAYED; ++ pp->wait_checks--; ++ return; ++ } else ++ pp->wait_checks = 0; ++ } ++ + pp->chkrstate = newstate; + if (newstate != pp->state) { + int oldstate = pp->state; +@@ -1182,9 +1193,14 @@ check_path (struct vectors * vecs, struc + * proactively fail path in the DM + */ + if (oldstate == PATH_UP || +- oldstate == PATH_GHOST) ++ oldstate == PATH_GHOST) { + fail_path(pp, 1); +- else ++ if (pp->mpp->delay_wait_checks > 0 && ++ pp->watch_checks > 0) { ++ pp->wait_checks = pp->mpp->delay_wait_checks; ++ pp->watch_checks = 0; ++ } ++ }else + fail_path(pp, 0); + + /* +@@ -1211,11 +1227,15 @@ check_path (struct vectors * vecs, struc + * reinstate this path + */ + if (oldstate != PATH_UP && +- oldstate != PATH_GHOST) ++ oldstate != PATH_GHOST) { ++ if (pp->mpp->delay_watch_checks > 0) ++ pp->watch_checks = pp->mpp->delay_watch_checks; + reinstate_path(pp, 1); +- else ++ } else { ++ if (pp->watch_checks > 0) ++ pp->watch_checks--; + reinstate_path(pp, 0); +- ++ } + new_path_up = 1; + + if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST) +@@ -1245,6 +1265,8 @@ check_path (struct vectors * vecs, struc + else + pp->checkint = conf->max_checkint; + } ++ if (pp->watch_checks > 0) ++ pp->watch_checks--; + pp->tick = pp->checkint; + condlog(4, "%s: delay next check %is", + pp->dev_t, pp->tick); +Index: multipath-tools-130222/multipath.conf.annotated +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.annotated ++++ multipath-tools-130222/multipath.conf.annotated +@@ -242,6 +242,30 @@ + # # files, just as if it was in /etc/multipath.conf + # # values : "" or a fully qualified pathname + # # default : "/etc/multipath/conf.d" ++# ++# # ++# # name : delay_watch_checks ++# # scope : multipathd ++# # desc : If set to a value greater than 0, multipathd will watch ++# # paths that have recently become valid for this many ++# # checks. If they fail again while they are being watched, ++# # when they next become valid, they will not be used until ++# # they have stayed up for delay_wait_checks checks. ++# # values : no| > 0 ++# # default : no ++# delay_watch_checks 12 ++# ++# # ++# # name : delay_wait_checks ++# # scope : multipathd ++# # desc : If set to a value greater than 0, when a device that has ++# # recently come back online fails again within ++# # delay_watch_checks checks, the next time it comes back ++# # online, it will marked and delayed, and not used until ++# # it has passed delay_wait_checks checks. ++# # values : no| > 0 ++# # default : no ++# delay_wait_checks 12 + #} + # + ## +@@ -383,6 +407,13 @@ + # # + # flush_on_last_del yes + # ++# # ++# # name : delay_watch_checks ++# # See defualts section for information. ++# ++# # ++# # name : delay_wait_checks ++# # See defualts section for information. + # } + # multipath { + # wwid 1DEC_____321816758474 +@@ -566,6 +597,15 @@ + # # before removing it from the system. + # # values : n > 0 + # dev_loss_tmo 600 ++# ++# # ++# # name : delay_watch_checks ++# # See defaults section for information. ++# ++# # ++# # name : delay_wait_checks ++# # See defaults section for information. ++# + # } + # device { + # vendor "COMPAQ " +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -27,6 +27,8 @@ + # retain_attached_hw_handler no + # detect_prio no + # config_dir "/etc/multipath/conf.d" ++# delay_watch_checks no ++# delay_wait_checks no + #} + #blacklist { + # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -459,6 +459,25 @@ alphabetically for file ending in ".conf + information from them, just as if it was in /etc/multipath.conf. config_dir + must either be "" or a fully qualified directory name. Default is + .I "/etc/multipath/conf.d" ++.TP ++.B delay_watch_checks ++If set to a value greater than 0, multipathd will watch paths that have ++recently become valid for this many checks. If they fail again while they are ++being watched, when they next become valid, they will not be used until they ++have stayed up for ++.I delay_wait_checks ++checks. Default is ++.I no ++.TP ++.B delay_wait_checks ++If set to a value greater than 0, when a device that has recently come back ++online fails again within ++.I delay_watch_checks ++checks, the next time it comes back online, it will marked and delayed, and not ++used until it has passed ++.I delay_wait_checks ++checks. Default is ++.I no + . + .SH "blacklist section" + The +@@ -562,6 +581,10 @@ section: + .B reservation_key + .TP + .B deferred_remove ++.TP ++.B delay_watch_checks ++.TP ++.B delay_wait_checks + .RE + .PD + .LP +@@ -654,6 +677,10 @@ section: + .B detect_prio + .TP + .B deferred_remove ++.TP ++.B delay_watch_checks ++.TP ++.B delay_wait_checks + .RE + .PD + .LP +Index: multipath-tools-130222/libmultipath/checkers.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.c ++++ multipath-tools-130222/libmultipath/checkers.c +@@ -16,7 +16,8 @@ char *checker_state_names[] = { + "up", + "shaky", + "ghost", +- "pending" ++ "pending", ++ "delayed" + }; + + static LIST_HEAD(checkers); +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -341,6 +341,8 @@ merge_hwe (struct hwentry * dst, struct + merge_num(retain_hwhandler); + merge_num(detect_prio); + merge_num(deferred_remove); ++ merge_num(delay_watch_checks); ++ merge_num(delay_wait_checks); + + /* + * Make sure features is consistent with +@@ -399,6 +401,8 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(retain_hwhandler); + overwrite_num(detect_prio); + overwrite_num(deferred_remove); ++ overwrite_num(delay_watch_checks); ++ overwrite_num(delay_wait_checks); + + /* + * Make sure features is consistent with diff --git a/SOURCES/0115-RHBZ-1198418-fix-double-free.patch b/SOURCES/0115-RHBZ-1198418-fix-double-free.patch new file mode 100644 index 0000000..a403760 --- /dev/null +++ b/SOURCES/0115-RHBZ-1198418-fix-double-free.patch @@ -0,0 +1,28 @@ +--- + multipathd/main.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -310,10 +310,15 @@ ev_add_map (char * dev, char * alias, st + /* + * now we can register the map + */ +- if (map_present && (mpp = add_map_without_path(vecs, alias))) { +- sync_map_state(mpp); +- condlog(2, "%s: devmap %s registered", alias, dev); +- return 0; ++ if (map_present) { ++ if ((mpp = add_map_without_path(vecs, alias))) { ++ sync_map_state(mpp); ++ condlog(2, "%s: devmap %s registered", alias, dev); ++ return 0; ++ } else { ++ condlog(2, "%s: uev_add_map failed", dev); ++ return 1; ++ } + } + r = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec, &refwwid); + diff --git a/SOURCES/0116-UPBZ-1188179-dell-36xxi.patch b/SOURCES/0116-UPBZ-1188179-dell-36xxi.patch new file mode 100644 index 0000000..e32118b --- /dev/null +++ b/SOURCES/0116-UPBZ-1188179-dell-36xxi.patch @@ -0,0 +1,83 @@ +--- + libmultipath/hwtable.c | 30 ++++++++++++++++++++++++++++++ + multipath.conf.defaults | 26 ++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -772,6 +772,36 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_RDAC, + .prio_args = NULL, + }, ++ { ++ /* DELL MD36xxi */ ++ .vendor = "DELL", ++ .product = "MD36xxi", ++ .bl_product = "Universal Xport", ++ .features = "2 pg_init_retries 50", ++ .hwhandler = "1 rdac", ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = 15, ++ .checker_name = RDAC, ++ .prio_name = PRIO_RDAC, ++ .prio_args = NULL, ++ }, ++ { ++ /* DELL MD36xxf */ ++ .vendor = "DELL", ++ .product = "MD36xxf", ++ .bl_product = "Universal Xport", ++ .features = "2 pg_init_retries 50", ++ .hwhandler = "1 rdac", ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = 15, ++ .checker_name = RDAC, ++ .prio_name = PRIO_RDAC, ++ .prio_args = NULL, ++ }, + /* + * NETAPP controller family + * +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -655,6 +655,32 @@ + # no_path_retry 15 + # } + # device { ++# vendor "DELL" ++# product "MD36xxi" ++# product_blacklist "Universal Xport" ++# path_grouping_policy "group_by_prio" ++# path_checker "rdac" ++# features "2 pg_init_retries 50" ++# hardware_handler "1 rdac" ++# prio "rdac" ++# failback "immediate" ++# rr_weight "uniform" ++# no_path_retry 15 ++# } ++# device { ++# vendor "DELL" ++# product "MD36xxf" ++# product_blacklist "Universal Xport" ++# path_grouping_policy "group_by_prio" ++# path_checker "rdac" ++# features "2 pg_init_retries 50" ++# hardware_handler "1 rdac" ++# prio "rdac" ++# failback "immediate" ++# rr_weight "uniform" ++# no_path_retry 15 ++# } ++# device { + # vendor "NETAPP" + # product "LUN.*" + # path_grouping_policy "group_by_prio" diff --git a/SOURCES/0117-RHBZ-1198424-autodetect-clariion-alua.patch b/SOURCES/0117-RHBZ-1198424-autodetect-clariion-alua.patch new file mode 100644 index 0000000..64a302d --- /dev/null +++ b/SOURCES/0117-RHBZ-1198424-autodetect-clariion-alua.patch @@ -0,0 +1,31 @@ +--- + libmultipath/hwtable.c | 2 ++ + multipath.conf.defaults | 2 ++ + 2 files changed, 4 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -272,6 +272,8 @@ static struct hwentry default_hw[] = { + .checker_name = EMC_CLARIION, + .prio_name = PRIO_EMC, + .prio_args = NULL, ++ .retain_hwhandler = RETAIN_HWHANDLER_ON, ++ .detect_prio = DETECT_PRIO_ON, + }, + { + .vendor = "EMC", +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -261,6 +261,8 @@ + # failback immediate + # rr_weight "uniform" + # no_path_retry 60 ++# retain_attached_hw_handler yes ++# detect_prio yes + # } + # device { + # vendor "EMC" diff --git a/SOURCES/0118-UPBZ-1200738-update-eternus-config.patch b/SOURCES/0118-UPBZ-1200738-update-eternus-config.patch new file mode 100644 index 0000000..10e96e3 --- /dev/null +++ b/SOURCES/0118-UPBZ-1200738-update-eternus-config.patch @@ -0,0 +1,31 @@ +--- + libmultipath/hwtable.c | 2 +- + multipath.conf.defaults | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -310,7 +310,7 @@ static struct hwentry default_hw[] = { + }, + { + .vendor = "FUJITSU", +- .product = "ETERNUS_DX(L|400|8000)", ++ .product = "ETERNUS_DX(H|L|M|400|8000)", + .features = "1 queue_if_no_path", + .hwhandler = DEFAULT_HWHANDLER, + .pgpolicy = GROUP_BY_PRIO, +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -288,7 +288,7 @@ + # } + # device { + # vendor "FUJITSU" +-# product "ETERNUS_DX(L|400|8000)" ++# product "ETERNUS_DX(H|L|M|400|8000)" + # path_grouping_policy "group_by_prio" + # path_checker "tur" + # features "1 queue_if_no_path" diff --git a/SOURCES/0119-RHBZ-1081397-save-alua-info.patch b/SOURCES/0119-RHBZ-1081397-save-alua-info.patch new file mode 100644 index 0000000..c9913f3 --- /dev/null +++ b/SOURCES/0119-RHBZ-1081397-save-alua-info.patch @@ -0,0 +1,565 @@ +--- + libmultipath/prio.c | 34 ++++++++++++++++- + libmultipath/prio.h | 7 +++ + libmultipath/prioritizers/alua.c | 62 +++++++++++++++++++++++-------- + libmultipath/prioritizers/alua_rtpg.c | 22 +++++++++-- + libmultipath/prioritizers/alua_rtpg.h | 4 +- + libmultipath/prioritizers/const.c | 4 ++ + libmultipath/prioritizers/datacore.c | 3 + + libmultipath/prioritizers/def_func.h | 11 +++++ + libmultipath/prioritizers/emc.c | 4 ++ + libmultipath/prioritizers/hds.c | 4 ++ + libmultipath/prioritizers/hp_sw.c | 4 ++ + libmultipath/prioritizers/iet.c | 4 ++ + libmultipath/prioritizers/ontap.c | 4 ++ + libmultipath/prioritizers/random.c | 4 ++ + libmultipath/prioritizers/rdac.c | 4 ++ + libmultipath/prioritizers/weightedpath.c | 3 + + libmultipath/propsel.c | 4 +- + multipathd/main.c | 24 ++++++++---- + 18 files changed, 174 insertions(+), 32 deletions(-) + +Index: multipath-tools-130222/libmultipath/prio.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prio.c ++++ multipath-tools-130222/libmultipath/prio.c +@@ -112,9 +112,24 @@ struct prio * add_prio (char * name) + p->getprio = (int (*)(struct path *, char *)) dlsym(p->handle, "getprio"); + errstr = dlerror(); + if (errstr != NULL) +- condlog(0, "A dynamic linking error occurred: (%s)", errstr); ++ condlog(0, "A dynamic linking error occurred with getprio: (%s)", errstr); + if (!p->getprio) + goto out; ++ ++ p->initprio = (int (*)(struct prio *)) dlsym(p->handle, "initprio"); ++ errstr = dlerror(); ++ if (errstr != NULL) ++ condlog(0, "A dynamic linking error occurred with initprio: (%s)", errstr); ++ if (!p->initprio) ++ goto out; ++ ++ p->freeprio = (int (*)(struct prio *)) dlsym(p->handle, "freeprio"); ++ errstr = dlerror(); ++ if (errstr != NULL) ++ condlog(0, "A dynamic linking error occurred with freeprio: (%s)", errstr); ++ if (!p->freeprio) ++ goto out; ++ + list_add(&p->node, &prioritizers); + return p; + out: +@@ -122,6 +137,13 @@ out: + return NULL; + } + ++int prio_init (struct prio * p) ++{ ++ if (!p || !p->initprio) ++ return 1; ++ return p->initprio(p); ++} ++ + int prio_getprio (struct prio * p, struct path * pp) + { + return p->getprio(pp, p->args); +@@ -156,8 +178,16 @@ void prio_get (struct prio * dst, char * + strncpy(dst->name, src->name, PRIO_NAME_LEN); + if (args) + strncpy(dst->args, args, PRIO_ARGS_LEN); ++ dst->initprio = src->initprio; + dst->getprio = src->getprio; ++ dst->freeprio = src->freeprio; + dst->handle = NULL; ++ dst->context = NULL; ++ ++ if (dst->initprio(dst) != 0){ ++ memset(dst, 0x0, sizeof(struct prio)); ++ return; ++ } + + src->refcount++; + } +@@ -173,6 +203,8 @@ void prio_put (struct prio * dst) + src = NULL; + else + src = prio_lookup(dst->name); ++ if (dst->freeprio) ++ dst->freeprio(dst); + memset(dst, 0x0, sizeof(struct prio)); + free_prio(src); + } +Index: multipath-tools-130222/libmultipath/prio.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prio.h ++++ multipath-tools-130222/libmultipath/prio.h +@@ -46,9 +46,15 @@ struct prio { + void *handle; + int refcount; + struct list_head node; ++ void * context; + char name[PRIO_NAME_LEN]; + char args[PRIO_ARGS_LEN]; ++ int (*initprio)(struct prio * p); ++ /* You are allowed to call initprio multiple times without calling ++ * freeprio. Doing so will reinitialize it (possibly skipping ++ * allocations) */ + int (*getprio)(struct path *, char *); ++ int (*freeprio)(struct prio * p); + }; + + unsigned int get_prio_timeout(unsigned int default_timeout); +@@ -57,6 +63,7 @@ void cleanup_prio (void); + struct prio * add_prio (char *); + struct prio * prio_lookup (char *); + int prio_getprio (struct prio *, struct path *); ++int prio_init (struct prio *); + void prio_get (struct prio *, char *, char *); + void prio_put (struct prio *); + int prio_selected (struct prio *); +Index: multipath-tools-130222/libmultipath/prioritizers/alua.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua.c ++++ multipath-tools-130222/libmultipath/prioritizers/alua.c +@@ -37,6 +37,12 @@ static const char * aas_string[] = { + [AAS_TRANSITIONING] = "transitioning between states", + }; + ++struct alua_context { ++ int tpg_support; ++ int tpg; ++ int buflen; ++}; ++ + static const char *aas_print_string(int rc) + { + rc &= 0x7f; +@@ -51,25 +57,26 @@ static const char *aas_print_string(int + } + + int +-get_alua_info(int fd) ++get_alua_info(int fd, struct alua_context *ct) + { + int rc; +- int tpg; + int aas; + +- rc = get_target_port_group_support(fd); +- if (rc < 0) +- return -ALUA_PRIO_TPGS_FAILED; +- +- if (rc == TPGS_NONE) +- return -ALUA_PRIO_NOT_SUPPORTED; +- +- tpg = get_target_port_group(fd); +- if (tpg < 0) +- return -ALUA_PRIO_RTPG_FAILED; ++ if (ct->tpg_support <= 0 || ct->tpg < 0) { ++ ct->tpg_support = get_target_port_group_support(fd); ++ if (ct->tpg_support < 0) ++ return -ALUA_PRIO_TPGS_FAILED; ++ ++ if (ct->tpg_support == TPGS_NONE) ++ return -ALUA_PRIO_NOT_SUPPORTED; ++ ++ ct->tpg = get_target_port_group(fd, &ct->buflen); ++ if (ct->tpg < 0) ++ return -ALUA_PRIO_RTPG_FAILED; ++ } + +- condlog(3, "reported target port group is %i", tpg); +- rc = get_asymmetric_access_state(fd, tpg); ++ condlog(3, "reported target port group is %i", ct->tpg); ++ rc = get_asymmetric_access_state(fd, ct->tpg, &ct->buflen); + if (rc < 0) + return -ALUA_PRIO_GETAAS_FAILED; + aas = (rc & 0x0f); +@@ -88,7 +95,7 @@ int getprio (struct path * pp, char * ar + if (pp->fd < 0) + return -ALUA_PRIO_NO_INFORMATION; + +- rc = get_alua_info(pp->fd); ++ rc = get_alua_info(pp->fd, pp->prio.context); + if (rc >= 0) { + aas = (rc & 0x0f); + priopath = (rc & 0x80); +@@ -128,3 +135,28 @@ int getprio (struct path * pp, char * ar + } + return rc; + } ++ ++int initprio(struct prio *p) ++{ ++ if (!p->context) { ++ struct alua_context *ct; ++ ++ ct = malloc(sizeof(struct alua_context)); ++ if (!ct) ++ return 1; ++ p->context = ct; ++ } ++ memset(p->context, 0, sizeof(struct alua_context)); ++ return 0; ++} ++ ++ ++int freeprio(struct prio *p) ++{ ++ if (p->context) { ++ free(p->context); ++ p->context = NULL; ++ } ++ return 0; ++} ++ +Index: multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua_rtpg.c ++++ multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.c +@@ -171,7 +171,7 @@ get_target_port_group_support(int fd) + } + + int +-get_target_port_group(int fd) ++get_target_port_group(int fd, int *buflen_ptr) + { + unsigned char *buf; + struct vpd83_data * vpd83; +@@ -179,7 +179,12 @@ get_target_port_group(int fd) + int rc; + int buflen, scsi_buflen; + +- buflen = 128; /* Lets start from 128 */ ++ if (!buflen_ptr || *buflen_ptr == 0) { ++ buflen = 128; /* Lets start from 128 */ ++ if (buflen_ptr) ++ *buflen_ptr = 128; ++ } else ++ buflen = *buflen_ptr; + buf = (unsigned char *)malloc(buflen); + if (!buf) { + PRINT_DEBUG("malloc failed: could not allocate" +@@ -202,6 +207,8 @@ get_target_port_group(int fd) + return -RTPG_RTPG_FAILED; + } + buflen = scsi_buflen; ++ if (buflen_ptr) ++ *buflen_ptr = buflen; + memset(buf, 0, buflen); + rc = do_inquiry(fd, 1, 0x83, buf, buflen); + if (rc < 0) +@@ -269,7 +276,7 @@ do_rtpg(int fd, void* resp, long resplen + } + + int +-get_asymmetric_access_state(int fd, unsigned int tpg) ++get_asymmetric_access_state(int fd, unsigned int tpg, int *buflen_ptr) + { + unsigned char *buf; + struct rtpg_data * tpgd; +@@ -278,7 +285,12 @@ get_asymmetric_access_state(int fd, unsi + int buflen; + uint32_t scsi_buflen; + +- buflen = 128; /* Initial value from old code */ ++ if (!buflen_ptr || *buflen_ptr == 0) { ++ buflen = 128; /* Initial value from old code */ ++ if (buflen_ptr) ++ *buflen_ptr = 128; ++ } else ++ buflen = *buflen_ptr; + buf = (unsigned char *)malloc(buflen); + if (!buf) { + PRINT_DEBUG ("malloc failed: could not allocate" +@@ -299,6 +311,8 @@ get_asymmetric_access_state(int fd, unsi + return -RTPG_RTPG_FAILED; + } + buflen = scsi_buflen; ++ if (buflen_ptr) ++ *buflen_ptr = buflen; + memset(buf, 0, buflen); + rc = do_rtpg(fd, buf, buflen); + if (rc < 0) +Index: multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua_rtpg.h ++++ multipath-tools-130222/libmultipath/prioritizers/alua_rtpg.h +@@ -23,8 +23,8 @@ + #define RTPG_TPG_NOT_FOUND 4 + + int get_target_port_group_support(int fd); +-int get_target_port_group(int fd); +-int get_asymmetric_access_state(int fd, unsigned int tpg); ++int get_target_port_group(int fd, int *buflen_ptr); ++int get_asymmetric_access_state(int fd, unsigned int tpg, int *buflen_ptr); + + #endif /* __RTPG_H__ */ + +Index: multipath-tools-130222/libmultipath/prioritizers/const.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/const.c ++++ multipath-tools-130222/libmultipath/prioritizers/const.c +@@ -1,8 +1,12 @@ + #include + + #include ++#include "def_func.h" + + int getprio (struct path * pp, char * args) + { + return 1; + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/datacore.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/datacore.c ++++ multipath-tools-130222/libmultipath/prioritizers/datacore.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include "def_func.h" + + #define INQ_REPLY_LEN 255 + #define INQ_CMD_CODE 0x12 +@@ -111,3 +112,5 @@ int getprio (struct path * pp, char * ar + return datacore_prio(pp->dev, pp->fd, args); + } + ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/def_func.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/prioritizers/def_func.h +@@ -0,0 +1,11 @@ ++#ifndef _DEF_FUNC_H ++#define _DEF_FUNC_H ++ ++#include "prio.h" ++ ++#define declare_nop_prio(name) \ ++int name (struct prio *p) \ ++{ \ ++ return 0; \ ++} ++#endif /* _DEF_FUNC_H */ +Index: multipath-tools-130222/libmultipath/prioritizers/emc.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/emc.c ++++ multipath-tools-130222/libmultipath/prioritizers/emc.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include "def_func.h" + + #define INQUIRY_CMD 0x12 + #define INQUIRY_CMDLEN 6 +@@ -85,3 +86,6 @@ int getprio (struct path * pp, char * ar + { + return emc_clariion_prio(pp->dev, pp->fd); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/hds.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/hds.c ++++ multipath-tools-130222/libmultipath/prioritizers/hds.c +@@ -76,6 +76,7 @@ + #include + #include + #include ++#include "def_func.h" + + #define INQ_REPLY_LEN 255 + #define INQ_CMD_CODE 0x12 +@@ -170,3 +171,6 @@ int getprio (struct path * pp, char * ar + { + return hds_modular_prio(pp->dev, pp->fd); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/hp_sw.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/hp_sw.c ++++ multipath-tools-130222/libmultipath/prioritizers/hp_sw.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include "def_func.h" + + #define TUR_CMD_LEN 6 + #define SCSI_CHECK_CONDITION 0x2 +@@ -99,3 +100,6 @@ int getprio (struct path * pp, char * ar + { + return hp_sw_prio(pp->dev, pp->fd); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/iet.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/iet.c ++++ multipath-tools-130222/libmultipath/prioritizers/iet.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include "def_func.h" + + // + // This prioritizer suits iSCSI needs, makes it possible to prefer one path. +@@ -141,3 +142,6 @@ int getprio(struct path * pp, char * arg + { + return iet_prio(pp->dev, args); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/ontap.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/ontap.c ++++ multipath-tools-130222/libmultipath/prioritizers/ontap.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include "def_func.h" + + #define INQUIRY_CMD 0x12 + #define INQUIRY_CMDLEN 6 +@@ -245,3 +246,6 @@ int getprio (struct path * pp, char * ar + { + return ontap_prio(pp->dev, pp->fd); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/random.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/random.c ++++ multipath-tools-130222/libmultipath/prioritizers/random.c +@@ -4,6 +4,7 @@ + #include + + #include ++#include "def_func.h" + + int getprio (struct path * pp, char * args) + { +@@ -13,3 +14,6 @@ int getprio (struct path * pp, char * ar + srand((unsigned int)tv.tv_usec); + return 1+(int) (10.0*rand()/(RAND_MAX+1.0)); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/rdac.c ++++ multipath-tools-130222/libmultipath/prioritizers/rdac.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include "def_func.h" + + #define INQUIRY_CMD 0x12 + #define INQUIRY_CMDLEN 6 +@@ -95,3 +96,6 @@ int getprio (struct path * pp, char * ar + { + return rdac_prio(pp->dev, pp->fd); + } ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/prioritizers/weightedpath.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/weightedpath.c ++++ multipath-tools-130222/libmultipath/prioritizers/weightedpath.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include "def_func.h" + + char *get_next_string(char **temp, char *split_char) + { +@@ -104,3 +105,5 @@ int getprio(struct path *pp, char *args) + return prio_path_weight(pp, args); + } + ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -401,10 +401,10 @@ detect_prio(struct path * pp) + + if (get_target_port_group_support(pp->fd) <= 0) + return; +- ret = get_target_port_group(pp->fd); ++ ret = get_target_port_group(pp->fd, NULL); + if (ret < 0) + return; +- if (get_asymmetric_access_state(pp->fd, ret) < 0) ++ if (get_asymmetric_access_state(pp->fd, ret, NULL) < 0) + return; + prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS); + } +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -700,20 +700,23 @@ static int + uev_update_path (struct uevent *uev, struct vectors * vecs) + { + int ro, retval = 0; ++ struct path * pp; ++ ++ pp = find_path_by_dev(vecs->pathvec, uev->kernel); ++ if (!pp) { ++ condlog(0, "%s: spurious uevent, path not found", ++ uev->kernel); ++ return 1; ++ } ++ /* reinit the prio values on change event, in case something is ++ * different */ ++ prio_init(&pp->prio); + + ro = uevent_get_disk_ro(uev); + + if (ro >= 0) { +- struct path * pp; +- + condlog(2, "%s: update path write_protect to '%d' (uevent)", + uev->kernel, ro); +- pp = find_path_by_dev(vecs->pathvec, uev->kernel); +- if (!pp) { +- condlog(0, "%s: spurious uevent, path not found", +- uev->kernel); +- return 1; +- } + if (pp->mpp) { + retval = reload_map(vecs, pp->mpp, 0); + +@@ -1218,6 +1221,11 @@ check_path (struct vectors * vecs, struc + } + + if(newstate == PATH_UP || newstate == PATH_GHOST){ ++ /* ++ * Reinitialize the prioritizer, in case something ++ * changed. ++ */ ++ prio_init(&pp->prio); + if ( pp->mpp && pp->mpp->prflag ){ + /* + * Check Persistent Reservation. diff --git a/SOURCES/0120-RHBZ-1043093-realloc-fix.patch b/SOURCES/0120-RHBZ-1043093-realloc-fix.patch new file mode 100644 index 0000000..96b812a --- /dev/null +++ b/SOURCES/0120-RHBZ-1043093-realloc-fix.patch @@ -0,0 +1,195 @@ +--- + libmultipath/dmparser.c | 6 ++++-- + libmultipath/regex.c | 9 ++++++++- + multipath/main.c | 9 ++++++--- + multipathd/cli_handlers.c | 41 ++++++++++++----------------------------- + multipathd/uxlsnr.c | 13 ++++++++++++- + 5 files changed, 42 insertions(+), 36 deletions(-) + +Index: multipath-tools-130222/libmultipath/dmparser.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dmparser.c ++++ multipath-tools-130222/libmultipath/dmparser.c +@@ -20,14 +20,16 @@ + static int + merge_words (char ** dst, char * word, int space) + { +- char * p; ++ char * p = *dst; + int len; + + len = strlen(*dst) + strlen(word) + space; + *dst = REALLOC(*dst, len + 1); + +- if (!*dst) ++ if (!*dst) { ++ free(p); + return 1; ++ } + + p = *dst; + +Index: multipath-tools-130222/libmultipath/regex.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/regex.c ++++ multipath-tools-130222/libmultipath/regex.c +@@ -123,7 +123,14 @@ static void init_syntax_once(void) + + /* (Re)Allocate N items of type T using malloc, or fail. */ + #define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +-#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) ++#define RETALLOC(addr, n, t) \ ++do { \ ++ t *tmp = (t *) realloc (addr, (n) * sizeof (t)); \ ++ if (!tmp) \ ++ free(addr); \ ++ (addr) = tmp; \ ++} while(0) ++ + #define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + + #define BYTEWIDTH 8 /* In bits. */ +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -394,7 +394,7 @@ out: + static int + dump_config (void) + { +- char * c; ++ char * c, * tmp = NULL; + char * reply; + unsigned int maxlen = 256; + int again = 1; +@@ -402,9 +402,12 @@ dump_config (void) + reply = MALLOC(maxlen); + + while (again) { +- if (!reply) ++ if (!reply) { ++ if (tmp) ++ free(tmp); + return 1; +- c = reply; ++ } ++ c = tmp = reply; + c += snprint_defaults(c, reply + maxlen - c); + again = ((c - reply) == maxlen); + if (again) { +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -26,11 +26,14 @@ + #define REALLOC_REPLY(r, a, m) \ + do { \ + if ((a)) { \ ++ char *tmp = (r); \ + (r) = REALLOC((r), (m) * 2); \ + if ((r)) { \ + memset((r) + (m), 0, (m)); \ + (m) *= 2; \ + } \ ++ else \ ++ free(tmp); \ + } \ + } while (0) + +@@ -144,7 +147,7 @@ show_config (char ** r, int * len) + unsigned int maxlen = INITIAL_REPLY_LEN; + int again = 1; + +- reply = MALLOC(maxlen); ++ c = reply = MALLOC(maxlen); + + while (again) { + if (!reply) +@@ -152,44 +155,24 @@ show_config (char ** r, int * len) + c = reply; + c += snprint_defaults(c, reply + maxlen - c); + again = ((c - reply) == maxlen); +- if (again) { +- reply = REALLOC(reply, maxlen * 2); +- if (!reply) +- return 1; +- memset(reply + maxlen, 0, maxlen); +- maxlen *= 2; ++ REALLOC_REPLY(reply, again, maxlen); ++ if (again) + continue; +- } + c += snprint_blacklist(c, reply + maxlen - c); + again = ((c - reply) == maxlen); +- if (again) { +- reply = REALLOC(reply, maxlen * 2); +- if (!reply) +- return 1; +- memset(reply + maxlen, 0, maxlen); +- maxlen *= 2; ++ REALLOC_REPLY(reply, again, maxlen); ++ if (again) + continue; +- } + c += snprint_blacklist_except(c, reply + maxlen - c); + again = ((c - reply) == maxlen); +- if (again) { +- reply = REALLOC(reply, maxlen * 2); +- if (!reply) +- return 1; +- memset(reply + maxlen, 0, maxlen); +- maxlen *= 2; ++ REALLOC_REPLY(reply, again, maxlen); ++ if (again) + continue; +- } + c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable); + again = ((c - reply) == maxlen); +- if (again) { +- reply = REALLOC(reply, maxlen * 2); +- if (!reply) +- return 1; +- memset(reply + maxlen, 0, maxlen); +- maxlen *= 2; ++ REALLOC_REPLY(reply, again, maxlen); ++ if (again) + continue; +- } + c += snprint_mptable(c, reply + maxlen - c, conf->mptable); + again = ((c - reply) == maxlen); + REALLOC_REPLY(reply, again, maxlen); +Index: multipath-tools-130222/multipathd/uxlsnr.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxlsnr.c ++++ multipath-tools-130222/multipathd/uxlsnr.c +@@ -64,6 +64,10 @@ static void new_client(int ux_sock) + + /* put it in our linked list */ + c = (struct client *)MALLOC(sizeof(*c)); ++ if (!c) { ++ close(fd); ++ return; ++ } + memset(c, 0, sizeof(*c)); + c->fd = fd; + c->next = clients; +@@ -124,11 +128,18 @@ void * uxsock_listen(int (*uxsock_trigge + sigdelset(&mask, SIGHUP); + sigdelset(&mask, SIGUSR1); + while (1) { ++ struct pollfd *tmp; + struct client *c; + int i, poll_count; + + /* setup for a poll */ +- polls = REALLOC(polls, (1+num_clients) * sizeof(*polls)); ++ tmp = REALLOC(polls, (1+num_clients) * sizeof(*polls)); ++ /* If we can't allocate poliing space for the new client, ++ * close it */ ++ if (!tmp) ++ dead_client(clients); ++ else ++ polls = tmp; + polls[0].fd = ux_sock; + polls[0].events = POLLIN; + diff --git a/SOURCES/0121-RHBZ-1197234-rules-fix.patch b/SOURCES/0121-RHBZ-1197234-rules-fix.patch new file mode 100644 index 0000000..41d672b --- /dev/null +++ b/SOURCES/0121-RHBZ-1197234-rules-fix.patch @@ -0,0 +1,28 @@ +--- + multipath/multipath.rules | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -21,6 +21,7 @@ ACTION!="change", GOTO="update_timestamp + IMPORT{db}="DM_MULTIPATH_TIMESTAMP" + IMPORT{db}="DM_MULTIPATH_DEVICE_PATH" + IMPORT{db}="DM_MULTIPATH_WIPE_PARTS" ++IMPORT{db}="DM_MULTIPATH_NEED_KPARTX" + # Check if the device is part of a multipath device. the -T option just keeps + # the old result if the timestamp hasn't changed. + PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -T $env{DM_MULTIPATH_TIMESTAMP}:$env{DM_MULTIPATH_DEVICE_PATH} -c $env{DEVNAME}", \ +@@ -43,7 +44,10 @@ KERNEL!="dm-*", GOTO="end_mpath" + ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10" + ACTION!="change", GOTO="end_mpath" + ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" ++ENV{DM_ACTIVATION}=="1", ENV{DM_MULTIPATH_NEED_KPARTX}="1" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" +-ENV{DM_ACTIVATION}=="1", RUN+="$env{MPATH_SBIN_PATH}/kpartx -u $tempnode" ++ENV{DM_ACTIVATION}!="1", ENV{DM_MULTIPATH_NEED_KPARTX}!="1", GOTO="end_mpath" ++RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode", \ ++ ENV{DM_MULTIPATH_NEED_KPARTX}="" + LABEL="end_mpath" diff --git a/SOURCES/0122-RHBZ-1212590-dont-use-var.patch b/SOURCES/0122-RHBZ-1212590-dont-use-var.patch new file mode 100644 index 0000000..52d743a --- /dev/null +++ b/SOURCES/0122-RHBZ-1212590-dont-use-var.patch @@ -0,0 +1,33 @@ +--- + libmultipath/defaults.h | 4 ++-- + multipathd/multipathd.service | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -26,8 +26,8 @@ + #define MAX_CHECKINT(a) (a << 2) + + #define MAX_DEV_LOSS_TMO 0x7FFFFFFF +-#define DEFAULT_PIDFILE "/var/run/multipathd/multipathd.pid" +-#define DEFAULT_TIMESTAMP_FILE "/var/run/multipathd/timestamp" ++#define DEFAULT_PIDFILE "/run/multipathd/multipathd.pid" ++#define DEFAULT_TIMESTAMP_FILE "/run/multipathd/timestamp" + #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" + #define DEFAULT_CONFIGFILE "/etc/multipath.conf" + #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -9,7 +9,7 @@ Conflicts=shutdown.target + + [Service] + Type=forking +-PIDFile=/var/run/multipathd/multipathd.pid ++PIDFile=/run/multipathd/multipathd.pid + ExecStartPre=/sbin/modprobe dm-multipath + ExecStartPre=-/sbin/multipath -A + ExecStart=/sbin/multipathd diff --git a/SOURCES/0123-UPBZ-1166072-fix-path-offline.patch b/SOURCES/0123-UPBZ-1166072-fix-path-offline.patch new file mode 100644 index 0000000..0f1a912 --- /dev/null +++ b/SOURCES/0123-UPBZ-1166072-fix-path-offline.patch @@ -0,0 +1,19 @@ +--- + libmultipath/discovery.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -946,9 +946,7 @@ path_offline (struct path * pp) + + condlog(3, "%s: path state = %s", pp->dev, buff); + +- if (!strncmp(buff, "offline", 7) || +- !strncmp(buff, "quiesce", 7) || +- !strncmp(buff, "transport-offline", 17)) { ++ if (!strncmp(buff, "offline", 7)) { + pp->offline = 1; + return PATH_DOWN; + } diff --git a/SOURCES/0124-RHBZ-1209275-retrigger-uevents.patch b/SOURCES/0124-RHBZ-1209275-retrigger-uevents.patch new file mode 100644 index 0000000..e0b1886 --- /dev/null +++ b/SOURCES/0124-RHBZ-1209275-retrigger-uevents.patch @@ -0,0 +1,214 @@ +--- + libmultipath/config.c | 2 ++ + libmultipath/config.h | 2 ++ + libmultipath/defaults.h | 2 ++ + libmultipath/dict.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/discovery.c | 8 +++++--- + libmultipath/structs.h | 8 ++++++++ + multipathd/main.c | 15 ++++++++++++++- + 7 files changed, 79 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -673,6 +673,8 @@ load_config (char * file, struct udev *u + conf->force_sync = 0; + conf->ignore_new_boot_devs = 0; + conf->processed_main_config = 0; ++ conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES; ++ conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -139,6 +139,8 @@ struct config { + int processed_main_config; + int delay_watch_checks; + int delay_wait_checks; ++ int retrigger_tries; ++ int retrigger_delay; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -21,6 +21,8 @@ + #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF + #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF + #define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF ++#define DEFAULT_RETRIGGER_DELAY 10 ++#define DEFAULT_RETRIGGER_TRIES 3 + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -839,6 +839,38 @@ def_delay_wait_checks_handler(vector str + return 0; + } + ++static int ++def_retrigger_tries_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ conf->retrigger_tries = atoi(buff); ++ FREE(buff); ++ ++ return 0; ++} ++ ++static int ++def_retrigger_delay_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ conf->retrigger_delay = atoi(buff); ++ FREE(buff); ++ ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -3194,6 +3226,18 @@ snprint_def_delay_wait_checks(char * buf + } + + static int ++snprint_def_retrigger_tries (char * buff, int len, void * data) ++{ ++ return snprintf(buff, len, "%i", conf->retrigger_tries); ++} ++ ++static int ++snprint_def_retrigger_delay (char * buff, int len, void * data) ++{ ++ return snprintf(buff, len, "%i", conf->retrigger_delay); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3267,6 +3311,8 @@ init_keywords(void) + install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir); + install_keyword("delay_watch_checks", &def_delay_watch_checks_handler, &snprint_def_delay_watch_checks); + install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks); ++ install_keyword("retrigger_tries", &def_retrigger_tries_handler, &snprint_def_retrigger_tries); ++ install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1111,9 +1111,13 @@ get_uid (struct path * pp) + len = strlen(value); + } + strncpy(pp->wwid, value, len); ++ pp->missing_udev_info = INFO_OK; ++ pp->tick = 0; + } else { + condlog(3, "%s: no %s attribute", pp->dev, + pp->uid_attribute); ++ pp->missing_udev_info = INFO_MISSING; ++ pp->tick = conf->retrigger_delay; + } + + /* Strip any trailing blanks */ +@@ -1201,10 +1205,8 @@ pathinfo (struct path *pp, vector hwtabl + * Retrieve path priority, even for PATH_DOWN paths if it has never + * been successfully obtained before. + */ +- if ((mask & DI_PRIO) && path_state == PATH_UP) { ++ if ((mask & DI_PRIO) && path_state == PATH_UP && strlen(pp->wwid)) { + if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) { +- if (!strlen(pp->wwid)) +- get_uid(pp); + get_prio(pp); + } + } +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -139,6 +139,12 @@ enum delay_checks_states { + DELAY_CHECKS_UNDEF = 0, + }; + ++enum missing_udev_info_states { ++ INFO_OK, ++ INFO_MISSING, ++ INFO_REQUESTED, ++}; ++ + struct sg_id { + int host_no; + int channel; +@@ -193,6 +199,8 @@ struct path { + struct checker checker; + struct multipath * mpp; + int fd; ++ int missing_udev_info; ++ int retriggers; + + /* configlet pointers */ + struct hwentry * hwe; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -708,6 +708,10 @@ uev_update_path (struct uevent *uev, str + uev->kernel); + return 1; + } ++ ++ if (pp->missing_udev_info == INFO_REQUESTED) ++ return uev_add_path(uev, vecs); ++ + /* reinit the prio values on change event, in case something is + * different */ + prio_init(&pp->prio); +@@ -1133,12 +1137,21 @@ check_path (struct vectors * vecs, struc + int chkr_new_path_up = 0; + int oldchkrstate = pp->chkrstate; + +- if (!pp->mpp) ++ if (!pp->mpp && (pp->missing_udev_info != INFO_MISSING || ++ pp->retriggers >= conf->retrigger_tries)) + return; + + if (pp->tick && --pp->tick) + return; /* don't check this path yet */ + ++ if (!pp->mpp) { ++ pp->missing_udev_info = INFO_REQUESTED; ++ pp->retriggers++; ++ sysfs_attr_set_value(pp->udev, "uevent", "change", ++ strlen("change")); ++ return; ++ } ++ + /* + * provision a next check soonest, + * in case we exit abnormaly from here diff --git a/SOURCES/0125-RHBZ-1153832-kpartx-delete.patch b/SOURCES/0125-RHBZ-1153832-kpartx-delete.patch new file mode 100644 index 0000000..329bc44 --- /dev/null +++ b/SOURCES/0125-RHBZ-1153832-kpartx-delete.patch @@ -0,0 +1,26 @@ +--- + kpartx/kpartx.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -409,7 +409,7 @@ main(int argc, char **argv){ + break; + + case DELETE: +- for (j = n-1; j >= 0; j--) { ++ for (j = MAXSLICES-1; j >= 0; j--) { + if (safe_sprintf(partname, "%s%s%d", + mapname, delim, j+1)) { + fprintf(stderr, "partname too small\n"); +@@ -417,7 +417,7 @@ main(int argc, char **argv){ + } + strip_slash(partname); + +- if (!slices[j].size || !dm_map_present(partname)) ++ if (!dm_map_present(partname)) + continue; + + if (!dm_simplecmd(DM_DEVICE_REMOVE, partname, diff --git a/SOURCES/0126-RHBZ-1211383-alias-collision.patch b/SOURCES/0126-RHBZ-1211383-alias-collision.patch new file mode 100644 index 0000000..965bf53 --- /dev/null +++ b/SOURCES/0126-RHBZ-1211383-alias-collision.patch @@ -0,0 +1,113 @@ +--- + libmultipath/config.c | 4 ++++ + libmultipath/config.h | 1 + + libmultipath/configure.c | 3 +++ + libmultipath/dict.c | 33 +++++++++++++++++++++++++++++++++ + 4 files changed, 41 insertions(+) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -422,6 +422,9 @@ select_action (struct multipath * mpp, v + condlog(2, "%s: unable to rename %s to %s (%s is used by %s)", + mpp->wwid, cmpp->alias, mpp->alias, + mpp->alias, cmpp_by_name->wwid); ++ /* reset alias to existing alias */ ++ FREE(mpp->alias); ++ mpp->alias = STRDUP(cmpp->alias); + mpp->action = ACT_NOTHING; + return; + } +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -675,6 +675,7 @@ load_config (char * file, struct udev *u + conf->processed_main_config = 0; + conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES; + conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY; ++ conf->new_bindings_in_boot = 0; + + /* + * preload default hwtable +@@ -794,6 +795,9 @@ load_config (char * file, struct udev *u + if (conf->ignore_new_boot_devs) + in_initrd(); + ++ if (conf->new_bindings_in_boot == 0 && in_initrd()) ++ conf->bindings_read_only = 1; ++ + return 0; + out: + free_config(conf); +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -141,6 +141,7 @@ struct config { + int delay_wait_checks; + int retrigger_tries; + int retrigger_delay; ++ int new_bindings_in_boot; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -871,6 +871,29 @@ def_retrigger_delay_handler(vector strve + return 0; + } + ++static int ++def_new_bindings_in_boot_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->new_bindings_in_boot = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->new_bindings_in_boot = 1; ++ else ++ conf->new_bindings_in_boot = 0; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -3238,6 +3261,15 @@ snprint_def_retrigger_delay (char * buff + } + + static int ++snprint_def_new_bindings_in_boot(char * buff, int len, void * data) ++{ ++ if (conf->new_bindings_in_boot == 1) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3313,6 +3345,7 @@ init_keywords(void) + install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks); + install_keyword("retrigger_tries", &def_retrigger_tries_handler, &snprint_def_retrigger_tries); + install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay); ++ install_keyword("new_bindings_in_boot", &def_new_bindings_in_boot_handler, &snprint_def_new_bindings_in_boot); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); diff --git a/SOURCES/0127-RHBZ-1201030-use-blk-availability.patch b/SOURCES/0127-RHBZ-1201030-use-blk-availability.patch new file mode 100644 index 0000000..b2cd7cf --- /dev/null +++ b/SOURCES/0127-RHBZ-1201030-use-blk-availability.patch @@ -0,0 +1,15 @@ +--- + multipathd/multipathd.service | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -1,5 +1,6 @@ + [Unit] + Description=Device-Mapper Multipath Device Controller ++Requires=blk-availability.service + Before=iscsi.service iscsid.service lvm2-activation-early.service + After=syslog.target + ConditionPathExists=/etc/multipath.conf diff --git a/SOURCES/0128-RHBZ-1222123-mpathconf-allow.patch b/SOURCES/0128-RHBZ-1222123-mpathconf-allow.patch new file mode 100644 index 0000000..a48d8ae --- /dev/null +++ b/SOURCES/0128-RHBZ-1222123-mpathconf-allow.patch @@ -0,0 +1,240 @@ +--- + multipath/mpathconf | 135 +++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 124 insertions(+), 11 deletions(-) + +Index: multipath-tools-130222/multipath/mpathconf +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf ++++ multipath-tools-130222/multipath/mpathconf +@@ -1,4 +1,4 @@ +-#!/bin/sh ++#!/bin/bash + # + # Copyright (C) 2010 Red Hat, Inc. All rights reserved. + # +@@ -17,12 +17,14 @@ + # This program was largely ripped off from lvmconf + # + +-unset ENABLE FIND FRIENDLY MODULE MULTIPATHD HAVE_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_DEFAULTS HAVE_FRIENDLY HAVE_MULTIPATHD HAVE_MODULE SHOW_STATUS CHANGED_CONFIG ++unset ENABLE FIND FRIENDLY MODULE MULTIPATHD HAVE_DISABLE HAVE_WWID_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_EXCEPTIONS HAVE_DEFAULTS HAVE_FRIENDLY HAVE_MULTIPATHD HAVE_MODULE HAVE_OUTFILE SHOW_STATUS CHANGED_CONFIG WWID_LIST + + DEFAULT_CONFIGFILE="/usr/share/doc/device-mapper-multipath-0.4.9/multipath.conf" + CONFIGFILE="/etc/multipath.conf" ++OUTPUTFILE="/etc/multipath.conf" + MULTIPATHDIR="/etc/multipath" + TMPFILE=/etc/multipath/.multipath.conf.tmp ++WWIDS=0 + + function usage + { +@@ -31,13 +33,60 @@ function usage + echo "Commands:" + echo "Enable: --enable " + echo "Disable: --disable" ++ echo "Only allow certain wwids (instead of enable): --allow " + echo "Set user_friendly_names (Default y): --user_friendly_names " + echo "Set find_multipaths (Default y): --find_multipaths " + echo "Load the dm-multipath modules on enable (Default y): --with_module " + echo "start/stop/reload multipathd (Default n): --with_multipathd " ++ echo "select output file (Default /etc/multipath.conf): --outfile " + echo "" + } + ++function get_dm_deps ++{ ++ shift 3 ++ while [ -n "$1" -a -n "$2" ]; do ++ MAJOR=$(echo $1 | tr -d '(,') ++ MINOR=$(echo $2 | tr -d ')') ++ UUID=`dmsetup info -c --noheadings -o uuid -j $MAJOR -m $MINOR 2> /dev/null` ++ if [ -n "$UUID" ] ; then ++ set_dm_wwid $UUID ++ fi ++ shift 2 ++ done ++} ++ ++function set_dm_wwid ++{ ++ if [[ "$1" =~ ^part[[:digit:]]+-mpath- ]] ; then ++ WWID_LIST[$WWIDS]="${1##part*-mpath-}" ++ ((WWIDS++)) ++ elif [[ "$1" =~ ^mpath- ]] ; then ++ WWID_LIST[$WWIDS]="${1##mpath-}" ++ ((WWIDS++)) ++ else ++ get_dm_deps `dmsetup deps -u $1` ++ fi ++} ++ ++function set_wwid ++{ ++ UUID="" ++ if [[ "$1" =~ ^[[:digit:]]+:[[:digit:]]+$ ]] ; then ++ MAJOR=${1%%:*} ++ MINOR=${1##*:} ++ UUID=`dmsetup info -c --noheadings -o uuid -j $MAJOR -m $MINOR 2> /dev/null` ++ else ++ UUID=`dmsetup info -c --noheadings -o uuid $1 2> /dev/null` ++ fi ++ if [ -n "$UUID" ] ; then ++ set_dm_wwid $UUID ++ else ++ WWID_LIST[$WWIDS]="$1" ++ ((WWIDS++)) ++ fi ++} ++ + function parse_args + { + while [ -n "$1" ]; do +@@ -50,6 +99,16 @@ function parse_args + ENABLE=0 + shift + ;; ++ --allow) ++ ENABLE=2 ++ if [ -n "$2" ]; then ++ set_wwid $2 ++ shift 2 ++ else ++ usage ++ exit 1 ++ fi ++ ;; + --user_friendly_names) + if [ -n "$2" ]; then + FRIENDLY=$2 +@@ -86,6 +145,16 @@ function parse_args + exit 1 + fi + ;; ++ --outfile) ++ if [ -n "$2" ]; then ++ OUTPUTFILE=$2 ++ HAVE_OUTFILE=1 ++ shift 2 ++ else ++ usage ++ exit 1 ++ fi ++ ;; + *) + usage + exit +@@ -120,6 +189,22 @@ function validate_args + echo "--with_multipathd must be either 'y' or 'n'" + exit 1 + fi ++ if [ "$ENABLE" = 2 -a -z "$HAVE_OUTFILE" ]; then ++ echo "Because --allow makes changes that cannot be automatically reversed," ++ echo "you must set --outfile when you set --allow" ++ exit 1 ++ fi ++} ++ ++function add_blacklist_exceptions ++{ ++ echo "blacklist_exceptions {" >> $TMPFILE ++ INDEX=0 ++ while [ "$INDEX" -lt "$WWIDS" ] ; do ++ echo " wwid \"${WWID_LIST[$INDEX]}\"" >> $TMPFILE ++ ((INDEX++)) ++ done ++ echo "}" >> $TMPFILE + } + + umask 0077 +@@ -146,6 +231,10 @@ if grep -q "^blacklist[[:space:]]*{" $TM + HAVE_BLACKLIST=1 + fi + ++if grep -q "^blacklist_exceptions[[:space:]]*{" $TMPFILE ; then ++ HAVE_EXCEPTIONS=1 ++fi ++ + if grep -q "^defaults[[:space:]]*{" $TMPFILE ; then + HAVE_DEFAULTS=1 + fi +@@ -169,11 +258,19 @@ fi + if [ "$HAVE_BLACKLIST" = "1" ]; then + if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*devnode \"\.\?\*\"" ; then + HAVE_DISABLE=1 +- elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[#[:space:]]*devnode \"\.\?\*\"" ; then ++ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"" ; then + HAVE_DISABLE=0 + fi + fi + ++if [ "$HAVE_BLACKLIST" = "1" ]; then ++ if sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*wwid \"\.\?\*\"" ; then ++ HAVE_WWID_DISABLE=1 ++ elif sed -n '/^blacklist[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"" ; then ++ HAVE_WWID_DISABLE=0 ++ fi ++fi ++ + if [ "$HAVE_DEFAULTS" = "1" ]; then + if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*find_multipaths[[:space:]]*\(yes\|1\)" ; then + HAVE_FIND=1 +@@ -241,17 +338,33 @@ defaults { + _EOF_ + fi + +-if [ "$ENABLE" = 1 ]; then ++if [ "$ENABLE" = 2 ]; then ++ if [ "$HAVE_DISABLE" = 1 ]; then ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE ++ fi ++ if [ -z "$HAVE_WWID_DISABLE" ]; then ++ sed -i '/^blacklist[[:space:]]*{/ a\ ++ wwid ".*" ++' $TMPFILE ++ elif [ "$HAVE_WWID_DISABLE" = 0 ]; then ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"/ wwid ".*"/' $TMPFILE ++ fi ++ if [ "$HAVE_EXCEPTIONS" = 1 ]; then ++ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/d' $TMPFILE ++ fi ++ echo $HAVE_WWID_DISABLE ++ add_blacklist_exceptions ++elif [ "$ENABLE" = 1 ]; then + if [ "$HAVE_DISABLE" = 1 ]; then + sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*devnode \"\.\?\*\"/# devnode ".*"/' $TMPFILE + fi + elif [ "$ENABLE" = 0 ]; then + if [ -z "$HAVE_DISABLE" ]; then + sed -i '/^blacklist[[:space:]]*{/ a\ +- devnode "*" ++ devnode ".*" + ' $TMPFILE + elif [ "$HAVE_DISABLE" = 0 ]; then +- sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[#[:space:]]*devnode \"\.\?\*\"/ devnode ".*"/' $TMPFILE ++ sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*devnode \"\.\?\*\"/ devnode ".*"/' $TMPFILE + fi + fi + +@@ -289,17 +402,17 @@ elif [ "$FRIENDLY" = "y" ]; then + fi + fi + +-if [ -f "$CONFIGFILE" ]; then +- cp $CONFIGFILE $CONFIGFILE.old ++if [ -f "$OUTPUTFILE" ]; then ++ cp $OUTPUTFILE $OUTPUTFILE.old + if [ $? != 0 ]; then +- echo "failed to backup old config file, $CONFIGFILE not updated" ++ echo "failed to backup old config file, $OUTPUTFILE not updated" + exit 1 + fi + fi + +-cp $TMPFILE $CONFIGFILE ++cp $TMPFILE $OUTPUTFILE + if [ $? != 0 ]; then +- echo "failed to copy new config file into place, check $CONFIGFILE is still OK" ++ echo "failed to copy new config file into place, check $OUTPUTFILE is still OK" + exit 1 + fi + diff --git a/SOURCES/0129-UPBZ-1254292-iscsi-targetname.patch b/SOURCES/0129-UPBZ-1254292-iscsi-targetname.patch new file mode 100644 index 0000000..26a6831 --- /dev/null +++ b/SOURCES/0129-UPBZ-1254292-iscsi-targetname.patch @@ -0,0 +1,17 @@ +--- + libmultipath/discovery.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -280,6 +280,8 @@ sysfs_get_tgt_nodename (struct path *pp, + const char *value; + + value = udev_device_get_sysattr_value(tgtdev, "tgtname"); ++ if (!value) ++ value = udev_device_get_sysattr_value(tgtdev, "targetname"); + if (value) { + pp->sg_id.proto_id = SCSI_PROTOCOL_ISCSI; + pp->sg_id.transport_id = tgtid; diff --git a/SOURCES/0130-RHBZ-1259523-host_name_len.patch b/SOURCES/0130-RHBZ-1259523-host_name_len.patch new file mode 100644 index 0000000..1460550 --- /dev/null +++ b/SOURCES/0130-RHBZ-1259523-host_name_len.patch @@ -0,0 +1,17 @@ +--- + libmultipath/structs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -15,7 +15,7 @@ + #define BLK_DEV_SIZE 33 + #define PATH_SIZE 512 + #define NAME_SIZE 512 +-#define HOST_NAME_LEN 8 ++#define HOST_NAME_LEN 16 + #define SLOT_NAME_SIZE 40 + + #define SCSI_VENDOR_SIZE 9 diff --git a/SOURCES/0131-UPBZ-1259831-lock-retry.patch b/SOURCES/0131-UPBZ-1259831-lock-retry.patch new file mode 100644 index 0000000..3f5bd4d --- /dev/null +++ b/SOURCES/0131-UPBZ-1259831-lock-retry.patch @@ -0,0 +1,33 @@ +--- + multipathd/main.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -462,6 +462,7 @@ ev_add_path (struct path * pp, struct ve + char params[PARAMS_SIZE] = {0}; + int retries = 3; + int start_waiter = 0; ++ int ret; + + /* + * need path UID to go any further +@@ -540,7 +541,15 @@ rescan: + /* + * reload the map for the multipath mapped device + */ +- if (domap(mpp, params) <= 0) { ++retry: ++ ret = domap(mpp, params); ++ if (ret <= 0) { ++ if (ret < 0 && retries-- > 0) { ++ condlog(0, "%s: retry domap for addition of new " ++ "path %s", mpp->alias, pp->dev); ++ sleep(1); ++ goto retry; ++ } + condlog(0, "%s: failed in domap for addition of new " + "path %s", mpp->alias, pp->dev); + /* diff --git a/SOURCES/0132-RHBZ-1296979-fix-define.patch b/SOURCES/0132-RHBZ-1296979-fix-define.patch new file mode 100644 index 0000000..cc50722 --- /dev/null +++ b/SOURCES/0132-RHBZ-1296979-fix-define.patch @@ -0,0 +1,17 @@ +--- + libmultipath/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-bz1296979/libmultipath/Makefile +=================================================================== +--- multipath-bz1296979.orig/libmultipath/Makefile ++++ multipath-bz1296979/libmultipath/Makefile +@@ -30,7 +30,7 @@ ifneq ($(strip $(LIBDM_API_COOKIE)),0) + CFLAGS += -DLIBDM_API_COOKIE + endif + +-LIBUDEV_API_RECVBUF = $(shell grep -Ecs '^[a-z]*[[:space:]]+udev_monitor_set_resolve_buffer_size' /usr/include/libudev.h) ++LIBUDEV_API_RECVBUF = $(shell grep -Ecs '^[a-z]*[[:space:]]+udev_monitor_set_receive_buffer_size' /usr/include/libudev.h) + + ifneq ($(strip $(LIBUDEV_API_RECVBUF)),0) + CFLAGS += -DLIBUDEV_API_RECVBUF diff --git a/SOURCES/0133-RHBZ-1241774-sun-partition-numbering.patch b/SOURCES/0133-RHBZ-1241774-sun-partition-numbering.patch new file mode 100644 index 0000000..1cf555f --- /dev/null +++ b/SOURCES/0133-RHBZ-1241774-sun-partition-numbering.patch @@ -0,0 +1,17 @@ +--- + kpartx/sun.c | 2 -- + 1 file changed, 2 deletions(-) + +Index: multipath-tools-130222/kpartx/sun.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/sun.c ++++ multipath-tools-130222/kpartx/sun.c +@@ -82,8 +82,6 @@ read_sun_pt(int fd, struct slice all, st + for(i=0, n=0; ipartitions[i]; + +- if (s->num_sectors == 0) +- continue; + if (n < ns) { + sp[n].start = offset + + be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks); diff --git a/SOURCES/0134-RHBZ-1241528-check-mpath-prefix.patch b/SOURCES/0134-RHBZ-1241528-check-mpath-prefix.patch new file mode 100644 index 0000000..9701a36 --- /dev/null +++ b/SOURCES/0134-RHBZ-1241528-check-mpath-prefix.patch @@ -0,0 +1,168 @@ +--- + libmpathpersist/mpath_persist.c | 4 +- + libmultipath/devmapper.c | 67 +++++++++++++++++++++++++++++----------- + libmultipath/devmapper.h | 1 + multipathd/main.c | 2 - + 4 files changed, 53 insertions(+), 21 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -160,7 +160,7 @@ int mpath_persistent_reserve_in (int fd, + + condlog(3, "alias = %s", alias); + map_present = dm_map_present(alias); +- if (map_present && dm_type(alias, TGT_MPATH) <= 0){ ++ if (map_present && !dm_is_mpath(alias)){ + condlog( 0, "%s: not a multipath device.", alias); + ret = MPATH_PR_DMMP_ERROR; + goto out; +@@ -250,7 +250,7 @@ int mpath_persistent_reserve_out ( int f + condlog(3, "alias = %s", alias); + map_present = dm_map_present(alias); + +- if (map_present && dm_type(alias, TGT_MPATH) <= 0){ ++ if (map_present && !dm_is_mpath(alias)){ + condlog(3, "%s: not a multipath device.", alias); + ret = MPATH_PR_DMMP_ERROR; + goto out; +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -564,6 +564,48 @@ out: + return r; + } + ++extern int ++dm_is_mpath(const char * name) ++{ ++ int r = 0; ++ struct dm_task *dmt; ++ struct dm_info info; ++ uint64_t start, length; ++ char *target_type = NULL; ++ char *params; ++ const char *uuid; ++ ++ if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) ++ return 0; ++ ++ if (!dm_task_set_name(dmt, name)) ++ goto out; ++ ++ dm_task_no_open_count(dmt); ++ ++ if (!dm_task_run(dmt)) ++ goto out; ++ ++ if (!dm_task_get_info(dmt, &info) || !info.exists) ++ goto out; ++ ++ uuid = dm_task_get_uuid(dmt); ++ ++ if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN) != 0) ++ goto out; ++ ++ /* Fetch 1st target */ ++ dm_get_next_target(dmt, NULL, &start, &length, &target_type, ¶ms); ++ ++ if (!target_type || strcmp(target_type, TGT_MPATH) != 0) ++ goto out; ++ ++ r = 1; ++out: ++ dm_task_destroy(dmt); ++ return r; ++} ++ + static int + dm_dev_t (const char * mapname, char * dev_t, int len) + { +@@ -672,10 +714,7 @@ _dm_flush_map (const char * mapname, int + { + int r; + +- if (!dm_map_present(mapname)) +- return 0; +- +- if (dm_type(mapname, TGT_MPATH) <= 0) ++ if (!dm_is_mpath(mapname)) + return 0; /* nothing to do */ + + if (dm_remove_partmaps(mapname, need_sync, deferred_remove)) +@@ -725,10 +764,7 @@ dm_suspend_and_flush_map (const char * m + unsigned long long mapsize; + char params[PARAMS_SIZE] = {0}; + +- if (!dm_map_present(mapname)) +- return 0; +- +- if (dm_type(mapname, TGT_MPATH) <= 0) ++ if (!dm_is_mpath(mapname)) + return 0; /* nothing to do */ + + if (!dm_get_map(mapname, &mapsize, params)) { +@@ -899,7 +935,6 @@ dm_get_maps (vector mp) + { + struct multipath * mpp; + int r = 1; +- int info; + struct dm_task *dmt; + struct dm_names *names; + unsigned next = 0; +@@ -924,9 +959,7 @@ dm_get_maps (vector mp) + } + + do { +- info = dm_type(names->name, TGT_MPATH); +- +- if (info <= 0) ++ if (!dm_is_mpath(names->name)) + goto next; + + mpp = alloc_multipath(); +@@ -939,13 +972,11 @@ dm_get_maps (vector mp) + if (!mpp->alias) + goto out1; + +- if (info > 0) { +- if (dm_get_map(names->name, &mpp->size, NULL)) +- goto out1; ++ if (dm_get_map(names->name, &mpp->size, NULL)) ++ goto out1; + +- dm_get_uuid(names->name, mpp->wwid); +- dm_get_info(names->name, &mpp->dmi); +- } ++ dm_get_uuid(names->name, mpp->wwid); ++ dm_get_info(names->name, &mpp->dmi); + + if (!vector_alloc_slot(mp)) + goto out1; +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -23,6 +23,7 @@ int dm_map_present (const char *); + int dm_get_map(const char *, unsigned long long *, char *); + int dm_get_status(char *, char *); + int dm_type(const char *, char *); ++int dm_is_mpath(const char *); + int _dm_flush_map (const char *, int, int); + int dm_flush_map_nopaths(const char * mapname, int deferred_remove); + #define dm_flush_map(mapname) _dm_flush_map(mapname, 1, 0) +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -285,7 +285,7 @@ ev_add_map (char * dev, char * alias, st + + map_present = dm_map_present(alias); + +- if (map_present && dm_type(alias, TGT_MPATH) <= 0) { ++ if (map_present && !dm_is_mpath(alias)) { + condlog(4, "%s: not a multipath map", alias); + return 0; + } diff --git a/SOURCES/0135-RHBZ-1299600-path-dev-uevents.patch b/SOURCES/0135-RHBZ-1299600-path-dev-uevents.patch new file mode 100644 index 0000000..2de58a4 --- /dev/null +++ b/SOURCES/0135-RHBZ-1299600-path-dev-uevents.patch @@ -0,0 +1,121 @@ +--- + libmultipath/configure.c | 30 ++++++++++++++++++++++++++++-- + libmultipath/configure.h | 1 + + libmultipath/wwids.c | 4 ++-- + multipath/main.c | 2 +- + multipathd/main.c | 3 ++- + 5 files changed, 34 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -38,6 +38,7 @@ + #include "util.h" + #include "uxsock.h" + #include "wwids.h" ++#include "sysfs.h" + + /* group paths in pg by host adapter + */ +@@ -569,6 +570,29 @@ fail: + return 1; + } + ++void ++trigger_uevents (struct multipath *mpp) ++{ ++ struct pathgroup * pgp; ++ struct path * pp; ++ int i, j; ++ ++ if (!mpp || !mpp->pg) ++ return; ++ ++ vector_foreach_slot (mpp->pg, pgp, i) { ++ if (!pgp->paths) ++ continue; ++ vector_foreach_slot(pgp->paths, pp, j) { ++ if (!pp->udev) ++ continue; ++ sysfs_attr_set_value(pp->udev, "uevent", "change", ++ strlen("change")); ++ } ++ } ++} ++ ++ + /* + * Return value: + */ +@@ -658,8 +682,10 @@ domap (struct multipath * mpp, char * pa + * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD + * succeeded + */ +- if (mpp->action == ACT_CREATE) +- remember_wwid(mpp->wwid); ++ if (mpp->action == ACT_CREATE) { ++ if (remember_wwid(mpp->wwid) == 1) ++ trigger_uevents(mpp); ++ } + if (!conf->daemon) { + /* multipath client mode */ + dm_switchgroup(mpp->alias, mpp->bestpg); +Index: multipath-tools-130222/libmultipath/wwids.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/wwids.c ++++ multipath-tools-130222/libmultipath/wwids.c +@@ -310,7 +310,7 @@ remember_wwid(char *wwid) + } + else + condlog(4, "wwid %s already in wwids file", wwid); +- return 0; ++ return ret; + } + + int remember_cmdline_wwid(void) +@@ -344,7 +344,7 @@ int remember_cmdline_wwid(void) + next++; + } + if (strlen(ptr)) { +- if (remember_wwid(ptr) != 0) ++ if (remember_wwid(ptr) < 0) + ret = -1; + } + else { +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -303,7 +303,7 @@ configure (void) + } + if (conf->cmd == CMD_ADD_WWID) { + r = remember_wwid(refwwid); +- if (r == 0) ++ if (r >= 0) + printf("wwid '%s' added\n", refwwid); + else + printf("failed adding '%s' to wwids file\n", +Index: multipath-tools-130222/libmultipath/configure.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.h ++++ multipath-tools-130222/libmultipath/configure.h +@@ -31,3 +31,4 @@ int coalesce_paths (struct vectors *vecs + int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid); + int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh); + int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name); ++void trigger_uevents (struct multipath *mpp); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1435,7 +1435,8 @@ configure (struct vectors * vecs, int st + + sync_maps_state(mpvec); + vector_foreach_slot(mpvec, mpp, i){ +- remember_wwid(mpp->wwid); ++ if (remember_wwid(mpp->wwid) > 0) ++ trigger_uevents(mpp); + update_map_pr(mpp); + } + diff --git a/SOURCES/0136-RHBZ-1304687-wait-for-map-add.patch b/SOURCES/0136-RHBZ-1304687-wait-for-map-add.patch new file mode 100644 index 0000000..dbada98 --- /dev/null +++ b/SOURCES/0136-RHBZ-1304687-wait-for-map-add.patch @@ -0,0 +1,508 @@ +--- + libmultipath/config.c | 1 + libmultipath/config.h | 2 + libmultipath/configure.c | 4 + + libmultipath/defaults.h | 1 + libmultipath/dict.c | 25 ++++++++ + libmultipath/structs.h | 2 + multipath.conf.defaults | 1 + multipath/multipath.conf.5 | 8 ++ + multipathd/cli_handlers.c | 65 ++++++++++++++++++---- + multipathd/main.c | 132 +++++++++++++++++++++++++++++++++++++++++++-- + multipathd/main.h | 1 + 11 files changed, 229 insertions(+), 13 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -701,6 +701,10 @@ domap (struct multipath * mpp, char * pa + */ + if (mpp->action != ACT_CREATE) + mpp->action = ACT_NOTHING; ++ else { ++ mpp->wait_for_udev = 1; ++ mpp->uev_wait_tick = conf->uev_wait_timeout; ++ } + } + dm_setgeometry(mpp); + return DOMAP_OK; +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -217,6 +217,8 @@ struct multipath { + int bestpg; + int queuedio; + int action; ++ int wait_for_udev; ++ int uev_wait_tick; + int pgfailback; + int failback_tick; + int rr_weight; +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -548,6 +548,11 @@ cli_reload(void *v, char **reply, int *l + condlog(0, "%s: invalid map name. cannot reload", mapname); + return 1; + } ++ if (mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, failing reload", ++ mpp->alias); ++ return 1; ++ } + + return reload_map(vecs, mpp, 0); + } +@@ -592,6 +597,12 @@ cli_resize(void *v, char **reply, int *l + return 1; + } + ++ if (mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, failing resize", ++ mpp->alias); ++ return 1; ++ } ++ + pgp = VECTOR_SLOT(mpp->pg, 0); + + if (!pgp){ +@@ -756,6 +767,12 @@ cli_reconfigure(void * v, char ** reply, + { + struct vectors * vecs = (struct vectors *)data; + ++ if (need_to_delay_reconfig(vecs)) { ++ conf->delayed_reconfig = 1; ++ condlog(2, "delaying reconfigure (operator)"); ++ return 0; ++ } ++ + condlog(2, "reconfigure (operator)"); + + return reconfigure(vecs); +@@ -766,17 +783,25 @@ cli_suspend(void * v, char ** reply, int + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); +- int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0); ++ int r; ++ struct multipath * mpp; + + param = convert_dev(param, 0); +- condlog(2, "%s: suspend (operator)", param); ++ mpp = find_mp_by_alias(vecs->mpvec, param); ++ if (!mpp) ++ return 1; + +- if (!r) /* error */ ++ if (mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, failing suspend", ++ mpp->alias); + return 1; ++ } + +- struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param); ++ r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0); + +- if (!mpp) ++ condlog(2, "%s: suspend (operator)", param); ++ ++ if (!r) /* error */ + return 1; + + dm_get_info(param, &mpp->dmi); +@@ -788,17 +813,25 @@ cli_resume(void * v, char ** reply, int + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); +- int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0); ++ int r; ++ struct multipath * mpp; + + param = convert_dev(param, 0); +- condlog(2, "%s: resume (operator)", param); ++ mpp = find_mp_by_alias(vecs->mpvec, param); ++ if (!mpp) ++ return 1; + +- if (!r) /* error */ ++ if (mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, failing resume", ++ mpp->alias); + return 1; ++ } + +- struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0); + +- if (!mpp) ++ condlog(2, "%s: resume (operator)", param); ++ ++ if (!r) /* error */ + return 1; + + dm_get_info(param, &mpp->dmi); +@@ -831,9 +864,21 @@ cli_reinstate(void * v, char ** reply, i + int + cli_reassign (void * v, char ** reply, int * len, void * data) + { ++ struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); ++ struct multipath *mpp; + + param = convert_dev(param, 0); ++ mpp = find_mp_by_alias(vecs->mpvec, param); ++ if (!mpp) ++ return 1; ++ ++ if (mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, failing reassign", ++ mpp->alias); ++ return 1; ++ } ++ + condlog(3, "%s: reset devices (operator)", param); + + dm_reassign(param); +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -142,6 +142,8 @@ struct config { + int retrigger_tries; + int retrigger_delay; + int new_bindings_in_boot; ++ int delayed_reconfig; ++ int uev_wait_timeout; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -251,6 +251,47 @@ flush_map(struct multipath * mpp, struct + return 0; + } + ++int ++update_map (struct multipath *mpp, struct vectors *vecs) ++{ ++ int retries = 3; ++ char params[PARAMS_SIZE] = {0}; ++ ++retry: ++ condlog(4, "%s: updating new map", mpp->alias); ++ if (adopt_paths(vecs->pathvec, mpp, 1)) { ++ condlog(0, "%s: failed to adopt paths for new map update", ++ mpp->alias); ++ retries = -1; ++ goto fail; ++ } ++ verify_paths(mpp, vecs, NULL); ++ mpp->flush_on_last_del = FLUSH_UNDEF; ++ mpp->action = ACT_RELOAD; ++ ++ if (setup_map(mpp, params, PARAMS_SIZE)) { ++ condlog(0, "%s: failed to setup new map in update", mpp->alias); ++ retries = -1; ++ goto fail; ++ } ++ if (domap(mpp, params) <= 0 && retries-- > 0) { ++ condlog(0, "%s: map_udate sleep", mpp->alias); ++ sleep(1); ++ goto retry; ++ } ++ dm_lib_release(); ++ ++fail: ++ if (setup_multipath(vecs, mpp)) ++ return 1; ++ ++ sync_map_state(mpp); ++ ++ if (retries < 0) ++ condlog(0, "%s: failed reload in new map update", mpp->alias); ++ return 0; ++} ++ + static int + uev_add_map (struct uevent * uev, struct vectors * vecs) + { +@@ -293,6 +334,20 @@ ev_add_map (char * dev, char * alias, st + mpp = find_mp_by_alias(vecs->mpvec, alias); + + if (mpp) { ++ if (mpp->wait_for_udev > 1) { ++ if (update_map(mpp, vecs)) ++ /* setup multipathd removed the map */ ++ return 1; ++ } ++ if (mpp->wait_for_udev) { ++ mpp->wait_for_udev = 0; ++ if (conf->delayed_reconfig && ++ !need_to_delay_reconfig(vecs)) { ++ condlog(2, "reconfigure (delayed)"); ++ reconfigure(vecs); ++ return 0; ++ } ++ } + /* + * Not really an error -- we generate our own uevent + * if we create a multipath mapped device as a result +@@ -471,7 +526,14 @@ ev_add_path (struct path * pp, struct ve + condlog(0, "%s: failed to get path uid", pp->dev); + goto fail; /* leave path added to pathvec */ + } +- mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); ++ mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); ++ if (mpp && mpp->wait_for_udev) { ++ mpp->wait_for_udev = 2; ++ orphan_path(pp); ++ return 0; ++ } ++ ++ pp->mpp = mpp; + rescan: + if (mpp) { + if ((!pp->size) || (mpp->size != pp->size)) { +@@ -670,6 +732,12 @@ ev_remove_path (struct path *pp, struct + " removal of path %s", mpp->alias, pp->dev); + goto fail; + } ++ ++ if (mpp->wait_for_udev) { ++ mpp->wait_for_udev = 2; ++ goto out; ++ } ++ + /* + * reload the map + */ +@@ -731,6 +799,11 @@ uev_update_path (struct uevent *uev, str + condlog(2, "%s: update path write_protect to '%d' (uevent)", + uev->kernel, ro); + if (pp->mpp) { ++ if (pp->mpp->wait_for_udev) { ++ pp->mpp->wait_for_udev = 2; ++ return 0; ++ } ++ + retval = reload_map(vecs, pp->mpp, 0); + + condlog(2, "%s: map %s reloaded (retval %d)", +@@ -1063,6 +1136,33 @@ followover_should_failback(struct path * + } + + static void ++missing_uev_wait_tick(struct vectors *vecs) ++{ ++ struct multipath * mpp; ++ unsigned int i; ++ int timed_out = 0; ++ ++ vector_foreach_slot (vecs->mpvec, mpp, i) { ++ if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) { ++ timed_out = 1; ++ condlog(0, "%s: timeout waiting on creation uevent. enabling reloads", mpp->alias); ++ if (mpp->wait_for_udev > 1 && update_map(mpp, vecs)) { ++ /* update_map removed map */ ++ i--; ++ continue; ++ } ++ mpp->wait_for_udev = 0; ++ } ++ } ++ ++ if (timed_out && conf->delayed_reconfig && ++ !need_to_delay_reconfig(vecs)) { ++ condlog(2, "reconfigure (delayed)"); ++ reconfigure(vecs); ++ } ++} ++ ++static void + defered_failback_tick (vector mpvec) + { + struct multipath * mpp; +@@ -1316,6 +1416,9 @@ check_path (struct vectors * vecs, struc + + pp->state = newstate; + ++ ++ if (pp->mpp->wait_for_udev) ++ return; + /* + * path prio refreshing + */ +@@ -1369,6 +1472,7 @@ checkerloop (void *ap) + if (vecs->mpvec) { + defered_failback_tick(vecs->mpvec); + retry_count_tick(vecs->mpvec); ++ missing_uev_wait_tick(vecs); + } + if (count) + count--; +@@ -1465,6 +1569,22 @@ configure (struct vectors * vecs, int st + } + + int ++need_to_delay_reconfig(struct vectors * vecs) ++{ ++ struct multipath *mpp; ++ int i; ++ ++ if (!VECTOR_SIZE(vecs->mpvec)) ++ return 0; ++ ++ vector_foreach_slot(vecs->mpvec, mpp, i) { ++ if (mpp->wait_for_udev) ++ return 1; ++ } ++ return 0; ++} ++ ++int + reconfigure (struct vectors * vecs) + { + struct config * old = conf; +@@ -1544,12 +1664,18 @@ void + handle_signals(void) + { + if (reconfig_sig && running_state == DAEMON_RUNNING) { +- condlog(2, "reconfigure (signal)"); + pthread_cleanup_push(cleanup_lock, + &gvecs->lock); + lock(gvecs->lock); + pthread_testcancel(); +- reconfigure(gvecs); ++ if (need_to_delay_reconfig(gvecs)) { ++ conf->delayed_reconfig = 1; ++ condlog(2, "delaying reconfigure (signal)"); ++ } ++ else { ++ condlog(2, "reconfigure (signal)"); ++ reconfigure(gvecs); ++ } + lock_cleanup_pop(gvecs->lock); + } + if (log_reset_sig) { +Index: multipath-tools-130222/multipathd/main.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.h ++++ multipath-tools-130222/multipathd/main.h +@@ -18,6 +18,7 @@ extern pid_t daemon_pid; + + void exit_daemon(void); + const char * daemon_status(void); ++int need_to_delay_reconfig (struct vectors *); + int reconfigure (struct vectors *); + int ev_add_path (struct path *, struct vectors *); + int ev_remove_path (struct path *, struct vectors *); +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -676,6 +676,7 @@ load_config (char * file, struct udev *u + conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES; + conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY; + conf->new_bindings_in_boot = 0; ++ conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -23,6 +23,7 @@ + #define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF + #define DEFAULT_RETRIGGER_DELAY 10 + #define DEFAULT_RETRIGGER_TRIES 3 ++#define DEFAULT_UEV_WAIT_TIMEOUT 30 + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -872,6 +872,24 @@ def_retrigger_delay_handler(vector strve + } + + static int ++def_uev_wait_timeout_handler(vector strvec) ++{ ++ char *buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ conf->uev_wait_timeout = atoi(buff); ++ if (conf->uev_wait_timeout <= 0) ++ conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; ++ FREE(buff); ++ ++ return 0; ++} ++ ++static int + def_new_bindings_in_boot_handler(vector strvec) + { + char * buff; +@@ -3261,6 +3279,12 @@ snprint_def_retrigger_delay (char * buff + } + + static int ++snprint_def_uev_wait_timeout (char * buff, int len, void * data) ++{ ++ return snprintf(buff, len, "%i", conf->uev_wait_timeout); ++} ++ ++static int + snprint_def_new_bindings_in_boot(char * buff, int len, void * data) + { + if (conf->new_bindings_in_boot == 1) +@@ -3345,6 +3369,7 @@ init_keywords(void) + install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks); + install_keyword("retrigger_tries", &def_retrigger_tries_handler, &snprint_def_retrigger_tries); + install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay); ++ install_keyword("missing_uev_wait_timeout", &def_uev_wait_timeout_handler, &snprint_def_uev_wait_timeout); + install_keyword("new_bindings_in_boot", &def_new_bindings_in_boot_handler, &snprint_def_new_bindings_in_boot); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -29,6 +29,7 @@ + # config_dir "/etc/multipath/conf.d" + # delay_watch_checks no + # delay_wait_checks no ++# missing_uev_wait_timeout 30 + #} + #blacklist { + # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -478,6 +478,14 @@ used until it has passed + .I delay_wait_checks + checks. Default is + .I no ++.TP ++.B missing_uev_wait_timeout ++Controls how many seconds multipathd will wait, after a new multipath device ++is created, to receive a change event from udev for the device, before ++automatically enabling device reloads. Usually multipathd will delay reloads ++on a device until it receives a change uevent from the initial table load. The ++default is ++.I 30 + . + .SH "blacklist section" + The diff --git a/SOURCES/0137-RHBZ-1280524-clear-chkr-msg.patch b/SOURCES/0137-RHBZ-1280524-clear-chkr-msg.patch new file mode 100644 index 0000000..c05e28e --- /dev/null +++ b/SOURCES/0137-RHBZ-1280524-clear-chkr-msg.patch @@ -0,0 +1,17 @@ +--- + multipathd/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1270,6 +1270,8 @@ check_path (struct vectors * vecs, struc + newstate = path_offline(pp); + if (newstate == PATH_UP) + newstate = get_state(pp, 1); ++ else ++ checker_clear_message(&pp->checker); + + if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { + condlog(2, "%s: unusable path", pp->dev); diff --git a/SOURCES/0138-RHBZ-1288660-fix-mpathconf-allow.patch b/SOURCES/0138-RHBZ-1288660-fix-mpathconf-allow.patch new file mode 100644 index 0000000..9050fc7 --- /dev/null +++ b/SOURCES/0138-RHBZ-1288660-fix-mpathconf-allow.patch @@ -0,0 +1,86 @@ +--- + multipath/mpathconf | 37 ++++++++++++++++++++++++++----------- + 1 file changed, 26 insertions(+), 11 deletions(-) + +Index: multipath-tools-130222/multipath/mpathconf +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf ++++ multipath-tools-130222/multipath/mpathconf +@@ -42,6 +42,19 @@ function usage + echo "" + } + ++function add_wwid ++{ ++ INDEX=0 ++ while [ "$INDEX" -lt "$WWIDS" ] ; do ++ if [ "$1" = "${WWID_LIST[$INDEX]}" ] ; then ++ return ++ fi ++ ((INDEX++)) ++ done ++ WWID_LIST[$WWIDS]="$1" ++ ((WWIDS++)) ++} ++ + function get_dm_deps + { + shift 3 +@@ -59,11 +72,9 @@ function get_dm_deps + function set_dm_wwid + { + if [[ "$1" =~ ^part[[:digit:]]+-mpath- ]] ; then +- WWID_LIST[$WWIDS]="${1##part*-mpath-}" +- ((WWIDS++)) ++ add_wwid "${1##part*-mpath-}" + elif [[ "$1" =~ ^mpath- ]] ; then +- WWID_LIST[$WWIDS]="${1##mpath-}" +- ((WWIDS++)) ++ add_wwid "${1##mpath-}" + else + get_dm_deps `dmsetup deps -u $1` + fi +@@ -82,8 +93,7 @@ function set_wwid + if [ -n "$UUID" ] ; then + set_dm_wwid $UUID + else +- WWID_LIST[$WWIDS]="$1" +- ((WWIDS++)) ++ add_wwid "$1" + fi + } + +@@ -198,13 +208,13 @@ function validate_args + + function add_blacklist_exceptions + { +- echo "blacklist_exceptions {" >> $TMPFILE + INDEX=0 + while [ "$INDEX" -lt "$WWIDS" ] ; do +- echo " wwid \"${WWID_LIST[$INDEX]}\"" >> $TMPFILE ++ sed -i '/^blacklist_exceptions[[:space:]]*{/ a\ ++ wwid '"\"${WWID_LIST[$INDEX]}\""' ++' $TMPFILE + ((INDEX++)) + done +- echo "}" >> $TMPFILE + } + + umask 0077 +@@ -350,9 +360,14 @@ if [ "$ENABLE" = 2 ]; then + sed -i '/^blacklist[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*wwid \"\.\?\*\"/ wwid ".*"/' $TMPFILE + fi + if [ "$HAVE_EXCEPTIONS" = 1 ]; then +- sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/d' $TMPFILE ++ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ {/^[[:space:]]*wwid/ d}' $TMPFILE ++ else ++ cat >> $TMPFILE <<- _EOF_ ++ ++blacklist_exceptions { ++} ++_EOF_ + fi +- echo $HAVE_WWID_DISABLE + add_blacklist_exceptions + elif [ "$ENABLE" = 1 ]; then + if [ "$HAVE_DISABLE" = 1 ]; then diff --git a/SOURCES/0139-RHBZ-1273173-queue-no-daemon-doc.patch b/SOURCES/0139-RHBZ-1273173-queue-no-daemon-doc.patch new file mode 100644 index 0000000..da5f63d --- /dev/null +++ b/SOURCES/0139-RHBZ-1273173-queue-no-daemon-doc.patch @@ -0,0 +1,158 @@ +--- + multipath.conf.defaults | 54 ++++++++++++++++++++++++++++++++++++++------- + multipath/multipath.conf.5 | 2 - + 2 files changed, 47 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -377,7 +377,7 @@ multipathd running, access to the paths + cannot be told to stop queueing IO. Setting queue_without_daemon to + .I no + , avoids this problem. Default is +-.I yes ++.I no + .TP + .B bindings_file + The full pathname of the binding file to be used when the user_friendly_names option is set. Defaults to +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -4,6 +4,9 @@ + #defaults { + # verbosity 2 + # polling_interval 5 ++# max_polling_interval 20 ++# reassign_maps "yes" ++# multipath_dir "/lib64/multipath" + # path_selector "service-time 0" + # path_grouping_policy "failover" + # uid_attribute "ID_SERIAL" +@@ -12,28 +15,36 @@ + # features "0" + # path_checker "directio" + # alias_prefix "mpath" ++# failback "manual" + # rr_min_io 1000 + # rr_min_io_rq 1 + # max_fds 1048576 + # rr_weight "uniform" +-# queue_without_daemon "yes" +-# pg_timeout "none" ++# queue_without_daemon "no" + # flush_on_last_del "no" + # user_friendly_names "no" + # fast_io_fail_tmo 5 + # bindings_file "/etc/multipath/bindings" + # wwids_file /etc/multipath/wwids + # log_checker_err always ++# find_multipaths no + # retain_attached_hw_handler no + # detect_prio no ++# hw_str_match no ++# force_sync no ++# deferred_remove no ++# ignore_new_boot_devs no + # config_dir "/etc/multipath/conf.d" + # delay_watch_checks no + # delay_wait_checks no ++# retrigger_tries 3 ++# retrigger_delay 10 + # missing_uev_wait_timeout 30 ++# new_bindings_in_boot no + #} + #blacklist { + # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" +-# devnode "^hd[a-z]" ++# devnode "^(td|hd|vd)[a-z]" + # devnode "^dcssblk[0-9]*" + # device { + # vendor "DGC" +@@ -68,7 +79,7 @@ + # product "Universal Xport" + # } + # device { +-# vendor "(LSI|ENGENIO)" ++# vendor "(NETAPP|LSI|ENGENIO)" + # product "Universal Xport" + # } + #} +@@ -666,7 +677,7 @@ + # features "2 pg_init_retries 50" + # hardware_handler "1 rdac" + # prio "rdac" +-# failback "immediate" ++# failback immediate + # rr_weight "uniform" + # no_path_retry 15 + # } +@@ -679,7 +690,7 @@ + # features "2 pg_init_retries 50" + # hardware_handler "1 rdac" + # prio "rdac" +-# failback "immediate" ++# failback immediate + # rr_weight "uniform" + # no_path_retry 15 + # } +@@ -696,6 +707,7 @@ + # rr_min_io 128 + # flush_on_last_del "yes" + # dev_loss_tmo "infinity" ++# user_friendly_names no + # retain_attached_hw_handler yes + # detect_prio yes + # } +@@ -876,7 +888,7 @@ + # rr_min_io_rq 1 + # } + # device { +-# vendor "(LSI|ENGENIO)" ++# vendor "(NETAPP|LSI|ENGENIO)" + # product "INF-01-00" + # product_blacklist "Universal Xport" + # path_grouping_policy "group_by_prio" +@@ -886,7 +898,9 @@ + # prio "rdac" + # failback immediate + # rr_weight "uniform" +-# no_path_retry 15 ++# no_path_retry 30 ++# retain_attached_hw_handler yes ++# detect_prio yes + # } + # device { + # vendor "STK" +@@ -925,6 +939,30 @@ + # rr_weight "uniform" + # no_path_retry "queue" + # } ++# device { ++# vendor "DataCore" ++# product "Virtual Disk" ++# path_grouping_policy "group_by_prio" ++# path_checker "tur" ++# features "0" ++# hardware_handler "0" ++# prio "alua" ++# failback immediate ++# rr_weight "uniform" ++# no_path_retry "queue" ++# } ++# device { ++# vendor "XtremIO" ++# product "XtremApp" ++# path_grouping_policy "multibus" ++# path_selector "queue-length 0" ++# path_checker "directio" ++# features "0" ++# hardware_handler "0" ++# prio "const" ++# failback immediate ++# fast_io_fail_tmo 15 ++# } + #} + #multipaths { + #} diff --git a/SOURCES/0140-RHBZ-1299647-fix-help.patch b/SOURCES/0140-RHBZ-1299647-fix-help.patch new file mode 100644 index 0000000..c504974 --- /dev/null +++ b/SOURCES/0140-RHBZ-1299647-fix-help.patch @@ -0,0 +1,16 @@ +--- + multipath/main.c | 1 - + 1 file changed, 1 deletion(-) + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -111,7 +111,6 @@ usage (char * progname) + " -r force devmap reload\n" \ + " -i ignore wwids file\n" \ + " -B treat the bindings file as read only\n" \ +- " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ + " -b fil bindings file location\n" \ + " -w remove a device from the wwids file\n" \ + " -W reset the wwids file include only the current devices\n" \ diff --git a/SOURCES/0141-RHBZ-1303953-mpathpersist-typo.patch b/SOURCES/0141-RHBZ-1303953-mpathpersist-typo.patch new file mode 100644 index 0000000..7525902 --- /dev/null +++ b/SOURCES/0141-RHBZ-1303953-mpathpersist-typo.patch @@ -0,0 +1,17 @@ +--- + libmpathpersist/mpath_persist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -822,7 +822,7 @@ int update_map_pr(struct multipath *mpp) + if (!mpp->reservation_key) + { + /* Nothing to do. Assuming pr mgmt feature is disabled*/ +- condlog(3, "%s: reservation_key not set in multiapth.conf", mpp->alias); ++ condlog(3, "%s: reservation_key not set in multipath.conf", mpp->alias); + return MPATH_PR_SUCCESS; + } + diff --git a/SOURCES/0142-RHBZ-1283750-kpartx-fix.patch b/SOURCES/0142-RHBZ-1283750-kpartx-fix.patch new file mode 100644 index 0000000..0bc21b8 --- /dev/null +++ b/SOURCES/0142-RHBZ-1283750-kpartx-fix.patch @@ -0,0 +1,189 @@ +--- + kpartx/devmapper.c | 17 +++++++++++++-- + kpartx/devmapper.h | 2 - + kpartx/kpartx.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 69 insertions(+), 7 deletions(-) + +Index: multipath-tools-130222/kpartx/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.c ++++ multipath-tools-130222/kpartx/devmapper.c +@@ -140,12 +140,16 @@ addout: + } + + extern int +-dm_map_present (char * str) ++dm_map_present (char * str, char **uuid) + { + int r = 0; + struct dm_task *dmt; ++ const char *uuidtmp; + struct dm_info info; + ++ if (uuid) ++ *uuid = NULL; ++ + if (!(dmt = dm_task_create(DM_DEVICE_INFO))) + return 0; + +@@ -160,8 +164,15 @@ dm_map_present (char * str) + if (!dm_task_get_info(dmt, &info)) + goto out; + +- if (info.exists) +- r = 1; ++ if (!info.exists) ++ goto out; ++ ++ r = 1; ++ if (uuid) { ++ uuidtmp = dm_task_get_uuid(dmt); ++ if (uuidtmp && strlen(uuidtmp)) ++ *uuid = strdup(uuidtmp); ++ } + out: + dm_task_destroy(dmt); + return r; +Index: multipath-tools-130222/kpartx/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.h ++++ multipath-tools-130222/kpartx/devmapper.h +@@ -14,7 +14,7 @@ int dm_prereq (char *, int, int, int); + int dm_simplecmd (int, const char *, int, uint32_t *, uint16_t); + int dm_addmap (int, const char *, const char *, const char *, uint64_t, + int, const char *, int, mode_t, uid_t, gid_t, uint32_t *); +-int dm_map_present (char *); ++int dm_map_present (char *, char **); + char * dm_mapname(int major, int minor); + dev_t dm_get_first_dep(char *devname); + char * dm_mapuuid(int major, int minor); +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -191,6 +191,21 @@ get_hotplug_device(void) + return device; + } + ++static int ++check_uuid(char *uuid, char *part_uuid, char **err_msg) { ++ char *map_uuid = strchr(part_uuid, '-'); ++ if (!map_uuid || strncmp(part_uuid, "part", 4) != 0) { ++ *err_msg = "not a kpartx partition"; ++ return -1; ++ } ++ map_uuid++; ++ if (strcmp(uuid, map_uuid) != 0) { ++ *err_msg = "a partition of a different device"; ++ return -1; ++ } ++ return 0; ++} ++ + int + main(int argc, char **argv){ + int i, j, m, n, op, off, arg, ro=0; +@@ -410,6 +425,8 @@ main(int argc, char **argv){ + + case DELETE: + for (j = MAXSLICES-1; j >= 0; j--) { ++ char *part_uuid, *reason; ++ + if (safe_sprintf(partname, "%s%s%d", + mapname, delim, j+1)) { + fprintf(stderr, "partname too small\n"); +@@ -417,9 +434,18 @@ main(int argc, char **argv){ + } + strip_slash(partname); + +- if (!dm_map_present(partname)) ++ if (!dm_map_present(partname, &part_uuid)) + continue; + ++ if (part_uuid && uuid) { ++ if (check_uuid(uuid, part_uuid, &reason) != 0) { ++ fprintf(stderr, "%s is %s. Not removing\n", partname, reason); ++ free(part_uuid); ++ continue; ++ } ++ free(part_uuid); ++ } ++ + if (!dm_simplecmd(DM_DEVICE_REMOVE, partname, + 0, &cookie, 0)) { + r++; +@@ -444,6 +470,8 @@ main(int argc, char **argv){ + case UPDATE: + /* ADD and UPDATE share the same code that adds new partitions. */ + for (j = 0; j < n; j++) { ++ char *part_uuid, *reason; ++ + if (slices[j].size == 0) + continue; + +@@ -460,9 +488,19 @@ main(int argc, char **argv){ + exit(1); + } + +- op = (dm_map_present(partname) ? ++ op = (dm_map_present(partname, &part_uuid) ? + DM_DEVICE_RELOAD : DM_DEVICE_CREATE); + ++ if (part_uuid && uuid) { ++ if (check_uuid(uuid, part_uuid, &reason) != 0) { ++ fprintf(stderr, "%s is already in use, and %s\n", partname, reason); ++ r++; ++ free(part_uuid); ++ continue; ++ } ++ free(part_uuid); ++ } ++ + if (!dm_addmap(op, partname, DM_TARGET, params, + slices[j].size, ro, uuid, j+1, + buf.st_mode & 0777, buf.st_uid, +@@ -470,6 +508,7 @@ main(int argc, char **argv){ + fprintf(stderr, "create/reload failed on %s\n", + partname); + r++; ++ continue; + } + if (op == DM_DEVICE_RELOAD && + !dm_simplecmd(DM_DEVICE_RESUME, partname, +@@ -477,6 +516,7 @@ main(int argc, char **argv){ + fprintf(stderr, "resume failed on %s\n", + partname); + r++; ++ continue; + } + dm_devn(partname, &slices[j].major, + &slices[j].minor); +@@ -494,6 +534,7 @@ main(int argc, char **argv){ + } + + for (j = MAXSLICES-1; j >= 0; j--) { ++ char *part_uuid, *reason; + if (safe_sprintf(partname, "%s%s%d", + mapname, delim, j+1)) { + fprintf(stderr, "partname too small\n"); +@@ -501,9 +542,19 @@ main(int argc, char **argv){ + } + strip_slash(partname); + +- if (slices[j].size || !dm_map_present(partname)) ++ if (slices[j].size || ++ !dm_map_present(partname, &part_uuid)) + continue; + ++ if (part_uuid && uuid) { ++ if (check_uuid(uuid, part_uuid, &reason) != 0) { ++ fprintf(stderr, "%s is %s. Not removing\n", partname, reason); ++ free(part_uuid); ++ continue; ++ } ++ free(part_uuid); ++ } ++ + if (!dm_simplecmd(DM_DEVICE_REMOVE, + partname, 1, &cookie, 0)) { + r++; diff --git a/SOURCES/0143-RHBZ-1299648-kpartx-sync.patch b/SOURCES/0143-RHBZ-1299648-kpartx-sync.patch new file mode 100644 index 0000000..5e9928d --- /dev/null +++ b/SOURCES/0143-RHBZ-1299648-kpartx-sync.patch @@ -0,0 +1,59 @@ +--- + kpartx/kpartx.c | 10 +++++++--- + multipath/multipath.rules | 2 +- + 2 files changed, 8 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -57,7 +57,7 @@ struct pt { + } pts[MAXTYPES]; + + int ptct = 0; +-int udev_sync = 0; ++int udev_sync = 1; + + static void + addpts(char *t, ptreader f) +@@ -85,7 +85,7 @@ initpts(void) + addpts("ps3", read_ps3_pt); + } + +-static char short_opts[] = "rladfgvp:t:su"; ++static char short_opts[] = "rladfgvp:t:snu"; + + /* Used in gpt.c */ + int force_gpt=0; +@@ -104,7 +104,8 @@ usage(void) { + printf("\t-g force GUID partition table (GPT)\n"); + printf("\t-f force devmap create\n"); + printf("\t-v verbose\n"); +- printf("\t-s sync mode. Don't return until the partitions are created\n"); ++ printf("\t-n nosync mode. Return before the partitions are created\n"); ++ printf("\t-s sync mode. Don't return until the partitions are created. Default.\n"); + return 1; + } + +@@ -285,6 +286,9 @@ main(int argc, char **argv){ + case 's': + udev_sync = 1; + break; ++ case 'n': ++ udev_sync = 0; ++ break; + case 'u': + what = UPDATE; + break; +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -48,6 +48,6 @@ ENV{DM_ACTIVATION}=="1", ENV{DM_MULTIPAT + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" + ENV{DM_ACTIVATION}!="1", ENV{DM_MULTIPATH_NEED_KPARTX}!="1", GOTO="end_mpath" +-RUN+="$env{MPATH_SBIN_PATH}/kpartx -a $tempnode", \ ++RUN+="$env{MPATH_SBIN_PATH}/kpartx -an $tempnode", \ + ENV{DM_MULTIPATH_NEED_KPARTX}="" + LABEL="end_mpath" diff --git a/SOURCES/0144-RHBZ-1299652-alua-pref-arg.patch b/SOURCES/0144-RHBZ-1299652-alua-pref-arg.patch new file mode 100644 index 0000000..9ae0b40 --- /dev/null +++ b/SOURCES/0144-RHBZ-1299652-alua-pref-arg.patch @@ -0,0 +1,136 @@ +--- + libmultipath/prioritizers/alua.c | 20 +++++++++++++++++++- + libmultipath/propsel.c | 18 ++++++++++-------- + multipath/multipath.conf.5 | 19 ++++++++++++++++--- + 3 files changed, 45 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/libmultipath/prioritizers/alua.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/alua.c ++++ multipath-tools-130222/libmultipath/prioritizers/alua.c +@@ -86,15 +86,33 @@ get_alua_info(int fd, struct alua_contex + return rc; + } + ++int get_exclusive_perf_arg(char *args) ++{ ++ char *ptr; ++ ++ if (args == NULL) ++ return 0; ++ ptr = strstr(args, "exclusive_pref_bit"); ++ if (!ptr) ++ return 0; ++ if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t') ++ return 0; ++ if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t') ++ return 0; ++ return 1; ++} ++ + int getprio (struct path * pp, char * args) + { + int rc; + int aas; + int priopath; ++ int exclusive_perf; + + if (pp->fd < 0) + return -ALUA_PRIO_NO_INFORMATION; + ++ exclusive_perf = get_exclusive_perf_arg(args); + rc = get_alua_info(pp->fd, pp->prio.context); + if (rc >= 0) { + aas = (rc & 0x0f); +@@ -115,7 +133,7 @@ int getprio (struct path * pp, char * ar + default: + rc = 0; + } +- if (priopath && aas != AAS_OPTIMIZED) ++ if (priopath && (aas != AAS_OPTIMIZED || exclusive_perf)) + rc += 80; + } else { + switch(-rc) { +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -420,17 +420,19 @@ select_prio (struct path * pp) + if (prio_selected(p)) { + condlog(3, "%s: prio = %s (detected setting)", + pp->dev, prio_name(p)); ++ condlog(3, "%s: prio args = %s (detected setting)", ++ pp->dev, prio_args(p)); + return 0; + } + } + +- if ((mpe = find_mpe(pp->wwid))) { +- if (mpe->prio_name) { +- prio_get(p, mpe->prio_name, mpe->prio_args); +- condlog(3, "%s: prio = %s (LUN setting)", +- pp->dev, prio_name(p)); +- return 0; +- } ++ if ((mpe = find_mpe(pp->wwid)) && mpe->prio_name) { ++ prio_get(p, mpe->prio_name, mpe->prio_args); ++ condlog(3, "%s: prio = %s (LUN setting)", ++ pp->dev, prio_name(p)); ++ condlog(3, "%s: prio args = %s (LUN setting)", ++ pp->dev, prio_args(p)); ++ return 0; + } + + if (pp->hwe && pp->hwe->prio_name) { +@@ -452,7 +454,7 @@ select_prio (struct path * pp) + prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS); + condlog(3, "%s: prio = %s (internal default)", + pp->dev, DEFAULT_PRIO); +- condlog(3, "%s: prio = %s (internal default)", ++ condlog(3, "%s: prio args = %s (internal default)", + pp->dev, DEFAULT_PRIO_ARGS); + return 0; + } +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -182,7 +182,9 @@ Return a constant priority of \fI1\fR. + Generate the path priority for EMC arrays. + .TP + .B alua +-Generate the path priority based on the SCSI-3 ALUA settings. ++Generate the path priority based on the SCSI-3 ALUA settings. This prioritizer ++accepts the optional prio_arg ++.I exclusive_pref_bit + .TP + .B ontap + Generate the path priority for NetApp arrays. +@@ -208,14 +210,25 @@ Default value is \fBconst\fR. + .RE + .TP + .B prio_args +-Arguments to pass to to the prio function. Currently only used with +-.I weighted, which needs a value of the form ++Arguments to pass to to the prio function. This only applies to certain ++prioritizers ++.RS ++.TP 12 ++.B weighted ++Needs a value of the form + .I " ..." + .I hbtl + regex can be of SCSI H:B:T:L format Ex: 1:0:.:. , *:0:0:. + .I devname + regex can be of device name format Ex: sda , sd.e + .TP ++.B alua ++If ++.I exclusive_pref_bit ++is set, paths with the TPGS pref bit set will always be in their own path ++group. ++.RE ++.TP + .B features + Specify any device-mapper features to be used. Syntax is + .I num list diff --git a/SOURCES/0145-UP-resize-help-msg.patch b/SOURCES/0145-UP-resize-help-msg.patch new file mode 100644 index 0000000..33ca0f6 --- /dev/null +++ b/SOURCES/0145-UP-resize-help-msg.patch @@ -0,0 +1,172 @@ +diff --git a/multipathd/cli.c b/multipathd/cli.c +index acc4249..8d26956 100644 +--- a/multipathd/cli.c ++++ b/multipathd/cli.c +@@ -320,52 +320,90 @@ alloc_handlers (void) + } + + static int +-genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw) ++genhelp_sprint_aliases (char * reply, int maxlen, vector keys, ++ struct key * refkw) + { +- int i, fwd = 0; ++ int i, len = 0; + struct key * kw; + +- vector_foreach_slot (keys, kw, i) +- if (kw->code == refkw->code && kw != refkw) +- fwd += sprintf(reply, "|%s", kw->str); ++ vector_foreach_slot (keys, kw, i) { ++ if (kw->code == refkw->code && kw != refkw) { ++ len += snprintf(reply + len, maxlen - len, ++ "|%s", kw->str); ++ if (len >= maxlen) ++ return len; ++ } ++ } + +- return fwd; ++ return len; + } + +-static char * +-genhelp_handler (void) +-{ ++static int ++do_genhelp(char *reply, int maxlen) { ++ int len = 0; + int i, j; + unsigned long fp; + struct handler * h; + struct key * kw; +- char * reply; +- char * p; +- +- reply = MALLOC(INITIAL_REPLY_LEN); + +- if (!reply) +- return NULL; +- +- p = reply; +- p += sprintf(p, VERSION_STRING); +- p += sprintf(p, "CLI commands reference:\n"); ++ len += snprintf(reply + len, maxlen - len, VERSION_STRING); ++ if (len >= maxlen) ++ goto out; ++ len += snprintf(reply + len, maxlen - len, "CLI commands reference:\n"); ++ if (len >= maxlen) ++ goto out; + + vector_foreach_slot (handlers, h, i) { + fp = h->fingerprint; + vector_foreach_slot (keys, kw, j) { + if ((kw->code & fp)) { + fp -= kw->code; +- p += sprintf(p, " %s", kw->str); +- p += genhelp_sprint_aliases(p, keys, kw); +- +- if (kw->has_param) +- p += sprintf(p, " $%s", kw->str); ++ len += snprintf(reply + len , maxlen - len, ++ " %s", kw->str); ++ if (len >= maxlen) ++ goto out; ++ len += genhelp_sprint_aliases(reply + len, ++ maxlen - len, ++ keys, kw); ++ if (len >= maxlen) ++ goto out; ++ ++ if (kw->has_param) { ++ len += snprintf(reply + len, ++ maxlen - len, ++ " $%s", kw->str); ++ if (len >= maxlen) ++ goto out; ++ } + } + } +- p += sprintf(p, "\n"); ++ len += snprintf(reply + len, maxlen - len, "\n"); ++ if (len >= maxlen) ++ goto out; + } ++out: ++ return len; ++} ++ + ++static char * ++genhelp_handler (void) ++{ ++ char * reply; ++ char * p = NULL; ++ int maxlen = INITIAL_REPLY_LEN; ++ int again = 1; ++ ++ reply = MALLOC(maxlen); ++ ++ while (again) { ++ if (!reply) ++ return NULL; ++ p = reply; ++ p += do_genhelp(reply, maxlen); ++ again = ((p - reply) >= maxlen); ++ REALLOC_REPLY(reply, again, maxlen); ++ } + return reply; + } + +diff --git a/multipathd/cli.h b/multipathd/cli.h +index 09fdc68..2e0e1da 100644 +--- a/multipathd/cli.h ++++ b/multipathd/cli.h +@@ -71,7 +71,21 @@ enum { + #define SETPRSTATUS (1UL << __SETPRSTATUS) + #define UNSETPRSTATUS (1UL << __UNSETPRSTATUS) + +-#define INITIAL_REPLY_LEN 1100 ++#define INITIAL_REPLY_LEN 1200 ++ ++#define REALLOC_REPLY(r, a, m) \ ++ do { \ ++ if ((a)) { \ ++ char *tmp = (r); \ ++ (r) = REALLOC((r), (m) * 2); \ ++ if ((r)) { \ ++ memset((r) + (m), 0, (m)); \ ++ (m) *= 2; \ ++ } \ ++ else \ ++ free(tmp); \ ++ } \ ++ } while (0) + + struct key { + char * str; +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index e47899a..23683f2 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -23,20 +23,6 @@ + #include "cli.h" + #include "uevent.h" + +-#define REALLOC_REPLY(r, a, m) \ +- do { \ +- if ((a)) { \ +- char *tmp = (r); \ +- (r) = REALLOC((r), (m) * 2); \ +- if ((r)) { \ +- memset((r) + (m), 0, (m)); \ +- (m) *= 2; \ +- } \ +- else \ +- free(tmp); \ +- } \ +- } while (0) +- + int + show_paths (char ** r, int * len, struct vectors * vecs, char * style) + { diff --git a/SOURCES/0146-UPBZ-1299651-raw-output.patch b/SOURCES/0146-UPBZ-1299651-raw-output.patch new file mode 100644 index 0000000..93a171e --- /dev/null +++ b/SOURCES/0146-UPBZ-1299651-raw-output.patch @@ -0,0 +1,393 @@ +--- + libmultipath/print.c | 42 ++++++++++++++++++++++++---------------- + libmultipath/print.h | 4 +-- + multipathd/cli.c | 5 +++- + multipathd/cli.h | 6 +++-- + multipathd/cli_handlers.c | 48 ++++++++++++++++++++++++++++++++++------------ + multipathd/cli_handlers.h | 2 + + multipathd/main.c | 2 + + 7 files changed, 76 insertions(+), 33 deletions(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -32,14 +32,21 @@ + #define MAX(x,y) (x > y) ? x : y + #define TAIL (line + len - 1 - c) + #define NOPAD s = c +-#define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \ +- *c++ = ' '; s = c ++#define PAD(x) \ ++do { \ ++ while ((int)(c - s) < (x) && (c < (line + len - 1))) \ ++ *c++ = ' '; \ ++ s = c; \ ++} while (0) ++ + #define ENDLINE \ + if (c > line) \ + line[c - line - 1] = '\n' +-#define PRINT(var, size, format, args...) \ +- fwd = snprintf(var, size, format, ##args); \ +- c += (fwd >= size) ? size : fwd; ++#define PRINT(var, size, format, args...) \ ++do { \ ++ fwd = snprintf(var, size, format, ##args); \ ++ c += (fwd >= size) ? size : fwd; \ ++} while (0) + + /* + * information printing helpers +@@ -720,7 +727,7 @@ snprint_multipath_header (char * line, i + + int + snprint_multipath (char * line, int len, char * format, +- struct multipath * mpp) ++ struct multipath * mpp, int pad) + { + char * c = line; /* line cursor */ + char * s = line; /* for padding */ +@@ -747,7 +754,8 @@ snprint_multipath (char * line, int len, + + data->snprint(buff, MAX_FIELD_LEN, mpp); + PRINT(c, TAIL, "%s", buff); +- PAD(data->width); ++ if (pad) ++ PAD(data->width); + buff[0] = '\0'; + } while (*f++); + +@@ -790,7 +798,7 @@ snprint_path_header (char * line, int le + + int + snprint_path (char * line, int len, char * format, +- struct path * pp) ++ struct path * pp, int pad) + { + char * c = line; /* line cursor */ + char * s = line; /* for padding */ +@@ -817,7 +825,8 @@ snprint_path (char * line, int len, char + + data->snprint(buff, MAX_FIELD_LEN, pp); + PRINT(c, TAIL, "%s", buff); +- PAD(data->width); ++ if (pad) ++ PAD(data->width); + } while (*f++); + + ENDLINE; +@@ -909,7 +918,7 @@ snprint_multipath_topology (char * buff, + reset_multipath_layout(); + + if (verbosity == 1) +- return snprint_multipath(buff, len, "%n", mpp); ++ return snprint_multipath(buff, len, "%n", mpp, 1); + + if(isatty(1)) + c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */ +@@ -928,10 +937,11 @@ snprint_multipath_topology (char * buff, + if(isatty(1)) + c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */ + +- fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp); ++ fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp, 1); + if (fwd > len) + return len; +- fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp); ++ fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp, ++ 1); + if (fwd > len) + return len; + +@@ -958,7 +968,7 @@ snprint_multipath_topology (char * buff, + strcpy(f, " |- " PRINT_PATH_INDENT); + else + strcpy(f, " `- " PRINT_PATH_INDENT); +- fwd += snprint_path(buff + fwd, len - fwd, fmt, pp); ++ fwd += snprint_path(buff + fwd, len - fwd, fmt, pp, 1); + if (fwd > len) + return len; + } +@@ -1425,7 +1435,7 @@ snprint_devices (char * buff, int len, s + if (r > 0) + fwd += snprintf(buff + fwd, len - fwd, + " devnode blacklisted, unmonitored"); +- else if (r < 0) ++ else if (r <= 0) + fwd += snprintf(buff + fwd, len - fwd, + " devnode whitelisted, unmonitored"); + } else +@@ -1455,7 +1465,7 @@ print_path (struct path * pp, char * sty + char line[MAX_LINE_LEN]; + + memset(&line[0], 0, MAX_LINE_LEN); +- snprint_path(&line[0], MAX_LINE_LEN, style, pp); ++ snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1); + printf("%s", line); + } + +@@ -1465,7 +1475,7 @@ print_multipath (struct multipath * mpp, + char line[MAX_LINE_LEN]; + + memset(&line[0], 0, MAX_LINE_LEN); +- snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp); ++ snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp, 1); + printf("%s", line); + } + +Index: multipath-tools-130222/libmultipath/print.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.h ++++ multipath-tools-130222/libmultipath/print.h +@@ -37,8 +37,8 @@ void get_path_layout (vector pathvec, in + void get_multipath_layout (vector mpvec, int header); + int snprint_path_header (char *, int, char *); + int snprint_multipath_header (char *, int, char *); +-int snprint_path (char *, int, char *, struct path *); +-int snprint_multipath (char *, int, char *, struct multipath *); ++int snprint_path (char *, int, char *, struct path *, int); ++int snprint_multipath (char *, int, char *, struct multipath *, int); + int snprint_multipath_topology (char *, int, struct multipath * mpp, + int verbosity); + int snprint_defaults (char *, int); +Index: multipath-tools-130222/multipathd/cli.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.c ++++ multipath-tools-130222/multipathd/cli.c +@@ -180,7 +180,7 @@ load_keys (void) + r += add_key(keys, "config", CONFIG, 0); + r += add_key(keys, "blacklist", BLACKLIST, 0); + r += add_key(keys, "devices", DEVICES, 0); +- r += add_key(keys, "format", FMT, 1); ++ r += add_key(keys, "raw", RAW, 0); + r += add_key(keys, "wildcards", WILDCARDS, 0); + r += add_key(keys, "quit", QUIT, 0); + r += add_key(keys, "exit", QUIT, 0); +@@ -188,6 +188,7 @@ load_keys (void) + r += add_key(keys, "getprstatus", GETPRSTATUS, 0); + r += add_key(keys, "setprstatus", SETPRSTATUS, 0); + r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0); ++ r += add_key(keys, "format", FMT, 1); + + if (r) { + free_keys(keys); +@@ -463,12 +464,14 @@ cli_init (void) { + + add_handler(LIST+PATHS, NULL); + add_handler(LIST+PATHS+FMT, NULL); ++ add_handler(LIST+PATHS+RAW+FMT, NULL); + add_handler(LIST+STATUS, NULL); + add_handler(LIST+DAEMON, NULL); + add_handler(LIST+MAPS, NULL); + add_handler(LIST+MAPS+STATUS, NULL); + add_handler(LIST+MAPS+STATS, NULL); + add_handler(LIST+MAPS+FMT, NULL); ++ add_handler(LIST+MAPS+RAW+FMT, NULL); + add_handler(LIST+MAPS+TOPOLOGY, NULL); + add_handler(LIST+TOPOLOGY, NULL); + add_handler(LIST+MAP+TOPOLOGY, NULL); +Index: multipath-tools-130222/multipathd/cli.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.h ++++ multipath-tools-130222/multipathd/cli.h +@@ -26,13 +26,14 @@ enum { + __CONFIG, + __BLACKLIST, + __DEVICES, +- __FMT, ++ __RAW, + __WILDCARDS, + __QUIT, + __SHUTDOWN, + __GETPRSTATUS, + __SETPRSTATUS, + __UNSETPRSTATUS, ++ __FMT, + }; + + #define LIST (1 << __LIST) +@@ -62,7 +63,7 @@ enum { + #define CONFIG (1 << __CONFIG) + #define BLACKLIST (1 << __BLACKLIST) + #define DEVICES (1 << __DEVICES) +-#define FMT (1 << __FMT) ++#define RAW (1 << __RAW) + #define COUNT (1 << __COUNT) + #define WILDCARDS (1 << __WILDCARDS) + #define QUIT (1 << __QUIT) +@@ -70,6 +71,7 @@ enum { + #define GETPRSTATUS (1UL << __GETPRSTATUS) + #define SETPRSTATUS (1UL << __SETPRSTATUS) + #define UNSETPRSTATUS (1UL << __UNSETPRSTATUS) ++#define FMT (1UL << __FMT) + + #define INITIAL_REPLY_LEN 1200 + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -24,7 +24,8 @@ + #include "uevent.h" + + int +-show_paths (char ** r, int * len, struct vectors * vecs, char * style) ++show_paths (char ** r, int * len, struct vectors * vecs, char * style, ++ int pretty) + { + int i; + struct path * pp; +@@ -42,13 +43,13 @@ show_paths (char ** r, int * len, struct + + c = reply; + +- if (VECTOR_SIZE(vecs->pathvec) > 0) ++ if (pretty && VECTOR_SIZE(vecs->pathvec) > 0) + c += snprint_path_header(c, reply + maxlen - c, + style); + + vector_foreach_slot(vecs->pathvec, pp, i) + c += snprint_path(c, reply + maxlen - c, +- style, pp); ++ style, pp, pretty); + + again = ((c - reply) == (maxlen - 1)); + +@@ -183,7 +184,7 @@ cli_list_paths (void * v, char ** reply, + + condlog(3, "list paths (operator)"); + +- return show_paths(reply, len, vecs, PRINT_PATH_CHECKER); ++ return show_paths(reply, len, vecs, PRINT_PATH_CHECKER, 1); + } + + int +@@ -194,7 +195,18 @@ cli_list_paths_fmt (void * v, char ** re + + condlog(3, "list paths (operator)"); + +- return show_paths(reply, len, vecs, fmt); ++ return show_paths(reply, len, vecs, fmt, 1); ++} ++ ++int ++cli_list_paths_raw (void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ char * fmt = get_keyparam(v, FMT); ++ ++ condlog(3, "list paths (operator)"); ++ ++ return show_paths(reply, len, vecs, fmt, 0); + } + + int +@@ -285,7 +297,8 @@ show_daemon (char ** r, int *len) + } + + int +-show_maps (char ** r, int *len, struct vectors * vecs, char * style) ++show_maps (char ** r, int *len, struct vectors * vecs, char * style, ++ int pretty) + { + int i; + struct multipath * mpp; +@@ -302,13 +315,13 @@ show_maps (char ** r, int *len, struct v + return 1; + + c = reply; +- if (VECTOR_SIZE(vecs->mpvec) > 0) ++ if (pretty && VECTOR_SIZE(vecs->mpvec) > 0) + c += snprint_multipath_header(c, reply + maxlen - c, + style); + + vector_foreach_slot(vecs->mpvec, mpp, i) + c += snprint_multipath(c, reply + maxlen - c, +- style, mpp); ++ style, mpp, pretty); + + again = ((c - reply) == (maxlen - 1)); + +@@ -327,7 +340,18 @@ cli_list_maps_fmt (void * v, char ** rep + + condlog(3, "list maps (operator)"); + +- return show_maps(reply, len, vecs, fmt); ++ return show_maps(reply, len, vecs, fmt, 1); ++} ++ ++int ++cli_list_maps_raw (void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ char * fmt = get_keyparam(v, FMT); ++ ++ condlog(3, "list maps (operator)"); ++ ++ return show_maps(reply, len, vecs, fmt, 0); + } + + int +@@ -337,7 +361,7 @@ cli_list_maps (void * v, char ** reply, + + condlog(3, "list maps (operator)"); + +- return show_maps(reply, len, vecs, PRINT_MAP_NAMES); ++ return show_maps(reply, len, vecs, PRINT_MAP_NAMES, 1); + } + + int +@@ -357,7 +381,7 @@ cli_list_maps_status (void * v, char ** + + condlog(3, "list maps status (operator)"); + +- return show_maps(reply, len, vecs, PRINT_MAP_STATUS); ++ return show_maps(reply, len, vecs, PRINT_MAP_STATUS, 1); + } + + int +@@ -367,7 +391,7 @@ cli_list_maps_stats (void * v, char ** r + + condlog(3, "list maps stats (operator)"); + +- return show_maps(reply, len, vecs, PRINT_MAP_STATS); ++ return show_maps(reply, len, vecs, PRINT_MAP_STATS, 1); + } + + int +Index: multipath-tools-130222/multipathd/cli_handlers.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.h ++++ multipath-tools-130222/multipathd/cli_handlers.h +@@ -1,9 +1,11 @@ + int cli_list_paths (void * v, char ** reply, int * len, void * data); + int cli_list_paths_fmt (void * v, char ** reply, int * len, void * data); ++int cli_list_paths_raw (void * v, char ** reply, int * len, void * data); + int cli_list_status (void * v, char ** reply, int * len, void * data); + int cli_list_daemon (void * v, char ** reply, int * len, void * data); + int cli_list_maps (void * v, char ** reply, int * len, void * data); + int cli_list_maps_fmt (void * v, char ** reply, int * len, void * data); ++int cli_list_maps_raw (void * v, char ** reply, int * len, void * data); + int cli_list_maps_status (void * v, char ** reply, int * len, void * data); + int cli_list_maps_stats (void * v, char ** reply, int * len, void * data); + int cli_list_map_topology (void * v, char ** reply, int * len, void * data); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -967,12 +967,14 @@ uxlsnrloop (void * ap) + + set_handler_callback(LIST+PATHS, cli_list_paths); + set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt); ++ set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw); + set_handler_callback(LIST+MAPS, cli_list_maps); + set_handler_callback(LIST+STATUS, cli_list_status); + set_handler_callback(LIST+DAEMON, cli_list_daemon); + set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status); + set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats); + set_handler_callback(LIST+MAPS+FMT, cli_list_maps_fmt); ++ set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw); + set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology); + set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology); + set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology); diff --git a/SOURCES/0147-RHBZ-1272620-fail-rm-msg.patch b/SOURCES/0147-RHBZ-1272620-fail-rm-msg.patch new file mode 100644 index 0000000..b48ed6b --- /dev/null +++ b/SOURCES/0147-RHBZ-1272620-fail-rm-msg.patch @@ -0,0 +1,60 @@ +--- + multipathd/cli_handlers.c | 8 ++++---- + multipathd/main.c | 4 ++-- + 2 files changed, 6 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -459,7 +459,7 @@ cli_del_path (void * v, char ** reply, i + pp = find_path_by_dev(vecs->pathvec, param); + if (!pp) { + condlog(0, "%s: path already removed", param); +- return 0; ++ return 1; + } + return ev_remove_path(pp, vecs); + } +@@ -520,19 +520,19 @@ cli_del_map (void * v, char ** reply, in + minor = dm_get_minor(param); + if (minor < 0) { + condlog(2, "%s: not a device mapper table", param); +- return 0; ++ return 1; + } + major = dm_get_major(param); + if (major < 0) { + condlog(2, "%s: not a device mapper table", param); +- return 0; ++ return 1; + } + sprintf(dev_path,"dm-%d", minor); + alias = dm_mapname(major, minor); + if (!alias) { + condlog(2, "%s: mapname not found for %d:%d", + param, major, minor); +- return 0; ++ return 1; + } + rc = ev_remove_map(param, alias, minor, vecs); + FREE(alias); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -437,12 +437,12 @@ ev_remove_map (char * devname, char * al + if (!mpp) { + condlog(2, "%s: devmap not registered, can't remove", + devname); +- return 0; ++ return 1; + } + if (strcmp(mpp->alias, alias)) { + condlog(2, "%s: minor number mismatch (map %d, event %d)", + mpp->alias, mpp->dmi->minor, minor); +- return 0; ++ return 1; + } + return flush_map(mpp, vecs, 0); + } diff --git a/SOURCES/0148-RHBZ-1292599-verify-before-remove.patch b/SOURCES/0148-RHBZ-1292599-verify-before-remove.patch new file mode 100644 index 0000000..3e33b89 --- /dev/null +++ b/SOURCES/0148-RHBZ-1292599-verify-before-remove.patch @@ -0,0 +1,142 @@ +--- + libmultipath/devmapper.c | 45 +++++++++++++++++++++++++++++++++++++-------- + libmultipath/devmapper.h | 2 +- + 2 files changed, 38 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -33,6 +33,9 @@ + #define UUID_PREFIX_LEN 6 + + static int dm_cancel_remove_partmaps(const char * mapname); ++static int do_foreach_partmaps (const char * mapname, ++ int (*partmap_func)(const char *, void *), ++ void *data); + + #ifndef LIBDM_API_COOKIE + static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a) +@@ -709,6 +712,26 @@ out: + return r; + } + ++static int ++partmap_in_use(const char *name, void *data) ++{ ++ int part_count, *ret_count = (int *)data; ++ int open_count = dm_get_opencount(name); ++ ++ if (ret_count) ++ (*ret_count)++; ++ part_count = 0; ++ if (open_count) { ++ if (do_foreach_partmaps(name, partmap_in_use, &part_count)) ++ return 1; ++ if (open_count != part_count) { ++ condlog(2, "%s: map in use", name); ++ return 1; ++ } ++ } ++ return 0; ++} ++ + extern int + _dm_flush_map (const char * mapname, int need_sync, int deferred_remove) + { +@@ -717,6 +740,11 @@ _dm_flush_map (const char * mapname, int + if (!dm_is_mpath(mapname)) + return 0; /* nothing to do */ + ++ /* If you aren't doing a deferred remove, make sure that no ++ * devices are in use */ ++ if (!do_deferred(deferred_remove) && partmap_in_use(mapname, NULL)) ++ return 1; ++ + if (dm_remove_partmaps(mapname, need_sync, deferred_remove)) + return 1; + +@@ -825,7 +853,7 @@ dm_flush_maps (void) + } + + int +-dm_message(char * mapname, char * message) ++dm_message(const char * mapname, char * message) + { + int r = 1; + struct dm_task *dmt; +@@ -1076,7 +1104,8 @@ bad: + } + + static int +-do_foreach_partmaps (const char * mapname, int (*partmap_func)(char *, void *), ++do_foreach_partmaps (const char * mapname, ++ int (*partmap_func)(const char *, void *), + void *data) + { + struct dm_task *dmt; +@@ -1149,7 +1178,7 @@ struct remove_data { + }; + + static int +-remove_partmap(char *name, void *data) ++remove_partmap(const char *name, void *data) + { + struct remove_data *rd = (struct remove_data *)data; + +@@ -1176,7 +1205,7 @@ dm_remove_partmaps (const char * mapname + #ifdef LIBDM_API_DEFERRED + + static int +-cancel_remove_partmap (char *name, void *unused) ++cancel_remove_partmap (const char *name, void *unused) + { + if (dm_get_opencount(name)) + dm_cancel_remove_partmaps(name); +@@ -1296,13 +1325,13 @@ out: + } + + struct rename_data { +- char *old; ++ const char *old; + char *new; + char *delim; + }; + + static int +-rename_partmap (char *name, void *data) ++rename_partmap (const char *name, void *data) + { + char buff[PARAMS_SIZE]; + int offset; +@@ -1319,7 +1348,7 @@ rename_partmap (char *name, void *data) + } + + int +-dm_rename_partmaps (char * old, char * new) ++dm_rename_partmaps (const char * old, char * new) + { + struct rename_data rd; + +@@ -1333,7 +1362,7 @@ dm_rename_partmaps (char * old, char * n + } + + int +-dm_rename (char * old, char * new) ++dm_rename (const char * old, char * new) + { + int r = 0; + struct dm_task *dmt; +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -47,7 +47,7 @@ int dm_remove_partmaps (const char * map + int deferred_remove); + int dm_get_uuid(char *name, char *uuid); + int dm_get_info (char * mapname, struct dm_info ** dmi); +-int dm_rename (char * old, char * new); ++int dm_rename (const char * old, char * new); + int dm_reassign(const char * mapname); + int dm_reassign_table(const char *name, char *old, char *new); + int dm_setgeometry(struct multipath *mpp); diff --git a/SOURCES/0149-RHBZ-1292599-restore-removed-parts.patch b/SOURCES/0149-RHBZ-1292599-restore-removed-parts.patch new file mode 100644 index 0000000..62757c4 --- /dev/null +++ b/SOURCES/0149-RHBZ-1292599-restore-removed-parts.patch @@ -0,0 +1,82 @@ +--- + libmultipath/configure.c | 8 ++++++-- + libmultipath/structs.h | 1 + + multipathd/main.c | 1 + + 3 files changed, 8 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -398,6 +398,7 @@ select_action (struct multipath * mpp, v + cmpp->alias, mpp->alias); + strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE); + mpp->action = ACT_RENAME; ++ mpp->force_udev_reload = force_reload; + if (force_reload) + mpp->action = ACT_RENAME2; + return; +@@ -437,11 +438,13 @@ select_action (struct multipath * mpp, v + return; + } + if (force_reload) { ++ mpp->force_udev_reload = 1; + mpp->action = ACT_RELOAD; + condlog(3, "%s: set ACT_RELOAD (forced by user)", + mpp->alias); + return; + } ++ mpp->force_udev_reload = !pathcount(mpp, PATH_WILD); + if (cmpp->size != mpp->size) { + mpp->action = ACT_RESIZE; + condlog(3, "%s: set ACT_RESIZE (size change)", +@@ -651,7 +654,7 @@ domap (struct multipath * mpp, char * pa + case ACT_RELOAD: + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, MPATH_UDEV_RELOAD_FLAG); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, (mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG); + break; + + case ACT_RESIZE: +@@ -669,7 +672,7 @@ domap (struct multipath * mpp, char * pa + if (r) { + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, MPATH_UDEV_RELOAD_FLAG); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, (mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG); + } + break; + +@@ -682,6 +685,7 @@ domap (struct multipath * mpp, char * pa + * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD + * succeeded + */ ++ mpp->force_udev_reload = 0; + if (mpp->action == ACT_CREATE) { + if (remember_wwid(mpp->wwid) == 1) + trigger_uevents(mpp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -234,6 +234,7 @@ struct multipath { + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; ++ int force_udev_reload; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -554,6 +554,7 @@ rescan: + + condlog(4,"%s: adopting all paths for path %s", + mpp->alias, pp->dev); ++ mpp->force_udev_reload = !pathcount(mpp, PATH_WILD); + if (adopt_paths(vecs->pathvec, mpp, 1)) + goto fail; /* leave path added to pathvec */ + diff --git a/SOURCES/0150-RHBZ-1253913-fix-startup-msg.patch b/SOURCES/0150-RHBZ-1253913-fix-startup-msg.patch new file mode 100644 index 0000000..8a020ce --- /dev/null +++ b/SOURCES/0150-RHBZ-1253913-fix-startup-msg.patch @@ -0,0 +1,128 @@ +--- + multipathd/main.c | 38 +++++++++++++++++++++++++++++--------- + 1 file changed, 29 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -87,6 +87,7 @@ unsigned int mpath_mx_alloc_len; + int logsink; + enum daemon_status running_state; + pid_t daemon_pid; ++pid_t parent_pid = -1; + + static sem_t exit_sem; + /* +@@ -1718,6 +1719,12 @@ sigusr2 (int sig) + } + + static void ++sigalrm (int sig) ++{ ++ exit(0); ++} ++ ++static void + signal_init(void) + { + sigset_t set; +@@ -1820,6 +1827,9 @@ child (void * param) + } + + running_state = DAEMON_START; ++ pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid); ++ if (parent_pid > 0) ++ kill(parent_pid, SIGALRM); + + condlog(2, "--------start up--------"); + condlog(2, "read " DEFAULT_CONFIGFILE); +@@ -1911,8 +1921,6 @@ child (void * param) + } + pthread_attr_destroy(&misc_attr); + +- /* Startup complete, create logfile */ +- pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid); + update_timestamp(1); + /* Ignore errors, we can live without */ + +@@ -1992,7 +2000,10 @@ daemonize(void) + { + int pid; + int dev_null_fd; ++ struct sigaction oldsig; + ++ oldsig.sa_handler = signal_set(SIGALRM, sigalrm); ++ parent_pid = getpid(); + if( (pid = fork()) < 0){ + fprintf(stderr, "Failed first fork : %s\n", strerror(errno)); + return -1; +@@ -2000,10 +2011,13 @@ daemonize(void) + else if (pid != 0) + return pid; + ++ signal_set(SIGALRM, oldsig.sa_handler); + setsid(); + +- if ( (pid = fork()) < 0) ++ if ( (pid = fork()) < 0) { + fprintf(stderr, "Failed second fork : %s\n", strerror(errno)); ++ goto fail; ++ } + else if (pid != 0) + _exit(0); + +@@ -2014,30 +2028,34 @@ daemonize(void) + if (dev_null_fd < 0){ + fprintf(stderr, "cannot open /dev/null for input & output : %s\n", + strerror(errno)); +- _exit(0); ++ goto fail; + } + + close(STDIN_FILENO); + if (dup(dev_null_fd) < 0) { + fprintf(stderr, "cannot dup /dev/null to stdin : %s\n", + strerror(errno)); +- _exit(0); ++ goto fail; + } + close(STDOUT_FILENO); + if (dup(dev_null_fd) < 0) { + fprintf(stderr, "cannot dup /dev/null to stdout : %s\n", + strerror(errno)); +- _exit(0); ++ goto fail; + } + close(STDERR_FILENO); + if (dup(dev_null_fd) < 0) { + fprintf(stderr, "cannot dup /dev/null to stderr : %s\n", + strerror(errno)); +- _exit(0); ++ goto fail; + } + close(dev_null_fd); + daemon_pid = getpid(); + return 0; ++ ++fail: ++ kill(parent_pid, SIGALRM); ++ _exit(0); + } + + int +@@ -2116,10 +2134,12 @@ main (int argc, char *argv[]) + if (err < 0) + /* error */ + exit(1); +- else if (err > 0) ++ else if (err > 0) { ++ /* wait up to 3 seconds for the child to start */ ++ sleep(3); + /* parent dies */ + exit(0); +- else ++ } else + /* child lives */ + return (child(NULL)); + } diff --git a/SOURCES/0151-RHBZ-1297456-weighted-fix.patch b/SOURCES/0151-RHBZ-1297456-weighted-fix.patch new file mode 100644 index 0000000..57b2fed --- /dev/null +++ b/SOURCES/0151-RHBZ-1297456-weighted-fix.patch @@ -0,0 +1,156 @@ +--- + libmultipath/print.c | 8 +++--- + libmultipath/print.h | 4 +++ + libmultipath/prioritizers/weightedpath.c | 37 +++++++++++++++++++++++++++++++ + libmultipath/prioritizers/weightedpath.h | 1 + multipath/multipath.conf.5 | 8 +++++- + 5 files changed, 53 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -468,19 +468,19 @@ out: + return ret; + } + +-static int ++int + snprint_host_wwnn (char * buff, size_t len, struct path * pp) + { + return snprint_host_attr(buff, len, pp, "node_name"); + } + +-static int ++int + snprint_host_wwpn (char * buff, size_t len, struct path * pp) + { + return snprint_host_attr(buff, len, pp, "port_name"); + } + +-static int ++int + snprint_tgt_wwpn (char * buff, size_t len, struct path * pp) + { + struct udev_device *rport_dev = NULL; +@@ -510,7 +510,7 @@ out: + } + + +-static int ++int + snprint_tgt_wwnn (char * buff, size_t len, struct path * pp) + { + if (pp->tgt_node_name[0] == '\0') +Index: multipath-tools-130222/libmultipath/print.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.h ++++ multipath-tools-130222/libmultipath/print.h +@@ -50,6 +50,10 @@ int snprint_status (char *, int, struct + int snprint_devices (char *, int, struct vectors *); + int snprint_hwtable (char *, int, vector); + int snprint_mptable (char *, int, vector); ++int snprint_host_wwnn (char *, size_t, struct path *); ++int snprint_host_wwpn (char *, size_t, struct path *); ++int snprint_tgt_wwnn (char *, size_t, struct path *); ++int snprint_tgt_wwpn (char *, size_t, struct path *); + + void print_multipath_topology (struct multipath * mpp, int verbosity); + void print_path (struct path * pp, char * style); +Index: multipath-tools-130222/libmultipath/prioritizers/weightedpath.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/weightedpath.c ++++ multipath-tools-130222/libmultipath/prioritizers/weightedpath.c +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + #include "def_func.h" + + char *get_next_string(char **temp, char *split_char) +@@ -43,6 +45,36 @@ char *get_next_string(char **temp, char + return token; + } + ++#define CHECK_LEN \ ++do { \ ++ if ((p - str) >= (len - 1)) { \ ++ condlog(0, "%s: %s - buffer size too small", pp->dev, pp->prio.name); \ ++ return -1; \ ++ } \ ++} while(0) ++ ++static int ++build_wwn_path(struct path *pp, char *str, int len) ++{ ++ char *p = str; ++ ++ p += snprint_host_wwnn(p, str + len - p, pp); ++ CHECK_LEN; ++ p += snprintf(p, str + len - p, ":"); ++ CHECK_LEN; ++ p += snprint_host_wwpn(p, str + len - p, pp); ++ CHECK_LEN; ++ p += snprintf(p, str + len - p, ":"); ++ CHECK_LEN; ++ p += snprint_tgt_wwnn(p, str + len - p, pp); ++ CHECK_LEN; ++ p += snprintf(p, str + len - p, ":"); ++ CHECK_LEN; ++ p += snprint_tgt_wwpn(p, str + len - p, pp); ++ CHECK_LEN; ++ return 0; ++} ++ + /* main priority routine */ + int prio_path_weight(struct path *pp, char *prio_args) + { +@@ -72,6 +104,11 @@ int prio_path_weight(struct path *pp, ch + pp->sg_id.channel, pp->sg_id.scsi_id, pp->sg_id.lun); + } else if (!strcmp(regex, DEV_NAME)) { + strcpy(path, pp->dev); ++ } else if (!strcmp(regex, WWN)) { ++ if (build_wwn_path(pp, path, FILE_NAME_SIZE) != 0) { ++ FREE(arg); ++ return priority; ++ } + } else { + condlog(0, "%s: %s - Invalid arguments", pp->dev, + pp->prio.name); +Index: multipath-tools-130222/libmultipath/prioritizers/weightedpath.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/weightedpath.h ++++ multipath-tools-130222/libmultipath/prioritizers/weightedpath.h +@@ -4,6 +4,7 @@ + #define PRIO_WEIGHTED_PATH "weightedpath" + #define HBTL "hbtl" + #define DEV_NAME "devname" ++#define WWN "wwn" + #define DEFAULT_PRIORITY 0 + + int prio_path_weight(struct path *pp, char *prio_args); +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -216,11 +216,17 @@ prioritizers + .TP 12 + .B weighted + Needs a value of the form +-.I " ..." ++.I " ..." + .I hbtl + regex can be of SCSI H:B:T:L format Ex: 1:0:.:. , *:0:0:. + .I devname + regex can be of device name format Ex: sda , sd.e ++.I wwn ++regex can be of the form ++.I "host_wwnn:host_wwpn:target_wwnn:target_wwpn" ++these values can be looked up through sysfs or by running ++.I mulitpathd show paths format "%N:%R:%n:%r" ++Ex: 0x200100e08ba0aea0:0x210100e08ba0aea0:.*:.* , .*:.*:iqn.2009-10.com.redhat.msp.lab.ask-06:.* + .TP + .B alua + If diff --git a/SOURCES/0152-RHBZ-1269293-fix-blk-unit-file.patch b/SOURCES/0152-RHBZ-1269293-fix-blk-unit-file.patch new file mode 100644 index 0000000..cadc3f3 --- /dev/null +++ b/SOURCES/0152-RHBZ-1269293-fix-blk-unit-file.patch @@ -0,0 +1,16 @@ +--- + multipathd/multipathd.service | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -1,6 +1,6 @@ + [Unit] + Description=Device-Mapper Multipath Device Controller +-Requires=blk-availability.service ++Wants=blk-availability.service + Before=iscsi.service iscsid.service lvm2-activation-early.service + After=syslog.target + ConditionPathExists=/etc/multipath.conf diff --git a/SOURCES/0153-RH-fix-i686-size-bug.patch b/SOURCES/0153-RH-fix-i686-size-bug.patch new file mode 100644 index 0000000..325ec9d --- /dev/null +++ b/SOURCES/0153-RH-fix-i686-size-bug.patch @@ -0,0 +1,156 @@ +--- + multipathd/cli.c | 22 +++++++++++----------- + multipathd/cli.h | 20 +++++++++++--------- + 2 files changed, 22 insertions(+), 20 deletions(-) + +Index: multipath-tools-130222/multipathd/cli.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.c ++++ multipath-tools-130222/multipathd/cli.c +@@ -26,7 +26,7 @@ alloc_handler (void) + } + + static int +-add_key (vector vec, char * str, unsigned long code, int has_param) ++add_key (vector vec, char * str, uint64_t code, int has_param) + { + struct key * kw; + +@@ -57,7 +57,7 @@ out: + } + + int +-add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *)) ++add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *)) + { + struct handler * h; + +@@ -79,7 +79,7 @@ add_handler (unsigned long fp, int (*fn) + } + + static struct handler * +-find_handler (unsigned long fp) ++find_handler (uint64_t fp) + { + int i; + struct handler *h; +@@ -92,7 +92,7 @@ find_handler (unsigned long fp) + } + + int +-set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *)) ++set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *)) + { + struct handler * h = find_handler(fp); + +@@ -293,11 +293,11 @@ out: + return r; + } + +-static unsigned long ++static uint64_t + fingerprint(vector vec) + { + int i; +- unsigned long fp = 0; ++ uint64_t fp = 0; + struct key * kw; + + if (!vec) +@@ -343,7 +343,7 @@ static int + do_genhelp(char *reply, int maxlen) { + int len = 0; + int i, j; +- unsigned long fp; ++ uint64_t fp; + struct handler * h; + struct key * kw; + +@@ -442,7 +442,7 @@ parse_cmd (char * cmd, char ** reply, in + } + + char * +-get_keyparam (vector v, unsigned long code) ++get_keyparam (vector v, uint64_t code) + { + struct key * kw; + int i; +@@ -515,7 +515,7 @@ void cli_exit(void) + } + + static int +-key_match_fingerprint (struct key * kw, unsigned long fp) ++key_match_fingerprint (struct key * kw, uint64_t fp) + { + if (!fp) + return 0; +@@ -530,7 +530,7 @@ char * + key_generator (const char * str, int state) + { + static int index, len, has_param; +- static unsigned long rlfp; ++ static uint64_t rlfp; + struct key * kw; + int i; + struct handler *h; +@@ -600,7 +600,7 @@ key_generator (const char * str, int sta + * nfp is the candidate fingerprint we try to + * validate against all known command fingerprints. + */ +- unsigned long nfp = rlfp | kw->code; ++ uint64_t nfp = rlfp | kw->code; + vector_foreach_slot(handlers, h, i) { + if (!rlfp || ((h->fingerprint & nfp) == nfp)) { + /* +Index: multipath-tools-130222/multipathd/cli.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.h ++++ multipath-tools-130222/multipathd/cli.h +@@ -1,3 +1,5 @@ ++#include ++ + enum { + __LIST, + __ADD, +@@ -68,10 +70,10 @@ enum { + #define WILDCARDS (1 << __WILDCARDS) + #define QUIT (1 << __QUIT) + #define SHUTDOWN (1 << __SHUTDOWN) +-#define GETPRSTATUS (1UL << __GETPRSTATUS) +-#define SETPRSTATUS (1UL << __SETPRSTATUS) +-#define UNSETPRSTATUS (1UL << __UNSETPRSTATUS) +-#define FMT (1UL << __FMT) ++#define GETPRSTATUS (1ULL << __GETPRSTATUS) ++#define SETPRSTATUS (1ULL << __SETPRSTATUS) ++#define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS) ++#define FMT (1ULL << __FMT) + + #define INITIAL_REPLY_LEN 1200 + +@@ -92,21 +94,21 @@ enum { + struct key { + char * str; + char * param; +- unsigned long code; ++ uint64_t code; + int has_param; + }; + + struct handler { +- unsigned long fingerprint; ++ uint64_t fingerprint; + int (*fn)(void *, char **, int *, void *); + }; + + int alloc_handlers (void); +-int add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *)); +-int set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *)); ++int add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *)); ++int set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *)); + int parse_cmd (char * cmd, char ** reply, int * len, void *); + int load_keys (void); +-char * get_keyparam (vector v, unsigned long code); ++char * get_keyparam (vector v, uint64_t code); + void free_keys (vector vec); + void free_handlers (void); + int cli_init (void); diff --git a/SOURCES/0154-UPBZ-1291406-disable-reinstate.patch b/SOURCES/0154-UPBZ-1291406-disable-reinstate.patch new file mode 100644 index 0000000..2da4e3f --- /dev/null +++ b/SOURCES/0154-UPBZ-1291406-disable-reinstate.patch @@ -0,0 +1,154 @@ +--- + libmultipath/propsel.c | 20 ++++++++++++++++---- + libmultipath/structs.h | 1 + + multipathd/main.c | 37 ++++++++++++++++++++++++++----------- + 3 files changed, 43 insertions(+), 15 deletions(-) + +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -398,9 +398,11 @@ detect_prio(struct path * pp) + { + int ret; + struct prio *p = &pp->prio; ++ int tpgs = 0; + +- if (get_target_port_group_support(pp->fd) <= 0) ++ if ((tpgs = get_target_port_group_support(pp->fd)) <= 0) + return; ++ pp->tpgs = tpgs; + ret = get_target_port_group(pp->fd, NULL); + if (ret < 0) + return; +@@ -432,7 +434,7 @@ select_prio (struct path * pp) + pp->dev, prio_name(p)); + condlog(3, "%s: prio args = %s (LUN setting)", + pp->dev, prio_args(p)); +- return 0; ++ goto out; + } + + if (pp->hwe && pp->hwe->prio_name) { +@@ -441,7 +443,7 @@ select_prio (struct path * pp) + pp->dev, pp->hwe->prio_name); + condlog(3, "%s: prio args = %s (controller setting)", + pp->dev, pp->hwe->prio_args); +- return 0; ++ goto out; + } + if (conf->prio_name) { + prio_get(p, conf->prio_name, conf->prio_args); +@@ -449,13 +451,23 @@ select_prio (struct path * pp) + pp->dev, conf->prio_name); + condlog(3, "%s: prio args = %s (config file default)", + pp->dev, conf->prio_args); +- return 0; ++ goto out; + } + prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS); + condlog(3, "%s: prio = %s (internal default)", + pp->dev, DEFAULT_PRIO); + condlog(3, "%s: prio args = %s (internal default)", + pp->dev, DEFAULT_PRIO_ARGS); ++out: ++ /* ++ * fetch tpgs mode for alua ++ */ ++ if (!strncmp(prio_name(p), PRIO_ALUA, PRIO_NAME_LEN)) { ++ int tpgs = 0; ++ if (!pp->tpgs && ++ (tpgs = get_target_port_group_support(pp->fd)) >= 0) ++ pp->tpgs = tpgs; ++ } + return 0; + } + +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -193,6 +193,7 @@ struct path { + int detect_prio; + int watch_checks; + int wait_checks; ++ int tpgs; + char * uid_attribute; + struct prio prio; + char * prio_args; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include "prioritizers/alua_rtpg.h" + + /* + * libcheckers +@@ -1248,6 +1249,7 @@ check_path (struct vectors * vecs, struc + int newstate; + int new_path_up = 0; + int chkr_new_path_up = 0; ++ int disable_reinstate = 0; + int oldchkrstate = pp->chkrstate; + + if (!pp->mpp && (pp->missing_udev_info != INFO_MISSING || +@@ -1312,6 +1314,16 @@ check_path (struct vectors * vecs, struc + pp->wait_checks = 0; + } + ++ /* ++ * don't reinstate failed path, if its in stand-by ++ * and if target supports only implicit tpgs mode. ++ * this will prevent unnecessary i/o by dm on stand-by ++ * paths if there are no other active paths in map. ++ */ ++ disable_reinstate = (newstate == PATH_GHOST && ++ pp->mpp->nr_active == 0 && ++ pp->tpgs == TPGS_IMPLICIT) ? 1 : 0; ++ + pp->chkrstate = newstate; + if (newstate != pp->state) { + int oldstate = pp->state; +@@ -1367,15 +1379,17 @@ check_path (struct vectors * vecs, struc + /* + * reinstate this path + */ +- if (oldstate != PATH_UP && +- oldstate != PATH_GHOST) { +- if (pp->mpp->delay_watch_checks > 0) +- pp->watch_checks = pp->mpp->delay_watch_checks; +- reinstate_path(pp, 1); +- } else { +- if (pp->watch_checks > 0) +- pp->watch_checks--; +- reinstate_path(pp, 0); ++ if (!disable_reinstate) { ++ if (oldstate != PATH_UP && ++ oldstate != PATH_GHOST) { ++ if (pp->mpp->delay_watch_checks > 0) ++ pp->watch_checks = pp->mpp->delay_watch_checks; ++ reinstate_path(pp, 1); ++ } else { ++ if (pp->watch_checks > 0) ++ pp->watch_checks--; ++ reinstate_path(pp, 0); ++ } + } + new_path_up = 1; + +@@ -1390,8 +1404,9 @@ check_path (struct vectors * vecs, struc + enable_group(pp); + } + else if (newstate == PATH_UP || newstate == PATH_GHOST) { +- if (pp->dmstate == PSTATE_FAILED || +- pp->dmstate == PSTATE_UNDEF) { ++ if ((pp->dmstate == PSTATE_FAILED || ++ pp->dmstate == PSTATE_UNDEF) && ++ !disable_reinstate) { + /* Clear IO errors */ + reinstate_path(pp, 0); + } else { diff --git a/SOURCES/0155-UPBZ-1300415-PURE-config.patch b/SOURCES/0155-UPBZ-1300415-PURE-config.patch new file mode 100644 index 0000000..9be598c --- /dev/null +++ b/SOURCES/0155-UPBZ-1300415-PURE-config.patch @@ -0,0 +1,54 @@ +--- + libmultipath/hwtable.c | 16 ++++++++++++++++ + multipath.conf.defaults | 11 +++++++++++ + 2 files changed, 27 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1166,6 +1166,22 @@ static struct hwentry default_hw[] = { + .prio_name = DEFAULT_PRIO, + .prio_args = NULL, + }, ++ { ++ .vendor = "PURE", ++ .product = "FlashArray", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .selector = "queue-length 0", ++ .pgpolicy = MULTIBUS, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .checker_name = TUR, ++ .fast_io_fail = 10, ++ .user_friendly_names = USER_FRIENDLY_NAMES_OFF, ++ .prio_name = DEFAULT_PRIO, ++ .no_path_retry = 0, ++ .dev_loss = 60, ++ .prio_args = NULL, ++ }, + /* + * EOL + */ +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -963,6 +963,17 @@ + # failback immediate + # fast_io_fail_tmo 15 + # } ++# device { ++# vendor "PURE" ++# path_selector "queue-length 0" ++# path_grouping_policy "multibus" ++# path_checker "tur" ++# fast_io_fail_tmo 10 ++# user_friendly_names "no" ++# no_path_retry 0 ++# features 0 ++# dev_loss_tmo 60 ++# } + #} + #multipaths { + #} diff --git a/SOURCES/0156-UPBZ-1313324-dont-fail-discovery.patch b/SOURCES/0156-UPBZ-1313324-dont-fail-discovery.patch new file mode 100644 index 0000000..7e33cfe --- /dev/null +++ b/SOURCES/0156-UPBZ-1313324-dont-fail-discovery.patch @@ -0,0 +1,236 @@ +--- + libmpathpersist/mpath_persist.c | 14 ++++++------ + libmultipath/discovery.c | 46 ++++++++++++++++++++-------------------- + libmultipath/discovery.h | 4 +++ + multipath/main.c | 2 - + multipathd/main.c | 6 +++-- + 5 files changed, 39 insertions(+), 33 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -178,7 +178,7 @@ int mpath_persistent_reserve_in (int fd, + goto out; + } + +- if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER)) { ++ if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) { + ret = MPATH_PR_DMMP_ERROR; + goto out1; + } +@@ -262,13 +262,13 @@ int mpath_persistent_reserve_out ( int f + curmp = vector_alloc (); + pathvec = vector_alloc (); + +- if (!curmp || !pathvec){ +- condlog (0, "%s: vector allocation failed.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out; +- } ++ if (!curmp || !pathvec){ ++ condlog (0, "%s: vector allocation failed.", alias); ++ ret = MPATH_PR_DMMP_ERROR; ++ goto out; ++ } + +- if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER)) { ++ if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) { + ret = MPATH_PR_DMMP_ERROR; + goto out1; + } +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -32,7 +32,7 @@ int + store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice, + int flag, struct path **pp_ptr) + { +- int err = 1; ++ int err = PATHINFO_FAILED; + struct path * pp; + const char * devname; + +@@ -41,12 +41,12 @@ store_pathinfo (vector pathvec, vector h + + devname = udev_device_get_sysname(udevice); + if (!devname) +- return 1; ++ return PATHINFO_FAILED; + + pp = alloc_path(); + + if (!pp) +- return 1; ++ return PATHINFO_FAILED; + + if(safe_sprintf(pp->dev, "%s", devname)) { + condlog(0, "pp->dev too small"); +@@ -80,19 +80,16 @@ path_discover (vector pathvec, struct co + + devname = udev_device_get_sysname(udevice); + if (!devname) +- return 0; ++ return PATHINFO_FAILED; + + if (filter_devnode(conf->blist_devnode, conf->elist_devnode, + (char *)devname) > 0) +- return 0; ++ return PATHINFO_SKIPPED; + + pp = find_path_by_dev(pathvec, (char *)devname); + if (!pp) { +- if (store_pathinfo(pathvec, conf->hwtable, +- udevice, flag, NULL) != 1) +- return 0; +- else +- return 1; ++ return store_pathinfo(pathvec, conf->hwtable, ++ udevice, flag, NULL); + } + return pathinfo(pp, conf->hwtable, flag); + } +@@ -104,11 +101,11 @@ path_discovery (vector pathvec, struct c + struct udev_list_entry *entry; + struct udev_device *udevice; + const char *devpath; +- int r = 0; ++ int num_paths = 0, total_paths = 0; + + udev_iter = udev_enumerate_new(conf->udev); + if (!udev_iter) +- return 1; ++ return -ENOMEM; + + udev_enumerate_add_match_subsystem(udev_iter, "block"); + udev_enumerate_scan_devices(udev_iter); +@@ -121,17 +118,20 @@ path_discovery (vector pathvec, struct c + udevice = udev_device_new_from_syspath(conf->udev, devpath); + if (!udevice) { + condlog(4, "%s: no udev information", devpath); +- r++; + continue; + } + devtype = udev_device_get_devtype(udevice); +- if(devtype && !strncmp(devtype, "disk", 4)) +- r += path_discover(pathvec, conf, udevice, flag); ++ if(devtype && !strncmp(devtype, "disk", 4)) { ++ total_paths++; ++ if (path_discover(pathvec, conf, ++ udevice, flag) == PATHINFO_OK) ++ num_paths++; ++ } + udev_device_unref(udevice); + } + udev_enumerate_unref(udev_iter); +- condlog(4, "Discovery status %d", r); +- return r; ++ condlog(4, "Discovered %d/%d paths", num_paths, total_paths); ++ return (total_paths - num_paths); + } + + #define declare_sysfs_get_str(fname) \ +@@ -1021,7 +1021,7 @@ get_state (struct path * pp, int daemon) + + if (!checker_selected(c)) { + if (daemon) { +- if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) { ++ if (pathinfo(pp, conf->hwtable, DI_SYSFS) != PATHINFO_OK) { + condlog(3, "%s: couldn't get sysfs pathinfo", + pp->dev); + return PATH_UNCHECKED; +@@ -1140,7 +1140,7 @@ pathinfo (struct path *pp, vector hwtabl + int path_state; + + if (!pp) +- return 1; ++ return PATHINFO_FAILED; + + condlog(3, "%s: mask = 0x%x", pp->dev, mask); + +@@ -1148,12 +1148,12 @@ pathinfo (struct path *pp, vector hwtabl + * fetch info available in sysfs + */ + if (mask & DI_SYSFS && sysfs_pathinfo(pp)) +- return 1; ++ return PATHINFO_FAILED; + + if (mask & DI_BLACKLIST && mask & DI_SYSFS) { + if (filter_device(conf->blist_device, conf->elist_device, + pp->vendor_id, pp->product_id) > 0) { +- return 2; ++ return PATHINFO_SKIPPED; + } + } + +@@ -1199,7 +1199,7 @@ pathinfo (struct path *pp, vector hwtabl + if (mask & DI_BLACKLIST && mask & DI_WWID) { + if (filter_wwid(conf->blist_wwid, conf->elist_wwid, + pp->wwid) > 0) { +- return 2; ++ return PATHINFO_SKIPPED; + } + } + +@@ -1213,7 +1213,7 @@ pathinfo (struct path *pp, vector hwtabl + } + } + +- return 0; ++ return PATHINFO_OK; + + blank: + /* +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -24,6 +24,10 @@ + #define SCSI_COMMAND_TERMINATED 0x22 + #define SG_ERR_DRIVER_SENSE 0x08 + ++#define PATHINFO_OK 0 ++#define PATHINFO_FAILED 1 ++#define PATHINFO_SKIPPED 2 ++ + struct config; + + int sysfs_get_dev (struct udev_device *udev, char * buff, size_t len); +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -343,7 +343,7 @@ configure (void) + /* maximum info */ + di_flag = DI_ALL; + +- if (path_discovery(pathvec, conf, di_flag)) ++ if (path_discovery(pathvec, conf, di_flag) < 0) + goto out; + + if (conf->verbosity > 2) +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1515,7 +1515,7 @@ configure (struct vectors * vecs, int st + struct multipath * mpp; + struct path * pp; + vector mpvec; +- int i; ++ int i, ret; + + if (!vecs->pathvec && !(vecs->pathvec = vector_alloc())) + return 1; +@@ -1529,7 +1529,9 @@ configure (struct vectors * vecs, int st + /* + * probe for current path (from sysfs) and map (from dm) sets + */ +- path_discovery(vecs->pathvec, conf, DI_ALL); ++ ret = path_discovery(vecs->pathvec, conf, DI_ALL); ++ if (ret < 0) ++ return 1; + + vector_foreach_slot (vecs->pathvec, pp, i){ + if (filter_path(conf, pp) > 0){ diff --git a/SOURCES/0157-RHBZ-1319853-multipath-c-error-msg.patch b/SOURCES/0157-RHBZ-1319853-multipath-c-error-msg.patch new file mode 100644 index 0000000..dbf47c7 --- /dev/null +++ b/SOURCES/0157-RHBZ-1319853-multipath-c-error-msg.patch @@ -0,0 +1,63 @@ +--- + libmultipath/alias.c | 8 ++++++++ + libmultipath/alias.h | 1 + + multipath/main.c | 7 ++++++- + 3 files changed, 15 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/alias.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.c ++++ multipath-tools-130222/libmultipath/alias.c +@@ -36,6 +36,14 @@ + * See the file COPYING included with this distribution for more details. + */ + ++int ++valid_alias(char *alias) ++{ ++ if (strchr(alias, '/') != NULL) ++ return 0; ++ return 1; ++} ++ + + static int + format_devname(char *name, int id, int len, char *prefix) +Index: multipath-tools-130222/libmultipath/alias.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/alias.h ++++ multipath-tools-130222/libmultipath/alias.h +@@ -7,6 +7,7 @@ + "# alias wwid\n" \ + "#\n" + ++int valid_alias(char *alias); + char *get_user_friendly_alias(char *wwid, char *file, char *prefix, + int bindings_readonly); + int get_user_friendly_wwid(char *alias, char *buff, char *file); +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -454,8 +454,9 @@ get_dev_type(char *dev) { + } + else if (sscanf(dev, "%d:%d", &i, &i) == 2) + return DEV_DEVT; +- else ++ else if (valid_alias(dev)) + return DEV_DEVMAP; ++ return DEV_NONE; + } + + int +@@ -607,6 +608,10 @@ main (int argc, char *argv[]) + + strncpy(conf->dev, argv[optind], FILE_NAME_SIZE); + conf->dev_type = get_dev_type(conf->dev); ++ if (conf->dev_type == DEV_NONE) { ++ condlog(0, "'%s' is not a valid argument\n", conf->dev); ++ goto out; ++ } + } + conf->daemon = 0; + diff --git a/SOURCES/0158-RHBZ-1318581-timestamp-doc-fix.patch b/SOURCES/0158-RHBZ-1318581-timestamp-doc-fix.patch new file mode 100644 index 0000000..d9af360 --- /dev/null +++ b/SOURCES/0158-RHBZ-1318581-timestamp-doc-fix.patch @@ -0,0 +1,26 @@ +--- + multipath/multipath.8 | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +Index: multipath-tools-130222/multipath/multipath.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.8 ++++ multipath-tools-130222/multipath/multipath.8 +@@ -83,6 +83,17 @@ remove the wwid for the specified device + .B \-W + reset the wwids file to only include the current multipath devices + .TP ++.B \-T "tm:valid" ++check if ++.I tm ++matches the multipathd configuration timestamp value from ++.I "/run/multipathd/timestamp" ++If so, return success if ++.I valid ++is 1. Otherwise, return failure. If the timestamp doesn't match continue ++with multipath execution. This option is designed to be used with -c by ++the udev rules. ++.TP + .BI \-p " policy" + force new maps to use the specified policy: + .RS 1.2i diff --git a/SOURCES/0159-UPBZ-1255885-udev-waits.patch b/SOURCES/0159-UPBZ-1255885-udev-waits.patch new file mode 100644 index 0000000..9e0921b --- /dev/null +++ b/SOURCES/0159-UPBZ-1255885-udev-waits.patch @@ -0,0 +1,287 @@ +--- + kpartx/devmapper.c | 41 ++++++++++++++++++++++++++++------------- + kpartx/devmapper.h | 4 ++-- + kpartx/kpartx.c | 16 ++++++++-------- + libmultipath/config.h | 1 - + libmultipath/devmapper.c | 19 +++++++++++++------ + multipath/main.c | 2 -- + 6 files changed, 51 insertions(+), 32 deletions(-) + +Index: multipath-tools-130222/kpartx/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.c ++++ multipath-tools-130222/kpartx/devmapper.c +@@ -14,13 +14,6 @@ + #define MAX_PREFIX_LEN 8 + #define PARAMS_SIZE 1024 + +-#ifndef LIBDM_API_COOKIE +-static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a) +-{ +- return 1; +-} +-#endif +- + extern int + dm_prereq (char * str, int x, int y, int z) + { +@@ -60,10 +53,13 @@ dm_prereq (char * str, int x, int y, int + } + + extern int +-dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie, uint16_t udev_flags) { ++dm_simplecmd (int task, const char *name, int no_flush, uint16_t udev_flags) { + int r = 0; + 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; + + if (!(dmt = dm_task_create(task))) +@@ -78,10 +74,17 @@ dm_simplecmd (int task, const char *name + if (no_flush) + dm_task_no_flush(dmt); + +- if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, ((udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK) | udev_flags)) ++#ifdef LIBDM_API_COOKIE ++ if (!udev_sync) ++ udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; ++ if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto out; ++#endif + r = dm_task_run(dmt); +- ++#ifdef LIBDM_API_COOKIE ++ if (udev_wait_flag) ++ dm_udev_wait(cookie); ++#endif + out: + dm_task_destroy(dmt); + return r; +@@ -90,10 +93,14 @@ dm_simplecmd (int task, const char *name + extern int + dm_addmap (int task, const char *name, const char *target, + const char *params, uint64_t size, int ro, const char *uuid, int part, +- mode_t mode, uid_t uid, gid_t gid, uint32_t *cookie) { ++ mode_t mode, uid_t uid, gid_t gid) { + int r = 0; + struct dm_task *dmt; + char *prefixed_uuid = NULL; ++#ifdef LIBDM_API_COOKIE ++ uint32_t cookie = 0; ++ uint16_t udev_flags = 0; ++#endif + + if (!(dmt = dm_task_create (task))) + return 0; +@@ -128,10 +135,18 @@ dm_addmap (int task, const char *name, c + + dm_task_no_open_count(dmt); + +- if (task == DM_DEVICE_CREATE && !dm_task_set_cookie(dmt, cookie, (udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK)) ++#ifdef LIBDM_API_COOKIE ++ if (!udev_sync) ++ udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK; ++ if (task == DM_DEVICE_CREATE && ++ !dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto addout; ++#endif + r = dm_task_run (dmt); +- ++#ifdef LIBDM_API_COOKIE ++ if (task == DM_DEVICE_CREATE) ++ dm_udev_wait(cookie); ++#endif + addout: + dm_task_destroy (dmt); + free(prefixed_uuid); +Index: multipath-tools-130222/kpartx/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/kpartx/devmapper.h ++++ multipath-tools-130222/kpartx/devmapper.h +@@ -11,9 +11,9 @@ + extern int udev_sync; + + int dm_prereq (char *, int, int, int); +-int dm_simplecmd (int, const char *, int, uint32_t *, uint16_t); ++int dm_simplecmd (int, const char *, int, uint16_t); + int dm_addmap (int, const char *, const char *, const char *, uint64_t, +- int, const char *, int, mode_t, uid_t, gid_t, uint32_t *); ++ int, const char *, int, mode_t, uid_t, gid_t); + int dm_map_present (char *, char **); + char * dm_mapname(int major, int minor); + dev_t dm_get_first_dep(char *devname); +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -224,7 +224,6 @@ main(int argc, char **argv){ + int hotplug = 0; + int loopcreated = 0; + struct stat buf; +- uint32_t cookie = 0; + + initpts(); + init_crc32(); +@@ -300,6 +299,8 @@ main(int argc, char **argv){ + #ifdef LIBDM_API_COOKIE + if (!udev_sync) + dm_udev_set_sync_support(0); ++ else ++ dm_udev_set_sync_support(1); + #endif + + if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE || what == UPDATE)) { +@@ -451,7 +452,7 @@ main(int argc, char **argv){ + } + + if (!dm_simplecmd(DM_DEVICE_REMOVE, partname, +- 0, &cookie, 0)) { ++ 0, 0)) { + r++; + continue; + } +@@ -508,7 +509,7 @@ main(int argc, char **argv){ + if (!dm_addmap(op, partname, DM_TARGET, params, + slices[j].size, ro, uuid, j+1, + buf.st_mode & 0777, buf.st_uid, +- buf.st_gid, &cookie)) { ++ buf.st_gid)) { + fprintf(stderr, "create/reload failed on %s\n", + partname); + r++; +@@ -516,12 +517,13 @@ main(int argc, char **argv){ + } + if (op == DM_DEVICE_RELOAD && + !dm_simplecmd(DM_DEVICE_RESUME, partname, +- 1, &cookie, MPATH_UDEV_RELOAD_FLAG)) { ++ 1, MPATH_UDEV_RELOAD_FLAG)) { + fprintf(stderr, "resume failed on %s\n", + partname); + r++; + continue; + } ++ + dm_devn(partname, &slices[j].major, + &slices[j].minor); + +@@ -560,7 +562,7 @@ main(int argc, char **argv){ + } + + if (!dm_simplecmd(DM_DEVICE_REMOVE, +- partname, 1, &cookie, 0)) { ++ partname, 1, 0)) { + r++; + continue; + } +@@ -586,9 +588,7 @@ main(int argc, char **argv){ + } + printf("loop deleted : %s\n", device); + } +-#ifdef LIBDM_API_COOKIE +- dm_udev_wait(cookie); +-#endif ++ + dm_lib_release(); + dm_lib_exit(); + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -129,7 +129,6 @@ struct config { + uid_t uid; + gid_t gid; + mode_t mode; +- uint32_t cookie; + int reassign_maps; + int retain_hwhandler; + int detect_prio; +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -215,6 +215,7 @@ dm_simplecmd (int task, const char *name + int r = 0; + int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME || + task == DM_DEVICE_REMOVE)); ++ uint32_t cookie = 0; + struct dm_task *dmt; + + if (!(dmt = dm_task_create (task))) +@@ -233,10 +234,12 @@ dm_simplecmd (int task, const char *name + if (do_deferred(deferred_remove)) + dm_task_deferred_remove(dmt); + #endif +- if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags)) ++ if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags)) + goto out; + r = dm_task_run (dmt); + ++ if (udev_wait_flag) ++ udev_wait(cookie); + out: + dm_task_destroy (dmt); + return r; +@@ -264,6 +267,7 @@ dm_addmap (int task, const char *target, + int r = 0; + struct dm_task *dmt; + char *prefixed_uuid = NULL; ++ uint32_t cookie = 0; + + if (!(dmt = dm_task_create (task))) + return 0; +@@ -304,10 +308,12 @@ dm_addmap (int task, const char *target, + dm_task_no_open_count(dmt); + + if (task == DM_DEVICE_CREATE && +- !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) ++ !dm_task_set_cookie(dmt, &cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) + goto freeout; + r = dm_task_run (dmt); + ++ if (task == DM_DEVICE_CREATE) ++ udev_wait(cookie); + freeout: + if (prefixed_uuid) + FREE(prefixed_uuid); +@@ -1366,6 +1372,7 @@ dm_rename (const char * old, char * new) + { + int r = 0; + struct dm_task *dmt; ++ uint32_t cookie; + + if (dm_rename_partmaps(old, new)) + return r; +@@ -1381,12 +1388,12 @@ dm_rename (const char * old, char * new) + + dm_task_no_open_count(dmt); + +- if (!dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) +- goto out; +- if (!dm_task_run(dmt)) ++ if (!dm_task_set_cookie(dmt, &cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) + goto out; ++ r = dm_task_run(dmt); ++ ++ udev_wait(cookie); + +- r = 1; + out: + dm_task_destroy(dmt); + return r; +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -681,8 +681,6 @@ main (int argc, char *argv[]) + condlog(3, "restart multipath configuration process"); + + out: +- udev_wait(conf->cookie); +- + dm_lib_release(); + dm_lib_exit(); + diff --git a/SOURCES/0160-RH-udev-flags.patch b/SOURCES/0160-RH-udev-flags.patch new file mode 100644 index 0000000..29a2c9c --- /dev/null +++ b/SOURCES/0160-RH-udev-flags.patch @@ -0,0 +1,20 @@ +--- + libmultipath/devmapper.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -213,8 +213,9 @@ dm_prereq (void) + static int + dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags, int deferred_remove) { + int r = 0; +- int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME || +- task == DM_DEVICE_REMOVE)); ++ int udev_wait_flag = ((need_sync && (task == DM_DEVICE_RESUME || ++ task == DM_DEVICE_REMOVE)) || ++ udev_flags); + uint32_t cookie = 0; + struct dm_task *dmt; + diff --git a/SOURCES/0161-RHBZ-1311659-no-kpartx.patch b/SOURCES/0161-RHBZ-1311659-no-kpartx.patch new file mode 100644 index 0000000..8656548 --- /dev/null +++ b/SOURCES/0161-RHBZ-1311659-no-kpartx.patch @@ -0,0 +1,618 @@ +--- + libmultipath/config.c | 3 + + libmultipath/config.h | 3 + + libmultipath/configure.c | 15 +++-- + libmultipath/defaults.h | 1 + libmultipath/devmapper.c | 35 +++++++++---- + libmultipath/devmapper.h | 8 ++- + libmultipath/dict.c | 114 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/propsel.c | 26 ++++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 7 ++ + multipath/multipath.conf.5 | 10 +++ + multipath/multipath.rules | 1 + multipathd/cli_handlers.c | 4 + + 13 files changed, 211 insertions(+), 17 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -343,6 +343,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(deferred_remove); + merge_num(delay_watch_checks); + merge_num(delay_wait_checks); ++ merge_num(skip_kpartx); + + /* + * Make sure features is consistent with +@@ -403,6 +404,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(deferred_remove); + overwrite_num(delay_watch_checks); + overwrite_num(delay_wait_checks); ++ overwrite_num(skip_kpartx); + + /* + * Make sure features is consistent with +@@ -677,6 +679,7 @@ load_config (char * file, struct udev *u + conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY; + conf->new_bindings_in_boot = 0; + conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; ++ conf->skip_kpartx = DEFAULT_SKIP_KPARTX; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -64,6 +64,7 @@ struct hwentry { + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; ++ int skip_kpartx; + char * bl_product; + }; + +@@ -90,6 +91,7 @@ struct mpentry { + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; ++ int skip_kpartx; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -143,6 +145,7 @@ struct config { + int new_bindings_in_boot; + int delayed_reconfig; + int uev_wait_timeout; ++ int skip_kpartx; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -294,6 +294,7 @@ setup_map (struct multipath * mpp, char + select_deferred_remove(mpp); + select_delay_watch_checks(mpp); + select_delay_wait_checks(mpp); ++ select_skip_kpartx(mpp); + + sysfs_set_scsi_tmo(mpp); + /* +@@ -446,6 +447,7 @@ select_action (struct multipath * mpp, v + } + mpp->force_udev_reload = !pathcount(mpp, PATH_WILD); + if (cmpp->size != mpp->size) { ++ mpp->force_udev_reload = 1; + mpp->action = ACT_RESIZE; + condlog(3, "%s: set ACT_RESIZE (size change)", + mpp->alias); +@@ -609,6 +611,7 @@ extern int + domap (struct multipath * mpp, char * params) + { + int r = 0; ++ uint16_t udev_flags = ((mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG) | ((mpp->skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0); + + /* + * last chance to quit before touching the devmaps +@@ -654,25 +657,27 @@ domap (struct multipath * mpp, char * pa + case ACT_RELOAD: + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, (mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, ++ udev_flags); + break; + + case ACT_RESIZE: + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1, 0); ++ r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1, ++ udev_flags); + break; + + case ACT_RENAME: +- r = dm_rename(mpp->alias_old, mpp->alias); ++ r = dm_rename(mpp->alias_old, mpp->alias, mpp->skip_kpartx); + break; + + case ACT_RENAME2: +- r = dm_rename(mpp->alias_old, mpp->alias); ++ r = dm_rename(mpp->alias_old, mpp->alias, mpp->skip_kpartx); + if (r) { + r = dm_addmap_reload(mpp, params); + if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, (mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags); + } + break; + +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -24,6 +24,7 @@ + #define DEFAULT_RETRIGGER_DELAY 10 + #define DEFAULT_RETRIGGER_TRIES 3 + #define DEFAULT_UEV_WAIT_TIMEOUT 30 ++#define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -262,13 +262,14 @@ dm_device_remove (const char *name, int + deferred_remove); + } + +-extern int ++static int + dm_addmap (int task, const char *target, struct multipath *mpp, char * params, +- int use_uuid, int ro) { ++ int use_uuid, int ro, int skip_kpartx) { + int r = 0; + struct dm_task *dmt; + char *prefixed_uuid = NULL; + uint32_t cookie = 0; ++ uint16_t udev_flags = ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0); + + if (!(dmt = dm_task_create (task))) + return 0; +@@ -309,7 +310,7 @@ dm_addmap (int task, const char *target, + dm_task_no_open_count(dmt); + + if (task == DM_DEVICE_CREATE && +- !dm_task_set_cookie(dmt, &cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) ++ !dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto freeout; + r = dm_task_run (dmt); + +@@ -332,7 +333,8 @@ dm_addmap_create (struct multipath *mpp, + for (ro = 0; ro <= 1; ro++) { + int err; + +- if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro)) ++ if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, ++ mpp, params, 1, ro, mpp->skip_kpartx)) + return 1; + /* + * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD. +@@ -354,11 +356,11 @@ dm_addmap_create (struct multipath *mpp, + + extern int + dm_addmap_reload (struct multipath *mpp, char *params) { +- if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW)) ++ if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW, SKIP_KPARTX_OFF)) + return 1; + if (errno != EROFS) + return 0; +- return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO); ++ return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO, SKIP_KPARTX_OFF); + } + + extern int +@@ -720,6 +722,12 @@ out: + } + + static int ++has_partmap(const char *name, void *data) ++{ ++ return 1; ++} ++ ++static int + partmap_in_use(const char *name, void *data) + { + int part_count, *ret_count = (int *)data; +@@ -798,10 +806,16 @@ dm_suspend_and_flush_map (const char * m + int s = 0, queue_if_no_path = 0; + unsigned long long mapsize; + char params[PARAMS_SIZE] = {0}; ++ int udev_flags = 0; + + if (!dm_is_mpath(mapname)) + return 0; /* nothing to do */ + ++ /* if the device currently has no partitions, do not ++ run kpartx on it if you fail to delete it */ ++ if (do_foreach_partmaps(mapname, has_partmap, NULL) == 0) ++ udev_flags |= MPATH_UDEV_NO_KPARTX_FLAG; ++ + if (!dm_get_map(mapname, &mapsize, params)) { + if (strstr(params, "queue_if_no_path")) + queue_if_no_path = 1; +@@ -820,7 +834,7 @@ dm_suspend_and_flush_map (const char * m + return 0; + } + condlog(2, "failed to remove multipath map %s", mapname); +- dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, 0); ++ dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, udev_flags); + if (queue_if_no_path) + s = dm_queue_if_no_path((char *)mapname, 1); + return 1; +@@ -1349,7 +1363,7 @@ rename_partmap (const char *name, void * + for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */ + snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim, + name + offset); +- dm_rename(name, buff); ++ dm_rename(name, buff, SKIP_KPARTX_OFF); + condlog(4, "partition map %s renamed", name); + return 0; + } +@@ -1369,11 +1383,12 @@ dm_rename_partmaps (const char * old, ch + } + + int +-dm_rename (const char * old, char * new) ++dm_rename (const char * old, char * new, int skip_kpartx) + { + int r = 0; + struct dm_task *dmt; + uint32_t cookie; ++ uint16_t udev_flags = ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0); + + if (dm_rename_partmaps(old, new)) + return r; +@@ -1389,7 +1404,7 @@ dm_rename (const char * old, char * new) + + dm_task_no_open_count(dmt); + +- if (!dm_task_set_cookie(dmt, &cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) ++ if (!dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto out; + r = dm_task_run(dmt); + +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -12,6 +12,12 @@ + #define MPATH_UDEV_RELOAD_FLAG 0 + #endif + ++#ifdef DM_SUBSYSTEM_UDEV_FLAG1 ++#define MPATH_UDEV_NO_KPARTX_FLAG DM_SUBSYSTEM_UDEV_FLAG1 ++#else ++#define MPATH_UDEV_NO_KPARTX_FLAG 0 ++#endif ++ + void dm_init(void); + int dm_prereq (void); + int dm_drv_version (unsigned int * version, char * str); +@@ -47,7 +53,7 @@ int dm_remove_partmaps (const char * map + int deferred_remove); + int dm_get_uuid(char *name, char *uuid); + int dm_get_info (char * mapname, struct dm_info ** dmi); +-int dm_rename (const char * old, char * new); ++int dm_rename (const char * old, char * new, int skip_kpartx); + int dm_reassign(const char * mapname); + int dm_reassign_table(const char *name, char *old, char *new); + int dm_setgeometry(struct multipath *mpp); +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -779,6 +779,29 @@ def_deferred_remove_handler(vector strve + } + + static int ++def_skip_kpartx_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->skip_kpartx = SKIP_KPARTX_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->skip_kpartx = SKIP_KPARTX_ON; ++ else ++ conf->skip_kpartx = DEFAULT_SKIP_KPARTX; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + def_ignore_new_boot_devs_handler(vector strvec) + { + char * buff; +@@ -1629,6 +1652,33 @@ hw_deferred_remove_handler(vector strvec + } + + static int ++hw_skip_kpartx_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->skip_kpartx = SKIP_KPARTX_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->skip_kpartx = SKIP_KPARTX_ON; ++ else ++ hwe->skip_kpartx = SKIP_KPARTX_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + hw_delay_watch_checks_handler(vector strvec) + { + struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); +@@ -2154,6 +2204,32 @@ mp_deferred_remove_handler(vector strvec + } + + static int ++mp_skip_kpartx_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "0") == 0)) ++ mpe->skip_kpartx = SKIP_KPARTX_OFF; ++ else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "1") == 0)) ++ mpe->skip_kpartx = SKIP_KPARTX_ON; ++ else ++ mpe->skip_kpartx = SKIP_KPARTX_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + mp_delay_watch_checks_handler(vector strvec) + { + struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); +@@ -2461,6 +2537,19 @@ snprint_mp_deferred_remove (char * buff, + } + + static int ++snprint_mp_skip_kpartx (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->skip_kpartx == SKIP_KPARTX_UNDEF) ++ return 0; ++ else if (mpe->skip_kpartx == SKIP_KPARTX_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "yes"); ++} ++ ++static int + snprint_mp_delay_watch_checks(char * buff, int len, void * data) + { + struct mpentry * mpe = (struct mpentry *)data; +@@ -2813,6 +2902,19 @@ snprint_hw_deferred_remove(char * buff, + } + + static int ++snprint_hw_skip_kpartx(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->skip_kpartx == SKIP_KPARTX_ON) ++ return snprintf(buff, len, "yes"); ++ else if (hwe->skip_kpartx == SKIP_KPARTX_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return 0; ++} ++ ++static int + snprint_hw_delay_watch_checks(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -3231,6 +3333,15 @@ snprint_def_deferred_remove(char * buff, + } + + static int ++snprint_def_skip_kpartx(char * buff, int len, void * data) ++{ ++ if (conf->skip_kpartx == SKIP_KPARTX_ON) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_def_ignore_new_boot_devs(char * buff, int len, void * data) + { + if (conf->ignore_new_boot_devs == 1) +@@ -3364,6 +3475,7 @@ init_keywords(void) + install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); + install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); + install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs); ++ install_keyword("skip_kpartx", &def_skip_kpartx_handler, &snprint_def_skip_kpartx); + install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir); + install_keyword("delay_watch_checks", &def_delay_watch_checks_handler, &snprint_def_delay_watch_checks); + install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks); +@@ -3438,6 +3550,7 @@ init_keywords(void) + install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove); + install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks); + install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks); ++ install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx); + install_sublevel_end(); + + install_keyword_root("multipaths", &multipaths_handler); +@@ -3465,5 +3578,6 @@ init_keywords(void) + install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove); + install_keyword("delay_watch_checks", &mp_delay_watch_checks_handler, &snprint_mp_delay_watch_checks); + install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks); ++ install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -854,3 +854,29 @@ select_delay_wait_checks (struct multipa + condlog(3, "delay_wait_checks = DISABLED (internal default)"); + return 0; + } ++ ++extern int ++select_skip_kpartx (struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->skip_kpartx != SKIP_KPARTX_UNDEF) { ++ mp->skip_kpartx = mp->mpe->skip_kpartx; ++ condlog(3, "skip_kpartx = %i (multipath setting)", ++ mp->skip_kpartx); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->skip_kpartx != SKIP_KPARTX_UNDEF) { ++ mp->skip_kpartx = mp->hwe->skip_kpartx; ++ condlog(3, "skip_kpartx = %i (controler setting)", ++ mp->skip_kpartx); ++ return 0; ++ } ++ if (conf->skip_kpartx != SKIP_KPARTX_UNDEF) { ++ mp->skip_kpartx = conf->skip_kpartx; ++ condlog(3, "skip_kpartx = %i (config file default)", ++ mp->skip_kpartx); ++ return 0; ++ } ++ mp->skip_kpartx = DEFAULT_SKIP_KPARTX; ++ condlog(3, "skip_kpartx = DISABLED (internal default)"); ++ return 0; ++} +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -23,3 +23,4 @@ int select_detect_prio(struct path * pp) + int select_deferred_remove(struct multipath *mp); + int select_delay_watch_checks (struct multipath * mp); + int select_delay_wait_checks (struct multipath * mp); ++int select_skip_kpartx (struct multipath * mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -121,6 +121,12 @@ enum deferred_remove_states { + DEFERRED_REMOVE_IN_PROGRESS, + }; + ++enum skip_kpartx_states { ++ SKIP_KPARTX_UNDEF, ++ SKIP_KPARTX_OFF, ++ SKIP_KPARTX_ON, ++}; ++ + enum scsi_protocol { + SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ + SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ +@@ -236,6 +242,7 @@ struct multipath { + int delay_watch_checks; + int delay_wait_checks; + int force_udev_reload; ++ int skip_kpartx; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -44,6 +44,7 @@ KERNEL!="dm-*", GOTO="end_mpath" + ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10" + ACTION!="change", GOTO="end_mpath" + ENV{DM_UUID}!="mpath-?*", GOTO="end_mpath" ++ENV{DM_SUBSYSTEM_UDEV_FLAG1}=="1", GOTO="end_mpath" + ENV{DM_ACTIVATION}=="1", ENV{DM_MULTIPATH_NEED_KPARTX}="1" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -825,19 +825,21 @@ cli_resume(void * v, char ** reply, int + char * param = get_keyparam(v, MAP); + int r; + struct multipath * mpp; ++ uint16_t udev_flags; + + param = convert_dev(param, 0); + mpp = find_mp_by_alias(vecs->mpvec, param); + if (!mpp) + return 1; + ++ udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0; + if (mpp->wait_for_udev) { + condlog(2, "%s: device not fully created, failing resume", + mpp->alias); + return 1; + } + +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0); ++ r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, udev_flags); + + condlog(2, "%s: resume (operator)", param); + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -505,6 +505,12 @@ automatically enabling device reloads. U + on a device until it receives a change uevent from the initial table load. The + default is + .I 30 ++.TP ++.B skip_kpartx ++If set to ++.I yes ++, kpartx will not automatically create partitions on the device. The default is ++.I no + . + .SH "blacklist section" + The +@@ -612,6 +618,8 @@ section: + .B delay_watch_checks + .TP + .B delay_wait_checks ++.TP ++.B skip_kpartx + .RE + .PD + .LP +@@ -708,6 +716,8 @@ section: + .B delay_watch_checks + .TP + .B delay_wait_checks ++.TP ++.B skip_kpartx + .RE + .PD + .LP diff --git a/SOURCES/0162-RHBZ-1333331-huawei-config.patch b/SOURCES/0162-RHBZ-1333331-huawei-config.patch new file mode 100644 index 0000000..7b97e07 --- /dev/null +++ b/SOURCES/0162-RHBZ-1333331-huawei-config.patch @@ -0,0 +1,24 @@ +--- + libmultipath/hwtable.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1182,6 +1182,15 @@ static struct hwentry default_hw[] = { + .dev_loss = 60, + .prio_args = NULL, + }, ++ { ++ .vendor = "HUAWEI", ++ .product = "XSG1", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .pgpolicy = MULTIBUS, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .checker_name = TUR, ++ }, + /* + * EOL + */ diff --git a/SOURCES/0163-UPBZ-1333492-resize-map.patch b/SOURCES/0163-UPBZ-1333492-resize-map.patch new file mode 100644 index 0000000..cc24b6f --- /dev/null +++ b/SOURCES/0163-UPBZ-1333492-resize-map.patch @@ -0,0 +1,24 @@ +--- + multipathd/cli_handlers.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -571,6 +571,7 @@ int resize_map(struct multipath *mpp, un + struct vectors * vecs) + { + char params[PARAMS_SIZE] = {0}; ++ unsigned long long orig_size = mpp->size; + + mpp->size = size; + update_mpp_paths(mpp, vecs->pathvec); +@@ -579,6 +580,7 @@ int resize_map(struct multipath *mpp, un + if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed to resize map : %s", mpp->alias, + strerror(errno)); ++ mpp->size = orig_size; + return 1; + } + return 0; diff --git a/SOURCES/0164-RHBZ-1311463-dos-part-rollover.patch b/SOURCES/0164-RHBZ-1311463-dos-part-rollover.patch new file mode 100644 index 0000000..dc511f2 --- /dev/null +++ b/SOURCES/0164-RHBZ-1311463-dos-part-rollover.patch @@ -0,0 +1,17 @@ +--- + kpartx/dos.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/kpartx/dos.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/dos.c ++++ multipath-tools-130222/kpartx/dos.c +@@ -78,7 +78,7 @@ read_dos_pt(int fd, struct slice all, st + unsigned long offset = all.start; + int i, n=4; + unsigned char *bp; +- int sector_size_mul = get_sector_size(fd)/512; ++ uint64_t sector_size_mul = get_sector_size(fd)/512; + + bp = (unsigned char *)getblock(fd, offset); + if (bp == NULL) diff --git a/SOURCES/0165-UPBZ-1341748-MSA-2040-conf.patch b/SOURCES/0165-UPBZ-1341748-MSA-2040-conf.patch new file mode 100644 index 0000000..6c6e64a --- /dev/null +++ b/SOURCES/0165-UPBZ-1341748-MSA-2040-conf.patch @@ -0,0 +1,30 @@ +--- + libmultipath/hwtable.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -175,6 +175,21 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .prio_args = NULL, + }, ++ { ++ /* HP MSA 1040/2040 product family */ ++ .vendor = "HP", ++ .product = "MSA (1|2)040 SA(N|S)", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = 18, ++ .minio = 100, ++ .checker_name = TUR, ++ .prio_name = PRIO_ALUA, ++ .prio_args = NULL, ++ }, + + { + /* HP SVSP */ diff --git a/SOURCES/0166-RHBZ-1323429-dont-allow-new-wwid.patch b/SOURCES/0166-RHBZ-1323429-dont-allow-new-wwid.patch new file mode 100644 index 0000000..bcc61cc --- /dev/null +++ b/SOURCES/0166-RHBZ-1323429-dont-allow-new-wwid.patch @@ -0,0 +1,24 @@ +--- + libmultipath/dmparser.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: multipath-tools-130222/libmultipath/dmparser.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dmparser.c ++++ multipath-tools-130222/libmultipath/dmparser.c +@@ -360,6 +360,15 @@ disassemble_map (vector pathvec, char * + else if (!strlen(pp->wwid)) + strncpy(pp->wwid, mpp->wwid, WWID_SIZE); + ++ /* ++ * Something went wrong. Likely the user changed the ++ * path uid_attribute after creating a device ++ */ ++ else if (strcmp(pp->wwid, mpp->wwid) != 0) { ++ condlog(0, "%s: path wwid appears to have changed. Using map wwid.\n", pp->dev_t); ++ strncpy(pp->wwid, mpp->wwid, WWID_SIZE); ++ } ++ + pgp->id ^= (long)pp; + pp->pgindex = i + 1; + diff --git a/SOURCES/0167-RHBZ-1335176-fix-show-cmds.patch b/SOURCES/0167-RHBZ-1335176-fix-show-cmds.patch new file mode 100644 index 0000000..cbc5817 --- /dev/null +++ b/SOURCES/0167-RHBZ-1335176-fix-show-cmds.patch @@ -0,0 +1,138 @@ +--- + libmultipath/print.c | 7 +++++++ + libmultipath/structs.h | 1 + + libmultipath/structs_vec.c | 24 ++++++++++++++---------- + multipathd/cli_handlers.c | 11 ++++++++++- + multipathd/main.c | 2 ++ + 5 files changed, 34 insertions(+), 11 deletions(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -248,6 +248,12 @@ snprint_q_timeouts (char * buff, size_t + } + + static int ++snprint_map_failures (char * buff, size_t len, struct multipath * mpp) ++{ ++ return snprint_uint(buff, len, mpp->stat_map_failures); ++} ++ ++static int + snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp) + { + return snprint_str(buff, len, mpp->wwid); +@@ -546,6 +552,7 @@ struct multipath_data mpd[] = { + {'t', "dm-st", 0, snprint_dm_map_state}, + {'S', "size", 0, snprint_multipath_size}, + {'f', "features", 0, snprint_features}, ++ {'x', "failures", 0, snprint_map_failures}, + {'h', "hwhandler", 0, snprint_hwhandler}, + {'A', "action", 0, snprint_action}, + {'0', "path_faults", 0, snprint_path_faults}, +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -270,6 +270,7 @@ struct multipath { + unsigned int stat_map_loads; + unsigned int stat_total_queueing_time; + unsigned int stat_queueing_timeouts; ++ unsigned int stat_map_failures; + + /* checkers shared data */ + void * mpcontext; +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -579,16 +579,20 @@ int update_multipath (struct vectors *ve + */ + void update_queue_mode_del_path(struct multipath *mpp) + { +- if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) { +- /* +- * Enter retry mode. +- * meaning of +1: retry_tick may be decremented in +- * checkerloop before starting retry. +- */ +- mpp->stat_queueing_timeouts++; +- mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1; +- condlog(1, "%s: Entering recovery mode: max_retries=%d", +- mpp->alias, mpp->no_path_retry); ++ if (--mpp->nr_active == 0) { ++ if (mpp->no_path_retry > 0) { ++ /* ++ * Enter retry mode. ++ * meaning of +1: retry_tick may be decremented in ++ * checkerloop before starting retry. ++ */ ++ mpp->stat_queueing_timeouts++; ++ mpp->retry_tick = mpp->no_path_retry * ++ conf->checkint + 1; ++ condlog(1, "%s: Entering recovery mode: max_retries=%d", ++ mpp->alias, mpp->no_path_retry); ++ } else if (mpp->no_path_retry != NO_PATH_RETRY_QUEUE) ++ mpp->stat_map_failures++; + } + condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active); + } +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -319,9 +319,14 @@ show_maps (char ** r, int *len, struct v + c += snprint_multipath_header(c, reply + maxlen - c, + style); + +- vector_foreach_slot(vecs->mpvec, mpp, i) ++ vector_foreach_slot(vecs->mpvec, mpp, i) { ++ if (update_multipath(vecs, mpp->alias, 0)) { ++ i--; ++ continue; ++ } + c += snprint_multipath(c, reply + maxlen - c, + style, mpp, pretty); ++ } + + again = ((c - reply) == (maxlen - 1)); + +@@ -742,6 +747,8 @@ cli_disable_queueing(void *v, char **rep + return 1; + } + ++ if (mpp->nr_active == 0) ++ mpp->stat_map_failures++; + mpp->retry_tick = 0; + dm_queue_if_no_path(mpp->alias, 0); + return 0; +@@ -756,6 +763,8 @@ cli_disable_all_queueing(void *v, char * + + condlog(2, "disable queueing (operator)"); + vector_foreach_slot(vecs->mpvec, mpp, i) { ++ if (mpp->nr_active == 0) ++ mpp->stat_map_failures++; + mpp->retry_tick = 0; + dm_queue_if_no_path(mpp->alias, 0); + } +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -716,6 +716,7 @@ ev_remove_path (struct path *pp, struct + mpp->retry_tick = 0; + mpp->no_path_retry = NO_PATH_RETRY_FAIL; + mpp->flush_on_last_del = FLUSH_IN_PROGRESS; ++ mpp->stat_map_failures++; + dm_queue_if_no_path(mpp->alias, 0); + } + if (!flush_map(mpp, vecs, 1)) { +@@ -1197,6 +1198,7 @@ retry_count_tick(vector mpvec) + mpp->stat_total_queueing_time++; + condlog(4, "%s: Retrying.. No active path", mpp->alias); + if(--mpp->retry_tick == 0) { ++ mpp->stat_map_failures++; + dm_queue_if_no_path(mpp->alias, 0); + condlog(2, "%s: Disable queueing", mpp->alias); + } diff --git a/SOURCES/0168-RHBZ-1347769-shared-lock.patch b/SOURCES/0168-RHBZ-1347769-shared-lock.patch new file mode 100644 index 0000000..084d112 --- /dev/null +++ b/SOURCES/0168-RHBZ-1347769-shared-lock.patch @@ -0,0 +1,17 @@ +--- + libmultipath/configure.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -552,7 +552,7 @@ lock_multipath (struct multipath * mpp, + if (!pgp->paths) + continue; + vector_foreach_slot(pgp->paths, pp, j) { +- if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) && ++ if (lock && flock(pp->fd, LOCK_SH | LOCK_NB) && + errno == EWOULDBLOCK) + goto fail; + else if (!lock) diff --git a/SOURCES/0169-UPBZ-1353357-json-output.patch b/SOURCES/0169-UPBZ-1353357-json-output.patch new file mode 100644 index 0000000..14fa840 --- /dev/null +++ b/SOURCES/0169-UPBZ-1353357-json-output.patch @@ -0,0 +1,549 @@ +--- + libmultipath/print.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/print.h | 61 ++++++++++++ + multipathd/cli.c | 3 + multipathd/cli.h | 2 + multipathd/cli_handlers.c | 93 +++++++++++++++++++ + multipathd/cli_handlers.h | 2 + multipathd/main.c | 2 + multipathd/multipathd.8 | 9 + + 8 files changed, 393 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -269,6 +269,61 @@ snprint_multipath_vpr (char * buff, size + pp->vendor_id, pp->product_id); + } + ++ ++static int ++snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp) ++{ ++ struct pathgroup * pgp; ++ struct path * pp; ++ int i, j; ++ ++ vector_foreach_slot(mpp->pg, pgp, i) { ++ if (!pgp) ++ continue; ++ vector_foreach_slot(pgp->paths, pp, j) { ++ if (strlen(pp->vendor_id)) ++ return snprintf(buff, len, "%s", pp->vendor_id); ++ } ++ } ++ return snprintf(buff, len, "##"); ++} ++ ++static int ++snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp) ++{ ++ struct pathgroup * pgp; ++ struct path * pp; ++ int i, j; ++ ++ vector_foreach_slot(mpp->pg, pgp, i) { ++ if (!pgp) ++ continue; ++ vector_foreach_slot(pgp->paths, pp, j) { ++ if (strlen(pp->product_id)) ++ return snprintf(buff, len, "%s", pp->product_id); ++ } ++ } ++ return snprintf(buff, len, "##"); ++} ++ ++static int ++snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp) ++{ ++ struct pathgroup * pgp; ++ struct path * pp; ++ int i, j; ++ ++ vector_foreach_slot(mpp->pg, pgp, i) { ++ if (!pgp) ++ continue; ++ vector_foreach_slot(pgp->paths, pp, j) { ++ if (strlen(pp->rev)) ++ return snprintf(buff, len, "%s", pp->rev); ++ } ++ } ++ return snprintf(buff, len, "##"); ++} ++ + static int + snprint_action (char * buff, size_t len, struct multipath * mpp) + { +@@ -561,6 +616,9 @@ struct multipath_data mpd[] = { + {'3', "total_q_time", 0, snprint_total_q_time}, + {'4', "q_timeouts", 0, snprint_q_timeouts}, + {'s', "vend/prod/rev", 0, snprint_multipath_vpr}, ++ {'v', "vend", 0, snprint_multipath_vend}, ++ {'p', "prod", 0, snprint_multipath_prod}, ++ {'e', "rev", 0, snprint_multipath_rev}, + {0, NULL, 0 , NULL} + }; + +@@ -983,6 +1041,170 @@ snprint_multipath_topology (char * buff, + return fwd; + } + ++static int ++snprint_json (char * buff, int len, int indent, char *json_str) ++{ ++ int fwd = 0, i; ++ ++ for (i = 0; i < indent; i++) { ++ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT); ++ if (fwd > len) ++ return fwd; ++ } ++ ++ fwd += snprintf(buff + fwd, len - fwd, "%s", json_str); ++ return fwd; ++} ++ ++static int ++snprint_json_header (char * buff, int len) ++{ ++ int fwd = 0; ++ ++ fwd += snprint_json(buff, len, 0, PRINT_JSON_START_ELEM); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_START_VERSION, ++ PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION); ++ return fwd; ++} ++ ++static int ++snprint_json_elem_footer (char * buff, int len, int indent, int last) ++{ ++ int fwd = 0, i; ++ ++ for (i = 0; i < indent; i++) { ++ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT); ++ if (fwd > len) ++ return fwd; ++ } ++ ++ if (last == 1) ++ fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM); ++ else ++ fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM); ++ return fwd; ++} ++ ++static int ++snprint_multipath_fields_json (char * buff, int len, ++ struct multipath * mpp, int last) ++{ ++ int i, j, fwd = 0; ++ struct path *pp; ++ struct pathgroup *pgp; ++ ++ fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS); ++ if (fwd > len) ++ return fwd; ++ ++ vector_foreach_slot (mpp->pg, pgp, i) { ++ ++ pgp->selector = mpp->selector; ++ fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS); ++ if (fwd > len) ++ return fwd; ++ ++ vector_foreach_slot (pgp->paths, pp, j) { ++ fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprint_json_elem_footer(buff + fwd, ++ len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths)); ++ if (fwd > len) ++ return fwd; ++ } ++ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprint_json_elem_footer(buff + fwd, ++ len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg)); ++ if (fwd > len) ++ return fwd; ++ } ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); ++ if (fwd > len) ++ return fwd; ++ ++ fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last); ++ return fwd; ++} ++ ++int ++snprint_multipath_map_json (char * buff, int len, ++ struct multipath * mpp, int last){ ++ int fwd = 0; ++ ++ fwd += snprint_json_header(buff, len); ++ if (fwd > len) ++ return len; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP); ++ if (fwd > len) ++ return len; ++ ++ fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1); ++ if (fwd > len) ++ return len; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 0, "\n"); ++ if (fwd > len) ++ return len; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST); ++ if (fwd > len) ++ return len; ++ return fwd; ++} ++ ++int ++snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs) ++{ ++ int i, fwd = 0; ++ struct multipath * mpp; ++ ++ fwd += snprint_json_header(buff, len); ++ if (fwd > len) ++ return len; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 1, PRINT_JSON_START_MAPS); ++ if (fwd > len) ++ return len; ++ ++ vector_foreach_slot(vecs->mpvec, mpp, i) { ++ fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, ++ mpp, i + 1 == VECTOR_SIZE(vecs->mpvec)); ++ if (fwd > len) ++ return len; ++ } ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); ++ if (fwd > len) ++ return len; ++ ++ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST); ++ if (fwd > len) ++ return len; ++ return fwd; ++} ++ + static int + snprint_hwentry (char * buff, int len, struct hwentry * hwe) + { +Index: multipath-tools-130222/libmultipath/print.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.h ++++ multipath-tools-130222/libmultipath/print.h +@@ -7,6 +7,63 @@ + #define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r" + #define PRINT_PG_INDENT "policy='%s' prio=%p status=%t" + ++#define PRINT_JSON_MULTIPLIER 5 ++#define PRINT_JSON_MAJOR_VERSION 0 ++#define PRINT_JSON_MINOR_VERSION 1 ++#define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \ ++ " \"minor_version\": %d,\n" ++#define PRINT_JSON_START_ELEM "{\n" ++#define PRINT_JSON_START_MAP " \"map\":" ++#define PRINT_JSON_START_MAPS "\"maps\": [" ++#define PRINT_JSON_START_PATHS "\"paths\": [" ++#define PRINT_JSON_START_GROUPS "\"path_groups\": [" ++#define PRINT_JSON_END_ELEM "}," ++#define PRINT_JSON_END_LAST_ELEM "}" ++#define PRINT_JSON_END_LAST "}\n" ++#define PRINT_JSON_END_ARRAY "]\n" ++#define PRINT_JSON_INDENT " " ++#define PRINT_JSON_MAP "{\n" \ ++ " \"name\" : \"%n\",\n" \ ++ " \"uuid\" : \"%w\",\n" \ ++ " \"sysfs\" : \"%d\",\n" \ ++ " \"failback\" : \"%F\",\n" \ ++ " \"queueing\" : \"%Q\",\n" \ ++ " \"paths\" : %N,\n" \ ++ " \"write_prot\" : \"%r\",\n" \ ++ " \"dm_st\" : \"%t\",\n" \ ++ " \"features\" : \"%f\",\n" \ ++ " \"hwhandler\" : \"%h\",\n" \ ++ " \"action\" : \"%A\",\n" \ ++ " \"path_faults\" : %0,\n" \ ++ " \"vend\" : \"%v\",\n" \ ++ " \"prod\" : \"%p\",\n" \ ++ " \"rev\" : \"%e\",\n" \ ++ " \"switch_grp\" : %1,\n" \ ++ " \"map_loads\" : %2,\n" \ ++ " \"total_q_time\" : %3,\n" \ ++ " \"q_timeouts\" : %4," ++ ++#define PRINT_JSON_GROUP "{\n" \ ++ " \"selector\" : \"%s\",\n" \ ++ " \"pri\" : %p,\n" \ ++ " \"dm_st\" : \"%t\"," ++ ++#define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n" ++ ++#define PRINT_JSON_PATH "{\n" \ ++ " \"dev\" : \"%d\",\n"\ ++ " \"dev_t\" : \"%D\",\n" \ ++ " \"dm_st\" : \"%t\",\n" \ ++ " \"dev_st\" : \"%o\",\n" \ ++ " \"chk_st\" : \"%T\",\n" \ ++ " \"checker\" : \"%c\",\n" \ ++ " \"pri\" : %p,\n" \ ++ " \"host_wwnn\" : \"%N\",\n" \ ++ " \"target_wwnn\" : \"%n\",\n" \ ++ " \"host_wwpn\" : \"%R\",\n" \ ++ " \"target_wwpn\" : \"%r\",\n" \ ++ " \"host_adapter\" : \"%a\"" ++ + #define MAX_LINE_LEN 80 + #define MAX_LINES 64 + #define MAX_FIELD_LEN 64 +@@ -41,6 +98,10 @@ int snprint_path (char *, int, char *, s + int snprint_multipath (char *, int, char *, struct multipath *, int); + int snprint_multipath_topology (char *, int, struct multipath * mpp, + int verbosity); ++int snprint_multipath_topology_json (char * buff, int len, ++ struct vectors * vecs); ++int snprint_multipath_map_json (char * buff, int len, ++ struct multipath * mpp, int last); + int snprint_defaults (char *, int); + int snprint_blacklist (char *, int); + int snprint_blacklist_except (char *, int); +Index: multipath-tools-130222/multipathd/cli.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.c ++++ multipath-tools-130222/multipathd/cli.c +@@ -189,6 +189,7 @@ load_keys (void) + r += add_key(keys, "setprstatus", SETPRSTATUS, 0); + r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0); + r += add_key(keys, "format", FMT, 1); ++ r += add_key(keys, "json", JSON, 0); + + if (r) { + free_keys(keys); +@@ -473,8 +474,10 @@ cli_init (void) { + add_handler(LIST+MAPS+FMT, NULL); + add_handler(LIST+MAPS+RAW+FMT, NULL); + add_handler(LIST+MAPS+TOPOLOGY, NULL); ++ add_handler(LIST+MAPS+JSON, NULL); + add_handler(LIST+TOPOLOGY, NULL); + add_handler(LIST+MAP+TOPOLOGY, NULL); ++ add_handler(LIST+MAP+JSON, NULL); + add_handler(LIST+CONFIG, NULL); + add_handler(LIST+BLACKLIST, NULL); + add_handler(LIST+DEVICES, NULL); +Index: multipath-tools-130222/multipathd/cli.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.h ++++ multipath-tools-130222/multipathd/cli.h +@@ -36,6 +36,7 @@ enum { + __SETPRSTATUS, + __UNSETPRSTATUS, + __FMT, ++ __JSON, + }; + + #define LIST (1 << __LIST) +@@ -74,6 +75,7 @@ enum { + #define SETPRSTATUS (1ULL << __SETPRSTATUS) + #define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS) + #define FMT (1ULL << __FMT) ++#define JSON (1ULL << __JSON) + + #define INITIAL_REPLY_LEN 1200 + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -127,6 +127,70 @@ show_maps_topology (char ** r, int * len + } + + int ++show_maps_json (char ** r, int * len, struct vectors * vecs) ++{ ++ int i; ++ struct multipath * mpp; ++ char * c; ++ char * reply; ++ unsigned int maxlen = INITIAL_REPLY_LEN * ++ PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec); ++ int again = 1; ++ ++ vector_foreach_slot(vecs->mpvec, mpp, i) { ++ if (update_multipath(vecs, mpp->alias, 0)) { ++ return 1; ++ } ++ } ++ ++ reply = MALLOC(maxlen); ++ ++ while (again) { ++ if (!reply) ++ return 1; ++ ++ c = reply; ++ ++ c += snprint_multipath_topology_json(c, maxlen, vecs); ++ again = ((c - reply) == maxlen); ++ ++ REALLOC_REPLY(reply, again, maxlen); ++ } ++ *r = reply; ++ *len = (int)(c - reply); ++ return 0; ++} ++ ++int ++show_map_json (char ** r, int * len, struct multipath * mpp, ++ struct vectors * vecs) ++{ ++ char * c; ++ char * reply; ++ unsigned int maxlen = INITIAL_REPLY_LEN; ++ int again = 1; ++ ++ if (update_multipath(vecs, mpp->alias, 0)) ++ return 1; ++ reply = MALLOC(maxlen); ++ ++ while (again) { ++ if (!reply) ++ return 1; ++ ++ c = reply; ++ ++ c += snprint_multipath_map_json(c, maxlen, mpp, 1); ++ again = ((c - reply) == maxlen); ++ ++ REALLOC_REPLY(reply, again, maxlen); ++ } ++ *r = reply; ++ *len = (int)(c - reply); ++ return 0; ++} ++ ++int + show_config (char ** r, int * len) + { + char * c; +@@ -239,6 +303,35 @@ cli_list_maps_topology (void * v, char * + } + + int ++cli_list_map_json (void * v, char ** reply, int * len, void * data) ++{ ++ struct multipath * mpp; ++ struct vectors * vecs = (struct vectors *)data; ++ char * param = get_keyparam(v, MAP); ++ ++ param = convert_dev(param, 0); ++ get_path_layout(vecs->pathvec, 0); ++ mpp = find_mp_by_str(vecs->mpvec, param); ++ ++ if (!mpp) ++ return 1; ++ ++ condlog(3, "list multipath json %s (operator)", param); ++ ++ return show_map_json(reply, len, mpp, vecs); ++} ++ ++int ++cli_list_maps_json (void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ ++ condlog(3, "list multipaths json (operator)"); ++ ++ return show_maps_json(reply, len, vecs); ++} ++ ++int + cli_list_wildcards (void * v, char ** reply, int * len, void * data) + { + char * c; +Index: multipath-tools-130222/multipathd/cli_handlers.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.h ++++ multipath-tools-130222/multipathd/cli_handlers.h +@@ -10,6 +10,8 @@ int cli_list_maps_status (void * v, char + int cli_list_maps_stats (void * v, char ** reply, int * len, void * data); + int cli_list_map_topology (void * v, char ** reply, int * len, void * data); + int cli_list_maps_topology (void * v, char ** reply, int * len, void * data); ++int cli_list_map_json (void * v, char ** reply, int * len, void * data); ++int cli_list_maps_json (void * v, char ** reply, int * len, void * data); + int cli_list_config (void * v, char ** reply, int * len, void * data); + int cli_list_blacklist (void * v, char ** reply, int * len, void * data); + int cli_list_devices (void * v, char ** reply, int * len, void * data); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -981,7 +981,9 @@ uxlsnrloop (void * ap) + set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw); + set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology); + set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology); ++ set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json); + set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology); ++ set_handler_callback(LIST+MAP+JSON, cli_list_map_json); + set_handler_callback(LIST+CONFIG, cli_list_config); + set_handler_callback(LIST+BLACKLIST, cli_list_blacklist); + set_handler_callback(LIST+DEVICES, cli_list_devices); +Index: multipath-tools-130222/multipathd/multipathd.8 +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.8 ++++ multipath-tools-130222/multipathd/multipathd.8 +@@ -53,11 +53,15 @@ using a format string with multipath for + Show the status of all multipath devices that the multipathd is monitoring. + .TP + .B list|show maps|multipaths stats +-Show some statistics of all multipath devices that the multipathd is monitoring. ++Show some statistics of all multipath devices that multipathd is monitoring. + .TP + .B list|show maps|multipaths topology + Show the current multipath topology. Same as "multipath \-ll". + .TP ++.B list|show maps|multipaths json ++Show the multipath devices that multipathd is monitoring, using JSON ++formatted output. ++.TP + .B list|show topology + Show the current multipath topology. Same as "multipath \-ll". + .TP +@@ -65,6 +69,9 @@ Show the current multipath topology. Sam + Show topology of a single multipath device specified by $map, e.g. 36005076303ffc56200000000000010aa. + This map could be obtained from "list maps". + .TP ++.B list|show map|multipath $map json ++Show a single multipath device specified by $map, using JSON formatted output. ++.TP + .B list|show wildcards + Show the format wildcards used in interactive commands taking $format + .TP diff --git a/SOURCES/0170-UPBZ-1352925-fix-typo.patch b/SOURCES/0170-UPBZ-1352925-fix-typo.patch new file mode 100644 index 0000000..2521c3d --- /dev/null +++ b/SOURCES/0170-UPBZ-1352925-fix-typo.patch @@ -0,0 +1,26 @@ +--- + multipath/main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -286,7 +286,7 @@ configure (void) + if (failed == 2 && conf->cmd == CMD_VALID_PATH) + printf("%s is not a valid multipath device path\n", conf->dev); + else +- condlog(3, "scope is nul"); ++ condlog(3, "scope is null"); + goto out; + } + if (conf->cmd == CMD_REMOVE_WWID) { +@@ -358,7 +358,7 @@ configure (void) + + + if (conf->cmd == CMD_VALID_PATH) { +- /* This only happens if find_multipaths is and ++ /* This only happens if find_multipaths and + * ignore_wwids is set. + * If there is currently a multipath device matching + * the refwwid, or there is more than one path matching diff --git a/SOURCES/0171-UPBZ-1356651-allow-zero-size.patch b/SOURCES/0171-UPBZ-1356651-allow-zero-size.patch new file mode 100644 index 0000000..0fe05b5 --- /dev/null +++ b/SOURCES/0171-UPBZ-1356651-allow-zero-size.patch @@ -0,0 +1,79 @@ +--- + libmultipath/discovery.c | 5 +++++ + libmultipath/structs_vec.c | 2 +- + multipathd/main.c | 26 +++++--------------------- + 3 files changed, 11 insertions(+), 22 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1188,6 +1188,11 @@ pathinfo (struct path *pp, vector hwtabl + if (pp->state == PATH_UNCHECKED || + pp->state == PATH_WILD) + goto blank; ++ if (pp->state == PATH_UP && !pp->size) { ++ condlog(3, "%s: device size is 0, " ++ "path unuseable", pp->dev); ++ pp->state = PATH_GHOST; ++ } + } else { + condlog(3, "%s: path inaccessible", pp->dev); + pp->chkrstate = pp->state = path_state; +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -551,7 +551,7 @@ int update_multipath (struct vectors *ve + + if (pp->state != PATH_DOWN) { + int oldstate = pp->state; +- condlog(2, "%s: mark as failed", pp->dev_t); ++ condlog(2, "%s: mark as failed", pp->dev); + mpp->stat_path_failures++; + pp->state = PATH_DOWN; + if (oldstate == PATH_UP || +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -538,15 +538,10 @@ ev_add_path (struct path * pp, struct ve + pp->mpp = mpp; + rescan: + if (mpp) { +- if ((!pp->size) || (mpp->size != pp->size)) { +- if (!pp->size) +- condlog(0, "%s: failed to add new path %s, " +- "device size is 0", +- mpp->alias, pp->dev); +- else +- condlog(0, "%s: failed to add new path %s, " +- "device size mismatch", +- mpp->alias, pp->dev); ++ if (pp->size && mpp->size != pp->size) { ++ condlog(0, "%s: failed to add new path %s, " ++ "device size mismatch", ++ mpp->alias, pp->dev); + int i = find_slot(vecs->pathvec, (void *)pp); + if (i != -1) + vector_del_slot(vecs->pathvec, i); +@@ -563,18 +558,7 @@ rescan: + verify_paths(mpp, vecs, NULL); + mpp->flush_on_last_del = FLUSH_UNDEF; + mpp->action = ACT_RELOAD; +- } +- else { +- if (!pp->size) { +- condlog(0, "%s: failed to create new map," +- " device size is 0 ", pp->dev); +- int i = find_slot(vecs->pathvec, (void *)pp); +- if (i != -1) +- vector_del_slot(vecs->pathvec, i); +- free_path(pp); +- return 1; +- } +- ++ } else { + if (!should_multipath(pp, vecs->pathvec)) { + orphan_path(pp); + return 0; diff --git a/SOURCES/0172-RHBZ-1350931-no-active-add.patch b/SOURCES/0172-RHBZ-1350931-no-active-add.patch new file mode 100644 index 0000000..4e79e32 --- /dev/null +++ b/SOURCES/0172-RHBZ-1350931-no-active-add.patch @@ -0,0 +1,37 @@ +--- + multipathd/main.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -530,9 +530,15 @@ ev_add_path (struct path * pp, struct ve + } + mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); + if (mpp && mpp->wait_for_udev) { +- mpp->wait_for_udev = 2; +- orphan_path(pp); +- return 0; ++ if (pathcount(mpp, PATH_UP) == 0 && ++ (pathcount(mpp, PATH_GHOST) == 0 || ++ pp->tpgs == TPGS_IMPLICIT)) ++ mpp->force_udev_reload = 1; ++ else { ++ mpp->wait_for_udev = 2; ++ orphan_path(pp); ++ return 0; ++ } + } + + pp->mpp = mpp; +@@ -551,7 +557,8 @@ rescan: + + condlog(4,"%s: adopting all paths for path %s", + mpp->alias, pp->dev); +- mpp->force_udev_reload = !pathcount(mpp, PATH_WILD); ++ if (pathcount(mpp, PATH_WILD) == 0) ++ mpp->force_udev_reload = 1; + if (adopt_paths(vecs->pathvec, mpp, 1)) + goto fail; /* leave path added to pathvec */ + diff --git a/SOURCES/0173-RH-update-man-page.patch b/SOURCES/0173-RH-update-man-page.patch new file mode 100644 index 0000000..80c6dbf --- /dev/null +++ b/SOURCES/0173-RH-update-man-page.patch @@ -0,0 +1,99 @@ +--- + multipath/multipath.conf.5 | 56 ++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 51 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -240,18 +240,21 @@ Specify any device-mapper features to be + .I num list + where + .I num +-is the number of features in ++is the number, between 0 and 6, of features in + .I list. +-Possible values for the feature list are ++Possible values for the feature list are: + .RS + .TP 12 +-.B queue_if_no_path ++.I queue_if_no_path + Queue IO if no path is active; identical to the + .I no_path_retry + keyword. + .TP +-.B no_partitions +-Disable automatic partitions generation via kpartx. ++.I pg_init_retries ++Number of times to retry pg_init, it must be between 1 and 50. ++.TP ++.I pg_init_delay_msecs ++Number of msecs before pg_init retry, it must be between 0 and 60000. + .RE + .TP + .B path_checker +@@ -511,6 +514,45 @@ If set to + .I yes + , kpartx will not automatically create partitions on the device. The default is + .I no ++.TP ++.B ignore_new_boot_devs ++If set to ++.I yes ++, multipath will never attempt to create a multipath device whose wwid is not ++listed in /etc/multipath/wwids, while running in the initramfs. This keeps ++multipath from adding new devices during the initramfs portion of bootup. The ++default is ++.I no ++.TP ++.B retrigger_tries ++This sets how many times multipathd will reissue change uevents on block ++devices that are not blacklisted, but have no wwid set by udev. Multipath ++assumes that any devices that should not report a wwid are blacklisted. This ++means that if a non-blacklisted device has no wwid, it is likely that udev ++timed out while processing it. Multipathd will wait for a while, and then ++reissue a change uevent to give udev another chance to set the wwid. The ++default is ++.I 3 ++.TP ++.B retrigger_delay ++This sets how long multipathd should wait, after receiving a uevent for a ++non-blacklisted device without a wwid set by udev, before reissuing a ++change uevent. The goal of this delay is to give udev a chance to finish ++processing its current batch of uevents before sending more, to hopefully ++avoid it timing out. The default is ++.I 10 ++.TP ++.B new_bindings_in_boot ++If set to ++.I yes ++, multipath will allow new user_friendly_names bindings to be created while ++running in the initramfs. Otherwise, multipath will not create ++user_friendly_names bindings while running in the initramfs. Instead, it will ++use the WWID for the name of a device that was configured to use ++user_friendly_names. When multipathd is restarted later in boot on the ++regular filesystem, the device will be renamed to a user_friendly_name. The ++default is ++.I no + . + .SH "blacklist section" + The +@@ -603,6 +645,8 @@ section: + .TP + .B flush_on_last_del + .TP ++.B user_friendly_names ++.TP + .B no_path_retry + .TP + .B rr_min_io +@@ -697,6 +741,8 @@ section: + .TP + .B no_path_retry + .TP ++.B user_friendly_names ++.TP + .B rr_min_io + .TP + .B rr_min_io_rq diff --git a/SOURCES/0174-RHBZ-1362396-modprobe.patch b/SOURCES/0174-RHBZ-1362396-modprobe.patch new file mode 100644 index 0000000..509510c --- /dev/null +++ b/SOURCES/0174-RHBZ-1362396-modprobe.patch @@ -0,0 +1,16 @@ +--- + multipathd/multipathd.init.redhat | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/multipathd/multipathd.init.redhat +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.init.redhat ++++ multipath-tools-130222/multipathd/multipathd.init.redhat +@@ -67,6 +67,7 @@ popd > /dev/null + start() { + test -x $DAEMON || exit 5 + echo -n $"Starting $prog daemon: " ++ modprobe dm-multipath >/dev/null 2>&1 + daemon $DAEMON + RETVAL=$? + [ $RETVAL -eq 0 ] && touch $lockdir/$prog diff --git a/SOURCES/0175-RHBZ-1357382-ordering.patch b/SOURCES/0175-RHBZ-1357382-ordering.patch new file mode 100644 index 0000000..c778596 --- /dev/null +++ b/SOURCES/0175-RHBZ-1357382-ordering.patch @@ -0,0 +1,17 @@ +--- + multipathd/multipathd.service | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/multipathd.service +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.service ++++ multipath-tools-130222/multipathd/multipathd.service +@@ -2,7 +2,7 @@ + Description=Device-Mapper Multipath Device Controller + Wants=blk-availability.service + Before=iscsi.service iscsid.service lvm2-activation-early.service +-After=syslog.target ++After=syslog.target systemd-udev-trigger.service + ConditionPathExists=/etc/multipath.conf + ConditionKernelCommandLine=!nompath + DefaultDependencies=no diff --git a/SOURCES/0176-RHBZ-1363830-fix-rename.patch b/SOURCES/0176-RHBZ-1363830-fix-rename.patch new file mode 100644 index 0000000..428b2f1 --- /dev/null +++ b/SOURCES/0176-RHBZ-1363830-fix-rename.patch @@ -0,0 +1,17 @@ +--- + libmultipath/devmapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -1387,7 +1387,7 @@ dm_rename (const char * old, char * new, + { + int r = 0; + struct dm_task *dmt; +- uint32_t cookie; ++ uint32_t cookie = 0; + uint16_t udev_flags = ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0); + + if (dm_rename_partmaps(old, new)) diff --git a/SOURCES/0177-libmultipath-correctly-initialize-pp-sg_id.patch b/SOURCES/0177-libmultipath-correctly-initialize-pp-sg_id.patch new file mode 100644 index 0000000..1c927be --- /dev/null +++ b/SOURCES/0177-libmultipath-correctly-initialize-pp-sg_id.patch @@ -0,0 +1,38 @@ +From e2b87038125c79089e0bd4c6fd905667c5108740 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Tue, 9 Aug 2016 13:36:04 -0500 +Subject: [PATCH 01/11] libmultipath: correctly initialize pp->sg_id + +For BZ 1348372 from upstream: + +commit b4d9ca8dc8bbfbd3782bf4cf2cb1a440685ccd07 +Author: Hannes Reinecke +Date: Wed Nov 11 13:38:57 2015 +0100 + + libmultipath: correctly initialize pp->sg_id + + The default SCSI protocol is 'SCSI_PROTOCOL_UNSPEC'; + '0' is SCSI_PROTOCOL_FCP. + + Signed-off-by: Hannes Reinecke + +Signed-off-by: Mike Christie +--- + libmultipath/structs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libmultipath/structs.c b/libmultipath/structs.c +index 30d247d..26a6a3b 100644 +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -94,6 +94,7 @@ alloc_path (void) + pp->sg_id.channel = -1; + pp->sg_id.scsi_id = -1; + pp->sg_id.lun = -1; ++ pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC; + pp->fd = -1; + pp->priority = PRIO_UNDEF; + } +-- +1.8.3.1 + diff --git a/SOURCES/0178-libmultipath-add-rbd-discovery.patch b/SOURCES/0178-libmultipath-add-rbd-discovery.patch new file mode 100644 index 0000000..6930e46 --- /dev/null +++ b/SOURCES/0178-libmultipath-add-rbd-discovery.patch @@ -0,0 +1,219 @@ +From 2fc494b81157059e0be66022f6a2110f1ce179c3 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Tue, 9 Aug 2016 13:44:10 -0500 +Subject: [PATCH 02/11] libmultipath: add rbd discovery + +For BZ 1348372 from upstream commit: + +Commit 152f3f803ee922075e8b25027eb9dc5699f1aefa +Author: Mike Christie +Date: Mon Aug 8 07:01:47 2016 -0500 + + libmultipath: add rbd discovery + + rbd is a block device interface for Ceph. It does not support + any SCSI commands, so this patch adds bus detection and virtual + vendor/product pathinfo. + +-------- + +Porting notes: + +get_uid() chunk does not match upstream due to rhel not having +the get uid callout code and sysfs uid detection code. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers.h | 1 + + libmultipath/discovery.c | 116 ++++++++++++++++++++++++++++++++++++++++------- + libmultipath/structs.h | 1 + + 3 files changed, 101 insertions(+), 17 deletions(-) + +diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h +index f6fe326..735bb25 100644 +--- a/libmultipath/checkers.h ++++ b/libmultipath/checkers.h +@@ -75,6 +75,7 @@ enum path_check_state { + #define EMC_CLARIION "emc_clariion" + #define READSECTOR0 "readsector0" + #define CCISS_TUR "cciss_tur" ++#define RBD "rbd" + + #define DEFAULT_CHECKER DIRECTIO + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index 7a8282b..1b9f390 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -781,6 +781,21 @@ scsi_sysfs_pathinfo (struct path * pp) + } + + static int ++rbd_sysfs_pathinfo (struct path * pp) ++{ ++ sprintf(pp->vendor_id, "Ceph"); ++ sprintf(pp->product_id, "RBD"); ++ ++ condlog(3, "%s: vendor = %s product = %s", pp->dev, pp->vendor_id, ++ pp->product_id); ++ /* ++ * set the hwe configlet pointer ++ */ ++ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL); ++ return 0; ++} ++ ++static int + ccw_sysfs_pathinfo (struct path * pp) + { + struct udev_device *parent; +@@ -974,6 +989,8 @@ sysfs_pathinfo(struct path * pp) + pp->bus = SYSFS_BUS_CCW; + if (!strncmp(pp->dev,"sd", 2)) + pp->bus = SYSFS_BUS_SCSI; ++ if (!strncmp(pp->dev,"rbd", 3)) ++ pp->bus = SYSFS_BUS_RBD; + + if (pp->bus == SYSFS_BUS_UNDEF) + return 0; +@@ -986,6 +1003,9 @@ sysfs_pathinfo(struct path * pp) + } else if (pp->bus == SYSFS_BUS_CCISS) { + if (cciss_sysfs_pathinfo(pp)) + return 1; ++ } else if (pp->bus == SYSFS_BUS_RBD) { ++ if (rbd_sysfs_pathinfo(pp)) ++ return 1; + } + return 0; + } +@@ -1087,10 +1107,60 @@ get_prio (struct path * pp) + } + + static int ++get_rbd_uid(struct path * pp) ++{ ++ struct udev_device *rbd_bus_dev; ++ int ret, rbd_bus_id; ++ const char *pool, *image, *snap; ++ char sysfs_path[PATH_SIZE]; ++ uint64_t snap_id, max_snap_id = -3; ++ ++ ret = sscanf(pp->dev, "rbd%d", &rbd_bus_id); ++ if (ret != 1) ++ return -EINVAL; ++ ++ snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/rbd/devices/%d", ++ rbd_bus_id); ++ rbd_bus_dev = udev_device_new_from_syspath(conf->udev, sysfs_path); ++ if (!rbd_bus_dev) ++ return -ENODEV; ++ ++ ret = -EINVAL; ++ pool = udev_device_get_sysattr_value(rbd_bus_dev, "pool_id"); ++ if (!pool) ++ goto free_dev; ++ ++ image = udev_device_get_sysattr_value(rbd_bus_dev, "image_id"); ++ if (!image) ++ goto free_dev; ++ ++ snap = udev_device_get_sysattr_value(rbd_bus_dev, "snap_id"); ++ if (!snap) ++ goto free_dev; ++ snap_id = strtoull(snap, NULL, 19); ++ if (snap_id >= max_snap_id) ++ ret = snprintf(pp->wwid, WWID_SIZE, "%s-%s", pool, image); ++ else ++ ret = snprintf(pp->wwid, WWID_SIZE, "%s-%s-%s", pool, ++ image, snap); ++ if (ret < WWID_SIZE) { ++ ret = 0; ++ } else { ++ condlog(0, "%s: wwid overflow", pp->dev); ++ ret = -EOVERFLOW; ++ } ++ ++free_dev: ++ udev_device_unref(rbd_bus_dev); ++ return ret; ++} ++ ++static int + get_uid (struct path * pp) + { + char *c; + const char *value; ++ int ret; + + if (!pp->uid_attribute) + select_getuid(pp); +@@ -1101,25 +1171,37 @@ get_uid (struct path * pp) + } + + memset(pp->wwid, 0, WWID_SIZE); +- value = udev_device_get_property_value(pp->udev, pp->uid_attribute); +- if ((!value || strlen(value) == 0) && conf->cmd == CMD_VALID_PATH) +- value = getenv(pp->uid_attribute); +- if (value && strlen(value)) { +- size_t len = WWID_SIZE; +- +- if (strlen(value) + 1 > WWID_SIZE) { +- condlog(0, "%s: wwid overflow", pp->dev); +- } else { +- len = strlen(value); ++ if (pp->bus == SYSFS_BUS_RBD) { ++ ret = get_rbd_uid(pp); ++ if (ret) { ++ condlog(1, "%s: failed to get sysfs uid: %s", ++ pp->dev, strerror(-ret)); ++ pp->missing_udev_info = INFO_MISSING; ++ pp->tick = conf->retrigger_delay; + } +- strncpy(pp->wwid, value, len); +- pp->missing_udev_info = INFO_OK; +- pp->tick = 0; + } else { +- condlog(3, "%s: no %s attribute", pp->dev, +- pp->uid_attribute); +- pp->missing_udev_info = INFO_MISSING; +- pp->tick = conf->retrigger_delay; ++ value = udev_device_get_property_value(pp->udev, ++ pp->uid_attribute); ++ if ((!value || strlen(value) == 0) && ++ conf->cmd == CMD_VALID_PATH) ++ value = getenv(pp->uid_attribute); ++ if (value && strlen(value)) { ++ size_t len = WWID_SIZE; ++ ++ if (strlen(value) + 1 > WWID_SIZE) { ++ condlog(0, "%s: wwid overflow", pp->dev); ++ } else { ++ len = strlen(value); ++ } ++ strncpy(pp->wwid, value, len); ++ pp->missing_udev_info = INFO_OK; ++ pp->tick = 0; ++ } else { ++ condlog(3, "%s: no %s attribute", pp->dev, ++ pp->uid_attribute); ++ pp->missing_udev_info = INFO_MISSING; ++ pp->tick = conf->retrigger_delay; ++ } + } + + /* Strip any trailing blanks */ +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index b5b4567..e566462 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -52,6 +52,7 @@ enum sysfs_buses { + SYSFS_BUS_IDE, + SYSFS_BUS_CCW, + SYSFS_BUS_CCISS, ++ SYSFS_BUS_RBD, + }; + + enum pathstates { +-- +1.8.3.1 + diff --git a/SOURCES/0179-multipath-tools-add-checker-callout-to-repair-path.patch b/SOURCES/0179-multipath-tools-add-checker-callout-to-repair-path.patch new file mode 100644 index 0000000..8b48f7d --- /dev/null +++ b/SOURCES/0179-multipath-tools-add-checker-callout-to-repair-path.patch @@ -0,0 +1,250 @@ +From 1073621a7a63ca4e9a00baedd8edc51e5381eb95 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Tue, 9 Aug 2016 13:46:11 -0500 +Subject: [PATCH 03/11] multipath-tools: add checker callout to repair path + +For BZ 1348372 from upstream commit: + +commit 015f87b16a7797a17afd514aec46e65c2a1a2f73 +Author: Mike Christie +Date: Mon Aug 8 07:01:48 2016 -0500 + + multipath-tools: add checker callout to repair path + + This patch adds a callback which can be used to repair a path + if check() has determined it is in the PATH_DOWN state. + + The next patch that adds rbd checker support which will use this to + handle the case where a rbd device is blacklisted. + +-------- + +Porting notes: +checkerloop difference due to different path tracking. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers.c | 23 +++++++++++++++++++++++ + libmultipath/checkers.h | 4 ++++ + libmultipath/checkers/cciss_tur.c | 5 +++++ + libmultipath/checkers/directio.c | 5 +++++ + libmultipath/checkers/emc_clariion.c | 5 +++++ + libmultipath/checkers/hp_sw.c | 5 +++++ + libmultipath/checkers/rdac.c | 5 +++++ + libmultipath/checkers/readsector0.c | 5 +++++ + libmultipath/checkers/tur.c | 5 +++++ + multipathd/main.c | 9 +++++++++ + 10 files changed, 71 insertions(+) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index 7f9db2d..fa7d8b7 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -137,6 +137,14 @@ struct checker * add_checker (char * name) + if (!c->free) + goto out; + ++ c->repair = (void (*)(struct checker *)) dlsym(c->handle, ++ "libcheck_repair"); ++ errstr = dlerror(); ++ if (errstr != NULL) ++ condlog(0, "A dynamic linking error occurred: (%s)", errstr); ++ if (!c->repair) ++ goto out; ++ + c->fd = 0; + c->sync = 1; + list_add(&c->node, &checkers); +@@ -202,6 +210,20 @@ void checker_put (struct checker * dst) + free_checker(src); + } + ++void checker_repair (struct checker * c) ++{ ++ if (!c) ++ return; ++ ++ c->message[0] = '\0'; ++ if (c->disable) { ++ MSG(c, "checker disabled"); ++ return; ++ } ++ ++ c->repair(c); ++} ++ + int checker_check (struct checker * c) + { + int r; +@@ -266,6 +288,7 @@ void checker_get (struct checker * dst, char * name) + dst->sync = src->sync; + strncpy(dst->name, src->name, CHECKER_NAME_LEN); + strncpy(dst->message, src->message, CHECKER_MSG_LEN); ++ dst->repair = src->repair; + dst->check = src->check; + dst->init = src->init; + dst->free = src->free; +diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h +index 735bb25..ad3b9e4 100644 +--- a/libmultipath/checkers.h ++++ b/libmultipath/checkers.h +@@ -106,6 +106,9 @@ struct checker { + multipath-wide. Use MALLOC if + you want to stuff data in. */ + int (*check)(struct checker *); ++ void (*repair)(struct checker *); /* called if check returns ++ PATH_DOWN to bring path into ++ usable state */ + int (*init)(struct checker *); /* to allocate the context */ + void (*free)(struct checker *); /* to free the context */ + }; +@@ -125,6 +128,7 @@ void checker_set_async (struct checker *); + void checker_set_fd (struct checker *, int); + void checker_enable (struct checker *); + void checker_disable (struct checker *); ++void checker_repair (struct checker *); + int checker_check (struct checker *); + int checker_selected (struct checker *); + char * checker_name (struct checker *); +diff --git a/libmultipath/checkers/cciss_tur.c b/libmultipath/checkers/cciss_tur.c +index 4c26901..7e4eb81 100644 +--- a/libmultipath/checkers/cciss_tur.c ++++ b/libmultipath/checkers/cciss_tur.c +@@ -63,6 +63,11 @@ void libcheck_free (struct checker * c) + return; + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + extern int + libcheck_check (struct checker * c) + { +diff --git a/libmultipath/checkers/directio.c b/libmultipath/checkers/directio.c +index 46fe6a7..1a997ed 100644 +--- a/libmultipath/checkers/directio.c ++++ b/libmultipath/checkers/directio.c +@@ -116,6 +116,11 @@ void libcheck_free (struct checker * c) + free(ct); + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + static int + check_state(int fd, struct directio_context *ct, int sync, int timeout_secs) + { +diff --git a/libmultipath/checkers/emc_clariion.c b/libmultipath/checkers/emc_clariion.c +index b42d267..43b5025 100644 +--- a/libmultipath/checkers/emc_clariion.c ++++ b/libmultipath/checkers/emc_clariion.c +@@ -90,6 +90,11 @@ void libcheck_free (struct checker * c) + free(c->context); + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + int libcheck_check (struct checker * c) + { + unsigned char sense_buffer[128] = { 0, }; +diff --git a/libmultipath/checkers/hp_sw.c b/libmultipath/checkers/hp_sw.c +index b50ac0c..857ac5e 100644 +--- a/libmultipath/checkers/hp_sw.c ++++ b/libmultipath/checkers/hp_sw.c +@@ -44,6 +44,11 @@ void libcheck_free (struct checker * c) + return; + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + static int + do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, + void *resp, int mx_resp_len, int noisy, unsigned int timeout) +diff --git a/libmultipath/checkers/rdac.c b/libmultipath/checkers/rdac.c +index f0e0af3..5469e61 100644 +--- a/libmultipath/checkers/rdac.c ++++ b/libmultipath/checkers/rdac.c +@@ -139,6 +139,11 @@ void libcheck_free (struct checker * c) + return; + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + static int + do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len, + unsigned int timeout) +diff --git a/libmultipath/checkers/readsector0.c b/libmultipath/checkers/readsector0.c +index 0550fb6..b3ed1f3 100644 +--- a/libmultipath/checkers/readsector0.c ++++ b/libmultipath/checkers/readsector0.c +@@ -23,6 +23,11 @@ void libcheck_free (struct checker * c) + return; + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + int libcheck_check (struct checker * c) + { + unsigned char buf[4096]; +diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c +index 1e5b039..91f1458 100644 +--- a/libmultipath/checkers/tur.c ++++ b/libmultipath/checkers/tur.c +@@ -187,6 +187,11 @@ void libcheck_free (struct checker * c) + return; + } + ++void libcheck_repair (struct checker * c) ++{ ++ return; ++} ++ + #define TUR_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args); + + int +diff --git a/multipathd/main.c b/multipathd/main.c +index 8808c88..d26fd22 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1455,6 +1455,14 @@ check_path (struct vectors * vecs, struct path * pp) + } + } + ++void repair_path(struct vectors * vecs, struct path * pp) ++{ ++ if (pp->state != PATH_DOWN) ++ return; ++ ++ checker_repair(&pp->checker); ++} ++ + static void * + checkerloop (void *ap) + { +@@ -1483,6 +1491,7 @@ checkerloop (void *ap) + if (vecs->pathvec) { + vector_foreach_slot (vecs->pathvec, pp, i) { + check_path(vecs, pp); ++ repair_path(vecs, pp); + } + } + if (vecs->mpvec) { +-- +1.8.3.1 + diff --git a/SOURCES/0180-multipath-tools-Add-rbd-checker.patch b/SOURCES/0180-multipath-tools-Add-rbd-checker.patch new file mode 100644 index 0000000..cf8a752 --- /dev/null +++ b/SOURCES/0180-multipath-tools-Add-rbd-checker.patch @@ -0,0 +1,746 @@ +From e28c340ed961409700d46a1cb9a820a8b7a4d016 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Thu, 11 Aug 2016 02:12:12 -0500 +Subject: [PATCH 04/11] multipath-tools: Add rbd checker. + +For BZ 1348372 from upstream commit: + +commit d1cad5649b6fcf9027d43ca0405c900080133e32 +Author: Mike Christie +Date: Mon Aug 8 07:01:49 2016 -0500 + + multipath-tools: Add rbd checker. + + This checker currently only handles the case where a path is failed + due to it being blacklisted by the ceph cluster. The specific use + case for me is when LIO exports rbd images through multiple LIO + instances. + + The problem it handles is when rbd instance1 has the exclusive lock, + but becomes unreachable another host in the cluster will take over + and blacklist the instance1. This prevents it from sending stale IO + and corrupting data. + + Later, when the host is reachable, we will want to failback to it. + To this, the checker will detect we were blacklisted, unmap the old + image which will make sure old IO is failed, and then remap the +image + and unblacklist the host. multipathd will then handle this like a + path being removed and re-added. + +-------- + +Porting notes: +Added rbd to multipath.conf.annotated. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers/Makefile | 7 + libmultipath/checkers/rbd.c | 639 +++++++++++++++++++++++++++++++++++++++++ + multipath.conf.annotated | 4 + multipath/multipath.conf.5 | 3 + 4 files changed, 651 insertions(+), 2 deletions(-) + create mode 100644 libmultipath/checkers/rbd.c + +Index: multipath-tools-130222/libmultipath/checkers/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/Makefile ++++ multipath-tools-130222/libmultipath/checkers/Makefile +@@ -14,10 +14,17 @@ LIBS= \ + libcheckhp_sw.so \ + libcheckrdac.so + ++ifeq ($(shell test -r /usr/include/rados/librados.h && echo 1),1) ++LIBS += libcheckrbd.so ++endif ++ + CFLAGS += -fPIC -I.. + + all: $(LIBS) + ++libcheckrbd.so: rbd.o ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lrados -ludev ++ + libcheckdirectio.so: libsg.o directio.o + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio + +Index: multipath-tools-130222/libmultipath/checkers/rbd.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/checkers/rbd.c +@@ -0,0 +1,639 @@ ++/* ++ * Copyright (c) 2016 Red Hat ++ * Copyright (c) 2004 Christophe Varoqui ++ * ++ * Code based off of tur.c and ceph's krbd.cc ++ */ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rados/librados.h" ++ ++#include "structs.h" ++#include "checkers.h" ++ ++#include "../libmultipath/debug.h" ++#include "../libmultipath/uevent.h" ++ ++struct rbd_checker_context; ++typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg); ++ ++#define RBD_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args); ++ ++struct rbd_checker_context { ++ int rbd_bus_id; ++ char *client_addr; ++ char *config_info; ++ char *snap; ++ char *pool; ++ char *image; ++ char *username; ++ int remapped; ++ int blacklisted; ++ ++ rados_t cluster; ++ ++ int state; ++ int running; ++ time_t time; ++ thread_fn *fn; ++ pthread_t thread; ++ pthread_mutex_t lock; ++ pthread_cond_t active; ++ pthread_spinlock_t hldr_lock; ++ int holders; ++ char message[CHECKER_MSG_LEN]; ++}; ++ ++int libcheck_init(struct checker * c) ++{ ++ struct rbd_checker_context *ct; ++ struct udev_device *block_dev; ++ struct udev_device *bus_dev; ++ struct udev *udev; ++ struct stat sb; ++ const char *block_name, *addr, *config_info; ++ const char *image, *pool, *snap, *username; ++ char sysfs_path[PATH_SIZE]; ++ int ret; ++ ++ ct = malloc(sizeof(struct rbd_checker_context)); ++ if (!ct) ++ return 1; ++ memset(ct, 0, sizeof(struct rbd_checker_context)); ++ ct->holders = 1; ++ pthread_cond_init(&ct->active, NULL); ++ pthread_mutex_init(&ct->lock, NULL); ++ pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE); ++ c->context = ct; ++ ++ /* ++ * The rbd block layer sysfs device is not linked to the rbd bus ++ * device that we interact with, so figure that out now. ++ */ ++ if (fstat(c->fd, &sb) != 0) ++ goto free_ct; ++ ++ udev = udev_new(); ++ if (!udev) ++ goto free_ct; ++ ++ block_dev = udev_device_new_from_devnum(udev, 'b', sb.st_rdev); ++ if (!block_dev) ++ goto free_udev; ++ ++ block_name = udev_device_get_sysname(block_dev); ++ ret = sscanf(block_name, "rbd%d", &ct->rbd_bus_id); ++ ++ udev_device_unref(block_dev); ++ if (ret != 1) ++ goto free_udev; ++ ++ snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/rbd/devices/%d", ++ ct->rbd_bus_id); ++ bus_dev = udev_device_new_from_syspath(udev, sysfs_path); ++ if (!bus_dev) ++ goto free_udev; ++ ++ addr = udev_device_get_sysattr_value(bus_dev, "client_addr"); ++ if (!addr) { ++ condlog(0, "Could not find client_addr in rbd sysfs. Try " ++ "updating kernel"); ++ goto free_dev; ++ } ++ ++ ct->client_addr = strdup(addr); ++ if (!ct->client_addr) ++ goto free_dev; ++ ++ config_info = udev_device_get_sysattr_value(bus_dev, "config_info"); ++ if (!config_info) ++ goto free_addr; ++ ++ ct->config_info = strdup(config_info); ++ if (!ct->config_info) ++ goto free_addr; ++ ++ username = strstr(config_info, "name="); ++ if (username) { ++ char *end; ++ int len; ++ ++ username += 5; ++ end = strchr(username, ','); ++ if (!end) ++ goto free_info; ++ len = end - username; ++ ++ ct->username = malloc(len + 1); ++ if (!ct->username) ++ goto free_info; ++ strncpy(ct->username, username, len); ++ ct->username[len] = '\0'; ++ } ++ ++ image = udev_device_get_sysattr_value(bus_dev, "name"); ++ if (!image) ++ goto free_username; ++ ++ ct->image = strdup(image); ++ if (!ct->image) ++ goto free_info; ++ ++ pool = udev_device_get_sysattr_value(bus_dev, "pool"); ++ if (!pool) ++ goto free_image; ++ ++ ct->pool = strdup(pool); ++ if (!ct->pool) ++ goto free_image; ++ ++ snap = udev_device_get_sysattr_value(bus_dev, "current_snap"); ++ if (!snap) ++ goto free_pool; ++ ++ if (strcmp("-", snap)) { ++ ct->snap = strdup(snap); ++ if (!ct->snap) ++ goto free_pool; ++ } ++ ++ if (rados_create(&ct->cluster, NULL) < 0) { ++ condlog(0, "Could not create rados cluster"); ++ goto free_snap; ++ } ++ ++ if (rados_conf_read_file(ct->cluster, NULL) < 0) { ++ condlog(0, "Could not read rados conf"); ++ goto shutdown_rados; ++ } ++ ++ ret = rados_connect(ct->cluster); ++ if (ret < 0) { ++ condlog(0, "Could not connect to rados cluster"); ++ goto shutdown_rados; ++ } ++ ++ udev_device_unref(bus_dev); ++ udev_unref(udev); ++ ++ condlog(3, "rbd%d checker init %s %s/%s@%s %s", ct->rbd_bus_id, ++ ct->client_addr, ct->pool, ct->image, ct->snap ? ct->snap : "-", ++ ct->username ? ct->username : "none"); ++ return 0; ++ ++shutdown_rados: ++ rados_shutdown(ct->cluster); ++free_snap: ++ if (ct->snap) ++ free(ct->snap); ++free_pool: ++ free(ct->pool); ++free_image: ++ free(ct->image); ++free_username: ++ if (ct->username) ++ free(ct->username); ++free_info: ++ free(ct->config_info); ++free_addr: ++ free(ct->client_addr); ++free_dev: ++ udev_device_unref(bus_dev); ++free_udev: ++ udev_unref(udev); ++free_ct: ++ free(ct); ++ return 1; ++} ++ ++void cleanup_context(struct rbd_checker_context *ct) ++{ ++ pthread_mutex_destroy(&ct->lock); ++ pthread_cond_destroy(&ct->active); ++ pthread_spin_destroy(&ct->hldr_lock); ++ ++ rados_shutdown(ct->cluster); ++ ++ if (ct->username) ++ free(ct->username); ++ if (ct->snap) ++ free(ct->snap); ++ free(ct->pool); ++ free(ct->image); ++ free(ct->config_info); ++ free(ct->client_addr); ++ free(ct); ++} ++ ++void libcheck_free(struct checker * c) ++{ ++ if (c->context) { ++ struct rbd_checker_context *ct = c->context; ++ int holders; ++ pthread_t thread; ++ ++ pthread_spin_lock(&ct->hldr_lock); ++ ct->holders--; ++ holders = ct->holders; ++ thread = ct->thread; ++ pthread_spin_unlock(&ct->hldr_lock); ++ if (holders) ++ pthread_cancel(thread); ++ else ++ cleanup_context(ct); ++ c->context = NULL; ++ } ++} ++ ++static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg) ++{ ++ char *addr_tok, *start, *save; ++ char *cmd[2]; ++ char *blklist, *stat; ++ size_t blklist_len, stat_len; ++ int ret; ++ char *end; ++ ++ cmd[0] = "{\"prefix\": \"osd blacklist ls\"}"; ++ cmd[1] = NULL; ++ ++ ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0, ++ &blklist, &blklist_len, &stat, &stat_len); ++ if (ret < 0) { ++ RBD_MSG(msg, "rbd checker failed: mon command failed %d", ++ ret); ++ return ret; ++ } ++ ++ if (!blklist || !blklist_len) ++ goto free_bufs; ++ ++ /* ++ * parse list of addrs with the format ++ * ipv4:port/nonce date time\n ++ * or ++ * [ipv6]:port/nonce date time\n ++ */ ++ ret = 0; ++ for (start = blklist; ; start = NULL) { ++ addr_tok = strtok_r(start, "\n", &save); ++ if (!addr_tok || !strlen(addr_tok)) ++ break; ++ ++ end = strchr(addr_tok, ' '); ++ if (!end) { ++ RBD_MSG(msg, "rbd%d checker failed: invalid blacklist %s", ++ ct->rbd_bus_id, addr_tok); ++ break; ++ } ++ *end = '\0'; ++ ++ if (!strcmp(addr_tok, ct->client_addr)) { ++ ct->blacklisted = 1; ++ RBD_MSG(msg, "rbd%d checker: %s is blacklisted", ++ ct->rbd_bus_id, ct->client_addr); ++ ret = 1; ++ break; ++ } ++ } ++ ++free_bufs: ++ rados_buffer_free(blklist); ++ rados_buffer_free(stat); ++ return ret; ++} ++ ++int rbd_check(struct rbd_checker_context *ct, char *msg) ++{ ++ if (ct->blacklisted || rbd_is_blacklisted(ct, msg) == 1) ++ return PATH_DOWN; ++ ++ RBD_MSG(msg, "rbd checker reports path is up"); ++ /* ++ * Path may have issues, but the ceph cluster is at least ++ * accepting IO, so we can attempt to do IO. ++ * ++ * TODO: in future versions, we can run other tests to ++ * verify OSDs and networks. ++ */ ++ return PATH_UP; ++} ++ ++int safe_write(int fd, const void *buf, size_t count) ++{ ++ while (count > 0) { ++ ssize_t r = write(fd, buf, count); ++ if (r < 0) { ++ if (errno == EINTR) ++ continue; ++ return -errno; ++ } ++ count -= r; ++ buf = (char *)buf + r; ++ } ++ return 0; ++} ++ ++static int sysfs_write_rbd_bus(const char *which, const char *buf, ++ size_t buf_len) ++{ ++ char sysfs_path[PATH_SIZE]; ++ int fd; ++ int r; ++ ++ /* we require newer kernels so single_major should alwayws be there */ ++ snprintf(sysfs_path, sizeof(sysfs_path), ++ "/sys/bus/rbd/%s_single_major", which); ++ fd = open(sysfs_path, O_WRONLY); ++ if (fd < 0) ++ return -errno; ++ ++ r = safe_write(fd, buf, buf_len); ++ close(fd); ++ return r; ++} ++ ++static int rbd_remap(struct rbd_checker_context *ct) ++{ ++ char *argv[11]; ++ pid_t pid; ++ int ret = 0, i = 0; ++ int status; ++ ++ pid = fork(); ++ switch (pid) { ++ case 0: ++ argv[i++] = "rbd"; ++ argv[i++] = "map"; ++ argv[i++] = "-o noshare"; ++ if (ct->username) { ++ argv[i++] = "--id"; ++ argv[i++] = ct->username; ++ } ++ argv[i++] = "--pool"; ++ argv[i++] = ct->pool; ++ if (ct->snap) { ++ argv[i++] = "--snap"; ++ argv[i++] = ct->snap; ++ } ++ argv[i++] = ct->image; ++ argv[i] = NULL; ++ ++ ret = execvp(argv[0], argv); ++ condlog(0, "Error executing rbd: %s", strerror(errno)); ++ exit(-1); ++ case -1: ++ condlog(0, "fork failed: %s", strerror(errno)); ++ return -1; ++ default: ++ ret = -1; ++ wait(&status); ++ if (WIFEXITED(status)) { ++ status = WEXITSTATUS(status); ++ if (status == 0) ++ ret = 0; ++ else ++ condlog(0, "rbd failed with %d", status); ++ } ++ } ++ ++ return ret; ++} ++ ++static int sysfs_write_rbd_remove(const char *buf, int buf_len) ++{ ++ return sysfs_write_rbd_bus("remove", buf, buf_len); ++} ++ ++static int rbd_rm_blacklist(struct rbd_checker_context *ct) ++{ ++ char *cmd[2]; ++ char *stat, *cmd_str; ++ size_t stat_len; ++ int ret; ++ ++ ret = asprintf(&cmd_str, "{\"prefix\": \"osd blacklist\", \"blacklistop\": \"rm\", \"addr\": \"%s\"}", ++ ct->client_addr); ++ if (ret == -1) ++ return -ENOMEM; ++ ++ cmd[0] = cmd_str; ++ cmd[1] = NULL; ++ ++ ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0, ++ NULL, 0, &stat, &stat_len); ++ if (ret < 0) { ++ condlog(1, "rbd%d repair failed to remove blacklist for %s %d", ++ ct->rbd_bus_id, ct->client_addr, ret); ++ goto free_cmd; ++ } ++ ++ condlog(1, "rbd%d repair rm blacklist for %s", ++ ct->rbd_bus_id, ct->client_addr); ++ free(stat); ++free_cmd: ++ free(cmd_str); ++ return ret; ++} ++ ++static int rbd_repair(struct rbd_checker_context *ct, char *msg) ++{ ++ char del[17]; ++ int ret; ++ ++ if (!ct->blacklisted) ++ return PATH_UP; ++ ++ if (!ct->remapped) { ++ ret = rbd_remap(ct); ++ if (ret) { ++ RBD_MSG(msg, "rbd%d repair failed to remap. Err %d", ++ ct->rbd_bus_id, ret); ++ return PATH_DOWN; ++ } ++ } ++ ct->remapped = 1; ++ ++ snprintf(del, sizeof(del), "%d force", ct->rbd_bus_id); ++ ret = sysfs_write_rbd_remove(del, strlen(del) + 1); ++ if (ret) { ++ RBD_MSG(msg, "rbd%d repair failed to clean up. Err %d", ++ ct->rbd_bus_id, ret); ++ return PATH_DOWN; ++ } ++ ++ ret = rbd_rm_blacklist(ct); ++ if (ret) { ++ RBD_MSG(msg, "rbd%d repair could not remove blacklist entry. Err %d", ++ ct->rbd_bus_id, ret); ++ return PATH_DOWN; ++ } ++ ++ ct->remapped = 0; ++ ct->blacklisted = 0; ++ ++ RBD_MSG(msg, "rbd%d has been repaired", ct->rbd_bus_id); ++ return PATH_UP; ++} ++ ++#define rbd_thread_cleanup_push(ct) pthread_cleanup_push(cleanup_func, ct) ++#define rbd_thread_cleanup_pop(ct) pthread_cleanup_pop(1) ++ ++void cleanup_func(void *data) ++{ ++ int holders; ++ struct rbd_checker_context *ct = data; ++ pthread_spin_lock(&ct->hldr_lock); ++ ct->holders--; ++ holders = ct->holders; ++ ct->thread = 0; ++ pthread_spin_unlock(&ct->hldr_lock); ++ if (!holders) ++ cleanup_context(ct); ++} ++ ++void *rbd_thread(void *ctx) ++{ ++ struct rbd_checker_context *ct = ctx; ++ int state; ++ ++ condlog(3, "rbd%d thread starting up", ct->rbd_bus_id); ++ ++ ct->message[0] = '\0'; ++ /* This thread can be canceled, so setup clean up */ ++ rbd_thread_cleanup_push(ct) ++ ++ /* checker start up */ ++ pthread_mutex_lock(&ct->lock); ++ ct->state = PATH_PENDING; ++ pthread_mutex_unlock(&ct->lock); ++ ++ state = ct->fn(ct, ct->message); ++ ++ /* checker done */ ++ pthread_mutex_lock(&ct->lock); ++ ct->state = state; ++ pthread_mutex_unlock(&ct->lock); ++ pthread_cond_signal(&ct->active); ++ ++ condlog(3, "rbd%d thead finished, state %s", ct->rbd_bus_id, ++ checker_state_name(state)); ++ rbd_thread_cleanup_pop(ct); ++ return ((void *)0); ++} ++ ++static void rbd_timeout(struct timespec *tsp) ++{ ++ struct timeval now; ++ ++ gettimeofday(&now, NULL); ++ tsp->tv_sec = now.tv_sec; ++ tsp->tv_nsec = now.tv_usec * 1000; ++ tsp->tv_nsec += 1000000; /* 1 millisecond */ ++} ++ ++static int rbd_exec_fn(struct checker *c, thread_fn *fn) ++{ ++ struct rbd_checker_context *ct = c->context; ++ struct timespec tsp; ++ pthread_attr_t attr; ++ int rbd_status, r; ++ ++ if (c->sync) ++ return rbd_check(ct, c->message); ++ /* ++ * Async mode ++ */ ++ r = pthread_mutex_lock(&ct->lock); ++ if (r != 0) { ++ condlog(2, "rbd%d mutex lock failed with %d", ct->rbd_bus_id, ++ r); ++ MSG(c, "rbd%d thread failed to initialize", ct->rbd_bus_id); ++ return PATH_WILD; ++ } ++ ++ if (ct->running) { ++ /* Check if checker is still running */ ++ if (ct->thread) { ++ condlog(3, "rbd%d thread not finished", ct->rbd_bus_id); ++ rbd_status = PATH_PENDING; ++ } else { ++ /* checker done */ ++ ct->running = 0; ++ rbd_status = ct->state; ++ strncpy(c->message, ct->message, CHECKER_MSG_LEN); ++ c->message[CHECKER_MSG_LEN - 1] = '\0'; ++ } ++ pthread_mutex_unlock(&ct->lock); ++ } else { ++ /* Start new checker */ ++ ct->state = PATH_UNCHECKED; ++ ct->fn = fn; ++ pthread_spin_lock(&ct->hldr_lock); ++ ct->holders++; ++ pthread_spin_unlock(&ct->hldr_lock); ++ setup_thread_attr(&attr, 32 * 1024, 1); ++ r = pthread_create(&ct->thread, &attr, rbd_thread, ct); ++ if (r) { ++ pthread_mutex_unlock(&ct->lock); ++ ct->thread = 0; ++ ct->holders--; ++ condlog(3, "rbd%d failed to start rbd thread, using sync mode", ++ ct->rbd_bus_id); ++ return fn(ct, c->message); ++ } ++ pthread_attr_destroy(&attr); ++ rbd_timeout(&tsp); ++ r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp); ++ rbd_status = ct->state; ++ strncpy(c->message, ct->message,CHECKER_MSG_LEN); ++ c->message[CHECKER_MSG_LEN -1] = '\0'; ++ pthread_mutex_unlock(&ct->lock); ++ ++ if (ct->thread && ++ (rbd_status == PATH_PENDING || rbd_status == PATH_UNCHECKED)) { ++ condlog(3, "rbd%d thread still running", ++ ct->rbd_bus_id); ++ ct->running = 1; ++ rbd_status = PATH_PENDING; ++ } ++ } ++ ++ return rbd_status; ++} ++ ++void libcheck_repair(struct checker * c) ++{ ++ struct rbd_checker_context *ct = c->context; ++ ++ if (!ct || !ct->blacklisted) ++ return; ++ rbd_exec_fn(c, rbd_repair); ++} ++ ++int libcheck_check(struct checker * c) ++{ ++ struct rbd_checker_context *ct = c->context; ++ ++ if (!ct) ++ return PATH_UNCHECKED; ++ ++ if (ct->blacklisted) ++ return PATH_DOWN; ++ ++ return rbd_exec_fn(c, rbd_check); ++} +Index: multipath-tools-130222/multipath.conf.annotated +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.annotated ++++ multipath-tools-130222/multipath.conf.annotated +@@ -97,7 +97,7 @@ + # # scope : multipath & multipathd + # # desc : the default method used to determine the paths' state + # # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac| +-# cciss_tur|hp_tur ++# cciss_tur|hp_tur|rbd + # # default : directio + # # + # path_checker directio +@@ -493,7 +493,7 @@ + # # scope : multipathd & multipathd + # # desc : path checking algorithm to use to check path state + # # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac| +-# # cciss_tur|hp_tur ++# # cciss_tur|hp_tur|rbd + # # + # path_checker directio + # +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -284,6 +284,9 @@ Check the path state for LSI/Engenio/Net + .B directio + Read the first sector with direct I/O. + .TP ++.B rbd ++Check if the path is in the Ceph blacklist. ++.TP + Default value is \fIdirectio\fR. + .RE + .TP diff --git a/SOURCES/0181-multipath-tools-Add-rbd-to-the-hwtable.patch b/SOURCES/0181-multipath-tools-Add-rbd-to-the-hwtable.patch new file mode 100644 index 0000000..fd9d6ff --- /dev/null +++ b/SOURCES/0181-multipath-tools-Add-rbd-to-the-hwtable.patch @@ -0,0 +1,51 @@ +From b25186a60347e2a0f2e53a10c05d9ad52a88c890 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Tue, 9 Aug 2016 13:53:21 -0500 +Subject: [PATCH 05/11] multipath-tools: Add rbd to the hwtable + +For BZ 1348372 from upstream commit: + +commit 61fe9e521965ff70db6a65370b394d769077d54c +Author: Mike Christie +Date: Mon Aug 8 07:01:50 2016 -0500 + + multipath-tools: Add rbd to the hwtable + + Add rbd to hwtable. These defaults are for the HA type of setup + supported by the checker. We do no support features like multibus + at the dm-multipath level yet + +Signed-off-by: Mike Christie +--- + libmultipath/hwtable.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index 61d1033..d278c04 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -1206,6 +1206,21 @@ static struct hwentry default_hw[] = { + .pgfailback = -FAILBACK_IMMEDIATE, + .checker_name = TUR, + }, ++ { ++ /* ++ * Red Hat ++ * ++ * Maintainer: Mike Christie ++ * Mail: mchristi@redhat.com ++ */ ++ .vendor = "Ceph", ++ .product = "RBD", ++ .pgpolicy = FAILOVER, ++ .no_path_retry = NO_PATH_RETRY_FAIL, ++ .checker_name = RBD, ++ .deferred_remove = DEFERRED_REMOVE_ON, ++ }, ++ + /* + * EOL + */ +-- +1.8.3.1 + diff --git a/SOURCES/0182-multipath-tools-check-for-initialized-checker-before.patch b/SOURCES/0182-multipath-tools-check-for-initialized-checker-before.patch new file mode 100644 index 0000000..26b8f28 --- /dev/null +++ b/SOURCES/0182-multipath-tools-check-for-initialized-checker-before.patch @@ -0,0 +1,49 @@ +From 7592f62383e6143a54d89885e505834c4977c4a6 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Tue, 16 Aug 2016 11:44:27 -0500 +Subject: [PATCH 06/11] multipath-tools: check for initialized checker before + +For bz from upstream commit: + +commit b5773d46a4550c3c222bb415197e0bc5f09c1169 +Author: Mike Christie +Date: Mon Aug 15 12:13:45 2016 -0500 + + multipath-tools: check for initialized checker before + + This fixes a regression added with: + 015f87b16a7797a17afd514aec46e65c2a1a2f73 + + We can hit a race where when pathinfo is setting up a path, the path + could have gone down already. In the DI_CHECKER chunk we then do not +run + get_state and attach a checker. Later when check_path is run + path_offline could still return PATH_DOWN or PATH_REMOVED and + get_state is again not run so we do not get to attach a checker. I + was then running repair_path since the state was PATH_DOWN, and we +then + hit a segfault. + + This has us test if a checker is selected before running repair. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index fa7d8b7..6cd8d34 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -212,7 +212,7 @@ void checker_put (struct checker * dst) + + void checker_repair (struct checker * c) + { +- if (!c) ++ if (!c || !checker_selected(c)) + return; + + c->message[0] = '\0'; +-- +1.8.3.1 + diff --git a/SOURCES/0183-multipathd-Don-t-call-repair-on-blacklisted-path.patch b/SOURCES/0183-multipathd-Don-t-call-repair-on-blacklisted-path.patch new file mode 100644 index 0000000..93323c1 --- /dev/null +++ b/SOURCES/0183-multipathd-Don-t-call-repair-on-blacklisted-path.patch @@ -0,0 +1,91 @@ +From 2926316c8492a1d18c7bbdac0fac75c38ce16152 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Tue, 16 Aug 2016 11:47:16 -0500 +Subject: [PATCH 07/11] multipathd: Don't call repair on blacklisted path + +For BZ 1348372 from upstream commit: + +Author: Mike Christie +Date: Mon Aug 15 12:13:46 2016 -0500 + + multipathd: Don't call repair on blacklisted paths + + This fixes a regression added in + 015f87b16a7797a17afd514aec46e65c2a1a2f73 + + If a path is blacklisted the checkerloop will free the path so + don't call repair on it. + + This moves the repair call down into check_path, because I think + we also do not need to call it for other cases where we cannot get + the uuid info or being orphaned. + +Signed-off-by: Mike Christie +--- + multipathd/main.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index d26fd22..4638c8b 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1238,6 +1238,16 @@ int update_path_groups(struct multipath *mpp, struct vectors *vecs, int refresh) + return 0; + } + ++void repair_path(struct path * pp) ++{ ++ if (pp->state != PATH_DOWN) ++ return; ++ ++ checker_repair(&pp->checker); ++ if (strlen(checker_message(&pp->checker))) ++ LOG_MSG(1, checker_message(&pp->checker)); ++} ++ + void + check_path (struct vectors * vecs, struct path * pp) + { +@@ -1352,6 +1362,7 @@ check_path (struct vectors * vecs, struct path * pp) + pp->mpp->failback_tick = 0; + + pp->mpp->stat_path_failures++; ++ repair_path(pp); + return; + } + +@@ -1431,7 +1442,7 @@ check_path (struct vectors * vecs, struct path * pp) + } + + pp->state = newstate; +- ++ repair_path(pp); + + if (pp->mpp->wait_for_udev) + return; +@@ -1455,14 +1466,6 @@ check_path (struct vectors * vecs, struct path * pp) + } + } + +-void repair_path(struct vectors * vecs, struct path * pp) +-{ +- if (pp->state != PATH_DOWN) +- return; +- +- checker_repair(&pp->checker); +-} +- + static void * + checkerloop (void *ap) + { +@@ -1491,7 +1494,6 @@ checkerloop (void *ap) + if (vecs->pathvec) { + vector_foreach_slot (vecs->pathvec, pp, i) { + check_path(vecs, pp); +- repair_path(vecs, pp); + } + } + if (vecs->mpvec) { +-- +1.8.3.1 + diff --git a/SOURCES/0184-rbd-fix-sync-repair-support.patch b/SOURCES/0184-rbd-fix-sync-repair-support.patch new file mode 100644 index 0000000..6ae6303 --- /dev/null +++ b/SOURCES/0184-rbd-fix-sync-repair-support.patch @@ -0,0 +1,29 @@ +From d1bda720153b4978121fbae40f82d2f4b9aff997 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Thu, 25 Aug 2016 01:34:11 -0500 +Subject: [PATCH 08/11] rbd: fix sync repair support + +If sync was set we were calling check instead +of function passed in. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers/rbd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c +index 6f1b53a..76f4005 100644 +--- a/libmultipath/checkers/rbd.c ++++ b/libmultipath/checkers/rbd.c +@@ -554,7 +554,7 @@ static int rbd_exec_fn(struct checker *c, thread_fn *fn) + int rbd_status, r; + + if (c->sync) +- return rbd_check(ct, c->message); ++ return fn(ct, c->message); + /* + * Async mode + */ +-- +1.8.3.1 + diff --git a/SOURCES/0185-rbd-check-for-nonshared-clients.patch b/SOURCES/0185-rbd-check-for-nonshared-clients.patch new file mode 100644 index 0000000..c209d73 --- /dev/null +++ b/SOURCES/0185-rbd-check-for-nonshared-clients.patch @@ -0,0 +1,32 @@ +From c9a788f437f2729f943cd03c43e84b65d74eb015 Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Wed, 31 Aug 2016 15:22:09 -0500 +Subject: [PATCH 09/11] rbd: check for nonshared clients + +The rbd checker only supports nonshared clients so add a check +during init time. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers/rbd.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c +index 76f4005..a6f3405 100644 +--- a/libmultipath/checkers/rbd.c ++++ b/libmultipath/checkers/rbd.c +@@ -123,6 +123,11 @@ int libcheck_init(struct checker * c) + if (!config_info) + goto free_addr; + ++ if (!strstr(config_info, "noshare")) { ++ condlog(3, "Only nonshared clients supported."); ++ goto free_addr; ++ } ++ + ct->config_info = strdup(config_info); + if (!ct->config_info) + goto free_addr; +-- +1.8.3.1 + diff --git a/SOURCES/0186-rbd-check-for-exclusive-lock-enabled.patch b/SOURCES/0186-rbd-check-for-exclusive-lock-enabled.patch new file mode 100644 index 0000000..290850b --- /dev/null +++ b/SOURCES/0186-rbd-check-for-exclusive-lock-enabled.patch @@ -0,0 +1,56 @@ +From 513d210cdbccfdaadb0cf7f09ba97d563aac52bb Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Wed, 31 Aug 2016 15:40:16 -0500 +Subject: [PATCH 10/11] rbd: check for exclusive lock enabled + +Only attach the checker if the rbd image has the exclusive lock +enabled. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers/rbd.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c +index a6f3405..e34bf53 100644 +--- a/libmultipath/checkers/rbd.c ++++ b/libmultipath/checkers/rbd.c +@@ -33,6 +33,8 @@ typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg); + + #define RBD_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args); + ++#define RBD_FEATURE_EXCLUSIVE_LOCK (1 << 2) ++ + struct rbd_checker_context { + int rbd_bus_id; + char *client_addr; +@@ -65,8 +67,9 @@ int libcheck_init(struct checker * c) + struct udev_device *bus_dev; + struct udev *udev; + struct stat sb; +- const char *block_name, *addr, *config_info; ++ const char *block_name, *addr, *config_info, *features_str; + const char *image, *pool, *snap, *username; ++ uint64_t features = 0; + char sysfs_path[PATH_SIZE]; + int ret; + +@@ -119,6 +122,15 @@ int libcheck_init(struct checker * c) + if (!ct->client_addr) + goto free_dev; + ++ features_str = udev_device_get_sysattr_value(bus_dev, "features"); ++ if (!features_str) ++ goto free_addr; ++ features = strtoll(features_str, NULL, 16); ++ if (!(features & RBD_FEATURE_EXCLUSIVE_LOCK)) { ++ condlog(3, "Exclusive lock not set."); ++ goto free_addr; ++ } ++ + config_info = udev_device_get_sysattr_value(bus_dev, "config_info"); + if (!config_info) + goto free_addr; +-- +1.8.3.1 + diff --git a/SOURCES/0187-rbd-fixup-log-messages.patch b/SOURCES/0187-rbd-fixup-log-messages.patch new file mode 100644 index 0000000..c4ed6db --- /dev/null +++ b/SOURCES/0187-rbd-fixup-log-messages.patch @@ -0,0 +1,238 @@ +From 3ed9a923904887e41c774c71232ae2a1ff6fc3fb Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Wed, 31 Aug 2016 15:59:53 -0500 +Subject: [PATCH 11/11] rbd: fixup log messages + +Add rbd device prefix to condlog messages that was missing it, and drop +it in RBD_MSG because it is already added by caller. + +Signed-off-by: Mike Christie +--- + libmultipath/checkers/rbd.c | 67 +++++++++++++++++++++++---------------------- + 1 file changed, 35 insertions(+), 32 deletions(-) + +diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c +index e34bf53..8e6cd3c 100644 +--- a/libmultipath/checkers/rbd.c ++++ b/libmultipath/checkers/rbd.c +@@ -113,8 +113,8 @@ int libcheck_init(struct checker * c) + + addr = udev_device_get_sysattr_value(bus_dev, "client_addr"); + if (!addr) { +- condlog(0, "Could not find client_addr in rbd sysfs. Try " +- "updating kernel"); ++ condlog(0, "rbd%d: Could not find client_addr in rbd sysfs. " ++ "Try updating kernel", ct->rbd_bus_id); + goto free_dev; + } + +@@ -127,7 +127,7 @@ int libcheck_init(struct checker * c) + goto free_addr; + features = strtoll(features_str, NULL, 16); + if (!(features & RBD_FEATURE_EXCLUSIVE_LOCK)) { +- condlog(3, "Exclusive lock not set."); ++ condlog(3, "rbd%d: Exclusive lock not set.", ct->rbd_bus_id); + goto free_addr; + } + +@@ -136,7 +136,8 @@ int libcheck_init(struct checker * c) + goto free_addr; + + if (!strstr(config_info, "noshare")) { +- condlog(3, "Only nonshared clients supported."); ++ condlog(3, "rbd%d: Only nonshared clients supported.", ++ ct->rbd_bus_id); + goto free_addr; + } + +@@ -189,18 +190,20 @@ int libcheck_init(struct checker * c) + } + + if (rados_create(&ct->cluster, NULL) < 0) { +- condlog(0, "Could not create rados cluster"); ++ condlog(0, "rbd%d: Could not create rados cluster", ++ ct->rbd_bus_id); + goto free_snap; + } + + if (rados_conf_read_file(ct->cluster, NULL) < 0) { +- condlog(0, "Could not read rados conf"); ++ condlog(0, "rbd%d: Could not read rados conf", ct->rbd_bus_id); + goto shutdown_rados; + } + + ret = rados_connect(ct->cluster); + if (ret < 0) { +- condlog(0, "Could not connect to rados cluster"); ++ condlog(0, "rbd%d: Could not connect to rados cluster", ++ ct->rbd_bus_id); + goto shutdown_rados; + } + +@@ -291,8 +294,7 @@ static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg) + ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0, + &blklist, &blklist_len, &stat, &stat_len); + if (ret < 0) { +- RBD_MSG(msg, "rbd checker failed: mon command failed %d", +- ret); ++ RBD_MSG(msg, "checker failed: mon command failed %d", ret); + return ret; + } + +@@ -313,16 +315,15 @@ static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg) + + end = strchr(addr_tok, ' '); + if (!end) { +- RBD_MSG(msg, "rbd%d checker failed: invalid blacklist %s", +- ct->rbd_bus_id, addr_tok); ++ RBD_MSG(msg, "checker failed: invalid blacklist %s", ++ addr_tok); + break; + } + *end = '\0'; + + if (!strcmp(addr_tok, ct->client_addr)) { + ct->blacklisted = 1; +- RBD_MSG(msg, "rbd%d checker: %s is blacklisted", +- ct->rbd_bus_id, ct->client_addr); ++ RBD_MSG(msg, "%s is blacklisted", ct->client_addr); + ret = 1; + break; + } +@@ -339,7 +340,7 @@ int rbd_check(struct rbd_checker_context *ct, char *msg) + if (ct->blacklisted || rbd_is_blacklisted(ct, msg) == 1) + return PATH_DOWN; + +- RBD_MSG(msg, "rbd checker reports path is up"); ++ RBD_MSG(msg, "checker reports path is up"); + /* + * Path may have issues, but the ceph cluster is at least + * accepting IO, so we can attempt to do IO. +@@ -411,10 +412,12 @@ static int rbd_remap(struct rbd_checker_context *ct) + argv[i] = NULL; + + ret = execvp(argv[0], argv); +- condlog(0, "Error executing rbd: %s", strerror(errno)); ++ condlog(0, "rbd%d: Error executing rbd: %s", ct->rbd_bus_id, ++ strerror(errno)); + exit(-1); + case -1: +- condlog(0, "fork failed: %s", strerror(errno)); ++ condlog(0, "rbd%d: fork failed: %s", ct->rbd_bus_id, ++ strerror(errno)); + return -1; + default: + ret = -1; +@@ -424,7 +427,8 @@ static int rbd_remap(struct rbd_checker_context *ct) + if (status == 0) + ret = 0; + else +- condlog(0, "rbd failed with %d", status); ++ condlog(0, "rbd%d: failed with %d", ++ ct->rbd_bus_id, status); + } + } + +@@ -454,12 +458,12 @@ static int rbd_rm_blacklist(struct rbd_checker_context *ct) + ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0, + NULL, 0, &stat, &stat_len); + if (ret < 0) { +- condlog(1, "rbd%d repair failed to remove blacklist for %s %d", ++ condlog(1, "rbd%d: repair failed to remove blacklist for %s %d", + ct->rbd_bus_id, ct->client_addr, ret); + goto free_cmd; + } + +- condlog(1, "rbd%d repair rm blacklist for %s", ++ condlog(1, "rbd%d: repair rm blacklist for %s", + ct->rbd_bus_id, ct->client_addr); + free(stat); + free_cmd: +@@ -478,8 +482,7 @@ static int rbd_repair(struct rbd_checker_context *ct, char *msg) + if (!ct->remapped) { + ret = rbd_remap(ct); + if (ret) { +- RBD_MSG(msg, "rbd%d repair failed to remap. Err %d", +- ct->rbd_bus_id, ret); ++ RBD_MSG(msg, "repair failed to remap. Err %d", ret); + return PATH_DOWN; + } + } +@@ -488,22 +491,21 @@ static int rbd_repair(struct rbd_checker_context *ct, char *msg) + snprintf(del, sizeof(del), "%d force", ct->rbd_bus_id); + ret = sysfs_write_rbd_remove(del, strlen(del) + 1); + if (ret) { +- RBD_MSG(msg, "rbd%d repair failed to clean up. Err %d", +- ct->rbd_bus_id, ret); ++ RBD_MSG(msg, "repair failed to clean up. Err %d", ret); + return PATH_DOWN; + } + + ret = rbd_rm_blacklist(ct); + if (ret) { +- RBD_MSG(msg, "rbd%d repair could not remove blacklist entry. Err %d", +- ct->rbd_bus_id, ret); ++ RBD_MSG(msg, "repair could not remove blacklist entry. Err %d", ++ ret); + return PATH_DOWN; + } + + ct->remapped = 0; + ct->blacklisted = 0; + +- RBD_MSG(msg, "rbd%d has been repaired", ct->rbd_bus_id); ++ RBD_MSG(msg, "has been repaired"); + return PATH_UP; + } + +@@ -528,7 +530,7 @@ void *rbd_thread(void *ctx) + struct rbd_checker_context *ct = ctx; + int state; + +- condlog(3, "rbd%d thread starting up", ct->rbd_bus_id); ++ condlog(3, "rbd%d: thread starting up", ct->rbd_bus_id); + + ct->message[0] = '\0'; + /* This thread can be canceled, so setup clean up */ +@@ -547,7 +549,7 @@ void *rbd_thread(void *ctx) + pthread_mutex_unlock(&ct->lock); + pthread_cond_signal(&ct->active); + +- condlog(3, "rbd%d thead finished, state %s", ct->rbd_bus_id, ++ condlog(3, "rbd%d: thead finished, state %s", ct->rbd_bus_id, + checker_state_name(state)); + rbd_thread_cleanup_pop(ct); + return ((void *)0); +@@ -577,16 +579,17 @@ static int rbd_exec_fn(struct checker *c, thread_fn *fn) + */ + r = pthread_mutex_lock(&ct->lock); + if (r != 0) { +- condlog(2, "rbd%d mutex lock failed with %d", ct->rbd_bus_id, ++ condlog(2, "rbd%d: mutex lock failed with %d", ct->rbd_bus_id, + r); +- MSG(c, "rbd%d thread failed to initialize", ct->rbd_bus_id); ++ MSG(c, "rbd%d: thread failed to initialize", ct->rbd_bus_id); + return PATH_WILD; + } + + if (ct->running) { + /* Check if checker is still running */ + if (ct->thread) { +- condlog(3, "rbd%d thread not finished", ct->rbd_bus_id); ++ condlog(3, "rbd%d: thread not finished", ++ ct->rbd_bus_id); + rbd_status = PATH_PENDING; + } else { + /* checker done */ +@@ -623,7 +626,7 @@ static int rbd_exec_fn(struct checker *c, thread_fn *fn) + + if (ct->thread && + (rbd_status == PATH_PENDING || rbd_status == PATH_UNCHECKED)) { +- condlog(3, "rbd%d thread still running", ++ condlog(3, "rbd%d: thread still running", + ct->rbd_bus_id); + ct->running = 1; + rbd_status = PATH_PENDING; +-- +1.8.3.1 + diff --git a/SOURCES/0188-RHBZ-1368501-dont-exit.patch b/SOURCES/0188-RHBZ-1368501-dont-exit.patch new file mode 100644 index 0000000..4783991 --- /dev/null +++ b/SOURCES/0188-RHBZ-1368501-dont-exit.patch @@ -0,0 +1,208 @@ +--- + libmultipath/configure.c | 8 +++-- + multipathd/main.c | 68 +++++++++++++++++++++++++++++++++++++---------- + 2 files changed, 59 insertions(+), 17 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -829,8 +829,10 @@ coalesce_paths (struct vectors * vecs, v + * at this point, we know we really got a new mp + */ + mpp = add_map_with_path(vecs, pp1, 0); +- if (!mpp) +- return 1; ++ if (!mpp) { ++ orphan_path(pp1); ++ continue; ++ } + + if (pp1->priority == PRIO_UNDEF) + mpp->action = ACT_REJECT; +@@ -879,7 +881,7 @@ coalesce_paths (struct vectors * vecs, v + condlog(3, "%s: domap (%u) failure " + "for create/reload map", + mpp->alias, r); +- if (r == DOMAP_FAIL) { ++ if (r == DOMAP_FAIL || conf->daemon) { + condlog(2, "%s: %s map", + mpp->alias, (mpp->action == ACT_CREATE)? + "ignoring" : "removing"); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -821,7 +821,7 @@ map_discovery (struct vectors * vecs) + + vector_foreach_slot (vecs->mpvec, mpp, i) + if (setup_multipath(vecs, mpp)) +- return 1; ++ i--; + + return 0; + } +@@ -1523,21 +1523,29 @@ configure (struct vectors * vecs, int st + vector mpvec; + int i, ret; + +- if (!vecs->pathvec && !(vecs->pathvec = vector_alloc())) ++ if (!vecs->pathvec && !(vecs->pathvec = vector_alloc())) { ++ condlog(0, "couldn't allocate path vec in configure"); + return 1; ++ } + +- if (!vecs->mpvec && !(vecs->mpvec = vector_alloc())) ++ if (!vecs->mpvec && !(vecs->mpvec = vector_alloc())) { ++ condlog(0, "couldn't allocate multipath vec in configure"); + return 1; ++ } + +- if (!(mpvec = vector_alloc())) ++ if (!(mpvec = vector_alloc())) { ++ condlog(0, "couldn't allocate new maps vec in configure"); + return 1; ++ } + + /* + * probe for current path (from sysfs) and map (from dm) sets + */ + ret = path_discovery(vecs->pathvec, conf, DI_ALL); +- if (ret < 0) ++ if (ret < 0) { ++ condlog(0, "configure failed at path discovery"); + return 1; ++ } + + vector_foreach_slot (vecs->pathvec, pp, i){ + if (filter_path(conf, pp) > 0){ +@@ -1548,21 +1556,27 @@ configure (struct vectors * vecs, int st + else + pp->checkint = conf->checkint; + } +- if (map_discovery(vecs)) ++ if (map_discovery(vecs)) { ++ condlog(0, "configure failed at map discovery"); + return 1; ++ } + + /* + * create new set of maps & push changed ones into dm + */ +- if (coalesce_paths(vecs, mpvec, NULL, 1)) ++ if (coalesce_paths(vecs, mpvec, NULL, 1)) { ++ condlog(0, "configure failed while coalescing paths"); + return 1; ++ } + + /* + * may need to remove some maps which are no longer relevant + * e.g., due to blacklist changes in conf file + */ +- if (coalesce_maps(vecs, mpvec)) ++ if (coalesce_maps(vecs, mpvec)) { ++ condlog(0, "configure failed while coalescing maps"); + return 1; ++ } + + dm_lib_release(); + +@@ -1588,11 +1602,15 @@ configure (struct vectors * vecs, int st + * start dm event waiter threads for these new maps + */ + vector_foreach_slot(vecs->mpvec, mpp, i) { +- if (setup_multipath(vecs, mpp)) +- return 1; ++ if (setup_multipath(vecs, mpp)) { ++ i--; ++ continue; ++ } + if (start_waiters) +- if (start_waiter_thread(mpp, vecs)) +- return 1; ++ if (start_waiter_thread(mpp, vecs)) { ++ remove_map(mpp, vecs, 1); ++ i--; ++ } + } + return 0; + } +@@ -1857,15 +1875,23 @@ child (void * param) + condlog(2, "--------start up--------"); + condlog(2, "read " DEFAULT_CONFIGFILE); + +- if (load_config(DEFAULT_CONFIGFILE, udev)) ++ if (load_config(DEFAULT_CONFIGFILE, udev)) { ++ condlog(0, "failed to load config"); ++ if (logsink) ++ log_thread_stop(); + exit(1); ++ } + + if (init_checkers()) { + condlog(0, "failed to initialize checkers"); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + if (init_prio()) { + condlog(0, "failed to initialize prioritizers"); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + +@@ -1898,8 +1924,12 @@ child (void * param) + } + + vecs = gvecs = init_vecs(); +- if (!vecs) ++ if (!vecs) { ++ condlog(0, "failed to create vecs"); ++ if (logsink) ++ log_thread_stop(); + exit(1); ++ } + + setscheduler(); + set_oom_adj(); +@@ -1911,11 +1941,15 @@ child (void * param) + */ + if ((rc = pthread_create(&uevent_thr, &uevent_attr, ueventloop, udev))) { + condlog(0, "failed to create uevent thread: %d", rc); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + pthread_attr_destroy(&uevent_attr); + if ((rc = pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs))) { + condlog(0, "failed to create cli listener: %d", rc); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + /* +@@ -1927,6 +1961,8 @@ child (void * param) + if (configure(vecs, 1)) { + unlock(vecs->lock); + condlog(0, "failure during configuration"); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + unlock(vecs->lock); +@@ -1936,10 +1972,14 @@ child (void * param) + */ + if ((rc = pthread_create(&check_thr, &misc_attr, checkerloop, vecs))) { + condlog(0,"failed to create checker loop thread: %d", rc); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + if ((rc = pthread_create(&uevq_thr, &misc_attr, uevqloop, vecs))) { + condlog(0, "failed to create uevent dispatcher: %d", rc); ++ if (logsink) ++ log_thread_stop(); + exit(1); + } + pthread_attr_destroy(&misc_attr); diff --git a/SOURCES/0189-RHBZ-1368211-remove-retries.patch b/SOURCES/0189-RHBZ-1368211-remove-retries.patch new file mode 100644 index 0000000..253d572 --- /dev/null +++ b/SOURCES/0189-RHBZ-1368211-remove-retries.patch @@ -0,0 +1,168 @@ +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 1 + + libmultipath/devmapper.c | 35 +++++++++++++++++++---------------- + libmultipath/dict.c | 25 +++++++++++++++++++++++++ + multipath.conf.defaults | 1 + + multipath/multipath.conf.5 | 5 +++++ + 6 files changed, 52 insertions(+), 16 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -803,10 +803,11 @@ dm_flush_map_nopaths(const char * mapnam + extern int + dm_suspend_and_flush_map (const char * mapname) + { +- int s = 0, queue_if_no_path = 0; ++ int need_reset = 0, queue_if_no_path = 0; + unsigned long long mapsize; + char params[PARAMS_SIZE] = {0}; + int udev_flags = 0; ++ int retries = conf->remove_retries; + + if (!dm_is_mpath(mapname)) + return 0; /* nothing to do */ +@@ -821,22 +822,24 @@ dm_suspend_and_flush_map (const char * m + queue_if_no_path = 1; + } + +- if (queue_if_no_path) +- s = dm_queue_if_no_path((char *)mapname, 0); +- /* Leave queue_if_no_path alone if unset failed */ +- if (s) +- queue_if_no_path = 0; +- else +- s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0, 0); +- +- if (!dm_flush_map(mapname)) { +- condlog(4, "multipath map %s removed", mapname); +- return 0; +- } ++ if (queue_if_no_path && dm_queue_if_no_path((char *)mapname, 0) == 0) ++ need_reset = 1; ++ ++ do { ++ if (!queue_if_no_path || need_reset) ++ dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0, 0); ++ ++ if (!dm_flush_map(mapname)) { ++ condlog(4, "multipath map %s removed", mapname); ++ return 0; ++ } ++ dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, udev_flags); ++ if (retries) ++ sleep(1); ++ } while (retries-- > 0); + condlog(2, "failed to remove multipath map %s", mapname); +- dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, udev_flags); +- if (queue_if_no_path) +- s = dm_queue_if_no_path((char *)mapname, 1); ++ if (need_reset) ++ dm_queue_if_no_path((char *)mapname, 1); + return 1; + } + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -680,6 +680,7 @@ load_config (char * file, struct udev *u + conf->new_bindings_in_boot = 0; + conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; + conf->skip_kpartx = DEFAULT_SKIP_KPARTX; ++ conf->remove_retries = 0; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -146,6 +146,7 @@ struct config { + int delayed_reconfig; + int uev_wait_timeout; + int skip_kpartx; ++ int remove_retries; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -935,6 +935,24 @@ def_new_bindings_in_boot_handler(vector + return 0; + } + ++static int ++def_remove_retries_handler(vector strvec) ++{ ++ char *buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ conf->remove_retries = atoi(buff); ++ if (conf->remove_retries < 0) ++ conf->remove_retries = 0; ++ FREE(buff); ++ ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -3405,6 +3423,12 @@ snprint_def_new_bindings_in_boot(char * + } + + static int ++snprint_def_remove_retries (char * buff, int len, void * data) ++{ ++ return snprintf(buff, len, "%i", conf->remove_retries); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3483,6 +3507,7 @@ init_keywords(void) + install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay); + install_keyword("missing_uev_wait_timeout", &def_uev_wait_timeout_handler, &snprint_def_uev_wait_timeout); + install_keyword("new_bindings_in_boot", &def_new_bindings_in_boot_handler, &snprint_def_new_bindings_in_boot); ++ install_keyword("remove_retries", &def_remove_retries_handler, &snprint_def_remove_retries); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -41,6 +41,7 @@ + # retrigger_delay 10 + # missing_uev_wait_timeout 30 + # new_bindings_in_boot no ++# remove_retries 0 + #} + #blacklist { + # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -556,6 +556,11 @@ user_friendly_names. When multipathd is + regular filesystem, the device will be renamed to a user_friendly_name. The + default is + .I no ++.TP ++.B remove_retries ++This sets how may times multipath will retry removing a device that is in-use. ++Between each attempt, multipath will sleep 1 second. The default is ++.I 0 + . + .SH "blacklist section" + The diff --git a/SOURCES/0190-RHBZ-1380602-rbd-lock-on-read.patch b/SOURCES/0190-RHBZ-1380602-rbd-lock-on-read.patch new file mode 100644 index 0000000..584d37f --- /dev/null +++ b/SOURCES/0190-RHBZ-1380602-rbd-lock-on-read.patch @@ -0,0 +1,38 @@ +--- + libmultipath/checkers/rbd.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/checkers/rbd.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rbd.c ++++ multipath-tools-130222/libmultipath/checkers/rbd.c +@@ -45,6 +45,7 @@ struct rbd_checker_context { + char *username; + int remapped; + int blacklisted; ++ int lock_on_read:1; + + rados_t cluster; + +@@ -141,6 +142,9 @@ int libcheck_init(struct checker * c) + goto free_addr; + } + ++ if (strstr(config_info, "lock_on_read")) ++ ct->lock_on_read = 1; ++ + ct->config_info = strdup(config_info); + if (!ct->config_info) + goto free_addr; +@@ -397,7 +401,10 @@ static int rbd_remap(struct rbd_checker_ + case 0: + argv[i++] = "rbd"; + argv[i++] = "map"; +- argv[i++] = "-o noshare"; ++ if (ct->lock_on_read) ++ argv[i++] = "-o noshare,lock_on_read"; ++ else ++ argv[i++] = "-o noshare"; + if (ct->username) { + argv[i++] = "--id"; + argv[i++] = ct->username; diff --git a/SOURCES/0191-RHBZ-1169168-disable-changed-paths.patch b/SOURCES/0191-RHBZ-1169168-disable-changed-paths.patch new file mode 100644 index 0000000..4c1eb6b --- /dev/null +++ b/SOURCES/0191-RHBZ-1169168-disable-changed-paths.patch @@ -0,0 +1,228 @@ +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 1 + + libmultipath/dict.c | 33 +++++++++++++++++++++++++++++++++ + libmultipath/discovery.c | 11 ++++++----- + libmultipath/discovery.h | 1 + + libmultipath/structs.h | 1 + + multipath/multipath.conf.5 | 6 ++++++ + multipathd/main.c | 26 ++++++++++++++++++++++++++ + 8 files changed, 75 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1155,8 +1155,8 @@ free_dev: + return ret; + } + +-static int +-get_uid (struct path * pp) ++int ++get_uid (struct path * pp, struct udev_device *udev) + { + char *c; + const char *value; +@@ -1165,7 +1165,7 @@ get_uid (struct path * pp) + if (!pp->uid_attribute) + select_getuid(pp); + +- if (!pp->udev) { ++ if (!udev) { + condlog(1, "%s: no udev information", pp->dev); + return 1; + } +@@ -1180,7 +1180,7 @@ get_uid (struct path * pp) + pp->tick = conf->retrigger_delay; + } + } else { +- value = udev_device_get_property_value(pp->udev, ++ value = udev_device_get_property_value(udev, + pp->uid_attribute); + if ((!value || strlen(value) == 0) && + conf->cmd == CMD_VALID_PATH) +@@ -1194,6 +1194,7 @@ get_uid (struct path * pp) + len = strlen(value); + } + strncpy(pp->wwid, value, len); ++ condlog(4, "%s: got wwid of '%s'", pp->dev, pp->wwid); + pp->missing_udev_info = INFO_OK; + pp->tick = 0; + } else { +@@ -1282,7 +1283,7 @@ pathinfo (struct path *pp, vector hwtabl + } + + if ((mask & DI_WWID) && !strlen(pp->wwid)) +- get_uid(pp); ++ get_uid(pp, pp->udev); + if (mask & DI_BLACKLIST && mask & DI_WWID) { + if (filter_wwid(conf->blist_wwid, conf->elist_wwid, + pp->wwid) > 0) { +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -44,6 +44,7 @@ int sysfs_set_scsi_tmo (struct multipath + int sysfs_get_timeout(struct path *pp, unsigned int *timeout); + int sysfs_get_host_pci_name(struct path *pp, char *pci_name); + int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address); ++int get_uid (struct path * pp, struct udev_device *udev); + + /* + * discovery bitmask +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -209,6 +209,7 @@ struct path { + int fd; + int missing_udev_info; + int retriggers; ++ int wwid_changed; + + /* configlet pointers */ + struct hwentry * hwe; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -784,6 +784,26 @@ uev_update_path (struct uevent *uev, str + if (pp->missing_udev_info == INFO_REQUESTED) + return uev_add_path(uev, vecs); + ++ if (conf->disable_changed_wwids && ++ (strlen(pp->wwid) || pp->wwid_changed)) { ++ char wwid[WWID_SIZE]; ++ ++ strcpy(wwid, pp->wwid); ++ get_uid(pp, uev->udev); ++ if (strcmp(wwid, pp->wwid) != 0) { ++ condlog(0, "%s: path wwid changed from '%s' to '%s'. disallowing", uev->kernel, wwid, pp->wwid); ++ strcpy(pp->wwid, wwid); ++ if (!pp->wwid_changed) { ++ pp->wwid_changed = 1; ++ pp->tick = 1; ++ dm_fail_path(pp->mpp->alias, pp->dev_t); ++ } ++ } ++ else { ++ pp->wwid_changed = 0; ++ } ++ } ++ + /* reinit the prio values on change event, in case something is + * different */ + prio_init(&pp->prio); +@@ -1284,6 +1304,12 @@ check_path (struct vectors * vecs, struc + else + checker_clear_message(&pp->checker); + ++ if (pp->wwid_changed) { ++ condlog(2, "%s: path wwid has changed. Refusing to use", ++ pp->dev); ++ newstate = PATH_DOWN; ++ } ++ + if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { + condlog(2, "%s: unusable path", pp->dev); + pathinfo(pp, conf->hwtable, 0); +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -681,6 +681,7 @@ load_config (char * file, struct udev *u + conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; + conf->skip_kpartx = DEFAULT_SKIP_KPARTX; + conf->remove_retries = 0; ++ conf->disable_changed_wwids = 0; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -147,6 +147,7 @@ struct config { + int uev_wait_timeout; + int skip_kpartx; + int remove_retries; ++ int disable_changed_wwids; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -953,6 +953,29 @@ def_remove_retries_handler(vector strvec + return 0; + } + ++static int ++def_disable_changed_wwids_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->disable_changed_wwids = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->disable_changed_wwids = 1; ++ else ++ conf->disable_changed_wwids = 0; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -3429,6 +3452,15 @@ snprint_def_remove_retries (char * buff, + } + + static int ++snprint_def_disable_changed_wwids(char * buff, int len, void * data) ++{ ++ if (conf->disable_changed_wwids == 1) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3508,6 +3540,7 @@ init_keywords(void) + install_keyword("missing_uev_wait_timeout", &def_uev_wait_timeout_handler, &snprint_def_uev_wait_timeout); + install_keyword("new_bindings_in_boot", &def_new_bindings_in_boot_handler, &snprint_def_new_bindings_in_boot); + install_keyword("remove_retries", &def_remove_retries_handler, &snprint_def_remove_retries); ++ install_keyword("disable_changed_wwids", &def_disable_changed_wwids_handler, &snprint_def_disable_changed_wwids); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -557,6 +557,12 @@ regular filesystem, the device will be r + default is + .I no + .TP ++.B disable_changed_wwids ++If set to \fIyes\fR, multipathd will check the path wwid on change events, and ++if it has changed from the wwid of the multipath device, multipathd will ++disable access to the path until the wwid changes back. The default is ++.I no ++.TP + .B remove_retries + This sets how may times multipath will retry removing a device that is in-use. + Between each attempt, multipath will sleep 1 second. The default is diff --git a/SOURCES/0192-RHBZ-1362409-infinibox-config.patch b/SOURCES/0192-RHBZ-1362409-infinibox-config.patch new file mode 100644 index 0000000..dd56f8b --- /dev/null +++ b/SOURCES/0192-RHBZ-1362409-infinibox-config.patch @@ -0,0 +1,34 @@ +--- + libmultipath/hwtable.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1168,6 +1168,25 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .prio_args = NULL, + }, ++ /* ++ * Infinidat ++ */ ++ { ++ .vendor = "NFINIDAT", ++ .product = "InfiniBox.*", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = 30, ++ .rr_weight = RR_WEIGHT_PRIO, ++ .no_path_retry = NO_PATH_RETRY_FAIL, ++ .checker_name = TUR, ++ .prio_name = PRIO_ALUA, ++ .prio_args = NULL, ++ .selector = "round-robin 0", ++ .flush_on_last_del = FLUSH_ENABLED, ++ .dev_loss = 30, ++ }, + { + .vendor = "XtremIO", + .product = "XtremApp", diff --git a/SOURCES/0194-RHBZ-1351964-kpartx-recurse.patch b/SOURCES/0194-RHBZ-1351964-kpartx-recurse.patch new file mode 100644 index 0000000..be5b22e --- /dev/null +++ b/SOURCES/0194-RHBZ-1351964-kpartx-recurse.patch @@ -0,0 +1,17 @@ +--- + kpartx/dos.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/kpartx/dos.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/dos.c ++++ multipath-tools-130222/kpartx/dos.c +@@ -46,7 +46,7 @@ read_extended_partition(int fd, struct p + for (i=0; i<2; i++) { + memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); + if (is_extended(p.sys_type)) { +- if (p.nr_sects && !moretodo) { ++ if (p.start_sect && p.nr_sects && !moretodo) { + next = start + sector_size_mul * le32_to_cpu(p.start_sect); + moretodo = 1; + } diff --git a/SOURCES/0195-RHBZ-1359510-no-daemon-msg.patch b/SOURCES/0195-RHBZ-1359510-no-daemon-msg.patch new file mode 100644 index 0000000..667f10d --- /dev/null +++ b/SOURCES/0195-RHBZ-1359510-no-daemon-msg.patch @@ -0,0 +1,111 @@ +--- + libmultipath/configure.c | 21 ++++++++++++++++++++- + libmultipath/configure.h | 1 + + multipath/main.c | 21 +++++++++++++++++++++ + 3 files changed, 42 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -743,7 +743,8 @@ deadmap (struct multipath * mpp) + return 1; /* dead */ + } + +-int check_daemon(void) ++extern int ++check_daemon(void) + { + int fd; + char *reply; +@@ -776,6 +777,7 @@ coalesce_paths (struct vectors * vecs, v + { + int r = 1; + int k, i; ++ int map_processed = 0; + char empty_buff[WWID_SIZE]; + char params[PARAMS_SIZE]; + struct multipath * mpp; +@@ -936,6 +938,13 @@ coalesce_paths (struct vectors * vecs, v + else + remove_map(mpp, vecs, 0); + } ++ ++ /* By now at least one multipath device map is processed, ++ * so set map_processed = 1 ++ */ ++ if (!map_processed) ++ map_processed = 1; ++ + } + /* + * Flush maps with only dead paths (ie not in sysfs) +@@ -963,6 +972,16 @@ coalesce_paths (struct vectors * vecs, v + condlog(2, "%s: remove (dead)", alias); + } + } ++ ++ /* If there is at least one multipath device map processed then ++ * check if 'multipathd' service is running or not? ++ */ ++ if (map_processed) { ++ if (!conf->daemon && !check_daemon()) ++ condlog(0, "'multipathd' service is currently not " ++ "running, IO failover/failback will not work"); ++ } ++ + return 0; + } + +Index: multipath-tools-130222/libmultipath/configure.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.h ++++ multipath-tools-130222/libmultipath/configure.h +@@ -27,6 +27,7 @@ enum actions { + int setup_map (struct multipath * mpp, char * params, int params_size ); + int domap (struct multipath * mpp, char * params); + int reinstate_paths (struct multipath *mpp); ++int check_daemon(void); + int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload); + int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid); + int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh); +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -178,6 +178,7 @@ static int + get_dm_mpvec (vector curmp, vector pathvec, char * refwwid) + { + int i; ++ int maps_present = 0; + struct multipath * mpp; + char params[PARAMS_SIZE], status[PARAMS_SIZE]; + +@@ -226,7 +227,27 @@ get_dm_mpvec (vector curmp, vector pathv + + if (conf->cmd == CMD_CREATE) + reinstate_paths(mpp); ++ ++ /* At this place we have found at least one multipath ++ * device map, so set maps_present = 1 ++ */ ++ if (!maps_present) ++ maps_present = 1; ++ + } ++ ++ /* If there is at least one multipath device map present then ++ * check if 'multipathd' service is running or not? ++ */ ++ if (maps_present) { ++ if (!conf->daemon && !check_daemon()) { ++ condlog(0, "multipath device maps are present, but " ++ "'multipathd' service is not running"); ++ condlog(0, "IO failover/failback will not work without " ++ "'multipathd' service running"); ++ } ++ } ++ + return 0; + } + diff --git a/SOURCES/0196-RHBZ-1239173-dont-set-flag.patch b/SOURCES/0196-RHBZ-1239173-dont-set-flag.patch new file mode 100644 index 0000000..269edc8 --- /dev/null +++ b/SOURCES/0196-RHBZ-1239173-dont-set-flag.patch @@ -0,0 +1,38 @@ +--- + libmultipath/configure.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -257,7 +257,7 @@ extern int + setup_map (struct multipath * mpp, char * params, int params_size) + { + struct pathgroup * pgp; +- int i; ++ int i, old_nr_active; + + /* + * don't bother if devmap size is unknown +@@ -311,8 +311,12 @@ setup_map (struct multipath * mpp, char + if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp)) + return 1; + ++ old_nr_active = mpp->nr_active; + mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST); + ++ if (mpp->nr_active && !old_nr_active) ++ mpp->force_udev_reload = 1; ++ + /* + * ponders each path group and determine highest prio pg + * to switch over (default to first) +@@ -445,7 +449,6 @@ select_action (struct multipath * mpp, v + mpp->alias); + return; + } +- mpp->force_udev_reload = !pathcount(mpp, PATH_WILD); + if (cmpp->size != mpp->size) { + mpp->force_udev_reload = 1; + mpp->action = ACT_RESIZE; diff --git a/SOURCES/0197-RHBZ-1394059-max-sectors-kb.patch b/SOURCES/0197-RHBZ-1394059-max-sectors-kb.patch new file mode 100644 index 0000000..f5cfa23 --- /dev/null +++ b/SOURCES/0197-RHBZ-1394059-max-sectors-kb.patch @@ -0,0 +1,474 @@ +--- + libmultipath/config.c | 3 + + libmultipath/config.h | 3 + + libmultipath/configure.c | 1 + libmultipath/defaults.h | 1 + libmultipath/devmapper.c | 4 +- + libmultipath/dict.c | 87 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/discovery.c | 60 +++++++++++++++++++++++++++++++ + libmultipath/discovery.h | 1 + libmultipath/propsel.c | 25 ++++++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 7 +++ + multipath/multipath.conf.5 | 8 ++++ + 12 files changed, 200 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -344,6 +344,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(delay_watch_checks); + merge_num(delay_wait_checks); + merge_num(skip_kpartx); ++ merge_num(max_sectors_kb); + + /* + * Make sure features is consistent with +@@ -405,6 +406,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(delay_watch_checks); + overwrite_num(delay_wait_checks); + overwrite_num(skip_kpartx); ++ overwrite_num(max_sectors_kb); + + /* + * Make sure features is consistent with +@@ -682,6 +684,7 @@ load_config (char * file, struct udev *u + conf->skip_kpartx = DEFAULT_SKIP_KPARTX; + conf->remove_retries = 0; + conf->disable_changed_wwids = 0; ++ conf->max_sectors_kb = DEFAULT_MAX_SECTORS_KB; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -65,6 +65,7 @@ struct hwentry { + int delay_watch_checks; + int delay_wait_checks; + int skip_kpartx; ++ int max_sectors_kb; + char * bl_product; + }; + +@@ -92,6 +93,7 @@ struct mpentry { + int delay_watch_checks; + int delay_wait_checks; + int skip_kpartx; ++ int max_sectors_kb; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -148,6 +150,7 @@ struct config { + int skip_kpartx; + int remove_retries; + int disable_changed_wwids; ++ int max_sectors_kb; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -295,6 +295,7 @@ setup_map (struct multipath * mpp, char + select_delay_watch_checks(mpp); + select_delay_wait_checks(mpp); + select_skip_kpartx(mpp); ++ select_max_sectors_kb(mpp); + + sysfs_set_scsi_tmo(mpp); + /* +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -25,6 +25,7 @@ + #define DEFAULT_RETRIGGER_TRIES 3 + #define DEFAULT_UEV_WAIT_TIMEOUT 30 + #define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF ++#define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -976,6 +976,22 @@ def_disable_changed_wwids_handler(vector + return 0; + } + ++static int ++def_max_sectors_kb_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((conf->max_sectors_kb = atoi(buff)) < MAX_SECTORS_KB_MIN) ++ conf->max_sectors_kb = MAX_SECTORS_KB_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1765,6 +1781,26 @@ hw_delay_wait_checks_handler(vector strv + return 0; + } + ++static int ++hw_max_sectors_kb_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((hwe->max_sectors_kb = atoi(buff)) < MAX_SECTORS_KB_MIN) ++ hwe->max_sectors_kb = MAX_SECTORS_KB_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -2316,6 +2352,26 @@ mp_delay_wait_checks_handler(vector strv + return 0; + } + ++static int ++mp_max_sectors_kb_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((mpe->max_sectors_kb = atoi(buff)) < MAX_SECTORS_KB_MIN) ++ mpe->max_sectors_kb = MAX_SECTORS_KB_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2615,6 +2671,16 @@ snprint_mp_delay_wait_checks(char * buff + } + + static int ++snprint_mp_max_sectors_kb(char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->max_sectors_kb == MAX_SECTORS_KB_UNDEF) ++ return 0; ++ return snprintf(buff, len, "%d", mpe->max_sectors_kb); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -2993,6 +3059,16 @@ snprint_detect_prio(char * buff, int len + } + + static int ++snprint_hw_max_sectors_kb(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->max_sectors_kb == MAX_SECTORS_KB_UNDEF) ++ return 0; ++ return snprintf(buff, len, "%d", hwe->max_sectors_kb); ++} ++ ++static int + snprint_def_polling_interval (char * buff, int len, void * data) + { + return snprintf(buff, len, "%i", conf->checkint); +@@ -3461,6 +3537,14 @@ snprint_def_disable_changed_wwids(char * + } + + static int ++snprint_def_max_sectors_kb(char * buff, int len, void * data) ++{ ++ if (conf->max_sectors_kb == MAX_SECTORS_KB_UNDEF) ++ return 0; ++ return snprintf(buff, len, "%d", conf->max_sectors_kb); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3541,6 +3625,7 @@ init_keywords(void) + install_keyword("new_bindings_in_boot", &def_new_bindings_in_boot_handler, &snprint_def_new_bindings_in_boot); + install_keyword("remove_retries", &def_remove_retries_handler, &snprint_def_remove_retries); + install_keyword("disable_changed_wwids", &def_disable_changed_wwids_handler, &snprint_def_disable_changed_wwids); ++ install_keyword("max_sectors_kb", &def_max_sectors_kb_handler, &snprint_def_max_sectors_kb); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -3609,6 +3694,7 @@ init_keywords(void) + install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks); + install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks); + install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx); ++ install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb); + install_sublevel_end(); + + install_keyword_root("multipaths", &multipaths_handler); +@@ -3637,5 +3723,6 @@ init_keywords(void) + install_keyword("delay_watch_checks", &mp_delay_watch_checks_handler, &snprint_mp_delay_watch_checks); + install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks); + install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx); ++ install_keyword("max_sectors_kb", &mp_max_sectors_kb_handler, &snprint_mp_max_sectors_kb); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -27,6 +28,7 @@ + #include "discovery.h" + #include "prio.h" + #include "defaults.h" ++#include "devmapper.h" + + int + store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice, +@@ -166,6 +168,64 @@ declare_sysfs_get_str(rev); + declare_sysfs_get_str(dev); + + int ++sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload) ++{ ++ struct pathgroup * pgp; ++ struct path *pp; ++ char buff[11]; ++ struct udev_device *udevice = NULL; ++ int i, j, len, ret; ++ int max_sectors_kb; ++ ++ if (mpp->max_sectors_kb == MAX_SECTORS_KB_UNDEF) ++ return 0; ++ max_sectors_kb = mpp->max_sectors_kb; ++ if (is_reload) { ++ if (!mpp->dmi && dm_get_info(mpp->alias, &mpp->dmi) != 0) { ++ condlog(0, "failed to get dm info on %s to set max_sectors_kb", mpp->alias); ++ return 1; ++ } ++ udevice = udev_device_new_from_devnum(conf->udev, 'b', ++ makedev(mpp->dmi->major, ++ mpp->dmi->minor)); ++ if (!udevice) { ++ condlog(0, "failed to get udev device to set max_sectors_kb for %s", mpp->alias); ++ return 1; ++ } ++ if (sysfs_attr_get_value(udevice, "queue/max_sectors_kb", ++ buff, sizeof(buff)) <= 0) { ++ condlog(0, "failed to get current max_sectors_kb from %s", mpp->alias); ++ goto fail_reload; ++ } ++ if (sscanf(buff, "%u\n", &max_sectors_kb) != 1) { ++ condlog(0, "can't parse current max_sectors_kb from %s", ++ mpp->alias); ++ goto fail_reload; ++ } ++ udev_device_unref(udevice); ++ } ++ snprintf(buff, 11, "%d", max_sectors_kb); ++ len = strlen(buff); ++ ++ vector_foreach_slot (mpp->pg, pgp, i) { ++ vector_foreach_slot (pgp->paths, pp, j) { ++ ret = sysfs_attr_set_value(pp->udev, ++ "queue/max_sectors_kb", ++ buff, len); ++ if (ret < 0) { ++ condlog(0, "failed setting max_sectors_kb on %s : %s", pp->dev, strerror(-ret)); ++ return 1; ++ } ++ } ++ } ++ return 0; ++ ++fail_reload: ++ udev_device_unref(udevice); ++ return 1; ++} ++ ++int + sysfs_get_timeout(struct path *pp, unsigned int *timeout) + { + const char *attr = NULL; +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -41,6 +41,7 @@ int store_pathinfo (vector pathvec, vect + struct udev_device *udevice, int flag, + struct path **pp_ptr); + int sysfs_set_scsi_tmo (struct multipath *mpp); ++int sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload); + int sysfs_get_timeout(struct path *pp, unsigned int *timeout); + int sysfs_get_host_pci_name(struct path *pp, char *pci_name); + int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address); +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -880,3 +880,28 @@ select_skip_kpartx (struct multipath * m + condlog(3, "skip_kpartx = DISABLED (internal default)"); + return 0; + } ++ ++extern int ++select_max_sectors_kb (struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->max_sectors_kb != MAX_SECTORS_KB_UNDEF) { ++ mp->max_sectors_kb = mp->mpe->max_sectors_kb; ++ condlog(3, "max_sectors_kb = %i (multipath setting)", ++ mp->max_sectors_kb); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->max_sectors_kb != MAX_SECTORS_KB_UNDEF) { ++ mp->max_sectors_kb = mp->hwe->max_sectors_kb; ++ condlog(3, "max_sectors_kb = %i (controler setting)", ++ mp->max_sectors_kb); ++ return 0; ++ } ++ if (conf->max_sectors_kb != MAX_SECTORS_KB_UNDEF) { ++ mp->max_sectors_kb = conf->max_sectors_kb; ++ condlog(3, "max_sectors_kb = %i (config file default)", ++ mp->max_sectors_kb); ++ return 0; ++ } ++ mp->max_sectors_kb = MAX_SECTORS_KB_UNDEF; ++ return 0; ++} +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -24,3 +24,4 @@ int select_deferred_remove(struct multip + int select_delay_watch_checks (struct multipath * mp); + int select_delay_wait_checks (struct multipath * mp); + int select_skip_kpartx (struct multipath * mp); ++int select_max_sectors_kb (struct multipath * mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -128,6 +128,12 @@ enum skip_kpartx_states { + SKIP_KPARTX_ON, + }; + ++ ++enum max_sectors_kb_states { ++ MAX_SECTORS_KB_UNDEF = 0, ++ MAX_SECTORS_KB_MIN = 4, /* can't be smaller than page size */ ++}; ++ + enum scsi_protocol { + SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ + SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ +@@ -245,6 +251,7 @@ struct multipath { + int delay_wait_checks; + int force_udev_reload; + int skip_kpartx; ++ int max_sectors_kb; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -567,6 +567,10 @@ disable access to the path until the wwi + This sets how may times multipath will retry removing a device that is in-use. + Between each attempt, multipath will sleep 1 second. The default is + .I 0 ++.TP ++.B max_sectors_kb ++Sets the max_sectors_kb device parameter on all path devices and the multipath ++device to the specified value. Default is device dependent. + . + .SH "blacklist section" + The +@@ -678,6 +682,8 @@ section: + .B delay_wait_checks + .TP + .B skip_kpartx ++.TP ++.B max_sectors_kb + .RE + .PD + .LP +@@ -778,6 +784,8 @@ section: + .B delay_wait_checks + .TP + .B skip_kpartx ++.TP ++.B max_sectors_kb + .RE + .PD + .LP +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -21,7 +21,7 @@ + #include "devmapper.h" + #include "config.h" + #include "sysfs.h" +- ++#include "discovery.h" + #include "log_pthread.h" + #include + #include +@@ -330,6 +330,7 @@ extern int + dm_addmap_create (struct multipath *mpp, char * params) { + int ro; + ++ sysfs_set_max_sectors_kb(mpp, 0); + for (ro = 0; ro <= 1; ro++) { + int err; + +@@ -356,6 +357,7 @@ dm_addmap_create (struct multipath *mpp, + + extern int + dm_addmap_reload (struct multipath *mpp, char *params) { ++ sysfs_set_max_sectors_kb(mpp, 1); + if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW, SKIP_KPARTX_OFF)) + return 1; + if (errno != EROFS) diff --git a/SOURCES/0198-RHBZ-1372032-detect-path-checker.patch b/SOURCES/0198-RHBZ-1372032-detect-path-checker.patch new file mode 100644 index 0000000..48fcfce --- /dev/null +++ b/SOURCES/0198-RHBZ-1372032-detect-path-checker.patch @@ -0,0 +1,377 @@ +--- + libmultipath/config.c | 4 ++ + libmultipath/config.h | 2 + + libmultipath/defaults.h | 1 + libmultipath/dict.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/discovery.c | 1 + libmultipath/hwtable.c | 1 + libmultipath/propsel.c | 65 +++++++++++++++++++++++++++++++-------- + libmultipath/propsel.h | 1 + libmultipath/structs.h | 7 ++++ + multipath/multipath.conf.5 | 9 +++++ + 10 files changed, 152 insertions(+), 13 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -340,6 +340,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(user_friendly_names); + merge_num(retain_hwhandler); + merge_num(detect_prio); ++ merge_num(detect_checker); + merge_num(deferred_remove); + merge_num(delay_watch_checks); + merge_num(delay_wait_checks); +@@ -402,6 +403,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(user_friendly_names); + overwrite_num(retain_hwhandler); + overwrite_num(detect_prio); ++ overwrite_num(detect_checker); + overwrite_num(deferred_remove); + overwrite_num(delay_watch_checks); + overwrite_num(delay_wait_checks); +@@ -476,6 +478,7 @@ store_hwe (vector hwtable, struct hwentr + hwe->user_friendly_names = dhwe->user_friendly_names; + hwe->retain_hwhandler = dhwe->retain_hwhandler; + hwe->detect_prio = dhwe->detect_prio; ++ hwe->detect_checker = dhwe->detect_checker; + + if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product))) + goto out; +@@ -672,6 +675,7 @@ load_config (char * file, struct udev *u + conf->fast_io_fail = DEFAULT_FAST_IO_FAIL; + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; + conf->detect_prio = DEFAULT_DETECT_PRIO; ++ conf->detect_checker = DEFAULT_DETECT_CHECKER; + conf->deferred_remove = DEFAULT_DEFERRED_REMOVE; + conf->hw_strmatch = 0; + conf->force_sync = 0; +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -61,6 +61,7 @@ struct hwentry { + int user_friendly_names; + int retain_hwhandler; + int detect_prio; ++ int detect_checker; + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; +@@ -136,6 +137,7 @@ struct config { + int reassign_maps; + int retain_hwhandler; + int detect_prio; ++ int detect_checker; + int force_sync; + int deferred_remove; + int ignore_new_boot_devs; +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -19,6 +19,7 @@ + #define DEFAULT_FAST_IO_FAIL 5 + #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF + #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF ++#define DEFAULT_DETECT_CHECKER DETECT_CHECKER_OFF + #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF + #define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF + #define DEFAULT_RETRIGGER_DELAY 10 +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -714,6 +714,29 @@ def_detect_prio_handler(vector strvec) + } + + static int ++def_detect_checker_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->detect_checker = DETECT_CHECKER_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->detect_checker = DETECT_CHECKER_ON; ++ else ++ conf->detect_checker = DETECT_CHECKER_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + def_hw_strmatch_handler(vector strvec) + { + char *buff; +@@ -1682,6 +1705,33 @@ hw_detect_prio_handler(vector strvec) + } + + static int ++hw_detect_checker_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->detect_checker = DETECT_CHECKER_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->detect_checker = DETECT_CHECKER_ON; ++ else ++ hwe->detect_checker = DETECT_CHECKER_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + hw_deferred_remove_handler(vector strvec) + { + struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); +@@ -3059,6 +3109,19 @@ snprint_detect_prio(char * buff, int len + } + + static int ++snprint_detect_checker(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->detect_checker == DETECT_CHECKER_ON) ++ return snprintf(buff, len, "yes"); ++ else if (hwe->detect_checker == DETECT_CHECKER_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return 0; ++} ++ ++static int + snprint_hw_max_sectors_kb(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -3424,6 +3487,15 @@ snprint_def_detect_prio(char * buff, int + } + + static int ++snprint_def_detect_checker(char * buff, int len, void * data) ++{ ++ if (conf->detect_checker == DETECT_PRIO_ON) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_def_hw_strmatch(char * buff, int len, void * data) + { + if (conf->hw_strmatch) +@@ -3611,6 +3683,7 @@ init_keywords(void) + install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths); + install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler); + install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio); ++ install_keyword("detect_path_checker", &def_detect_checker_handler, &snprint_def_detect_checker); + install_keyword("hw_str_match", &def_hw_strmatch_handler, &snprint_def_hw_strmatch); + install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync); + install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove); +@@ -3690,6 +3763,7 @@ init_keywords(void) + install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names); + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler); + install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio); ++ install_keyword("detect_path_checker", &hw_detect_checker_handler, &snprint_detect_checker); + install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove); + install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks); + install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1107,6 +1107,7 @@ get_state (struct path * pp, int daemon) + return PATH_UNCHECKED; + } + } ++ select_detect_checker(pp); + select_checker(pp); + if (!checker_selected(c)) { + condlog(3, "%s: No checker selected", pp->dev); +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -289,6 +289,7 @@ static struct hwentry default_hw[] = { + .prio_args = NULL, + .retain_hwhandler = RETAIN_HWHANDLER_ON, + .detect_prio = DETECT_PRIO_ON, ++ .detect_checker = DETECT_CHECKER_ON, + }, + { + .vendor = "EMC", +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -335,11 +335,43 @@ select_hwhandler (struct multipath * mp) + return 0; + } + ++int ++detect_alua(struct path * pp) ++{ ++ int ret; ++ int tpgs = 0; ++ ++ if ((tpgs = get_target_port_group_support(pp->fd)) <= 0) ++ return 0; ++ pp->tpgs = tpgs; ++ ret = get_target_port_group(pp->fd, NULL); ++ if (ret < 0) ++ return 0; ++ if (get_asymmetric_access_state(pp->fd, ret, NULL) < 0) ++ return 0; ++ return 1; ++} ++ ++void ++detect_checker(struct path * pp) ++{ ++ if (detect_alua(pp)) ++ checker_get(&pp->checker, TUR); ++} ++ + extern int + select_checker(struct path *pp) + { + struct checker * c = &pp->checker; + ++ if (pp->detect_checker == DETECT_CHECKER_ON) { ++ detect_checker(pp); ++ if (checker_selected(c)) { ++ condlog(3, "%s: path checker = %s (detected setting)", ++ pp->dev, checker_name(c)); ++ goto out; ++ } ++ } + if (pp->hwe && pp->hwe->checker_name) { + checker_get(c, pp->hwe->checker_name); + condlog(3, "%s: path checker = %s (controller setting)", +@@ -396,19 +428,8 @@ select_getuid (struct path * pp) + void + detect_prio(struct path * pp) + { +- int ret; +- struct prio *p = &pp->prio; +- int tpgs = 0; +- +- if ((tpgs = get_target_port_group_support(pp->fd)) <= 0) +- return; +- pp->tpgs = tpgs; +- ret = get_target_port_group(pp->fd, NULL); +- if (ret < 0) +- return; +- if (get_asymmetric_access_state(pp->fd, ret, NULL) < 0) +- return; +- prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS); ++ if (detect_alua(pp)) ++ prio_get(&pp->prio, PRIO_ALUA, DEFAULT_PRIO_ARGS); + } + + extern int +@@ -803,6 +824,24 @@ select_detect_prio (struct path * pp) + return 0; + } + ++extern int ++select_detect_checker (struct path * pp) ++{ ++ if (pp->hwe && pp->hwe->detect_checker) { ++ pp->detect_checker = pp->hwe->detect_checker; ++ condlog(3, "%s: detect_checker = %d (controller default)", pp->dev, pp->detect_checker); ++ return 0; ++ } ++ if (conf->detect_checker) { ++ pp->detect_checker = conf->detect_checker; ++ condlog(3, "%s: detect_checker = %d (config file default)", pp->dev, pp->detect_checker); ++ return 0; ++ } ++ pp->detect_checker = DEFAULT_DETECT_CHECKER; ++ condlog(3, "%s: detect_checker = %d (compiled in default)", pp->dev, pp->detect_checker); ++ return 0; ++} ++ + extern int + select_delay_watch_checks (struct multipath * mp) + { +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -20,6 +20,7 @@ int select_dev_loss(struct multipath *mp + int select_reservation_key(struct multipath *mp); + int select_retain_hwhandler (struct multipath * mp); + int select_detect_prio(struct path * pp); ++int select_detect_checker(struct path * pp); + int select_deferred_remove(struct multipath *mp); + int select_delay_watch_checks (struct multipath * mp); + int select_delay_wait_checks (struct multipath * mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -115,6 +115,12 @@ enum detect_prio_states { + DETECT_PRIO_ON, + }; + ++enum detect_checker_states { ++ DETECT_CHECKER_UNDEF, ++ DETECT_CHECKER_OFF, ++ DETECT_CHECKER_ON, ++}; ++ + enum deferred_remove_states { + DEFERRED_REMOVE_UNDEF, + DEFERRED_REMOVE_OFF, +@@ -204,6 +210,7 @@ struct path { + int priority; + int pgindex; + int detect_prio; ++ int detect_checker; + int watch_checks; + int wait_checks; + int tpgs; +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -448,6 +448,15 @@ will automatically use the + prioritizer. If not, the prioritizer will be selected as usual. Default is + .I no + .TP ++.B detect_checker ++If set to ++.I yes ++, multipath will try to detect if the device supports ALUA. If so, the device ++will automatically use the ++.I tur ++checker. If not, the prioritizer will be selected as ususal. Default is ++.I no ++.TP + .B hw_str_match + If set to + .I yes diff --git a/SOURCES/0199-RHBZ-1279355-3pardata-config.patch b/SOURCES/0199-RHBZ-1279355-3pardata-config.patch new file mode 100644 index 0000000..037de3d --- /dev/null +++ b/SOURCES/0199-RHBZ-1279355-3pardata-config.patch @@ -0,0 +1,17 @@ +--- + libmultipath/hwtable.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -69,7 +69,7 @@ static struct hwentry default_hw[] = { + .pgpolicy = MULTIBUS, + .pgfailback = FAILBACK_UNDEF, + .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = NO_PATH_RETRY_UNDEF, ++ .no_path_retry = 12, + .checker_name = DEFAULT_CHECKER, + .prio_name = DEFAULT_PRIO, + .prio_args = NULL, diff --git a/SOURCES/0200-RHBZ-1402092-orphan-status.patch b/SOURCES/0200-RHBZ-1402092-orphan-status.patch new file mode 100644 index 0000000..67830ca --- /dev/null +++ b/SOURCES/0200-RHBZ-1402092-orphan-status.patch @@ -0,0 +1,29 @@ +--- + libmultipath/print.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -386,7 +386,9 @@ snprint_dev_t (char * buff, size_t len, + static int + snprint_offline (char * buff, size_t len, struct path * pp) + { +- if (pp->offline) ++ if (!pp || !pp->mpp) ++ return snprintf(buff, len, "unknown"); ++ else if (pp->offline) + return snprintf(buff, len, "offline"); + else + return snprintf(buff, len, "running"); +@@ -395,6 +397,9 @@ snprint_offline (char * buff, size_t len + static int + snprint_chk_state (char * buff, size_t len, struct path * pp) + { ++ if (!pp || !pp->mpp) ++ return snprintf(buff, len, "undef"); ++ + switch (pp->state) { + case PATH_UP: + return snprintf(buff, len, "ready"); diff --git a/SOURCES/0201-RHBZ-1403552-silence-warning.patch b/SOURCES/0201-RHBZ-1403552-silence-warning.patch new file mode 100644 index 0000000..c816ea0 --- /dev/null +++ b/SOURCES/0201-RHBZ-1403552-silence-warning.patch @@ -0,0 +1,59 @@ +--- + libmultipath/discovery.c | 15 +++++++++++---- + multipathd/main.c | 10 ++++++++++ + 2 files changed, 21 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -84,10 +84,6 @@ path_discover (vector pathvec, struct co + if (!devname) + return PATHINFO_FAILED; + +- if (filter_devnode(conf->blist_devnode, conf->elist_devnode, +- (char *)devname) > 0) +- return PATHINFO_SKIPPED; +- + pp = find_path_by_dev(pathvec, (char *)devname); + if (!pp) { + return store_pathinfo(pathvec, conf->hwtable, +@@ -1286,6 +1282,17 @@ pathinfo (struct path *pp, vector hwtabl + if (!pp) + return PATHINFO_FAILED; + ++ /* ++ * For behavior backward-compatibility with multipathd, ++ * the blacklisting by filter_devnode() is not ++ * limited by DI_BLACKLIST and occurs before this debug ++ * message with the mask value. ++ */ ++ if (filter_devnode(conf->blist_devnode, ++ conf->elist_devnode, ++ pp->dev) > 0) ++ return PATHINFO_SKIPPED; ++ + condlog(3, "%s: mask = 0x%x", pp->dev, mask); + + /* +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -776,6 +776,16 @@ uev_update_path (struct uevent *uev, str + + pp = find_path_by_dev(vecs->pathvec, uev->kernel); + if (!pp) { ++ /* If the path is blacklisted, print a debug/non-default verbosity message. */ ++ if (uev->udev) { ++ int flag = DI_SYSFS | DI_WWID; ++ ++ if (store_pathinfo(NULL, conf->hwtable, uev->udev, flag, NULL) == PATHINFO_SKIPPED) { ++ condlog(3, "%s: spurious uevent, path is blacklisted", uev->kernel); ++ return 0; ++ } ++ } ++ + condlog(0, "%s: spurious uevent, path not found", + uev->kernel); + return 1; diff --git a/SOURCES/0202-RHBZ-1362120-skip-prio.patch b/SOURCES/0202-RHBZ-1362120-skip-prio.patch new file mode 100644 index 0000000..8a187ad --- /dev/null +++ b/SOURCES/0202-RHBZ-1362120-skip-prio.patch @@ -0,0 +1,18 @@ +--- + multipathd/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1248,7 +1248,8 @@ int update_prio(struct path *pp, int ref + return changed; + } + oldpriority = pp->priority; +- pathinfo(pp, conf->hwtable, DI_PRIO); ++ if (pp->state != PATH_DOWN) ++ pathinfo(pp, conf->hwtable, DI_PRIO); + + if (pp->priority == oldpriority) + return 0; diff --git a/SOURCES/0203-RHBZ-1363718-add-msgs.patch b/SOURCES/0203-RHBZ-1363718-add-msgs.patch new file mode 100644 index 0000000..9eaadc0 --- /dev/null +++ b/SOURCES/0203-RHBZ-1363718-add-msgs.patch @@ -0,0 +1,24 @@ +--- + multipathd/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -337,6 +337,7 @@ ev_add_map (char * dev, char * alias, st + + if (mpp) { + if (mpp->wait_for_udev > 1) { ++ condlog(2, "%s: performing delayed actions", mpp->alias); + if (update_map(mpp, vecs)) + /* setup multipathd removed the map */ + return 1; +@@ -535,6 +536,7 @@ ev_add_path (struct path * pp, struct ve + pp->tpgs == TPGS_IMPLICIT)) + mpp->force_udev_reload = 1; + else { ++ condlog(2, "%s : delaying path addition until %s is fully initialized", pp->dev, mpp->alias); + mpp->wait_for_udev = 2; + orphan_path(pp); + return 0; diff --git a/SOURCES/0204-RHBZ-1406226-nimble-config.patch b/SOURCES/0204-RHBZ-1406226-nimble-config.patch new file mode 100644 index 0000000..c3f2e90 --- /dev/null +++ b/SOURCES/0204-RHBZ-1406226-nimble-config.patch @@ -0,0 +1,28 @@ +--- + libmultipath/hwtable.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1189,6 +1189,19 @@ static struct hwentry default_hw[] = { + .dev_loss = 30, + }, + { ++ .vendor = "Nimble", ++ .product = "Server", ++ .features = "1 queue_if_no_path", ++ .hwhandler = "1 alua", ++ .pgpolicy = GROUP_BY_PRIO, ++ .prio_name = PRIO_ALUA, ++ .prio_args = NULL, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .selector = "round-robin 0", ++ .dev_loss = MAX_DEV_LOSS_TMO, ++ .fast_io_fail = 1, ++ }, ++ { + .vendor = "XtremIO", + .product = "XtremApp", + .features = DEFAULT_FEATURES, diff --git a/SOURCES/0205-RHBZ-1416569-reset-stats.patch b/SOURCES/0205-RHBZ-1416569-reset-stats.patch new file mode 100644 index 0000000..b152f88 --- /dev/null +++ b/SOURCES/0205-RHBZ-1416569-reset-stats.patch @@ -0,0 +1,126 @@ +--- + multipathd/cli.c | 2 ++ + multipathd/cli_handlers.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + multipathd/cli_handlers.h | 2 ++ + multipathd/main.c | 2 ++ + multipathd/multipathd.8 | 6 ++++++ + 5 files changed, 56 insertions(+) + +Index: multipath-tools-130222/multipathd/cli.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.c ++++ multipath-tools-130222/multipathd/cli.c +@@ -482,6 +482,8 @@ cli_init (void) { + add_handler(LIST+BLACKLIST, NULL); + add_handler(LIST+DEVICES, NULL); + add_handler(LIST+WILDCARDS, NULL); ++ add_handler(RESET+MAPS+STATS, NULL); ++ add_handler(RESET+MAP+STATS, NULL); + add_handler(ADD+PATH, NULL); + add_handler(DEL+PATH, NULL); + add_handler(ADD+MAP, NULL); +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -233,6 +233,17 @@ show_config (char ** r, int * len) + return 0; + } + ++void ++reset_stats(struct multipath * mpp) ++{ ++ mpp->stat_switchgroup = 0; ++ mpp->stat_path_failures = 0; ++ mpp->stat_map_loads = 0; ++ mpp->stat_total_queueing_time = 0; ++ mpp->stat_queueing_timeouts = 0; ++ mpp->stat_map_failures = 0; ++} ++ + int + cli_list_config (void * v, char ** reply, int * len, void * data) + { +@@ -501,6 +512,39 @@ cli_list_daemon (void * v, char ** reply + } + + int ++cli_reset_maps_stats (void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ int i; ++ struct multipath * mpp; ++ ++ condlog(3, "reset multipaths stats (operator)"); ++ ++ vector_foreach_slot(vecs->mpvec, mpp, i) { ++ reset_stats(mpp); ++ } ++ return 0; ++} ++ ++int ++cli_reset_map_stats (void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ struct multipath * mpp; ++ char * param = get_keyparam(v, MAP); ++ ++ param = convert_dev(param, 0); ++ mpp = find_mp_by_str(vecs->mpvec, param); ++ ++ if (!mpp) ++ return 1; ++ ++ condlog(3, "reset multipath %s stats (operator)", param); ++ reset_stats(mpp); ++ return 0; ++} ++ ++int + cli_add_path (void * v, char ** reply, int * len, void * data) + { + struct vectors * vecs = (struct vectors *)data; +Index: multipath-tools-130222/multipathd/cli_handlers.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.h ++++ multipath-tools-130222/multipathd/cli_handlers.h +@@ -16,6 +16,8 @@ int cli_list_config (void * v, char ** r + int cli_list_blacklist (void * v, char ** reply, int * len, void * data); + int cli_list_devices (void * v, char ** reply, int * len, void * data); + int cli_list_wildcards (void * v, char ** reply, int * len, void * data); ++int cli_reset_maps_stats (void * v, char ** reply, int * len, void * data); ++int cli_reset_map_stats (void * v, char ** reply, int * len, void * data); + int cli_add_path (void * v, char ** reply, int * len, void * data); + int cli_del_path (void * v, char ** reply, int * len, void * data); + int cli_add_map (void * v, char ** reply, int * len, void * data); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1011,6 +1011,8 @@ uxlsnrloop (void * ap) + set_handler_callback(LIST+BLACKLIST, cli_list_blacklist); + set_handler_callback(LIST+DEVICES, cli_list_devices); + set_handler_callback(LIST+WILDCARDS, cli_list_wildcards); ++ set_handler_callback(RESET+MAPS+STATS, cli_reset_maps_stats); ++ set_handler_callback(RESET+MAP+STATS, cli_reset_map_stats); + set_handler_callback(ADD+PATH, cli_add_path); + set_handler_callback(DEL+PATH, cli_del_path); + set_handler_callback(ADD+MAP, cli_add_map); +Index: multipath-tools-130222/multipathd/multipathd.8 +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.8 ++++ multipath-tools-130222/multipathd/multipathd.8 +@@ -87,6 +87,12 @@ Show all available block devices by name + .B list|show status + Show the number of path checkers in each possible state, the number of monitored paths, and whether multipathd is currently handling a uevent. + .TP ++.B reset maps|multipaths stats ++Reset the stat counters for all multipath devices. ++.TP ++.B reset map|multipath $map stats ++Reset the stat counters for a specific multipath device. ++.TP + .B add path $path + Add a path to the list of monitored paths. $path is as listed in /sys/block (e.g. sda). + .TP diff --git a/SOURCES/0206-RHBZ-1239173-pt2-no-paths.patch b/SOURCES/0206-RHBZ-1239173-pt2-no-paths.patch new file mode 100644 index 0000000..c38be56 --- /dev/null +++ b/SOURCES/0206-RHBZ-1239173-pt2-no-paths.patch @@ -0,0 +1,121 @@ +--- + libmultipath/configure.c | 2 - + libmultipath/devmapper.h | 6 ++++ + multipath/11-dm-mpath.rules | 61 +++++++++++++++++++++++++++++++++----------- + 3 files changed, 54 insertions(+), 15 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -615,7 +615,7 @@ extern int + domap (struct multipath * mpp, char * params) + { + int r = 0; +- uint16_t udev_flags = ((mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG) | ((mpp->skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0); ++ uint16_t udev_flags = ((mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG) | ((mpp->skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0) | ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG); + + /* + * last chance to quit before touching the devmaps +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -18,6 +18,12 @@ + #define MPATH_UDEV_NO_KPARTX_FLAG 0 + #endif + ++#ifdef DM_SUBSYSTEM_UDEV_FLAG2 ++#define MPATH_UDEV_NO_PATHS_FLAG DM_SUBSYSTEM_UDEV_FLAG2 ++#else ++#define MPATH_UDEV_NO_PATHS_FLAG 0 ++#endif ++ + void dm_init(void); + int dm_prereq (void); + int dm_drv_version (unsigned int * version, char * str); +Index: multipath-tools-130222/multipath/11-dm-mpath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/11-dm-mpath.rules ++++ multipath-tools-130222/multipath/11-dm-mpath.rules +@@ -2,33 +2,66 @@ ACTION!="add|change", GOTO="mpath_end" + ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="mpath_end" + ENV{DM_UUID}!="mpath-?*", GOTO="mpath_end" + ++IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD" ++IMPORT{db}="MPATH_DEVICE_READY" ++ ++# If this uevent didn't come from dm, don't try to update the ++# device state ++ENV{DM_COOKIE}!="?*", ENV{DM_ACTION}!="PATH_*", IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG", IMPORT{db}="DM_NOSCAN", GOTO="scan_import" ++ ++ENV{.MPATH_DEVICE_READY_OLD}="$env{MPATH_DEVICE_READY}" ++ ++# multipath sets DM_SUBSYSTEM_UDEV_FLAG2 when it reloads a ++# table with no active devices. If this happens, mark the ++# device not ready ++ENV{DM_SUBSYSTEM_UDEV_FLAG2}=="1", ENV{MPATH_DEVICE_READY}="0",\ ++ GOTO="mpath_action" ++ ++# If the last path has failed mark the device not ready ++ENV{DM_ACTION}=="PATH_FAILED", ENV{DM_NR_VALID_PATHS}=="0",\ ++ ENV{MPATH_DEVICE_READY}="0", GOTO="mpath_action" ++ ++# Don't mark a device ready on a PATH_FAILED event. even if ++# DM_NR_VALID_PATHS is greater than 0. Just keep the existing ++# value ++ENV{DM_ACTION}=="PATH_FAILED", GOTO="mpath_action" ++ ++# This event is either a PATH_REINSTATED or a table reload where ++# there are active paths. Mark the device ready ++ENV{MPATH_DEVICE_READY}="" ++ ++LABEL="mpath_action" ++# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem. ++# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its ++# paths are lost/recovered. For any stack above the mpath device, this is not ++# something that should be reacted upon since it would be useless extra work. ++# It's exactly mpath's job to provide *seamless* device access to any of the ++# paths that are available underneath. ++ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0" ++ + # Do not initiate scanning if no path is available, + # otherwise there would be a hang or IO error on access. + # We'd like to avoid this, especially within udev processing. +-ENV{DM_NR_VALID_PATHS}!="?*", IMPORT{db}="DM_NR_VALID_PATHS" +-ENV{DM_NR_VALID_PATHS}=="0", ENV{DM_NOSCAN}="1" ++ENV{MPATH_DEVICE_READY}=="0", ENV{DM_NOSCAN}="1" + + # Also skip all foreign rules if no path is available. + # Remember the original value of DM_DISABLE_OTHER_RULES_FLAG + # and restore it back once we have at least one path available. +-IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD" +-ENV{DM_ACTION}=="PATH_FAILED",\ +- ENV{DM_NR_VALID_PATHS}=="0",\ ++ENV{MPATH_DEVICE_READY}=="0", ENV{.MPATH_DEVICE_READY_OLD}!="0",\ + ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}=="",\ + ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}",\ + ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" +-ENV{DM_ACTION}=="PATH_REINSTATED",\ +- ENV{DM_NR_VALID_PATHS}=="1",\ ++ENV{MPATH_DEVICE_READY}!="0", ENV{.MPATH_DEVICE_READY_OLD}=="0",\ + ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}",\ + ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="",\ + ENV{DM_ACTIVATION}="1" + +-# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem. +-# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its +-# paths are lost/recovered. For any stack above the mpath device, this is not +-# something that should be reacted upon since it would be useless extra work. +-# It's exactly mpath's job to provide *seamless* device access to any of the +-# paths that are available underneath. +-ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0" ++LABEL="scan_import" ++ENV{DM_NOSCAN}!="1", GOTO="mpath_end" ++ENV{ID_FS_TYPE}!="?*", IMPORT{db}="ID_FS_TYPE" ++ENV{ID_FS_USAGE}!="?*", IMPORT{db}="ID_FS_USAGE" ++ENV{ID_FS_UUID}!="?*", IMPORT{db}="ID_FS_UUID" ++ENV{ID_FS_ENC}!="?*", IMPORT{db}="ID_FS_UUID_ENC" ++ENV{ID_FS_VERSION}!="?*", IMPORT{db}="ID_FS_VERSION" + + LABEL="mpath_end" diff --git a/SOURCES/0207-UP-add-libmpathcmd.patch b/SOURCES/0207-UP-add-libmpathcmd.patch new file mode 100644 index 0000000..ee19d65 --- /dev/null +++ b/SOURCES/0207-UP-add-libmpathcmd.patch @@ -0,0 +1,840 @@ +From c146b5840bbd7ad89c8a8de6192590ad0595a977 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 7 Apr 2016 18:19:58 -0500 +Subject: [PATCH] Add libmpathcmd library and use it internally + +Other programs would like to communicate with multipathd to issue +command or check status. Instead of having them exec multipathd, +I've pulled the code that sends commands and receives replies from +multipathd into its own library. I've made the multipath tools use +this library internally as well. + +Signed-off-by: Benjamin Marzinski +--- + Makefile | 1 + Makefile.inc | 2 + libmpathcmd/Makefile | 32 +++++++ + libmpathcmd/mpath_cmd.c | 178 +++++++++++++++++++++++++++++++++++++++ + libmpathcmd/mpath_cmd.h | 125 +++++++++++++++++++++++++++ + libmpathpersist/Makefile | 5 - + libmpathpersist/mpath_updatepr.c | 30 +++--- + libmultipath/Makefile | 4 + libmultipath/config.c | 1 + libmultipath/configure.c | 10 +- + libmultipath/uxsock.c | 88 +++---------------- + libmultipath/uxsock.h | 6 - + mpathpersist/Makefile | 2 + multipath/Makefile | 5 - + multipathd/Makefile | 4 + multipathd/uxclnt.c | 13 +- + multipathd/uxlsnr.c | 9 - + 17 files changed, 401 insertions(+), 114 deletions(-) + create mode 100644 libmpathcmd/Makefile + create mode 100644 libmpathcmd/mpath_cmd.c + create mode 100644 libmpathcmd/mpath_cmd.h + +Index: multipath-tools-130222/Makefile +=================================================================== +--- multipath-tools-130222.orig/Makefile ++++ multipath-tools-130222/Makefile +@@ -20,6 +20,7 @@ export KRNLSRC + export KRNLOBJ + + BUILDDIRS = \ ++ libmpathcmd \ + libmultipath \ + libmultipath/prioritizers \ + libmultipath/checkers \ +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -34,6 +34,8 @@ syslibdir = $(prefix)/usr/$(LIB) + libdir = $(prefix)/usr/$(LIB)/multipath + unitdir = $(prefix)/lib/systemd/system + mpathpersistdir = $(TOPDIR)/libmpathpersist ++includedir = $(prefix)/usr/include ++mpathcmddir = $(TOPDIR)/libmpathcmd + + GZIP = /bin/gzip -9 -c + INSTALL_PROGRAM = install +Index: multipath-tools-130222/libmpathcmd/Makefile +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmpathcmd/Makefile +@@ -0,0 +1,32 @@ ++# Makefile ++# ++include ../Makefile.inc ++ ++SONAME=0 ++DEVLIB = libmpathcmd.so ++LIBS = $(DEVLIB).$(SONAME) ++ ++CFLAGS += -fPIC ++ ++OBJS = mpath_cmd.o ++ ++all: $(LIBS) ++ ++$(LIBS): $(OBJS) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS) ++ ln -sf $@ $(DEVLIB) ++ ++install: $(LIBS) ++ $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) ++ $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) ++ ln -sf $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ $(INSTALL_PROGRAM) -d $(DESTDIR)$(includedir) ++ $(INSTALL_PROGRAM) -m 644 mpath_cmd.h $(DESTDIR)$(includedir) ++ ++uninstall: ++ rm -f $(DESTDIR)$(syslibdir)/$(LIBS) ++ rm -f $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ rm -f $(DESTDIR)$(includedir)/mpath_cmd.h ++ ++clean: ++ rm -f core *.a *.o *.gz *.so *.so.* +Index: multipath-tools-130222/libmpathcmd/mpath_cmd.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmpathcmd/mpath_cmd.c +@@ -0,0 +1,178 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mpath_cmd.h" ++ ++/* ++ * keep reading until its all read ++ */ ++static ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout) ++{ ++ size_t total = 0; ++ ssize_t n; ++ int ret; ++ struct pollfd pfd; ++ ++ while (len) { ++ pfd.fd = fd; ++ pfd.events = POLLIN; ++ ret = poll(&pfd, 1, timeout); ++ if (!ret) { ++ errno = ETIMEDOUT; ++ return -1; ++ } else if (ret < 0) { ++ if (errno == EINTR) ++ continue; ++ return -1; ++ } else if (!(pfd.revents & POLLIN)) ++ continue; ++ n = read(fd, buf, len); ++ if (n < 0) { ++ if ((errno == EINTR) || (errno == EAGAIN)) ++ continue; ++ return -1; ++ } ++ if (!n) ++ return total; ++ buf = n + (char *)buf; ++ len -= n; ++ total += n; ++ } ++ return total; ++} ++ ++/* ++ * keep writing until it's all sent ++ */ ++static size_t write_all(int fd, const void *buf, size_t len) ++{ ++ size_t total = 0; ++ ++ while (len) { ++ ssize_t n = write(fd, buf, len); ++ if (n < 0) { ++ if ((errno == EINTR) || (errno == EAGAIN)) ++ continue; ++ return total; ++ } ++ if (!n) ++ return total; ++ buf = n + (char *)buf; ++ len -= n; ++ total += n; ++ } ++ return total; ++} ++ ++/* ++ * connect to a unix domain socket ++ */ ++int mpath_connect(void) ++{ ++ int fd, len; ++ struct sockaddr_un addr; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sun_family = AF_LOCAL; ++ addr.sun_path[0] = '\0'; ++ len = strlen(DEFAULT_SOCKET) + 1 + sizeof(sa_family_t); ++ strncpy(&addr.sun_path[1], DEFAULT_SOCKET, len); ++ ++ fd = socket(AF_LOCAL, SOCK_STREAM, 0); ++ if (fd == -1) ++ return -1; ++ ++ if (connect(fd, (struct sockaddr *)&addr, len) == -1) { ++ close(fd); ++ return -1; ++ } ++ ++ return fd; ++} ++ ++int mpath_disconnect(int fd) ++{ ++ return close(fd); ++} ++ ++ssize_t mpath_recv_reply_len(int fd, unsigned int timeout) ++{ ++ size_t len; ++ ssize_t ret; ++ ++ ret = read_all(fd, &len, sizeof(len), timeout); ++ if (ret < 0) ++ return ret; ++ if (ret != sizeof(len)) { ++ errno = EIO; ++ return -1; ++ } ++ return len; ++} ++ ++int mpath_recv_reply_data(int fd, char *reply, size_t len, ++ unsigned int timeout) ++{ ++ ssize_t ret; ++ ++ ret = read_all(fd, reply, len, timeout); ++ if (ret < 0) ++ return ret; ++ if (ret != len) { ++ errno = EIO; ++ return -1; ++ } ++ reply[len - 1] = '\0'; ++ return 0; ++} ++ ++int mpath_recv_reply(int fd, char **reply, unsigned int timeout) ++{ ++ int err; ++ ssize_t len; ++ ++ *reply = NULL; ++ len = mpath_recv_reply_len(fd, timeout); ++ if (len <= 0) ++ return -1; ++ *reply = malloc(len); ++ if (!*reply) ++ return -1; ++ err = mpath_recv_reply_data(fd, *reply, len, timeout); ++ if (err) { ++ free(*reply); ++ *reply = NULL; ++ return -1; ++ } ++ return 0; ++} ++ ++int mpath_send_cmd(int fd, const char *cmd) ++{ ++ size_t len; ++ ++ if (cmd != NULL) ++ len = strlen(cmd) + 1; ++ else ++ len = 0; ++ if (write_all(fd, &len, sizeof(len)) != sizeof(len)) ++ return -1; ++ if (len && write_all(fd, cmd, len) != len) ++ return -1; ++ return 0; ++} ++ ++int mpath_process_cmd(int fd, const char *cmd, char **reply, ++ unsigned int timeout) ++{ ++ if (mpath_send_cmd(fd, cmd) != 0) ++ return -1; ++ return mpath_recv_reply(fd, reply, timeout); ++} +Index: multipath-tools-130222/libmpathcmd/mpath_cmd.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmpathcmd/mpath_cmd.h +@@ -0,0 +1,125 @@ ++/* ++ * Copyright (C) 2015 Red Hat, Inc. ++ * ++ * This file is part of the device-mapper multipath userspace tools. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifndef LIB_MPATH_CMD_H ++#define LIB_MPATH_CMD_H ++ ++#ifdef __cpluscplus ++extern "C" { ++#endif ++ ++#define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" ++#define DEFAULT_REPLY_TIMEOUT 10000 ++ ++ ++/* ++ * DESCRIPTION: ++ * Connect to the running multipathd daemon. On systems with the ++ * multipathd.socket systemd unit file installed, this command will ++ * start multipathd if it is not already running. This function ++ * must be run before any of the others in this library ++ * ++ * RETURNS: ++ * A file descriptor on success. -1 on failure (with errno set). ++ */ ++int mpath_connect(void); ++ ++ ++/* ++ * DESCRIPTION: ++ * Disconnect from the multipathd daemon. This function must be ++ * run after after processing all the multipath commands. ++ * ++ * RETURNS: ++ * 0 on success. -1 on failure (with errno set). ++ */ ++int mpath_disconnect(int fd); ++ ++ ++/* ++ * DESCRIPTION ++ * Send multipathd a command and return the reply. This function ++ * does the same as calling mpath_send_cmd() and then ++ * mpath_recv_reply() ++ * ++ * RETURNS: ++ * 0 on successs, 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). ++ */ ++int mpath_process_cmd(int fd, const char *cmd, char **reply, ++ unsigned int timeout); ++ ++ ++/* ++ * DESCRIPTION: ++ * Send a command to multipathd ++ * ++ * RETURNS: ++ * 0 on success. -1 on failure (with errno set) ++ */ ++int mpath_send_cmd(int fd, const char *cmd); ++ ++ ++/* ++ * DESCRIPTION: ++ * Return a reply from multipathd for a previously sent command. ++ * This is equivalent to calling mpath_recv_reply_len(), allocating ++ * a buffer of the appropriate size, and then calling ++ * mpath_recv_reply_data() with that buffer. ++ * ++ * RETURNS: ++ * 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). ++ */ ++int mpath_recv_reply(int fd, char **reply, unsigned int timeout); ++ ++ ++/* ++ * DESCRIPTION: ++ * Return the size of the upcoming reply data from the sent multipath ++ * command. This must be called before calling mpath_recv_reply_data(). ++ * ++ * RETURNS: ++ * The required size of the reply data buffer on success. -1 on ++ * failure (with errno set). ++ */ ++ssize_t mpath_recv_reply_len(int fd, unsigned int timeout); ++ ++ ++/* ++ * DESCRIPTION: ++ * Return the reply data from the sent multipath command. ++ * mpath_recv_reply_len must be called first. reply must point to a ++ * buffer of len size. ++ * ++ * RETURNS: ++ * 0 on success, and reply will contain the reply data string. -1 ++ * on failure (with errno set). ++ */ ++int mpath_recv_reply_data(int fd, char *reply, size_t len, ++ unsigned int timeout); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /* LIB_MPATH_CMD_H */ +Index: multipath-tools-130222/libmpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/Makefile ++++ multipath-tools-130222/libmpathpersist/Makefile +@@ -10,8 +10,9 @@ DEVLIB = libmpathpersist.so + LIBS = $(DEVLIB).$(SONAME) + + +-CFLAGS += -fPIC -I$(multipathdir) -I$(mpathpersistdir) +-LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath ++CFLAGS += -fPIC -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) ++LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ ++ -L$(mpathcmddir) -lmpathcmd + + OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + +Index: multipath-tools-130222/libmpathpersist/mpath_updatepr.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_updatepr.c ++++ multipath-tools-130222/libmpathpersist/mpath_updatepr.c +@@ -12,9 +12,9 @@ + #include + #include + #include ++#include ++#include + #include "memory.h" +-#include "../libmultipath/uxsock.h" +-#include "../libmultipath/defaults.h" + + unsigned long mem_allocated; /* Total memory used in Bytes */ + +@@ -23,10 +23,9 @@ int update_prflag(char * arg1, char * ar + int fd; + char str[64]; + char *reply; +- size_t len; + int ret = 0; + +- fd = ux_socket_connect(DEFAULT_SOCKET); ++ fd = mpath_connect(); + if (fd == -1) { + condlog (0, "ux socket connect error"); + return 1 ; +@@ -34,18 +33,23 @@ int update_prflag(char * arg1, char * ar + + snprintf(str,sizeof(str),"map %s %s", arg1, arg2); + condlog (2, "%s: pr flag message=%s", arg1, str); +- send_packet(fd, str, strlen(str) + 1); +- recv_packet(fd, &reply, &len); +- +- condlog (2, "%s: message=%s reply=%s", arg1, str, reply); +- if (!reply || strncmp(reply,"ok", 2) == 0) +- ret = -1; +- else if (strncmp(reply, "fail", 4) == 0) ++ send_packet(fd, str); ++ ret = recv_packet(fd, &reply); ++ if (ret < 0) { ++ condlog(2, "%s: message=%s recv error=%d", arg1, str, errno); + ret = -2; +- else{ +- ret = atoi(reply); ++ } else { ++ condlog (2, "%s: message=%s reply=%s", arg1, str, reply); ++ if (!reply || strncmp(reply,"ok", 2) == 0) ++ ret = -1; ++ else if (strncmp(reply, "fail", 4) == 0) ++ ret = -2; ++ else{ ++ ret = atoi(reply); ++ } + } + + free(reply); ++ mpath_disconnect(fd); + return ret; + } +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -7,8 +7,8 @@ include ../Makefile.inc + SONAME=0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) +-LIBDEPS = -lpthread -ldl -ldevmapper -ludev +-CFLAGS += -fPIC ++LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd ++CFLAGS += -fPIC -I$(mpathcmddir) + + OBJS = memory.o parser.o vector.o devmapper.o \ + hwtable.o blacklist.o util.o dmparser.o config.o \ +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -25,6 +25,7 @@ + #include "prio.h" + #include "devmapper.h" + #include "version.h" ++#include "mpath_cmd.h" + + static int + hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2) +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -752,16 +753,15 @@ check_daemon(void) + { + int fd; + char *reply; +- size_t len; + int ret = 0; + +- fd = ux_socket_connect(DEFAULT_SOCKET); ++ fd = mpath_connect(); + if (fd == -1) + return 0; + +- if (send_packet(fd, "show daemon", 12) != 0) ++ if (send_packet(fd, "show daemon") != 0) + goto out; +- if (recv_packet(fd, &reply, &len) != 0) ++ if (recv_packet(fd, &reply) != 0) + goto out; + + if (strstr(reply, "shutdown")) +@@ -772,7 +772,7 @@ check_daemon(void) + out_free: + FREE(reply); + out: +- close(fd); ++ mpath_disconnect(fd); + return ret; + } + +Index: multipath-tools-130222/libmultipath/uxsock.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uxsock.c ++++ multipath-tools-130222/libmultipath/uxsock.c +@@ -16,37 +16,10 @@ + #include + #include + #include ++#include + + #include "memory.h" + #include "uxsock.h" +- +-/* +- * connect to a unix domain socket +- */ +-int ux_socket_connect(const char *name) +-{ +- int fd, len; +- struct sockaddr_un addr; +- +- memset(&addr, 0, sizeof(addr)); +- addr.sun_family = AF_LOCAL; +- addr.sun_path[0] = '\0'; +- len = strlen(name) + 1 + sizeof(sa_family_t); +- strncpy(&addr.sun_path[1], name, len); +- +- fd = socket(AF_LOCAL, SOCK_STREAM, 0); +- if (fd == -1) { +- return -1; +- } +- +- if (connect(fd, (struct sockaddr *)&addr, len) == -1) { +- close(fd); +- return -1; +- } +- +- return fd; +-} +- + /* + * create a unix domain socket and start listening on it + * return a file descriptor open on the socket +@@ -102,32 +75,9 @@ size_t write_all(int fd, const void *buf + } + + /* +- * keep reading until its all read +- */ +-size_t read_all(int fd, void *buf, size_t len) +-{ +- size_t total = 0; +- +- while (len) { +- ssize_t n = read(fd, buf, len); +- if (n < 0) { +- if ((errno == EINTR) || (errno == EAGAIN)) +- continue; +- return total; +- } +- if (!n) +- return total; +- buf = n + (char *)buf; +- len -= n; +- total += n; +- } +- return total; +-} +- +-/* + * send a packet in length prefix format + */ +-int send_packet(int fd, const char *buf, size_t len) ++int send_packet(int fd, const char *buf) + { + int ret = 0; + sigset_t set, old; +@@ -137,10 +87,7 @@ int send_packet(int fd, const char *buf, + sigaddset(&set, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &set, &old); + +- if (write_all(fd, &len, sizeof(len)) != sizeof(len)) +- ret = -1; +- if (!ret && write_all(fd, buf, len) != len) +- ret = -1; ++ ret = mpath_send_cmd(fd, buf); + + /* And unblock it again */ + pthread_sigmask(SIG_SETMASK, &old, NULL); +@@ -151,25 +98,24 @@ int send_packet(int fd, const char *buf, + /* + * receive a packet in length prefix format + */ +-int recv_packet(int fd, char **buf, size_t *len) ++int recv_packet(int fd, char **buf) + { +- if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) { +- (*buf) = NULL; +- *len = 0; +- return -1; +- } +- if (len == 0) { +- (*buf) = NULL; +- return 0; +- } +- (*buf) = MALLOC(*len); ++ int err; ++ ssize_t len; ++ unsigned int timeout = DEFAULT_REPLY_TIMEOUT; ++ ++ *buf = NULL; ++ len = mpath_recv_reply_len(fd, timeout); ++ if (len <= 0) ++ return len; ++ (*buf) = MALLOC(len); + if (!*buf) +- return -1; +- if (read_all(fd, *buf, *len) != *len) { ++ return -ENOMEM; ++ err = mpath_recv_reply_data(fd, *buf, len, timeout); ++ if (err) { + FREE(*buf); + (*buf) = NULL; +- *len = 0; +- return -1; ++ return err; + } + return 0; + } +Index: multipath-tools-130222/libmultipath/uxsock.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uxsock.h ++++ multipath-tools-130222/libmultipath/uxsock.h +@@ -1,7 +1,5 @@ + /* some prototypes */ +-int ux_socket_connect(const char *name); + int ux_socket_listen(const char *name); +-int send_packet(int fd, const char *buf, size_t len); +-int recv_packet(int fd, char **buf, size_t *len); ++int send_packet(int fd, const char *buf); ++int recv_packet(int fd, char **buf); + size_t write_all(int fd, const void *buf, size_t len); +-size_t read_all(int fd, void *buf, size_t len); +Index: multipath-tools-130222/mpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/Makefile ++++ multipath-tools-130222/mpathpersist/Makefile +@@ -5,7 +5,7 @@ include ../Makefile.inc + OBJS = main.o + + CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) +-LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath -ludev ++LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev + + EXEC = mpathpersist + +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -6,8 +6,9 @@ include ../Makefile.inc + + OBJS = main.o + +-CFLAGS += -fPIC -I$(multipathdir) +-LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev ++CFLAGS += -I$(multipathdir) -I$(mpathcmddir) ++LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev \ ++ -L$(mpathcmddir) -lmpathcmd + + EXEC = multipath + +Index: multipath-tools-130222/multipathd/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipathd/Makefile ++++ multipath-tools-130222/multipathd/Makefile +@@ -5,10 +5,10 @@ include ../Makefile.inc + # + # basic flags setting + # +-CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathpersistdir) ++CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) + LDFLAGS += -lpthread -ldevmapper -lreadline -ludev -ldl \ + -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \ +- -Wl,-z,now -pie ++ -L$(mpathcmddir) -lmpathcmd -Wl,-z,now -pie + + # + # debuging stuff +Index: multipath-tools-130222/multipathd/uxclnt.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxclnt.c ++++ multipath-tools-130222/multipathd/uxclnt.c +@@ -17,6 +17,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -49,7 +50,6 @@ static void process(int fd) + rl_readline_name = "multipathd"; + rl_completion_entry_function = key_generator; + while ((line = readline("multipathd> "))) { +- size_t len; + size_t llen = strlen(line); + + if (!llen) { +@@ -61,8 +61,8 @@ static void process(int fd) + if (!strncmp(line, "quit", 4) && llen == 4) + break; + +- if (send_packet(fd, line, llen + 1) != 0) break; +- if (recv_packet(fd, &reply, &len) != 0) break; ++ if (send_packet(fd, line) != 0) break; ++ if (recv_packet(fd, &reply) != 0) break; + + print_reply(reply); + +@@ -77,13 +77,12 @@ static void process(int fd) + static void process_req(int fd, char * inbuf) + { + char *reply; +- size_t len; + +- if (send_packet(fd, inbuf, strlen(inbuf) + 1) != 0) { ++ if (send_packet(fd, inbuf) != 0) { + printf("cannot send packet\n"); + return; + } +- if (recv_packet(fd, &reply, &len) != 0) ++ if (recv_packet(fd, &reply) != 0) + printf("error receiving packet\n"); + else { + printf("%s", reply); +@@ -98,7 +97,7 @@ int uxclnt(char * inbuf) + { + int fd; + +- fd = ux_socket_connect(DEFAULT_SOCKET); ++ fd = mpath_connect(); + if (fd == -1) { + perror("ux_socket_connect"); + exit(1); +Index: multipath-tools-130222/multipathd/uxlsnr.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxlsnr.c ++++ multipath-tools-130222/multipathd/uxlsnr.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "cli.h" +@@ -108,7 +109,6 @@ void * uxsock_listen(int (*uxsock_trigge + void * trigger_data) + { + int ux_sock; +- size_t len; + int rlen; + char *inbuf; + char *reply; +@@ -171,16 +171,15 @@ void * uxsock_listen(int (*uxsock_trigge + struct client *next = c->next; + + if (polls[i].revents & POLLIN) { +- if (recv_packet(c->fd, &inbuf, &len) != 0) { ++ if (recv_packet(c->fd, &inbuf) != 0) { + dead_client(c); + } else { +- inbuf[len - 1] = 0; + condlog(4, "Got request [%s]", inbuf); + uxsock_trigger(inbuf, &reply, &rlen, + trigger_data); + if (reply) { +- if (send_packet(c->fd, reply, +- rlen) != 0) { ++ if (send_packet(c->fd, ++ reply) != 0) { + dead_client(c); + } + condlog(4, "Reply [%d bytes]", diff --git a/SOURCES/0208-UPBZ-1430097-multipathd-IPC-changes.patch b/SOURCES/0208-UPBZ-1430097-multipathd-IPC-changes.patch new file mode 100644 index 0000000..cddf641 --- /dev/null +++ b/SOURCES/0208-UPBZ-1430097-multipathd-IPC-changes.patch @@ -0,0 +1,280 @@ +[PATCH] Multipath: Remove duplicated memset() for multipathd show command. +[PATCH] multipath-tools: New way to limit the IPC command length. +[PATCH] multipath-tools: Perform socket client uid check on IPC commands. + +Signed-off-by: Gris Ge +--- + libmultipath/print.c | 10 ---------- + libmultipath/uxsock.c | 38 +++++++++++++++++++++++++++++--------- + libmultipath/uxsock.h | 9 +++++++++ + multipathd/main.c | 15 +++++++++++++-- + multipathd/uxlsnr.c | 31 ++++++++++++++++++++++++++----- + multipathd/uxlsnr.h | 8 +++++--- + 6 files changed, 82 insertions(+), 29 deletions(-) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -771,8 +771,6 @@ snprint_multipath_header (char * line, i + int fwd; + struct multipath_data * data; + +- memset(line, 0, len); +- + do { + if (!TAIL) + break; +@@ -806,8 +804,6 @@ snprint_multipath (char * line, int len, + struct multipath_data * data; + char buff[MAX_FIELD_LEN] = {}; + +- memset(line, 0, len); +- + do { + if (!TAIL) + break; +@@ -842,8 +838,6 @@ snprint_path_header (char * line, int le + int fwd; + struct path_data * data; + +- memset(line, 0, len); +- + do { + if (!TAIL) + break; +@@ -877,8 +871,6 @@ snprint_path (char * line, int len, char + struct path_data * data; + char buff[MAX_FIELD_LEN]; + +- memset(line, 0, len); +- + do { + if (!TAIL) + break; +@@ -914,8 +906,6 @@ snprint_pathgroup (char * line, int len, + struct pathgroup_data * data; + char buff[MAX_FIELD_LEN]; + +- memset(line, 0, len); +- + do { + if (!TAIL) + break; +Index: multipath-tools-130222/libmultipath/uxsock.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uxsock.c ++++ multipath-tools-130222/libmultipath/uxsock.c +@@ -20,6 +20,15 @@ + + #include "memory.h" + #include "uxsock.h" ++ ++/* ++ * Code is similar with mpath_recv_reply() with data size limitation ++ * and debug-able malloc. ++ * When limit == 0, it means no limit on data size, used for socket client ++ * to receiving data from multipathd. ++ */ ++static int _recv_packet(int fd, char **buf, ssize_t limit); ++ + /* + * create a unix domain socket and start listening on it + * return a file descriptor open on the socket +@@ -95,27 +104,38 @@ int send_packet(int fd, const char *buf) + return ret; + } + +-/* +- * receive a packet in length prefix format +- */ +-int recv_packet(int fd, char **buf) ++static int _recv_packet(int fd, char **buf, ssize_t limit) + { +- int err; +- ssize_t len; ++ int err = 0; ++ ssize_t len = 0; + unsigned int timeout = DEFAULT_REPLY_TIMEOUT; + + *buf = NULL; + len = mpath_recv_reply_len(fd, timeout); + if (len <= 0) + return len; ++ if ((limit > 0) && (len > limit)) ++ return -EINVAL; + (*buf) = MALLOC(len); + if (!*buf) + return -ENOMEM; + err = mpath_recv_reply_data(fd, *buf, len, timeout); +- if (err) { ++ if (err != 0) { + FREE(*buf); + (*buf) = NULL; +- return err; + } +- return 0; ++ return err; ++} ++ ++/* ++ * receive a packet in length prefix format ++ */ ++int recv_packet(int fd, char **buf) ++{ ++ return _recv_packet(fd, buf, 0 /* no limit */); ++} ++ ++int recv_packet_from_client(int fd, char **buf) ++{ ++ return _recv_packet(fd, buf, _MAX_CMD_LEN); + } +Index: multipath-tools-130222/libmultipath/uxsock.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uxsock.h ++++ multipath-tools-130222/libmultipath/uxsock.h +@@ -3,3 +3,12 @@ int ux_socket_listen(const char *name); + int send_packet(int fd, const char *buf); + int recv_packet(int fd, char **buf); + size_t write_all(int fd, const void *buf, size_t len); ++ ++#define _MAX_CMD_LEN 512 ++ ++/* ++ * Used for receiving socket command from untrusted socket client where data ++ * size is restricted to 512(_MAX_CMD_LEN) at most. ++ * Return -EINVAL if data length requested by client exceeded the _MAX_CMD_LEN. ++ */ ++int recv_packet_from_client(int fd, char **buf); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include "prioritizers/alua_rtpg.h" + +@@ -859,7 +860,8 @@ map_discovery (struct vectors * vecs) + } + + int +-uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data) ++uxsock_trigger (char * str, char ** reply, int * len, bool is_root, ++ void * trigger_data) + { + struct vectors * vecs; + int r; +@@ -872,6 +874,15 @@ uxsock_trigger (char * str, char ** repl + lock(vecs->lock); + pthread_testcancel(); + ++ if ((str != NULL) && (is_root == false) && ++ (strncmp(str, "list", strlen("list")) != 0) && ++ (strncmp(str, "show", strlen("show")) != 0)) { ++ *reply = STRDUP("permission deny: need to be root"); ++ *len = strlen(*reply) + 1; ++ r = 1; ++ goto out; ++ } ++ + r = parse_cmd(str, reply, len, vecs); + + if (r > 0) { +@@ -885,7 +896,7 @@ uxsock_trigger (char * str, char ** repl + r = 0; + } + /* else if (r < 0) leave *reply alone */ +- ++out: + lock_cleanup_pop(vecs->lock); + return r; + } +Index: multipath-tools-130222/multipathd/uxlsnr.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxlsnr.c ++++ multipath-tools-130222/multipathd/uxlsnr.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -48,6 +49,23 @@ struct pollfd *polls; + volatile sig_atomic_t reconfig_sig = 0; + volatile sig_atomic_t log_reset_sig = 0; + ++static bool _socket_client_is_root(int fd); ++ ++static bool _socket_client_is_root(int fd) ++{ ++ socklen_t len = 0; ++ struct ucred uc; ++ ++ len = sizeof(struct ucred); ++ if ((fd >= 0) && ++ (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) == 0) && ++ (uc.uid == 0)) ++ return true; ++ ++ /* Treat error as not root client */ ++ return false; ++} ++ + /* + * handle a new client joining + */ +@@ -105,8 +123,7 @@ void uxsock_cleanup(void *arg) + /* + * entry point + */ +-void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *), +- void * trigger_data) ++void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data) + { + int ux_sock; + int rlen; +@@ -171,12 +188,16 @@ void * uxsock_listen(int (*uxsock_trigge + struct client *next = c->next; + + if (polls[i].revents & POLLIN) { +- if (recv_packet(c->fd, &inbuf) != 0) { ++ if (recv_packet_from_client(c->fd, ++ &inbuf) != 0) { + dead_client(c); ++ } else if (!inbuf) { ++ condlog(4, "recv_packet_from_client " ++ "get null request"); ++ continue; + } else { + condlog(4, "Got request [%s]", inbuf); +- uxsock_trigger(inbuf, &reply, &rlen, +- trigger_data); ++ uxsock_trigger(inbuf, &reply, &rlen, _socket_client_is_root(c->fd), trigger_data); + if (reply) { + if (send_packet(c->fd, + reply) != 0) { +Index: multipath-tools-130222/multipathd/uxlsnr.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxlsnr.h ++++ multipath-tools-130222/multipathd/uxlsnr.h +@@ -1,9 +1,11 @@ + #ifndef _UXLSNR_H + #define _UXLSNR_H + +-void * uxsock_listen(int (*uxsock_trigger) +- (char *, char **, int *, void *), +- void * trigger_data); ++#include ++ ++typedef int (uxsock_trigger_fn)(char *, char **, int *, bool, void *); ++ ++void *uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data); + + extern volatile sig_atomic_t reconfig_sig; + extern volatile sig_atomic_t log_reset_sig; diff --git a/SOURCES/0209-UPBZ-1430097-multipath-C-API.patch b/SOURCES/0209-UPBZ-1430097-multipath-C-API.patch new file mode 100644 index 0000000..08a6f1d --- /dev/null +++ b/SOURCES/0209-UPBZ-1430097-multipath-C-API.patch @@ -0,0 +1,5632 @@ +From 4335abb36f33f12eadc943729901fac31f3dc012 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Fri, 24 Feb 2017 20:50:26 +0800 +Subject: [PATCH] multipath-tools: Introducing multipath C API + +Features: + + * Use mpath_cmd.h for IPC connection and use output of 'show maps json'. + * Library user guide will be 'man 3 libdmmp.h'. + * Every public function has its own manpage in section 3 which is + generated by linux 'kernel-doc' tool. + +Usage: + + make -j5 + sudo make install \ + bindir=/usr/sbin/ \ + syslibdir=/usr/lib64/ \ + libdir=/usr/lib64/multipath \ + rcdir=/etc/rc.d/init.d \ + unitdir=/usr/lib/systemd/system \ + includedir=/usr/include + make -C libdmmp check + make -C libdmmp speed_test + + man libdmmp.h + man dmmp_mpath_array_get + man + +Performance: + + * 10k scsi_debug sdX with 2 disks per mpath (i7-6820HQ 16GiB RAM): + $ make -C libdmmp speed_test + Got 5000 mpath + real 3.22 + user 0.15 + sys 0.01 + +Misc: + * Developer note is libdmmp/DEV_NOTES. + +Changes since V4: + + * Add new function dmmp_mpath_kdev_name_get() to query the '/dev/dm-01' for + mpath. + * Updated manpages. + * Rebased to current master ea4367159d32444e48a409a4f1c4f18324b737a9. + +Signed-off-by: Gris Ge +--- + .gitignore | 8 + Makefile | 1 + Makefile.inc | 6 + libdmmp/DEV_NOTES | 41 + libdmmp/Makefile | 84 + + libdmmp/docs/doc-preclean.pl | 28 + libdmmp/docs/kernel-doc | 3156 ++++++++++++++++++++++++++++++++++++++ + libdmmp/docs/libdmmp.h.3 | 113 + + libdmmp/docs/split-man.pl | 40 + libdmmp/libdmmp.c | 285 +++ + libdmmp/libdmmp.pc.in | 9 + libdmmp/libdmmp/libdmmp.h | 653 +++++++ + libdmmp/libdmmp_misc.c | 87 + + libdmmp/libdmmp_mp.c | 159 + + libdmmp/libdmmp_path.c | 115 + + libdmmp/libdmmp_pg.c | 208 ++ + libdmmp/libdmmp_private.h | 208 ++ + libdmmp/test/Makefile | 30 + libdmmp/test/libdmmp_speed_test.c | 49 + libdmmp/test/libdmmp_test.c | 147 + + 20 files changed, 5426 insertions(+), 1 deletion(-) + create mode 100644 libdmmp/DEV_NOTES + create mode 100644 libdmmp/Makefile + create mode 100644 libdmmp/docs/doc-preclean.pl + create mode 100644 libdmmp/docs/kernel-doc + create mode 100644 libdmmp/docs/libdmmp.h.3 + create mode 100644 libdmmp/docs/split-man.pl + create mode 100644 libdmmp/libdmmp.c + create mode 100644 libdmmp/libdmmp.pc.in + create mode 100644 libdmmp/libdmmp/libdmmp.h + create mode 100644 libdmmp/libdmmp_misc.c + create mode 100644 libdmmp/libdmmp_mp.c + create mode 100644 libdmmp/libdmmp_path.c + create mode 100644 libdmmp/libdmmp_pg.c + create mode 100644 libdmmp/libdmmp_private.h + create mode 100644 libdmmp/test/Makefile + create mode 100644 libdmmp/test/libdmmp_speed_test.c + create mode 100644 libdmmp/test/libdmmp_test.c + +Index: multipath-tools-130222/.gitignore +=================================================================== +--- multipath-tools-130222.orig/.gitignore ++++ multipath-tools-130222/.gitignore +@@ -10,3 +10,11 @@ multipath/multipath + multipathd/multipathd + mpathpersist/mpathpersist + .nfs* ++*.swp ++*.patch ++*.rej ++*.orig ++libdmmp/docs/man/*.3.gz ++libdmmp/*.so.* ++libdmmp/test/libdmmp_test ++libdmmp/test/libdmmp_speed_test +Index: multipath-tools-130222/Makefile +=================================================================== +--- multipath-tools-130222.orig/Makefile ++++ multipath-tools-130222/Makefile +@@ -25,6 +25,7 @@ BUILDDIRS = \ + libmultipath/prioritizers \ + libmultipath/checkers \ + libmpathpersist \ ++ libdmmp \ + multipath \ + multipathd \ + mpathpersist \ +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -36,8 +36,12 @@ unitdir = $(prefix)/lib/systemd/syst + mpathpersistdir = $(TOPDIR)/libmpathpersist + includedir = $(prefix)/usr/include + mpathcmddir = $(TOPDIR)/libmpathcmd ++libdmmpdir = $(TOPDIR)/libdmmp ++pkgconfdir = $(prefix)/usr/$(LIB)/pkgconfig + +-GZIP = /bin/gzip -9 -c ++GZIP = /bin/gzip -9 -c ++RM = rm -f ++LN = ln -sf + INSTALL_PROGRAM = install + + ifndef RPM_OPT_FLAGS +Index: multipath-tools-130222/libdmmp/DEV_NOTES +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/DEV_NOTES +@@ -0,0 +1,41 @@ ++== Planed features == ++ * Expose all properties used by /usr/bin/multipath ++ ++== Code style == ++ * Keep things as simple as possible. ++ * Linux Kernel code style. ++ * Don't use typedef. ++ * Don't use enum. ++ * We are not smarter than API user, so don't create wrapping function like: ++ ++ ``` ++ dmmp_mpath_search_by_id(struct dmmp_context *ctx, ++ struct dmmp_mpath **dmmp_mp, ++ uint32_t dmmp_mp_count, const char *id) ++ ++ dmmp_path_group_id_search(struct dmmp_mpath *dmmp_mp, ++ const char *blk_name) ++ ``` ++ * The performance is the same for query single mpath and query all mpaths, ++ so no `dmmp_mpath_of_wwid(struct dmmp_context *ctx, const char *wwid)` yet. ++ ++== Naming scheme == ++ * Public constants should be named as `DMMP_XXX_YYY`. ++ * Public functions should be named as `dmmp__`. ++ * Private constants should be named as `_DMMP_XXX_YYY`. ++ * Private functions should be named as `_dmmp__`. ++ ++== Code Layout == ++ * libdmmp_private.h ++ Internal functions or macros. ++ * libdmmp.c ++ Handling multipathd IPC and generate dmmp_context and ++ dmmp_mpath_array_get(). ++ * libdmmp_mp.c ++ For `struct dmmp_mpath` ++ * libdmmp_pg.c ++ For `struct dmmp_path_group` ++ * libdmmp_path.c ++ For `struct dmmp_path` ++ * libdmmp_misc.c ++ Misc functions. +Index: multipath-tools-130222/libdmmp/Makefile +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/Makefile +@@ -0,0 +1,84 @@ ++# Makefile ++# ++# Copyright (C) 2015 - 2016 Red Hat, Inc. ++# Gris Ge ++# ++include ../Makefile.inc ++ ++LIBDMMP_VERSION=0.1.0 ++SONAME=$(LIBDMMP_VERSION) ++DEVLIB = libdmmp.so ++LIBS = $(DEVLIB).$(SONAME) ++LIBDEPS = -pthread ++PKGFILE = libdmmp.pc ++EXTRA_MAN_FILES = libdmmp.h.3 ++HEADERS = libdmmp/libdmmp.h ++OBJS = libdmmp.o libdmmp_mp.o libdmmp_pg.o libdmmp_path.o libdmmp_misc.o ++ ++CFLAGS += -fPIC -fvisibility=hidden -I$(libdmmpdir) -I$(mpathcmddir) \ ++ $(shell pkg-config --cflags json-c) ++LDFLAGS += $(shell pkg-config --libs json-c) -L$(mpathcmddir) -lmpathcmd ++ ++all: $(LIBS) doc ++ ++$(LIBS): $(OBJS) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) \ ++ -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS) ++ $(LN) $@ $(DEVLIB) ++ ++install: ++ $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) ++ $(INSTALL_PROGRAM) -m 644 -D \ ++ $(HEADERS) $(DESTDIR)$(includedir)/$(HEADERS) ++ $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ $(INSTALL_PROGRAM) -m 644 -D \ ++ $(PKGFILE).in $(DESTDIR)$(pkgconfdir)/$(PKGFILE) ++ perl -i -pe 's|__VERSION__|$(LIBDMMP_VERSION)|g' \ ++ $(DESTDIR)$(pkgconfdir)/$(PKGFILE) ++ perl -i -pe 's|__LIBDIR__|$(syslibdir)|g' \ ++ $(DESTDIR)$(pkgconfdir)/$(PKGFILE) ++ perl -i -pe 's|__INCLUDEDIR__|$(includedir)|g' \ ++ $(DESTDIR)$(pkgconfdir)/$(PKGFILE) ++ @for file in docs/man/*.3.gz; do \ ++ $(INSTALL_PROGRAM) -m 644 -D \ ++ $$file \ ++ $(DESTDIR)$(man3dir)/ || exit $?; \ ++ done ++ ++uninstall: ++ $(RM) $(DESTDIR)$(syslibdir)/$(LIBS) ++ $(RM) $(DESTDIR)$(includedir)/$(HEADERS) ++ $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) ++ @for file in $(DESTDIR)$(man3dir)/dmmp_*; do \ ++ $(RM) $$file; \ ++ done ++ $(RM) $(DESTDIR)$(man3dir)/libdmmp.h* ++ ++clean: ++ $(RM) core *.a *.o *.gz *.so *.so.* ++ $(RM) docs/man/*.3.gz ++ $(MAKE) -C test clean ++ ++check: all ++ $(MAKE) -C test check ++ ++speed_test: all ++ $(MAKE) -C test speed_test ++ ++doc: docs/man/$(EXTRA_MAN_FILES).gz ++ ++TEMPFILE := $(shell mktemp) ++ ++docs/man/$(EXTRA_MAN_FILES).gz: $(HEADERS) ++ @for file in $(EXTRA_MAN_FILES); do \ ++ $(INSTALL_PROGRAM) -v -m 644 -D docs/$$file docs/man/$$file; \ ++ done ++ cat $(HEADERS) | \ ++ perl docs/doc-preclean.pl > $(TEMPFILE) ++ perl docs/kernel-doc -man $(TEMPFILE) | \ ++ perl docs/split-man.pl docs/man ++ -rm -f $(TEMPFILE) ++ @for file in docs/man/*.3; do \ ++ gzip -f $$file; \ ++ done ++ find docs/man -type f -name \*[0-9].gz +Index: multipath-tools-130222/libdmmp/docs/doc-preclean.pl +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/docs/doc-preclean.pl +@@ -0,0 +1,28 @@ ++#!/usr/bin/perl ++# Copyright (C) 2016 Red Hat, Inc. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Author: Gris Ge ++ ++use strict; ++ ++my @REMOVE_KEY_LIST=("DMMP_DLL_EXPORT"); ++ ++while (<>) { ++ for my $key (@REMOVE_KEY_LIST) { ++ (s/$key//g); ++ } ++ print; ++} +Index: multipath-tools-130222/libdmmp/docs/kernel-doc +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/docs/kernel-doc +@@ -0,0 +1,3156 @@ ++#!/usr/bin/perl -w ++ ++use strict; ++ ++## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ++## Copyright (C) 2000, 1 Tim Waugh ## ++## Copyright (C) 2001 Simon Huggins ## ++## Copyright (C) 2005-2012 Randy Dunlap ## ++## Copyright (C) 2012 Dan Luedtke ## ++## ## ++## #define enhancements by Armin Kuster ## ++## Copyright (c) 2000 MontaVista Software, Inc. ## ++## ## ++## This software falls under the GNU General Public License. ## ++## Please read the COPYING file for more information ## ++ ++# 18/01/2001 - Cleanups ++# Functions prototyped as foo(void) same as foo() ++# Stop eval'ing where we don't need to. ++# -- huggie@earth.li ++ ++# 27/06/2001 - Allowed whitespace after initial "/**" and ++# allowed comments before function declarations. ++# -- Christian Kreibich ++ ++# Still to do: ++# - add perldoc documentation ++# - Look more closely at some of the scarier bits :) ++ ++# 26/05/2001 - Support for separate source and object trees. ++# Return error code. ++# Keith Owens ++ ++# 23/09/2001 - Added support for typedefs, structs, enums and unions ++# Support for Context section; can be terminated using empty line ++# Small fixes (like spaces vs. \s in regex) ++# -- Tim Jansen ++ ++# 25/07/2012 - Added support for HTML5 ++# -- Dan Luedtke ++ ++sub usage { ++ my $message = <<"EOF"; ++Usage: $0 [OPTION ...] FILE ... ++ ++Read C language source or header FILEs, extract embedded documentation comments, ++and print formatted documentation to standard output. ++ ++The documentation comments are identified by "/**" opening comment mark. See ++Documentation/kernel-doc-nano-HOWTO.txt for the documentation comment syntax. ++ ++Output format selection (mutually exclusive): ++ -docbook Output DocBook format. ++ -html Output HTML format. ++ -html5 Output HTML5 format. ++ -list Output symbol list format. This is for use by docproc. ++ -man Output troff manual page format. This is the default. ++ -rst Output reStructuredText format. ++ -text Output plain text format. ++ ++Output selection (mutually exclusive): ++ -export Only output documentation for symbols that have been ++ exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() ++ in any input FILE or -export-file FILE. ++ -internal Only output documentation for symbols that have NOT been ++ exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() ++ in any input FILE or -export-file FILE. ++ -function NAME Only output documentation for the given function(s) ++ or DOC: section title(s). All other functions and DOC: ++ sections are ignored. May be specified multiple times. ++ -nofunction NAME Do NOT output documentation for the given function(s); ++ only output documentation for the other functions and ++ DOC: sections. May be specified multiple times. ++ ++Output selection modifiers: ++ -no-doc-sections Do not output DOC: sections. ++ -enable-lineno Enable output of #define LINENO lines. Only works with ++ reStructuredText format. ++ -export-file FILE Specify an additional FILE in which to look for ++ EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used with ++ -export or -internal. May be specified multiple times. ++ ++Other parameters: ++ -v Verbose output, more warnings and other information. ++ -h Print this help. ++ ++EOF ++ print $message; ++ exit 1; ++} ++ ++# ++# format of comments. ++# In the following table, (...)? signifies optional structure. ++# (...)* signifies 0 or more structure elements ++# /** ++# * function_name(:)? (- short description)? ++# (* @parameterx: (description of parameter x)?)* ++# (* a blank line)? ++# * (Description:)? (Description of function)? ++# * (section header: (section description)? )* ++# (*)?*/ ++# ++# So .. the trivial example would be: ++# ++# /** ++# * my_function ++# */ ++# ++# If the Description: header tag is omitted, then there must be a blank line ++# after the last parameter specification. ++# e.g. ++# /** ++# * my_function - does my stuff ++# * @my_arg: its mine damnit ++# * ++# * Does my stuff explained. ++# */ ++# ++# or, could also use: ++# /** ++# * my_function - does my stuff ++# * @my_arg: its mine damnit ++# * Description: Does my stuff explained. ++# */ ++# etc. ++# ++# Besides functions you can also write documentation for structs, unions, ++# enums and typedefs. Instead of the function name you must write the name ++# of the declaration; the struct/union/enum/typedef must always precede ++# the name. Nesting of declarations is not supported. ++# Use the argument mechanism to document members or constants. ++# e.g. ++# /** ++# * struct my_struct - short description ++# * @a: first member ++# * @b: second member ++# * ++# * Longer description ++# */ ++# struct my_struct { ++# int a; ++# int b; ++# /* private: */ ++# int c; ++# }; ++# ++# All descriptions can be multiline, except the short function description. ++# ++# For really longs structs, you can also describe arguments inside the ++# body of the struct. ++# eg. ++# /** ++# * struct my_struct - short description ++# * @a: first member ++# * @b: second member ++# * ++# * Longer description ++# */ ++# struct my_struct { ++# int a; ++# int b; ++# /** ++# * @c: This is longer description of C ++# * ++# * You can use paragraphs to describe arguments ++# * using this method. ++# */ ++# int c; ++# }; ++# ++# This should be use only for struct/enum members. ++# ++# You can also add additional sections. When documenting kernel functions you ++# should document the "Context:" of the function, e.g. whether the functions ++# can be called form interrupts. Unlike other sections you can end it with an ++# empty line. ++# A non-void function should have a "Return:" section describing the return ++# value(s). ++# Example-sections should contain the string EXAMPLE so that they are marked ++# appropriately in DocBook. ++# ++# Example: ++# /** ++# * user_function - function that can only be called in user context ++# * @a: some argument ++# * Context: !in_interrupt() ++# * ++# * Some description ++# * Example: ++# * user_function(22); ++# */ ++# ... ++# ++# ++# All descriptive text is further processed, scanning for the following special ++# patterns, which are highlighted appropriately. ++# ++# 'funcname()' - function ++# '$ENVVAR' - environmental variable ++# '&struct_name' - name of a structure (up to two words including 'struct') ++# '@parameter' - name of a parameter ++# '%CONST' - name of a constant. ++ ++## init lots of data ++ ++ ++my $errors = 0; ++my $warnings = 0; ++my $anon_struct_union = 0; ++ ++# match expressions used to find embedded type information ++my $type_constant = '\%([-_\w]+)'; ++my $type_func = '(\w+)\(\)'; ++my $type_param = '\@(\w+(\.\.\.)?)'; ++my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params ++my $type_struct = '\&((struct\s*)*[_\w]+)'; ++my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; ++my $type_env = '(\$\w+)'; ++my $type_enum_full = '\&(enum)\s*([_\w]+)'; ++my $type_struct_full = '\&(struct)\s*([_\w]+)'; ++my $type_typedef_full = '\&(typedef)\s*([_\w]+)'; ++my $type_union_full = '\&(union)\s*([_\w]+)'; ++my $type_member = '\&([_\w]+)((\.|->)[_\w]+)'; ++my $type_member_func = $type_member . '\(\)'; ++ ++# Output conversion substitutions. ++# One for each output format ++ ++# these work fairly well ++my @highlights_html = ( ++ [$type_constant, "\$1"], ++ [$type_func, "\$1"], ++ [$type_struct_xml, "\$1"], ++ [$type_env, "\$1"], ++ [$type_param, "\$1"] ++ ); ++my $local_lt = "\\\\\\\\lt:"; ++my $local_gt = "\\\\\\\\gt:"; ++my $blankline_html = $local_lt . "p" . $local_gt; # was "

" ++ ++# html version 5 ++my @highlights_html5 = ( ++ [$type_constant, "\$1"], ++ [$type_func, "\$1"], ++ [$type_struct_xml, "\$1"], ++ [$type_env, "\$1"], ++ [$type_param, "\$1]"] ++ ); ++my $blankline_html5 = $local_lt . "br /" . $local_gt; ++ ++# XML, docbook format ++my @highlights_xml = ( ++ ["([^=])\\\"([^\\\"<]+)\\\"", "\$1\$2"], ++ [$type_constant, "\$1"], ++ [$type_struct_xml, "\$1"], ++ [$type_param, "\$1"], ++ [$type_func, "\$1"], ++ [$type_env, "\$1"] ++ ); ++my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; ++ ++# gnome, docbook format ++my @highlights_gnome = ( ++ [$type_constant, "\$1"], ++ [$type_func, "\$1"], ++ [$type_struct, "\$1"], ++ [$type_env, "\$1"], ++ [$type_param, "\$1" ] ++ ); ++my $blankline_gnome = "\n"; ++ ++# these are pretty rough ++my @highlights_man = ( ++ [$type_constant, "\$1"], ++ [$type_func, "\\\\fB\$1\\\\fP"], ++ [$type_struct, "\\\\fI\$1\\\\fP"], ++ [$type_param, "\\\\fI\$1\\\\fP"] ++ ); ++my $blankline_man = ""; ++ ++# text-mode ++my @highlights_text = ( ++ [$type_constant, "\$1"], ++ [$type_func, "\$1"], ++ [$type_struct, "\$1"], ++ [$type_param, "\$1"] ++ ); ++my $blankline_text = ""; ++ ++# rst-mode ++my @highlights_rst = ( ++ [$type_constant, "``\$1``"], ++ # Note: need to escape () to avoid func matching later ++ [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"], ++ [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"], ++ [$type_fp_param, "**\$1\\\\(\\\\)**"], ++ [$type_func, "\\:c\\:func\\:`\$1()`"], ++ [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], ++ [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], ++ [$type_typedef_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], ++ [$type_union_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], ++ # in rst this can refer to any type ++ [$type_struct, "\\:c\\:type\\:`\$1`"], ++ [$type_param, "**\$1**"] ++ ); ++my $blankline_rst = "\n"; ++ ++# list mode ++my @highlights_list = ( ++ [$type_constant, "\$1"], ++ [$type_func, "\$1"], ++ [$type_struct, "\$1"], ++ [$type_param, "\$1"] ++ ); ++my $blankline_list = ""; ++ ++# read arguments ++if ($#ARGV == -1) { ++ usage(); ++} ++ ++my $kernelversion; ++my $dohighlight = ""; ++ ++my $verbose = 0; ++my $output_mode = "man"; ++my $output_preformatted = 0; ++my $no_doc_sections = 0; ++my $enable_lineno = 0; ++my @highlights = @highlights_man; ++my $blankline = $blankline_man; ++my $modulename = "Kernel API"; ++ ++use constant { ++ OUTPUT_ALL => 0, # output all symbols and doc sections ++ OUTPUT_INCLUDE => 1, # output only specified symbols ++ OUTPUT_EXCLUDE => 2, # output everything except specified symbols ++ OUTPUT_EXPORTED => 3, # output exported symbols ++ OUTPUT_INTERNAL => 4, # output non-exported symbols ++}; ++my $output_selection = OUTPUT_ALL; ++my $show_not_found = 0; ++ ++my @export_file_list; ++ ++my @build_time; ++if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && ++ (my $seconds = `date -d"${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') { ++ @build_time = gmtime($seconds); ++} else { ++ @build_time = localtime; ++} ++ ++my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', ++ 'July', 'August', 'September', 'October', ++ 'November', 'December')[$build_time[4]] . ++ " " . ($build_time[5]+1900); ++ ++# Essentially these are globals. ++# They probably want to be tidied up, made more localised or something. ++# CAVEAT EMPTOR! Some of the others I localised may not want to be, which ++# could cause "use of undefined value" or other bugs. ++my ($function, %function_table, %parametertypes, $declaration_purpose); ++my $declaration_start_line; ++my ($type, $declaration_name, $return_type); ++my ($newsection, $newcontents, $prototype, $brcount, %source_map); ++ ++if (defined($ENV{'KBUILD_VERBOSE'})) { ++ $verbose = "$ENV{'KBUILD_VERBOSE'}"; ++} ++ ++# Generated docbook code is inserted in a template at a point where ++# docbook v3.1 requires a non-zero sequence of RefEntry's; see: ++# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html ++# We keep track of number of generated entries and generate a dummy ++# if needs be to ensure the expanded template can be postprocessed ++# into html. ++my $section_counter = 0; ++ ++my $lineprefix=""; ++ ++# Parser states ++use constant { ++ STATE_NORMAL => 0, # normal code ++ STATE_NAME => 1, # looking for function name ++ STATE_FIELD => 2, # scanning field start ++ STATE_PROTO => 3, # scanning prototype ++ STATE_DOCBLOCK => 4, # documentation block ++ STATE_INLINE => 5, # gathering documentation outside main block ++}; ++my $state; ++my $in_doc_sect; ++ ++# Inline documentation state ++use constant { ++ STATE_INLINE_NA => 0, # not applicable ($state != STATE_INLINE) ++ STATE_INLINE_NAME => 1, # looking for member name (@foo:) ++ STATE_INLINE_TEXT => 2, # looking for member documentation ++ STATE_INLINE_END => 3, # done ++ STATE_INLINE_ERROR => 4, # error - Comment without header was found. ++ # Spit a warning as it's not ++ # proper kernel-doc and ignore the rest. ++}; ++my $inline_doc_state; ++ ++#declaration types: can be ++# 'function', 'struct', 'union', 'enum', 'typedef' ++my $decl_type; ++ ++my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. ++my $doc_end = '\*/'; ++my $doc_com = '\s*\*\s*'; ++my $doc_com_body = '\s*\* ?'; ++my $doc_decl = $doc_com . '(\w+)'; ++# @params and a strictly limited set of supported section names ++my $doc_sect = $doc_com . ++ '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:(.*)'; ++my $doc_content = $doc_com_body . '(.*)'; ++my $doc_block = $doc_com . 'DOC:\s*(.*)?'; ++my $doc_inline_start = '^\s*/\*\*\s*$'; ++my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)'; ++my $doc_inline_end = '^\s*\*/\s*$'; ++my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$'; ++my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;'; ++ ++my %parameterdescs; ++my %parameterdesc_start_lines; ++my @parameterlist; ++my %sections; ++my @sectionlist; ++my %section_start_lines; ++my $sectcheck; ++my $struct_actual; ++ ++my $contents = ""; ++my $new_start_line = 0; ++ ++# the canonical section names. see also $doc_sect above. ++my $section_default = "Description"; # default section ++my $section_intro = "Introduction"; ++my $section = $section_default; ++my $section_context = "Context"; ++my $section_return = "Return"; ++ ++my $undescribed = "-- undescribed --"; ++ ++reset_state(); ++ ++while ($ARGV[0] =~ m/^-(.*)/) { ++ my $cmd = shift @ARGV; ++ if ($cmd eq "-html") { ++ $output_mode = "html"; ++ @highlights = @highlights_html; ++ $blankline = $blankline_html; ++ } elsif ($cmd eq "-html5") { ++ $output_mode = "html5"; ++ @highlights = @highlights_html5; ++ $blankline = $blankline_html5; ++ } elsif ($cmd eq "-man") { ++ $output_mode = "man"; ++ @highlights = @highlights_man; ++ $blankline = $blankline_man; ++ } elsif ($cmd eq "-text") { ++ $output_mode = "text"; ++ @highlights = @highlights_text; ++ $blankline = $blankline_text; ++ } elsif ($cmd eq "-rst") { ++ $output_mode = "rst"; ++ @highlights = @highlights_rst; ++ $blankline = $blankline_rst; ++ } elsif ($cmd eq "-docbook") { ++ $output_mode = "xml"; ++ @highlights = @highlights_xml; ++ $blankline = $blankline_xml; ++ } elsif ($cmd eq "-list") { ++ $output_mode = "list"; ++ @highlights = @highlights_list; ++ $blankline = $blankline_list; ++ } elsif ($cmd eq "-gnome") { ++ $output_mode = "gnome"; ++ @highlights = @highlights_gnome; ++ $blankline = $blankline_gnome; ++ } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document ++ $modulename = shift @ARGV; ++ } elsif ($cmd eq "-function") { # to only output specific functions ++ $output_selection = OUTPUT_INCLUDE; ++ $function = shift @ARGV; ++ $function_table{$function} = 1; ++ } elsif ($cmd eq "-nofunction") { # output all except specific functions ++ $output_selection = OUTPUT_EXCLUDE; ++ $function = shift @ARGV; ++ $function_table{$function} = 1; ++ } elsif ($cmd eq "-export") { # only exported symbols ++ $output_selection = OUTPUT_EXPORTED; ++ %function_table = (); ++ } elsif ($cmd eq "-internal") { # only non-exported symbols ++ $output_selection = OUTPUT_INTERNAL; ++ %function_table = (); ++ } elsif ($cmd eq "-export-file") { ++ my $file = shift @ARGV; ++ push(@export_file_list, $file); ++ } elsif ($cmd eq "-v") { ++ $verbose = 1; ++ } elsif (($cmd eq "-h") || ($cmd eq "--help")) { ++ usage(); ++ } elsif ($cmd eq '-no-doc-sections') { ++ $no_doc_sections = 1; ++ } elsif ($cmd eq '-enable-lineno') { ++ $enable_lineno = 1; ++ } elsif ($cmd eq '-show-not-found') { ++ $show_not_found = 1; ++ } ++} ++ ++# continue execution near EOF; ++ ++# get kernel version from env ++sub get_kernel_version() { ++ my $version = 'unknown kernel version'; ++ ++ if (defined($ENV{'KERNELVERSION'})) { ++ $version = $ENV{'KERNELVERSION'}; ++ } ++ return $version; ++} ++ ++# ++sub print_lineno { ++ my $lineno = shift; ++ if ($enable_lineno && defined($lineno)) { ++ print "#define LINENO " . $lineno . "\n"; ++ } ++} ++## ++# dumps section contents to arrays/hashes intended for that purpose. ++# ++sub dump_section { ++ my $file = shift; ++ my $name = shift; ++ my $contents = join "\n", @_; ++ ++ if ($name =~ m/$type_param/) { ++ $name = $1; ++ $parameterdescs{$name} = $contents; ++ $sectcheck = $sectcheck . $name . " "; ++ $parameterdesc_start_lines{$name} = $new_start_line; ++ $new_start_line = 0; ++ } elsif ($name eq "@\.\.\.") { ++ $name = "..."; ++ $parameterdescs{$name} = $contents; ++ $sectcheck = $sectcheck . $name . " "; ++ $parameterdesc_start_lines{$name} = $new_start_line; ++ $new_start_line = 0; ++ } else { ++ if (defined($sections{$name}) && ($sections{$name} ne "")) { ++ # Only warn on user specified duplicate section names. ++ if ($name ne $section_default) { ++ print STDERR "${file}:$.: warning: duplicate section name '$name'\n"; ++ ++$warnings; ++ } ++ $sections{$name} .= $contents; ++ } else { ++ $sections{$name} = $contents; ++ push @sectionlist, $name; ++ $section_start_lines{$name} = $new_start_line; ++ $new_start_line = 0; ++ } ++ } ++} ++ ++## ++# dump DOC: section after checking that it should go out ++# ++sub dump_doc_section { ++ my $file = shift; ++ my $name = shift; ++ my $contents = join "\n", @_; ++ ++ if ($no_doc_sections) { ++ return; ++ } ++ ++ if (($output_selection == OUTPUT_ALL) || ++ ($output_selection == OUTPUT_INCLUDE && ++ defined($function_table{$name})) || ++ ($output_selection == OUTPUT_EXCLUDE && ++ !defined($function_table{$name}))) ++ { ++ dump_section($file, $name, $contents); ++ output_blockhead({'sectionlist' => \@sectionlist, ++ 'sections' => \%sections, ++ 'module' => $modulename, ++ 'content-only' => ($output_selection != OUTPUT_ALL), }); ++ } ++} ++ ++## ++# output function ++# ++# parameterdescs, a hash. ++# function => "function name" ++# parameterlist => @list of parameters ++# parameterdescs => %parameter descriptions ++# sectionlist => @list of sections ++# sections => %section descriptions ++# ++ ++sub output_highlight { ++ my $contents = join "\n",@_; ++ my $line; ++ ++# DEBUG ++# if (!defined $contents) { ++# use Carp; ++# confess "output_highlight got called with no args?\n"; ++# } ++ ++ if ($output_mode eq "html" || $output_mode eq "html5" || ++ $output_mode eq "xml") { ++ $contents = local_unescape($contents); ++ # convert data read & converted thru xml_escape() into &xyz; format: ++ $contents =~ s/\\\\\\/\&/g; ++ } ++# print STDERR "contents b4:$contents\n"; ++ eval $dohighlight; ++ die $@ if $@; ++# print STDERR "contents af:$contents\n"; ++ ++# strip whitespaces when generating html5 ++ if ($output_mode eq "html5") { ++ $contents =~ s/^\s+//; ++ $contents =~ s/\s+$//; ++ } ++ foreach $line (split "\n", $contents) { ++ if (! $output_preformatted) { ++ $line =~ s/^\s*//; ++ } ++ if ($line eq ""){ ++ if (! $output_preformatted) { ++ print $lineprefix, local_unescape($blankline); ++ } ++ } else { ++ $line =~ s/\\\\\\/\&/g; ++ if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { ++ print "\\&$line"; ++ } else { ++ print $lineprefix, $line; ++ } ++ } ++ print "\n"; ++ } ++} ++ ++# output sections in html ++sub output_section_html(%) { ++ my %args = %{$_[0]}; ++ my $section; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "

$section

\n"; ++ print "
\n"; ++ output_highlight($args{'sections'}{$section}); ++ print "
\n"; ++ } ++} ++ ++# output enum in html ++sub output_enum_html(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $count; ++ print "

enum " . $args{'enum'} . "

\n"; ++ ++ print "enum " . $args{'enum'} . " {
\n"; ++ $count = 0; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print " " . $parameter . ""; ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ",\n"; ++ } ++ print "
"; ++ } ++ print "};
\n"; ++ ++ print "

Constants

\n"; ++ print "
\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "
" . $parameter . "\n"; ++ print "
"; ++ output_highlight($args{'parameterdescs'}{$parameter}); ++ } ++ print "
\n"; ++ output_section_html(@_); ++ print "
\n"; ++} ++ ++# output typedef in html ++sub output_typedef_html(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $count; ++ print "

typedef " . $args{'typedef'} . "

\n"; ++ ++ print "typedef " . $args{'typedef'} . "\n"; ++ output_section_html(@_); ++ print "
\n"; ++} ++ ++# output struct in html ++sub output_struct_html(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ ++ print "

" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "

\n"; ++ print "" . $args{'type'} . " " . $args{'struct'} . " {
\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ if ($parameter =~ /^#/) { ++ print "$parameter
\n"; ++ next; ++ } ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print "    $1$parameter) ($2);
\n"; ++ } elsif ($type =~ m/^(.*?)\s*(:.*)/) { ++ # bitfield ++ print "    $1 $parameter$2;
\n"; ++ } else { ++ print "    $type $parameter;
\n"; ++ } ++ } ++ print "};
\n"; ++ ++ print "

Members

\n"; ++ print "
\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ ($parameter =~ /^#/) && next; ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print "
" . $parameter . "\n"; ++ print "
"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ } ++ print "
\n"; ++ output_section_html(@_); ++ print "
\n"; ++} ++ ++# output function in html ++sub output_function_html(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ ++ print "

" . $args{'function'} . " - " . $args{'purpose'} . "

\n"; ++ print "" . $args{'functiontype'} . "\n"; ++ print "" . $args{'function'} . "\n"; ++ print "("; ++ $count = 0; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print "$1$parameter) ($2)"; ++ } else { ++ print "" . $type . " " . $parameter . ""; ++ } ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ",\n"; ++ } ++ } ++ print ")\n"; ++ ++ print "

Arguments

\n"; ++ print "
\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print "
" . $parameter . "\n"; ++ print "
"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ } ++ print "
\n"; ++ output_section_html(@_); ++ print "
\n"; ++} ++ ++# output DOC: block header in html ++sub output_blockhead_html(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "

$section

\n"; ++ print "
    \n"; ++ output_highlight($args{'sections'}{$section}); ++ print "
\n"; ++ } ++ print "
\n"; ++} ++ ++# output sections in html5 ++sub output_section_html5(%) { ++ my %args = %{$_[0]}; ++ my $section; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "
\n"; ++ print "

$section

\n"; ++ print "

\n"; ++ output_highlight($args{'sections'}{$section}); ++ print "

\n"; ++ print "
\n"; ++ } ++} ++ ++# output enum in html5 ++sub output_enum_html5(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $count; ++ my $html5id; ++ ++ $html5id = $args{'enum'}; ++ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; ++ print "
"; ++ print "

enum " . $args{'enum'} . "

\n"; ++ print "
    \n"; ++ print "
  1. "; ++ print "enum "; ++ print "" . $args{'enum'} . " {"; ++ print "
  2. \n"; ++ $count = 0; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "
  3. "; ++ print "" . $parameter . ""; ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ","; ++ } ++ print "
  4. \n"; ++ } ++ print "
  5. };
  6. \n"; ++ print "
\n"; ++ ++ print "
\n"; ++ print "

Constants

\n"; ++ print "
\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "
" . $parameter . "
\n"; ++ print "
"; ++ output_highlight($args{'parameterdescs'}{$parameter}); ++ print "
\n"; ++ } ++ print "
\n"; ++ print "
\n"; ++ output_section_html5(@_); ++ print "
\n"; ++} ++ ++# output typedef in html5 ++sub output_typedef_html5(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $count; ++ my $html5id; ++ ++ $html5id = $args{'typedef'}; ++ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; ++ print "
\n"; ++ print "

typedef " . $args{'typedef'} . "

\n"; ++ ++ print "
    \n"; ++ print "
  1. "; ++ print "typedef "; ++ print "" . $args{'typedef'} . ""; ++ print "
  2. \n"; ++ print "
\n"; ++ output_section_html5(@_); ++ print "
\n"; ++} ++ ++# output struct in html5 ++sub output_struct_html5(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $html5id; ++ ++ $html5id = $args{'struct'}; ++ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; ++ print "
\n"; ++ print "
\n"; ++ print "

" . $args{'type'} . " " . $args{'struct'} . "

"; ++ print "

". $args{'purpose'} . "

\n"; ++ print "
\n"; ++ print "
    \n"; ++ print "
  1. "; ++ print "" . $args{'type'} . " "; ++ print "" . $args{'struct'} . " {"; ++ print "
  2. \n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "
  3. "; ++ if ($parameter =~ /^#/) { ++ print "" . $parameter ."\n"; ++ print "
  4. \n"; ++ next; ++ } ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print "$1 "; ++ print "$parameter"; ++ print ") "; ++ print "($2);"; ++ } elsif ($type =~ m/^(.*?)\s*(:.*)/) { ++ # bitfield ++ print "$1 "; ++ print "$parameter"; ++ print "$2;"; ++ } else { ++ print "$type "; ++ print "$parameter;"; ++ } ++ print "\n"; ++ } ++ print "
  5. };
  6. \n"; ++ print "
\n"; ++ ++ print "
\n"; ++ print "

Members

\n"; ++ print "
\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ ($parameter =~ /^#/) && next; ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print "
" . $parameter . "
\n"; ++ print "
"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ print "
\n"; ++ } ++ print "
\n"; ++ print "
\n"; ++ output_section_html5(@_); ++ print "
\n"; ++} ++ ++# output function in html5 ++sub output_function_html5(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ my $html5id; ++ ++ $html5id = $args{'function'}; ++ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; ++ print "
\n"; ++ print "
\n"; ++ print "

" . $args{'function'} . "

"; ++ print "

" . $args{'purpose'} . "

\n"; ++ print "
\n"; ++ print "
    \n"; ++ print "
  1. "; ++ print "" . $args{'functiontype'} . " "; ++ print "" . $args{'function'} . " ("; ++ print "
  2. "; ++ $count = 0; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "
  3. "; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print "$1 "; ++ print "$parameter"; ++ print ") "; ++ print "($2)"; ++ } else { ++ print "$type "; ++ print "$parameter"; ++ } ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ","; ++ } ++ print "
  4. \n"; ++ } ++ print "
  5. )
  6. \n"; ++ print "
\n"; ++ ++ print "
\n"; ++ print "

Arguments

\n"; ++ print "

\n"; ++ print "

\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print "
" . $parameter . "
\n"; ++ print "
"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ print "
\n"; ++ } ++ print "
\n"; ++ print "
\n"; ++ output_section_html5(@_); ++ print "
\n"; ++} ++ ++# output DOC: block header in html5 ++sub output_blockhead_html5(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ my $html5id; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ $html5id = $section; ++ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; ++ print "
\n"; ++ print "

$section

\n"; ++ print "

\n"; ++ output_highlight($args{'sections'}{$section}); ++ print "

\n"; ++ } ++ print "
\n"; ++} ++ ++sub output_section_xml(%) { ++ my %args = %{$_[0]}; ++ my $section; ++ # print out each section ++ $lineprefix=" "; ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "\n"; ++ print "$section\n"; ++ if ($section =~ m/EXAMPLE/i) { ++ print "\n"; ++ $output_preformatted = 1; ++ } else { ++ print "\n"; ++ } ++ output_highlight($args{'sections'}{$section}); ++ $output_preformatted = 0; ++ if ($section =~ m/EXAMPLE/i) { ++ print "\n"; ++ } else { ++ print "\n"; ++ } ++ print "\n"; ++ } ++} ++ ++# output function in XML DocBook ++sub output_function_xml(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ my $id; ++ ++ $id = "API-" . $args{'function'}; ++ $id =~ s/[^A-Za-z0-9]/-/g; ++ ++ print "\n"; ++ print "\n"; ++ print " LINUX\n"; ++ print " Kernel Hackers Manual\n"; ++ print " $man_date\n"; ++ print "\n"; ++ print "\n"; ++ print " " . $args{'function'} . "\n"; ++ print " 9\n"; ++ print " " . $kernelversion . "\n"; ++ print "\n"; ++ print "\n"; ++ print " " . $args{'function'} . "\n"; ++ print " \n"; ++ print " "; ++ output_highlight ($args{'purpose'}); ++ print " \n"; ++ print "\n"; ++ ++ print "\n"; ++ print " Synopsis\n"; ++ print " \n"; ++ print " " . $args{'functiontype'} . " "; ++ print "" . $args{'function'} . " \n"; ++ ++ $count = 0; ++ if ($#{$args{'parameterlist'}} >= 0) { ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print " $1$parameter)\n"; ++ print " $2\n"; ++ } else { ++ print " " . $type; ++ print " $parameter\n"; ++ } ++ } ++ } else { ++ print " \n"; ++ } ++ print " \n"; ++ print "\n"; ++ ++ # print parameters ++ print "\n Arguments\n"; ++ if ($#{$args{'parameterlist'}} >= 0) { ++ print " \n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ print " \n $parameter\n"; ++ print " \n \n"; ++ $lineprefix=" "; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ print " \n \n \n"; ++ } ++ print " \n"; ++ } else { ++ print " \n None\n \n"; ++ } ++ print "\n"; ++ ++ output_section_xml(@_); ++ print "\n\n"; ++} ++ ++# output struct in XML DocBook ++sub output_struct_xml(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $id; ++ ++ $id = "API-struct-" . $args{'struct'}; ++ $id =~ s/[^A-Za-z0-9]/-/g; ++ ++ print "\n"; ++ print "\n"; ++ print " LINUX\n"; ++ print " Kernel Hackers Manual\n"; ++ print " $man_date\n"; ++ print "\n"; ++ print "\n"; ++ print " " . $args{'type'} . " " . $args{'struct'} . "\n"; ++ print " 9\n"; ++ print " " . $kernelversion . "\n"; ++ print "\n"; ++ print "\n"; ++ print " " . $args{'type'} . " " . $args{'struct'} . "\n"; ++ print " \n"; ++ print " "; ++ output_highlight ($args{'purpose'}); ++ print " \n"; ++ print "\n"; ++ ++ print "\n"; ++ print " Synopsis\n"; ++ print " \n"; ++ print $args{'type'} . " " . $args{'struct'} . " {\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ if ($parameter =~ /^#/) { ++ my $prm = $parameter; ++ # convert data read & converted thru xml_escape() into &xyz; format: ++ # This allows us to have #define macros interspersed in a struct. ++ $prm =~ s/\\\\\\/\&/g; ++ print "$prm\n"; ++ next; ++ } ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ defined($args{'parameterdescs'}{$parameter_name}) || next; ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print " $1 $parameter) ($2);\n"; ++ } elsif ($type =~ m/^(.*?)\s*(:.*)/) { ++ # bitfield ++ print " $1 $parameter$2;\n"; ++ } else { ++ print " " . $type . " " . $parameter . ";\n"; ++ } ++ } ++ print "};"; ++ print " \n"; ++ print "\n"; ++ ++ print " \n"; ++ print " Members\n"; ++ ++ if ($#{$args{'parameterlist'}} >= 0) { ++ print " \n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ ($parameter =~ /^#/) && next; ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ defined($args{'parameterdescs'}{$parameter_name}) || next; ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print " "; ++ print " $parameter\n"; ++ print " \n"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ print " \n"; ++ print " \n"; ++ } ++ print " \n"; ++ } else { ++ print " \n None\n \n"; ++ } ++ print " \n"; ++ ++ output_section_xml(@_); ++ ++ print "\n\n"; ++} ++ ++# output enum in XML DocBook ++sub output_enum_xml(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ my $id; ++ ++ $id = "API-enum-" . $args{'enum'}; ++ $id =~ s/[^A-Za-z0-9]/-/g; ++ ++ print "\n"; ++ print "\n"; ++ print " LINUX\n"; ++ print " Kernel Hackers Manual\n"; ++ print " $man_date\n"; ++ print "\n"; ++ print "\n"; ++ print " enum " . $args{'enum'} . "\n"; ++ print " 9\n"; ++ print " " . $kernelversion . "\n"; ++ print "\n"; ++ print "\n"; ++ print " enum " . $args{'enum'} . "\n"; ++ print " \n"; ++ print " "; ++ output_highlight ($args{'purpose'}); ++ print " \n"; ++ print "\n"; ++ ++ print "\n"; ++ print " Synopsis\n"; ++ print " \n"; ++ print "enum " . $args{'enum'} . " {\n"; ++ $count = 0; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print " $parameter"; ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ","; ++ } ++ print "\n"; ++ } ++ print "};"; ++ print " \n"; ++ print "\n"; ++ ++ print "\n"; ++ print " Constants\n"; ++ print " \n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ print " "; ++ print " $parameter\n"; ++ print " \n"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ print " \n"; ++ print " \n"; ++ } ++ print " \n"; ++ print "\n"; ++ ++ output_section_xml(@_); ++ ++ print "\n\n"; ++} ++ ++# output typedef in XML DocBook ++sub output_typedef_xml(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $id; ++ ++ $id = "API-typedef-" . $args{'typedef'}; ++ $id =~ s/[^A-Za-z0-9]/-/g; ++ ++ print "\n"; ++ print "\n"; ++ print " LINUX\n"; ++ print " Kernel Hackers Manual\n"; ++ print " $man_date\n"; ++ print "\n"; ++ print "\n"; ++ print " typedef " . $args{'typedef'} . "\n"; ++ print " 9\n"; ++ print "\n"; ++ print "\n"; ++ print " typedef " . $args{'typedef'} . "\n"; ++ print " \n"; ++ print " "; ++ output_highlight ($args{'purpose'}); ++ print " \n"; ++ print "\n"; ++ ++ print "\n"; ++ print " Synopsis\n"; ++ print " typedef " . $args{'typedef'} . ";\n"; ++ print "\n"; ++ ++ output_section_xml(@_); ++ ++ print "\n\n"; ++} ++ ++# output in XML DocBook ++sub output_blockhead_xml(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ ++ my $id = $args{'module'}; ++ $id =~ s/[^A-Za-z0-9]/-/g; ++ ++ # print out each section ++ $lineprefix=" "; ++ foreach $section (@{$args{'sectionlist'}}) { ++ if (!$args{'content-only'}) { ++ print "\n $section\n"; ++ } ++ if ($section =~ m/EXAMPLE/i) { ++ print "\n"; ++ $output_preformatted = 1; ++ } else { ++ print "\n"; ++ } ++ output_highlight($args{'sections'}{$section}); ++ $output_preformatted = 0; ++ if ($section =~ m/EXAMPLE/i) { ++ print "\n"; ++ } else { ++ print ""; ++ } ++ if (!$args{'content-only'}) { ++ print "\n\n"; ++ } ++ } ++ ++ print "\n\n"; ++} ++ ++# output in XML DocBook ++sub output_function_gnome { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ my $id; ++ ++ $id = $args{'module'} . "-" . $args{'function'}; ++ $id =~ s/[^A-Za-z0-9]/-/g; ++ ++ print "\n"; ++ print " " . $args{'function'} . "\n"; ++ ++ print " \n"; ++ print " " . $args{'functiontype'} . " "; ++ print "" . $args{'function'} . " "; ++ print "\n"; ++ ++ $count = 0; ++ if ($#{$args{'parameterlist'}} >= 0) { ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print " $1 $parameter)\n"; ++ print " $2\n"; ++ } else { ++ print " " . $type; ++ print " $parameter\n"; ++ } ++ } ++ } else { ++ print " \n"; ++ } ++ print " \n"; ++ if ($#{$args{'parameterlist'}} >= 0) { ++ print " \n"; ++ print "\n"; ++ print "\n"; ++ print "\n"; ++ print "\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ print " $parameter\n"; ++ print " \n"; ++ $lineprefix=" "; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ print " \n"; ++ } ++ print " \n"; ++ } else { ++ print " \n None\n \n"; ++ } ++ ++ # print out each section ++ $lineprefix=" "; ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "\n $section\n"; ++ if ($section =~ m/EXAMPLE/i) { ++ print "\n"; ++ $output_preformatted = 1; ++ } else { ++ } ++ print "\n"; ++ output_highlight($args{'sections'}{$section}); ++ $output_preformatted = 0; ++ print "\n"; ++ if ($section =~ m/EXAMPLE/i) { ++ print "\n"; ++ } else { ++ } ++ print " \n"; ++ } ++ ++ print "\n\n"; ++} ++ ++## ++# output function in man ++sub output_function_man(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ ++ print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; ++ ++ print ".SH NAME\n"; ++ print $args{'function'} . " \\- " . $args{'purpose'} . "\n"; ++ ++ print ".SH SYNOPSIS\n"; ++ if ($args{'functiontype'} ne "") { ++ print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; ++ } else { ++ print ".B \"" . $args{'function'} . "\n"; ++ } ++ $count = 0; ++ my $parenth = "("; ++ my $post = ","; ++ foreach my $parameter (@{$args{'parameterlist'}}) { ++ if ($count == $#{$args{'parameterlist'}}) { ++ $post = ");"; ++ } ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n"; ++ } else { ++ $type =~ s/([^\*])$/$1 /; ++ print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n"; ++ } ++ $count++; ++ $parenth = ""; ++ } ++ ++ print ".SH ARGUMENTS\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ print ".IP \"" . $parameter . "\" 12\n"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ } ++ foreach $section (@{$args{'sectionlist'}}) { ++ print ".SH \"", uc $section, "\"\n"; ++ output_highlight($args{'sections'}{$section}); ++ } ++} ++ ++## ++# output enum in man ++sub output_enum_man(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ ++ print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n"; ++ ++ print ".SH NAME\n"; ++ print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n"; ++ ++ print ".SH SYNOPSIS\n"; ++ print "enum " . $args{'enum'} . " {\n"; ++ $count = 0; ++ foreach my $parameter (@{$args{'parameterlist'}}) { ++ print ".br\n.BI \" $parameter\"\n"; ++ if ($count == $#{$args{'parameterlist'}}) { ++ print "\n};\n"; ++ last; ++ } ++ else { ++ print ", \n.br\n"; ++ } ++ $count++; ++ } ++ ++ print ".SH Constants\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ print ".IP \"" . $parameter . "\" 12\n"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ } ++ foreach $section (@{$args{'sectionlist'}}) { ++ print ".SH \"$section\"\n"; ++ output_highlight($args{'sections'}{$section}); ++ } ++} ++ ++## ++# output struct in man ++sub output_struct_man(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ ++ print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n"; ++ ++ print ".SH NAME\n"; ++ print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n"; ++ ++ print ".SH SYNOPSIS\n"; ++ print $args{'type'} . " " . $args{'struct'} . " {\n.br\n"; ++ ++ foreach my $parameter (@{$args{'parameterlist'}}) { ++ if ($parameter =~ /^#/) { ++ print ".BI \"$parameter\"\n.br\n"; ++ next; ++ } ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n"; ++ } elsif ($type =~ m/^(.*?)\s*(:.*)/) { ++ # bitfield ++ print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n"; ++ } else { ++ $type =~ s/([^\*])$/$1 /; ++ print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n"; ++ } ++ print "\n.br\n"; ++ } ++ print "};\n.br\n"; ++ ++ print ".SH Members\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ ($parameter =~ /^#/) && next; ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print ".IP \"" . $parameter . "\" 12\n"; ++ output_highlight($args{'parameterdescs'}{$parameter_name}); ++ } ++ foreach $section (@{$args{'sectionlist'}}) { ++ print ".SH \"$section\"\n"; ++ output_highlight($args{'sections'}{$section}); ++ } ++} ++ ++## ++# output typedef in man ++sub output_typedef_man(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ ++ print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n"; ++ ++ print ".SH NAME\n"; ++ print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print ".SH \"$section\"\n"; ++ output_highlight($args{'sections'}{$section}); ++ } ++} ++ ++sub output_blockhead_man(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $count; ++ ++ print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n"; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print ".SH \"$section\"\n"; ++ output_highlight($args{'sections'}{$section}); ++ } ++} ++ ++## ++# output in text ++sub output_function_text(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $start; ++ ++ print "Name:\n\n"; ++ print $args{'function'} . " - " . $args{'purpose'} . "\n"; ++ ++ print "\nSynopsis:\n\n"; ++ if ($args{'functiontype'} ne "") { ++ $start = $args{'functiontype'} . " " . $args{'function'} . " ("; ++ } else { ++ $start = $args{'function'} . " ("; ++ } ++ print $start; ++ ++ my $count = 0; ++ foreach my $parameter (@{$args{'parameterlist'}}) { ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print $1 . $parameter . ") (" . $2; ++ } else { ++ print $type . " " . $parameter; ++ } ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ",\n"; ++ print " " x length($start); ++ } else { ++ print ");\n\n"; ++ } ++ } ++ ++ print "Arguments:\n\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n"; ++ } ++ output_section_text(@_); ++} ++ ++#output sections in text ++sub output_section_text(%) { ++ my %args = %{$_[0]}; ++ my $section; ++ ++ print "\n"; ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "$section:\n\n"; ++ output_highlight($args{'sections'}{$section}); ++ } ++ print "\n\n"; ++} ++ ++# output enum in text ++sub output_enum_text(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $count; ++ print "Enum:\n\n"; ++ ++ print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n"; ++ print "enum " . $args{'enum'} . " {\n"; ++ $count = 0; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "\t$parameter"; ++ if ($count != $#{$args{'parameterlist'}}) { ++ $count++; ++ print ","; ++ } ++ print "\n"; ++ } ++ print "};\n\n"; ++ ++ print "Constants:\n\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "$parameter\n\t"; ++ print $args{'parameterdescs'}{$parameter} . "\n"; ++ } ++ ++ output_section_text(@_); ++} ++ ++# output typedef in text ++sub output_typedef_text(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $count; ++ print "Typedef:\n\n"; ++ ++ print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n"; ++ output_section_text(@_); ++} ++ ++# output struct as text ++sub output_struct_text(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ ++ print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n"; ++ print $args{'type'} . " " . $args{'struct'} . " {\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ if ($parameter =~ /^#/) { ++ print "$parameter\n"; ++ next; ++ } ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print "\t$1 $parameter) ($2);\n"; ++ } elsif ($type =~ m/^(.*?)\s*(:.*)/) { ++ # bitfield ++ print "\t$1 $parameter$2;\n"; ++ } else { ++ print "\t" . $type . " " . $parameter . ";\n"; ++ } ++ } ++ print "};\n\n"; ++ ++ print "Members:\n\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ ($parameter =~ /^#/) && next; ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ print "$parameter\n\t"; ++ print $args{'parameterdescs'}{$parameter_name} . "\n"; ++ } ++ print "\n"; ++ output_section_text(@_); ++} ++ ++sub output_blockhead_text(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print " $section:\n"; ++ print " -> "; ++ output_highlight($args{'sections'}{$section}); ++ } ++} ++ ++## ++# output in restructured text ++# ++ ++# ++# This could use some work; it's used to output the DOC: sections, and ++# starts by putting out the name of the doc section itself, but that tends ++# to duplicate a header already in the template file. ++# ++sub output_blockhead_rst(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ if ($output_selection != OUTPUT_INCLUDE) { ++ print "**$section**\n\n"; ++ } ++ print_lineno($section_start_lines{$section}); ++ output_highlight_rst($args{'sections'}{$section}); ++ print "\n"; ++ } ++} ++ ++sub output_highlight_rst { ++ my $contents = join "\n",@_; ++ my $line; ++ ++ # undo the evil effects of xml_escape() earlier ++ $contents = xml_unescape($contents); ++ ++ eval $dohighlight; ++ die $@ if $@; ++ ++ foreach $line (split "\n", $contents) { ++ print $lineprefix . $line . "\n"; ++ } ++} ++ ++sub output_function_rst(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ my $oldprefix = $lineprefix; ++ my $start = ""; ++ ++ if ($args{'typedef'}) { ++ print ".. c:type:: ". $args{'function'} . "\n\n"; ++ print_lineno($declaration_start_line); ++ print " **Typedef**: "; ++ $lineprefix = ""; ++ output_highlight_rst($args{'purpose'}); ++ $start = "\n\n**Syntax**\n\n ``"; ++ } else { ++ print ".. c:function:: "; ++ } ++ if ($args{'functiontype'} ne "") { ++ $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; ++ } else { ++ $start .= $args{'function'} . " ("; ++ } ++ print $start; ++ ++ my $count = 0; ++ foreach my $parameter (@{$args{'parameterlist'}}) { ++ if ($count ne 0) { ++ print ", "; ++ } ++ $count++; ++ $type = $args{'parametertypes'}{$parameter}; ++ ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print $1 . $parameter . ") (" . $2; ++ } else { ++ print $type . " " . $parameter; ++ } ++ } ++ if ($args{'typedef'}) { ++ print ");``\n\n"; ++ } else { ++ print ")\n\n"; ++ print_lineno($declaration_start_line); ++ $lineprefix = " "; ++ output_highlight_rst($args{'purpose'}); ++ print "\n"; ++ } ++ ++ print "**Parameters**\n\n"; ++ $lineprefix = " "; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ my $parameter_name = $parameter; ++ #$parameter_name =~ s/\[.*//; ++ $type = $args{'parametertypes'}{$parameter}; ++ ++ if ($type ne "") { ++ print "``$type $parameter``\n"; ++ } else { ++ print "``$parameter``\n"; ++ } ++ ++ print_lineno($parameterdesc_start_lines{$parameter_name}); ++ ++ if (defined($args{'parameterdescs'}{$parameter_name}) && ++ $args{'parameterdescs'}{$parameter_name} ne $undescribed) { ++ output_highlight_rst($args{'parameterdescs'}{$parameter_name}); ++ } else { ++ print " *undescribed*\n"; ++ } ++ print "\n"; ++ } ++ ++ $lineprefix = $oldprefix; ++ output_section_rst(@_); ++} ++ ++sub output_section_rst(%) { ++ my %args = %{$_[0]}; ++ my $section; ++ my $oldprefix = $lineprefix; ++ $lineprefix = ""; ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "**$section**\n\n"; ++ print_lineno($section_start_lines{$section}); ++ output_highlight_rst($args{'sections'}{$section}); ++ print "\n"; ++ } ++ print "\n"; ++ $lineprefix = $oldprefix; ++} ++ ++sub output_enum_rst(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $oldprefix = $lineprefix; ++ my $count; ++ my $name = "enum " . $args{'enum'}; ++ ++ print "\n\n.. c:type:: " . $name . "\n\n"; ++ print_lineno($declaration_start_line); ++ $lineprefix = " "; ++ output_highlight_rst($args{'purpose'}); ++ print "\n"; ++ ++ print "**Constants**\n\n"; ++ $lineprefix = " "; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ print "``$parameter``\n"; ++ if ($args{'parameterdescs'}{$parameter} ne $undescribed) { ++ output_highlight_rst($args{'parameterdescs'}{$parameter}); ++ } else { ++ print " *undescribed*\n"; ++ } ++ print "\n"; ++ } ++ ++ $lineprefix = $oldprefix; ++ output_section_rst(@_); ++} ++ ++sub output_typedef_rst(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $oldprefix = $lineprefix; ++ my $name = "typedef " . $args{'typedef'}; ++ ++ print "\n\n.. c:type:: " . $name . "\n\n"; ++ print_lineno($declaration_start_line); ++ $lineprefix = " "; ++ output_highlight_rst($args{'purpose'}); ++ print "\n"; ++ ++ $lineprefix = $oldprefix; ++ output_section_rst(@_); ++} ++ ++sub output_struct_rst(%) { ++ my %args = %{$_[0]}; ++ my ($parameter); ++ my $oldprefix = $lineprefix; ++ my $name = $args{'type'} . " " . $args{'struct'}; ++ ++ print "\n\n.. c:type:: " . $name . "\n\n"; ++ print_lineno($declaration_start_line); ++ $lineprefix = " "; ++ output_highlight_rst($args{'purpose'}); ++ print "\n"; ++ ++ print "**Definition**\n\n"; ++ print "::\n\n"; ++ print " " . $args{'type'} . " " . $args{'struct'} . " {\n"; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ if ($parameter =~ /^#/) { ++ print " " . "$parameter\n"; ++ next; ++ } ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { ++ # pointer-to-function ++ print " $1 $parameter) ($2);\n"; ++ } elsif ($type =~ m/^(.*?)\s*(:.*)/) { ++ # bitfield ++ print " $1 $parameter$2;\n"; ++ } else { ++ print " " . $type . " " . $parameter . ";\n"; ++ } ++ } ++ print " };\n\n"; ++ ++ print "**Members**\n\n"; ++ $lineprefix = " "; ++ foreach $parameter (@{$args{'parameterlist'}}) { ++ ($parameter =~ /^#/) && next; ++ ++ my $parameter_name = $parameter; ++ $parameter_name =~ s/\[.*//; ++ ++ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; ++ $type = $args{'parametertypes'}{$parameter}; ++ print_lineno($parameterdesc_start_lines{$parameter_name}); ++ print "``" . $parameter . "``\n"; ++ output_highlight_rst($args{'parameterdescs'}{$parameter_name}); ++ print "\n"; ++ } ++ print "\n"; ++ ++ $lineprefix = $oldprefix; ++ output_section_rst(@_); ++} ++ ++ ++## list mode output functions ++ ++sub output_function_list(%) { ++ my %args = %{$_[0]}; ++ ++ print $args{'function'} . "\n"; ++} ++ ++# output enum in list ++sub output_enum_list(%) { ++ my %args = %{$_[0]}; ++ print $args{'enum'} . "\n"; ++} ++ ++# output typedef in list ++sub output_typedef_list(%) { ++ my %args = %{$_[0]}; ++ print $args{'typedef'} . "\n"; ++} ++ ++# output struct as list ++sub output_struct_list(%) { ++ my %args = %{$_[0]}; ++ ++ print $args{'struct'} . "\n"; ++} ++ ++sub output_blockhead_list(%) { ++ my %args = %{$_[0]}; ++ my ($parameter, $section); ++ ++ foreach $section (@{$args{'sectionlist'}}) { ++ print "DOC: $section\n"; ++ } ++} ++ ++## ++# generic output function for all types (function, struct/union, typedef, enum); ++# calls the generated, variable output_ function name based on ++# functype and output_mode ++sub output_declaration { ++ no strict 'refs'; ++ my $name = shift; ++ my $functype = shift; ++ my $func = "output_${functype}_$output_mode"; ++ if (($output_selection == OUTPUT_ALL) || ++ (($output_selection == OUTPUT_INCLUDE || ++ $output_selection == OUTPUT_EXPORTED) && ++ defined($function_table{$name})) || ++ (($output_selection == OUTPUT_EXCLUDE || ++ $output_selection == OUTPUT_INTERNAL) && ++ !($functype eq "function" && defined($function_table{$name})))) ++ { ++ &$func(@_); ++ $section_counter++; ++ } ++} ++ ++## ++# generic output function - calls the right one based on current output mode. ++sub output_blockhead { ++ no strict 'refs'; ++ my $func = "output_blockhead_" . $output_mode; ++ &$func(@_); ++ $section_counter++; ++} ++ ++## ++# takes a declaration (struct, union, enum, typedef) and ++# invokes the right handler. NOT called for functions. ++sub dump_declaration($$) { ++ no strict 'refs'; ++ my ($prototype, $file) = @_; ++ my $func = "dump_" . $decl_type; ++ &$func(@_); ++} ++ ++sub dump_union($$) { ++ dump_struct(@_); ++} ++ ++sub dump_struct($$) { ++ my $x = shift; ++ my $file = shift; ++ my $nested; ++ ++ if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { ++ #my $decl_type = $1; ++ $declaration_name = $2; ++ my $members = $3; ++ ++ # ignore embedded structs or unions ++ $members =~ s/({.*})//g; ++ $nested = $1; ++ ++ # ignore members marked private: ++ $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; ++ $members =~ s/\/\*\s*private:.*//gosi; ++ # strip comments: ++ $members =~ s/\/\*.*?\*\///gos; ++ $nested =~ s/\/\*.*?\*\///gos; ++ # strip kmemcheck_bitfield_{begin,end}.*; ++ $members =~ s/kmemcheck_bitfield_.*?;//gos; ++ # strip attributes ++ $members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i; ++ $members =~ s/__aligned\s*\([^;]*\)//gos; ++ $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos; ++ # replace DECLARE_BITMAP ++ $members =~ s/DECLARE_BITMAP\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; ++ ++ create_parameterlist($members, ';', $file); ++ check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); ++ ++ output_declaration($declaration_name, ++ 'struct', ++ {'struct' => $declaration_name, ++ 'module' => $modulename, ++ 'parameterlist' => \@parameterlist, ++ 'parameterdescs' => \%parameterdescs, ++ 'parametertypes' => \%parametertypes, ++ 'sectionlist' => \@sectionlist, ++ 'sections' => \%sections, ++ 'purpose' => $declaration_purpose, ++ 'type' => $decl_type ++ }); ++ } ++ else { ++ print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; ++ ++$errors; ++ } ++} ++ ++sub dump_enum($$) { ++ my $x = shift; ++ my $file = shift; ++ ++ $x =~ s@/\*.*?\*/@@gos; # strip comments. ++ # strip #define macros inside enums ++ $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; ++ ++ if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { ++ $declaration_name = $1; ++ my $members = $2; ++ ++ foreach my $arg (split ',', $members) { ++ $arg =~ s/^\s*(\w+).*/$1/; ++ push @parameterlist, $arg; ++ if (!$parameterdescs{$arg}) { ++ $parameterdescs{$arg} = $undescribed; ++ print STDERR "${file}:$.: warning: Enum value '$arg' ". ++ "not described in enum '$declaration_name'\n"; ++ } ++ ++ } ++ ++ output_declaration($declaration_name, ++ 'enum', ++ {'enum' => $declaration_name, ++ 'module' => $modulename, ++ 'parameterlist' => \@parameterlist, ++ 'parameterdescs' => \%parameterdescs, ++ 'sectionlist' => \@sectionlist, ++ 'sections' => \%sections, ++ 'purpose' => $declaration_purpose ++ }); ++ } ++ else { ++ print STDERR "${file}:$.: error: Cannot parse enum!\n"; ++ ++$errors; ++ } ++} ++ ++sub dump_typedef($$) { ++ my $x = shift; ++ my $file = shift; ++ ++ $x =~ s@/\*.*?\*/@@gos; # strip comments. ++ ++ # Parse function prototypes ++ if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ || ++ $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) { ++ ++ # Function typedefs ++ $return_type = $1; ++ $declaration_name = $2; ++ my $args = $3; ++ ++ create_parameterlist($args, ',', $file); ++ ++ output_declaration($declaration_name, ++ 'function', ++ {'function' => $declaration_name, ++ 'typedef' => 1, ++ 'module' => $modulename, ++ 'functiontype' => $return_type, ++ 'parameterlist' => \@parameterlist, ++ 'parameterdescs' => \%parameterdescs, ++ 'parametertypes' => \%parametertypes, ++ 'sectionlist' => \@sectionlist, ++ 'sections' => \%sections, ++ 'purpose' => $declaration_purpose ++ }); ++ return; ++ } ++ ++ while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { ++ $x =~ s/\(*.\)\s*;$/;/; ++ $x =~ s/\[*.\]\s*;$/;/; ++ } ++ ++ if ($x =~ /typedef.*\s+(\w+)\s*;/) { ++ $declaration_name = $1; ++ ++ output_declaration($declaration_name, ++ 'typedef', ++ {'typedef' => $declaration_name, ++ 'module' => $modulename, ++ 'sectionlist' => \@sectionlist, ++ 'sections' => \%sections, ++ 'purpose' => $declaration_purpose ++ }); ++ } ++ else { ++ print STDERR "${file}:$.: error: Cannot parse typedef!\n"; ++ ++$errors; ++ } ++} ++ ++sub save_struct_actual($) { ++ my $actual = shift; ++ ++ # strip all spaces from the actual param so that it looks like one string item ++ $actual =~ s/\s*//g; ++ $struct_actual = $struct_actual . $actual . " "; ++} ++ ++sub create_parameterlist($$$) { ++ my $args = shift; ++ my $splitter = shift; ++ my $file = shift; ++ my $type; ++ my $param; ++ ++ # temporarily replace commas inside function pointer definition ++ while ($args =~ /(\([^\),]+),/) { ++ $args =~ s/(\([^\),]+),/$1#/g; ++ } ++ ++ foreach my $arg (split($splitter, $args)) { ++ # strip comments ++ $arg =~ s/\/\*.*\*\///; ++ # strip leading/trailing spaces ++ $arg =~ s/^\s*//; ++ $arg =~ s/\s*$//; ++ $arg =~ s/\s+/ /; ++ ++ if ($arg =~ /^#/) { ++ # Treat preprocessor directive as a typeless variable just to fill ++ # corresponding data structures "correctly". Catch it later in ++ # output_* subs. ++ push_parameter($arg, "", $file); ++ } elsif ($arg =~ m/\(.+\)\s*\(/) { ++ # pointer-to-function ++ $arg =~ tr/#/,/; ++ $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; ++ $param = $1; ++ $type = $arg; ++ $type =~ s/([^\(]+\(\*?)\s*$param/$1/; ++ save_struct_actual($param); ++ push_parameter($param, $type, $file); ++ } elsif ($arg) { ++ $arg =~ s/\s*:\s*/:/g; ++ $arg =~ s/\s*\[/\[/g; ++ ++ my @args = split('\s*,\s*', $arg); ++ if ($args[0] =~ m/\*/) { ++ $args[0] =~ s/(\*+)\s*/ $1/; ++ } ++ ++ my @first_arg; ++ if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { ++ shift @args; ++ push(@first_arg, split('\s+', $1)); ++ push(@first_arg, $2); ++ } else { ++ @first_arg = split('\s+', shift @args); ++ } ++ ++ unshift(@args, pop @first_arg); ++ $type = join " ", @first_arg; ++ ++ foreach $param (@args) { ++ if ($param =~ m/^(\*+)\s*(.*)/) { ++ save_struct_actual($2); ++ push_parameter($2, "$type $1", $file); ++ } ++ elsif ($param =~ m/(.*?):(\d+)/) { ++ if ($type ne "") { # skip unnamed bit-fields ++ save_struct_actual($1); ++ push_parameter($1, "$type:$2", $file) ++ } ++ } ++ else { ++ save_struct_actual($param); ++ push_parameter($param, $type, $file); ++ } ++ } ++ } ++ } ++} ++ ++sub push_parameter($$$) { ++ my $param = shift; ++ my $type = shift; ++ my $file = shift; ++ ++ if (($anon_struct_union == 1) && ($type eq "") && ++ ($param eq "}")) { ++ return; # ignore the ending }; from anon. struct/union ++ } ++ ++ $anon_struct_union = 0; ++ my $param_name = $param; ++ $param_name =~ s/\[.*//; ++ ++ if ($type eq "" && $param =~ /\.\.\.$/) ++ { ++ if (!$param =~ /\w\.\.\.$/) { ++ # handles unnamed variable parameters ++ $param = "..."; ++ } ++ if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { ++ $parameterdescs{$param} = "variable arguments"; ++ } ++ } ++ elsif ($type eq "" && ($param eq "" or $param eq "void")) ++ { ++ $param="void"; ++ $parameterdescs{void} = "no arguments"; ++ } ++ elsif ($type eq "" && ($param eq "struct" or $param eq "union")) ++ # handle unnamed (anonymous) union or struct: ++ { ++ $type = $param; ++ $param = "{unnamed_" . $param . "}"; ++ $parameterdescs{$param} = "anonymous\n"; ++ $anon_struct_union = 1; ++ } ++ ++ # warn if parameter has no description ++ # (but ignore ones starting with # as these are not parameters ++ # but inline preprocessor statements); ++ # also ignore unnamed structs/unions; ++ if (!$anon_struct_union) { ++ if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { ++ ++ $parameterdescs{$param_name} = $undescribed; ++ ++ if (($type eq 'function') || ($type eq 'enum')) { ++ print STDERR "${file}:$.: warning: Function parameter ". ++ "or member '$param' not " . ++ "described in '$declaration_name'\n"; ++ } ++ print STDERR "${file}:$.: warning:" . ++ " No description found for parameter '$param'\n"; ++ ++$warnings; ++ } ++ } ++ ++ $param = xml_escape($param); ++ ++ # strip spaces from $param so that it is one continuous string ++ # on @parameterlist; ++ # this fixes a problem where check_sections() cannot find ++ # a parameter like "addr[6 + 2]" because it actually appears ++ # as "addr[6", "+", "2]" on the parameter list; ++ # but it's better to maintain the param string unchanged for output, ++ # so just weaken the string compare in check_sections() to ignore ++ # "[blah" in a parameter string; ++ ###$param =~ s/\s*//g; ++ push @parameterlist, $param; ++ $parametertypes{$param} = $type; ++} ++ ++sub check_sections($$$$$$) { ++ my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; ++ my @sects = split ' ', $sectcheck; ++ my @prms = split ' ', $prmscheck; ++ my $err; ++ my ($px, $sx); ++ my $prm_clean; # strip trailing "[array size]" and/or beginning "*" ++ ++ foreach $sx (0 .. $#sects) { ++ $err = 1; ++ foreach $px (0 .. $#prms) { ++ $prm_clean = $prms[$px]; ++ $prm_clean =~ s/\[.*\]//; ++ $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i; ++ # ignore array size in a parameter string; ++ # however, the original param string may contain ++ # spaces, e.g.: addr[6 + 2] ++ # and this appears in @prms as "addr[6" since the ++ # parameter list is split at spaces; ++ # hence just ignore "[..." for the sections check; ++ $prm_clean =~ s/\[.*//; ++ ++ ##$prm_clean =~ s/^\**//; ++ if ($prm_clean eq $sects[$sx]) { ++ $err = 0; ++ last; ++ } ++ } ++ if ($err) { ++ if ($decl_type eq "function") { ++ print STDERR "${file}:$.: warning: " . ++ "Excess function parameter " . ++ "'$sects[$sx]' " . ++ "description in '$decl_name'\n"; ++ ++$warnings; ++ } else { ++ if ($nested !~ m/\Q$sects[$sx]\E/) { ++ print STDERR "${file}:$.: warning: " . ++ "Excess struct/union/enum/typedef member " . ++ "'$sects[$sx]' " . ++ "description in '$decl_name'\n"; ++ ++$warnings; ++ } ++ } ++ } ++ } ++} ++ ++## ++# Checks the section describing the return value of a function. ++sub check_return_section { ++ my $file = shift; ++ my $declaration_name = shift; ++ my $return_type = shift; ++ ++ # Ignore an empty return type (It's a macro) ++ # Ignore functions with a "void" return type. (But don't ignore "void *") ++ if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { ++ return; ++ } ++ ++ if (!defined($sections{$section_return}) || ++ $sections{$section_return} eq "") { ++ print STDERR "${file}:$.: warning: " . ++ "No description found for return value of " . ++ "'$declaration_name'\n"; ++ ++$warnings; ++ } ++} ++ ++## ++# takes a function prototype and the name of the current file being ++# processed and spits out all the details stored in the global ++# arrays/hashes. ++sub dump_function($$) { ++ my $prototype = shift; ++ my $file = shift; ++ my $noret = 0; ++ ++ $prototype =~ s/^static +//; ++ $prototype =~ s/^extern +//; ++ $prototype =~ s/^asmlinkage +//; ++ $prototype =~ s/^inline +//; ++ $prototype =~ s/^__inline__ +//; ++ $prototype =~ s/^__inline +//; ++ $prototype =~ s/^__always_inline +//; ++ $prototype =~ s/^noinline +//; ++ $prototype =~ s/__init +//; ++ $prototype =~ s/__init_or_module +//; ++ $prototype =~ s/__meminit +//; ++ $prototype =~ s/__must_check +//; ++ $prototype =~ s/__weak +//; ++ my $define = $prototype =~ s/^#\s*define\s+//; #ak added ++ $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; ++ ++ # Yes, this truly is vile. We are looking for: ++ # 1. Return type (may be nothing if we're looking at a macro) ++ # 2. Function name ++ # 3. Function parameters. ++ # ++ # All the while we have to watch out for function pointer parameters ++ # (which IIRC is what the two sections are for), C types (these ++ # regexps don't even start to express all the possibilities), and ++ # so on. ++ # ++ # If you mess with these regexps, it's a good idea to check that ++ # the following functions' documentation still comes out right: ++ # - parport_register_device (function pointer parameters) ++ # - atomic_set (macro) ++ # - pci_match_device, __copy_to_user (long return type) ++ ++ if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) { ++ # This is an object-like macro, it has no return type and no parameter ++ # list. ++ # Function-like macros are not allowed to have spaces between ++ # declaration_name and opening parenthesis (notice the \s+). ++ $return_type = $1; ++ $declaration_name = $2; ++ $noret = 1; ++ } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || ++ $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || ++ $prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { ++ $return_type = $1; ++ $declaration_name = $2; ++ my $args = $3; ++ ++ create_parameterlist($args, ',', $file); ++ } else { ++ print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n"; ++ return; ++ } ++ ++ my $prms = join " ", @parameterlist; ++ check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); ++ ++ # This check emits a lot of warnings at the moment, because many ++ # functions don't have a 'Return' doc section. So until the number ++ # of warnings goes sufficiently down, the check is only performed in ++ # verbose mode. ++ # TODO: always perform the check. ++ if ($verbose && !$noret) { ++ check_return_section($file, $declaration_name, $return_type); ++ } ++ ++ output_declaration($declaration_name, ++ 'function', ++ {'function' => $declaration_name, ++ 'module' => $modulename, ++ 'functiontype' => $return_type, ++ 'parameterlist' => \@parameterlist, ++ 'parameterdescs' => \%parameterdescs, ++ 'parametertypes' => \%parametertypes, ++ 'sectionlist' => \@sectionlist, ++ 'sections' => \%sections, ++ 'purpose' => $declaration_purpose ++ }); ++} ++ ++sub reset_state { ++ $function = ""; ++ %parameterdescs = (); ++ %parametertypes = (); ++ @parameterlist = (); ++ %sections = (); ++ @sectionlist = (); ++ $sectcheck = ""; ++ $struct_actual = ""; ++ $prototype = ""; ++ ++ $state = STATE_NORMAL; ++ $inline_doc_state = STATE_INLINE_NA; ++} ++ ++sub tracepoint_munge($) { ++ my $file = shift; ++ my $tracepointname = 0; ++ my $tracepointargs = 0; ++ ++ if ($prototype =~ m/TRACE_EVENT\((.*?),/) { ++ $tracepointname = $1; ++ } ++ if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { ++ $tracepointname = $1; ++ } ++ if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { ++ $tracepointname = $2; ++ } ++ $tracepointname =~ s/^\s+//; #strip leading whitespace ++ if ($prototype =~ m/TP_PROTO\((.*?)\)/) { ++ $tracepointargs = $1; ++ } ++ if (($tracepointname eq 0) || ($tracepointargs eq 0)) { ++ print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n". ++ "$prototype\n"; ++ } else { ++ $prototype = "static inline void trace_$tracepointname($tracepointargs)"; ++ } ++} ++ ++sub syscall_munge() { ++ my $void = 0; ++ ++ $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs ++## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { ++ if ($prototype =~ m/SYSCALL_DEFINE0/) { ++ $void = 1; ++## $prototype = "long sys_$1(void)"; ++ } ++ ++ $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name ++ if ($prototype =~ m/long (sys_.*?),/) { ++ $prototype =~ s/,/\(/; ++ } elsif ($void) { ++ $prototype =~ s/\)/\(void\)/; ++ } ++ ++ # now delete all of the odd-number commas in $prototype ++ # so that arg types & arg names don't have a comma between them ++ my $count = 0; ++ my $len = length($prototype); ++ if ($void) { ++ $len = 0; # skip the for-loop ++ } ++ for (my $ix = 0; $ix < $len; $ix++) { ++ if (substr($prototype, $ix, 1) eq ',') { ++ $count++; ++ if ($count % 2 == 1) { ++ substr($prototype, $ix, 1) = ' '; ++ } ++ } ++ } ++} ++ ++sub process_proto_function($$) { ++ my $x = shift; ++ my $file = shift; ++ ++ $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line ++ ++ if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) { ++ # do nothing ++ } ++ elsif ($x =~ /([^\{]*)/) { ++ $prototype .= $1; ++ } ++ ++ if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { ++ $prototype =~ s@/\*.*?\*/@@gos; # strip comments. ++ $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. ++ $prototype =~ s@^\s+@@gos; # strip leading spaces ++ if ($prototype =~ /SYSCALL_DEFINE/) { ++ syscall_munge(); ++ } ++ if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || ++ $prototype =~ /DEFINE_SINGLE_EVENT/) ++ { ++ tracepoint_munge($file); ++ } ++ dump_function($prototype, $file); ++ reset_state(); ++ } ++} ++ ++sub process_proto_type($$) { ++ my $x = shift; ++ my $file = shift; ++ ++ $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's. ++ $x =~ s@^\s+@@gos; # strip leading spaces ++ $x =~ s@\s+$@@gos; # strip trailing spaces ++ $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line ++ ++ if ($x =~ /^#/) { ++ # To distinguish preprocessor directive from regular declaration later. ++ $x .= ";"; ++ } ++ ++ while (1) { ++ if ( $x =~ /([^{};]*)([{};])(.*)/ ) { ++ $prototype .= $1 . $2; ++ ($2 eq '{') && $brcount++; ++ ($2 eq '}') && $brcount--; ++ if (($2 eq ';') && ($brcount == 0)) { ++ dump_declaration($prototype, $file); ++ reset_state(); ++ last; ++ } ++ $x = $3; ++ } else { ++ $prototype .= $x; ++ last; ++ } ++ } ++} ++ ++# xml_escape: replace <, >, and & in the text stream; ++# ++# however, formatting controls that are generated internally/locally in the ++# kernel-doc script are not escaped here; instead, they begin life like ++# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings ++# are converted to their mnemonic-expected output, without the 4 * '\' & ':', ++# just before actual output; (this is done by local_unescape()) ++sub xml_escape($) { ++ my $text = shift; ++ if (($output_mode eq "text") || ($output_mode eq "man")) { ++ return $text; ++ } ++ $text =~ s/\&/\\\\\\amp;/g; ++ $text =~ s/\/\\\\\\gt;/g; ++ return $text; ++} ++ ++# xml_unescape: reverse the effects of xml_escape ++sub xml_unescape($) { ++ my $text = shift; ++ if (($output_mode eq "text") || ($output_mode eq "man")) { ++ return $text; ++ } ++ $text =~ s/\\\\\\amp;/\&/g; ++ $text =~ s/\\\\\\lt;//g; ++ return $text; ++} ++ ++# convert local escape strings to html ++# local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) ++sub local_unescape($) { ++ my $text = shift; ++ if (($output_mode eq "text") || ($output_mode eq "man")) { ++ return $text; ++ } ++ $text =~ s/\\\\\\\\lt://g; ++ return $text; ++} ++ ++sub map_filename($) { ++ my $file; ++ my ($orig_file) = @_; ++ ++ if (defined($ENV{'SRCTREE'})) { ++ $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; ++ } else { ++ $file = $orig_file; ++ } ++ ++ if (defined($source_map{$file})) { ++ $file = $source_map{$file}; ++ } ++ ++ return $file; ++} ++ ++sub process_export_file($) { ++ my ($orig_file) = @_; ++ my $file = map_filename($orig_file); ++ ++ if (!open(IN,"<$file")) { ++ print STDERR "Error: Cannot open file $file\n"; ++ ++$errors; ++ return; ++ } ++ ++ while () { ++ if (/$export_symbol/) { ++ $function_table{$2} = 1; ++ } ++ } ++ ++ close(IN); ++} ++ ++sub process_file($) { ++ my $file; ++ my $identifier; ++ my $func; ++ my $descr; ++ my $in_purpose = 0; ++ my $initial_section_counter = $section_counter; ++ my ($orig_file) = @_; ++ my $leading_space; ++ ++ $file = map_filename($orig_file); ++ ++ if (!open(IN,"<$file")) { ++ print STDERR "Error: Cannot open file $file\n"; ++ ++$errors; ++ return; ++ } ++ ++ $. = 1; ++ ++ $section_counter = 0; ++ while () { ++ while (s/\\\s*$//) { ++ $_ .= ; ++ } ++ if ($state == STATE_NORMAL) { ++ if (/$doc_start/o) { ++ $state = STATE_NAME; # next line is always the function name ++ $in_doc_sect = 0; ++ $declaration_start_line = $. + 1; ++ } ++ } elsif ($state == STATE_NAME) {# this line is the function name (always) ++ if (/$doc_block/o) { ++ $state = STATE_DOCBLOCK; ++ $contents = ""; ++ $new_start_line = $. + 1; ++ ++ if ( $1 eq "" ) { ++ $section = $section_intro; ++ } else { ++ $section = $1; ++ } ++ } ++ elsif (/$doc_decl/o) { ++ $identifier = $1; ++ if (/\s*([\w\s]+?)\s*-/) { ++ $identifier = $1; ++ } ++ ++ $state = STATE_FIELD; ++ # if there's no @param blocks need to set up default section ++ # here ++ $contents = ""; ++ $section = $section_default; ++ $new_start_line = $. + 1; ++ if (/-(.*)/) { ++ # strip leading/trailing/multiple spaces ++ $descr= $1; ++ $descr =~ s/^\s*//; ++ $descr =~ s/\s*$//; ++ $descr =~ s/\s+/ /g; ++ $declaration_purpose = xml_escape($descr); ++ $in_purpose = 1; ++ } else { ++ $declaration_purpose = ""; ++ } ++ ++ if (($declaration_purpose eq "") && $verbose) { ++ print STDERR "${file}:$.: warning: missing initial short description on line:\n"; ++ print STDERR $_; ++ ++$warnings; ++ } ++ ++ if ($identifier =~ m/^struct/) { ++ $decl_type = 'struct'; ++ } elsif ($identifier =~ m/^union/) { ++ $decl_type = 'union'; ++ } elsif ($identifier =~ m/^enum/) { ++ $decl_type = 'enum'; ++ } elsif ($identifier =~ m/^typedef/) { ++ $decl_type = 'typedef'; ++ } else { ++ $decl_type = 'function'; ++ } ++ ++ if ($verbose) { ++ print STDERR "${file}:$.: info: Scanning doc for $identifier\n"; ++ } ++ } else { ++ print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", ++ " - I thought it was a doc line\n"; ++ ++$warnings; ++ $state = STATE_NORMAL; ++ } ++ } elsif ($state == STATE_FIELD) { # look for head: lines, and include content ++ if (/$doc_sect/i) { # case insensitive for supported section names ++ $newsection = $1; ++ $newcontents = $2; ++ ++ # map the supported section names to the canonical names ++ if ($newsection =~ m/^description$/i) { ++ $newsection = $section_default; ++ } elsif ($newsection =~ m/^context$/i) { ++ $newsection = $section_context; ++ } elsif ($newsection =~ m/^returns?$/i) { ++ $newsection = $section_return; ++ } elsif ($newsection =~ m/^\@return$/) { ++ # special: @return is a section, not a param description ++ $newsection = $section_return; ++ } ++ ++ if (($contents ne "") && ($contents ne "\n")) { ++ if (!$in_doc_sect && $verbose) { ++ print STDERR "${file}:$.: warning: contents before sections\n"; ++ ++$warnings; ++ } ++ dump_section($file, $section, xml_escape($contents)); ++ $section = $section_default; ++ } ++ ++ $in_doc_sect = 1; ++ $in_purpose = 0; ++ $contents = $newcontents; ++ $new_start_line = $.; ++ while ((substr($contents, 0, 1) eq " ") || ++ substr($contents, 0, 1) eq "\t") { ++ $contents = substr($contents, 1); ++ } ++ if ($contents ne "") { ++ $contents .= "\n"; ++ } ++ $section = $newsection; ++ $leading_space = undef; ++ } elsif (/$doc_end/) { ++ if (($contents ne "") && ($contents ne "\n")) { ++ dump_section($file, $section, xml_escape($contents)); ++ $section = $section_default; ++ $contents = ""; ++ } ++ # look for doc_com + + doc_end: ++ if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { ++ print STDERR "${file}:$.: warning: suspicious ending line: $_"; ++ ++$warnings; ++ } ++ ++ $prototype = ""; ++ $state = STATE_PROTO; ++ $brcount = 0; ++# print STDERR "end of doc comment, looking for prototype\n"; ++ } elsif (/$doc_content/) { ++ # miguel-style comment kludge, look for blank lines after ++ # @parameter line to signify start of description ++ if ($1 eq "") { ++ if ($section =~ m/^@/ || $section eq $section_context) { ++ dump_section($file, $section, xml_escape($contents)); ++ $section = $section_default; ++ $contents = ""; ++ $new_start_line = $.; ++ } else { ++ $contents .= "\n"; ++ } ++ $in_purpose = 0; ++ } elsif ($in_purpose == 1) { ++ # Continued declaration purpose ++ chomp($declaration_purpose); ++ $declaration_purpose .= " " . xml_escape($1); ++ $declaration_purpose =~ s/\s+/ /g; ++ } else { ++ my $cont = $1; ++ if ($section =~ m/^@/ || $section eq $section_context) { ++ if (!defined $leading_space) { ++ if ($cont =~ m/^(\s+)/) { ++ $leading_space = $1; ++ } else { ++ $leading_space = ""; ++ } ++ } ++ ++ $cont =~ s/^$leading_space//; ++ } ++ $contents .= $cont . "\n"; ++ } ++ } else { ++ # i dont know - bad line? ignore. ++ print STDERR "${file}:$.: warning: bad line: $_"; ++ ++$warnings; ++ } ++ } elsif ($state == STATE_INLINE) { # scanning for inline parameters ++ # First line (state 1) needs to be a @parameter ++ if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { ++ $section = $1; ++ $contents = $2; ++ $new_start_line = $.; ++ if ($contents ne "") { ++ while ((substr($contents, 0, 1) eq " ") || ++ substr($contents, 0, 1) eq "\t") { ++ $contents = substr($contents, 1); ++ } ++ $contents .= "\n"; ++ } ++ $inline_doc_state = STATE_INLINE_TEXT; ++ # Documentation block end */ ++ } elsif (/$doc_inline_end/) { ++ if (($contents ne "") && ($contents ne "\n")) { ++ dump_section($file, $section, xml_escape($contents)); ++ $section = $section_default; ++ $contents = ""; ++ } ++ $state = STATE_PROTO; ++ $inline_doc_state = STATE_INLINE_NA; ++ # Regular text ++ } elsif (/$doc_content/) { ++ if ($inline_doc_state == STATE_INLINE_TEXT) { ++ $contents .= $1 . "\n"; ++ # nuke leading blank lines ++ if ($contents =~ /^\s*$/) { ++ $contents = ""; ++ } ++ } elsif ($inline_doc_state == STATE_INLINE_NAME) { ++ $inline_doc_state = STATE_INLINE_ERROR; ++ print STDERR "${file}:$.: warning: "; ++ print STDERR "Incorrect use of kernel-doc format: $_"; ++ ++$warnings; ++ } ++ } ++ } elsif ($state == STATE_PROTO) { # scanning for function '{' (end of prototype) ++ if (/$doc_inline_oneline/) { ++ $section = $1; ++ $contents = $2; ++ if ($contents ne "") { ++ $contents .= "\n"; ++ dump_section($file, $section, xml_escape($contents)); ++ $section = $section_default; ++ $contents = ""; ++ } ++ } elsif (/$doc_inline_start/) { ++ $state = STATE_INLINE; ++ $inline_doc_state = STATE_INLINE_NAME; ++ } elsif ($decl_type eq 'function') { ++ process_proto_function($_, $file); ++ } else { ++ process_proto_type($_, $file); ++ } ++ } elsif ($state == STATE_DOCBLOCK) { ++ if (/$doc_end/) ++ { ++ dump_doc_section($file, $section, xml_escape($contents)); ++ $section = $section_default; ++ $contents = ""; ++ $function = ""; ++ %parameterdescs = (); ++ %parametertypes = (); ++ @parameterlist = (); ++ %sections = (); ++ @sectionlist = (); ++ $prototype = ""; ++ $state = STATE_NORMAL; ++ } ++ elsif (/$doc_content/) ++ { ++ if ( $1 eq "" ) ++ { ++ $contents .= $blankline; ++ } ++ else ++ { ++ $contents .= $1 . "\n"; ++ } ++ } ++ } ++ } ++ if ($initial_section_counter == $section_counter) { ++ print STDERR "${file}:1: warning: no structured comments found\n"; ++ if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) { ++ print STDERR " Was looking for '$_'.\n" for keys %function_table; ++ } ++ if ($output_mode eq "xml") { ++ # The template wants at least one RefEntry here; make one. ++ print "\n"; ++ print " \n"; ++ print " \n"; ++ print " ${orig_file}\n"; ++ print " \n"; ++ print " \n"; ++ print " Document generation inconsistency\n"; ++ print " \n"; ++ print " \n"; ++ print " \n"; ++ print " \n"; ++ print " Oops\n"; ++ print " \n"; ++ print " \n"; ++ print " \n"; ++ print " The template for this document tried to insert\n"; ++ print " the structured comment from the file\n"; ++ print " ${orig_file} at this point,\n"; ++ print " but none was found.\n"; ++ print " This dummy section is inserted to allow\n"; ++ print " generation to continue.\n"; ++ print " \n"; ++ print " \n"; ++ print " \n"; ++ print "\n"; ++ } ++ } ++} ++ ++ ++$kernelversion = get_kernel_version(); ++ ++# generate a sequence of code that will splice in highlighting information ++# using the s// operator. ++for (my $k = 0; $k < @highlights; $k++) { ++ my $pattern = $highlights[$k][0]; ++ my $result = $highlights[$k][1]; ++# print STDERR "scanning pattern:$pattern, highlight:($result)\n"; ++ $dohighlight .= "\$contents =~ s:$pattern:$result:gs;\n"; ++} ++ ++# Read the file that maps relative names to absolute names for ++# separate source and object directories and for shadow trees. ++if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { ++ my ($relname, $absname); ++ while() { ++ chop(); ++ ($relname, $absname) = (split())[0..1]; ++ $relname =~ s:^/+::; ++ $source_map{$relname} = $absname; ++ } ++ close(SOURCE_MAP); ++} ++ ++if ($output_selection == OUTPUT_EXPORTED || ++ $output_selection == OUTPUT_INTERNAL) { ++ ++ push(@export_file_list, @ARGV); ++ ++ foreach (@export_file_list) { ++ chomp; ++ process_export_file($_); ++ } ++} ++ ++foreach (@ARGV) { ++ chomp; ++ process_file($_); ++} ++if ($verbose && $errors) { ++ print STDERR "$errors errors\n"; ++} ++if ($verbose && $warnings) { ++ print STDERR "$warnings warnings\n"; ++} ++ ++exit($errors); +Index: multipath-tools-130222/libdmmp/docs/libdmmp.h.3 +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/docs/libdmmp.h.3 +@@ -0,0 +1,113 @@ ++.TH "libdmmp.h" 3 "January 2016" "Device Mapper Multipath API - libdmmp Manual" ++ ++.SH NAME ++libdmmp.h \- Device Mapper Multipath API. ++ ++.SH SYNOPSIS ++#include ++ ++.SH "DESCRIPTION" ++ ++All the libdmmp public functions ships its own man pages. ++Use 'man 3 ' to check the detail usage. ++ ++.SH "USAGE" ++ ++To use libdmmp in your project, we suggest to use the 'pkg-config' way: ++ ++ * Add this line into your configure.ac: ++ ++ PKG_CHECK_MODULES([LIBDMMP], [libdmmp]) ++ ++ * Add these lines into your Makefile.am: ++ ++ foo_LDFLAGS += $(LIBDMMP_LIBS) ++ foo_CFLAGS += $(LIBDMMP_CFLAGS) ++ ++.SH LOG HANDLING ++ ++The log handler function could be set via 'dmmp_context_log_func_set()'. ++The log priority could be set via 'dmmp_context_log_priority_set()'. ++ ++By default, the log priorities is 'DMMP_LOG_PRIORITY_WARNING'. ++By default, the log handler is print log to STDERR, and its code is listed ++below in case you want to create your own log handler. ++ ++ static int _DMMP_LOG_STRERR_ALIGN_WIDTH = 80; ++ ++ static void _log_stderr(struct dmmp_context *ctx, ++ enum dmmp_log_priority priority, ++ const char *file, int line, ++ const char *func_name, ++ const char *format, va_list args) ++ { ++ int printed_bytes = 0; ++ ++ printed_bytes += fprintf(stderr, "libdmmp %s: ", ++ dmmp_log_priority_str(priority)); ++ printed_bytes += vfprintf(stderr, format, args); ++ userdata = dmmp_context_userdata_get(ctx); ++ if (userdata != NULL) ++ fprintf(stderr, "(with user data at memory address %p)", ++ userdata); ++ ++ if (printed_bytes < _DMMP_LOG_STRERR_ALIGN_WIDTH) { ++ fprintf(stderr, "%*s # %s:%s():%d\n", ++ _DMMP_LOG_STRERR_ALIGN_WIDTH - printed_bytes, "", file, ++ func_name, line); ++ } else { ++ fprintf(stderr, " # %s:%s():%d\n", file, func_name, line); ++ } ++ } ++ ++ ++.SH "SAMPLE CODE" ++ ++ #include ++ ++ int main(int argc, char *argv[]) { ++ struct dmmp_context *ctx = NULL; ++ struct dmmp_mpath **dmmp_mps = NULL; ++ struct dmmp_path_group **dmmp_pgs = NULL; ++ struct dmmp_path **dmmp_ps = NULL; ++ uint32_t dmmp_mp_count = 0; ++ uint32_t dmmp_pg_count = 0; ++ uint32_t dmmp_p_count = 0; ++ const char *name = NULL; ++ const char *wwid = NULL; ++ uint32_t i = 0; ++ int rc = DMMP_OK; ++ ++ ctx = dmmp_context_new(); ++ dmmp_context_log_priority_set(ctx, DMMP_LOG_PRIORITY_DEBUG); ++ // By default, log will be printed to STDERR, you could ++ // change that via dmmp_context_log_func_set() ++ rc = dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count); ++ if (rc != DMMP_OK) { ++ printf("dmmp_mpath_array_get() failed with %d: %s", rc, ++ dmmp_strerror(rc)); ++ goto out; ++ } ++ for (i = 0; i < dmmp_mp_count; ++i) { ++ name = dmmp_mpath_name_get(dmmp_mps[i]); ++ wwid = dmmp_mpath_wwid_get(dmmp_mps[i]); ++ printf("dmmp_mpath_array_get(): Got mpath: %s %s\n", name, ++ wwid); ++ // You could use dmmp_path_group_array_get() to retrieve ++ // path group information and then invoke dmmp_path_array_get() ++ // for path information. ++ } ++ ++ out: ++ dmmp_context_free(ctx); ++ dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); ++ if (rc != DMMP_OK) ++ exit(1); ++ exit(0); ++ } ++ ++.SH "LICENSE" ++GPLv2+ ++ ++.SH "BUG" ++Please report bug to +Index: multipath-tools-130222/libdmmp/docs/split-man.pl +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/docs/split-man.pl +@@ -0,0 +1,40 @@ ++#!/usr/bin/perl ++# Originally From: ++# https://www.kernel.org/doc/Documentation/kernel-doc-nano-HOWTO.txt ++# ++# Changes: ++# * Create manpage section 3 instead of 9. ++# * Replace 'Kernel Hackers Manual' to ++# 'Device Mapper Multipath API - libdmmp Manual' ++# * Remove LINUX from header. ++# * Remove DMMP_DLL_EXPORT. ++$man_sec_num = 3; ++$title = 'Device Mapper Multipath API - libdmmp Manual'; ++ ++if ( $#ARGV < 0 ) { ++ die "where do I put the results?\n"; ++} ++ ++mkdir $ARGV[0], 0777; ++$state = 0; ++while () { ++ if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) { ++ if ( $state == 1 ) { close OUT } ++ $state = 1; ++ $fn = "$ARGV[0]/$1.$man_sec_num"; ++ print STDERR "Creating $fn\n"; ++ open OUT, ">$fn" or die "can't open $fn: $!\n"; ++ ++ # Change man page code from 9 to $man_sec_num; ++ s/^\.TH (\"[^\"]*\") 9 \"([^\"]*)\"/\.TH $1 $man_sec_num \"$2\"/; ++ s/Kernel Hacker's Manual/$title/g; ++ s/LINUX//g; ++ ++ print OUT $_; ++ } ++ elsif ( $state != 0 ) { ++ print OUT $_; ++ } ++} ++ ++close OUT; +Index: multipath-tools-130222/libdmmp/libdmmp.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp.c +@@ -0,0 +1,285 @@ ++/* ++ * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "libdmmp/libdmmp.h" ++#include "libdmmp_private.h" ++ ++#define _DEFAULT_UXSOCK_TIMEOUT 60000 ++/* ^ 60 seconds. On system with 10k sdX, dmmp_mpath_array_get() ++ * only take 3.5 seconds, so this default value should be OK for most users. ++ */ ++ ++#define _DMMP_IPC_SHOW_JSON_CMD "show maps json" ++#define _DMMP_JSON_MAJOR_KEY "major_version" ++#define _DMMP_JSON_MAJOR_VERSION 0 ++#define _DMMP_JSON_MAPS_KEY "maps" ++#define _ERRNO_STR_BUFF_SIZE 256 ++ ++struct dmmp_context { ++ void (*log_func)(struct dmmp_context *ctx, int priority, ++ const char *file, int line, const char *func_name, ++ const char *format, va_list args); ++ int log_priority; ++ void *userdata; ++ unsigned int tmo; ++}; ++ ++_dmmp_getter_func_gen(dmmp_context_log_priority_get, ++ struct dmmp_context, ctx, log_priority, ++ int); ++ ++_dmmp_getter_func_gen(dmmp_context_userdata_get, struct dmmp_context, ctx, ++ userdata, void *); ++ ++_dmmp_getter_func_gen(dmmp_context_timeout_get, struct dmmp_context, ctx, tmo, ++ unsigned int); ++ ++_dmmp_array_free_func_gen(dmmp_mpath_array_free, struct dmmp_mpath, ++ _dmmp_mpath_free); ++ ++void _dmmp_log(struct dmmp_context *ctx, int priority, const char *file, ++ int line, const char *func_name, const char *format, ...) ++{ ++ va_list args; ++ ++ va_start(args, format); ++ ctx->log_func(ctx, priority, file, line, func_name, format, args); ++ va_end(args); ++} ++ ++struct dmmp_context *dmmp_context_new(void) ++{ ++ struct dmmp_context *ctx = NULL; ++ ++ ctx = (struct dmmp_context *) malloc(sizeof(struct dmmp_context)); ++ ++ if (ctx == NULL) ++ return NULL; ++ ++ ctx->log_func = _dmmp_log_stderr; ++ ctx->log_priority = DMMP_LOG_PRIORITY_DEFAULT; ++ ctx->userdata = NULL; ++ ctx->tmo = _DEFAULT_UXSOCK_TIMEOUT; ++ ++ return ctx; ++} ++ ++void dmmp_context_free(struct dmmp_context *ctx) ++{ ++ free(ctx); ++} ++ ++void dmmp_context_log_priority_set(struct dmmp_context *ctx, int priority) ++{ ++ assert(ctx != NULL); ++ ctx->log_priority = priority; ++} ++ ++void dmmp_context_timeout_set(struct dmmp_context *ctx, unsigned int tmo) ++{ ++ assert(ctx != NULL); ++ ctx->tmo = tmo; ++} ++ ++void dmmp_context_log_func_set ++ (struct dmmp_context *ctx, ++ void (*log_func)(struct dmmp_context *ctx, int priority, ++ const char *file, int line, const char *func_name, ++ const char *format, va_list args)) ++{ ++ assert(ctx != NULL); ++ ctx->log_func = log_func; ++} ++ ++void dmmp_context_userdata_set(struct dmmp_context *ctx, void *userdata) ++{ ++ assert(ctx != NULL); ++ ctx->userdata = userdata; ++} ++ ++int dmmp_mpath_array_get(struct dmmp_context *ctx, ++ struct dmmp_mpath ***dmmp_mps, uint32_t *dmmp_mp_count) ++{ ++ struct dmmp_mpath *dmmp_mp = NULL; ++ int rc = DMMP_OK; ++ char *j_str = NULL; ++ json_object *j_obj = NULL; ++ json_object *j_obj_map = NULL; ++ enum json_tokener_error j_err = json_tokener_success; ++ json_tokener *j_token = NULL; ++ struct array_list *ar_maps = NULL; ++ uint32_t i = 0; ++ int cur_json_major_version = -1; ++ int ar_maps_len = -1; ++ int socket_fd = -1; ++ int errno_save = 0; ++ char errno_str_buff[_ERRNO_STR_BUFF_SIZE]; ++ ++ assert(ctx != NULL); ++ assert(dmmp_mps != NULL); ++ assert(dmmp_mp_count != NULL); ++ ++ *dmmp_mps = NULL; ++ *dmmp_mp_count = 0; ++ ++ socket_fd = mpath_connect(); ++ if (socket_fd == -1) { ++ errno_save = errno; ++ memset(errno_str_buff, 0, _ERRNO_STR_BUFF_SIZE); ++ strerror_r(errno_save, errno_str_buff, _ERRNO_STR_BUFF_SIZE); ++ if (errno_save == ECONNREFUSED) { ++ rc = DMMP_ERR_NO_DAEMON; ++ _error(ctx, "Socket connection refuse. " ++ "Maybe multipathd daemon is not running"); ++ } else { ++ _error(ctx, "IPC failed with error %d(%s)", errno_save, ++ errno_str_buff); ++ rc = DMMP_ERR_IPC_ERROR; ++ } ++ goto out; ++ } ++ ++ if (mpath_process_cmd(socket_fd, _DMMP_IPC_SHOW_JSON_CMD, ++ &j_str, ctx->tmo) != 0) { ++ errno_save = errno; ++ memset(errno_str_buff, 0, _ERRNO_STR_BUFF_SIZE); ++ strerror_r(errno_save, errno_str_buff, _ERRNO_STR_BUFF_SIZE); ++ if (errno_save == ETIMEDOUT) { ++ rc = DMMP_ERR_IPC_TIMEOUT; ++ _error(ctx, "IPC communication timeout, try to " ++ "increase it via dmmp_context_timeout_set()"); ++ goto out; ++ } ++ _error(ctx, "IPC failed when process command '%s' with " ++ "error %d(%s)", _DMMP_IPC_SHOW_JSON_CMD, errno_save, ++ errno_str_buff); ++ rc = DMMP_ERR_IPC_ERROR; ++ goto out; ++ } ++ ++ if ((j_str == NULL) || (strlen(j_str) == 0)) { ++ _error(ctx, "IPC return empty reply for command %s", ++ _DMMP_IPC_SHOW_JSON_CMD); ++ rc = DMMP_ERR_IPC_ERROR; ++ goto out; ++ } ++ ++ _debug(ctx, "Got json output from multipathd: '%s'", j_str); ++ j_token = json_tokener_new(); ++ if (j_token == NULL) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: json_tokener_new() retuned NULL"); ++ goto out; ++ } ++ j_obj = json_tokener_parse_ex(j_token, j_str, strlen(j_str) + 1); ++ ++ if (j_obj == NULL) { ++ rc = DMMP_ERR_IPC_ERROR; ++ j_err = json_tokener_get_error(j_token); ++ _error(ctx, "Failed to parse JSON output from multipathd IPC: " ++ "%s", json_tokener_error_desc(j_err)); ++ goto out; ++ } ++ ++ _json_obj_get_value(ctx, j_obj, cur_json_major_version, ++ _DMMP_JSON_MAJOR_KEY, json_type_int, ++ json_object_get_int, rc, out); ++ ++ if (cur_json_major_version != _DMMP_JSON_MAJOR_VERSION) { ++ rc = DMMP_ERR_INCOMPATIBLE; ++ _error(ctx, "Incompatible multipathd JSON major version %d, " ++ "should be %d", cur_json_major_version, ++ _DMMP_JSON_MAJOR_VERSION); ++ goto out; ++ } ++ _debug(ctx, "multipathd JSON major version(%d) check pass", ++ _DMMP_JSON_MAJOR_VERSION); ++ ++ _json_obj_get_value(ctx, j_obj, ar_maps, _DMMP_JSON_MAPS_KEY, ++ json_type_array, json_object_get_array, rc, out); ++ ++ if (ar_maps == NULL) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: Got NULL map array from " ++ "_json_obj_get_value()"); ++ goto out; ++ } ++ ++ ar_maps_len = array_list_length(ar_maps); ++ if (ar_maps_len < 0) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: Got negative length for ar_maps"); ++ goto out; ++ } ++ else if (ar_maps_len == 0) ++ goto out; ++ else ++ *dmmp_mp_count = ar_maps_len & UINT32_MAX; ++ ++ *dmmp_mps = (struct dmmp_mpath **) ++ malloc(sizeof(struct dmmp_mpath *) * (*dmmp_mp_count)); ++ _dmmp_alloc_null_check(ctx, dmmp_mps, rc, out); ++ for (; i < *dmmp_mp_count; ++i) ++ (*dmmp_mps)[i] = NULL; ++ ++ for (i = 0; i < *dmmp_mp_count; ++i) { ++ j_obj_map = array_list_get_idx(ar_maps, i); ++ if (j_obj_map == NULL) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: array_list_get_idx() return NULL"); ++ goto out; ++ } ++ ++ dmmp_mp = _dmmp_mpath_new(); ++ _dmmp_alloc_null_check(ctx, dmmp_mp, rc, out); ++ (*dmmp_mps)[i] = dmmp_mp; ++ _good(_dmmp_mpath_update(ctx, dmmp_mp, j_obj_map), rc, out); ++ } ++ ++out: ++ if (socket_fd >= 0) ++ mpath_disconnect(socket_fd); ++ free(j_str); ++ if (j_token != NULL) ++ json_tokener_free(j_token); ++ if (j_obj != NULL) ++ json_object_put(j_obj); ++ ++ if (rc != DMMP_OK) { ++ dmmp_mpath_array_free(*dmmp_mps, *dmmp_mp_count); ++ *dmmp_mps = NULL; ++ *dmmp_mp_count = 0; ++ } ++ ++ return rc; ++} +Index: multipath-tools-130222/libdmmp/libdmmp.pc.in +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp.pc.in +@@ -0,0 +1,9 @@ ++includedir=__INCLUDEDIR__ ++libdir=__LIBDIR__ ++ ++Name: libdmmp ++Version: __VERSION__ ++Description: Device mapper multipath management library ++Requires: ++Libs: -L${libdir} -ldmmp ++Cflags: -I${includedir} +Index: multipath-tools-130222/libdmmp/libdmmp/libdmmp.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp/libdmmp.h +@@ -0,0 +1,653 @@ ++/* ++ * Copyright (C) 2015 - 2017 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++ ++#ifndef _LIB_DMMP_H_ ++#define _LIB_DMMP_H_ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define DMMP_DLL_EXPORT __attribute__ ((visibility ("default"))) ++#define DMMP_DLL_LOCAL __attribute__ ((visibility ("hidden"))) ++ ++#define DMMP_OK 0 ++#define DMMP_ERR_BUG 1 ++#define DMMP_ERR_NO_MEMORY 2 ++#define DMMP_ERR_IPC_TIMEOUT 3 ++#define DMMP_ERR_IPC_ERROR 4 ++#define DMMP_ERR_NO_DAEMON 5 ++#define DMMP_ERR_INCOMPATIBLE 6 ++ ++/* ++ * Use the syslog severity level as log priority ++ */ ++#define DMMP_LOG_PRIORITY_ERROR 3 ++#define DMMP_LOG_PRIORITY_WARNING 4 ++#define DMMP_LOG_PRIORITY_INFO 6 ++#define DMMP_LOG_PRIORITY_DEBUG 7 ++ ++#define DMMP_LOG_PRIORITY_DEFAULT DMMP_LOG_PRIORITY_WARNING ++ ++/** ++ * dmmp_log_priority_str() - Convert log priority to string. ++ * ++ * Convert log priority to string (const char *). ++ * ++ * @priority: ++ * int. Log priority. ++ * ++ * Return: ++ * const char *. Valid string are: ++ * ++ * * "ERROR" for DMMP_LOG_PRIORITY_ERROR ++ * ++ * * "WARN " for DMMP_LOG_PRIORITY_WARNING ++ * ++ * * "INFO " for DMMP_LOG_PRIORITY_INFO ++ * ++ * * "DEBUG" for DMMP_LOG_PRIORITY_DEBUG ++ * ++ * * "Invalid argument" for invalid log priority. ++ */ ++DMMP_DLL_EXPORT const char *dmmp_log_priority_str(int priority); ++ ++DMMP_DLL_EXPORT struct dmmp_context; ++ ++DMMP_DLL_EXPORT struct dmmp_mpath; ++ ++DMMP_DLL_EXPORT struct dmmp_path_group; ++ ++#define DMMP_PATH_GROUP_STATUS_UNKNOWN 0 ++#define DMMP_PATH_GROUP_STATUS_ENABLED 1 ++#define DMMP_PATH_GROUP_STATUS_DISABLED 2 ++#define DMMP_PATH_GROUP_STATUS_ACTIVE 3 ++ ++DMMP_DLL_EXPORT struct dmmp_path; ++ ++#define DMMP_PATH_STATUS_UNKNOWN 0 ++//#define DMMP_PATH_STATUS_UNCHECKED 1 ++// ^ print.h does not expose this. ++#define DMMP_PATH_STATUS_DOWN 2 ++#define DMMP_PATH_STATUS_UP 3 ++#define DMMP_PATH_STATUS_SHAKY 4 ++#define DMMP_PATH_STATUS_GHOST 5 ++#define DMMP_PATH_STATUS_PENDING 6 ++#define DMMP_PATH_STATUS_TIMEOUT 7 ++//#define DMMP_PATH_STATUS_REMOVED 8 ++// ^ print.h does not expose this. ++#define DMMP_PATH_STATUS_DELAYED 9 ++ ++/** ++ * dmmp_strerror() - Convert error code to string. ++ * ++ * Convert error code (int) to string (const char *): ++ * ++ * * DMMP_OK -- "OK" ++ * ++ * * DMMP_ERR_BUG -- "BUG of libdmmp library" ++ * ++ * * DMMP_ERR_NO_MEMORY -- "Out of memory" ++ * ++ * * DMMP_ERR_IPC_TIMEOUT -- "Timeout when communicate with multipathd, ++ * try to set bigger timeout value via dmmp_context_timeout_set ()" ++ * ++ * * DMMP_ERR_IPC_ERROR -- "Error when communicate with multipathd daemon" ++ * ++ * * DMMP_ERR_NO_DAEMON -- "The multipathd daemon not started" ++ * ++ * * DMMP_ERR_INCOMPATIBLE -- "The multipathd daemon version is not ++ * compatible with current library" ++ * ++ * * Other invalid error number -- "Invalid argument" ++ * ++ * @rc: ++ * int. Return code by libdmmp functions. When provided error code is not a ++ * valid error code, return "Invalid argument". ++ * ++ * Return: ++ * const char *. The meaning of provided error code. ++ * ++ */ ++DMMP_DLL_EXPORT const char *dmmp_strerror(int rc); ++ ++/** ++ * dmmp_context_new() - Create struct dmmp_context. ++ * ++ * The default logging level (DMMP_LOG_PRIORITY_DEFAULT) is ++ * DMMP_LOG_PRIORITY_WARNING which means only warning and error message will be ++ * forward to log handler function. The default log handler function will print ++ * log message to STDERR, to change so, please use dmmp_context_log_func_set() ++ * to set your own log handler, check manpage libdmmp.h(3) for detail. ++ * ++ * Return: ++ * Pointer of 'struct dmmp_context'. Should be freed by ++ * dmmp_context_free(). ++ */ ++DMMP_DLL_EXPORT struct dmmp_context *dmmp_context_new(void); ++ ++/** ++ * dmmp_context_free() - Release the memory of struct dmmp_context. ++ * ++ * Release the memory of struct dmmp_context, but the userdata memory defined ++ * via dmmp_context_userdata_set() will not be touched. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_context_free(struct dmmp_context *ctx); ++ ++/** ++ * dmmp_context_timeout_set() - Set IPC timeout. ++ * ++ * By default, the IPC to multipathd daemon will timeout after 60 seconds. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * @tmo: ++ * Timeout in milliseconds(1 seconds equal 1000 milliseconds). ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_context_timeout_set(struct dmmp_context *ctx, ++ unsigned int tmo); ++ ++/** ++ * dmmp_context_timeout_get() - Get IPC timeout. ++ * ++ * Retrieve timeout value of IPC connection to multipathd daemon. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * unsigned int. Timeout in milliseconds. ++ */ ++DMMP_DLL_EXPORT unsigned int dmmp_context_timeout_get(struct dmmp_context *ctx); ++ ++/** ++ * dmmp_context_log_priority_set() - Set log priority. ++ * ++ * ++ * When library generates log message, only equal or more important(less value) ++ * message will be forwarded to log handler function. Valid log priority values ++ * are: ++ * ++ * * DMMP_LOG_PRIORITY_ERROR -- 3 ++ * ++ * * DMMP_LOG_PRIORITY_WARNING -- 4 ++ * ++ * * DMMP_LOG_PRIORITY_INFO -- 5 ++ * ++ * * DMMP_LOG_PRIORITY_DEBUG -- 7 ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * @priority: ++ * int, log priority. ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_context_log_priority_set(struct dmmp_context *ctx, ++ int priority); ++ ++/** ++ * dmmp_context_log_priority_get() - Get log priority. ++ * ++ * Retrieve current log priority. Valid log priority values are: ++ * ++ * * DMMP_LOG_PRIORITY_ERROR -- 3 ++ * ++ * * DMMP_LOG_PRIORITY_WARNING -- 4 ++ * ++ * * DMMP_LOG_PRIORITY_INFO -- 5 ++ * ++ * * DMMP_LOG_PRIORITY_DEBUG -- 7 ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * int, log priority. ++ */ ++DMMP_DLL_EXPORT int dmmp_context_log_priority_get(struct dmmp_context *ctx); ++ ++/** ++ * dmmp_context_log_func_set() - Set log handler function. ++ * ++ * Set custom log handler. The log handler will be invoked when log message ++ * is equal or more important(less value) than log priority setting. ++ * Please check manpage libdmmp.h(3) for detail usage. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @log_func: ++ * Pointer of log handler function. ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_context_log_func_set ++ (struct dmmp_context *ctx, ++ void (*log_func) ++ (struct dmmp_context *ctx, int priority, ++ const char *file, int line, const char *func_name, ++ const char *format, va_list args)); ++ ++/** ++ * dmmp_context_userdata_set() - Set user data pointer. ++ * ++ * Store user data pointer into 'struct dmmp_context'. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @userdata: ++ * Pointer of user defined data. ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_context_userdata_set(struct dmmp_context *ctx, ++ void *userdata); ++ ++/** ++ * dmmp_context_userdata_get() - Get user data pointer. ++ * ++ * Retrieve user data pointer from 'struct dmmp_context'. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * void *. Pointer of user defined data. ++ */ ++DMMP_DLL_EXPORT void *dmmp_context_userdata_get(struct dmmp_context *ctx); ++ ++/** ++ * dmmp_mpath_array_get() - Query all existing multipath devices. ++ * ++ * Query all existing multipath devices and store them into a pointer array. ++ * The memory of 'dmmp_mps' should be freed via dmmp_mpath_array_free(). ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @dmmp_mps: ++ * Output pointer array of 'struct dmmp_mpath'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @dmmp_mp_count: ++ * Output pointer of uint32_t. Hold the size of 'dmmp_mps' pointer array. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * int. Valid error codes are: ++ * ++ * * DMMP_OK ++ * ++ * * DMMP_ERR_BUG ++ * ++ * * DMMP_ERR_NO_MEMORY ++ * ++ * * DMMP_ERR_NO_DAEMON ++ * ++ * * DMMP_ERR_INCONSISTENT_DATA ++ * ++ * Error number could be converted to string by dmmp_strerror(). ++ */ ++DMMP_DLL_EXPORT int dmmp_mpath_array_get(struct dmmp_context *ctx, ++ struct dmmp_mpath ***dmmp_mps, ++ uint32_t *dmmp_mp_count); ++ ++/** ++ * dmmp_mpath_array_free() - Free 'struct dmmp_mpath' pointer array. ++ * ++ * Free the 'dmmp_mps' pointer array generated by dmmp_mpath_array_get(). ++ * If provided 'dmmp_mps' pointer is NULL or dmmp_mp_count == 0, do nothing. ++ * ++ * @dmmp_mps: ++ * Pointer of 'struct dmmp_mpath' array. ++ * @dmmp_mp_count: ++ * uint32_t, the size of 'dmmp_mps' pointer array. ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_mpath_array_free(struct dmmp_mpath **dmmp_mps, ++ uint32_t dmmp_mp_count); ++ ++/** ++ * dmmp_mpath_wwid_get() - Retrieve WWID of certain mpath. ++ * ++ * @dmmp_mp: ++ * Pointer of 'struct dmmp_mpath'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * const char *. No need to free this memory, the resources will get ++ * freed when dmmp_mpath_array_free(). ++ */ ++DMMP_DLL_EXPORT const char *dmmp_mpath_wwid_get(struct dmmp_mpath *dmmp_mp); ++ ++/** ++ * dmmp_mpath_name_get() - Retrieve name(alias) of certain mpath. ++ * ++ * Retrieve the name (also known as alias) of certain mpath. ++ * When the config 'user_friendly_names' been set 'no', the name will be ++ * identical to WWID retrieved by dmmp_mpath_wwid_get(). ++ * ++ * @dmmp_mp: ++ * Pointer of 'struct dmmp_mpath'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * const char *. No need to free this memory, the resources will get ++ * freed when dmmp_mpath_array_free(). ++ */ ++DMMP_DLL_EXPORT const char *dmmp_mpath_name_get(struct dmmp_mpath *dmmp_mp); ++ ++/** ++ * dmmp_mpath_kdev_name_get() - Retrieve kernel DEVNAME of certain mpath. ++ * ++ * Retrieve DEVNAME name used by kernel uevent of specified mpath. ++ * Example: 'dm-1'. ++ * ++ * @dmmp_mp: ++ * Pointer of 'struct dmmp_mpath'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * const char *. No need to free this memory, the resources will get ++ * freed when dmmp_mpath_array_free(). ++ */ ++DMMP_DLL_EXPORT const char *dmmp_mpath_kdev_name_get ++ (struct dmmp_mpath *dmmp_mp); ++ ++/** ++ * dmmp_path_group_array_get() - Retrieve path groups pointer array. ++ * ++ * Retrieve the path groups of certain mpath. ++ * ++ * The memory of output pointer array is hold by 'struct dmmp_mpath', no ++ * need to free this memory, the resources will got freed when ++ * dmmp_mpath_array_free(). ++ * ++ * @dmmp_mp: ++ * Pointer of 'struct dmmp_mpath'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @dmmp_pgs: ++ * Output pointer of 'struct dmmp_path_group' pointer array. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @dmmp_pg_count: ++ * Output pointer of uint32_t. Hold the size of 'dmmp_pgs' pointer array. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_path_group_array_get ++ (struct dmmp_mpath *dmmp_mp, struct dmmp_path_group ***dmmp_pgs, ++ uint32_t *dmmp_pg_count); ++ ++/** ++ * dmmp_path_group_id_get() - Retrieve path group ID. ++ * ++ * Retrieve the path group ID which could be used to switch active path group ++ * via command: ++ * ++ * multipathd -k'switch multipath mpathb group $id' ++ * ++ * @dmmp_pg: ++ * Pointer of 'struct dmmp_path_group'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * uint32_t. ++ */ ++DMMP_DLL_EXPORT uint32_t dmmp_path_group_id_get ++ (struct dmmp_path_group *dmmp_pg); ++ ++/** ++ * dmmp_path_group_priority_get() - Retrieve path group priority. ++ * ++ * The enabled path group with highest priority will be next active path group ++ * if active path group down. ++ * ++ * @dmmp_pg: ++ * Pointer of 'struct dmmp_path_group'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * uint32_t. ++ */ ++DMMP_DLL_EXPORT uint32_t dmmp_path_group_priority_get ++ (struct dmmp_path_group *dmmp_pg); ++ ++/** ++ * dmmp_path_group_status_get() - Retrieve path group status. ++ * ++ * The valid path group statuses are: ++ * ++ * * DMMP_PATH_GROUP_STATUS_UNKNOWN ++ * ++ * * DMMP_PATH_GROUP_STATUS_ENABLED -- standby to be active ++ * ++ * * DMMP_PATH_GROUP_STATUS_DISABLED -- disabled due to all path down ++ * ++ * * DMMP_PATH_GROUP_STATUS_ACTIVE -- selected to handle I/O ++ * ++ * @dmmp_pg: ++ * Pointer of 'struct dmmp_path_group'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * uint32_t. ++ */ ++DMMP_DLL_EXPORT uint32_t dmmp_path_group_status_get ++ (struct dmmp_path_group *dmmp_pg); ++ ++/** ++ * dmmp_path_group_status_str() - Convert path group status to string. ++ * ++ * Convert path group status uint32_t to string (const char *). ++ * ++ * @pg_status: ++ * uint32_t. Path group status. ++ * When provided value is not a valid path group status, return "Invalid ++ * argument". ++ * ++ * Return: ++ * const char *. Valid string are: ++ * ++ * * "Invalid argument" ++ * ++ * * "undef" ++ * ++ * * "enabled" ++ * ++ * * "disabled" ++ * ++ * * "active" ++ */ ++DMMP_DLL_EXPORT const char *dmmp_path_group_status_str(uint32_t pg_status); ++ ++/** ++ * dmmp_path_group_selector_get() - Retrieve path group selector. ++ * ++ * Path group selector determine which path in active path group will be ++ * use to next I/O. ++ * ++ * @dmmp_pg: ++ * Pointer of 'struct dmmp_path_group'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * const char *. ++ */ ++DMMP_DLL_EXPORT const char *dmmp_path_group_selector_get ++ (struct dmmp_path_group *dmmp_pg); ++ ++/** ++ * dmmp_path_array_get() - Retrieve path pointer array. ++ * ++ * The memory of output pointer array is hold by 'struct dmmp_mpath', no ++ * need to free this memory, the resources will got freed when ++ * dmmp_mpath_array_free(). ++ * ++ * @dmmp_pg: ++ * Pointer of 'struct dmmp_path_group'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @dmmp_ps: ++ * Output pointer of 'struct dmmp_path' pointer array. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @dmmp_p_count: ++ * Output pointer of uint32_t. Hold the size of 'dmmp_ps' pointer array. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * void ++ */ ++DMMP_DLL_EXPORT void dmmp_path_array_get(struct dmmp_path_group *dmmp_pg, ++ struct dmmp_path ***dmmp_ps, ++ uint32_t *dmmp_p_count); ++ ++/** ++ * dmmp_path_blk_name_get() - Retrieve block name. ++ * ++ * Retrieve block name of certain path. The example of block names are 'sda', ++ * 'nvme0n1'. ++ * ++ * @dmmp_p: ++ * Pointer of 'struct dmmp_path'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * const char *. No need to free this memory, the resources will get ++ * freed when dmmp_mpath_array_free(). ++ */ ++DMMP_DLL_EXPORT const char *dmmp_path_blk_name_get(struct dmmp_path *dmmp_p); ++ ++/** ++ * dmmp_path_status_get() - Retrieve the path status. ++ * ++ * The valid path statuses are: ++ * ++ * * DMMP_PATH_STATUS_UNKNOWN ++ * ++ * * DMMP_PATH_STATUS_DOWN ++ * ++ * Path is down and you shouldn't try to send commands to it. ++ * ++ * * DMMP_PATH_STATUS_UP ++ * ++ * Path is up and I/O can be sent to it. ++ * ++ * * DMMP_PATH_STATUS_SHAKY ++ * ++ * Only emc_clariion checker when path not available for "normal" ++ * operations. ++ * ++ * * DMMP_PATH_STATUS_GHOST ++ * ++ * Only hp_sw and rdac checkers. Indicates a "passive/standby" ++ * path on active/passive HP arrays. These paths will return valid ++ * answers to certain SCSI commands (tur, read_capacity, inquiry, ++ * start_stop), but will fail I/O commands. The path needs an ++ * initialization command to be sent to it in order for I/Os to ++ * succeed. ++ * ++ * * DMMP_PATH_STATUS_PENDING ++ * ++ * Available for all async checkers when a check IO is in flight. ++ * ++ * * DMMP_PATH_STATUS_TIMEOUT ++ * ++ * Only tur checker when command timed out. ++ * ++ * * DMMP_PATH_STATUS_DELAYED ++ * ++ * If a path fails after being up for less than delay_watch_checks checks, ++ * when it comes back up again, it will not be marked as up until it has ++ * been up for delay_wait_checks checks. During this time, it is marked as ++ * "delayed". ++ * ++ * @dmmp_p: ++ * Pointer of 'struct dmmp_path'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * uint32_t. ++ */ ++DMMP_DLL_EXPORT uint32_t dmmp_path_status_get(struct dmmp_path *dmmp_p); ++ ++/** ++ * dmmp_path_status_str() - Convert path status to string. ++ * ++ * Convert path status uint32_t to string (const char *): ++ * ++ * * DMMP_PATH_STATUS_UNKNOWN -- "undef" ++ * ++ * * DMMP_PATH_STATUS_DOWN -- "faulty" ++ * ++ * * DMMP_PATH_STATUS_UP -- "ready" ++ * ++ * * DMMP_PATH_STATUS_SHAKY -- "shaky" ++ * ++ * * DMMP_PATH_STATUS_GHOST -- "ghost" ++ * ++ * * DMMP_PATH_STATUS_PENDING -- "pending" ++ * ++ * * DMMP_PATH_STATUS_TIMEOUT -- "timeout" ++ * ++ * * DMMP_PATH_STATUS_REMOVED -- "removed" ++ * ++ * * DMMP_PATH_STATUS_DELAYED -- "delayed" ++ * ++ * @path_status: ++ * uint32_t. Path status. ++ * When provided value is not a valid path status, return ++ * "Invalid argument". ++ * ++ * Return: ++ * const char *. The meaning of status value. ++ */ ++DMMP_DLL_EXPORT const char *dmmp_path_status_str(uint32_t path_status); ++ ++#ifdef __cplusplus ++} /* End of extern "C" */ ++#endif ++ ++#endif /* End of _LIB_DMMP_H_ */ +Index: multipath-tools-130222/libdmmp/libdmmp_misc.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp_misc.c +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "libdmmp/libdmmp.h" ++#include "libdmmp_private.h" ++ ++#define _DMMP_LOG_STRERR_ALIGN_WIDTH 80 ++/* ^ Only used in _dmmp_log_stderr() for pretty log output. ++ * When provided log message is less than 80 bytes, fill it with space, then ++ * print code file name, function name, line after the 80th bytes. ++ */ ++ ++static const struct _num_str_conv _DMMP_RC_MSG_CONV[] = { ++ {DMMP_OK, "OK"}, ++ {DMMP_ERR_NO_MEMORY, "Out of memory"}, ++ {DMMP_ERR_BUG, "BUG of libdmmp library"}, ++ {DMMP_ERR_IPC_TIMEOUT, "Timeout when communicate with multipathd, " ++ "try to increase it via " ++ "dmmp_context_timeout_set()"}, ++ {DMMP_ERR_IPC_ERROR, "Error when communicate with multipathd daemon"}, ++ {DMMP_ERR_NO_DAEMON, "The multipathd daemon not started"}, ++ {DMMP_ERR_INCOMPATIBLE, "Incompatible multipathd daemon version"}, ++}; ++ ++_dmmp_str_func_gen(dmmp_strerror, int, rc, _DMMP_RC_MSG_CONV); ++ ++static const struct _num_str_conv _DMMP_PRI_CONV[] = { ++ {DMMP_LOG_PRIORITY_DEBUG, "DEBUG"}, ++ {DMMP_LOG_PRIORITY_INFO, "INFO"}, ++ {DMMP_LOG_PRIORITY_WARNING, "WARNING"}, ++ {DMMP_LOG_PRIORITY_ERROR, "ERROR"}, ++}; ++_dmmp_str_func_gen(dmmp_log_priority_str, int, priority, _DMMP_PRI_CONV); ++ ++void _dmmp_log_stderr(struct dmmp_context *ctx, int priority, ++ const char *file, int line, const char *func_name, ++ const char *format, va_list args) ++{ ++ int printed_bytes = 0; ++ void *userdata = NULL; ++ ++ printed_bytes += fprintf(stderr, "libdmmp %s: ", ++ dmmp_log_priority_str(priority)); ++ printed_bytes += vfprintf(stderr, format, args); ++ ++ userdata = dmmp_context_userdata_get(ctx); ++ if (userdata != NULL) ++ fprintf(stderr, "(userdata address: %p)", ++ userdata); ++ /* ^ Just demonstrate how userdata could be used and ++ * bypass clang static analyzer about unused ctx argument warning ++ */ ++ ++ if (printed_bytes < _DMMP_LOG_STRERR_ALIGN_WIDTH) { ++ fprintf(stderr, "%*s # %s:%s():%d\n", ++ _DMMP_LOG_STRERR_ALIGN_WIDTH - printed_bytes, "", file, ++ func_name, line); ++ } else { ++ fprintf(stderr, " # %s:%s():%d\n", file, func_name, line); ++ } ++} +Index: multipath-tools-130222/libdmmp/libdmmp_mp.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp_mp.c +@@ -0,0 +1,159 @@ ++/* ++ * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "libdmmp/libdmmp.h" ++#include "libdmmp_private.h" ++ ++struct dmmp_mpath { ++ char *wwid; ++ char *alias; ++ uint32_t dmmp_pg_count; ++ struct dmmp_path_group **dmmp_pgs; ++ char *kdev_name; ++}; ++ ++_dmmp_getter_func_gen(dmmp_mpath_name_get, struct dmmp_mpath, dmmp_mp, ++ alias, const char *); ++_dmmp_getter_func_gen(dmmp_mpath_wwid_get, struct dmmp_mpath, dmmp_mp, ++ wwid, const char *); ++_dmmp_getter_func_gen(dmmp_mpath_kdev_name_get, struct dmmp_mpath, dmmp_mp, ++ kdev_name, const char *); ++ ++struct dmmp_mpath *_dmmp_mpath_new(void) ++{ ++ struct dmmp_mpath *dmmp_mp = NULL; ++ ++ dmmp_mp = (struct dmmp_mpath *) malloc(sizeof(struct dmmp_mpath)); ++ ++ if (dmmp_mp != NULL) { ++ dmmp_mp->wwid = NULL; ++ dmmp_mp->alias = NULL; ++ dmmp_mp->dmmp_pg_count = 0; ++ dmmp_mp->dmmp_pgs = NULL; ++ } ++ return dmmp_mp; ++} ++ ++int _dmmp_mpath_update(struct dmmp_context *ctx, struct dmmp_mpath *dmmp_mp, ++ json_object *j_obj_map) ++{ ++ int rc = DMMP_OK; ++ const char *wwid = NULL; ++ const char *alias = NULL; ++ struct array_list *ar_pgs = NULL; ++ int ar_pgs_len = -1; ++ uint32_t i = 0; ++ struct dmmp_path_group *dmmp_pg = NULL; ++ const char *kdev_name = NULL; ++ ++ assert(ctx != NULL); ++ assert(dmmp_mp != NULL); ++ assert(j_obj_map != NULL); ++ ++ _json_obj_get_value(ctx, j_obj_map, wwid, "uuid", json_type_string, ++ json_object_get_string, rc, out); ++ _json_obj_get_value(ctx, j_obj_map, alias, "name", json_type_string, ++ json_object_get_string, rc, out); ++ _json_obj_get_value(ctx, j_obj_map, kdev_name, "sysfs", ++ json_type_string, json_object_get_string, rc, out); ++ ++ _dmmp_null_or_empty_str_check(ctx, wwid, rc, out); ++ _dmmp_null_or_empty_str_check(ctx, alias, rc, out); ++ ++ dmmp_mp->wwid = strdup(wwid); ++ _dmmp_alloc_null_check(ctx, dmmp_mp->wwid, rc, out); ++ dmmp_mp->alias = strdup(alias); ++ _dmmp_alloc_null_check(ctx, dmmp_mp->alias, rc, out); ++ dmmp_mp->kdev_name = strdup(kdev_name); ++ _dmmp_alloc_null_check(ctx, dmmp_mp->kdev_name, rc, out); ++ ++ _json_obj_get_value(ctx, j_obj_map, ar_pgs, "path_groups", ++ json_type_array, json_object_get_array, rc, out); ++ ar_pgs_len = array_list_length(ar_pgs); ++ if (ar_pgs_len < 0) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: Got negative length for ar_pgs"); ++ goto out; ++ } ++ else if (ar_pgs_len == 0) ++ goto out; ++ else ++ dmmp_mp->dmmp_pg_count = ar_pgs_len & UINT32_MAX; ++ ++ dmmp_mp->dmmp_pgs = (struct dmmp_path_group **) ++ malloc(sizeof(struct dmmp_path_group *) * ++ dmmp_mp->dmmp_pg_count); ++ _dmmp_alloc_null_check(ctx, dmmp_mp->dmmp_pgs, rc, out); ++ for (; i < dmmp_mp->dmmp_pg_count; ++i) ++ dmmp_mp->dmmp_pgs[i] = NULL; ++ ++ for (i = 0; i < dmmp_mp->dmmp_pg_count; ++i) { ++ dmmp_pg = _dmmp_path_group_new(); ++ _dmmp_alloc_null_check(ctx, dmmp_pg, rc, out); ++ dmmp_mp->dmmp_pgs[i] = dmmp_pg; ++ _good(_dmmp_path_group_update(ctx, dmmp_pg, ++ array_list_get_idx(ar_pgs, i)), ++ rc, out); ++ } ++ ++ _debug(ctx, "Got mpath wwid: '%s', alias: '%s'", dmmp_mp->wwid, ++ dmmp_mp->alias); ++ ++out: ++ if (rc != DMMP_OK) ++ _dmmp_mpath_free(dmmp_mp); ++ return rc; ++} ++ ++void _dmmp_mpath_free(struct dmmp_mpath *dmmp_mp) ++{ ++ if (dmmp_mp == NULL) ++ return ; ++ ++ free((char *) dmmp_mp->alias); ++ free((char *) dmmp_mp->wwid); ++ free((char *) dmmp_mp->kdev_name); ++ ++ if (dmmp_mp->dmmp_pgs != NULL) ++ _dmmp_path_group_array_free(dmmp_mp->dmmp_pgs, ++ dmmp_mp->dmmp_pg_count); ++ ++ free(dmmp_mp); ++} ++ ++void dmmp_path_group_array_get(struct dmmp_mpath *dmmp_mp, ++ struct dmmp_path_group ***dmmp_pgs, ++ uint32_t *dmmp_pg_count) ++{ ++ assert(dmmp_mp != NULL); ++ assert(dmmp_pgs != NULL); ++ assert(dmmp_pg_count != NULL); ++ ++ *dmmp_pgs = dmmp_mp->dmmp_pgs; ++ *dmmp_pg_count = dmmp_mp->dmmp_pg_count; ++} +Index: multipath-tools-130222/libdmmp/libdmmp_path.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp_path.c +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "libdmmp/libdmmp.h" ++#include "libdmmp_private.h" ++ ++#define _DMMP_SHOW_PS_INDEX_BLK_NAME 0 ++#define _DMMP_SHOW_PS_INDEX_SATAUS 1 ++#define _DMMP_SHOW_PS_INDEX_WWID 2 ++#define _DMMP_SHOW_PS_INDEX_PGID 3 ++ ++struct dmmp_path { ++ char *blk_name; ++ uint32_t status; ++}; ++ ++static const struct _num_str_conv _DMMP_PATH_STATUS_CONV[] = { ++ {DMMP_PATH_STATUS_UNKNOWN, "undef"}, ++ {DMMP_PATH_STATUS_UP, "ready"}, ++ {DMMP_PATH_STATUS_DOWN, "faulty"}, ++ {DMMP_PATH_STATUS_SHAKY, "shaky"}, ++ {DMMP_PATH_STATUS_GHOST, "ghost"}, ++ {DMMP_PATH_STATUS_PENDING, "i/o pending"}, ++ {DMMP_PATH_STATUS_TIMEOUT, "i/o timeout"}, ++ {DMMP_PATH_STATUS_DELAYED, "delayed"}, ++}; ++ ++_dmmp_str_func_gen(dmmp_path_status_str, uint32_t, path_status, ++ _DMMP_PATH_STATUS_CONV); ++_dmmp_str_conv_func_gen(_dmmp_path_status_str_conv, ctx, path_status_str, ++ uint32_t, DMMP_PATH_STATUS_UNKNOWN, ++ _DMMP_PATH_STATUS_CONV); ++ ++_dmmp_getter_func_gen(dmmp_path_blk_name_get, struct dmmp_path, dmmp_p, ++ blk_name, const char *); ++_dmmp_getter_func_gen(dmmp_path_status_get, struct dmmp_path, dmmp_p, ++ status, uint32_t); ++ ++struct dmmp_path *_dmmp_path_new(void) ++{ ++ struct dmmp_path *dmmp_p = NULL; ++ ++ dmmp_p = (struct dmmp_path *) malloc(sizeof(struct dmmp_path)); ++ ++ if (dmmp_p != NULL) { ++ dmmp_p->blk_name = NULL; ++ dmmp_p->status = DMMP_PATH_STATUS_UNKNOWN; ++ } ++ return dmmp_p; ++} ++ ++int _dmmp_path_update(struct dmmp_context *ctx, struct dmmp_path *dmmp_p, ++ json_object *j_obj_p) ++{ ++ int rc = DMMP_OK; ++ const char *blk_name = NULL; ++ const char *status_str = NULL; ++ ++ assert(ctx != NULL); ++ assert(dmmp_p != NULL); ++ assert(j_obj_p != NULL); ++ ++ _json_obj_get_value(ctx, j_obj_p, blk_name, "dev", ++ json_type_string, json_object_get_string, rc, out); ++ _json_obj_get_value(ctx, j_obj_p, status_str, "chk_st", ++ json_type_string, json_object_get_string, rc, out); ++ ++ _dmmp_null_or_empty_str_check(ctx, blk_name, rc, out); ++ _dmmp_null_or_empty_str_check(ctx, status_str, rc, out); ++ ++ dmmp_p->blk_name = strdup(blk_name); ++ _dmmp_alloc_null_check(ctx, dmmp_p->blk_name, rc, out); ++ ++ dmmp_p->status = _dmmp_path_status_str_conv(ctx, status_str); ++ ++ _debug(ctx, "Got path blk_name: '%s'", dmmp_p->blk_name); ++ _debug(ctx, "Got path status: %s(%" PRIu32 ")", ++ dmmp_path_status_str(dmmp_p->status), dmmp_p->status); ++ ++out: ++ if (rc != DMMP_OK) ++ _dmmp_path_free(dmmp_p); ++ return rc; ++} ++ ++void _dmmp_path_free(struct dmmp_path *dmmp_p) ++{ ++ if (dmmp_p == NULL) ++ return; ++ free(dmmp_p->blk_name); ++ free(dmmp_p); ++} +Index: multipath-tools-130222/libdmmp/libdmmp_pg.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp_pg.c +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "libdmmp/libdmmp.h" ++#include "libdmmp_private.h" ++ ++#define _DMMP_SHOW_PGS_CMD "show groups raw format %w|%g|%p|%t|%s" ++#define _DMMP_SHOW_PG_INDEX_WWID 0 ++#define _DMMP_SHOW_PG_INDEX_PG_ID 1 ++#define _DMMP_SHOW_PG_INDEX_PRI 2 ++#define _DMMP_SHOW_PG_INDEX_STATUS 3 ++#define _DMMP_SHOW_PG_INDEX_SELECTOR 4 ++ ++struct dmmp_path_group { ++ uint32_t id; ++ /* ^ pgindex of struct path, will be used for path group switch */ ++ uint32_t status; ++ uint32_t priority; ++ char *selector; ++ uint32_t dmmp_p_count; ++ struct dmmp_path **dmmp_ps; ++}; ++ ++static const struct _num_str_conv _DMMP_PATH_GROUP_STATUS_CONV[] = { ++ {DMMP_PATH_GROUP_STATUS_UNKNOWN, "undef"}, ++ {DMMP_PATH_GROUP_STATUS_ACTIVE, "active"}, ++ {DMMP_PATH_GROUP_STATUS_DISABLED, "disabled"}, ++ {DMMP_PATH_GROUP_STATUS_ENABLED, "enabled"}, ++}; ++ ++_dmmp_str_func_gen(dmmp_path_group_status_str, uint32_t, pg_status, ++ _DMMP_PATH_GROUP_STATUS_CONV); ++_dmmp_str_conv_func_gen(_dmmp_path_group_status_str_conv, ctx, pg_status_str, ++ uint32_t, DMMP_PATH_GROUP_STATUS_UNKNOWN, ++ _DMMP_PATH_GROUP_STATUS_CONV); ++ ++_dmmp_getter_func_gen(dmmp_path_group_id_get, struct dmmp_path_group, dmmp_pg, ++ id, uint32_t); ++_dmmp_getter_func_gen(dmmp_path_group_status_get, struct dmmp_path_group, ++ dmmp_pg, status, uint32_t); ++_dmmp_getter_func_gen(dmmp_path_group_priority_get, struct dmmp_path_group, ++ dmmp_pg, priority, uint32_t); ++_dmmp_getter_func_gen(dmmp_path_group_selector_get, struct dmmp_path_group, ++ dmmp_pg, selector, const char *); ++_dmmp_array_free_func_gen(_dmmp_path_group_array_free, struct dmmp_path_group, ++ _dmmp_path_group_free); ++ ++ ++struct dmmp_path_group *_dmmp_path_group_new(void) ++{ ++ struct dmmp_path_group *dmmp_pg = NULL; ++ ++ dmmp_pg = (struct dmmp_path_group *) ++ malloc(sizeof(struct dmmp_path_group)); ++ ++ if (dmmp_pg != NULL) { ++ dmmp_pg->id = _DMMP_PATH_GROUP_ID_UNKNOWN; ++ dmmp_pg->status = DMMP_PATH_GROUP_STATUS_UNKNOWN; ++ dmmp_pg->priority = 0; ++ dmmp_pg->selector = NULL; ++ dmmp_pg->dmmp_p_count = 0; ++ dmmp_pg->dmmp_ps = NULL; ++ } ++ return dmmp_pg; ++} ++int _dmmp_path_group_update(struct dmmp_context *ctx, ++ struct dmmp_path_group *dmmp_pg, ++ json_object *j_obj_pg) ++{ ++ int rc = DMMP_OK; ++ uint32_t id = 0; ++ int priority_int = -1 ; ++ const char *status_str = NULL; ++ const char *selector = NULL; ++ struct array_list *ar_ps = NULL; ++ int ar_ps_len = -1; ++ uint32_t i = 0; ++ struct dmmp_path *dmmp_p = NULL; ++ ++ assert(ctx != NULL); ++ assert(dmmp_pg != NULL); ++ assert(j_obj_pg != NULL); ++ ++ _json_obj_get_value(ctx, j_obj_pg, status_str, "dm_st", ++ json_type_string, json_object_get_string, rc, out); ++ ++ _json_obj_get_value(ctx, j_obj_pg, selector, "selector", ++ json_type_string, json_object_get_string, rc, out); ++ ++ _json_obj_get_value(ctx, j_obj_pg, priority_int, "pri", ++ json_type_int, json_object_get_int, rc, out); ++ ++ _json_obj_get_value(ctx, j_obj_pg, id, "group", ++ json_type_int, json_object_get_int, rc, out); ++ ++ dmmp_pg->priority = (priority_int <= 0) ? 0 : priority_int & UINT32_MAX; ++ ++ _dmmp_null_or_empty_str_check(ctx, status_str, rc, out); ++ _dmmp_null_or_empty_str_check(ctx, selector, rc, out); ++ ++ dmmp_pg->selector = strdup(selector); ++ _dmmp_alloc_null_check(ctx, dmmp_pg->selector, rc, out); ++ ++ dmmp_pg->id = id; ++ ++ if (dmmp_pg->id == _DMMP_PATH_GROUP_ID_UNKNOWN) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: Got unknown(%d) path group ID", ++ _DMMP_PATH_GROUP_ID_UNKNOWN); ++ goto out; ++ } ++ ++ dmmp_pg->status = _dmmp_path_group_status_str_conv(ctx, status_str); ++ ++ _json_obj_get_value(ctx, j_obj_pg, ar_ps, "paths", ++ json_type_array, json_object_get_array, rc, out); ++ ++ ar_ps_len = array_list_length(ar_ps); ++ if (ar_ps_len < 0) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "BUG: Got negative length for ar_ps"); ++ goto out; ++ } ++ else if (ar_ps_len == 0) ++ goto out; ++ else ++ dmmp_pg->dmmp_p_count = ar_ps_len & UINT32_MAX; ++ ++ dmmp_pg->dmmp_ps = (struct dmmp_path **) ++ malloc(sizeof(struct dmmp_path *) * dmmp_pg->dmmp_p_count); ++ _dmmp_alloc_null_check(ctx, dmmp_pg->dmmp_ps, rc, out); ++ for (; i < dmmp_pg->dmmp_p_count; ++i) ++ dmmp_pg->dmmp_ps[i] = NULL; ++ ++ for (i = 0; i < dmmp_pg->dmmp_p_count; ++i) { ++ dmmp_p = _dmmp_path_new(); ++ _dmmp_alloc_null_check(ctx, dmmp_p, rc, out); ++ dmmp_pg->dmmp_ps[i] = dmmp_p; ++ _good(_dmmp_path_update(ctx, dmmp_p, ++ array_list_get_idx(ar_ps, i)), ++ rc, out); ++ } ++ ++ _debug(ctx, "Got path group id: %" PRIu32 "", dmmp_pg->id); ++ _debug(ctx, "Got path group priority: %" PRIu32 "", dmmp_pg->priority); ++ _debug(ctx, "Got path group status: %s(%" PRIu32 ")", ++ dmmp_path_group_status_str(dmmp_pg->status), dmmp_pg->status); ++ _debug(ctx, "Got path group selector: '%s'", dmmp_pg->selector); ++ ++out: ++ if (rc != DMMP_OK) ++ _dmmp_path_group_free(dmmp_pg); ++ return rc; ++} ++ ++void _dmmp_path_group_free(struct dmmp_path_group *dmmp_pg) ++{ ++ uint32_t i = 0; ++ ++ if (dmmp_pg == NULL) ++ return; ++ ++ free((char *) dmmp_pg->selector); ++ ++ if (dmmp_pg->dmmp_ps != NULL) { ++ for (i = 0; i < dmmp_pg->dmmp_p_count; ++i) { ++ _dmmp_path_free(dmmp_pg->dmmp_ps[i]); ++ } ++ free(dmmp_pg->dmmp_ps); ++ } ++ free(dmmp_pg); ++} ++ ++void dmmp_path_array_get(struct dmmp_path_group *mp_pg, ++ struct dmmp_path ***mp_paths, ++ uint32_t *dmmp_p_count) ++{ ++ assert(mp_pg != NULL); ++ assert(mp_paths != NULL); ++ assert(dmmp_p_count != NULL); ++ ++ *mp_paths = mp_pg->dmmp_ps; ++ *dmmp_p_count = mp_pg->dmmp_p_count; ++} +Index: multipath-tools-130222/libdmmp/libdmmp_private.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/libdmmp_private.h +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ * Todd Gill ++ */ ++ ++#ifndef _LIB_DMMP_PRIVATE_H_ ++#define _LIB_DMMP_PRIVATE_H_ ++ ++/* ++ * Notes: ++ * Internal/Private functions does not check input argument but using ++ * assert() to abort if NULL pointer found in argument. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "libdmmp/libdmmp.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define _good(rc, rc_val, out) \ ++ do { \ ++ rc_val = rc; \ ++ if (rc_val != DMMP_OK) \ ++ goto out; \ ++ } while(0) ++ ++#define _DMMP_PATH_GROUP_ID_UNKNOWN 0 ++ ++DMMP_DLL_LOCAL struct _num_str_conv { ++ const uint32_t value; ++ const char *str; ++}; ++ ++#define _dmmp_str_func_gen(func_name, var_type, var, conv_array) \ ++const char *func_name(var_type var) { \ ++ size_t i = 0; \ ++ uint32_t tmp_var = var & UINT32_MAX; \ ++ /* In the whole libdmmp, we don't have negative value */ \ ++ for (; i < sizeof(conv_array)/sizeof(conv_array[0]); ++i) { \ ++ if ((conv_array[i].value) == tmp_var) \ ++ return conv_array[i].str; \ ++ } \ ++ return "Invalid argument"; \ ++} ++ ++#define _dmmp_str_conv_func_gen(func_name, ctx, var_name, out_type, \ ++ unknown_value, conv_array) \ ++static out_type func_name(struct dmmp_context *ctx, const char *var_name) { \ ++ size_t i = 0; \ ++ for (; i < sizeof(conv_array)/sizeof(conv_array[0]); ++i) { \ ++ if (strcmp(conv_array[i].str, var_name) == 0) \ ++ return conv_array[i].value; \ ++ } \ ++ _warn(ctx, "Got unknown " #var_name ": '%s'", var_name); \ ++ return unknown_value; \ ++} ++ ++#define _json_obj_get_value(ctx, j_obj, out_value, key, value_type, \ ++ value_func, rc, out) \ ++do { \ ++ json_type j_type = json_type_null; \ ++ json_object *j_obj_tmp = NULL; \ ++ if (json_object_object_get_ex(j_obj, key, &j_obj_tmp) != TRUE) { \ ++ _error(ctx, "Invalid JSON output from multipathd IPC: " \ ++ "key '%s' not found", key); \ ++ rc = DMMP_ERR_IPC_ERROR; \ ++ goto out; \ ++ } \ ++ if (j_obj_tmp == NULL) { \ ++ _error(ctx, "BUG: Got NULL j_obj_tmp from " \ ++ "json_object_object_get_ex() while it return TRUE"); \ ++ rc = DMMP_ERR_BUG; \ ++ goto out; \ ++ } \ ++ j_type = json_object_get_type(j_obj_tmp); \ ++ if (j_type != value_type) { \ ++ _error(ctx, "Invalid value type for key'%s' of JSON output " \ ++ "from multipathd IPC. Should be %s(%d), " \ ++ "but got %s(%d)", key, json_type_to_name(value_type), \ ++ value_type, json_type_to_name(j_type), j_type); \ ++ rc = DMMP_ERR_IPC_ERROR; \ ++ goto out; \ ++ } \ ++ out_value = value_func(j_obj_tmp); \ ++} while(0); ++ ++DMMP_DLL_LOCAL int _dmmp_ipc_exec(struct dmmp_context *ctx, const char *cmd, ++ char **output); ++ ++DMMP_DLL_LOCAL struct dmmp_mpath *_dmmp_mpath_new(void); ++DMMP_DLL_LOCAL struct dmmp_path_group *_dmmp_path_group_new(void); ++DMMP_DLL_LOCAL struct dmmp_path *_dmmp_path_new(void); ++ ++DMMP_DLL_LOCAL int _dmmp_mpath_update(struct dmmp_context *ctx, ++ struct dmmp_mpath *dmmp_mp, ++ json_object *j_obj_map); ++DMMP_DLL_LOCAL int _dmmp_path_group_update(struct dmmp_context *ctx, ++ struct dmmp_path_group *dmmp_pg, ++ json_object *j_obj_pg); ++DMMP_DLL_LOCAL int _dmmp_path_update(struct dmmp_context *ctx, ++ struct dmmp_path *dmmp_p, ++ json_object *j_obj_p); ++ ++DMMP_DLL_LOCAL void _dmmp_mpath_free(struct dmmp_mpath *dmmp_mp); ++DMMP_DLL_LOCAL void _dmmp_path_group_free(struct dmmp_path_group *dmmp_pg); ++DMMP_DLL_LOCAL void _dmmp_path_group_array_free ++ (struct dmmp_path_group **dmmp_pgs, uint32_t dmmp_pg_count); ++DMMP_DLL_LOCAL void _dmmp_path_free(struct dmmp_path *dmmp_p); ++DMMP_DLL_LOCAL void _dmmp_log(struct dmmp_context *ctx, int priority, ++ const char *file, int line, ++ const char *func_name, ++ const char *format, ...); ++DMMP_DLL_LOCAL void _dmmp_log_err_str(struct dmmp_context *ctx, int rc); ++ ++DMMP_DLL_LOCAL void _dmmp_log_stderr(struct dmmp_context *ctx, int priority, ++ const char *file, int line, ++ const char *func_name, const char *format, ++ va_list args); ++ ++ ++#define _dmmp_log_cond(ctx, prio, arg...) \ ++ do { \ ++ if (dmmp_context_log_priority_get(ctx) >= prio) \ ++ _dmmp_log(ctx, prio, __FILE__, __LINE__, __FUNCTION__, \ ++ ## arg); \ ++ } while (0) ++ ++#define _debug(ctx, arg...) \ ++ _dmmp_log_cond(ctx, DMMP_LOG_PRIORITY_DEBUG, ## arg) ++#define _info(ctx, arg...) \ ++ _dmmp_log_cond(ctx, DMMP_LOG_PRIORITY_INFO, ## arg) ++#define _warn(ctx, arg...) \ ++ _dmmp_log_cond(ctx, DMMP_LOG_PRIORITY_WARNING, ## arg) ++#define _error(ctx, arg...) \ ++ _dmmp_log_cond(ctx, DMMP_LOG_PRIORITY_ERROR, ## arg) ++ ++/* ++ * Check pointer returned by malloc() or strdup(), if NULL, set ++ * rc as DMMP_ERR_NO_MEMORY, report error and goto goto_out. ++ */ ++#define _dmmp_alloc_null_check(ctx, ptr, rc, goto_out) \ ++ do { \ ++ if (ptr == NULL) { \ ++ rc = DMMP_ERR_NO_MEMORY; \ ++ _error(ctx, dmmp_strerror(rc)); \ ++ goto goto_out; \ ++ } \ ++ } while(0) ++ ++#define _dmmp_null_or_empty_str_check(ctx, var, rc, goto_out) \ ++ do { \ ++ if (var == NULL) { \ ++ rc = DMMP_ERR_BUG; \ ++ _error(ctx, "BUG: Got NULL " #var); \ ++ goto goto_out; \ ++ } \ ++ if (strlen(var) == 0) { \ ++ rc = DMMP_ERR_BUG; \ ++ _error(ctx, "BUG: Got empty " #var); \ ++ goto goto_out; \ ++ } \ ++ } while(0) ++ ++#define _dmmp_getter_func_gen(func_name, struct_name, struct_data, \ ++ prop_name, prop_type) \ ++ prop_type func_name(struct_name *struct_data) \ ++ { \ ++ assert(struct_data != NULL); \ ++ return struct_data->prop_name; \ ++ } ++ ++#define _dmmp_array_free_func_gen(func_name, struct_name, struct_free_func) \ ++ void func_name(struct_name **ptr_array, uint32_t ptr_count) \ ++ { \ ++ uint32_t i = 0; \ ++ if (ptr_array == NULL) \ ++ return; \ ++ for (; i < ptr_count; ++i) \ ++ struct_free_func(ptr_array[i]); \ ++ free(ptr_array); \ ++ } ++ ++#ifdef __cplusplus ++} /* End of extern "C" */ ++#endif ++ ++#endif /* End of _LIB_DMMP_PRIVATE_H_ */ +Index: multipath-tools-130222/libdmmp/test/Makefile +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/test/Makefile +@@ -0,0 +1,30 @@ ++# Makefile ++# ++# Copyright (C) 2015-2016 Gris Ge ++# ++include ../../Makefile.inc ++ ++_libdmmpdir=../$(libdmmpdir) ++_mpathcmddir=../$(mpathcmddir) ++ ++TEST_EXEC = libdmmp_test ++SPD_TEST_EXEC = libdmmp_speed_test ++CFLAGS += -I$(_libdmmpdir) ++LDFLAGS += -L$(_libdmmpdir) -ldmmp ++ ++all: $(TEST_EXEC) $(SPD_TEST_EXEC) ++ ++check: $(TEST_EXEC) $(SPD_TEST_EXEC) ++ sudo env LD_LIBRARY_PATH=$(_libdmmpdir):$(_mpathcmddir) \ ++ valgrind --quiet --leak-check=full \ ++ --show-reachable=no --show-possibly-lost=no \ ++ --trace-children=yes --error-exitcode=1 \ ++ ./$(TEST_EXEC) ++ $(MAKE) speed_test ++ ++speed_test: $(SPD_TEST_EXEC) ++ sudo env LD_LIBRARY_PATH=$(_libdmmpdir):$(_mpathcmddir) \ ++ time -p ./$(SPD_TEST_EXEC) ++ ++clean: ++ rm -f $(TEST_EXEC) $(SPD_TEST_EXEC) +Index: multipath-tools-130222/libdmmp/test/libdmmp_speed_test.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/test/libdmmp_speed_test.c +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2015-2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++int main(int argc, char *argv[]) ++{ ++ struct dmmp_context *ctx = NULL; ++ struct dmmp_mpath **dmmp_mps = NULL; ++ uint32_t dmmp_mp_count = 0; ++ int rc = EXIT_SUCCESS; ++ ++ ctx = dmmp_context_new(); ++ dmmp_context_log_priority_set(ctx, DMMP_LOG_PRIORITY_WARNING); ++ ++ if (dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count) != 0) { ++ printf("FAILED\n"); ++ rc = EXIT_FAILURE; ++ } else { ++ printf("Got %" PRIu32 " mpath\n", dmmp_mp_count); ++ dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); ++ } ++ dmmp_context_free(ctx); ++ exit(rc); ++} +Index: multipath-tools-130222/libdmmp/test/libdmmp_test.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libdmmp/test/libdmmp_test.c +@@ -0,0 +1,147 @@ ++/* ++ * Copyright (C) 2015-2016 Red Hat, Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Author: Gris Ge ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define FAIL(rc, out, ...) \ ++ do { \ ++ rc = EXIT_FAILURE; \ ++ fprintf(stderr, "FAIL: "__VA_ARGS__ ); \ ++ goto out; \ ++ } while(0) ++#define PASS(...) fprintf(stdout, "PASS: "__VA_ARGS__ ); ++#define FILE_NAME_SIZE 256 ++#define TMO 10000 /* Forcing timeout to 10 seconds */ ++ ++int test_paths(struct dmmp_path_group *mp_pg) ++{ ++ struct dmmp_path **mp_ps = NULL; ++ uint32_t mp_p_count = 0; ++ uint32_t i = 0; ++ const char *blk_name = NULL; ++ int rc = EXIT_SUCCESS; ++ ++ dmmp_path_array_get(mp_pg, &mp_ps, &mp_p_count); ++ if (mp_p_count == 0) ++ FAIL(rc, out, "dmmp_path_array_get(): Got no path\n"); ++ for (i = 0; i < mp_p_count; ++i) { ++ blk_name = dmmp_path_blk_name_get(mp_ps[i]); ++ if (blk_name == NULL) ++ FAIL(rc, out, "dmmp_path_blk_name_get(): Got NULL\n"); ++ PASS("dmmp_path_blk_name_get(): %s\n", blk_name); ++ PASS("dmmp_path_status_get(): %" PRIu32 " -- %s\n", ++ dmmp_path_status_get(mp_ps[i]), ++ dmmp_path_status_str(dmmp_path_status_get(mp_ps[i]))); ++ } ++out: ++ return rc; ++} ++ ++int test_path_groups(struct dmmp_mpath *dmmp_mp) ++{ ++ struct dmmp_path_group **dmmp_pgs = NULL; ++ uint32_t dmmp_pg_count = 0; ++ uint32_t i = 0; ++ int rc = EXIT_SUCCESS; ++ ++ dmmp_path_group_array_get(dmmp_mp, &dmmp_pgs, &dmmp_pg_count); ++ if ((dmmp_pg_count == 0) && (dmmp_pgs != NULL)) ++ FAIL(rc, out, "dmmp_path_group_array_get(): mp_pgs is not NULL " ++ "but mp_pg_count is 0\n"); ++ if ((dmmp_pg_count != 0) && (dmmp_pgs == NULL)) ++ FAIL(rc, out, "dmmp_path_group_array_get(): mp_pgs is NULL " ++ "but mp_pg_count is not 0\n"); ++ if (dmmp_pg_count == 0) ++ FAIL(rc, out, "dmmp_path_group_array_get(): " ++ "Got 0 path group\n"); ++ ++ PASS("dmmp_path_group_array_get(): Got %" PRIu32 " path groups\n", ++ dmmp_pg_count); ++ ++ for (i = 0; i < dmmp_pg_count; ++i) { ++ PASS("dmmp_path_group_id_get(): %" PRIu32 "\n", ++ dmmp_path_group_id_get(dmmp_pgs[i])); ++ PASS("dmmp_path_group_priority_get(): %" PRIu32 "\n", ++ dmmp_path_group_priority_get(dmmp_pgs[i])); ++ PASS("dmmp_path_group_status_get(): %" PRIu32 " -- %s\n", ++ dmmp_path_group_status_get(dmmp_pgs[i]), ++ dmmp_path_group_status_str ++ (dmmp_path_group_status_get(dmmp_pgs[i]))); ++ PASS("dmmp_path_group_selector_get(): %s\n", ++ dmmp_path_group_selector_get(dmmp_pgs[i])); ++ rc = test_paths(dmmp_pgs[i]); ++ if (rc != 0) ++ goto out; ++ } ++out: ++ return rc; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct dmmp_context *ctx = NULL; ++ struct dmmp_mpath **dmmp_mps = NULL; ++ uint32_t dmmp_mp_count = 0; ++ const char *name = NULL; ++ const char *wwid = NULL; ++ const char *kdev = NULL; ++ uint32_t i = 0; ++ int rc = EXIT_SUCCESS; ++ ++ ctx = dmmp_context_new(); ++ dmmp_context_log_priority_set(ctx, DMMP_LOG_PRIORITY_DEBUG); ++ dmmp_context_userdata_set(ctx, ctx); ++ dmmp_context_userdata_set(ctx, NULL); ++ dmmp_context_timeout_set(ctx, TMO); ++ if (dmmp_context_timeout_get(ctx) != TMO) ++ FAIL(rc, out, "dmmp_context_timeout_set(): Failed to set " ++ "timeout to %u", TMO); ++ ++ if (dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count) != 0) ++ FAIL(rc, out, "dmmp_mpath_array_get(): rc != 0\n"); ++ if (dmmp_mp_count == 0) ++ FAIL(rc, out, "dmmp_mpath_array_get(): " ++ "Got no multipath devices\n"); ++ PASS("dmmp_mpath_array_get(): Got %" PRIu32 " mpath\n", dmmp_mp_count); ++ for (i = 0; i < dmmp_mp_count; ++i) { ++ name = dmmp_mpath_name_get(dmmp_mps[i]); ++ wwid = dmmp_mpath_wwid_get(dmmp_mps[i]); ++ kdev = dmmp_mpath_kdev_name_get(dmmp_mps[i]); ++ if ((name == NULL) ||(wwid == NULL) || (kdev == NULL)) ++ FAIL(rc, out, ++ "dmmp_mpath_array_get(): Got NULL name or wwid"); ++ PASS("dmmp_mpath_array_get(): Got mpath(%s): %s %s\n", ++ kdev, name, wwid); ++ rc = test_path_groups(dmmp_mps[i]); ++ if (rc != 0) ++ goto out; ++ } ++ dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); ++out: ++ dmmp_context_free(ctx); ++ exit(rc); ++} diff --git a/SOURCES/0210-RH-fix-uninstall.patch b/SOURCES/0210-RH-fix-uninstall.patch new file mode 100644 index 0000000..7083ded --- /dev/null +++ b/SOURCES/0210-RH-fix-uninstall.patch @@ -0,0 +1,25 @@ +--- + libmpathpersist/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/Makefile ++++ multipath-tools-130222/libmpathpersist/Makefile +@@ -33,12 +33,14 @@ install: $(LIBS) + ln -sf $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) + install -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir) + install -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir) ++ $(INSTALL_PROGRAM) -m 644 mpath_persist.h $(DESTDIR)$(includedir) + + uninstall: + rm -f $(DESTDIR)$(syslibdir)/$(LIBS) + rm -f $(DESTDIR)$(syslibdir)/$(DEVLIB) +- rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_in.3.gz +- rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_out.3.gz ++ rm $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3.gz ++ rm $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3.gz ++ rm -f $(DESTDIR)$(includedir)/mpath_persist.h + + clean: + rm -f core *.a *.o diff --git a/SOURCES/0211-RH-strlen-fix.patch b/SOURCES/0211-RH-strlen-fix.patch new file mode 100644 index 0000000..2c12fe8 --- /dev/null +++ b/SOURCES/0211-RH-strlen-fix.patch @@ -0,0 +1,35 @@ +--- + multipathd/main.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -878,7 +878,8 @@ uxsock_trigger (char * str, char ** repl + (strncmp(str, "list", strlen("list")) != 0) && + (strncmp(str, "show", strlen("show")) != 0)) { + *reply = STRDUP("permission deny: need to be root"); +- *len = strlen(*reply) + 1; ++ if (*reply) ++ *len = strlen(*reply) + 1; + r = 1; + goto out; + } +@@ -887,12 +888,14 @@ uxsock_trigger (char * str, char ** repl + + if (r > 0) { + *reply = STRDUP("fail\n"); +- *len = strlen(*reply) + 1; ++ if (*reply) ++ *len = strlen(*reply) + 1; + r = 1; + } + else if (!r && *len == 0) { + *reply = STRDUP("ok\n"); +- *len = strlen(*reply) + 1; ++ if (*reply) ++ *len = strlen(*reply) + 1; + r = 0; + } + /* else if (r < 0) leave *reply alone */ diff --git a/SOURCES/0212-RHBZ-1431562-for-read-only.patch b/SOURCES/0212-RHBZ-1431562-for-read-only.patch new file mode 100644 index 0000000..b398100 --- /dev/null +++ b/SOURCES/0212-RHBZ-1431562-for-read-only.patch @@ -0,0 +1,56 @@ +--- + libmultipath/devmapper.c | 10 ++++++---- + libmultipath/structs.h | 1 + + multipathd/main.c | 5 +++-- + 3 files changed, 10 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -358,10 +358,12 @@ dm_addmap_create (struct multipath *mpp, + extern int + dm_addmap_reload (struct multipath *mpp, char *params) { + sysfs_set_max_sectors_kb(mpp, 1); +- if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW, SKIP_KPARTX_OFF)) +- return 1; +- if (errno != EROFS) +- return 0; ++ if (!mpp->force_readonly) { ++ if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW, SKIP_KPARTX_OFF)) ++ return 1; ++ if (errno != EROFS) ++ return 0; ++ } + return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO, SKIP_KPARTX_OFF); + } + +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -259,6 +259,7 @@ struct multipath { + int force_udev_reload; + int skip_kpartx; + int max_sectors_kb; ++ int force_readonly; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -831,9 +831,10 @@ uev_update_path (struct uevent *uev, str + pp->mpp->wait_for_udev = 2; + return 0; + } +- ++ if (ro == 1) ++ pp->mpp->force_readonly = 1; + retval = reload_map(vecs, pp->mpp, 0); +- ++ pp->mpp->force_readonly = 0; + condlog(2, "%s: map %s reloaded (retval %d)", + uev->kernel, pp->mpp->alias, retval); + } diff --git a/SOURCES/0213-RHBZ-1430908-merge-dell-configs.patch b/SOURCES/0213-RHBZ-1430908-merge-dell-configs.patch new file mode 100644 index 0000000..920547e --- /dev/null +++ b/SOURCES/0213-RHBZ-1430908-merge-dell-configs.patch @@ -0,0 +1,191 @@ +--- + libmultipath/hwtable.c | 81 +----------------------------------------------- + multipath.conf.defaults | 69 +--------------------------------------- + 2 files changed, 5 insertions(+), 145 deletions(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -731,91 +731,16 @@ static struct hwentry default_hw[] = { + .prio_args = NULL, + }, + { +- /* DELL MD3000 */ ++ /* DELL MD3xxxx family */ + .vendor = "DELL", +- .product = "MD3000", ++ .product = "^MD3", + .bl_product = "Universal Xport", + .features = "2 pg_init_retries 50", + .hwhandler = "1 rdac", + .pgpolicy = GROUP_BY_PRIO, + .pgfailback = -FAILBACK_IMMEDIATE, + .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, +- .checker_name = RDAC, +- .prio_name = PRIO_RDAC, +- .prio_args = NULL, +- }, +- { +- /* DELL MD3000i */ +- .vendor = "DELL", +- .product = "MD3000i", +- .bl_product = "Universal Xport", +- .features = "2 pg_init_retries 50", +- .hwhandler = "1 rdac", +- .pgpolicy = GROUP_BY_PRIO, +- .pgfailback = -FAILBACK_IMMEDIATE, +- .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, +- .checker_name = RDAC, +- .prio_name = PRIO_RDAC, +- .prio_args = NULL, +- }, +- { +- /* DELL MD32xx */ +- .vendor = "DELL", +- .product = "MD32xx", +- .bl_product = "Universal Xport", +- .features = "2 pg_init_retries 50", +- .hwhandler = "1 rdac", +- .pgpolicy = GROUP_BY_PRIO, +- .pgfailback = -FAILBACK_IMMEDIATE, +- .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, +- .checker_name = RDAC, +- .prio_name = PRIO_RDAC, +- .prio_args = NULL, +- }, +- { +- /* DELL MD32xxi */ +- .vendor = "DELL", +- .product = "MD32xxi", +- .bl_product = "Universal Xport", +- .features = "2 pg_init_retries 50", +- .hwhandler = "1 rdac", +- .pgpolicy = GROUP_BY_PRIO, +- .pgfailback = -FAILBACK_IMMEDIATE, +- .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, +- .checker_name = RDAC, +- .prio_name = PRIO_RDAC, +- .prio_args = NULL, +- }, +- { +- /* DELL MD36xxi */ +- .vendor = "DELL", +- .product = "MD36xxi", +- .bl_product = "Universal Xport", +- .features = "2 pg_init_retries 50", +- .hwhandler = "1 rdac", +- .pgpolicy = GROUP_BY_PRIO, +- .pgfailback = -FAILBACK_IMMEDIATE, +- .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, +- .checker_name = RDAC, +- .prio_name = PRIO_RDAC, +- .prio_args = NULL, +- }, +- { +- /* DELL MD36xxf */ +- .vendor = "DELL", +- .product = "MD36xxf", +- .bl_product = "Universal Xport", +- .features = "2 pg_init_retries 50", +- .hwhandler = "1 rdac", +- .pgpolicy = GROUP_BY_PRIO, +- .pgfailback = -FAILBACK_IMMEDIATE, +- .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 15, ++ .no_path_retry = 30, + .checker_name = RDAC, + .prio_name = PRIO_RDAC, + .prio_args = NULL, +Index: multipath-tools-130222/multipath.conf.defaults +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.defaults ++++ multipath-tools-130222/multipath.conf.defaults +@@ -619,7 +619,7 @@ + # } + # device { + # vendor "DELL" +-# product "MD3000" ++# product "^MD3" + # product_blacklist "Universal Xport" + # path_grouping_policy "group_by_prio" + # path_checker "rdac" +@@ -628,72 +628,7 @@ + # prio "rdac" + # failback immediate + # rr_weight "uniform" +-# no_path_retry 15 +-# } +-# device { +-# vendor "DELL" +-# product "MD3000i" +-# product_blacklist "Universal Xport" +-# path_grouping_policy "group_by_prio" +-# path_checker "rdac" +-# features "2 pg_init_retries 50" +-# hardware_handler "1 rdac" +-# prio "rdac" +-# failback immediate +-# rr_weight "uniform" +-# no_path_retry 15 +-# } +-# device { +-# vendor "DELL" +-# product "MD32xx" +-# product_blacklist "Universal Xport" +-# path_grouping_policy "group_by_prio" +-# path_checker "rdac" +-# features "2 pg_init_retries 50" +-# hardware_handler "1 rdac" +-# prio "rdac" +-# failback immediate +-# rr_weight "uniform" +-# no_path_retry 15 +-# } +-# device { +-# vendor "DELL" +-# product "MD32xxi" +-# product_blacklist "Universal Xport" +-# path_grouping_policy "group_by_prio" +-# path_checker "rdac" +-# features "2 pg_init_retries 50" +-# hardware_handler "1 rdac" +-# prio "rdac" +-# failback immediate +-# rr_weight "uniform" +-# no_path_retry 15 +-# } +-# device { +-# vendor "DELL" +-# product "MD36xxi" +-# product_blacklist "Universal Xport" +-# path_grouping_policy "group_by_prio" +-# path_checker "rdac" +-# features "2 pg_init_retries 50" +-# hardware_handler "1 rdac" +-# prio "rdac" +-# failback immediate +-# rr_weight "uniform" +-# no_path_retry 15 +-# } +-# device { +-# vendor "DELL" +-# product "MD36xxf" +-# product_blacklist "Universal Xport" +-# path_grouping_policy "group_by_prio" +-# path_checker "rdac" +-# features "2 pg_init_retries 50" +-# hardware_handler "1 rdac" +-# prio "rdac" +-# failback immediate +-# rr_weight "uniform" +-# no_path_retry 15 ++# no_path_retry 30 + # } + # device { + # vendor "NETAPP" diff --git a/SOURCES/0214-RHBZ-1392115-set-paths-not-ready.patch b/SOURCES/0214-RHBZ-1392115-set-paths-not-ready.patch new file mode 100644 index 0000000..a37bc24 --- /dev/null +++ b/SOURCES/0214-RHBZ-1392115-set-paths-not-ready.patch @@ -0,0 +1,33 @@ +--- + multipath/multipath.rules | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -4,8 +4,14 @@ SUBSYSTEM!="block", GOTO="end_mpath" + + IMPORT{cmdline}="nompath" + ENV{nompath}=="?*", GOTO="end_mpath" +-ENV{DEVTYPE}=="partition", IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH", \ +- GOTO="end_mpath" ++ENV{DEVTYPE}!="partition", GOTO="test_dev" ++IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH" ++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{ID_FS_TYPE}="none", \ ++ ENV{SYSTEMD_READY}="0" ++GOTO="end_mpath" ++ ++LABEL="test_dev" ++ + ENV{MPATH_SBIN_PATH}="/sbin" + TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" + TEST!="/etc/multipath.conf", GOTO="check_kpartx" +@@ -33,6 +39,7 @@ ENV{DM_MULTIPATH_DEVICE_PATH}="" + ENV{DM_MULTIPATH_WIPE_PARTS}="" + + LABEL="update_timestamp" ++ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{SYSTEMD_READY}="0" + ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DM_MULTIPATH_WIPE_PARTS}!="1", \ + ENV{DM_MULTIPATH_WIPE_PARTS}="1", \ + RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" diff --git a/SOURCES/0215-RHBZ-1444194-fix-check-partitions.patch b/SOURCES/0215-RHBZ-1444194-fix-check-partitions.patch new file mode 100644 index 0000000..10d511e --- /dev/null +++ b/SOURCES/0215-RHBZ-1444194-fix-check-partitions.patch @@ -0,0 +1,101 @@ +--- + libmultipath/devmapper.c | 53 +++++++++++++++++++++-------------------------- + 1 file changed, 24 insertions(+), 29 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -466,42 +466,35 @@ uuidout: + extern int + dm_get_uuid(char *name, char *uuid) + { +- char uuidtmp[WWID_SIZE]; +- +- if (dm_get_prefixed_uuid(name, uuidtmp)) ++ if (dm_get_prefixed_uuid(name, uuid)) + return 1; + +- if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN)) +- strcpy(uuid, uuidtmp + UUID_PREFIX_LEN); +- else +- strcpy(uuid, uuidtmp); +- ++ if (!strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN)) ++ memmove(uuid, uuid + UUID_PREFIX_LEN, ++ strlen(uuid + UUID_PREFIX_LEN) + 1); + return 0; + } + +-/* +- * returns: +- * 0 : if both uuids end with same suffix which starts with UUID_PREFIX +- * 1 : otherwise +- */ +-int +-dm_compare_uuid(const char* mapname1, const char* mapname2) ++static int ++is_mpath_part(const char *part_name, const char *map_name) + { +- char *p1, *p2; +- char uuid1[WWID_SIZE], uuid2[WWID_SIZE]; ++ char *p; ++ char part_uuid[WWID_SIZE], map_uuid[WWID_SIZE]; + +- if (dm_get_prefixed_uuid(mapname1, uuid1)) +- return 1; ++ if (dm_get_prefixed_uuid(part_name, part_uuid)) ++ return 0; + +- if (dm_get_prefixed_uuid(mapname2, uuid2)) +- return 1; ++ if (dm_get_prefixed_uuid(map_name, map_uuid)) ++ return 0; + +- p1 = strstr(uuid1, UUID_PREFIX); +- p2 = strstr(uuid2, UUID_PREFIX); +- if (p1 && p2 && !strcmp(p1, p2)) ++ if (strncmp(part_uuid, "part", 4) != 0) + return 0; + +- return 1; ++ p = strstr(part_uuid, UUID_PREFIX); ++ if (p && !strcmp(p, map_uuid)) ++ return 1; ++ ++ return 0; + } + + extern int +@@ -1143,6 +1136,7 @@ do_foreach_partmaps (const char * mapnam + unsigned long long size; + char dev_t[32]; + int r = 1; ++ char *p; + + if (!(dmt = dm_task_create(DM_DEVICE_LIST))) + return 1; +@@ -1171,10 +1165,10 @@ do_foreach_partmaps (const char * mapnam + (dm_type(names->name, TGT_PART) > 0) && + + /* +- * and both uuid end with same suffix starting +- * at UUID_PREFIX ++ * and the uuid of the target is a partition of the ++ * uuid of the multipath device + */ +- (!dm_compare_uuid(names->name, mapname)) && ++ is_mpath_part(names->name, mapname) && + + /* + * and we can fetch the map table from the kernel +@@ -1184,7 +1178,8 @@ do_foreach_partmaps (const char * mapnam + /* + * and the table maps over the multipath map + */ +- strstr(params, dev_t) ++ (p = strstr(params, dev_t)) && ++ !isdigit(*(p + strlen(dev_t))) + ) { + if (partmap_func(names->name, data) != 0) + goto out; diff --git a/SOURCES/0216-RHBZ-1448562-fix-reserve.patch b/SOURCES/0216-RHBZ-1448562-fix-reserve.patch new file mode 100644 index 0000000..b68376b --- /dev/null +++ b/SOURCES/0216-RHBZ-1448562-fix-reserve.patch @@ -0,0 +1,122 @@ +--- + libmpathpersist/mpath_persist.c | 43 +++++++++++++++++++++++++--------------- + libmpathpersist/mpath_persist.h | 4 ++- + 2 files changed, 30 insertions(+), 17 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -440,7 +440,7 @@ int mpath_prout_reg(struct multipath *mp + thread[i].param.rq_type = rq_type; + thread[i].param.paramp = paramp; + thread[i].param.noisy = noisy; +- thread[i].param.status = -1; ++ thread[i].param.status = MPATH_PR_SKIP; + + condlog (3, "THRED ID [%d] INFO]", i); + condlog (3, "rq_servact=%d ", thread[i].param.rq_servact); +@@ -476,14 +476,17 @@ int mpath_prout_reg(struct multipath *mp + rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param)); + if (rc){ + condlog (0, "%s: failed to create thread %d", mpp->wwid, rc); ++ thread[count].param.status = MPATH_PR_THREAD_ERROR; + } + count = count +1; + } + } + for( i=0; i < active_pathcount ; i++){ +- rc = pthread_join(thread[i].id, NULL); +- if (rc){ +- condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc); ++ if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { ++ rc = pthread_join(thread[i].id, NULL); ++ if (rc){ ++ condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc); ++ } + } + if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){ + rollback = 1; +@@ -502,23 +505,27 @@ int mpath_prout_reg(struct multipath *mp + if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){ + condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid); + for( i=0 ; i < active_pathcount ; i++){ +- if((thread[i].param.status == MPATH_PR_SUCCESS) && +- ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){ ++ if (thread[i].param.status == MPATH_PR_SUCCESS) { + memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8); + memset(&thread[i].param.paramp->sa_key, 0, 8); + thread[i].param.status = MPATH_PR_SUCCESS; + rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn, +- (void *)(&thread[count].param)); ++ (void *)(&thread[i].param)); + if (rc){ + condlog (0, "%s: failed to create thread for rollback. %d", mpp->wwid, rc); ++ thread[i].param.status = MPATH_PR_THREAD_ERROR; + } +- } ++ } else ++ thread[i].param.status = MPATH_PR_SKIP; + } + for(i=0; i < active_pathcount ; i++){ +- rc = pthread_join(thread[i].id, NULL); +- if (rc){ +- condlog (3, "%s: failed to join thread while rolling back %d", +- mpp->wwid, i); ++ if (thread[i].param.status != MPATH_PR_SKIP && ++ thread[i].param.status != MPATH_PR_THREAD_ERROR) { ++ rc = pthread_join(thread[i].id, NULL); ++ if (rc){ ++ condlog (3, "%s: failed to join thread while rolling back %d", ++ mpp->wwid, i); ++ } + } + } + } +@@ -649,16 +656,20 @@ int mpath_prout_rel(struct multipath *mp + condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev); + rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn, + (void *) (&thread[count].param)); +- if (rc) ++ if (rc) { + condlog (0, "%s: failed to create thread. %d", mpp->wwid, rc); ++ thread[count].param.status = MPATH_PR_THREAD_ERROR; ++ } + count = count + 1; + } + } + pthread_attr_destroy (&attr); + for (i = 0; i < active_pathcount; i++){ +- rc = pthread_join (thread[i].id, NULL); +- if (rc){ +- condlog (1, "%s: failed to join thread. %d", mpp->wwid, rc); ++ if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { ++ rc = pthread_join (thread[i].id, NULL); ++ if (rc){ ++ condlog (1, "%s: failed to join thread. %d", mpp->wwid, rc); ++ } + } + } + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.h +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.h ++++ multipath-tools-130222/libmpathpersist/mpath_persist.h +@@ -43,6 +43,7 @@ extern "C" { + + + /* PR RETURN_STATUS */ ++#define MPATH_PR_SKIP -1 /* skipping this path */ + #define MPATH_PR_SUCCESS 0 + #define MPATH_PR_SYNTAX_ERROR 1 /* syntax error or invalid parameter */ + /* status for check condition */ +@@ -59,7 +60,8 @@ extern "C" { + #define MPATH_PR_RESERV_CONFLICT 11 /* Reservation conflict on the device */ + #define MPATH_PR_FILE_ERROR 12 /* file (device node) problems(e.g. not found)*/ + #define MPATH_PR_DMMP_ERROR 13 /* DMMP related error.(e.g Error in getting dm info */ +-#define MPATH_PR_OTHER 14 /*other error/warning has occurred(transport ++#define MPATH_PR_THREAD_ERROR 14 /* pthreads error (e.g. unable to create new thread) */ ++#define MPATH_PR_OTHER 15 /*other error/warning has occurred(transport + or driver error) */ + + /* PR MASK */ diff --git a/SOURCES/0217-RHBZ-1448576-3PAR-config.patch b/SOURCES/0217-RHBZ-1448576-3PAR-config.patch new file mode 100644 index 0000000..a1c982f --- /dev/null +++ b/SOURCES/0217-RHBZ-1448576-3PAR-config.patch @@ -0,0 +1,32 @@ +--- + libmultipath/hwtable.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -65,14 +65,17 @@ static struct hwentry default_hw[] = { + .vendor = "3PARdata", + .product = "VV", + .features = DEFAULT_FEATURES, +- .hwhandler = DEFAULT_HWHANDLER, +- .pgpolicy = MULTIBUS, +- .pgfailback = FAILBACK_UNDEF, ++ .hwhandler = "1 alua", ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, + .rr_weight = RR_WEIGHT_NONE, +- .no_path_retry = 12, +- .checker_name = DEFAULT_CHECKER, +- .prio_name = DEFAULT_PRIO, ++ .no_path_retry = 18, ++ .checker_name = TUR, ++ .prio_name = PRIO_ALUA, + .prio_args = NULL, ++ .selector = "service-time 0", ++ .fast_io_fail = 10, ++ .dev_loss = MAX_DEV_LOSS_TMO, + }, + { + .vendor = "DEC", diff --git a/SOURCES/0218-RHBZ-1459370-add-feature-fix.patch b/SOURCES/0218-RHBZ-1459370-add-feature-fix.patch new file mode 100644 index 0000000..e40abc8 --- /dev/null +++ b/SOURCES/0218-RHBZ-1459370-add-feature-fix.patch @@ -0,0 +1,25 @@ +--- + libmultipath/structs.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +Index: multipath-tools-130222/libmultipath/structs.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.c ++++ multipath-tools-130222/libmultipath/structs.c +@@ -511,6 +511,16 @@ add_feature (char **f, char *n) + if (!n || *n == '0') + return 0; + ++ /* default feature is null */ ++ if (!*f) ++ { ++ l = asprintf(&t, "1 %s", n); ++ if (l == -1) ++ return 1; ++ *f = t; ++ return 0; ++ } ++ + /* Check if feature is already present */ + if (strstr(*f, n)) + return 0; diff --git a/SOURCES/0219-RHBZ-1448970-fix-resize.patch b/SOURCES/0219-RHBZ-1448970-fix-resize.patch new file mode 100644 index 0000000..b753119 --- /dev/null +++ b/SOURCES/0219-RHBZ-1448970-fix-resize.patch @@ -0,0 +1,149 @@ +--- + libmultipath/configure.c | 18 +++------------ + libmultipath/devmapper.c | 55 +++++++++++++++++++++++++++++++++++++++++------ + libmultipath/devmapper.h | 3 +- + 3 files changed, 55 insertions(+), 21 deletions(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -616,7 +616,6 @@ extern int + domap (struct multipath * mpp, char * params) + { + int r = 0; +- uint16_t udev_flags = ((mpp->force_udev_reload)? 0 : MPATH_UDEV_RELOAD_FLAG) | ((mpp->skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0) | ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG); + + /* + * last chance to quit before touching the devmaps +@@ -660,17 +659,11 @@ domap (struct multipath * mpp, char * pa + break; + + case ACT_RELOAD: +- r = dm_addmap_reload(mpp, params); +- if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, +- udev_flags); ++ r = dm_addmap_reload(mpp, params, 0); + break; + + case ACT_RESIZE: +- r = dm_addmap_reload(mpp, params); +- if (r) +- r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1, +- udev_flags); ++ r = dm_addmap_reload(mpp, params, 1); + break; + + case ACT_RENAME: +@@ -679,11 +672,8 @@ domap (struct multipath * mpp, char * pa + + case ACT_RENAME2: + r = dm_rename(mpp->alias_old, mpp->alias, mpp->skip_kpartx); +- if (r) { +- r = dm_addmap_reload(mpp, params); +- if (r) +- r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags); +- } ++ if (r) ++ r = dm_addmap_reload(mpp, params, 0); + break; + + default: +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -356,15 +356,33 @@ dm_addmap_create (struct multipath *mpp, + #define ADDMAP_RO 1 + + extern int +-dm_addmap_reload (struct multipath *mpp, char *params) { ++dm_addmap_reload (struct multipath *mpp, char *params, int flush) { ++ int r = 0; ++ uint16_t udev_flags = ((mpp->force_udev_reload)? ++ 0 : MPATH_UDEV_RELOAD_FLAG) | ++ ((mpp->skip_kpartx == SKIP_KPARTX_ON)? ++ MPATH_UDEV_NO_KPARTX_FLAG : 0) | ++ ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG); ++ + sysfs_set_max_sectors_kb(mpp, 1); +- if (!mpp->force_readonly) { +- if (dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW, SKIP_KPARTX_OFF)) +- return 1; +- if (errno != EROFS) ++ if (!mpp->force_readonly) ++ r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ++ ADDMAP_RW, SKIP_KPARTX_OFF); ++ if (!r) { ++ if (!mpp->force_readonly && errno != EROFS) + return 0; ++ r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ++ ADDMAP_RO, SKIP_KPARTX_OFF); + } +- return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO, SKIP_KPARTX_OFF); ++ if (r) ++ r = dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush, ++ 1, udev_flags, 0); ++ if (r) ++ return r; ++ if (dm_is_suspended(mpp->alias)) ++ dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush, 1, ++ udev_flags, 0); ++ return 0; + } + + extern int +@@ -613,6 +631,31 @@ dm_is_mpath(const char * name) + out: + dm_task_destroy(dmt); + return r; ++} ++ ++int ++dm_is_suspended(const char *mapname) ++{ ++ int r = -1; ++ struct dm_task *dmt; ++ struct dm_info info; ++ ++ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ return r; ++ ++ if (!dm_task_set_name(dmt, mapname)) ++ goto out; ++ ++ if (!dm_task_run(dmt)) ++ goto out; ++ ++ if (!dm_task_get_info(dmt, &info) || !info.exists) ++ goto out; ++ ++ r = info.suspended; ++out: ++ dm_task_destroy(dmt); ++ return r; + } + + static int +Index: multipath-tools-130222/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.h ++++ multipath-tools-130222/libmultipath/devmapper.h +@@ -30,7 +30,7 @@ int dm_drv_version (unsigned int * versi + int dm_simplecmd_flush (int, const char *, int, uint16_t); + int dm_simplecmd_noflush (int, const char *, uint16_t); + int dm_addmap_create (struct multipath *mpp, char *params); +-int dm_addmap_reload (struct multipath *mpp, char *params); ++int dm_addmap_reload (struct multipath *mpp, char *params, int flush); + int dm_map_present (const char *); + int dm_get_map(const char *, unsigned long long *, char *); + int dm_get_status(char *, char *); +@@ -51,6 +51,7 @@ int dm_switchgroup(char * mapname, int i + int dm_enablegroup(char * mapname, int index); + int dm_disablegroup(char * mapname, int index); + int dm_get_maps (vector mp); ++int dm_is_suspended(const char *mapname); + int dm_geteventnr (char *name); + int dm_get_major (char *name); + int dm_get_minor (char *name); diff --git a/SOURCES/0220-RHBZ-1448223-fix-kpartx.patch b/SOURCES/0220-RHBZ-1448223-fix-kpartx.patch new file mode 100644 index 0000000..3061a2f --- /dev/null +++ b/SOURCES/0220-RHBZ-1448223-fix-kpartx.patch @@ -0,0 +1,58 @@ +--- + kpartx/kpartx.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +Index: multipath-tools-130222/kpartx/kpartx.c +=================================================================== +--- multipath-tools-130222.orig/kpartx/kpartx.c ++++ multipath-tools-130222/kpartx/kpartx.c +@@ -114,10 +114,13 @@ set_delimiter (char * device, char * del + { + char * p = device; + +- while (*(p++) != 0x0) ++ if (*p == 0x0) ++ return; ++ ++ while (*(++p) != 0x0) + continue; + +- if (isdigit(*(p - 2))) ++ if (isdigit(*(p - 1))) + *delimiter = 'p'; + } + +@@ -136,15 +139,17 @@ strip_slash (char * device) + static int + find_devname_offset (char * device) + { +- char *p, *q = NULL; ++ char *p, *q; + +- p = device; ++ q = p = device; + +- while (*p++) ++ while (*p) { + if (*p == '/') +- q = p; ++ q = p + 1; ++ p++; ++ } + +- return (int)(q - device) + 1; ++ return (int)(q - device); + } + + static char * +@@ -343,6 +348,10 @@ main(int argc, char **argv){ + } + device = loopdev; + } ++ else if (!S_ISBLK(buf.st_mode)) { ++ fprintf(stderr, "invalid device: %s\n", device); ++ exit(1); ++ } + + off = find_devname_offset(device); + diff --git a/SOURCES/0221-RH-harden-files.patch b/SOURCES/0221-RH-harden-files.patch new file mode 100644 index 0000000..46099d0 --- /dev/null +++ b/SOURCES/0221-RH-harden-files.patch @@ -0,0 +1,101 @@ +--- + Makefile.inc | 2 +- + kpartx/Makefile | 4 ++-- + libmpathpersist/Makefile | 2 +- + mpathpersist/Makefile | 4 ++-- + multipath/Makefile | 4 ++-- + multipathd/Makefile | 2 +- + 6 files changed, 9 insertions(+), 9 deletions(-) + +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -48,7 +48,7 @@ ifndef RPM_OPT_FLAGS + RPM_OPT_FLAGS = -O2 -g -pipe -Wformat-security -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 + endif + +-LDFLAGS += -Wl,-z,relro ++LDFLAGS += -Wl,-z,relro -Wl,-z,now + OPTFLAGS = $(RPM_OPT_FLAGS) -Wunused -Wstrict-prototypes + CFLAGS = $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" + SHARED_FLAGS = -shared +Index: multipath-tools-130222/kpartx/Makefile +=================================================================== +--- multipath-tools-130222.orig/kpartx/Makefile ++++ multipath-tools-130222/kpartx/Makefile +@@ -4,7 +4,7 @@ + # + include ../Makefile.inc + +-CFLAGS += -fPIC -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ++CFLAGS += -fPIE -DPIE -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 + + LIBDM_API_COOKIE = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_set_cookie' /usr/include/libdevmapper.h) + +@@ -12,7 +12,7 @@ ifneq ($(strip $(LIBDM_API_COOKIE)),0) + CFLAGS += -DLIBDM_API_COOKIE + endif + +-LDFLAGS = -ldevmapper ++LDFLAGS += -ldevmapper -pie + OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \ + gpt.o mac.o ps3.o crc32.o lopart.o xstrncpy.o devmapper.o + EXEC = kpartx +Index: multipath-tools-130222/libmpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/Makefile ++++ multipath-tools-130222/libmpathpersist/Makefile +@@ -21,7 +21,7 @@ all: $(LIBS) + + $(LIBS): + $(CC) -Wall -c $(CFLAGS) *.c +- $(CC) -shared $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) ++ $(CC) $(LDFLAGS) -shared $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) + ln -s $(LIBS) $(DEVLIB) + $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz + $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz +Index: multipath-tools-130222/mpathpersist/Makefile +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/Makefile ++++ multipath-tools-130222/mpathpersist/Makefile +@@ -4,8 +4,8 @@ include ../Makefile.inc + + OBJS = main.o + +-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) +-LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev ++CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathpersistdir) ++LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev -pie + + EXEC = mpathpersist + +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -6,9 +6,9 @@ include ../Makefile.inc + + OBJS = main.o + +-CFLAGS += -I$(multipathdir) -I$(mpathcmddir) ++CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathcmddir) + LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev \ +- -L$(mpathcmddir) -lmpathcmd ++ -L$(mpathcmddir) -lmpathcmd -pie + + EXEC = multipath + +Index: multipath-tools-130222/multipathd/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipathd/Makefile ++++ multipath-tools-130222/multipathd/Makefile +@@ -8,7 +8,7 @@ include ../Makefile.inc + CFLAGS += -fPIE -DPIE -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) + LDFLAGS += -lpthread -ldevmapper -lreadline -ludev -ldl \ + -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \ +- -L$(mpathcmddir) -lmpathcmd -Wl,-z,now -pie ++ -L$(mpathcmddir) -lmpathcmd -pie + + # + # debuging stuff diff --git a/SOURCES/0222-RHBZ-1457288-fix-show-maps-json.patch b/SOURCES/0222-RHBZ-1457288-fix-show-maps-json.patch new file mode 100644 index 0000000..90f37b8 --- /dev/null +++ b/SOURCES/0222-RHBZ-1457288-fix-show-maps-json.patch @@ -0,0 +1,23 @@ +--- + multipathd/cli_handlers.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -133,10 +133,12 @@ show_maps_json (char ** r, int * len, st + struct multipath * mpp; + char * c; + char * reply; +- unsigned int maxlen = INITIAL_REPLY_LEN * +- PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec); ++ unsigned int maxlen = INITIAL_REPLY_LEN; + int again = 1; + ++ if (VECTOR_SIZE(vecs->mpvec) > 0) ++ maxlen *= PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec); ++ + vector_foreach_slot(vecs->mpvec, mpp, i) { + if (update_multipath(vecs, mpp->alias, 0)) { + return 1; diff --git a/SOURCES/0223-RHBZ-1452210-unpriv-sgio.patch b/SOURCES/0223-RHBZ-1452210-unpriv-sgio.patch new file mode 100644 index 0000000..7a5b4b1 --- /dev/null +++ b/SOURCES/0223-RHBZ-1452210-unpriv-sgio.patch @@ -0,0 +1,456 @@ +--- + libmultipath/config.c | 3 + + libmultipath/config.h | 3 + + libmultipath/configure.c | 2 + libmultipath/defaults.h | 1 + libmultipath/dict.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/discovery.c | 44 +++++++++++++++++ + libmultipath/discovery.h | 1 + libmultipath/propsel.c | 26 ++++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 8 ++- + multipath/multipath.conf.5 | 9 +++ + 11 files changed, 210 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -347,6 +347,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(delay_wait_checks); + merge_num(skip_kpartx); + merge_num(max_sectors_kb); ++ merge_num(unpriv_sgio); + + /* + * Make sure features is consistent with +@@ -410,6 +411,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(delay_wait_checks); + overwrite_num(skip_kpartx); + overwrite_num(max_sectors_kb); ++ overwrite_num(unpriv_sgio); + + /* + * Make sure features is consistent with +@@ -690,6 +692,7 @@ load_config (char * file, struct udev *u + conf->remove_retries = 0; + conf->disable_changed_wwids = 0; + conf->max_sectors_kb = DEFAULT_MAX_SECTORS_KB; ++ conf->unpriv_sgio = DEFAULT_UNPRIV_SGIO; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -67,6 +67,7 @@ struct hwentry { + int delay_wait_checks; + int skip_kpartx; + int max_sectors_kb; ++ int unpriv_sgio; + char * bl_product; + }; + +@@ -95,6 +96,7 @@ struct mpentry { + int delay_wait_checks; + int skip_kpartx; + int max_sectors_kb; ++ int unpriv_sgio; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -153,6 +155,7 @@ struct config { + int remove_retries; + int disable_changed_wwids; + int max_sectors_kb; ++ int unpriv_sgio; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -297,6 +297,7 @@ setup_map (struct multipath * mpp, char + select_delay_wait_checks(mpp); + select_skip_kpartx(mpp); + select_max_sectors_kb(mpp); ++ select_unpriv_sgio(mpp); + + sysfs_set_scsi_tmo(mpp); + /* +@@ -711,6 +712,7 @@ domap (struct multipath * mpp, char * pa + } + } + dm_setgeometry(mpp); ++ sysfs_set_unpriv_sgio(mpp); + return DOMAP_OK; + } + return DOMAP_FAIL; +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -27,6 +27,7 @@ + #define DEFAULT_UEV_WAIT_TIMEOUT 30 + #define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF + #define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF ++#define DEFAULT_UNPRIV_SGIO UNPRIV_SGIO_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -1015,6 +1015,28 @@ def_max_sectors_kb_handler(vector strvec + return 0; + } + ++static int ++def_unpriv_sgio_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->unpriv_sgio = UNPRIV_SGIO_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->unpriv_sgio = UNPRIV_SGIO_ON; ++ else ++ conf->unpriv_sgio = UNPRIV_SGIO_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1851,6 +1873,33 @@ hw_max_sectors_kb_handler(vector strvec) + return 0; + } + ++static int ++hw_unpriv_sgio_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->unpriv_sgio = UNPRIV_SGIO_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->unpriv_sgio = UNPRIV_SGIO_ON; ++ else ++ hwe->unpriv_sgio = UNPRIV_SGIO_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -2422,6 +2471,32 @@ mp_max_sectors_kb_handler(vector strvec) + return 0; + } + ++static int ++mp_unpriv_sgio_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "0") == 0)) ++ mpe->unpriv_sgio = UNPRIV_SGIO_OFF; ++ else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) || ++ (strlen(buff) == 1 && strcmp(buff, "1") == 0)) ++ mpe->unpriv_sgio = UNPRIV_SGIO_ON; ++ else ++ mpe->unpriv_sgio = UNPRIV_SGIO_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2731,6 +2806,19 @@ snprint_mp_max_sectors_kb(char * buff, i + } + + static int ++snprint_mp_unpriv_sgio (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->unpriv_sgio == UNPRIV_SGIO_UNDEF) ++ return 0; ++ else if (mpe->unpriv_sgio == UNPRIV_SGIO_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "yes"); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -3132,6 +3220,19 @@ snprint_hw_max_sectors_kb(char * buff, i + } + + static int ++snprint_hw_unpriv_sgio(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->unpriv_sgio == UNPRIV_SGIO_ON) ++ return snprintf(buff, len, "yes"); ++ else if (hwe->unpriv_sgio == UNPRIV_SGIO_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return 0; ++} ++ ++static int + snprint_def_polling_interval (char * buff, int len, void * data) + { + return snprintf(buff, len, "%i", conf->checkint); +@@ -3617,6 +3718,15 @@ snprint_def_max_sectors_kb(char * buff, + } + + static int ++snprint_def_unpriv_sgio(char * buff, int len, void * data) ++{ ++ if (conf->unpriv_sgio == UNPRIV_SGIO_ON) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3699,6 +3809,7 @@ init_keywords(void) + install_keyword("remove_retries", &def_remove_retries_handler, &snprint_def_remove_retries); + install_keyword("disable_changed_wwids", &def_disable_changed_wwids_handler, &snprint_def_disable_changed_wwids); + install_keyword("max_sectors_kb", &def_max_sectors_kb_handler, &snprint_def_max_sectors_kb); ++ install_keyword("unpriv_sgio", &def_unpriv_sgio_handler, &snprint_def_unpriv_sgio); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -3769,6 +3880,7 @@ init_keywords(void) + install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks); + install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx); + install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb); ++ install_keyword("unpriv_sgio", &hw_unpriv_sgio_handler, &snprint_hw_unpriv_sgio); + install_sublevel_end(); + + install_keyword_root("multipaths", &multipaths_handler); +@@ -3798,5 +3910,6 @@ init_keywords(void) + install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks); + install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx); + install_keyword("max_sectors_kb", &mp_max_sectors_kb_handler, &snprint_mp_max_sectors_kb); ++ install_keyword("unpriv_sgio", &mp_unpriv_sgio_handler, &snprint_mp_unpriv_sgio); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -944,3 +944,29 @@ select_max_sectors_kb (struct multipath + mp->max_sectors_kb = MAX_SECTORS_KB_UNDEF; + return 0; + } ++ ++extern int ++select_unpriv_sgio (struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->unpriv_sgio != UNPRIV_SGIO_UNDEF) { ++ mp->unpriv_sgio = mp->mpe->unpriv_sgio; ++ condlog(3, "unpriv_sgio = %i (multipath setting)", ++ mp->unpriv_sgio); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->unpriv_sgio != UNPRIV_SGIO_UNDEF) { ++ mp->unpriv_sgio = mp->hwe->unpriv_sgio; ++ condlog(3, "unpriv_sgio = %i (controler setting)", ++ mp->unpriv_sgio); ++ return 0; ++ } ++ if (conf->unpriv_sgio != UNPRIV_SGIO_UNDEF) { ++ mp->unpriv_sgio = conf->unpriv_sgio; ++ condlog(3, "unpriv_sgio = %i (config file default)", ++ mp->unpriv_sgio); ++ return 0; ++ } ++ mp->unpriv_sgio = DEFAULT_UNPRIV_SGIO; ++ condlog(3, "unpriv_sgio = DISABLED (internal default)"); ++ return 0; ++} +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -26,3 +26,4 @@ int select_delay_watch_checks (struct mu + int select_delay_wait_checks (struct multipath * mp); + int select_skip_kpartx (struct multipath * mp); + int select_max_sectors_kb (struct multipath * mp); ++int select_unpriv_sgio (struct multipath * mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -134,12 +134,17 @@ enum skip_kpartx_states { + SKIP_KPARTX_ON, + }; + +- + enum max_sectors_kb_states { + MAX_SECTORS_KB_UNDEF = 0, + MAX_SECTORS_KB_MIN = 4, /* can't be smaller than page size */ + }; + ++enum unpriv_sgio_states { ++ UNPRIV_SGIO_UNDEF, ++ UNPRIV_SGIO_OFF, ++ UNPRIV_SGIO_ON, ++}; ++ + enum scsi_protocol { + SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ + SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ +@@ -260,6 +265,7 @@ struct multipath { + int skip_kpartx; + int max_sectors_kb; + int force_readonly; ++ int unpriv_sgio; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -222,6 +222,50 @@ fail_reload: + } + + int ++sysfs_set_unpriv_sgio(struct multipath *mpp) ++{ ++ struct pathgroup * pgp; ++ struct path *pp; ++ int i, j, ret; ++ struct udev_device *udevice = NULL; ++ ++ if (mpp->unpriv_sgio != UNPRIV_SGIO_ON) ++ return 0; ++ if (!mpp->dmi && dm_get_info(mpp->alias, &mpp->dmi) != 0) { ++ condlog(0, "failed to get dm info on %s to set unpriv_sgio", ++ mpp->alias); ++ return 1; ++ } ++ udevice = udev_device_new_from_devnum(conf->udev, 'b', ++ makedev(mpp->dmi->major, ++ mpp->dmi->minor)); ++ if (!udevice) { ++ condlog(0, "failed to get udev device to set unpriv_sgio for %s", mpp->alias); ++ return 1; ++ } ++ ++ ret = sysfs_attr_set_value(udevice, "queue/unpriv_sgio", "1", 1); ++ udev_device_unref(udevice); ++ if (ret < 0) { ++ condlog(0, "failed setting unpriv_sgio on %s: %s", mpp->alias, ++ strerror(-ret)); ++ return 1; ++ } ++ ++ vector_foreach_slot(mpp->pg, pgp, i) { ++ vector_foreach_slot (pgp->paths, pp, j) { ++ ret = sysfs_attr_set_value(pp->udev, ++ "queue/unpriv_sgio", "1", 1); ++ if (ret < 0) { ++ condlog(0, "failed setting unpriv_sgio on %s: %s", mpp->alias, strerror(-ret)); ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++ ++int + sysfs_get_timeout(struct path *pp, unsigned int *timeout) + { + const char *attr = NULL; +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -42,6 +42,7 @@ int store_pathinfo (vector pathvec, vect + struct path **pp_ptr); + int sysfs_set_scsi_tmo (struct multipath *mpp); + int sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload); ++int sysfs_set_unpriv_sgio(struct multipath *mpp); + int sysfs_get_timeout(struct path *pp, unsigned int *timeout); + int sysfs_get_host_pci_name(struct path *pp, char *pci_name); + int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address); +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -580,6 +580,11 @@ Between each attempt, multipath will sle + .B max_sectors_kb + Sets the max_sectors_kb device parameter on all path devices and the multipath + device to the specified value. Default is device dependent. ++.TP ++.B unpriv_sgio ++If set to \fIyes\fR, multipath will set upriv_sgio on the multipath device and ++all its paths, when it is created or reloaded. The default is ++.I no + . + .SH "blacklist section" + The +@@ -693,6 +698,8 @@ section: + .B skip_kpartx + .TP + .B max_sectors_kb ++.TP ++.B unpriv_sgio + .RE + .PD + .LP +@@ -795,6 +802,8 @@ section: + .B skip_kpartx + .TP + .B max_sectors_kb ++.TP ++.B unpriv_sgio + .RE + .PD + .LP diff --git a/SOURCES/0224-RHBZ-1452210-prkey.patch b/SOURCES/0224-RHBZ-1452210-prkey.patch new file mode 100644 index 0000000..e981971 --- /dev/null +++ b/SOURCES/0224-RHBZ-1452210-prkey.patch @@ -0,0 +1,1413 @@ +--- + libmpathpersist/mpath_persist.c | 79 +++++++++--------- + libmpathpersist/mpath_updatepr.c | 40 +++++---- + libmpathpersist/mpathpr.h | 5 - + libmultipath/Makefile | 2 + libmultipath/byteorder.h | 43 ++++++++++ + libmultipath/checkers/rbd.c | 16 --- + libmultipath/config.c | 9 +- + libmultipath/config.h | 9 +- + libmultipath/defaults.h | 1 + libmultipath/dict.c | 140 ++++++++++++-------------------- + libmultipath/prkey.c | 167 +++++++++++++++++++++++++++++++++++++++ + libmultipath/prkey.h | 19 ++++ + libmultipath/propsel.c | 58 ++++++------- + libmultipath/structs.h | 14 ++- + libmultipath/util.c | 34 +++++++ + libmultipath/util.h | 4 + mpathpersist/main.c | 5 - + multipath/multipath.conf.5 | 18 +++- + multipathd/cli.c | 7 + + multipathd/cli.h | 8 + + multipathd/cli_handlers.c | 69 ++++++++++++++++ + multipathd/cli_handlers.h | 4 + multipathd/main.c | 29 ++---- + multipathd/multipathd.8 | 13 +++ + 24 files changed, 576 insertions(+), 217 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -221,9 +221,7 @@ int mpath_persistent_reserve_out ( int f + int map_present; + int major, minor; + int ret; +- int j; +- unsigned char *keyp; +- uint64_t prkey; ++ uint64_t prkey; + + conf->verbosity = verbose; + +@@ -290,6 +288,27 @@ int mpath_persistent_reserve_out ( int f + + select_reservation_key(mpp); + ++ memcpy(&prkey, paramp->sa_key, 8); ++ if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey && ++ ((!get_be64(mpp->reservation_key) && ++ rq_servact == MPATH_PROUT_REG_SA) || ++ rq_servact == MPATH_PROUT_REG_IGN_SA)) { ++ memcpy(&mpp->reservation_key, paramp->sa_key, 8); ++ if (update_prkey(alias, get_be64(mpp->reservation_key))) { ++ 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)) { ++ 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: +@@ -311,24 +330,19 @@ int mpath_persistent_reserve_out ( int f + } + + if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) || +- (rq_servact == MPATH_PROUT_REG_IGN_SA))) ++ (rq_servact == MPATH_PROUT_REG_IGN_SA))) + { +- keyp=paramp->sa_key; +- prkey = 0; +- for (j = 0; j < 8; ++j) { +- if (j > 0) +- prkey <<= 8; +- prkey |= *keyp; +- ++keyp; ++ if (!prkey) { ++ update_prflag(alias, 0); ++ update_prkey(alias, 0); + } +- if (prkey == 0) +- update_prflag(alias, "unset", noisy); + else +- update_prflag(alias, "set", noisy); ++ update_prflag(alias, 1); + } else { +- if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_CLEAR_SA) || +- (rq_servact == MPATH_PROUT_PREE_AB_SA ))){ +- update_prflag(alias, "unset", noisy); ++ if ((ret == MPATH_PR_SUCCESS) && ++ (rq_servact == MPATH_PROUT_CLEAR_SA)) { ++ update_prflag(alias, 0); ++ update_prkey(alias, 0); + } + } + out1: +@@ -729,8 +743,8 @@ int mpath_prout_rel(struct multipath *mp + goto out1; + } + +- if (mpp->reservation_key ){ +- memcpy (pamp->key, mpp->reservation_key, 8); ++ if (get_be64(mpp->reservation_key)){ ++ memcpy (pamp->key, &mpp->reservation_key, 8); + condlog (3, "%s: reservation key set.", mpp->wwid); + } + +@@ -741,9 +755,9 @@ int mpath_prout_rel(struct multipath *mp + pptr=pamp->trnptid_list[0]; + + for (i = 0; i < num; i++){ +- if (mpp->reservation_key && ++ if (get_be64(mpp->reservation_key) && + memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, +- mpp->reservation_key, 8)){ ++ &mpp->reservation_key, 8)){ + /*register with tarnsport id*/ + memset(pamp, 0, length); + pamp->trnptid_list[0] = pptr; +@@ -768,7 +782,7 @@ int mpath_prout_rel(struct multipath *mp + } + else + { +- if (mpp->reservation_key) ++ if (get_be64(mpp->reservation_key)) + found = 1; + } + +@@ -777,7 +791,7 @@ int mpath_prout_rel(struct multipath *mp + + if (found){ + memset (pamp, 0, length); +- memcpy (pamp->sa_key, mpp->reservation_key, 8); ++ 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); + } +@@ -826,11 +840,9 @@ int update_map_pr(struct multipath *mpp) + { + int noisy=0; + struct prin_resp *resp; +- int i,j, ret, isFound; +- unsigned char *keyp; +- uint64_t prkey; ++ int i, ret, isFound; + +- if (!mpp->reservation_key) ++ if (!get_be64(mpp->reservation_key)) + { + /* Nothing to do. Assuming pr mgmt feature is disabled*/ + condlog(3, "%s: reservation_key not set in multipath.conf", mpp->alias); +@@ -859,15 +871,8 @@ int update_map_pr(struct multipath *mpp) + return MPATH_PR_SUCCESS; + } + +- prkey = 0; +- keyp = mpp->reservation_key; +- for (j = 0; j < 8; ++j) { +- if (j > 0) +- prkey <<= 8; +- prkey |= *keyp; +- ++keyp; +- } +- condlog(2, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias, prkey); ++ 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++ ) +@@ -875,7 +880,7 @@ int update_map_pr(struct multipath *mpp) + 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)) ++ 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; +Index: multipath-tools-130222/libmpathpersist/mpath_updatepr.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_updatepr.c ++++ multipath-tools-130222/libmpathpersist/mpath_updatepr.c +@@ -1,7 +1,7 @@ +-#include +-#include ++#include ++#include + #include +- ++#include + #include + #include + #include +@@ -18,10 +18,10 @@ + + unsigned long mem_allocated; /* Total memory used in Bytes */ + +-int update_prflag(char * arg1, char * arg2, int noisy) ++static int do_update_pr(char * mapname, char * arg) + { + int fd; +- char str[64]; ++ char str[256]; + char *reply; + int ret = 0; + +@@ -31,25 +31,35 @@ int update_prflag(char * arg1, char * ar + return 1 ; + } + +- snprintf(str,sizeof(str),"map %s %s", arg1, arg2); +- condlog (2, "%s: pr flag message=%s", arg1, str); ++ snprintf(str,sizeof(str),"map %s %s", mapname, arg); ++ condlog (2, "%s: pr message=%s", mapname, arg); + send_packet(fd, str); + ret = recv_packet(fd, &reply); + if (ret < 0) { +- condlog(2, "%s: message=%s recv error=%d", arg1, str, errno); ++ condlog(2, "%s: message=%s recv error=%d", mapname, str, errno); + ret = -2; + } else { +- condlog (2, "%s: message=%s reply=%s", arg1, str, reply); ++ condlog (2, "%s: message=%s reply=%s", mapname, str, reply); + if (!reply || strncmp(reply,"ok", 2) == 0) +- ret = -1; +- else if (strncmp(reply, "fail", 4) == 0) +- ret = -2; +- else{ +- ret = atoi(reply); +- } ++ ret = 0; ++ else ret = -1; + } + + free(reply); + mpath_disconnect(fd); + return ret; + } ++ ++int update_prflag(char *mapname, int set) { ++ return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus"); ++} ++ ++int update_prkey(char *mapname, uint64_t prkey) { ++ char str[256]; ++ ++ if (prkey) ++ snprintf(str, sizeof(str), "setprkey key %" PRIx64, prkey); ++ else ++ snprintf(str, sizeof(str), "unsetprkey"); ++ return do_update_pr(mapname, str); ++} +Index: multipath-tools-130222/libmpathpersist/mpathpr.h +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpathpr.h ++++ multipath-tools-130222/libmpathpersist/mpathpr.h +@@ -1,6 +1,8 @@ + #ifndef MPATHPR_H + #define MPATHPR_H + ++#include ++ + struct prin_param { + char dev[FILE_NAME_SIZE]; + int rq_servact; +@@ -47,7 +49,8 @@ int mpath_prout_rel(struct multipath *mp + int send_prout_activepath(char * dev, int rq_servact, int rq_scope, + unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy); + +-int update_prflag(char * arg1, char * arg2, int noisy); ++int update_prflag(char *mapname, int set); ++int update_prkey(char *mapname, uint64_t prkey); + void * mpath_alloc_prin_response(int prin_sa); + int update_map_pr(struct multipath *mpp); + int devt2devname (char *devname, char *devt); +Index: multipath-tools-130222/libmultipath/byteorder.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/byteorder.h +@@ -0,0 +1,43 @@ ++#ifndef BYTEORDER_H_INCLUDED ++#define BYTEORDER_H_INCLUDED ++ ++#ifdef __linux__ ++# include ++# include ++#else ++# error unsupported ++#endif ++ ++#if BYTE_ORDER == LITTLE_ENDIAN ++# define le16_to_cpu(x) (x) ++# define be16_to_cpu(x) bswap_16(x) ++# define le32_to_cpu(x) (x) ++# define le64_to_cpu(x) (x) ++# define be32_to_cpu(x) bswap_32(x) ++# define be64_to_cpu(x) bswap_64(x) ++#elif BYTE_ORDER == BIG_ENDIAN ++# define le16_to_cpu(x) bswap_16(x) ++# define be16_to_cpu(x) (x) ++# define le32_to_cpu(x) bswap_32(x) ++# define le64_to_cpu(x) bswap_64(x) ++# define be32_to_cpu(x) (x) ++# define be64_to_cpu(x) (x) ++#else ++# error unsupported ++#endif ++ ++#define cpu_to_le16(x) le16_to_cpu(x) ++#define cpu_to_be16(x) be16_to_cpu(x) ++#define cpu_to_le32(x) le32_to_cpu(x) ++#define cpu_to_be32(x) be32_to_cpu(x) ++#define cpu_to_le64(x) le64_to_cpu(x) ++#define cpu_to_be64(x) be64_to_cpu(x) ++ ++struct be64 { ++ uint64_t _v; ++}; ++ ++#define get_be64(x) be64_to_cpu((x)._v) ++#define put_be64(x, y) do { (x)._v = cpu_to_be64(y); } while (0) ++ ++#endif /* BYTEORDER_H_INCLUDED */ +Index: multipath-tools-130222/libmultipath/checkers/rbd.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rbd.c ++++ multipath-tools-130222/libmultipath/checkers/rbd.c +@@ -27,6 +27,7 @@ + + #include "../libmultipath/debug.h" + #include "../libmultipath/uevent.h" ++#include "../libmultipath/util.h" + + struct rbd_checker_context; + typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg); +@@ -355,21 +356,6 @@ int rbd_check(struct rbd_checker_context + return PATH_UP; + } + +-int safe_write(int fd, const void *buf, size_t count) +-{ +- while (count > 0) { +- ssize_t r = write(fd, buf, count); +- if (r < 0) { +- if (errno == EINTR) +- continue; +- return -errno; +- } +- count -= r; +- buf = (char *)buf + r; +- } +- return 0; +-} +- + static int sysfs_write_rbd_bus(const char *which, const char *buf, + size_t buf_len) + { +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -574,6 +574,9 @@ free_config (struct config * conf) + if (conf->wwids_file) + FREE(conf->wwids_file); + ++ if (conf->prkeys_file) ++ FREE(conf->prkeys_file); ++ + if (conf->prio_name) + FREE(conf->prio_name); + +@@ -589,9 +592,6 @@ free_config (struct config * conf) + if (conf->config_dir) + FREE(conf->config_dir); + +- if (conf->reservation_key) +- FREE(conf->reservation_key); +- + free_blacklist(conf->blist_devnode); + free_blacklist(conf->blist_wwid); + free_blacklist_device(conf->blist_device); +@@ -666,6 +666,7 @@ load_config (char * file, struct udev *u + get_sys_max_fds(&conf->max_fds); + conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE); + conf->wwids_file = set_default(DEFAULT_WWIDS_FILE); ++ conf->prkeys_file = set_default(DEFAULT_PRKEYS_FILE); + conf->bindings_read_only = 0; + conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR); + conf->features = set_default(DEFAULT_FEATURES); +@@ -806,7 +807,7 @@ load_config (char * file, struct udev *u + conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE); + + if (!conf->multipath_dir || !conf->bindings_file || +- !conf->wwids_file) ++ !conf->wwids_file || !conf->prkeys_file) + goto out; + + if (conf->ignore_new_boot_devs) +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -3,6 +3,8 @@ + + #include + #include ++#include ++#include "byteorder.h" + + #define ORIGIN_DEFAULT 0 + #define ORIGIN_CONFIG 1 +@@ -80,7 +82,8 @@ struct mpentry { + + char * prio_name; + char * prio_args; +- unsigned char * reservation_key; ++ int prkey_source; ++ struct be64 reservation_key; + int pgpolicy; + int pgfailback; + int rr_weight; +@@ -167,12 +170,14 @@ struct config { + char * hwhandler; + char * bindings_file; + char * wwids_file; ++ char * prkeys_file; + char * prio_name; + char * prio_args; + char * checker_name; + char * alias_prefix; + char * config_dir; +- unsigned char * reservation_key; ++ int prkey_source; ++ struct be64 reservation_key; + + vector keywords; + vector mptable; +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -39,6 +39,7 @@ + #define DEFAULT_CONFIGFILE "/etc/multipath.conf" + #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" + #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" ++#define DEFAULT_PRKEYS_FILE "/etc/multipath/prkeys" + #define DEFAULT_CONFIG_DIR "/etc/multipath/conf.d" + + char * set_default (char * str); +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -20,6 +20,8 @@ + #include "defaults.h" + #include "prio.h" + #include "errno.h" ++#include "util.h" ++#include "prkey.h" + #include + + /* +@@ -554,46 +556,26 @@ static int + def_reservation_key_handler(vector strvec) + { + char *buff; +- char *tbuff; +- int j, k; +- int len; +- uint64_t prkey; ++ uint64_t prkey = 0; + + buff = set_value(strvec); + if (!buff) + return 1; + +- tbuff = buff; +- +- if (!memcmp("0x",buff, 2)) +- buff = buff + 2; +- +- len = strlen(buff); +- +- k = strspn(buff, "0123456789aAbBcCdDeEfF"); +- +- if (len != k) { +- FREE(tbuff); +- return 1; ++ if (strlen(buff) == 4 && !strcmp(buff, "file")) { ++ conf->prkey_source = PRKEY_SOURCE_FILE; ++ put_be64(conf->reservation_key, 0); ++ FREE(buff); ++ return 0; + } +- +- if (1 != sscanf (buff, "%" SCNx64 "", &prkey)) +- { +- FREE(tbuff); ++ else if (parse_prkey(buff, &prkey) != 0) { ++ FREE(buff); + return 1; + } + +- if (!conf->reservation_key) +- conf->reservation_key = (unsigned char *) malloc(8); +- +- memset(conf->reservation_key, 0, 8); +- +- for (j = 7; j >= 0; --j) { +- conf->reservation_key[j] = (prkey & 0xff); +- prkey >>= 8; +- } +- +- FREE(tbuff); ++ conf->prkey_source = PRKEY_SOURCE_CONF; ++ put_be64(conf->reservation_key, prkey); ++ FREE(buff); + return 0; + } + +@@ -668,6 +650,19 @@ wwids_file_handler(vector strvec) + } + + static int ++prkeys_file_handler(vector strvec) ++{ ++ if (conf->prkeys_file) ++ FREE(conf->prkeys_file); ++ conf->prkeys_file = set_value(strvec); ++ ++ if (!conf->prkeys_file) ++ return 1; ++ ++ return 0; ++} ++ ++static int + def_retain_hwhandler_handler(vector strvec) + { + char * buff; +@@ -2282,10 +2277,7 @@ static int + mp_reservation_key_handler (vector strvec) + { + char *buff; +- char *tbuff; + struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); +- +- int j, k, len; + uint64_t prkey; + + if (!mpe) +@@ -2295,35 +2287,20 @@ mp_reservation_key_handler (vector strve + if (!buff) + return 1; + +- tbuff = buff; +- if (!memcmp(buff, "0x", 2)) +- buff = buff + 2; +- +- len = strlen(buff); +- +- k = strspn(buff, "0123456789aAbBcCdDeEfF"); +- if (len != k) { +- FREE(tbuff); +- return 1; ++ if (strlen(buff) == 4 && !strcmp(buff, "file")) { ++ mpe->prkey_source = PRKEY_SOURCE_FILE; ++ put_be64(mpe->reservation_key, 0); ++ FREE(buff); ++ return 0; + } +- +- if (1 != sscanf (buff, "%" SCNx64 "", &prkey)) +- { +- FREE(tbuff); ++ else if (parse_prkey(buff, &prkey) != 0) { ++ FREE(buff); + return 1; + } + +- if (!mpe->reservation_key) +- mpe->reservation_key = (unsigned char *) malloc(8); +- +- memset(mpe->reservation_key, 0, 8); +- +- for (j = 7; j >= 0; --j) { +- mpe->reservation_key[j] = (prkey & 0xff); +- prkey >>= 8; +- } +- +- FREE(tbuff); ++ mpe->prkey_source = PRKEY_SOURCE_CONF; ++ put_be64(mpe->reservation_key, prkey); ++ FREE(buff); + return 0; + } + +@@ -2714,22 +2691,14 @@ snprint_mp_prio_args(char * buff, int le + static int + snprint_mp_reservation_key (char * buff, int len, void * data) + { +- int i; +- unsigned char *keyp; +- uint64_t prkey = 0; + struct mpentry * mpe = (struct mpentry *)data; + +- if (!mpe->reservation_key) ++ if (mpe->prkey_source == PRKEY_SOURCE_NONE) + return 0; +- keyp = (unsigned char *)mpe->reservation_key; +- for (i = 0; i < 8; i++) { +- if (i > 0) +- prkey <<= 8; +- prkey |= *keyp; +- keyp++; +- } +- +- return snprintf(buff, len, "0x%" PRIx64, prkey); ++ if (mpe->prkey_source == PRKEY_SOURCE_FILE) ++ return snprintf(buff, len, "file"); ++ return snprintf(buff, len, "0x%" PRIx64, ++ get_be64(mpe->reservation_key)); + } + + static int +@@ -3551,22 +3520,22 @@ snprint_def_wwids_file (char * buff, int + } + + static int +-snprint_def_reservation_key(char * buff, int len, void * data) ++snprint_def_prkeys_file (char * buff, int len, void * data) + { +- int i; +- unsigned char *keyp; +- uint64_t prkey = 0; ++ if (conf->prkeys_file == NULL) ++ return 0; ++ return snprintf(buff, len, "%s", conf->prkeys_file); ++} + +- if (!conf->reservation_key) ++static int ++snprint_def_reservation_key(char * buff, int len, void * data) ++{ ++ if (conf->prkey_source == PRKEY_SOURCE_NONE) + return 0; +- keyp = (unsigned char *)conf->reservation_key; +- for (i = 0; i < 8; i++) { +- if (i > 0) +- prkey <<= 8; +- prkey |= *keyp; +- keyp++; +- } +- return snprintf(buff, len, "0x%" PRIx64, prkey); ++ if (conf->prkey_source == PRKEY_SOURCE_FILE) ++ return snprintf(buff, len, "file"); ++ return snprintf(buff, len, "0x%" PRIx64, ++ get_be64(conf->reservation_key)); + } + + static int +@@ -3788,6 +3757,7 @@ init_keywords(void) + install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss); + install_keyword("bindings_file", &bindings_file_handler, &snprint_def_bindings_file); + install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file); ++ install_keyword("prkeys_file", &prkeys_file_handler, &snprint_def_prkeys_file); + install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err); + install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key); + install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths); +Index: multipath-tools-130222/libmultipath/prkey.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/prkey.c +@@ -0,0 +1,167 @@ ++#include "prkey.h" ++#include "structs.h" ++#include "file.h" ++#include "debug.h" ++#include "config.h" ++#include "util.h" ++#include "propsel.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define KEYSIZE 19 ++#define PRKEY_READ 0 ++#define PRKEY_WRITE 1 ++ ++static int do_prkey(int fd, char *wwid, char *keystr, int cmd) ++{ ++ char buf[4097]; ++ char *ptr; ++ off_t start = 0; ++ int bytes; ++ ++ while (1) { ++ if (lseek(fd, start, SEEK_SET) < 0) { ++ condlog(0, "prkey file read lseek failed : %s", ++ strerror(errno)); ++ return 1; ++ } ++ bytes = read(fd, buf, 4096); ++ if (bytes < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ condlog(0, "failed to read from prkey file : %s", ++ strerror(errno)); ++ return 1; ++ } ++ if (!bytes) { ++ ptr = NULL; ++ break; ++ } ++ buf[bytes] = '\0'; ++ ptr = strstr(buf, wwid); ++ while (ptr) { ++ if (ptr == buf || *(ptr - 1) != ' ' || ++ *(ptr + strlen(wwid)) != '\n') ++ ptr = strstr(ptr + strlen(wwid), wwid); ++ else ++ break; ++ } ++ if (ptr) { ++ condlog(3, "found prkey for '%s'", wwid); ++ ptr[strlen(wwid)] = '\0'; ++ if (ptr - KEYSIZE < buf || ++ (ptr - KEYSIZE != buf && ++ *(ptr - KEYSIZE - 1) != '\n')) { ++ condlog(0, "malformed prkey file line for wwid: '%s'", ptr); ++ return 1; ++ } ++ ptr = ptr - KEYSIZE; ++ break; ++ } ++ ptr = strrchr(buf, '\n'); ++ if (ptr == NULL) { ++ condlog(4, "couldn't file newline, assuming end of file"); ++ break; ++ } ++ start = start + (ptr - buf) + 1; ++ } ++ if (cmd == PRKEY_READ) { ++ if (!ptr || *ptr == '#') ++ return 1; ++ memcpy(keystr, ptr, KEYSIZE - 1); ++ keystr[KEYSIZE - 1] = '\0'; ++ return 0; ++ } ++ if (!ptr && !keystr) ++ return 0; ++ if (ptr) { ++ if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) { ++ condlog(0, "prkey write lseek failed : %s", ++ strerror(errno)); ++ return 1; ++ } ++ } ++ if (!keystr) { ++ if (safe_write(fd, "#", 1) < 0) { ++ condlog(0, "failed to write to prkey file : %s", ++ strerror(errno)); ++ return 1; ++ } ++ return 0; ++ } ++ if (!ptr) { ++ if (lseek(fd, 0, SEEK_END) < 0) { ++ condlog(0, "prkey write lseek failed : %s", ++ strerror(errno)); ++ return 1; ++ } ++ } ++ bytes = sprintf(buf, "%s %s\n", keystr, wwid); ++ if (safe_write(fd, buf, bytes) < 0) { ++ condlog(0, "failed to write to prkey file: %s", ++ strerror(errno)); ++ return 1; ++ } ++ return 0; ++} ++ ++int get_prkey(struct multipath *mpp, uint64_t *prkey) ++{ ++ int fd; ++ int unused; ++ int ret = 1; ++ char keystr[KEYSIZE]; ++ ++ if (!strlen(mpp->wwid)) ++ goto out; ++ ++ fd = open_file(conf->prkeys_file, &unused, PRKEYS_FILE_HEADER); ++ if (fd < 0) ++ goto out; ++ ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_READ); ++ if (ret) ++ goto out_file; ++ ret = !!parse_prkey(keystr, prkey); ++out_file: ++ close(fd); ++out: ++ return ret; ++} ++ ++int set_prkey(struct multipath *mpp, uint64_t prkey) ++{ ++ int fd; ++ int can_write = 1; ++ int ret = 1; ++ char keystr[KEYSIZE]; ++ ++ if (!strlen(mpp->wwid)) ++ goto out; ++ ++ fd = open_file(conf->prkeys_file, &can_write, PRKEYS_FILE_HEADER); ++ if (fd < 0) ++ goto out; ++ if (!can_write) { ++ condlog(0, "cannot set prkey, prkeys file is read-only"); ++ goto out_file; ++ } ++ if (prkey) { ++ snprintf(keystr, KEYSIZE, "0x%016" PRIx64, prkey); ++ keystr[KEYSIZE - 1] = '\0'; ++ ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_WRITE); ++ } ++ else ++ ret = do_prkey(fd, mpp->wwid, NULL, PRKEY_WRITE); ++ if (ret == 0) ++ select_reservation_key(mpp); ++ if (get_be64(mpp->reservation_key) != prkey) ++ ret = 1; ++out_file: ++ close(fd); ++out: ++ return ret; ++} +Index: multipath-tools-130222/libmultipath/prkey.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/prkey.h +@@ -0,0 +1,19 @@ ++#ifndef _PRKEY_H ++#define _PRKEY_H ++ ++#include "structs.h" ++#include ++ ++#define PRKEYS_FILE_HEADER \ ++"# Multipath persistent reservation keys, Version : 1.0\n" \ ++"# NOTE: this file is automatically maintained by the multipathd program.\n" \ ++"# You should not need to edit this file in normal circumstances.\n" \ ++"#\n" \ ++"# Format:\n" \ ++"# prkey wwid\n" \ ++"#\n" ++ ++int set_prkey(struct multipath *mpp, uint64_t prkey); ++int get_prkey(struct multipath *mpp, uint64_t *prkey); ++ ++#endif /* _PRKEY_H */ +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -18,6 +18,7 @@ + #include "prio.h" + #include "discovery.h" + #include "prioritizers/alua_rtpg.h" ++#include "prkey.h" + #include + + pgpolicyfn *pgpolicies[] = { +@@ -711,44 +712,39 @@ select_flush_on_last_del(struct multipat + extern int + select_reservation_key (struct multipath * mp) + { +- int j; +- unsigned char *keyp; +- uint64_t prkey = 0; +- +- mp->reservation_key = NULL; +- +- if (mp->mpe && mp->mpe->reservation_key) { +- keyp = mp->mpe->reservation_key; +- for (j = 0; j < 8; ++j) { +- if (j > 0) +- prkey <<= 8; +- prkey |= *keyp; +- ++keyp; +- } +- +- condlog(3, "%s: reservation_key = 0x%" PRIx64 " " +- "(multipath setting)", mp->alias, prkey); ++ uint64_t prkey; ++ char *origin = NULL; ++ char *from_file = ""; + ++ if (mp->mpe && mp->mpe->prkey_source != PRKEY_SOURCE_NONE) { ++ mp->prkey_source = mp->mpe->prkey_source; + mp->reservation_key = mp->mpe->reservation_key; +- return 0; ++ origin = "multipath setting"; ++ goto out; + } + +- if (conf->reservation_key) { +- keyp = conf->reservation_key; +- for (j = 0; j < 8; ++j) { +- if (j > 0) +- prkey <<= 8; +- prkey |= *keyp; +- ++keyp; +- } +- +- condlog(3, "%s: reservation_key = 0x%" PRIx64 +- " (config file default)", mp->alias, prkey); +- ++ if (conf->prkey_source != PRKEY_SOURCE_NONE) { ++ mp->prkey_source = conf->prkey_source; + mp->reservation_key = conf->reservation_key; +- return 0; ++ origin = "config file default"; ++ goto out; + } + ++ put_be64(mp->reservation_key, 0); ++ mp->prkey_source = PRKEY_SOURCE_NONE; ++ return 0; ++out: ++ if (mp->prkey_source == PRKEY_SOURCE_FILE) { ++ from_file = " (from prkeys file)"; ++ if (get_prkey(mp, &prkey) != 0) ++ put_be64(mp->reservation_key, 0); ++ else ++ put_be64(mp->reservation_key, prkey); ++ } ++ if (get_be64(mp->reservation_key)) ++ condlog(0, "%s: reservation_key = 0x%" PRIx64 " (%s)%s", ++ mp->alias, get_be64(mp->reservation_key), origin, ++ from_file); + return 0; + } + +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -2,8 +2,10 @@ + #define _STRUCTS_H + + #include ++#include + + #include "prio.h" ++#include "byteorder.h" + + #define WWID_SIZE 128 + #define SERIAL_SIZE 65 +@@ -27,7 +29,6 @@ + #define NO_PATH_RETRY_FAIL -1 + #define NO_PATH_RETRY_QUEUE -2 + +- + enum free_path_mode { + KEEP_PATHS, + FREE_PATHS +@@ -169,6 +170,12 @@ enum missing_udev_info_states { + INFO_REQUESTED, + }; + ++enum prkey_sources { ++ PRKEY_SOURCE_NONE, ++ PRKEY_SOURCE_CONF, ++ PRKEY_SOURCE_FILE, ++}; ++ + struct sg_id { + int host_no; + int channel; +@@ -298,8 +305,9 @@ struct multipath { + /* checkers shared data */ + void * mpcontext; + +- /* persistent management data*/ +- unsigned char * reservation_key; ++ /* persistent management data */ ++ int prkey_source; ++ struct be64 reservation_key; + unsigned char prflag; + }; + +Index: multipath-tools-130222/libmultipath/util.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.c ++++ multipath-tools-130222/libmultipath/util.c +@@ -5,12 +5,14 @@ + #include + #include + #include ++#include + + #include "debug.h" + #include "memory.h" + #include "checkers.h" + #include "vector.h" + #include "structs.h" ++#include "util.h" + + void + strchop(char *str) +@@ -297,3 +299,35 @@ int in_initrd(void) { + + return saved; + } ++ ++int parse_prkey(char *ptr, uint64_t *prkey) ++{ ++ if (!ptr) ++ return 1; ++ if (*ptr == '0') ++ ptr++; ++ if (*ptr == 'x' || *ptr == 'X') ++ ptr++; ++ if (*ptr == '\0' || strlen(ptr) > 16) ++ return 1; ++ if (strlen(ptr) != strspn(ptr, "0123456789aAbBcCdDeEfF")) ++ return 1; ++ if (sscanf(ptr, "%" SCNx64 "", prkey) != 1) ++ return 1; ++ return 0; ++} ++ ++int safe_write(int fd, const void *buf, size_t count) ++{ ++ while (count > 0) { ++ ssize_t r = write(fd, buf, count); ++ if (r < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ return -errno; ++ } ++ count -= r; ++ buf = (char *)buf + r; ++ } ++ return 0; ++} +Index: multipath-tools-130222/libmultipath/util.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.h ++++ multipath-tools-130222/libmultipath/util.h +@@ -1,6 +1,8 @@ + #ifndef _UTIL_H + #define _UTIL_H + ++#include ++ + void strchop(char *); + int basenamecpy (const char * src, char * dst, int); + int filepresent (char * run); +@@ -12,6 +14,8 @@ int devt2devname (char *, int, char *); + dev_t parse_devt(const char *dev_t); + char *convert_dev(char *dev, int is_path_device); + int in_initrd(void); ++int parse_prkey(char *ptr, uint64_t *prkey); ++int safe_write(int fd, const void *buf, size_t count); + + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) +Index: multipath-tools-130222/multipathd/cli.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.c ++++ multipath-tools-130222/multipathd/cli.c +@@ -190,6 +190,10 @@ load_keys (void) + r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0); + r += add_key(keys, "format", FMT, 1); + r += add_key(keys, "json", JSON, 0); ++ r += add_key(keys, "getprkey", GETPRKEY, 0); ++ r += add_key(keys, "setprkey", SETPRKEY, 0); ++ r += add_key(keys, "unsetprkey", UNSETPRKEY, 0); ++ r += add_key(keys, "key", KEY, 1); + + if (r) { + free_keys(keys); +@@ -506,6 +510,9 @@ cli_init (void) { + add_handler(GETPRSTATUS+MAP, NULL); + add_handler(SETPRSTATUS+MAP, NULL); + add_handler(UNSETPRSTATUS+MAP, NULL); ++ add_handler(GETPRKEY+MAP, NULL); ++ add_handler(SETPRKEY+MAP+KEY, NULL); ++ add_handler(UNSETPRKEY+MAP, NULL); + add_handler(FORCEQ+DAEMON, NULL); + add_handler(RESTOREQ+DAEMON, NULL); + +Index: multipath-tools-130222/multipathd/cli.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli.h ++++ multipath-tools-130222/multipathd/cli.h +@@ -37,6 +37,10 @@ enum { + __UNSETPRSTATUS, + __FMT, + __JSON, ++ __GETPRKEY, ++ __SETPRKEY, ++ __UNSETPRKEY, ++ __KEY, + }; + + #define LIST (1 << __LIST) +@@ -76,6 +80,10 @@ enum { + #define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS) + #define FMT (1ULL << __FMT) + #define JSON (1ULL << __JSON) ++#define GETPRKEY (1ULL << __GETPRKEY) ++#define SETPRKEY (1ULL << __SETPRKEY) ++#define UNSETPRKEY (1ULL << __UNSETPRKEY) ++#define KEY (1ULL << __KEY) + + #define INITIAL_REPLY_LEN 1200 + +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "cli.h" +@@ -1234,3 +1235,71 @@ cli_unsetprstatus(void * v, char ** repl + + return 0; + } ++ ++int ++cli_getprkey(void * v, char ** reply, int * len, void * data) ++{ ++ struct multipath * mpp; ++ struct vectors * vecs = (struct vectors *)data; ++ char *mapname = get_keyparam(v, MAP); ++ ++ mapname = convert_dev(mapname, 0); ++ condlog(3, "%s: get persistent reservation key (operator)", mapname); ++ mpp = find_mp_by_str(vecs->mpvec, mapname); ++ ++ if (!mpp) ++ return 1; ++ ++ *reply = malloc(20); ++ ++ if (!get_be64(mpp->reservation_key)) { ++ sprintf(*reply, "none\n"); ++ *len = strlen(*reply) + 1; ++ return 0; ++ } ++ snprintf(*reply, 20, "0x%" PRIx64 "\n", ++ get_be64(mpp->reservation_key)); ++ (*reply)[19] = '\0'; ++ *len = strlen(*reply) + 1; ++ return 0; ++} ++ ++int ++cli_unsetprkey(void * v, char ** reply, int * len, void * data) ++{ ++ struct multipath * mpp; ++ struct vectors * vecs = (struct vectors *)data; ++ char *mapname = get_keyparam(v, MAP); ++ ++ mapname = convert_dev(mapname, 0); ++ condlog(3, "%s: unset persistent reservation key (operator)", mapname); ++ mpp = find_mp_by_str(vecs->mpvec, mapname); ++ ++ if (!mpp) ++ return 1; ++ ++ return set_prkey(mpp, 0); ++} ++ ++int cli_setprkey(void * v, char ** reply, int * len, void * data) ++{ ++ struct multipath * mpp; ++ struct vectors * vecs = (struct vectors *)data; ++ char *mapname = get_keyparam(v, MAP); ++ char *keyparam = get_keyparam(v, KEY); ++ uint64_t prkey; ++ ++ mapname = convert_dev(mapname, 0); ++ condlog(3, "%s: set persistent reservation key (operator)", mapname); ++ mpp = find_mp_by_str(vecs->mpvec, mapname); ++ ++ if (!mpp) ++ return 1; ++ ++ if (parse_prkey(keyparam, &prkey) != 0) { ++ condlog(0, "%s: invalid prkey : '%s'", mapname, keyparam); ++ return 1; ++ } ++ ++ return set_prkey(mpp, prkey); ++} +Index: multipath-tools-130222/multipathd/cli_handlers.h +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.h ++++ multipath-tools-130222/multipathd/cli_handlers.h +@@ -42,4 +42,6 @@ int cli_reassign (void * v, char ** repl + int cli_getprstatus(void * v, char ** reply, int * len, void * data); + int cli_setprstatus(void * v, char ** reply, int * len, void * data); + int cli_unsetprstatus(void * v, char ** reply, int * len, void * data); +- ++int cli_getprkey(void * v, char ** reply, int * len, void * data); ++int cli_setprkey(void * v, char ** reply, int * len, void * data); ++int cli_unsetprkey(void * v, char ** reply, int * len, void * data); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "pidfile.h" +@@ -1050,6 +1051,9 @@ uxlsnrloop (void * ap) + set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus); + set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus); + set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus); ++ set_handler_callback(GETPRKEY+MAP, cli_getprkey); ++ set_handler_callback(SETPRKEY+MAP+KEY, cli_setprkey); ++ set_handler_callback(UNSETPRKEY+MAP, cli_unsetprkey); + set_handler_callback(FORCEQ+DAEMON, cli_force_no_daemon_q); + set_handler_callback(RESTOREQ+DAEMON, cli_restore_no_daemon_q); + +@@ -2266,10 +2270,8 @@ main (int argc, char *argv[]) + void * mpath_pr_event_handler_fn (void * pathp ) + { + struct multipath * mpp; +- int i,j, ret, isFound; ++ int i, ret, isFound; + struct path * pp = (struct path *)pathp; +- unsigned char *keyp; +- uint64_t prkey; + struct prout_param_descriptor *param; + struct prin_resp *resp; + +@@ -2297,22 +2299,15 @@ void * mpath_pr_event_handler_fn (void + ret = MPATH_PR_SUCCESS; + goto out; + } +- prkey = 0; +- keyp = (unsigned char *)mpp->reservation_key; +- for (j = 0; j < 8; ++j) { +- if (j > 0) +- prkey <<= 8; +- prkey |= *keyp; +- ++keyp; +- } +- condlog(2, "Multipath reservation_key: 0x%" PRIx64 " ", prkey); ++ condlog(2, "Multipath reservation_key: 0x%" PRIx64 " ", ++ get_be64(mpp->reservation_key)); + + isFound =0; + for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ ) + { + condlog(2, "PR IN READKEYS[%d] reservation key:",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)) ++ if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8)) + { + condlog(2, "%s: pr key found in prin readkeys response", mpp->alias); + isFound =1; +@@ -2329,11 +2324,7 @@ void * mpath_pr_event_handler_fn (void + + param= malloc(sizeof(struct prout_param_descriptor)); + memset(param, 0 , sizeof(struct prout_param_descriptor)); +- +- for (j = 7; j >= 0; --j) { +- param->sa_key[j] = (prkey & 0xff); +- prkey >>= 8; +- } ++ memcpy(param->sa_key, &mpp->reservation_key, 8); + param->num_transportid = 0; + + condlog(3, "device %s:%s", pp->dev, pp->mpp->wwid); +@@ -2360,7 +2351,7 @@ int mpath_pr_event_handle(struct path *p + + mpp = pp->mpp; + +- if (!mpp->reservation_key) ++ if (!get_be64(mpp->reservation_key)) + return -1; + + pthread_attr_init(&attr); +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -16,7 +16,7 @@ OBJS = memory.o parser.o vector.o devmap + pgpolicies.o debug.o regex.o defaults.o uevent.o \ + switchgroup.o uxsock.o print.o alias.o log_pthread.o \ + log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \ +- lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o ++ lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o + + LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h) + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -414,6 +414,13 @@ of the wwids for LUNs it has created mul + Defaults to + .I /etc/multipath/wwids + .TP ++.B prkeys_file ++The full pathname of the prkeys file, which is used by multipathd to keep ++track of the reservation key used for a specific WWID, when ++\fIreservation_key\fR is set to \fIfile\fR. ++Defaults to ++.I /etc/multipath/prkeys ++.TP + .B log_checker_err + If set to + .I once +@@ -428,7 +435,16 @@ This is the service action reservation k + set for all multipath devices using persistent reservations, and it must be + the same as the RESERVATION KEY field of the PERSISTENT RESERVE OUT parameter + list which contains an 8-byte value provided by the application client to the +-device server to identify the I_T nexus. It is unset by default. ++device server to identify the I_T nexus. ++.RS ++.PP ++Alternatively, this can be set to \fBfile\fR, which will store the RESERVATION ++KEY registered by mpathpersist in the \fIprkeys_file\fR. multipathd will then ++use this key to register additional paths as they appear. When the ++registration is removed, the RESERVATION KEY is removed from the ++\fIprkeys_file\fR. ++It is unset by default. ++.RE + .TP + .B retain_attached_hw_handler + If set to +Index: multipath-tools-130222/multipathd/multipathd.8 +=================================================================== +--- multipath-tools-130222.orig/multipathd/multipathd.8 ++++ multipath-tools-130222/multipathd/multipathd.8 +@@ -161,6 +161,19 @@ Disable persistent reservation managemen + .B map|multipath $map getprstatus + Get the current persistent reservation management status of $map + .TP ++.B map|multipath $map getprkey ++Get the current persistent reservation key associated with $map. ++.TP ++.B map|multipath $map setprkey key $key ++Set the persistent reservation key associated with $map to $key in the ++\fIprkeys_file\fR. This key will only be used by multipathd if ++\fIreservation_key\fR is set to \fIfile\fR in \fI/etc/multipath.conf\fR. ++.TP ++.B map|multipath $map unsetprkey ++Remove the persistent reservation key associated with $map from the ++\fIprkeys_file\fR. This will only unset the key used by multipathd if ++\fIreservation_key\fR is set to \fIfile\fR in \fI/etc/multipath.conf\fR. ++.TP + .B quit|exit + End interactive session. + .TP +Index: multipath-tools-130222/mpathpersist/main.c +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.c ++++ multipath-tools-130222/mpathpersist/main.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -139,7 +140,7 @@ int main (int argc, char * argv[]) + ++num_prout_param; + break; + case 'K': +- if (1 != sscanf (optarg, "%" SCNx64 "", ¶m_rk)) ++ if (parse_prkey(optarg, ¶m_rk) != 0) + { + fprintf (stderr, "bad argument to '--param-rk'\n"); + return MPATH_PR_SYNTAX_ERROR; +@@ -148,7 +149,7 @@ int main (int argc, char * argv[]) + break; + + case 'S': +- if (1 != sscanf (optarg, "%" SCNx64 "", ¶m_sark)) ++ if (parse_prkey(optarg, ¶m_sark) != 0) + { + fprintf (stderr, "bad argument to '--param-sark'\n"); + return MPATH_PR_SYNTAX_ERROR; diff --git a/SOURCES/0225-RH-udevdir.patch b/SOURCES/0225-RH-udevdir.patch new file mode 100644 index 0000000..b3c891f --- /dev/null +++ b/SOURCES/0225-RH-udevdir.patch @@ -0,0 +1,46 @@ +--- + Makefile.inc | 2 +- + multipath/Makefile | 10 +++++----- + 2 files changed, 6 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/multipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/multipath/Makefile ++++ multipath-tools-130222/multipath/Makefile +@@ -24,9 +24,9 @@ install: + $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + $(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/ +- $(INSTALL_PROGRAM) -d $(DESTDIR)/usr/lib/udev/rules.d +- $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules +- $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)/usr/lib/udev/rules.d/11-dm-mpath.rules ++ $(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)/rules.d ++ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules ++ $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(libudevdir)/rules.d/11-dm-mpath.rules + $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir) +@@ -34,8 +34,8 @@ install: + $(INSTALL_PROGRAM) -m 644 mpathconf.8.gz $(DESTDIR)$(mandir) + + uninstall: +- rm $(DESTDIR)/usr/lib/udev/rules.d/62-multipath.rules +- rm $(DESTDIR)/usr/lib/udev/rules.d/11-dm-mpath.rules ++ rm $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules ++ rm $(DESTDIR)$(libudevdir)/rules.d/11-dm-mpath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) + rm $(DESTDIR)$(bindir)/mpathconf + rm $(DESTDIR)$(mandir)/$(EXEC).8.gz +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -24,7 +24,7 @@ endif + prefix = + exec_prefix = $(prefix) + bindir = $(exec_prefix)/usr/sbin +-libudevdir = ${prefix}/lib/udev ++libudevdir = ${prefix}/usr/lib/udev + multipathdir = $(TOPDIR)/libmultipath + mandir = $(prefix)/usr/share/man/man8 + man5dir = $(prefix)/usr/share/man/man5 diff --git a/SOURCES/0226-RH-allow-overrides-section.patch b/SOURCES/0226-RH-allow-overrides-section.patch new file mode 100644 index 0000000..6b1dec1 --- /dev/null +++ b/SOURCES/0226-RH-allow-overrides-section.patch @@ -0,0 +1,64 @@ +--- + libmultipath/dict.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -3721,6 +3721,18 @@ snprint_bled_product (char * buff, int l + + #define __deprecated + ++static int ++nop_handler(vector strvec) ++{ ++ return 0; ++} ++ ++static int ++snprint_nop(char * buff, int len, void * data) ++{ ++ return 0; ++} ++ + void + init_keywords(void) + { +@@ -3853,6 +3865,36 @@ init_keywords(void) + install_keyword("unpriv_sgio", &hw_unpriv_sgio_handler, &snprint_hw_unpriv_sgio); + install_sublevel_end(); + ++ install_keyword_root("overrides", &nop_handler); ++ install_keyword("path_grouping_policy", &nop_handler, &snprint_nop); ++ install_keyword("uid_attribute", &nop_handler, &snprint_nop); ++ install_keyword("path_selector", &nop_handler, &snprint_nop); ++ install_keyword("path_checker", &nop_handler, &snprint_nop); ++ install_keyword("checker", &nop_handler, &snprint_nop); ++ install_keyword("alias_prefix", &nop_handler, &snprint_nop); ++ install_keyword("features", &nop_handler, &snprint_nop); ++ install_keyword("hardware_handler", &nop_handler, &snprint_nop); ++ install_keyword("prio", &nop_handler, &snprint_nop); ++ install_keyword("prio_args", &nop_handler, &snprint_nop); ++ install_keyword("failback", &nop_handler, &snprint_nop); ++ install_keyword("rr_weight", &nop_handler, &snprint_nop); ++ install_keyword("no_path_retry", &nop_handler, &snprint_nop); ++ install_keyword("rr_min_io", &nop_handler, &snprint_nop); ++ install_keyword("rr_min_io_rq", &nop_handler, &snprint_nop); ++ install_keyword("pg_timeout", &nop_handler, &snprint_nop); ++ install_keyword("flush_on_last_del", &nop_handler, &snprint_nop); ++ install_keyword("fast_io_fail_tmo", &nop_handler, &snprint_nop); ++ install_keyword("dev_loss_tmo", &nop_handler, &snprint_nop); ++ install_keyword("user_friendly_names", &nop_handler, &snprint_nop); ++ install_keyword("retain_attached_hw_handler", &nop_handler, &snprint_nop); ++ install_keyword("detect_prio", &nop_handler, &snprint_nop); ++ install_keyword("detect_path_checker", &nop_handler, &snprint_nop); ++ install_keyword("deferred_remove", &nop_handler, &snprint_nop); ++ install_keyword("delay_watch_checks", &nop_handler, &snprint_nop); ++ install_keyword("delay_wait_checks", &nop_handler, &snprint_nop); ++ install_keyword("skip_kpartx", &nop_handler, &snprint_nop); ++ install_keyword("max_sectors_kb", &nop_handler, &snprint_nop); ++ + install_keyword_root("multipaths", &multipaths_handler); + install_keyword_multi("multipath", &multipath_handler, NULL); + install_sublevel(); diff --git a/SOURCES/0227-RHBZ-1465773-fix-path-delay-msg.patch b/SOURCES/0227-RHBZ-1465773-fix-path-delay-msg.patch new file mode 100644 index 0000000..ed24a17 --- /dev/null +++ b/SOURCES/0227-RHBZ-1465773-fix-path-delay-msg.patch @@ -0,0 +1,17 @@ +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -538,7 +538,7 @@ ev_add_path (struct path * pp, struct ve + pp->tpgs == TPGS_IMPLICIT)) + mpp->force_udev_reload = 1; + else { +- condlog(2, "%s : delaying path addition until %s is fully initialized", pp->dev, mpp->alias); ++ condlog(2, "%s [%s]: delaying path addition until %s is fully initialized", pp->dev, pp->dev_t, mpp->alias); + mpp->wait_for_udev = 2; + orphan_path(pp); + return 0; diff --git a/SOURCES/0228-RHBZ-1464634-hauwei-config-update.patch b/SOURCES/0228-RHBZ-1464634-hauwei-config-update.patch new file mode 100644 index 0000000..a72c39b --- /dev/null +++ b/SOURCES/0228-RHBZ-1464634-hauwei-config-update.patch @@ -0,0 +1,22 @@ +--- + libmultipath/hwtable.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1163,9 +1163,12 @@ static struct hwentry default_hw[] = { + .product = "XSG1", + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, +- .pgpolicy = MULTIBUS, ++ .pgpolicy = GROUP_BY_PRIO, ++ .prio_name = PRIO_ALUA, ++ .prio_args = NULL, + .pgfailback = -FAILBACK_IMMEDIATE, + .checker_name = TUR, ++ .dev_loss = 30, + }, + { + /* diff --git a/SOURCES/0229-RHBZ-1467987-poll-on-udev-monitor.patch b/SOURCES/0229-RHBZ-1467987-poll-on-udev-monitor.patch new file mode 100644 index 0000000..46723d7 --- /dev/null +++ b/SOURCES/0229-RHBZ-1467987-poll-on-udev-monitor.patch @@ -0,0 +1,38 @@ +--- + libmultipath/uevent.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +Index: multipath-tools-130222/libmultipath/uevent.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.c ++++ multipath-tools-130222/libmultipath/uevent.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #include "memory.h" + #include "debug.h" +@@ -460,6 +461,21 @@ int uevent_listen(struct udev *udev) + struct uevent *uev; + struct udev_device *dev; + struct udev_list_entry *list_entry; ++ struct pollfd ev_poll; ++ int fdcount; ++ ++ memset(&ev_poll, 0, sizeof(struct pollfd)); ++ ev_poll.fd = fd; ++ ev_poll.events = POLLIN; ++ errno = 0; ++ fdcount = poll(&ev_poll, 1, -1); ++ if (fdcount <= 0 || !(ev_poll.revents & POLLIN)) { ++ if (!errno || errno == EINTR) ++ continue; ++ condlog(0, "error receiving uevent message"); ++ err = -errno; ++ break; ++ } + + dev = udev_monitor_receive_device(monitor); + if (!dev) { diff --git a/SOURCES/0230-UP-allow-invalid-creates.patch b/SOURCES/0230-UP-allow-invalid-creates.patch new file mode 100644 index 0000000..6f6cb4d --- /dev/null +++ b/SOURCES/0230-UP-allow-invalid-creates.patch @@ -0,0 +1,81 @@ +--- + libmultipath/devmapper.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -264,12 +264,15 @@ dm_device_remove (const char *name, int + + static int + dm_addmap (int task, const char *target, struct multipath *mpp, char * params, +- int use_uuid, int ro, int skip_kpartx) { ++ int use_uuid, int ro, uint16_t udev_flags) { + int r = 0; + struct dm_task *dmt; + char *prefixed_uuid = NULL; + uint32_t cookie = 0; +- uint16_t udev_flags = ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0); ++ ++ /* Need to add this here to allow 0 to be passed in udev_flags */ ++ if (conf->daemon) ++ udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK; + + if (!(dmt = dm_task_create (task))) + return 0; +@@ -326,16 +329,28 @@ dm_addmap (int task, const char *target, + return r; + } + ++static uint16_t build_udev_flags(const struct multipath *mpp, int reload) ++{ ++ /* DM_UDEV_DISABLE_LIBRARY_FALLBACK is added in dm_addmap */ ++ return (mpp->skip_kpartx == SKIP_KPARTX_ON ? ++ MPATH_UDEV_NO_KPARTX_FLAG : 0) | ++ (mpp->nr_active == 0 ? ++ MPATH_UDEV_NO_PATHS_FLAG : 0) | ++ (reload && !mpp->force_udev_reload ? ++ MPATH_UDEV_RELOAD_FLAG : 0); ++} ++ + extern int + dm_addmap_create (struct multipath *mpp, char * params) { + int ro; ++ uint16_t udev_flags = build_udev_flags(mpp, 0); + + sysfs_set_max_sectors_kb(mpp, 0); + for (ro = 0; ro <= 1; ro++) { + int err; + + if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, +- mpp, params, 1, ro, mpp->skip_kpartx)) ++ mpp, params, 1, ro, udev_flags)) + return 1; + /* + * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD. +@@ -358,21 +373,17 @@ dm_addmap_create (struct multipath *mpp, + extern int + dm_addmap_reload (struct multipath *mpp, char *params, int flush) { + int r = 0; +- uint16_t udev_flags = ((mpp->force_udev_reload)? +- 0 : MPATH_UDEV_RELOAD_FLAG) | +- ((mpp->skip_kpartx == SKIP_KPARTX_ON)? +- MPATH_UDEV_NO_KPARTX_FLAG : 0) | +- ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG); ++ uint16_t udev_flags = build_udev_flags(mpp, 1); + + sysfs_set_max_sectors_kb(mpp, 1); + if (!mpp->force_readonly) + r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, +- ADDMAP_RW, SKIP_KPARTX_OFF); ++ ADDMAP_RW, 0); + if (!r) { + if (!mpp->force_readonly && errno != EROFS) + return 0; + r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, +- ADDMAP_RO, SKIP_KPARTX_OFF); ++ ADDMAP_RO, 0); + } + if (r) + r = dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush, diff --git a/SOURCES/0231-RHBZ-1458852-delay-readying.patch b/SOURCES/0231-RHBZ-1458852-delay-readying.patch new file mode 100644 index 0000000..953fd3c --- /dev/null +++ b/SOURCES/0231-RHBZ-1458852-delay-readying.patch @@ -0,0 +1,489 @@ +--- + libmultipath/config.c | 4 + + libmultipath/config.h | 3 + + libmultipath/defaults.h | 1 + libmultipath/devmapper.c | 19 ++++++-- + libmultipath/dict.c | 104 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/propsel.c | 26 +++++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 7 +++ + multipath/multipath.conf.5 | 13 +++++ + multipath/multipath.rules | 1 + multipathd/main.c | 27 +++++++++++ + 11 files changed, 202 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -348,6 +348,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(skip_kpartx); + merge_num(max_sectors_kb); + merge_num(unpriv_sgio); ++ merge_num(ghost_delay); + + /* + * Make sure features is consistent with +@@ -412,6 +413,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(skip_kpartx); + overwrite_num(max_sectors_kb); + overwrite_num(unpriv_sgio); ++ overwrite_num(ghost_delay); + + /* + * Make sure features is consistent with +@@ -482,6 +484,7 @@ store_hwe (vector hwtable, struct hwentr + hwe->retain_hwhandler = dhwe->retain_hwhandler; + hwe->detect_prio = dhwe->detect_prio; + hwe->detect_checker = dhwe->detect_checker; ++ hwe->ghost_delay = dhwe->ghost_delay; + + if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product))) + goto out; +@@ -694,6 +697,7 @@ load_config (char * file, struct udev *u + conf->disable_changed_wwids = 0; + conf->max_sectors_kb = DEFAULT_MAX_SECTORS_KB; + conf->unpriv_sgio = DEFAULT_UNPRIV_SGIO; ++ conf->ghost_delay = DEFAULT_GHOST_DELAY; + + /* + * preload default hwtable +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -70,6 +70,7 @@ struct hwentry { + int skip_kpartx; + int max_sectors_kb; + int unpriv_sgio; ++ int ghost_delay; + char * bl_product; + }; + +@@ -100,6 +101,7 @@ struct mpentry { + int skip_kpartx; + int max_sectors_kb; + int unpriv_sgio; ++ int ghost_delay; + uid_t uid; + gid_t gid; + mode_t mode; +@@ -159,6 +161,7 @@ struct config { + int disable_changed_wwids; + int max_sectors_kb; + int unpriv_sgio; ++ int ghost_delay; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -28,6 +28,7 @@ + #define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF + #define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF + #define DEFAULT_UNPRIV_SGIO UNPRIV_SGIO_OFF ++#define DEFAULT_GHOST_DELAY GHOST_DELAY_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/devmapper.c ++++ multipath-tools-130222/libmultipath/devmapper.c +@@ -23,6 +23,7 @@ + #include "sysfs.h" + #include "discovery.h" + #include "log_pthread.h" ++#include "propsel.h" + #include + #include + +@@ -334,7 +335,7 @@ static uint16_t build_udev_flags(const s + /* DM_UDEV_DISABLE_LIBRARY_FALLBACK is added in dm_addmap */ + return (mpp->skip_kpartx == SKIP_KPARTX_ON ? + MPATH_UDEV_NO_KPARTX_FLAG : 0) | +- (mpp->nr_active == 0 ? ++ ((mpp->nr_active == 0 || mpp->ghost_delay_tick > 0)? + MPATH_UDEV_NO_PATHS_FLAG : 0) | + (reload && !mpp->force_udev_reload ? + MPATH_UDEV_RELOAD_FLAG : 0); +@@ -343,8 +344,16 @@ static uint16_t build_udev_flags(const s + extern int + dm_addmap_create (struct multipath *mpp, char * params) { + int ro; +- uint16_t udev_flags = build_udev_flags(mpp, 0); ++ uint16_t udev_flags; + ++ select_ghost_delay(mpp); ++ if (conf->daemon && mpp->ghost_delay > 0 && mpp->nr_active && ++ pathcount(mpp, PATH_GHOST) == mpp->nr_active) ++ mpp->ghost_delay_tick = mpp->ghost_delay; ++ else ++ mpp->ghost_delay = 0; ++ ++ udev_flags = build_udev_flags(mpp, 0); + sysfs_set_max_sectors_kb(mpp, 0); + for (ro = 0; ro <= 1; ro++) { + int err; +@@ -373,7 +382,11 @@ dm_addmap_create (struct multipath *mpp, + extern int + dm_addmap_reload (struct multipath *mpp, char *params, int flush) { + int r = 0; +- uint16_t udev_flags = build_udev_flags(mpp, 1); ++ uint16_t udev_flags; ++ ++ if (mpp->ghost_delay_tick > 0 && pathcount(mpp, PATH_UP)) ++ mpp->ghost_delay_tick = mpp->ghost_delay = 0; ++ udev_flags = build_udev_flags(mpp, 1); + + sysfs_set_max_sectors_kb(mpp, 1); + if (!mpp->force_readonly) +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -1032,6 +1032,25 @@ def_unpriv_sgio_handler(vector strvec) + return 0; + } + ++static int ++def_ghost_delay_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->ghost_delay = GHOST_DELAY_OFF; ++ if ((conf->ghost_delay = atoi(buff)) < 0) ++ conf->ghost_delay = DEFAULT_GHOST_DELAY; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1895,6 +1914,29 @@ hw_unpriv_sgio_handler(vector strvec) + return 0; + } + ++static int ++hw_ghost_delay_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->ghost_delay = GHOST_DELAY_OFF; ++ if ((hwe->ghost_delay = atoi(buff)) < 0) ++ hwe->ghost_delay = DEFAULT_GHOST_DELAY; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -2474,6 +2516,29 @@ mp_unpriv_sgio_handler(vector strvec) + return 0; + } + ++static int ++mp_ghost_delay_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->ghost_delay = GHOST_DELAY_OFF; ++ if ((mpe->ghost_delay = atoi(buff)) < 0) ++ mpe->ghost_delay = DEFAULT_GHOST_DELAY; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2788,6 +2853,19 @@ snprint_mp_unpriv_sgio (char * buff, int + } + + static int ++snprint_mp_ghost_delay (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->ghost_delay == GHOST_DELAY_UNDEF) ++ return 0; ++ else if (mpe->ghost_delay == GHOST_DELAY_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "%d", mpe->ghost_delay); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -3202,6 +3280,19 @@ snprint_hw_unpriv_sgio(char * buff, int + } + + static int ++snprint_hw_ghost_delay (char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->ghost_delay == GHOST_DELAY_UNDEF) ++ return 0; ++ else if (hwe->ghost_delay == GHOST_DELAY_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "%d", hwe->ghost_delay); ++} ++ ++static int + snprint_def_polling_interval (char * buff, int len, void * data) + { + return snprintf(buff, len, "%i", conf->checkint); +@@ -3696,6 +3787,16 @@ snprint_def_unpriv_sgio(char * buff, int + } + + static int ++snprint_def_ghost_delay (char * buff, int len, void * data) ++{ ++ if (conf->ghost_delay == GHOST_DELAY_OFF || ++ conf->ghost_delay == GHOST_DELAY_UNDEF) ++ return snprintf(buff, len, "no"); ++ else ++ return snprintf(buff, len, "%d", conf->ghost_delay); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3792,6 +3893,7 @@ init_keywords(void) + install_keyword("disable_changed_wwids", &def_disable_changed_wwids_handler, &snprint_def_disable_changed_wwids); + install_keyword("max_sectors_kb", &def_max_sectors_kb_handler, &snprint_def_max_sectors_kb); + install_keyword("unpriv_sgio", &def_unpriv_sgio_handler, &snprint_def_unpriv_sgio); ++ install_keyword("ghost_delay", &def_ghost_delay_handler, &snprint_def_ghost_delay); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -3863,6 +3965,7 @@ init_keywords(void) + install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx); + install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb); + install_keyword("unpriv_sgio", &hw_unpriv_sgio_handler, &snprint_hw_unpriv_sgio); ++ install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay); + install_sublevel_end(); + + install_keyword_root("overrides", &nop_handler); +@@ -3923,5 +4026,6 @@ init_keywords(void) + install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx); + install_keyword("max_sectors_kb", &mp_max_sectors_kb_handler, &snprint_mp_max_sectors_kb); + install_keyword("unpriv_sgio", &mp_unpriv_sgio_handler, &snprint_mp_unpriv_sgio); ++ install_keyword("ghost_delay", &mp_ghost_delay_handler, &snprint_mp_ghost_delay); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -966,3 +966,29 @@ select_unpriv_sgio (struct multipath * m + condlog(3, "unpriv_sgio = DISABLED (internal default)"); + return 0; + } ++ ++extern int ++select_ghost_delay (struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->ghost_delay != GHOST_DELAY_UNDEF) { ++ mp->ghost_delay = mp->mpe->ghost_delay; ++ condlog(3, "ghost_delay = %i (multipath setting)", ++ mp->ghost_delay); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->ghost_delay != GHOST_DELAY_UNDEF) { ++ mp->ghost_delay = mp->hwe->ghost_delay; ++ condlog(3, "ghost_delay = %i (controler setting)", ++ mp->ghost_delay); ++ return 0; ++ } ++ if (conf->ghost_delay != GHOST_DELAY_UNDEF) { ++ mp->ghost_delay = conf->ghost_delay; ++ condlog(3, "ghost_delay = %i (config file default)", ++ mp->ghost_delay); ++ return 0; ++ } ++ mp->ghost_delay = DEFAULT_GHOST_DELAY; ++ condlog(3, "ghost_delay = DISABLED (internal default)"); ++ return 0; ++} +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -27,3 +27,4 @@ int select_delay_wait_checks (struct mul + int select_skip_kpartx (struct multipath * mp); + int select_max_sectors_kb (struct multipath * mp); + int select_unpriv_sgio (struct multipath * mp); ++int select_ghost_delay (struct multipath * mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -176,6 +176,11 @@ enum prkey_sources { + PRKEY_SOURCE_FILE, + }; + ++enum ghost_delay_states { ++ GHOST_DELAY_OFF = -1, ++ GHOST_DELAY_UNDEF = 0, ++}; ++ + struct sg_id { + int host_no; + int channel; +@@ -273,6 +278,8 @@ struct multipath { + int max_sectors_kb; + int force_readonly; + int unpriv_sgio; ++ int ghost_delay; ++ int ghost_delay_tick; + unsigned int dev_loss; + uid_t uid; + gid_t gid; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -195,6 +195,8 @@ sync_map_state(struct multipath *mpp) + pp->state == PATH_WILD || + pp->state == PATH_DELAYED) + continue; ++ if (mpp->ghost_delay_tick > 0) ++ continue; + if ((pp->dmstate == PSTATE_FAILED || + pp->dmstate == PSTATE_UNDEF) && + (pp->state == PATH_UP || pp->state == PATH_GHOST)) +@@ -535,7 +537,7 @@ ev_add_path (struct path * pp, struct ve + if (mpp && mpp->wait_for_udev) { + if (pathcount(mpp, PATH_UP) == 0 && + (pathcount(mpp, PATH_GHOST) == 0 || +- pp->tpgs == TPGS_IMPLICIT)) ++ mpp->ghost_delay_tick > 0 || pp->tpgs == TPGS_IMPLICIT)) + mpp->force_udev_reload = 1; + else { + condlog(2, "%s [%s]: delaying path addition until %s is fully initialized", pp->dev, pp->dev_t, mpp->alias); +@@ -1215,6 +1217,28 @@ missing_uev_wait_tick(struct vectors *ve + } + + static void ++ghost_delay_tick(struct vectors *vecs) ++{ ++ struct multipath * mpp; ++ unsigned int i; ++ ++ vector_foreach_slot (vecs->mpvec, mpp, i) { ++ if (mpp->ghost_delay_tick <= 0) ++ continue; ++ if (--mpp->ghost_delay_tick <= 0) { ++ condlog(0, "%s: timed out waiting for active path", ++ mpp->alias); ++ if (update_map(mpp, vecs) != 0) { ++ /* update_map removed map */ ++ i--; ++ continue; ++ } ++ mpp->ghost_delay = mpp->ghost_delay_tick = 0; ++ } ++ } ++} ++ ++static void + defered_failback_tick (vector mpvec) + { + struct multipath * mpp; +@@ -1560,6 +1584,7 @@ checkerloop (void *ap) + defered_failback_tick(vecs->mpvec); + retry_count_tick(vecs->mpvec); + missing_uev_wait_tick(vecs); ++ ghost_delay_tick(vecs); + } + if (count) + count--; +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -55,6 +55,7 @@ ENV{DM_SUBSYSTEM_UDEV_FLAG1}=="1", GOTO= + ENV{DM_ACTIVATION}=="1", ENV{DM_MULTIPATH_NEED_KPARTX}="1" + ENV{DM_SUSPENDED}=="1", GOTO="end_mpath" + ENV{DM_ACTION}=="PATH_FAILED", GOTO="end_mpath" ++ENV{DM_NOSCAN}=="1", GOTO="end_mpath" + ENV{DM_ACTIVATION}!="1", ENV{DM_MULTIPATH_NEED_KPARTX}!="1", GOTO="end_mpath" + RUN+="$env{MPATH_SBIN_PATH}/kpartx -an $tempnode", \ + ENV{DM_MULTIPATH_NEED_KPARTX}="" +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -601,6 +601,15 @@ device to the specified value. Default i + If set to \fIyes\fR, multipath will set upriv_sgio on the multipath device and + all its paths, when it is created or reloaded. The default is + .I no ++.TP ++.B ghost_delay ++Sets the number of seconds that multipath will wait after creating a device ++with only ghost paths before marking it ready for use in systemd. This gives ++the active paths time to appear before the multipath runs the hardware handler ++to switch the ghost paths to active ones. Setting this to \fI0\fR or \fIoff\fR ++makes multipath immediately mark a device with only ghost paths as ready. The ++default is ++.I off + . + .SH "blacklist section" + The +@@ -716,6 +725,8 @@ section: + .B max_sectors_kb + .TP + .B unpriv_sgio ++.TP ++.B ghost_delay + .RE + .PD + .LP +@@ -820,6 +831,8 @@ section: + .B max_sectors_kb + .TP + .B unpriv_sgio ++.TP ++.B ghost_delay + .RE + .PD + .LP diff --git a/SOURCES/0232-RHBZ-1456955-property-blacklist.patch b/SOURCES/0232-RHBZ-1456955-property-blacklist.patch new file mode 100644 index 0000000..bebaa4e --- /dev/null +++ b/SOURCES/0232-RHBZ-1456955-property-blacklist.patch @@ -0,0 +1,501 @@ +--- + libmultipath/blacklist.c | 79 +++++++++++++++++++++++++++++++++++++++++---- + libmultipath/blacklist.h | 5 ++ + libmultipath/config.c | 20 ++++++++++- + libmultipath/config.h | 2 + + libmultipath/configure.c | 8 ++++ + libmultipath/dict.c | 38 ++++++++++++++++++++- + libmultipath/discovery.c | 2 + + libmultipath/print.c | 31 +++++++++++++++++ + multipath/multipath.conf.5 | 27 ++++++++++++++- + 9 files changed, 200 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/libmultipath/blacklist.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.c ++++ multipath-tools-130222/libmultipath/blacklist.c +@@ -2,6 +2,7 @@ + * Copyright (c) 2004, 2005 Christophe Varoqui + */ + #include ++#include + + #include "checkers.h" + #include "memory.h" +@@ -102,7 +103,7 @@ set_ble_device (vector blist, char * ven + } + + int +-_blacklist_exceptions (vector elist, char * str) ++_blacklist_exceptions (vector elist, const char * str) + { + int i; + struct blentry * ele; +@@ -115,7 +116,7 @@ _blacklist_exceptions (vector elist, cha + } + + int +-_blacklist (vector blist, char * str) ++_blacklist (vector blist, const char * str) + { + int i; + struct blentry * ble; +@@ -208,11 +209,14 @@ setup_default_blist (struct config * con + condlog(3, "%s: (%s:%s) %s", dev, vendor, product, (M)); \ + else if (wwid) \ + condlog(3, "%s: (%s) %s", dev, wwid, (M)); \ ++ else if (env) \ ++ condlog(3, "%s: (%s) %s", dev, env, (M)); \ + else \ + condlog(3, "%s: %s", dev, (M)) + + void +-log_filter (char *dev, char *vendor, char *product, char *wwid, int r) ++log_filter (const char *dev, char *vendor, char *product, char *wwid, ++ const char *env, int r) + { + /* + * Try to sort from most likely to least. +@@ -229,6 +233,9 @@ log_filter (char *dev, char *vendor, cha + case MATCH_DEVNODE_BLIST: + LOG_BLIST("device node name blacklisted"); + break; ++ case MATCH_PROPERTY_BLIST: ++ LOG_BLIST("udev property blacklisted"); ++ break; + case MATCH_DEVICE_BLIST_EXCEPT: + LOG_BLIST("vendor/product whitelisted"); + break; +@@ -238,6 +245,12 @@ log_filter (char *dev, char *vendor, cha + case MATCH_DEVNODE_BLIST_EXCEPT: + LOG_BLIST("device node name whitelisted"); + break; ++ case MATCH_PROPERTY_BLIST_EXCEPT: ++ LOG_BLIST("udev property whitelisted"); ++ break; ++ case MATCH_PROPERTY_BLIST_MISSING: ++ LOG_BLIST("blacklisted, udev property missing"); ++ break; + } + } + +@@ -257,7 +270,7 @@ int + filter_device (vector blist, vector elist, char * vendor, char * product) + { + int r = _filter_device(blist, elist, vendor, product); +- log_filter(NULL, vendor, product, NULL, r); ++ log_filter(NULL, vendor, product, NULL, NULL, r); + return r; + } + +@@ -277,7 +290,7 @@ int + filter_devnode (vector blist, vector elist, char * dev) + { + int r = _filter_devnode(blist, elist, dev); +- log_filter(dev, NULL, NULL, NULL, r); ++ log_filter(dev, NULL, NULL, NULL, NULL, r); + return r; + } + +@@ -297,15 +310,67 @@ int + filter_wwid (vector blist, vector elist, char * wwid) + { + int r = _filter_wwid(blist, elist, wwid); +- log_filter(NULL, NULL, NULL, wwid, r); ++ log_filter(NULL, NULL, NULL, wwid, NULL, r); + return r; + } + + int ++_filter_property (struct config *conf, const char *env) ++{ ++ if (_blacklist_exceptions(conf->elist_property, env)) ++ return MATCH_PROPERTY_BLIST_EXCEPT; ++ if (_blacklist(conf->blist_property, env)) ++ return MATCH_PROPERTY_BLIST; ++ ++ return 0; ++} ++ ++int ++filter_property(struct config * conf, struct udev_device * udev) ++{ ++ const char *devname = udev_device_get_sysname(udev); ++ struct udev_list_entry *list_entry; ++ int r; ++ ++ if (!udev || (!VECTOR_SIZE(conf->elist_property) && ++ !VECTOR_SIZE(conf->blist_property))) ++ return 0; ++ ++ udev_list_entry_foreach(list_entry, ++ udev_device_get_properties_list_entry(udev)) { ++ const char *env; ++ ++ env = udev_list_entry_get_name(list_entry); ++ if (!env) ++ continue; ++ ++ r = _filter_property(conf, env); ++ if (r) { ++ log_filter(devname, NULL, NULL, NULL, env, r); ++ return r; ++ } ++ } ++ ++ /* ++ * This is the inverse of the 'normal' matching; ++ * the environment variable _has_ to match. ++ */ ++ if (VECTOR_SIZE(conf->elist_property)) { ++ log_filter(devname, NULL, NULL, NULL, NULL, ++ MATCH_PROPERTY_BLIST_MISSING); ++ return MATCH_PROPERTY_BLIST_MISSING; ++ } ++ return 0; ++} ++ ++int + _filter_path (struct config * conf, struct path * pp) + { + int r; + ++ r = filter_property(conf, pp->udev); ++ if (r > 0) ++ return r; + r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev); + if (r > 0) + return r; +@@ -321,7 +386,7 @@ int + filter_path (struct config * conf, struct path * pp) + { + int r=_filter_path(conf, pp); +- log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, r); ++ log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, r); + return r; + } + +Index: multipath-tools-130222/libmultipath/blacklist.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.h ++++ multipath-tools-130222/libmultipath/blacklist.h +@@ -1,15 +1,19 @@ + #ifndef _BLACKLIST_H + #define _BLACKLIST_H + ++#include + #include "regex.h" + + #define MATCH_NOTHING 0 + #define MATCH_WWID_BLIST 1 + #define MATCH_DEVICE_BLIST 2 + #define MATCH_DEVNODE_BLIST 3 ++#define MATCH_PROPERTY_BLIST 4 ++#define MATCH_PROPERTY_BLIST_MISSING 5 + #define MATCH_WWID_BLIST_EXCEPT -MATCH_WWID_BLIST + #define MATCH_DEVICE_BLIST_EXCEPT -MATCH_DEVICE_BLIST + #define MATCH_DEVNODE_BLIST_EXCEPT -MATCH_DEVNODE_BLIST ++#define MATCH_PROPERTY_BLIST_EXCEPT -MATCH_PROPERTY_BLIST + + struct blentry { + char * str; +@@ -31,6 +35,7 @@ int filter_devnode (vector, vector, char + int filter_wwid (vector, vector, char *); + int filter_device (vector, vector, char *, char *); + int filter_path (struct config *, struct path *); ++int filter_property(struct config *, struct udev_device *); + int store_ble (vector, char *, int); + int set_ble_device (vector, char *, char *, int); + void free_blacklist (vector); +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -597,10 +597,12 @@ free_config (struct config * conf) + + free_blacklist(conf->blist_devnode); + free_blacklist(conf->blist_wwid); ++ free_blacklist(conf->blist_property); + free_blacklist_device(conf->blist_device); + + free_blacklist(conf->elist_devnode); + free_blacklist(conf->elist_wwid); ++ free_blacklist(conf->elist_property); + free_blacklist_device(conf->elist_device); + + free_mptable(conf->mptable); +@@ -779,8 +781,12 @@ load_config (char * file, struct udev *u + if (!conf->blist_device) + goto out; + } +- if (setup_default_blist(conf)) +- goto out; ++ if (conf->blist_property == NULL) { ++ conf->blist_property = vector_alloc(); ++ ++ if (!conf->blist_property) ++ goto out; ++ } + + if (conf->elist_devnode == NULL) { + conf->elist_devnode = vector_alloc(); +@@ -802,6 +808,16 @@ load_config (char * file, struct udev *u + goto out; + } + ++ if (conf->elist_property == NULL) { ++ conf->elist_property = vector_alloc(); ++ ++ if (!conf->elist_property) ++ goto out; ++ } ++ ++ if (setup_default_blist(conf)) ++ goto out; ++ + if (conf->mptable == NULL) { + conf->mptable = vector_alloc(); + if (!conf->mptable) +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -189,9 +189,11 @@ struct config { + vector blist_devnode; + vector blist_wwid; + vector blist_device; ++ vector blist_property; + vector elist_devnode; + vector elist_wwid; + vector elist_device; ++ vector elist_property; + }; + + struct config * conf; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -1027,6 +1027,10 @@ get_refwwid (char * dev, enum devtypes d + return ret; + } + } ++ if (pp->udev && pp->uid_attribute && ++ filter_property(conf, pp->udev) > 0) ++ return 2; ++ + refwwid = pp->wwid; + goto out; + } +@@ -1051,6 +1055,10 @@ get_refwwid (char * dev, enum devtypes d + return ret; + } + } ++ if (pp->udev && pp->uid_attribute && ++ filter_property(conf, pp->udev) > 0) ++ return 2; ++ + refwwid = pp->wwid; + goto out; + } +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -1063,8 +1063,11 @@ blacklist_handler(vector strvec) + conf->blist_wwid = vector_alloc(); + if (!conf->blist_device) + conf->blist_device = vector_alloc(); ++ if (!conf->blist_property) ++ conf->blist_property = vector_alloc(); + +- if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device) ++ if (!conf->blist_devnode || !conf->blist_wwid || ++ !conf->blist_device || !conf->blist_property) + return 1; + + return 0; +@@ -1079,8 +1082,11 @@ blacklist_exceptions_handler(vector strv + conf->elist_wwid = vector_alloc(); + if (!conf->elist_device) + conf->elist_device = vector_alloc(); ++ if (!conf->elist_property) ++ conf->elist_property = vector_alloc(); + +- if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device) ++ if (!conf->elist_devnode || !conf->elist_wwid || ++ !conf->elist_device || !conf->elist_property) + return 1; + + return 0; +@@ -1139,6 +1145,32 @@ ble_except_wwid_handler(vector strvec) + } + + static int ++ble_property_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ return store_ble(conf->blist_property, buff, ORIGIN_CONFIG); ++} ++ ++static int ++ble_except_property_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ return store_ble(conf->elist_property, buff, ORIGIN_CONFIG); ++} ++ ++static int + ble_device_handler(vector strvec) + { + return alloc_ble_device(conf->blist_device); +@@ -3903,6 +3935,7 @@ init_keywords(void) + install_keyword_root("blacklist", &blacklist_handler); + install_keyword_multi("devnode", &ble_devnode_handler, &snprint_ble_simple); + install_keyword_multi("wwid", &ble_wwid_handler, &snprint_ble_simple); ++ install_keyword_multi("property", &ble_property_handler, &snprint_ble_simple); + install_keyword_multi("device", &ble_device_handler, NULL); + install_sublevel(); + install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor); +@@ -3911,6 +3944,7 @@ init_keywords(void) + install_keyword_root("blacklist_exceptions", &blacklist_exceptions_handler); + install_keyword_multi("devnode", &ble_except_devnode_handler, &snprint_ble_simple); + install_keyword_multi("wwid", &ble_except_wwid_handler, &snprint_ble_simple); ++ install_keyword_multi("property", &ble_except_property_handler, &snprint_ble_simple); + install_keyword_multi("device", &ble_except_device_handler, NULL); + install_sublevel(); + install_keyword("vendor", &ble_except_vendor_handler, &snprint_bled_vendor); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1332,6 +1332,8 @@ pathinfo (struct path *pp, vector hwtabl + * limited by DI_BLACKLIST and occurs before this debug + * message with the mask value. + */ ++ if (pp->udev && filter_property(conf, pp->udev) > 0) ++ return PATHINFO_SKIPPED; + if (filter_devnode(conf->blist_devnode, + conf->elist_devnode, + pp->dev) > 0) +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -1415,6 +1415,19 @@ snprint_blacklist_report (char * buff, i + + if ((len - fwd - threshold) <= 0) + return len; ++ fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n" ++ "- blacklist:\n"); ++ if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property)) ++ return len; ++ ++ if ((len - fwd - threshold) <= 0) ++ return len; ++ fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n"); ++ if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0) ++ return len; ++ ++ if ((len - fwd - threshold) <= 0) ++ return len; + fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n" + "- blacklist:\n"); + if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0) +@@ -1480,6 +1493,15 @@ snprint_blacklist (char * buff, int len) + if (fwd > len) + return len; + } ++ vector_foreach_slot (conf->blist_property, ble, i) { ++ kw = find_keyword(rootkw->sub, "property"); ++ if (!kw) ++ return 0; ++ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n", ++ kw, ble); ++ if (fwd > len) ++ return len; ++ } + rootkw = find_keyword(rootkw->sub, "device"); + if (!rootkw) + return 0; +@@ -1544,6 +1566,15 @@ snprint_blacklist_except (char * buff, i + if (!kw) + return 0; + fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n", ++ kw, ele); ++ if (fwd > len) ++ return len; ++ } ++ vector_foreach_slot (conf->elist_property, ele, i) { ++ kw = find_keyword(rootkw->sub, "property"); ++ if (!kw) ++ return 0; ++ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n", + kw, ele); + if (fwd > len) + return len; +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -626,6 +626,9 @@ The \fIWorld Wide Identification\fR of a + .B devnode + Regular expression of the device nodes to be excluded. + .TP ++.B property ++Regular expresion of the udev property to be excluded. ++.TP + .B device + Subsection for the device description. This subsection recognizes the + .I vendor +@@ -650,8 +653,11 @@ The following keywords are recognized: + .B wwid + The \fIWorld Wide Identification\fR of a device. + .TP ++.B property ++Regular expresion of the udev property to be whitelisted. ++.TP + .B devnode +-Regular expression of the device nodes to be excluded. ++Regular expression of the device nodes to be whitelisted. + .TP + .B device + Subsection for the device description. This subsection recognizes the +@@ -661,6 +667,25 @@ and + keywords. For a full description of these keywords please see the + .I devices + section description. ++.LP ++The ++.I property ++blacklist and whitelist handling is different from the usual handling ++in the sense that if the whitelist is set, it ++.B has ++to match, otherwise the device will be blacklisted. ++In these cases the message ++.I blacklisted, udev property missing ++will be displayed. For example settting the ++.I property ++blacklist_exception to ++.I (SCSI_IDENT_|ID_WWN) ++will blacklist all devices that have no udev property whose name regex matches ++either ++.I SCSI_IDENT_ ++or ++.I ID_WWN. ++This works to exclude most non-multipathable devices. + .SH "multipaths section" + The only recognized attribute for the + .B multipaths diff --git a/SOURCES/0233-RHBZ-1451852-1482629-nimble-config.patch b/SOURCES/0233-RHBZ-1451852-1482629-nimble-config.patch new file mode 100644 index 0000000..96c9985 --- /dev/null +++ b/SOURCES/0233-RHBZ-1451852-1482629-nimble-config.patch @@ -0,0 +1,20 @@ +--- + libmultipath/hwtable.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1125,9 +1125,10 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .prio_args = NULL, + .pgfailback = -FAILBACK_IMMEDIATE, ++ .checker_name = TUR, + .selector = "round-robin 0", + .dev_loss = MAX_DEV_LOSS_TMO, +- .fast_io_fail = 1, ++ .fast_io_fail = 5, + }, + { + .vendor = "XtremIO", diff --git a/SOURCES/0234-RHBZ-1500109-doc-typo.patch b/SOURCES/0234-RHBZ-1500109-doc-typo.patch new file mode 100644 index 0000000..a9484db --- /dev/null +++ b/SOURCES/0234-RHBZ-1500109-doc-typo.patch @@ -0,0 +1,17 @@ +--- + multipath/multipath.conf.5 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -388,7 +388,7 @@ retry interval + \fIno_path_retry\fR * \fIpolling_interval\fR + if a number of retries is given with \fIno_path_retry\fR and the + overall retry interval is longer than the specified \fIdev_loss_tmo\fR value. +-The linux kernel will cap this value to \fI300\fR if \fBfast_io_fail_tmo\fR ++The linux kernel will cap this value to \fI600\fR if \fBfast_io_fail_tmo\fR + is not set. + .TP + .B queue_without_daemon diff --git a/SOURCES/0235-RHBZ-1480638-NVMe-support.patch b/SOURCES/0235-RHBZ-1480638-NVMe-support.patch new file mode 100644 index 0000000..bf1d580 --- /dev/null +++ b/SOURCES/0235-RHBZ-1480638-NVMe-support.patch @@ -0,0 +1,503 @@ +--- + libmultipath/checkers.c | 19 +++- + libmultipath/checkers.h | 3 + libmultipath/discovery.c | 183 +++++++++++++++++++++++++++++++++++++++------ + libmultipath/discovery.h | 2 + libmultipath/hwtable.c | 10 ++ + libmultipath/structs.h | 1 + libmultipath/uevent.c | 2 + multipath/multipath.conf.5 | 3 + multipathd/main.c | 27 ------ + 9 files changed, 194 insertions(+), 56 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -881,6 +882,46 @@ scsi_sysfs_pathinfo (struct path * pp) + } + + static int ++nvme_sysfs_pathinfo (struct path * pp) ++{ ++ struct udev_device *parent; ++ const char *attr_path = NULL; ++ ++ ++ attr_path = udev_device_get_sysname(pp->udev); ++ if (!attr_path) ++ return 1; ++ ++ if (sscanf(attr_path, "nvme%dn%d", ++ &pp->sg_id.host_no, ++ &pp->sg_id.scsi_id) != 2) ++ return 1; ++ pp->sg_id.channel = 0; ++ pp->sg_id.lun = 0; ++ ++ parent = udev_device_get_parent(pp->udev); ++ if (!parent) ++ return 1; ++ ++ snprintf(pp->vendor_id, SCSI_VENDOR_SIZE, "NVME"); ++ snprintf(pp->product_id, SCSI_PRODUCT_SIZE, "%s", ++ udev_device_get_sysattr_value(parent, "model")); ++ snprintf(pp->serial, SERIAL_SIZE, "%s", ++ udev_device_get_sysattr_value(parent, "serial")); ++ snprintf(pp->rev, SCSI_REV_SIZE, "%s", ++ udev_device_get_sysattr_value(parent, "firmware_rev")); ++ ++ condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); ++ condlog(3, "%s: product = %s", pp->dev, pp->product_id); ++ condlog(3, "%s: serial = %s", pp->dev, pp->serial); ++ condlog(3, "%s: rev = %s", pp->dev, pp->rev); ++ ++ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL); ++ ++ return 0; ++} ++ ++static int + rbd_sysfs_pathinfo (struct path * pp) + { + sprintf(pp->vendor_id, "Ceph"); +@@ -1040,14 +1081,20 @@ path_offline (struct path * pp) + { + struct udev_device * parent; + char buff[SCSI_STATE_SIZE]; ++ const char *subsys_type; + +- if (pp->bus != SYSFS_BUS_SCSI) ++ if (pp->bus == SYSFS_BUS_SCSI) ++ subsys_type = "scsi"; ++ else if (pp->bus == SYSFS_BUS_NVME) ++ subsys_type = "nvme"; ++ else + return PATH_UP; + + parent = pp->udev; + while (parent) { + const char *subsys = udev_device_get_subsystem(parent); +- if (subsys && !strncmp(subsys, "scsi", 4)) ++ if (subsys && !strncmp(subsys, subsys_type, ++ strlen(subsys_type))) + break; + parent = udev_device_get_parent(parent); + } +@@ -1063,15 +1110,30 @@ path_offline (struct path * pp) + + condlog(3, "%s: path state = %s", pp->dev, buff); + +- if (!strncmp(buff, "offline", 7)) { +- pp->offline = 1; +- return PATH_DOWN; ++ if (pp->bus == SYSFS_BUS_SCSI) { ++ if (!strncmp(buff, "offline", 7)) { ++ pp->offline = 1; ++ return PATH_DOWN; ++ } ++ pp->offline = 0; ++ if (!strncmp(buff, "blocked", 7) || ++ !strncmp(buff, "quiesce", 7)) ++ return PATH_PENDING; ++ else if (!strncmp(buff, "running", 7)) ++ return PATH_UP; ++ } ++ else if (pp->bus == SYSFS_BUS_NVME) { ++ if (!strncmp(buff, "dead", 4)) { ++ pp->offline = 1; ++ return PATH_DOWN; ++ } ++ pp->offline = 0; ++ if (!strncmp(buff, "new", 3) || ++ !strncmp(buff, "deleting", 8)) ++ return PATH_PENDING; ++ else if (!strncmp(buff, "live", 4)) ++ return PATH_UP; + } +- pp->offline = 0; +- if (!strncmp(buff, "blocked", 7) || !strncmp(buff, "quiesce", 7)) +- return PATH_PENDING; +- else if (!strncmp(buff, "running", 7)) +- return PATH_UP; + + return PATH_DOWN; + } +@@ -1091,6 +1153,8 @@ sysfs_pathinfo(struct path * pp) + pp->bus = SYSFS_BUS_SCSI; + if (!strncmp(pp->dev,"rbd", 3)) + pp->bus = SYSFS_BUS_RBD; ++ if (!strncmp(pp->dev,"nvme", 4)) ++ pp->bus = SYSFS_BUS_NVME; + + if (pp->bus == SYSFS_BUS_UNDEF) + return 0; +@@ -1106,6 +1170,9 @@ sysfs_pathinfo(struct path * pp) + } else if (pp->bus == SYSFS_BUS_RBD) { + if (rbd_sysfs_pathinfo(pp)) + return 1; ++ } else if (pp->bus == SYSFS_BUS_NVME) { ++ if (nvme_sysfs_pathinfo(pp)) ++ return 1; + } + return 0; + } +@@ -1132,7 +1199,7 @@ cciss_ioctl_pathinfo (struct path * pp, + } + + int +-get_state (struct path * pp, int daemon) ++get_state (struct path * pp, int daemon, int oldstate) + { + struct checker * c = &pp->checker; + int state; +@@ -1171,8 +1238,9 @@ get_state (struct path * pp, int daemon) + (pp->bus != SYSFS_BUS_SCSI || + sysfs_get_timeout(pp, &(c->timeout)))) + c->timeout = DEF_TIMEOUT; +- state = checker_check(c); +- condlog(3, "%s: state = %s", pp->dev, checker_state_name(state)); ++ state = checker_check(c, oldstate); ++ condlog(3, "%s: %s state = %s", pp->dev, ++ checker_name(c), checker_state_name(state)); + if (state != PATH_UP && state != PATH_GHOST && + strlen(checker_message(c))) + condlog(3, "%s: checker msg is \"%s\"", +@@ -1256,6 +1324,82 @@ free_dev: + return ret; + } + ++/* ++ * Mangle string of length *len starting at start ++ * by removing character sequence "00" (hex for a 0 byte), ++ * starting at end, backwards. ++ * Changes the value of *len if characters were removed. ++ * Returns a pointer to the position where "end" was moved to. ++ */ ++static char * ++skip_zeroes_backward(char* start, int *len, char *end) ++{ ++ char *p = end; ++ ++ while (p >= start + 2 && *(p - 1) == '0' && *(p - 2) == '0') ++ p -= 2; ++ ++ if (p == end) ++ return p; ++ ++ memmove(p, end, start + *len + 1 - end); ++ *len -= end - p; ++ ++ return p; ++} ++ ++/* ++ * Fix for NVME wwids looking like this: ++ * nvme.0000-3163653363666438366239656630386200-4c696e75780000000000000000000000000000000000000000000000000000000000000000000000-00000002 ++ * which are encountered in some combinations of Linux NVME host and target. ++ * The '00' are hex-encoded 0-bytes which are forbidden in the serial (SN) ++ * and model (MN) fields. Discard them. ++ * If a WWID of the above type is found, sets pp->wwid and returns a value > 0. ++ * Otherwise, returns 0. ++ */ ++static int ++fix_broken_nvme_wwid(struct path *pp, const char *value, int size) ++{ ++ static const char _nvme[] = "nvme."; ++ int len, i; ++ char mangled[256]; ++ char *p; ++ ++ len = strlen(value); ++ if (len >= sizeof(mangled)) ++ return 0; ++ ++ /* Check that value starts with "nvme.%04x-" */ ++ if (memcmp(value, _nvme, sizeof(_nvme) - 1) || value[9] != '-') ++ return 0; ++ for (i = 5; i < 9; i++) ++ if (!isxdigit(value[i])) ++ return 0; ++ ++ memcpy(mangled, value, len + 1); ++ ++ /* search end of "model" part and strip trailing '00' */ ++ p = memrchr(mangled, '-', len); ++ if (p == NULL) ++ return 0; ++ ++ p = skip_zeroes_backward(mangled, &len, p); ++ ++ /* search end of "serial" part */ ++ p = memrchr(mangled, '-', p - mangled); ++ if (p == NULL || memrchr(mangled, '-', p - mangled) != mangled + 9) ++ /* We expect exactly 3 '-' in the value */ ++ return 0; ++ ++ p = skip_zeroes_backward(mangled, &len, p); ++ if (len >= size) ++ return 0; ++ ++ memcpy(pp->wwid, mangled, len + 1); ++ condlog(2, "%s: over-long WWID shortened to %s", pp->dev, pp->wwid); ++ return len; ++} ++ + int + get_uid (struct path * pp, struct udev_device *udev) + { +@@ -1287,14 +1431,10 @@ get_uid (struct path * pp, struct udev_d + conf->cmd == CMD_VALID_PATH) + value = getenv(pp->uid_attribute); + if (value && strlen(value)) { +- size_t len = WWID_SIZE; +- +- if (strlen(value) + 1 > WWID_SIZE) { ++ size_t len = strlcpy(pp->wwid, value, WWID_SIZE); ++ if (len > WWID_SIZE && ++ !fix_broken_nvme_wwid(pp, value, WWID_SIZE)) + condlog(0, "%s: wwid overflow", pp->dev); +- } else { +- len = strlen(value); +- } +- strncpy(pp->wwid, value, len); + condlog(4, "%s: got wwid of '%s'", pp->dev, pp->wwid); + pp->missing_udev_info = INFO_OK; + pp->tick = 0; +@@ -1381,7 +1521,8 @@ pathinfo (struct path *pp, vector hwtabl + + if (mask & DI_CHECKER) { + if (path_state == PATH_UP) { +- pp->chkrstate = pp->state = get_state(pp, 0); ++ pp->chkrstate = pp->state = get_state(pp, 0, ++ path_state); + if (pp->state == PATH_UNCHECKED || + pp->state == PATH_WILD) + goto blank; +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1185,7 +1185,15 @@ static struct hwentry default_hw[] = { + .checker_name = RBD, + .deferred_remove = DEFERRED_REMOVE_ON, + }, +- ++ /* ++ * Generic NVMe devices ++ */ ++ { ++ .vendor = "NVME", ++ .product = ".*", ++ .uid_attribute = "ID_WWN", ++ .checker_name = NONE, ++ }, + /* + * EOL + */ +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -54,6 +54,7 @@ enum sysfs_buses { + SYSFS_BUS_CCW, + SYSFS_BUS_CCISS, + SYSFS_BUS_RBD, ++ SYSFS_BUS_NVME, + }; + + enum pathstates { +Index: multipath-tools-130222/libmultipath/checkers.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.c ++++ multipath-tools-130222/libmultipath/checkers.c +@@ -101,6 +101,8 @@ struct checker * add_checker (char * nam + if (!c) + return NULL; + snprintf(c->name, CHECKER_NAME_LEN, "%s", name); ++ if (!strncmp(c->name, NONE, 4)) ++ goto done; + snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so", + conf->multipath_dir, name); + if (stat(libname,&stbuf) < 0) { +@@ -144,7 +146,7 @@ struct checker * add_checker (char * nam + condlog(0, "A dynamic linking error occurred: (%s)", errstr); + if (!c->repair) + goto out; +- ++done: + c->fd = 0; + c->sync = 1; + list_add(&c->node, &checkers); +@@ -194,14 +196,16 @@ int checker_init (struct checker * c, vo + if (!c) + return 1; + c->mpcontext = mpctxt_addr; +- return c->init(c); ++ if (c->init) ++ return c->init(c); ++ return 0; + } + + void checker_put (struct checker * dst) + { + struct checker * src; + +- if (!dst) ++ if (!dst || !strlen(dst->name)) + return; + src = checker_lookup(dst->name); + if (dst->free) +@@ -221,10 +225,11 @@ void checker_repair (struct checker * c) + return; + } + +- c->repair(c); ++ if (c->repair) ++ c->repair(c); + } + +-int checker_check (struct checker * c) ++int checker_check (struct checker * c, int path_state) + { + int r; + +@@ -236,6 +241,8 @@ int checker_check (struct checker * c) + MSG(c, "checker disabled"); + return PATH_UNCHECKED; + } ++ if (!strncmp(c->name, NONE, 4)) ++ return path_state; + if (c->fd <= 0) { + MSG(c, "no usable fd"); + return PATH_WILD; +@@ -249,6 +256,8 @@ int checker_selected (struct checker * c + { + if (!c) + return 0; ++ if (!strncmp(c->name, NONE, 4)) ++ return 1; + return (c->check) ? 1 : 0; + } + +Index: multipath-tools-130222/libmultipath/checkers.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.h ++++ multipath-tools-130222/libmultipath/checkers.h +@@ -75,6 +75,7 @@ enum path_check_state { + #define EMC_CLARIION "emc_clariion" + #define READSECTOR0 "readsector0" + #define CCISS_TUR "cciss_tur" ++#define NONE "none" + #define RBD "rbd" + + #define DEFAULT_CHECKER DIRECTIO +@@ -129,7 +130,7 @@ void checker_set_fd (struct checker *, i + void checker_enable (struct checker *); + void checker_disable (struct checker *); + void checker_repair (struct checker *); +-int checker_check (struct checker *); ++int checker_check (struct checker *, int); + int checker_selected (struct checker *); + char * checker_name (struct checker *); + char * checker_message (struct checker *); +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -35,7 +35,7 @@ int path_discovery (vector pathvec, stru + + int do_tur (char *); + int path_offline (struct path *); +-int get_state (struct path * pp, int daemon); ++int get_state (struct path * pp, int daemon, int state); + int pathinfo (struct path *, vector hwtable, int mask); + int store_pathinfo (vector pathvec, vector hwtable, + struct udev_device *udevice, int flag, +Index: multipath-tools-130222/libmultipath/uevent.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.c ++++ multipath-tools-130222/libmultipath/uevent.c +@@ -447,7 +447,7 @@ int uevent_listen(struct udev *udev) + goto out; + } + err = udev_monitor_filter_add_match_subsystem_devtype(monitor, "block", +- NULL); ++ "disk"); + if (err) + condlog(2, "failed to create filter : %s", strerror(-err)); + err = udev_monitor_enable_receiving(monitor); +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -284,6 +284,9 @@ Check the path state for LSI/Engenio/Net + .B directio + Read the first sector with direct I/O. + .TP ++.B none ++Do not check the device, fallback to use the values retrieved from sysfs ++.TP + .B rbd + Check if the path is in the Ceph blacklist. + .TP +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -908,28 +908,6 @@ out: + return r; + } + +-static int +-uev_discard(char * devpath) +-{ +- char *tmp; +- char a[11], b[11]; +- +- /* +- * keep only block devices, discard partitions +- */ +- tmp = strstr(devpath, "/block/"); +- if (tmp == NULL){ +- condlog(4, "no /block/ in '%s'", devpath); +- return 1; +- } +- if (sscanf(tmp, "/block/%10s", a) != 1 || +- sscanf(tmp, "/block/%10[^/]/%10s", a, b) == 2) { +- condlog(4, "discard event on %s", devpath); +- return 1; +- } +- return 0; +-} +- + int + uev_trigger (struct uevent * uev, void * trigger_data) + { +@@ -938,9 +916,6 @@ uev_trigger (struct uevent * uev, void * + + vecs = (struct vectors *)trigger_data; + +- if (uev_discard(uev->devpath)) +- return 0; +- + pthread_cleanup_push(cleanup_lock, &vecs->lock); + lock(vecs->lock); + pthread_testcancel(); +@@ -1358,7 +1333,7 @@ check_path (struct vectors * vecs, struc + + newstate = path_offline(pp); + if (newstate == PATH_UP) +- newstate = get_state(pp, 1); ++ newstate = get_state(pp, 1, newstate); + else + checker_clear_message(&pp->checker); + diff --git a/SOURCES/0236-RHBZ-1525348-fix-msg.patch b/SOURCES/0236-RHBZ-1525348-fix-msg.patch new file mode 100644 index 0000000..04f9fe7 --- /dev/null +++ b/SOURCES/0236-RHBZ-1525348-fix-msg.patch @@ -0,0 +1,17 @@ +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -471,7 +471,7 @@ uev_add_path (struct uevent *uev, struct + + pp = find_path_by_dev(vecs->pathvec, uev->kernel); + if (pp) { +- condlog(0, "%s: spurious uevent, path already in pathvec", ++ condlog(2, "%s: spurious uevent, path already in pathvec", + uev->kernel); + if (pp->mpp) + return 0; diff --git a/SOURCES/0237-RHBZ-1526876-show-sysfs-state.patch b/SOURCES/0237-RHBZ-1526876-show-sysfs-state.patch new file mode 100644 index 0000000..5f77cb2 --- /dev/null +++ b/SOURCES/0237-RHBZ-1526876-show-sysfs-state.patch @@ -0,0 +1,38 @@ +--- + multipath/main.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -135,7 +135,7 @@ usage (char * progname) + } + + static int +-update_paths (struct multipath * mpp) ++update_paths (struct multipath * mpp, int quick) + { + int i, j; + struct pathgroup * pgp; +@@ -149,6 +149,10 @@ update_paths (struct multipath * mpp) + continue; + + vector_foreach_slot (pgp->paths, pp, j) { ++ if (quick) { ++ pp->mpp = mpp; ++ continue; ++ } + if (!strlen(pp->dev)) { + if (devt2devname(pp->dev, FILE_NAME_SIZE, + pp->dev_t)) { +@@ -213,8 +217,7 @@ get_dm_mpvec (vector curmp, vector pathv + * If not in "fast list mode", we need to fetch information + * about them + */ +- if (conf->cmd != CMD_LIST_SHORT) +- update_paths(mpp); ++ update_paths(mpp, (conf->cmd == CMD_LIST_SHORT)); + + if (conf->cmd == CMD_LIST_LONG) + mpp->bestpg = select_path_group(mpp); diff --git a/SOURCES/0238-RHBZ-1508483-mpathconf-info.patch b/SOURCES/0238-RHBZ-1508483-mpathconf-info.patch new file mode 100644 index 0000000..106a941 --- /dev/null +++ b/SOURCES/0238-RHBZ-1508483-mpathconf-info.patch @@ -0,0 +1,45 @@ +--- + libmultipath/config.c | 3 ++- + multipath/mpathconf.8 | 8 ++++++-- + 2 files changed, 8 insertions(+), 3 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -739,7 +739,8 @@ load_config (char * file, struct udev *u + condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); + condlog(0, "A default multipath.conf file is located at"); + condlog(0, "/usr/share/doc/device-mapper-multipath-%d.%d.%d/multipath.conf", MULTIPATH_VERSION(VERSION_CODE)); +- condlog(0, "You can run /sbin/mpathconf to create or modify /etc/multipath.conf"); ++ condlog(0, "You can run /sbin/mpathconf --enable to create"); ++ condlog(0, "/etc/multipath.conf. See man mpathconf(8) for more details"); + if (conf->blist_devnode == NULL) { + conf->blist_devnode = vector_alloc(); + if (!conf->blist_devnode) { +Index: multipath-tools-130222/multipath/mpathconf.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf.8 ++++ multipath-tools-130222/multipath/mpathconf.8 +@@ -19,7 +19,9 @@ daemon, and configure the + .B multipathd + service to start automatically or not. If + .B mpathconf +-is called with no commands, it will display the current configuration. ++is called with no commands, it will display the current configuration, but ++will not create or modify ++.B /etc/multipath.conf + + The default options for mpathconf are + .B --with_module +@@ -50,7 +52,9 @@ command. + .B --enable + Removes any line that blacklists all device nodes from the + .B /etc/multipath.conf +-blacklist section. ++blacklist section. Also, creates ++.B /etc/multipath.conf ++if it doesn't exist. + .TP + .B --disable + Adds a line that blacklists all device nodes to the diff --git a/SOURCES/0239-RHBZ-1544958-client-timeout.patch b/SOURCES/0239-RHBZ-1544958-client-timeout.patch new file mode 100644 index 0000000..ea38a16 --- /dev/null +++ b/SOURCES/0239-RHBZ-1544958-client-timeout.patch @@ -0,0 +1,17 @@ +--- + libmpathcmd/mpath_cmd.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmpathcmd/mpath_cmd.h +=================================================================== +--- multipath-tools-130222.orig/libmpathcmd/mpath_cmd.h ++++ multipath-tools-130222/libmpathcmd/mpath_cmd.h +@@ -27,7 +27,7 @@ extern "C" { + #endif + + #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" +-#define DEFAULT_REPLY_TIMEOUT 10000 ++#define DEFAULT_REPLY_TIMEOUT 60000 + + + /* diff --git a/SOURCES/0240-UPBZ-1568902-id_size.patch b/SOURCES/0240-UPBZ-1568902-id_size.patch new file mode 100644 index 0000000..9f1009f --- /dev/null +++ b/SOURCES/0240-UPBZ-1568902-id_size.patch @@ -0,0 +1,82 @@ +--- + libmultipath/discovery.c | 12 ++++++------ + libmultipath/structs.h | 11 +++++++++-- + 2 files changed, 15 insertions(+), 8 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -845,12 +845,12 @@ scsi_sysfs_pathinfo (struct path * pp) + + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); + +- if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE)) ++ if (sysfs_get_model(parent, pp->product_id, PATH_PRODUCT_SIZE)) + return 1; + + condlog(3, "%s: product = %s", pp->dev, pp->product_id); + +- if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE)) ++ if (sysfs_get_rev(parent, pp->rev, PATH_REV_SIZE)) + return 1; + + condlog(3, "%s: rev = %s", pp->dev, pp->rev); +@@ -904,11 +904,11 @@ nvme_sysfs_pathinfo (struct path * pp) + return 1; + + snprintf(pp->vendor_id, SCSI_VENDOR_SIZE, "NVME"); +- snprintf(pp->product_id, SCSI_PRODUCT_SIZE, "%s", ++ snprintf(pp->product_id, PATH_PRODUCT_SIZE, "%s", + udev_device_get_sysattr_value(parent, "model")); + snprintf(pp->serial, SERIAL_SIZE, "%s", + udev_device_get_sysattr_value(parent, "serial")); +- snprintf(pp->rev, SCSI_REV_SIZE, "%s", ++ snprintf(pp->rev, PATH_REV_SIZE, "%s", + udev_device_get_sysattr_value(parent, "firmware_rev")); + + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); +@@ -1022,12 +1022,12 @@ cciss_sysfs_pathinfo (struct path * pp) + + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); + +- if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE)) ++ if (sysfs_get_model(parent, pp->product_id, PATH_PRODUCT_SIZE)) + return 1; + + condlog(3, "%s: product = %s", pp->dev, pp->product_id); + +- if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE)) ++ if (sysfs_get_rev(parent, pp->rev, PATH_REV_SIZE)) + return 1; + + condlog(3, "%s: rev = %s", pp->dev, pp->rev); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -24,6 +24,13 @@ + #define SCSI_PRODUCT_SIZE 17 + #define SCSI_REV_SIZE 5 + #define SCSI_STATE_SIZE 19 ++#define NVME_MODEL_SIZE 41 ++#define NVME_REV_SIZE 9 ++ ++/* This must be the maximum of SCSI and NVME sizes */ ++#define PATH_PRODUCT_SIZE NVME_MODEL_SIZE ++#define PATH_REV_SIZE NVME_REV_SIZE ++ + + #define NO_PATH_RETRY_UNDEF 0 + #define NO_PATH_RETRY_FAIL -1 +@@ -212,8 +219,8 @@ struct path { + struct hd_geometry geom; + char wwid[WWID_SIZE]; + char vendor_id[SCSI_VENDOR_SIZE]; +- char product_id[SCSI_PRODUCT_SIZE]; +- char rev[SCSI_REV_SIZE]; ++ char product_id[PATH_PRODUCT_SIZE]; ++ char rev[PATH_REV_SIZE]; + char serial[SERIAL_SIZE]; + char tgt_node_name[NODE_NAME_SIZE]; + unsigned long long size; diff --git a/SOURCES/0241-RHBZ-1554516-show-path-failures.patch b/SOURCES/0241-RHBZ-1554516-show-path-failures.patch new file mode 100644 index 0000000..c13d8c6 --- /dev/null +++ b/SOURCES/0241-RHBZ-1554516-show-path-failures.patch @@ -0,0 +1,29 @@ +--- + libmultipath/print.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -601,6 +601,12 @@ snprint_path_checker (char * buff, size_ + return snprint_str(buff, len, c->name); + } + ++static int ++snprint_path_failures(char * buff, size_t len, struct path * pp) ++{ ++ return snprint_int(buff, len, pp->failcount); ++} ++ + struct multipath_data mpd[] = { + {'n', "name", 0, snprint_name}, + {'w', "uuid", 0, snprint_multipath_uuid}, +@@ -647,6 +653,7 @@ struct path_data pd[] = { + {'R', "host WWPN", 0, snprint_host_wwpn}, + {'r', "target WWPN", 0, snprint_tgt_wwpn}, + {'a', "host adapter", 0, snprint_host_adapter}, ++ {'0', "failures", 0, snprint_path_failures}, + {0, NULL, 0 , NULL} + }; + diff --git a/SOURCES/0242-RHBZ-1541116-all-tg-pt.patch b/SOURCES/0242-RHBZ-1541116-all-tg-pt.patch new file mode 100644 index 0000000..f56e012 --- /dev/null +++ b/SOURCES/0242-RHBZ-1541116-all-tg-pt.patch @@ -0,0 +1,385 @@ +--- + libmpathpersist/mpath_persist.c | 28 +++++++++++--- + libmultipath/config.c | 3 + + libmultipath/config.h | 2 + + libmultipath/defaults.h | 1 + libmultipath/dict.c | 77 ++++++++++++++++++++++++++++++++++++++++ + libmultipath/propsel.c | 20 ++++++++++ + libmultipath/propsel.h | 1 + libmultipath/structs.h | 7 +++ + multipath/multipath.conf.5 | 7 +++ + 9 files changed, 140 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222-patched/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222-patched.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222-patched/libmpathpersist/mpath_persist.c +@@ -287,6 +287,7 @@ int mpath_persistent_reserve_out ( int f + } + + select_reservation_key(mpp); ++ select_all_tg_pt(mpp); + + memcpy(&prkey, paramp->sa_key, 8); + if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey && +@@ -419,7 +420,7 @@ int mpath_prout_reg(struct multipath *mp + unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy) + { + +- int i, j; ++ int i, j, k; + struct pathgroup *pgp = NULL; + struct path *pp = NULL; + int rollback = 0; +@@ -444,11 +445,13 @@ int mpath_prout_reg(struct multipath *mp + } + + 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; +@@ -476,6 +479,17 @@ int mpath_prout_reg(struct multipath *mp + condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev); + continue; + } ++ if (mpp->all_tg_pt == ALL_TG_PT_ON && ++ 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; ++ } + strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE); + + if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){ +@@ -492,10 +506,12 @@ int mpath_prout_reg(struct multipath *mp + 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 < active_pathcount ; i++){ ++ for( i=0; i < count ; i++){ + if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { + rc = pthread_join(thread[i].id, NULL); + if (rc){ +@@ -518,7 +534,7 @@ int mpath_prout_reg(struct multipath *mp + } + if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){ + condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid); +- for( i=0 ; i < active_pathcount ; i++){ ++ for( i=0 ; i < count ; i++){ + if (thread[i].param.status == MPATH_PR_SUCCESS) { + memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8); + memset(&thread[i].param.paramp->sa_key, 0, 8); +@@ -532,7 +548,7 @@ int mpath_prout_reg(struct multipath *mp + } else + thread[i].param.status = MPATH_PR_SKIP; + } +- for(i=0; i < active_pathcount ; i++){ ++ 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); +@@ -678,7 +694,7 @@ int mpath_prout_rel(struct multipath *mp + } + } + pthread_attr_destroy (&attr); +- for (i = 0; i < active_pathcount; i++){ ++ for (i = 0; i < count; i++){ + if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { + rc = pthread_join (thread[i].id, NULL); + if (rc){ +@@ -687,7 +703,7 @@ int mpath_prout_rel(struct multipath *mp + } + } + +- for (i = 0; i < active_pathcount; i++){ ++ for (i = 0; i < count; i++){ + /* check thread status here and return the status */ + + if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT) +Index: multipath-tools-130222-patched/libmultipath/config.c +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/config.c ++++ multipath-tools-130222-patched/libmultipath/config.c +@@ -349,6 +349,7 @@ merge_hwe (struct hwentry * dst, struct + merge_num(max_sectors_kb); + merge_num(unpriv_sgio); + merge_num(ghost_delay); ++ merge_num(all_tg_pt); + + /* + * Make sure features is consistent with +@@ -414,6 +415,7 @@ overwrite_hwe (struct hwentry * dst, str + overwrite_num(max_sectors_kb); + overwrite_num(unpriv_sgio); + overwrite_num(ghost_delay); ++ overwrite_num(all_tg_pt); + + /* + * Make sure features is consistent with +@@ -700,6 +702,7 @@ load_config (char * file, struct udev *u + conf->max_sectors_kb = DEFAULT_MAX_SECTORS_KB; + conf->unpriv_sgio = DEFAULT_UNPRIV_SGIO; + conf->ghost_delay = DEFAULT_GHOST_DELAY; ++ conf->all_tg_pt = DEFAULT_ALL_TG_PT; + + /* + * preload default hwtable +Index: multipath-tools-130222-patched/libmultipath/config.h +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/config.h ++++ multipath-tools-130222-patched/libmultipath/config.h +@@ -71,6 +71,7 @@ struct hwentry { + int max_sectors_kb; + int unpriv_sgio; + int ghost_delay; ++ int all_tg_pt; + char * bl_product; + }; + +@@ -162,6 +163,7 @@ struct config { + int max_sectors_kb; + int unpriv_sgio; + int ghost_delay; ++ int all_tg_pt; + unsigned int version[3]; + + char * dev; +Index: multipath-tools-130222-patched/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/dict.c ++++ multipath-tools-130222-patched/libmultipath/dict.c +@@ -1051,6 +1051,29 @@ def_ghost_delay_handler(vector strvec) + return 0; + } + ++static int ++def_all_tg_pt_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->all_tg_pt = ALL_TG_PT_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->all_tg_pt = ALL_TG_PT_ON; ++ else ++ conf->all_tg_pt = DEFAULT_ALL_TG_PT; ++ ++ FREE(buff); ++ return 0; ++} ++ ++ + /* + * blacklist block handlers + */ +@@ -1969,6 +1992,33 @@ hw_ghost_delay_handler(vector strvec) + return 0; + } + ++static int ++hw_all_tg_pt_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->all_tg_pt = ALL_TG_PT_OFF; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ hwe->all_tg_pt = ALL_TG_PT_ON; ++ else ++ hwe->all_tg_pt = ALL_TG_PT_UNDEF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -3325,6 +3375,19 @@ snprint_hw_ghost_delay (char * buff, int + } + + static int ++snprint_hw_all_tg_pt(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->all_tg_pt == ALL_TG_PT_ON) ++ return snprintf(buff, len, "yes"); ++ else if (hwe->all_tg_pt == ALL_TG_PT_OFF) ++ return snprintf(buff, len, "no"); ++ else ++ return 0; ++} ++ ++static int + snprint_def_polling_interval (char * buff, int len, void * data) + { + return snprintf(buff, len, "%i", conf->checkint); +@@ -3829,6 +3892,15 @@ snprint_def_ghost_delay (char * buff, in + } + + static int ++snprint_def_all_tg_pt(char * buff, int len, void * data) ++{ ++ if (conf->all_tg_pt == ALL_TG_PT_ON) ++ return snprintf(buff, len, "yes"); ++ else ++ return snprintf(buff, len, "no"); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -3926,6 +3998,7 @@ init_keywords(void) + install_keyword("max_sectors_kb", &def_max_sectors_kb_handler, &snprint_def_max_sectors_kb); + install_keyword("unpriv_sgio", &def_unpriv_sgio_handler, &snprint_def_unpriv_sgio); + install_keyword("ghost_delay", &def_ghost_delay_handler, &snprint_def_ghost_delay); ++ install_keyword("all_tg_pt", &def_all_tg_pt_handler, &snprint_def_all_tg_pt); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -4000,6 +4073,7 @@ init_keywords(void) + install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb); + install_keyword("unpriv_sgio", &hw_unpriv_sgio_handler, &snprint_hw_unpriv_sgio); + install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay); ++ install_keyword("all_tg_pt", &hw_all_tg_pt_handler, &snprint_hw_all_tg_pt); + install_sublevel_end(); + + install_keyword_root("overrides", &nop_handler); +@@ -4031,6 +4105,9 @@ init_keywords(void) + install_keyword("delay_wait_checks", &nop_handler, &snprint_nop); + install_keyword("skip_kpartx", &nop_handler, &snprint_nop); + install_keyword("max_sectors_kb", &nop_handler, &snprint_nop); ++ install_keyword("unpriv_sgio", &nop_handler, &snprint_nop); ++ install_keyword("ghost_delay", &nop_handler, &snprint_nop); ++ install_keyword("all_tg_pt", &nop_handler, &snprint_nop); + + install_keyword_root("multipaths", &multipaths_handler); + install_keyword_multi("multipath", &multipath_handler, NULL); +Index: multipath-tools-130222-patched/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/propsel.c ++++ multipath-tools-130222-patched/libmultipath/propsel.c +@@ -992,3 +992,23 @@ select_ghost_delay (struct multipath * m + condlog(3, "ghost_delay = DISABLED (internal default)"); + return 0; + } ++ ++extern int ++select_all_tg_pt (struct multipath *mp) ++{ ++ if (mp->hwe && mp->hwe->all_tg_pt != ALL_TG_PT_UNDEF) { ++ mp->all_tg_pt = mp->hwe->all_tg_pt; ++ condlog(3, "all_tg_pt = %i (controller setting)", ++ mp->all_tg_pt); ++ return 0; ++ } ++ if (conf->all_tg_pt != GHOST_DELAY_UNDEF) { ++ mp->all_tg_pt = conf->all_tg_pt; ++ condlog(3, "all_tg_pt = %i (config file default)", ++ mp->all_tg_pt); ++ return 0; ++ } ++ mp->all_tg_pt = DEFAULT_ALL_TG_PT; ++ condlog(3, "all_tg_pt = %i (internal default)", mp->all_tg_pt); ++ return 0; ++} +Index: multipath-tools-130222-patched/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/structs.h ++++ multipath-tools-130222-patched/libmultipath/structs.h +@@ -154,6 +154,12 @@ enum unpriv_sgio_states { + UNPRIV_SGIO_ON, + }; + ++enum all_tg_pt_states { ++ ALL_TG_PT_UNDEF, ++ ALL_TG_PT_OFF, ++ ALL_TG_PT_ON, ++}; ++ + enum scsi_protocol { + SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ + SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ +@@ -324,6 +330,7 @@ struct multipath { + int prkey_source; + struct be64 reservation_key; + unsigned char prflag; ++ int all_tg_pt; + }; + + struct pathgroup { +Index: multipath-tools-130222-patched/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/propsel.h ++++ multipath-tools-130222-patched/libmultipath/propsel.h +@@ -28,3 +28,4 @@ int select_skip_kpartx (struct multipath + int select_max_sectors_kb (struct multipath * mp); + int select_unpriv_sgio (struct multipath * mp); + int select_ghost_delay (struct multipath * mp); ++int select_all_tg_pt (struct multipath *mp); +Index: multipath-tools-130222-patched/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222-patched.orig/libmultipath/defaults.h ++++ multipath-tools-130222-patched/libmultipath/defaults.h +@@ -29,6 +29,7 @@ + #define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF + #define DEFAULT_UNPRIV_SGIO UNPRIV_SGIO_OFF + #define DEFAULT_GHOST_DELAY GHOST_DELAY_OFF ++#define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: multipath-tools-130222-patched/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222-patched.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222-patched/multipath/multipath.conf.5 +@@ -449,6 +449,13 @@ registration is removed, the RESERVATION + It is unset by default. + .RE + .TP ++.B all_tg_pt ++This must be set to \fIyes\fR to successfully use mpathpersist on arrays that ++automatically set and clear registration keys on all target ports from a ++host, instead of per target port per host. ++Default is ++.I no ++.TP + .B retain_attached_hw_handler + If set to + .I yes diff --git a/SOURCES/0243-RHBZ-1498724-save-persist-options.patch b/SOURCES/0243-RHBZ-1498724-save-persist-options.patch new file mode 100644 index 0000000..7b7bb20 --- /dev/null +++ b/SOURCES/0243-RHBZ-1498724-save-persist-options.patch @@ -0,0 +1,504 @@ +--- + libmpathpersist/mpath_persist.c | 3 ++- + libmpathpersist/mpath_updatepr.c | 10 ++++++++-- + libmpathpersist/mpathpr.h | 3 ++- + libmultipath/Makefile | 2 +- + libmultipath/config.h | 2 ++ + libmultipath/dict.c | 24 ++++++++++++++++++------ + libmultipath/prkey.c | 25 ++++++++++++++++++++++--- + libmultipath/prkey.h | 4 ++-- + libmultipath/propsel.c | 13 ++++++++++--- + libmultipath/structs.h | 1 + + libmultipath/util.c | 16 ++++++++++++++++ + libmultipath/util.h | 1 + + multipath/multipath.conf.5 | 8 ++++++-- + multipathd/cli_handlers.c | 15 ++++++++++----- + multipathd/main.c | 1 + + 15 files changed, 102 insertions(+), 26 deletions(-) + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -86,6 +86,7 @@ struct mpentry { + char * prio_args; + int prkey_source; + struct be64 reservation_key; ++ uint8_t sa_flags; + int pgpolicy; + int pgfailback; + int rr_weight; +@@ -183,6 +184,7 @@ struct config { + char * config_dir; + int prkey_source; + struct be64 reservation_key; ++ uint8_t sa_flags; + + vector keywords; + vector mptable; +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -331,6 +331,7 @@ struct multipath { + struct be64 reservation_key; + unsigned char prflag; + int all_tg_pt; ++ uint8_t sa_flags; + }; + + struct pathgroup { +Index: multipath-tools-130222/libmultipath/util.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.c ++++ multipath-tools-130222/libmultipath/util.c +@@ -6,6 +6,8 @@ + #include + #include + #include ++#include ++#include + + #include "debug.h" + #include "memory.h" +@@ -317,6 +319,20 @@ int parse_prkey(char *ptr, uint64_t *prk + return 0; + } + ++int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags) ++{ ++ char *flagstr; ++ ++ flagstr = strchr(ptr, ':'); ++ *flags = 0; ++ if (flagstr) { ++ *flagstr++ = '\0'; ++ if (strlen(flagstr) == 5 && strcmp(flagstr, "aptpl") == 0) ++ *flags = MPATH_F_APTPL_MASK; ++ } ++ return parse_prkey(ptr, prkey); ++} ++ + int safe_write(int fd, const void *buf, size_t count) + { + while (count > 0) { +Index: multipath-tools-130222/libmultipath/util.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.h ++++ multipath-tools-130222/libmultipath/util.h +@@ -15,6 +15,7 @@ dev_t parse_devt(const char *dev_t); + char *convert_dev(char *dev, int is_path_device); + int in_initrd(void); + int parse_prkey(char *ptr, uint64_t *prkey); ++int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags); + int safe_write(int fd, const void *buf, size_t count); + + #define safe_sprintf(var, format, args...) \ +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -8,7 +8,7 @@ SONAME=0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) + LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd +-CFLAGS += -fPIC -I$(mpathcmddir) ++CFLAGS += -fPIC -I$(mpathcmddir) -I$(mpathpersistdir) + + OBJS = memory.o parser.o vector.o devmapper.o \ + hwtable.o blacklist.o util.o dmparser.o config.o \ +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -23,6 +23,8 @@ + #include "util.h" + #include "prkey.h" + #include ++#include ++#include + + /* + * default block handlers +@@ -557,6 +559,7 @@ def_reservation_key_handler(vector strve + { + char *buff; + uint64_t prkey = 0; ++ uint8_t flags; + + buff = set_value(strvec); + if (!buff) +@@ -568,12 +571,13 @@ def_reservation_key_handler(vector strve + FREE(buff); + return 0; + } +- else if (parse_prkey(buff, &prkey) != 0) { ++ else if (parse_prkey_flags(buff, &prkey, &flags) != 0) { + FREE(buff); + return 1; + } + + conf->prkey_source = PRKEY_SOURCE_CONF; ++ conf->sa_flags = flags; + put_be64(conf->reservation_key, prkey); + FREE(buff); + return 0; +@@ -2403,6 +2407,7 @@ mp_reservation_key_handler (vector strve + char *buff; + struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); + uint64_t prkey; ++ uint8_t flags; + + if (!mpe) + return 1; +@@ -2417,12 +2422,13 @@ mp_reservation_key_handler (vector strve + FREE(buff); + return 0; + } +- else if (parse_prkey(buff, &prkey) != 0) { ++ else if (parse_prkey_flags(buff, &prkey, &flags) != 0) { + FREE(buff); + return 1; + } + + mpe->prkey_source = PRKEY_SOURCE_CONF; ++ mpe->sa_flags = flags; + put_be64(mpe->reservation_key, prkey); + FREE(buff); + return 0; +@@ -2838,14 +2844,17 @@ snprint_mp_prio_args(char * buff, int le + static int + snprint_mp_reservation_key (char * buff, int len, void * data) + { ++ char *flagstr = ""; + struct mpentry * mpe = (struct mpentry *)data; + + if (mpe->prkey_source == PRKEY_SOURCE_NONE) + return 0; + if (mpe->prkey_source == PRKEY_SOURCE_FILE) + return snprintf(buff, len, "file"); +- return snprintf(buff, len, "0x%" PRIx64, +- get_be64(mpe->reservation_key)); ++ if (mpe->sa_flags == MPATH_F_APTPL_MASK) ++ flagstr = ":aptpl"; ++ return snprintf(buff, len, "0x%" PRIx64 "%s", ++ get_be64(mpe->reservation_key), flagstr); + } + + static int +@@ -3716,12 +3725,15 @@ snprint_def_prkeys_file (char * buff, in + static int + snprint_def_reservation_key(char * buff, int len, void * data) + { ++ char *flagstr = ""; + if (conf->prkey_source == PRKEY_SOURCE_NONE) + return 0; + if (conf->prkey_source == PRKEY_SOURCE_FILE) + return snprintf(buff, len, "file"); +- return snprintf(buff, len, "0x%" PRIx64, +- get_be64(conf->reservation_key)); ++ if (conf->sa_flags == MPATH_F_APTPL_MASK) ++ flagstr = ":aptpl"; ++ return snprintf(buff, len, "0x%" PRIx64 "%s", ++ get_be64(conf->reservation_key), flagstr); + } + + static int +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -295,7 +295,8 @@ int mpath_persistent_reserve_out ( int f + rq_servact == MPATH_PROUT_REG_SA) || + rq_servact == MPATH_PROUT_REG_IGN_SA)) { + memcpy(&mpp->reservation_key, paramp->sa_key, 8); +- if (update_prkey(alias, get_be64(mpp->reservation_key))) { ++ 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; +Index: multipath-tools-130222/libmpathpersist/mpath_updatepr.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_updatepr.c ++++ multipath-tools-130222/libmpathpersist/mpath_updatepr.c +@@ -15,6 +15,8 @@ + #include + #include + #include "memory.h" ++#include ++#include + + unsigned long mem_allocated; /* Total memory used in Bytes */ + +@@ -54,11 +56,15 @@ int update_prflag(char *mapname, int set + return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus"); + } + +-int update_prkey(char *mapname, uint64_t prkey) { ++int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags) { + char str[256]; ++ char *flagstr = ""; + ++ if (sa_flags & MPATH_F_APTPL_MASK) ++ flagstr = ":aptpl"; + if (prkey) +- snprintf(str, sizeof(str), "setprkey key %" PRIx64, prkey); ++ snprintf(str, sizeof(str), "setprkey key %" PRIx64 "%s", prkey, ++ flagstr); + else + snprintf(str, sizeof(str), "unsetprkey"); + return do_update_pr(mapname, str); +Index: multipath-tools-130222/libmpathpersist/mpathpr.h +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpathpr.h ++++ multipath-tools-130222/libmpathpersist/mpathpr.h +@@ -50,7 +50,8 @@ int send_prout_activepath(char * dev, in + unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy); + + int update_prflag(char *mapname, int set); +-int update_prkey(char *mapname, uint64_t prkey); ++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); + int devt2devname (char *devname, char *devt); +Index: multipath-tools-130222/libmultipath/prkey.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prkey.c ++++ multipath-tools-130222/libmultipath/prkey.c +@@ -11,6 +11,8 @@ + #include + #include + #include ++#include ++#include + + #define KEYSIZE 19 + #define PRKEY_READ 0 +@@ -109,7 +111,7 @@ static int do_prkey(int fd, char *wwid, + return 0; + } + +-int get_prkey(struct multipath *mpp, uint64_t *prkey) ++int get_prkey(struct multipath *mpp, uint64_t *prkey, uint8_t *sa_flags) + { + int fd; + int unused; +@@ -125,6 +127,9 @@ int get_prkey(struct multipath *mpp, uin + ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_READ); + if (ret) + goto out_file; ++ *sa_flags = 0; ++ if (strchr(keystr, 'X')) ++ *sa_flags = MPATH_F_APTPL_MASK; + ret = !!parse_prkey(keystr, prkey); + out_file: + close(fd); +@@ -132,7 +137,7 @@ out: + return ret; + } + +-int set_prkey(struct multipath *mpp, uint64_t prkey) ++int set_prkey(struct multipath *mpp, uint64_t prkey, uint8_t sa_flags) + { + int fd; + int can_write = 1; +@@ -142,6 +147,12 @@ int set_prkey(struct multipath *mpp, uin + if (!strlen(mpp->wwid)) + goto out; + ++ if (sa_flags & ~MPATH_F_APTPL_MASK) { ++ condlog(0, "unsupported pr flags, 0x%x", ++ sa_flags & ~MPATH_F_APTPL_MASK); ++ sa_flags &= MPATH_F_APTPL_MASK; ++ } ++ + fd = open_file(conf->prkeys_file, &can_write, PRKEYS_FILE_HEADER); + if (fd < 0) + goto out; +@@ -150,7 +161,15 @@ int set_prkey(struct multipath *mpp, uin + goto out_file; + } + if (prkey) { +- snprintf(keystr, KEYSIZE, "0x%016" PRIx64, prkey); ++ /* using the capitalization of the 'x' is a hack, but ++ * it's unlikely that mpath_persist will support more options ++ * since sg_persist doesn't, and this lets us keep the ++ * same file format as before instead of needing to change ++ * the format of the prkeys file */ ++ if (sa_flags) ++ snprintf(keystr, KEYSIZE, "0X%016" PRIx64, prkey); ++ else ++ snprintf(keystr, KEYSIZE, "0x%016" PRIx64, prkey); + keystr[KEYSIZE - 1] = '\0'; + ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_WRITE); + } +Index: multipath-tools-130222/libmultipath/prkey.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prkey.h ++++ multipath-tools-130222/libmultipath/prkey.h +@@ -13,7 +13,7 @@ + "# prkey wwid\n" \ + "#\n" + +-int set_prkey(struct multipath *mpp, uint64_t prkey); +-int get_prkey(struct multipath *mpp, uint64_t *prkey); ++int set_prkey(struct multipath *mpp, uint64_t prkey, uint8_t sa_flags); ++int get_prkey(struct multipath *mpp, uint64_t *prkey, uint8_t *sa_flags); + + #endif /* _PRKEY_H */ +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -20,6 +20,8 @@ + #include "prioritizers/alua_rtpg.h" + #include "prkey.h" + #include ++#include ++#include + + pgpolicyfn *pgpolicies[] = { + NULL, +@@ -715,10 +717,12 @@ select_reservation_key (struct multipath + uint64_t prkey; + char *origin = NULL; + char *from_file = ""; ++ char *flagstr = ""; + + if (mp->mpe && mp->mpe->prkey_source != PRKEY_SOURCE_NONE) { + mp->prkey_source = mp->mpe->prkey_source; + mp->reservation_key = mp->mpe->reservation_key; ++ mp->sa_flags = mp->mpe->sa_flags; + origin = "multipath setting"; + goto out; + } +@@ -726,6 +730,7 @@ select_reservation_key (struct multipath + if (conf->prkey_source != PRKEY_SOURCE_NONE) { + mp->prkey_source = conf->prkey_source; + mp->reservation_key = conf->reservation_key; ++ mp->sa_flags = conf->sa_flags; + origin = "config file default"; + goto out; + } +@@ -736,14 +741,16 @@ select_reservation_key (struct multipath + out: + if (mp->prkey_source == PRKEY_SOURCE_FILE) { + from_file = " (from prkeys file)"; +- if (get_prkey(mp, &prkey) != 0) ++ if (get_prkey(mp, &prkey, &mp->sa_flags) != 0) + put_be64(mp->reservation_key, 0); + else + put_be64(mp->reservation_key, prkey); + } ++ if (mp->sa_flags & MPATH_F_APTPL_MASK) ++ flagstr = ":aptpl"; + if (get_be64(mp->reservation_key)) +- condlog(0, "%s: reservation_key = 0x%" PRIx64 " (%s)%s", +- mp->alias, get_be64(mp->reservation_key), origin, ++ condlog(0, "%s: reservation_key = 0x%" PRIx64 "%s (%s)%s", ++ mp->alias, get_be64(mp->reservation_key), flagstr, origin, + from_file); + return 0; + } +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1242,6 +1243,7 @@ cli_getprkey(void * v, char ** reply, in + struct multipath * mpp; + struct vectors * vecs = (struct vectors *)data; + char *mapname = get_keyparam(v, MAP); ++ char *flagstr = ""; + + mapname = convert_dev(mapname, 0); + condlog(3, "%s: get persistent reservation key (operator)", mapname); +@@ -1257,8 +1259,10 @@ cli_getprkey(void * v, char ** reply, in + *len = strlen(*reply) + 1; + return 0; + } +- snprintf(*reply, 20, "0x%" PRIx64 "\n", +- get_be64(mpp->reservation_key)); ++ if (mpp->sa_flags & MPATH_F_APTPL_MASK) ++ flagstr = ":aptpl"; ++ snprintf(*reply, 20, "0x%" PRIx64 "%s\n", ++ get_be64(mpp->reservation_key), flagstr); + (*reply)[19] = '\0'; + *len = strlen(*reply) + 1; + return 0; +@@ -1278,7 +1282,7 @@ cli_unsetprkey(void * v, char ** reply, + if (!mpp) + return 1; + +- return set_prkey(mpp, 0); ++ return set_prkey(mpp, 0, 0); + } + + int cli_setprkey(void * v, char ** reply, int * len, void * data) +@@ -1288,6 +1292,7 @@ int cli_setprkey(void * v, char ** reply + char *mapname = get_keyparam(v, MAP); + char *keyparam = get_keyparam(v, KEY); + uint64_t prkey; ++ uint8_t flags; + + mapname = convert_dev(mapname, 0); + condlog(3, "%s: set persistent reservation key (operator)", mapname); +@@ -1296,10 +1301,10 @@ int cli_setprkey(void * v, char ** reply + if (!mpp) + return 1; + +- if (parse_prkey(keyparam, &prkey) != 0) { ++ if (parse_prkey_flags(keyparam, &prkey, &flags) != 0) { + condlog(0, "%s: invalid prkey : '%s'", mapname, keyparam); + return 1; + } + +- return set_prkey(mpp, prkey); ++ return set_prkey(mpp, prkey, flags); + } +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -2324,6 +2324,7 @@ void * mpath_pr_event_handler_fn (void + + param= malloc(sizeof(struct prout_param_descriptor)); + memset(param, 0 , sizeof(struct prout_param_descriptor)); ++ param->sa_flags = mpp->sa_flags; + memcpy(param->sa_key, &mpp->reservation_key, 8); + param->num_transportid = 0; + +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -438,14 +438,18 @@ This is the service action reservation k + set for all multipath devices using persistent reservations, and it must be + the same as the RESERVATION KEY field of the PERSISTENT RESERVE OUT parameter + list which contains an 8-byte value provided by the application client to the +-device server to identify the I_T nexus. ++device server to identify the I_T nexus. If the \fI--param-aptpl\fR option is ++used when registering the key with mpathpersist, \fB:aptpl\fR must be appended ++to the end of the reservation key. ++ + .RS + .PP + Alternatively, this can be set to \fBfile\fR, which will store the RESERVATION + KEY registered by mpathpersist in the \fIprkeys_file\fR. multipathd will then + use this key to register additional paths as they appear. When the + registration is removed, the RESERVATION KEY is removed from the +-\fIprkeys_file\fR. ++\fIprkeys_file\fR. The prkeys file will automatically keep track of whether ++the key was registered with \fI--param-aptpl\fR. + It is unset by default. + .RE + .TP diff --git a/SOURCES/0244-RHBZ-1562247-remove-rbd.patch b/SOURCES/0244-RHBZ-1562247-remove-rbd.patch new file mode 100644 index 0000000..931aed6 --- /dev/null +++ b/SOURCES/0244-RHBZ-1562247-remove-rbd.patch @@ -0,0 +1,1159 @@ +--- + libmultipath/checkers.c | 23 - + libmultipath/checkers.h | 5 + libmultipath/checkers/Makefile | 7 + libmultipath/checkers/cciss_tur.c | 5 + libmultipath/checkers/directio.c | 5 + libmultipath/checkers/emc_clariion.c | 5 + libmultipath/checkers/hp_sw.c | 5 + libmultipath/checkers/rbd.c | 652 ----------------------------------- + libmultipath/checkers/rdac.c | 5 + libmultipath/checkers/readsector0.c | 5 + libmultipath/checkers/tur.c | 5 + libmultipath/discovery.c | 112 ------ + libmultipath/hwtable.c | 14 + libmultipath/structs.h | 1 + multipath.conf.annotated | 4 + multipath/multipath.conf.5 | 3 + multipathd/main.c | 13 + 17 files changed, 18 insertions(+), 851 deletions(-) + +Index: multipath-tools-130222/libmultipath/checkers/rbd.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rbd.c ++++ /dev/null +@@ -1,652 +0,0 @@ +-/* +- * Copyright (c) 2016 Red Hat +- * Copyright (c) 2004 Christophe Varoqui +- * +- * Code based off of tur.c and ceph's krbd.cc +- */ +-#define _GNU_SOURCE +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "rados/librados.h" +- +-#include "structs.h" +-#include "checkers.h" +- +-#include "../libmultipath/debug.h" +-#include "../libmultipath/uevent.h" +-#include "../libmultipath/util.h" +- +-struct rbd_checker_context; +-typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg); +- +-#define RBD_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args); +- +-#define RBD_FEATURE_EXCLUSIVE_LOCK (1 << 2) +- +-struct rbd_checker_context { +- int rbd_bus_id; +- char *client_addr; +- char *config_info; +- char *snap; +- char *pool; +- char *image; +- char *username; +- int remapped; +- int blacklisted; +- int lock_on_read:1; +- +- rados_t cluster; +- +- int state; +- int running; +- time_t time; +- thread_fn *fn; +- pthread_t thread; +- pthread_mutex_t lock; +- pthread_cond_t active; +- pthread_spinlock_t hldr_lock; +- int holders; +- char message[CHECKER_MSG_LEN]; +-}; +- +-int libcheck_init(struct checker * c) +-{ +- struct rbd_checker_context *ct; +- struct udev_device *block_dev; +- struct udev_device *bus_dev; +- struct udev *udev; +- struct stat sb; +- const char *block_name, *addr, *config_info, *features_str; +- const char *image, *pool, *snap, *username; +- uint64_t features = 0; +- char sysfs_path[PATH_SIZE]; +- int ret; +- +- ct = malloc(sizeof(struct rbd_checker_context)); +- if (!ct) +- return 1; +- memset(ct, 0, sizeof(struct rbd_checker_context)); +- ct->holders = 1; +- pthread_cond_init(&ct->active, NULL); +- pthread_mutex_init(&ct->lock, NULL); +- pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE); +- c->context = ct; +- +- /* +- * The rbd block layer sysfs device is not linked to the rbd bus +- * device that we interact with, so figure that out now. +- */ +- if (fstat(c->fd, &sb) != 0) +- goto free_ct; +- +- udev = udev_new(); +- if (!udev) +- goto free_ct; +- +- block_dev = udev_device_new_from_devnum(udev, 'b', sb.st_rdev); +- if (!block_dev) +- goto free_udev; +- +- block_name = udev_device_get_sysname(block_dev); +- ret = sscanf(block_name, "rbd%d", &ct->rbd_bus_id); +- +- udev_device_unref(block_dev); +- if (ret != 1) +- goto free_udev; +- +- snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/rbd/devices/%d", +- ct->rbd_bus_id); +- bus_dev = udev_device_new_from_syspath(udev, sysfs_path); +- if (!bus_dev) +- goto free_udev; +- +- addr = udev_device_get_sysattr_value(bus_dev, "client_addr"); +- if (!addr) { +- condlog(0, "rbd%d: Could not find client_addr in rbd sysfs. " +- "Try updating kernel", ct->rbd_bus_id); +- goto free_dev; +- } +- +- ct->client_addr = strdup(addr); +- if (!ct->client_addr) +- goto free_dev; +- +- features_str = udev_device_get_sysattr_value(bus_dev, "features"); +- if (!features_str) +- goto free_addr; +- features = strtoll(features_str, NULL, 16); +- if (!(features & RBD_FEATURE_EXCLUSIVE_LOCK)) { +- condlog(3, "rbd%d: Exclusive lock not set.", ct->rbd_bus_id); +- goto free_addr; +- } +- +- config_info = udev_device_get_sysattr_value(bus_dev, "config_info"); +- if (!config_info) +- goto free_addr; +- +- if (!strstr(config_info, "noshare")) { +- condlog(3, "rbd%d: Only nonshared clients supported.", +- ct->rbd_bus_id); +- goto free_addr; +- } +- +- if (strstr(config_info, "lock_on_read")) +- ct->lock_on_read = 1; +- +- ct->config_info = strdup(config_info); +- if (!ct->config_info) +- goto free_addr; +- +- username = strstr(config_info, "name="); +- if (username) { +- char *end; +- int len; +- +- username += 5; +- end = strchr(username, ','); +- if (!end) +- goto free_info; +- len = end - username; +- +- ct->username = malloc(len + 1); +- if (!ct->username) +- goto free_info; +- strncpy(ct->username, username, len); +- ct->username[len] = '\0'; +- } +- +- image = udev_device_get_sysattr_value(bus_dev, "name"); +- if (!image) +- goto free_username; +- +- ct->image = strdup(image); +- if (!ct->image) +- goto free_info; +- +- pool = udev_device_get_sysattr_value(bus_dev, "pool"); +- if (!pool) +- goto free_image; +- +- ct->pool = strdup(pool); +- if (!ct->pool) +- goto free_image; +- +- snap = udev_device_get_sysattr_value(bus_dev, "current_snap"); +- if (!snap) +- goto free_pool; +- +- if (strcmp("-", snap)) { +- ct->snap = strdup(snap); +- if (!ct->snap) +- goto free_pool; +- } +- +- if (rados_create(&ct->cluster, NULL) < 0) { +- condlog(0, "rbd%d: Could not create rados cluster", +- ct->rbd_bus_id); +- goto free_snap; +- } +- +- if (rados_conf_read_file(ct->cluster, NULL) < 0) { +- condlog(0, "rbd%d: Could not read rados conf", ct->rbd_bus_id); +- goto shutdown_rados; +- } +- +- ret = rados_connect(ct->cluster); +- if (ret < 0) { +- condlog(0, "rbd%d: Could not connect to rados cluster", +- ct->rbd_bus_id); +- goto shutdown_rados; +- } +- +- udev_device_unref(bus_dev); +- udev_unref(udev); +- +- condlog(3, "rbd%d checker init %s %s/%s@%s %s", ct->rbd_bus_id, +- ct->client_addr, ct->pool, ct->image, ct->snap ? ct->snap : "-", +- ct->username ? ct->username : "none"); +- return 0; +- +-shutdown_rados: +- rados_shutdown(ct->cluster); +-free_snap: +- if (ct->snap) +- free(ct->snap); +-free_pool: +- free(ct->pool); +-free_image: +- free(ct->image); +-free_username: +- if (ct->username) +- free(ct->username); +-free_info: +- free(ct->config_info); +-free_addr: +- free(ct->client_addr); +-free_dev: +- udev_device_unref(bus_dev); +-free_udev: +- udev_unref(udev); +-free_ct: +- free(ct); +- return 1; +-} +- +-void cleanup_context(struct rbd_checker_context *ct) +-{ +- pthread_mutex_destroy(&ct->lock); +- pthread_cond_destroy(&ct->active); +- pthread_spin_destroy(&ct->hldr_lock); +- +- rados_shutdown(ct->cluster); +- +- if (ct->username) +- free(ct->username); +- if (ct->snap) +- free(ct->snap); +- free(ct->pool); +- free(ct->image); +- free(ct->config_info); +- free(ct->client_addr); +- free(ct); +-} +- +-void libcheck_free(struct checker * c) +-{ +- if (c->context) { +- struct rbd_checker_context *ct = c->context; +- int holders; +- pthread_t thread; +- +- pthread_spin_lock(&ct->hldr_lock); +- ct->holders--; +- holders = ct->holders; +- thread = ct->thread; +- pthread_spin_unlock(&ct->hldr_lock); +- if (holders) +- pthread_cancel(thread); +- else +- cleanup_context(ct); +- c->context = NULL; +- } +-} +- +-static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg) +-{ +- char *addr_tok, *start, *save; +- char *cmd[2]; +- char *blklist, *stat; +- size_t blklist_len, stat_len; +- int ret; +- char *end; +- +- cmd[0] = "{\"prefix\": \"osd blacklist ls\"}"; +- cmd[1] = NULL; +- +- ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0, +- &blklist, &blklist_len, &stat, &stat_len); +- if (ret < 0) { +- RBD_MSG(msg, "checker failed: mon command failed %d", ret); +- return ret; +- } +- +- if (!blklist || !blklist_len) +- goto free_bufs; +- +- /* +- * parse list of addrs with the format +- * ipv4:port/nonce date time\n +- * or +- * [ipv6]:port/nonce date time\n +- */ +- ret = 0; +- for (start = blklist; ; start = NULL) { +- addr_tok = strtok_r(start, "\n", &save); +- if (!addr_tok || !strlen(addr_tok)) +- break; +- +- end = strchr(addr_tok, ' '); +- if (!end) { +- RBD_MSG(msg, "checker failed: invalid blacklist %s", +- addr_tok); +- break; +- } +- *end = '\0'; +- +- if (!strcmp(addr_tok, ct->client_addr)) { +- ct->blacklisted = 1; +- RBD_MSG(msg, "%s is blacklisted", ct->client_addr); +- ret = 1; +- break; +- } +- } +- +-free_bufs: +- rados_buffer_free(blklist); +- rados_buffer_free(stat); +- return ret; +-} +- +-int rbd_check(struct rbd_checker_context *ct, char *msg) +-{ +- if (ct->blacklisted || rbd_is_blacklisted(ct, msg) == 1) +- return PATH_DOWN; +- +- RBD_MSG(msg, "checker reports path is up"); +- /* +- * Path may have issues, but the ceph cluster is at least +- * accepting IO, so we can attempt to do IO. +- * +- * TODO: in future versions, we can run other tests to +- * verify OSDs and networks. +- */ +- return PATH_UP; +-} +- +-static int sysfs_write_rbd_bus(const char *which, const char *buf, +- size_t buf_len) +-{ +- char sysfs_path[PATH_SIZE]; +- int fd; +- int r; +- +- /* we require newer kernels so single_major should alwayws be there */ +- snprintf(sysfs_path, sizeof(sysfs_path), +- "/sys/bus/rbd/%s_single_major", which); +- fd = open(sysfs_path, O_WRONLY); +- if (fd < 0) +- return -errno; +- +- r = safe_write(fd, buf, buf_len); +- close(fd); +- return r; +-} +- +-static int rbd_remap(struct rbd_checker_context *ct) +-{ +- char *argv[11]; +- pid_t pid; +- int ret = 0, i = 0; +- int status; +- +- pid = fork(); +- switch (pid) { +- case 0: +- argv[i++] = "rbd"; +- argv[i++] = "map"; +- if (ct->lock_on_read) +- argv[i++] = "-o noshare,lock_on_read"; +- else +- argv[i++] = "-o noshare"; +- if (ct->username) { +- argv[i++] = "--id"; +- argv[i++] = ct->username; +- } +- argv[i++] = "--pool"; +- argv[i++] = ct->pool; +- if (ct->snap) { +- argv[i++] = "--snap"; +- argv[i++] = ct->snap; +- } +- argv[i++] = ct->image; +- argv[i] = NULL; +- +- ret = execvp(argv[0], argv); +- condlog(0, "rbd%d: Error executing rbd: %s", ct->rbd_bus_id, +- strerror(errno)); +- exit(-1); +- case -1: +- condlog(0, "rbd%d: fork failed: %s", ct->rbd_bus_id, +- strerror(errno)); +- return -1; +- default: +- ret = -1; +- wait(&status); +- if (WIFEXITED(status)) { +- status = WEXITSTATUS(status); +- if (status == 0) +- ret = 0; +- else +- condlog(0, "rbd%d: failed with %d", +- ct->rbd_bus_id, status); +- } +- } +- +- return ret; +-} +- +-static int sysfs_write_rbd_remove(const char *buf, int buf_len) +-{ +- return sysfs_write_rbd_bus("remove", buf, buf_len); +-} +- +-static int rbd_rm_blacklist(struct rbd_checker_context *ct) +-{ +- char *cmd[2]; +- char *stat, *cmd_str; +- size_t stat_len; +- int ret; +- +- ret = asprintf(&cmd_str, "{\"prefix\": \"osd blacklist\", \"blacklistop\": \"rm\", \"addr\": \"%s\"}", +- ct->client_addr); +- if (ret == -1) +- return -ENOMEM; +- +- cmd[0] = cmd_str; +- cmd[1] = NULL; +- +- ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0, +- NULL, 0, &stat, &stat_len); +- if (ret < 0) { +- condlog(1, "rbd%d: repair failed to remove blacklist for %s %d", +- ct->rbd_bus_id, ct->client_addr, ret); +- goto free_cmd; +- } +- +- condlog(1, "rbd%d: repair rm blacklist for %s", +- ct->rbd_bus_id, ct->client_addr); +- free(stat); +-free_cmd: +- free(cmd_str); +- return ret; +-} +- +-static int rbd_repair(struct rbd_checker_context *ct, char *msg) +-{ +- char del[17]; +- int ret; +- +- if (!ct->blacklisted) +- return PATH_UP; +- +- if (!ct->remapped) { +- ret = rbd_remap(ct); +- if (ret) { +- RBD_MSG(msg, "repair failed to remap. Err %d", ret); +- return PATH_DOWN; +- } +- } +- ct->remapped = 1; +- +- snprintf(del, sizeof(del), "%d force", ct->rbd_bus_id); +- ret = sysfs_write_rbd_remove(del, strlen(del) + 1); +- if (ret) { +- RBD_MSG(msg, "repair failed to clean up. Err %d", ret); +- return PATH_DOWN; +- } +- +- ret = rbd_rm_blacklist(ct); +- if (ret) { +- RBD_MSG(msg, "repair could not remove blacklist entry. Err %d", +- ret); +- return PATH_DOWN; +- } +- +- ct->remapped = 0; +- ct->blacklisted = 0; +- +- RBD_MSG(msg, "has been repaired"); +- return PATH_UP; +-} +- +-#define rbd_thread_cleanup_push(ct) pthread_cleanup_push(cleanup_func, ct) +-#define rbd_thread_cleanup_pop(ct) pthread_cleanup_pop(1) +- +-void cleanup_func(void *data) +-{ +- int holders; +- struct rbd_checker_context *ct = data; +- pthread_spin_lock(&ct->hldr_lock); +- ct->holders--; +- holders = ct->holders; +- ct->thread = 0; +- pthread_spin_unlock(&ct->hldr_lock); +- if (!holders) +- cleanup_context(ct); +-} +- +-void *rbd_thread(void *ctx) +-{ +- struct rbd_checker_context *ct = ctx; +- int state; +- +- condlog(3, "rbd%d: thread starting up", ct->rbd_bus_id); +- +- ct->message[0] = '\0'; +- /* This thread can be canceled, so setup clean up */ +- rbd_thread_cleanup_push(ct) +- +- /* checker start up */ +- pthread_mutex_lock(&ct->lock); +- ct->state = PATH_PENDING; +- pthread_mutex_unlock(&ct->lock); +- +- state = ct->fn(ct, ct->message); +- +- /* checker done */ +- pthread_mutex_lock(&ct->lock); +- ct->state = state; +- pthread_mutex_unlock(&ct->lock); +- pthread_cond_signal(&ct->active); +- +- condlog(3, "rbd%d: thead finished, state %s", ct->rbd_bus_id, +- checker_state_name(state)); +- rbd_thread_cleanup_pop(ct); +- return ((void *)0); +-} +- +-static void rbd_timeout(struct timespec *tsp) +-{ +- struct timeval now; +- +- gettimeofday(&now, NULL); +- tsp->tv_sec = now.tv_sec; +- tsp->tv_nsec = now.tv_usec * 1000; +- tsp->tv_nsec += 1000000; /* 1 millisecond */ +-} +- +-static int rbd_exec_fn(struct checker *c, thread_fn *fn) +-{ +- struct rbd_checker_context *ct = c->context; +- struct timespec tsp; +- pthread_attr_t attr; +- int rbd_status, r; +- +- if (c->sync) +- return fn(ct, c->message); +- /* +- * Async mode +- */ +- r = pthread_mutex_lock(&ct->lock); +- if (r != 0) { +- condlog(2, "rbd%d: mutex lock failed with %d", ct->rbd_bus_id, +- r); +- MSG(c, "rbd%d: thread failed to initialize", ct->rbd_bus_id); +- return PATH_WILD; +- } +- +- if (ct->running) { +- /* Check if checker is still running */ +- if (ct->thread) { +- condlog(3, "rbd%d: thread not finished", +- ct->rbd_bus_id); +- rbd_status = PATH_PENDING; +- } else { +- /* checker done */ +- ct->running = 0; +- rbd_status = ct->state; +- strncpy(c->message, ct->message, CHECKER_MSG_LEN); +- c->message[CHECKER_MSG_LEN - 1] = '\0'; +- } +- pthread_mutex_unlock(&ct->lock); +- } else { +- /* Start new checker */ +- ct->state = PATH_UNCHECKED; +- ct->fn = fn; +- pthread_spin_lock(&ct->hldr_lock); +- ct->holders++; +- pthread_spin_unlock(&ct->hldr_lock); +- setup_thread_attr(&attr, 32 * 1024, 1); +- r = pthread_create(&ct->thread, &attr, rbd_thread, ct); +- if (r) { +- pthread_mutex_unlock(&ct->lock); +- ct->thread = 0; +- ct->holders--; +- condlog(3, "rbd%d failed to start rbd thread, using sync mode", +- ct->rbd_bus_id); +- return fn(ct, c->message); +- } +- pthread_attr_destroy(&attr); +- rbd_timeout(&tsp); +- r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp); +- rbd_status = ct->state; +- strncpy(c->message, ct->message,CHECKER_MSG_LEN); +- c->message[CHECKER_MSG_LEN -1] = '\0'; +- pthread_mutex_unlock(&ct->lock); +- +- if (ct->thread && +- (rbd_status == PATH_PENDING || rbd_status == PATH_UNCHECKED)) { +- condlog(3, "rbd%d: thread still running", +- ct->rbd_bus_id); +- ct->running = 1; +- rbd_status = PATH_PENDING; +- } +- } +- +- return rbd_status; +-} +- +-void libcheck_repair(struct checker * c) +-{ +- struct rbd_checker_context *ct = c->context; +- +- if (!ct || !ct->blacklisted) +- return; +- rbd_exec_fn(c, rbd_repair); +-} +- +-int libcheck_check(struct checker * c) +-{ +- struct rbd_checker_context *ct = c->context; +- +- if (!ct) +- return PATH_UNCHECKED; +- +- if (ct->blacklisted) +- return PATH_DOWN; +- +- return rbd_exec_fn(c, rbd_check); +-} +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1291,16 +1291,6 @@ int update_path_groups(struct multipath + return 0; + } + +-void repair_path(struct path * pp) +-{ +- if (pp->state != PATH_DOWN) +- return; +- +- checker_repair(&pp->checker); +- if (strlen(checker_message(&pp->checker))) +- LOG_MSG(1, checker_message(&pp->checker)); +-} +- + void + check_path (struct vectors * vecs, struct path * pp) + { +@@ -1421,7 +1411,6 @@ check_path (struct vectors * vecs, struc + pp->mpp->failback_tick = 0; + + pp->mpp->stat_path_failures++; +- repair_path(pp); + return; + } + +@@ -1501,7 +1490,7 @@ check_path (struct vectors * vecs, struc + } + + pp->state = newstate; +- repair_path(pp); ++ + + if (pp->mpp->wait_for_udev) + return; +Index: multipath-tools-130222/libmultipath/checkers.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.c ++++ multipath-tools-130222/libmultipath/checkers.c +@@ -139,13 +139,6 @@ struct checker * add_checker (char * nam + if (!c->free) + goto out; + +- c->repair = (void (*)(struct checker *)) dlsym(c->handle, +- "libcheck_repair"); +- errstr = dlerror(); +- if (errstr != NULL) +- condlog(0, "A dynamic linking error occurred: (%s)", errstr); +- if (!c->repair) +- goto out; + done: + c->fd = 0; + c->sync = 1; +@@ -214,21 +207,6 @@ void checker_put (struct checker * dst) + free_checker(src); + } + +-void checker_repair (struct checker * c) +-{ +- if (!c || !checker_selected(c)) +- return; +- +- c->message[0] = '\0'; +- if (c->disable) { +- MSG(c, "checker disabled"); +- return; +- } +- +- if (c->repair) +- c->repair(c); +-} +- + int checker_check (struct checker * c, int path_state) + { + int r; +@@ -297,7 +275,6 @@ void checker_get (struct checker * dst, + dst->sync = src->sync; + strncpy(dst->name, src->name, CHECKER_NAME_LEN); + strncpy(dst->message, src->message, CHECKER_MSG_LEN); +- dst->repair = src->repair; + dst->check = src->check; + dst->init = src->init; + dst->free = src->free; +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1171,20 +1171,6 @@ static struct hwentry default_hw[] = { + .checker_name = TUR, + .dev_loss = 30, + }, +- { +- /* +- * Red Hat +- * +- * Maintainer: Mike Christie +- * Mail: mchristi@redhat.com +- */ +- .vendor = "Ceph", +- .product = "RBD", +- .pgpolicy = FAILOVER, +- .no_path_retry = NO_PATH_RETRY_FAIL, +- .checker_name = RBD, +- .deferred_remove = DEFERRED_REMOVE_ON, +- }, + /* + * Generic NVMe devices + */ +Index: multipath-tools-130222/libmultipath/checkers/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/Makefile ++++ multipath-tools-130222/libmultipath/checkers/Makefile +@@ -14,17 +14,10 @@ LIBS= \ + libcheckhp_sw.so \ + libcheckrdac.so + +-ifeq ($(shell test -r /usr/include/rados/librados.h && echo 1),1) +-LIBS += libcheckrbd.so +-endif +- + CFLAGS += -fPIC -I.. + + all: $(LIBS) + +-libcheckrbd.so: rbd.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lrados -ludev +- + libcheckdirectio.so: libsg.o directio.o + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio + +Index: multipath-tools-130222/multipath.conf.annotated +=================================================================== +--- multipath-tools-130222.orig/multipath.conf.annotated ++++ multipath-tools-130222/multipath.conf.annotated +@@ -97,7 +97,7 @@ + # # scope : multipath & multipathd + # # desc : the default method used to determine the paths' state + # # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac| +-# cciss_tur|hp_tur|rbd ++# cciss_tur|hp_tur + # # default : directio + # # + # path_checker directio +@@ -493,7 +493,7 @@ + # # scope : multipathd & multipathd + # # desc : path checking algorithm to use to check path state + # # values : readsector0|tur|emc_clariion|hp_sw|directio|rdac| +-# # cciss_tur|hp_tur|rbd ++# # cciss_tur|hp_tur + # # + # path_checker directio + # +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -287,9 +287,6 @@ Read the first sector with direct I/O. + .B none + Do not check the device, fallback to use the values retrieved from sysfs + .TP +-.B rbd +-Check if the path is in the Ceph blacklist. +-.TP + Default value is \fIdirectio\fR. + .RE + .TP +Index: multipath-tools-130222/libmultipath/checkers.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.h ++++ multipath-tools-130222/libmultipath/checkers.h +@@ -76,7 +76,6 @@ enum path_check_state { + #define READSECTOR0 "readsector0" + #define CCISS_TUR "cciss_tur" + #define NONE "none" +-#define RBD "rbd" + + #define DEFAULT_CHECKER DIRECTIO + +@@ -107,9 +106,6 @@ struct checker { + multipath-wide. Use MALLOC if + you want to stuff data in. */ + int (*check)(struct checker *); +- void (*repair)(struct checker *); /* called if check returns +- PATH_DOWN to bring path into +- usable state */ + int (*init)(struct checker *); /* to allocate the context */ + void (*free)(struct checker *); /* to free the context */ + }; +@@ -129,7 +125,6 @@ void checker_set_async (struct checker * + void checker_set_fd (struct checker *, int); + void checker_enable (struct checker *); + void checker_disable (struct checker *); +-void checker_repair (struct checker *); + int checker_check (struct checker *, int); + int checker_selected (struct checker *); + char * checker_name (struct checker *); +Index: multipath-tools-130222/libmultipath/checkers/cciss_tur.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/cciss_tur.c ++++ multipath-tools-130222/libmultipath/checkers/cciss_tur.c +@@ -63,11 +63,6 @@ void libcheck_free (struct checker * c) + return; + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + extern int + libcheck_check (struct checker * c) + { +Index: multipath-tools-130222/libmultipath/checkers/directio.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/directio.c ++++ multipath-tools-130222/libmultipath/checkers/directio.c +@@ -116,11 +116,6 @@ void libcheck_free (struct checker * c) + free(ct); + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + static int + check_state(int fd, struct directio_context *ct, int sync, int timeout_secs) + { +Index: multipath-tools-130222/libmultipath/checkers/emc_clariion.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/emc_clariion.c ++++ multipath-tools-130222/libmultipath/checkers/emc_clariion.c +@@ -90,11 +90,6 @@ void libcheck_free (struct checker * c) + free(c->context); + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + int libcheck_check (struct checker * c) + { + unsigned char sense_buffer[128] = { 0, }; +Index: multipath-tools-130222/libmultipath/checkers/hp_sw.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/hp_sw.c ++++ multipath-tools-130222/libmultipath/checkers/hp_sw.c +@@ -44,11 +44,6 @@ void libcheck_free (struct checker * c) + return; + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + static int + do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, + void *resp, int mx_resp_len, int noisy, unsigned int timeout) +Index: multipath-tools-130222/libmultipath/checkers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c ++++ multipath-tools-130222/libmultipath/checkers/rdac.c +@@ -139,11 +139,6 @@ void libcheck_free (struct checker * c) + return; + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + static int + do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len, + unsigned int timeout) +Index: multipath-tools-130222/libmultipath/checkers/readsector0.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/readsector0.c ++++ multipath-tools-130222/libmultipath/checkers/readsector0.c +@@ -23,11 +23,6 @@ void libcheck_free (struct checker * c) + return; + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + int libcheck_check (struct checker * c) + { + unsigned char buf[4096]; +Index: multipath-tools-130222/libmultipath/checkers/tur.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/tur.c ++++ multipath-tools-130222/libmultipath/checkers/tur.c +@@ -187,11 +187,6 @@ void libcheck_free (struct checker * c) + return; + } + +-void libcheck_repair (struct checker * c) +-{ +- return; +-} +- + #define TUR_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args); + + int +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -922,21 +922,6 @@ nvme_sysfs_pathinfo (struct path * pp) + } + + static int +-rbd_sysfs_pathinfo (struct path * pp) +-{ +- sprintf(pp->vendor_id, "Ceph"); +- sprintf(pp->product_id, "RBD"); +- +- condlog(3, "%s: vendor = %s product = %s", pp->dev, pp->vendor_id, +- pp->product_id); +- /* +- * set the hwe configlet pointer +- */ +- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL); +- return 0; +-} +- +-static int + ccw_sysfs_pathinfo (struct path * pp) + { + struct udev_device *parent; +@@ -1151,8 +1136,6 @@ sysfs_pathinfo(struct path * pp) + pp->bus = SYSFS_BUS_CCW; + if (!strncmp(pp->dev,"sd", 2)) + pp->bus = SYSFS_BUS_SCSI; +- if (!strncmp(pp->dev,"rbd", 3)) +- pp->bus = SYSFS_BUS_RBD; + if (!strncmp(pp->dev,"nvme", 4)) + pp->bus = SYSFS_BUS_NVME; + +@@ -1167,9 +1150,6 @@ sysfs_pathinfo(struct path * pp) + } else if (pp->bus == SYSFS_BUS_CCISS) { + if (cciss_sysfs_pathinfo(pp)) + return 1; +- } else if (pp->bus == SYSFS_BUS_RBD) { +- if (rbd_sysfs_pathinfo(pp)) +- return 1; + } else if (pp->bus == SYSFS_BUS_NVME) { + if (nvme_sysfs_pathinfo(pp)) + return 1; +@@ -1275,55 +1255,6 @@ get_prio (struct path * pp) + return 0; + } + +-static int +-get_rbd_uid(struct path * pp) +-{ +- struct udev_device *rbd_bus_dev; +- int ret, rbd_bus_id; +- const char *pool, *image, *snap; +- char sysfs_path[PATH_SIZE]; +- uint64_t snap_id, max_snap_id = -3; +- +- ret = sscanf(pp->dev, "rbd%d", &rbd_bus_id); +- if (ret != 1) +- return -EINVAL; +- +- snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/rbd/devices/%d", +- rbd_bus_id); +- rbd_bus_dev = udev_device_new_from_syspath(conf->udev, sysfs_path); +- if (!rbd_bus_dev) +- return -ENODEV; +- +- ret = -EINVAL; +- pool = udev_device_get_sysattr_value(rbd_bus_dev, "pool_id"); +- if (!pool) +- goto free_dev; +- +- image = udev_device_get_sysattr_value(rbd_bus_dev, "image_id"); +- if (!image) +- goto free_dev; +- +- snap = udev_device_get_sysattr_value(rbd_bus_dev, "snap_id"); +- if (!snap) +- goto free_dev; +- snap_id = strtoull(snap, NULL, 19); +- if (snap_id >= max_snap_id) +- ret = snprintf(pp->wwid, WWID_SIZE, "%s-%s", pool, image); +- else +- ret = snprintf(pp->wwid, WWID_SIZE, "%s-%s-%s", pool, +- image, snap); +- if (ret < WWID_SIZE) { +- ret = 0; +- } else { +- condlog(0, "%s: wwid overflow", pp->dev); +- ret = -EOVERFLOW; +- } +- +-free_dev: +- udev_device_unref(rbd_bus_dev); +- return ret; +-} +- + /* + * Mangle string of length *len starting at start + * by removing character sequence "00" (hex for a 0 byte), +@@ -1405,7 +1336,6 @@ get_uid (struct path * pp, struct udev_d + { + char *c; + const char *value; +- int ret; + + if (!pp->uid_attribute) + select_getuid(pp); +@@ -1416,34 +1346,22 @@ get_uid (struct path * pp, struct udev_d + } + + memset(pp->wwid, 0, WWID_SIZE); +- if (pp->bus == SYSFS_BUS_RBD) { +- ret = get_rbd_uid(pp); +- if (ret) { +- condlog(1, "%s: failed to get sysfs uid: %s", +- pp->dev, strerror(-ret)); +- pp->missing_udev_info = INFO_MISSING; +- pp->tick = conf->retrigger_delay; +- } ++ value = udev_device_get_property_value(udev, pp->uid_attribute); ++ if ((!value || strlen(value) == 0) && conf->cmd == CMD_VALID_PATH) ++ value = getenv(pp->uid_attribute); ++ if (value && strlen(value)) { ++ size_t len = strlcpy(pp->wwid, value, WWID_SIZE); ++ if (len > WWID_SIZE && ++ !fix_broken_nvme_wwid(pp, value, WWID_SIZE)) ++ condlog(0, "%s: wwid overflow", pp->dev); ++ condlog(4, "%s: got wwid of '%s'", pp->dev, pp->wwid); ++ pp->missing_udev_info = INFO_OK; ++ pp->tick = 0; + } else { +- value = udev_device_get_property_value(udev, +- pp->uid_attribute); +- if ((!value || strlen(value) == 0) && +- conf->cmd == CMD_VALID_PATH) +- value = getenv(pp->uid_attribute); +- if (value && strlen(value)) { +- size_t len = strlcpy(pp->wwid, value, WWID_SIZE); +- if (len > WWID_SIZE && +- !fix_broken_nvme_wwid(pp, value, WWID_SIZE)) +- condlog(0, "%s: wwid overflow", pp->dev); +- condlog(4, "%s: got wwid of '%s'", pp->dev, pp->wwid); +- pp->missing_udev_info = INFO_OK; +- pp->tick = 0; +- } else { +- condlog(3, "%s: no %s attribute", pp->dev, +- pp->uid_attribute); +- pp->missing_udev_info = INFO_MISSING; +- pp->tick = conf->retrigger_delay; +- } ++ condlog(3, "%s: no %s attribute", pp->dev, ++ pp->uid_attribute); ++ pp->missing_udev_info = INFO_MISSING; ++ pp->tick = conf->retrigger_delay; + } + + /* Strip any trailing blanks */ +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -60,7 +60,6 @@ enum sysfs_buses { + SYSFS_BUS_IDE, + SYSFS_BUS_CCW, + SYSFS_BUS_CCISS, +- SYSFS_BUS_RBD, + SYSFS_BUS_NVME, + }; + diff --git a/SOURCES/0245-RHBZ-1584228-fix-readsector0_size.patch b/SOURCES/0245-RHBZ-1584228-fix-readsector0_size.patch new file mode 100644 index 0000000..c15013d --- /dev/null +++ b/SOURCES/0245-RHBZ-1584228-fix-readsector0_size.patch @@ -0,0 +1,17 @@ +--- + libmultipath/checkers/readsector0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/checkers/readsector0.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/readsector0.c ++++ multipath-tools-130222/libmultipath/checkers/readsector0.c +@@ -29,7 +29,7 @@ int libcheck_check (struct checker * c) + unsigned char sbuf[SENSE_BUFF_LEN]; + int ret; + +- ret = sg_read(c->fd, &buf[0], 4069, &sbuf[0], ++ ret = sg_read(c->fd, &buf[0], 4096, &sbuf[0], + SENSE_BUFF_LEN, c->timeout); + + switch (ret) diff --git a/SOURCES/0246-RHBZ-1593459-add-transport-blacklist.patch b/SOURCES/0246-RHBZ-1593459-add-transport-blacklist.patch new file mode 100644 index 0000000..7eb88cf --- /dev/null +++ b/SOURCES/0246-RHBZ-1593459-add-transport-blacklist.patch @@ -0,0 +1,519 @@ +--- + libmultipath/blacklist.c | 50 ++++++++++++++++++++++++++---- + libmultipath/blacklist.h | 3 + + libmultipath/config.c | 16 +++++++++ + libmultipath/config.h | 2 + + libmultipath/dict.c | 38 +++++++++++++++++++++-- + libmultipath/discovery.c | 5 +-- + libmultipath/print.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/print.h | 2 + + libmultipath/structs.h | 1 + multipath/multipath.conf.5 | 15 +++++++++ + 10 files changed, 194 insertions(+), 12 deletions(-) + +Index: multipath-tools-130222/libmultipath/blacklist.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.c ++++ multipath-tools-130222/libmultipath/blacklist.c +@@ -12,6 +12,8 @@ + #include "structs.h" + #include "config.h" + #include "blacklist.h" ++#include "structs_vec.h" ++#include "print.h" + + extern int + store_ble (vector blist, char * str, int origin) +@@ -211,12 +213,14 @@ setup_default_blist (struct config * con + condlog(3, "%s: (%s) %s", dev, wwid, (M)); \ + else if (env) \ + condlog(3, "%s: (%s) %s", dev, env, (M)); \ ++ else if (protocol) \ ++ condlog(3, "%s: (%s) %s", dev, protocol, (M)); \ + else \ + condlog(3, "%s: %s", dev, (M)) + + void + log_filter (const char *dev, char *vendor, char *product, char *wwid, +- const char *env, int r) ++ const char *env, char *protocol, int r) + { + /* + * Try to sort from most likely to least. +@@ -236,6 +240,9 @@ log_filter (const char *dev, char *vendo + case MATCH_PROPERTY_BLIST: + LOG_BLIST("udev property blacklisted"); + break; ++ case MATCH_PROTOCOL_BLIST: ++ LOG_BLIST("protocol blacklisted"); ++ break; + case MATCH_DEVICE_BLIST_EXCEPT: + LOG_BLIST("vendor/product whitelisted"); + break; +@@ -251,6 +258,9 @@ log_filter (const char *dev, char *vendo + case MATCH_PROPERTY_BLIST_MISSING: + LOG_BLIST("blacklisted, udev property missing"); + break; ++ case MATCH_PROTOCOL_BLIST_EXCEPT: ++ LOG_BLIST("protocol whitelisted"); ++ break; + } + } + +@@ -270,7 +280,7 @@ int + filter_device (vector blist, vector elist, char * vendor, char * product) + { + int r = _filter_device(blist, elist, vendor, product); +- log_filter(NULL, vendor, product, NULL, NULL, r); ++ log_filter(NULL, vendor, product, NULL, NULL, NULL, r); + return r; + } + +@@ -290,7 +300,7 @@ int + filter_devnode (vector blist, vector elist, char * dev) + { + int r = _filter_devnode(blist, elist, dev); +- log_filter(dev, NULL, NULL, NULL, NULL, r); ++ log_filter(dev, NULL, NULL, NULL, NULL, NULL, r); + return r; + } + +@@ -310,7 +320,7 @@ int + filter_wwid (vector blist, vector elist, char * wwid) + { + int r = _filter_wwid(blist, elist, wwid); +- log_filter(NULL, NULL, NULL, wwid, NULL, r); ++ log_filter(NULL, NULL, NULL, wwid, NULL, NULL, r); + return r; + } + +@@ -346,7 +356,7 @@ filter_property(struct config * conf, st + + r = _filter_property(conf, env); + if (r) { +- log_filter(devname, NULL, NULL, NULL, env, r); ++ log_filter(devname, NULL, NULL, NULL, env, NULL, r); + return r; + } + } +@@ -356,13 +366,35 @@ filter_property(struct config * conf, st + * the environment variable _has_ to match. + */ + if (VECTOR_SIZE(conf->elist_property)) { +- log_filter(devname, NULL, NULL, NULL, NULL, ++ log_filter(devname, NULL, NULL, NULL, NULL, NULL, + MATCH_PROPERTY_BLIST_MISSING); + return MATCH_PROPERTY_BLIST_MISSING; + } + return 0; + } + ++static int ++_filter_protocol(vector blist, vector elist, char *protocol_str) ++{ ++ if (_blacklist_exceptions(elist, protocol_str)) ++ return MATCH_PROTOCOL_BLIST_EXCEPT; ++ if (_blacklist(blist, protocol_str)) ++ return MATCH_PROTOCOL_BLIST; ++ return 0; ++} ++ ++int ++filter_protocol(vector blist, vector elist, struct path * pp) ++{ ++ char buf[PROTOCOL_BUF_SIZE]; ++ int r; ++ ++ snprint_path_protocol(buf, sizeof(buf), pp); ++ r = _filter_protocol(blist, elist, buf); ++ log_filter(pp->dev, NULL, NULL, NULL, NULL, buf, r); ++ return r; ++} ++ + int + _filter_path (struct config * conf, struct path * pp) + { +@@ -371,6 +403,9 @@ _filter_path (struct config * conf, stru + r = filter_property(conf, pp->udev); + if (r > 0) + return r; ++ r = filter_protocol(conf->blist_protocol, conf->elist_protocol, pp); ++ if (r > 0) ++ return r; + r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev); + if (r > 0) + return r; +@@ -386,7 +421,8 @@ int + filter_path (struct config * conf, struct path * pp) + { + int r=_filter_path(conf, pp); +- log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, r); ++ log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, ++ NULL, r); + return r; + } + +Index: multipath-tools-130222/libmultipath/blacklist.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/blacklist.h ++++ multipath-tools-130222/libmultipath/blacklist.h +@@ -10,10 +10,12 @@ + #define MATCH_DEVNODE_BLIST 3 + #define MATCH_PROPERTY_BLIST 4 + #define MATCH_PROPERTY_BLIST_MISSING 5 ++#define MATCH_PROTOCOL_BLIST 6 + #define MATCH_WWID_BLIST_EXCEPT -MATCH_WWID_BLIST + #define MATCH_DEVICE_BLIST_EXCEPT -MATCH_DEVICE_BLIST + #define MATCH_DEVNODE_BLIST_EXCEPT -MATCH_DEVNODE_BLIST + #define MATCH_PROPERTY_BLIST_EXCEPT -MATCH_PROPERTY_BLIST ++#define MATCH_PROTOCOL_BLIST_EXCEPT -MATCH_PROTOCOL_BLIST + + struct blentry { + char * str; +@@ -36,6 +38,7 @@ int filter_wwid (vector, vector, char *) + int filter_device (vector, vector, char *, char *); + int filter_path (struct config *, struct path *); + int filter_property(struct config *, struct udev_device *); ++int filter_protocol(vector, vector, struct path *); + int store_ble (vector, char *, int); + int set_ble_device (vector, char *, char *, int); + void free_blacklist (vector); +Index: multipath-tools-130222/libmultipath/config.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.c ++++ multipath-tools-130222/libmultipath/config.c +@@ -600,11 +600,13 @@ free_config (struct config * conf) + free_blacklist(conf->blist_devnode); + free_blacklist(conf->blist_wwid); + free_blacklist(conf->blist_property); ++ free_blacklist(conf->blist_protocol); + free_blacklist_device(conf->blist_device); + + free_blacklist(conf->elist_devnode); + free_blacklist(conf->elist_wwid); + free_blacklist(conf->elist_property); ++ free_blacklist(conf->elist_protocol); + free_blacklist_device(conf->elist_device); + + free_mptable(conf->mptable); +@@ -792,6 +794,13 @@ load_config (char * file, struct udev *u + goto out; + } + ++ if (conf->blist_protocol == NULL) { ++ conf->blist_protocol = vector_alloc(); ++ ++ if (!conf->blist_protocol) ++ goto out; ++ } ++ + if (conf->elist_devnode == NULL) { + conf->elist_devnode = vector_alloc(); + +@@ -819,6 +828,13 @@ load_config (char * file, struct udev *u + goto out; + } + ++ if (conf->elist_protocol == NULL) { ++ conf->elist_protocol = vector_alloc(); ++ ++ if (!conf->elist_protocol) ++ goto out; ++ } ++ + if (setup_default_blist(conf)) + goto out; + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -194,10 +194,12 @@ struct config { + vector blist_wwid; + vector blist_device; + vector blist_property; ++ vector blist_protocol; + vector elist_devnode; + vector elist_wwid; + vector elist_device; + vector elist_property; ++ vector elist_protocol; + }; + + struct config * conf; +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -1092,9 +1092,12 @@ blacklist_handler(vector strvec) + conf->blist_device = vector_alloc(); + if (!conf->blist_property) + conf->blist_property = vector_alloc(); ++ if (!conf->blist_protocol) ++ conf->blist_protocol = vector_alloc(); + + if (!conf->blist_devnode || !conf->blist_wwid || +- !conf->blist_device || !conf->blist_property) ++ !conf->blist_device || !conf->blist_property || ++ !conf->blist_protocol) + return 1; + + return 0; +@@ -1111,9 +1114,12 @@ blacklist_exceptions_handler(vector strv + conf->elist_device = vector_alloc(); + if (!conf->elist_property) + conf->elist_property = vector_alloc(); ++ if (!conf->elist_protocol) ++ conf->elist_protocol = vector_alloc(); + + if (!conf->elist_devnode || !conf->elist_wwid || +- !conf->elist_device || !conf->elist_property) ++ !conf->elist_device || !conf->elist_property || ++ !conf->elist_protocol) + return 1; + + return 0; +@@ -1198,6 +1204,32 @@ ble_except_property_handler(vector strve + } + + static int ++ble_protocol_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ return store_ble(conf->blist_protocol, buff, ORIGIN_CONFIG); ++} ++ ++static int ++ble_except_protocol_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ return store_ble(conf->elist_protocol, buff, ORIGIN_CONFIG); ++} ++ ++static int + ble_device_handler(vector strvec) + { + return alloc_ble_device(conf->blist_device); +@@ -4021,6 +4053,7 @@ init_keywords(void) + install_keyword_multi("devnode", &ble_devnode_handler, &snprint_ble_simple); + install_keyword_multi("wwid", &ble_wwid_handler, &snprint_ble_simple); + install_keyword_multi("property", &ble_property_handler, &snprint_ble_simple); ++ install_keyword_multi("protocol", &ble_protocol_handler, &snprint_ble_simple); + install_keyword_multi("device", &ble_device_handler, NULL); + install_sublevel(); + install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor); +@@ -4030,6 +4063,7 @@ init_keywords(void) + install_keyword_multi("devnode", &ble_except_devnode_handler, &snprint_ble_simple); + install_keyword_multi("wwid", &ble_except_wwid_handler, &snprint_ble_simple); + install_keyword_multi("property", &ble_except_property_handler, &snprint_ble_simple); ++ install_keyword_multi("protocol", &ble_except_protocol_handler, &snprint_ble_simple); + install_keyword_multi("device", &ble_except_device_handler, NULL); + install_sublevel(); + install_keyword("vendor", &ble_except_vendor_handler, &snprint_bled_vendor); +Index: multipath-tools-130222/libmultipath/print.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.c ++++ multipath-tools-130222/libmultipath/print.c +@@ -607,6 +607,48 @@ snprint_path_failures(char * buff, size_ + return snprint_int(buff, len, pp->failcount); + } + ++/* if you add a protocol string bigger than "scsi:unspec" you must ++ * also change PROTOCOL_BUF_SIZE */ ++int ++snprint_path_protocol(char * buff, size_t len, struct path * pp) ++{ ++ switch (pp->bus) { ++ case SYSFS_BUS_SCSI: ++ switch (pp->sg_id.proto_id) { ++ case SCSI_PROTOCOL_FCP: ++ return snprintf(buff, len, "scsi:fcp"); ++ case SCSI_PROTOCOL_SPI: ++ return snprintf(buff, len, "scsi:spi"); ++ case SCSI_PROTOCOL_SSA: ++ return snprintf(buff, len, "scsi:ssa"); ++ case SCSI_PROTOCOL_SBP: ++ return snprintf(buff, len, "scsi:sbp"); ++ case SCSI_PROTOCOL_SRP: ++ return snprintf(buff, len, "scsi:srp"); ++ case SCSI_PROTOCOL_ISCSI: ++ return snprintf(buff, len, "scsi:iscsi"); ++ case SCSI_PROTOCOL_SAS: ++ return snprintf(buff, len, "scsi:sas"); ++ case SCSI_PROTOCOL_ADT: ++ return snprintf(buff, len, "scsi:adt"); ++ case SCSI_PROTOCOL_ATA: ++ return snprintf(buff, len, "scsi:ata"); ++ case SCSI_PROTOCOL_UNSPEC: ++ default: ++ return snprintf(buff, len, "scsi:unspec"); ++ } ++ case SYSFS_BUS_CCW: ++ return snprintf(buff, len, "ccw"); ++ case SYSFS_BUS_CCISS: ++ return snprintf(buff, len, "cciss"); ++ case SYSFS_BUS_NVME: ++ return snprintf(buff, len, "nvme"); ++ case SYSFS_BUS_UNDEF: ++ default: ++ return snprintf(buff, len, "undef"); ++ } ++} ++ + struct multipath_data mpd[] = { + {'n', "name", 0, snprint_name}, + {'w', "uuid", 0, snprint_multipath_uuid}, +@@ -654,6 +696,7 @@ struct path_data pd[] = { + {'r', "target WWPN", 0, snprint_tgt_wwpn}, + {'a', "host adapter", 0, snprint_host_adapter}, + {'0', "failures", 0, snprint_path_failures}, ++ {'P', "protocol", 0, snprint_path_protocol}, + {0, NULL, 0 , NULL} + }; + +@@ -1435,6 +1478,19 @@ snprint_blacklist_report (char * buff, i + + if ((len - fwd - threshold) <= 0) + return len; ++ fwd += snprintf(buff + fwd, len - fwd, "protocol rules:\n" ++ "- blacklist:\n"); ++ if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_protocol)) ++ return len; ++ ++ if ((len - fwd - threshold) <= 0) ++ return len; ++ fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n"); ++ if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_protocol) == 0) ++ return len; ++ ++ if ((len - fwd - threshold) <= 0) ++ return len; + fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n" + "- blacklist:\n"); + if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0) +@@ -1509,6 +1565,15 @@ snprint_blacklist (char * buff, int len) + if (fwd > len) + return len; + } ++ vector_foreach_slot (conf->blist_protocol, ble, i) { ++ kw = find_keyword(rootkw->sub, "protocol"); ++ if (!kw) ++ return 0; ++ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n", ++ kw, ble); ++ if (fwd > len) ++ return len; ++ } + rootkw = find_keyword(rootkw->sub, "device"); + if (!rootkw) + return 0; +@@ -1582,6 +1647,15 @@ snprint_blacklist_except (char * buff, i + if (!kw) + return 0; + fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n", ++ kw, ele); ++ if (fwd > len) ++ return len; ++ } ++ vector_foreach_slot (conf->elist_protocol, ele, i) { ++ kw = find_keyword(rootkw->sub, "protocol"); ++ if (!kw) ++ return 0; ++ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n", + kw, ele); + if (fwd > len) + return len; +Index: multipath-tools-130222/libmultipath/print.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/print.h ++++ multipath-tools-130222/libmultipath/print.h +@@ -115,6 +115,8 @@ int snprint_host_wwnn (char *, size_t, s + int snprint_host_wwpn (char *, size_t, struct path *); + int snprint_tgt_wwnn (char *, size_t, struct path *); + int snprint_tgt_wwpn (char *, size_t, struct path *); ++#define PROTOCOL_BUF_SIZE sizeof("scsi:unspec") ++int snprint_path_protocol(char *, size_t, struct path *); + + void print_multipath_topology (struct multipath * mpp, int verbosity); + void print_path (struct path * pp, char * style); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -57,7 +57,6 @@ enum failback_mode { + enum sysfs_buses { + SYSFS_BUS_UNDEF, + SYSFS_BUS_SCSI, +- SYSFS_BUS_IDE, + SYSFS_BUS_CCW, + SYSFS_BUS_CCISS, + SYSFS_BUS_NVME, +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1407,9 +1407,10 @@ pathinfo (struct path *pp, vector hwtabl + + if (mask & DI_BLACKLIST && mask & DI_SYSFS) { + if (filter_device(conf->blist_device, conf->elist_device, +- pp->vendor_id, pp->product_id) > 0) { ++ pp->vendor_id, pp->product_id) > 0 || ++ filter_protocol(conf->blist_protocol, conf->elist_protocol, ++ pp) > 0) + return PATHINFO_SKIPPED; +- } + } + + path_state = path_offline(pp); +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -640,6 +640,10 @@ Regular expression of the device nodes t + .B property + Regular expresion of the udev property to be excluded. + .TP ++.B protocol ++Regular expression of the protocol to be excluded. See below for a ++list of recognized protocols ++.TP + .B device + Subsection for the device description. This subsection recognizes the + .I vendor +@@ -648,6 +652,13 @@ and + keywords. For a full description of these keywords please see the + .I devices + section description. ++.LP ++The protocol strings that multipath recognizes are \fIscsi:fcp\fR, ++\fIscsi:spi\fR, \fIscsi:ssa\fR, \fIscsi:sbp\fR, \fIscsi:srp\fR, ++\fIscsi:iscsi\fR, \fIscsi:sas\fR, \fIscsi:adt\fR, \fIscsi:ata\fR, ++\fIscsi:unspec\fR, \fIccw\fR, \fIcciss\fR, \fInvme\fR, and \fIundef\fR. ++The protocol that a path is using can be viewed by running ++\fBmultipathd show paths format "%d %P"\fR + .SH "blacklist_exceptions section" + The + .I blacklist_exceptions +@@ -667,6 +678,10 @@ The \fIWorld Wide Identification\fR of a + .B property + Regular expresion of the udev property to be whitelisted. + .TP ++.B protocol ++Regular expression of the protocol to be whitelisted. See the ++\fBblacklist section\fR for a list of recognized protocols ++.TP + .B devnode + Regular expression of the device nodes to be whitelisted. + .TP diff --git a/SOURCES/0247-RHBZ-1585824-mpathconf-allow-doc.patch b/SOURCES/0247-RHBZ-1585824-mpathconf-allow-doc.patch new file mode 100644 index 0000000..4af5baa --- /dev/null +++ b/SOURCES/0247-RHBZ-1585824-mpathconf-allow-doc.patch @@ -0,0 +1,36 @@ +--- + multipath/mpathconf.8 | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +Index: multipath-tools-130222/multipath/mpathconf.8 +=================================================================== +--- multipath-tools-130222.orig/multipath/mpathconf.8 ++++ multipath-tools-130222/multipath/mpathconf.8 +@@ -61,6 +61,16 @@ Adds a line that blacklists all device n + .B /etc/multipath.conf + blacklist section. If no blacklist section exists, it will create one. + .TP ++.B --allow \fB\fP ++Modifies the \fB/etc/multipath/conf\fP blacklist to blacklist all ++wwids and the blacklist_exceptions to whitelist \fB\fP. \fB\fP ++can be in the form of MAJOR:MINOR, a wwid, or the name of a device-mapper ++device, either a multipath device, or any device on stacked on top of one or ++more multipath devices. This command can be used multiple times to allow ++multiple devices. \fBNOTE:\fP This action will create a configuration file that ++mpathconf will not be able to revert back to its previous state. Because ++of this, \fB--outfile\fP is required when using \fB--allow\fP. ++.TP + .B --user_friendly_name \fP { \fBy\fP | \fBn\fP } + If set to \fBy\fP, this adds the line + .B user_friendly_names yes +@@ -76,6 +86,10 @@ to the + .B /etc/multipath.conf + defaults section. If set to \fBn\fP, this removes the line, if present. This + command can be used aldong with any other command. ++.TP ++.B --outfile \fB\fP ++Write the resulting multipath configuration to \fB\fP instead of ++\fB/etc/multipath.conf\fP. + .SH OPTIONS + .TP + .B --with_module\fP { \fBy\fP | \fBn\fP } diff --git a/SOURCES/0248-RHBZ-1594360-fix-param-rk-doc.patch b/SOURCES/0248-RHBZ-1594360-fix-param-rk-doc.patch new file mode 100644 index 0000000..3377c76 --- /dev/null +++ b/SOURCES/0248-RHBZ-1594360-fix-param-rk-doc.patch @@ -0,0 +1,32 @@ +--- + mpathpersist/main.c | 2 ++ + mpathpersist/mpathpersist.8 | 3 +++ + 2 files changed, 5 insertions(+) + +Index: multipath-tools-130222/mpathpersist/main.c +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.c ++++ multipath-tools-130222/mpathpersist/main.c +@@ -677,6 +677,8 @@ static void usage() + " --out|-o request PR Out command\n" + " --param-aptpl|-Z PR Out parameter 'APTPL'\n" + " --read-keys|-k PR In: Read Keys\n" ++ " --param-rk=RK|-K RK PR Out parameter reservation " ++ "key\n" + " --param-sark=SARK|-S SARK PR Out parameter service " + "action\n" + " reservation key (SARK is in " +Index: multipath-tools-130222/mpathpersist/mpathpersist.8 +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/mpathpersist.8 ++++ multipath-tools-130222/mpathpersist/mpathpersist.8 +@@ -48,6 +48,9 @@ PR Out parameter 'APTPL' + \fB\-\-read\-keys\fR|\-k + PR In: Read Keys + .TP ++\fB\-\-param\-rk\fR=\fIRK\fR|\-K RK ++PR Out parameter reservation key (RK is in hex) ++.TP + \fB\-\-param\-sark\fR=\fISARK\fR|\-S SARK + PR Out parameter service action + reservation key (SARK is in hex) diff --git a/SOURCES/0249-RHBZ-1610263-mpathpersist-max-fds.patch b/SOURCES/0249-RHBZ-1610263-mpathpersist-max-fds.patch new file mode 100644 index 0000000..4ad0525 --- /dev/null +++ b/SOURCES/0249-RHBZ-1610263-mpathpersist-max-fds.patch @@ -0,0 +1,228 @@ +--- + libmpathpersist/mpath_persist.c | 4 +++- + libmpathpersist/mpath_pr_ioctl.c | 4 +++- + libmpathpersist/mpathpr.h | 1 - + libmultipath/configure.c | 29 +++++++++++++++++++++++++++++ + libmultipath/configure.h | 1 + + mpathpersist/main.c | 8 +++++++- + multipath/main.c | 13 +------------ + multipathd/main.c | 28 +--------------------------- + 8 files changed, 45 insertions(+), 43 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include "mpath_persist.h" + #include "mpathpr.h" +@@ -71,7 +72,8 @@ updatepaths (struct multipath * mpp) + + vector_foreach_slot (pgp->paths, pp, j){ + if (!strlen(pp->dev)){ +- if (devt2devname(pp->dev, pp->dev_t)){ ++ if (devt2devname(pp->dev, sizeof(pp->dev), ++ pp->dev_t)){ + /* + * path is not in sysfs anymore + */ +Index: multipath-tools-130222/libmpathpersist/mpath_pr_ioctl.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_pr_ioctl.c ++++ multipath-tools-130222/libmpathpersist/mpath_pr_ioctl.c +@@ -1,5 +1,6 @@ + #include + #include ++#include + + #include + #include +@@ -306,7 +307,8 @@ int prin_do_scsi_ioctl(char * dev, int r + snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev); + fd = open(devname, O_WRONLY); + if(fd < 0){ +- condlog(0, "%s: Unable to open device ", dev); ++ condlog(0, "%s: Unable to open device: %s", devname, ++ strerror(errno)); + return MPATH_PR_FILE_ERROR; + } + +Index: multipath-tools-130222/libmpathpersist/mpathpr.h +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpathpr.h ++++ multipath-tools-130222/libmpathpersist/mpathpr.h +@@ -54,6 +54,5 @@ int update_prkey_flags(char *mapname, ui + #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); +-int devt2devname (char *devname, char *devt); + + #endif +Index: multipath-tools-130222/mpathpersist/main.c +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.c ++++ multipath-tools-130222/mpathpersist/main.c +@@ -5,6 +5,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -264,7 +268,7 @@ int main (int argc, char * argv[]) + + /* set verbosity */ + noisy = (loglevel >= 3) ? 1 : hex; +- verbose = (loglevel >= 3)? 3: loglevel; ++ verbose = (loglevel >= 4)? 4 : loglevel; + + if ((prout_flag + prin_flag) == 0) + { +@@ -356,6 +360,8 @@ int main (int argc, char * argv[]) + goto out; + } + ++ set_max_fds(conf->max_fds); ++ + /* open device */ + if ((fd = open (device_name, O_WRONLY)) < 0) + { +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -15,6 +15,8 @@ + #include + #include + #include ++#include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -1143,3 +1145,30 @@ extern int reload_map(struct vectors *ve + + return 0; + } ++ ++void set_max_fds(int max_fds) ++{ ++ struct rlimit fd_limit; ++ ++ if (!max_fds) ++ return; ++ ++ if (getrlimit(RLIMIT_NOFILE, &fd_limit) < 0) { ++ condlog(0, "can't get open fds limit: %s", ++ strerror(errno)); ++ fd_limit.rlim_cur = 0; ++ fd_limit.rlim_max = 0; ++ } ++ if (fd_limit.rlim_cur < conf->max_fds) { ++ fd_limit.rlim_cur = conf->max_fds; ++ if (fd_limit.rlim_max < conf->max_fds) ++ fd_limit.rlim_max = conf->max_fds; ++ if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0) ++ condlog(0, "can't set open fds limit to %lu/%lu : %s", ++ fd_limit.rlim_cur, fd_limit.rlim_max, ++ strerror(errno)); ++ else ++ condlog(3, "set open fds limit to %lu/%lu", ++ fd_limit.rlim_cur, fd_limit.rlim_max); ++ } ++} +Index: multipath-tools-130222/libmultipath/configure.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.h ++++ multipath-tools-130222/libmultipath/configure.h +@@ -33,3 +33,4 @@ int get_refwwid (char * dev, enum devtyp + int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh); + int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name); + void trigger_uevents (struct multipath *mpp); ++void set_max_fds(int max_fds); +Index: multipath-tools-130222/multipath/main.c +=================================================================== +--- multipath-tools-130222.orig/multipath/main.c ++++ multipath-tools-130222/multipath/main.c +@@ -52,8 +52,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include "dev_t.h" +@@ -638,16 +636,7 @@ main (int argc, char *argv[]) + } + } + conf->daemon = 0; +- +- if (conf->max_fds) { +- struct rlimit fd_limit; +- +- fd_limit.rlim_cur = conf->max_fds; +- fd_limit.rlim_max = conf->max_fds; +- if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0) +- condlog(0, "can't set open fds limit to %d : %s", +- conf->max_fds, strerror(errno)); +- } ++ set_max_fds(conf->max_fds); + + if (init_checkers()) { + condlog(0, "failed to initialize checkers"); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -12,8 +12,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -1946,31 +1944,7 @@ child (void * param) + + setlogmask(LOG_UPTO(conf->verbosity + 3)); + +- if (conf->max_fds) { +- struct rlimit fd_limit; +- +- if (getrlimit(RLIMIT_NOFILE, &fd_limit) < 0) { +- condlog(0, "can't get open fds limit: %s", +- strerror(errno)); +- fd_limit.rlim_cur = 0; +- fd_limit.rlim_max = 0; +- } +- if (fd_limit.rlim_cur < conf->max_fds) { +- fd_limit.rlim_cur = conf->max_fds; +- if (fd_limit.rlim_max < conf->max_fds) +- fd_limit.rlim_max = conf->max_fds; +- if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0) { +- condlog(0, "can't set open fds limit to " +- "%lu/%lu : %s", +- fd_limit.rlim_cur, fd_limit.rlim_max, +- strerror(errno)); +- } else { +- condlog(3, "set open fds limit to %lu/%lu", +- fd_limit.rlim_cur, fd_limit.rlim_max); +- } +- } +- +- } ++ set_max_fds(conf->max_fds); + + vecs = gvecs = init_vecs(); + if (!vecs) { diff --git a/SOURCES/0250-RHBZ-1610867-rescan-change.patch b/SOURCES/0250-RHBZ-1610867-rescan-change.patch new file mode 100644 index 0000000..4ac655b --- /dev/null +++ b/SOURCES/0250-RHBZ-1610867-rescan-change.patch @@ -0,0 +1,268 @@ +--- + libmultipath/structs_vec.c | 103 +++++++++------------------------------------ + libmultipath/structs_vec.h | 6 ++ + multipathd/main.c | 50 +++++++++++++++++++++ + 3 files changed, 75 insertions(+), 84 deletions(-) + +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -103,7 +103,7 @@ orphan_paths (vector pathvec, struct mul + } + } + +-static void ++void + set_multipath_wwid (struct multipath * mpp) + { + if (strlen(mpp->wwid)) +@@ -188,57 +188,36 @@ remove_maps_and_stop_waiters (struct vec + _remove_maps(vecs, STOP_WAITER); + } + +-static struct hwentry * ++void + extract_hwe_from_path(struct multipath * mpp) + { + struct path * pp = NULL; +- int pg_num = -1, p_num = -1, i; +- struct pathgroup * pgp = NULL; +- +- condlog(3, "%s: searching paths for valid hwe", mpp->alias); ++ int i; + +- if (mpp && mpp->pg) { +- vector_foreach_slot(mpp->pg, pgp, i) { +- if (pgp->status == PGSTATE_ACTIVE || +- pgp->status == PGSTATE_ENABLED) { +- pg_num = i; +- break; +- } +- } +- if (pg_num >= 0) +- pgp = VECTOR_SLOT(mpp->pg, pg_num); +- } ++ if (mpp->hwe || !mpp->paths) ++ return; + +- if (pgp && pgp->paths) { +- vector_foreach_slot(pgp->paths, pp, i) { +- if (pp->dmstate == PSTATE_FAILED) +- continue; +- if (strlen(pp->vendor_id) > 0 && +- strlen(pp->product_id) > 0 && +- strlen(pp->rev) > 0) { +- p_num = i; +- break; +- } ++ condlog(3, "%s: searching paths for valid hwe", mpp->alias); ++ /* doing this in two passes seems like paranoia to me */ ++ vector_foreach_slot(mpp->paths, pp, i) { ++ if (pp->state != PATH_UP) ++ continue; ++ if (pp->hwe) { ++ mpp->hwe = pp->hwe; ++ return; + } +- if (p_num >= 0) +- pp = VECTOR_SLOT(pgp->paths, i); + } +- +- if (pp) { +- condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); +- condlog(3, "%s: product = %s", pp->dev, pp->product_id); +- condlog(3, "%s: rev = %s", pp->dev, pp->rev); +- if (!pp->hwe) { +- condlog(3, "searching hwtable"); +- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, +- pp->product_id, pp->rev); ++ vector_foreach_slot(mpp->paths, pp, i) { ++ if (pp->state == PATH_UP) ++ continue; ++ if (pp->hwe) { ++ mpp->hwe = pp->hwe; ++ return; + } + } +- +- return pp?pp->hwe:NULL; + } + +-static int ++int + update_multipath_table (struct multipath *mpp, vector pathvec) + { + char params[PARAMS_SIZE] = {0}; +@@ -259,7 +238,7 @@ update_multipath_table (struct multipath + return 0; + } + +-static int ++int + update_multipath_status (struct multipath *mpp) + { + char status[PARAMS_SIZE] = {0}; +@@ -371,21 +350,11 @@ __setup_multipath (struct vectors * vecs + goto out; + } + +- set_multipath_wwid(mpp); +- mpp->mpe = find_mpe(mpp->wwid); +- condlog(3, "%s: discover", mpp->alias); +- + if (update_multipath_strings(mpp, vecs->pathvec)) { + condlog(0, "%s: failed to setup multipath", mpp->alias); + goto out; + } + +- if (!mpp->hwe) +- mpp->hwe = extract_hwe_from_path(mpp); +- if (!mpp->hwe) { +- condlog(3, "%s: no hardware entry found, using defaults", +- mpp->alias); +- } + if (reset) { + select_rr_weight(mpp); + select_pgfailback(mpp); +@@ -402,36 +371,6 @@ out: + return 1; + } + +-extern struct multipath * +-add_map_without_path (struct vectors * vecs, char * alias) +-{ +- struct multipath * mpp = alloc_multipath(); +- +- if (!mpp || !alias) +- return NULL; +- +- mpp->alias = STRDUP(alias); +- +- if (setup_multipath(vecs, mpp)) +- return NULL; /* mpp freed in setup_multipath */ +- +- if (adopt_paths(vecs->pathvec, mpp, 1)) +- goto out; +- +- if (!vector_alloc_slot(vecs->mpvec)) +- goto out; +- +- vector_set_slot(vecs->mpvec, mpp); +- +- if (start_waiter_thread(mpp, vecs)) +- goto out; +- +- return mpp; +-out: +- remove_map(mpp, vecs, PURGE_VEC); +- return NULL; +-} +- + static void + find_existing_alias (struct multipath * mpp, + struct vectors *vecs) +Index: multipath-tools-130222/libmultipath/structs_vec.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.h ++++ multipath-tools-130222/libmultipath/structs_vec.h +@@ -31,11 +31,15 @@ void remove_map_and_stop_waiter (struct + void remove_maps (struct vectors * vecs); + void remove_maps_and_stop_waiters (struct vectors * vecs); + +-struct multipath * add_map_without_path (struct vectors * vecs, char * alias); + struct multipath * add_map_with_path (struct vectors * vecs, + struct path * pp, int add_vec); + int update_multipath (struct vectors *vecs, char *mapname, int reset); + void update_queue_mode_del_path(struct multipath *mpp); + void update_queue_mode_add_path(struct multipath *mpp); + ++void extract_hwe_from_path(struct multipath * mpp); ++void set_multipath_wwid (struct multipath * mpp); ++int update_multipath_table (struct multipath *mpp, vector pathvec); ++int update_multipath_status (struct multipath *mpp); ++ + #endif /* _STRUCTS_VEC_H */ +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -273,6 +273,7 @@ retry: + mpp->flush_on_last_del = FLUSH_UNDEF; + mpp->action = ACT_RELOAD; + ++ extract_hwe_from_path(mpp); + if (setup_map(mpp, params, PARAMS_SIZE)) { + condlog(0, "%s: failed to setup new map in update", mpp->alias); + retries = -1; +@@ -296,6 +297,49 @@ fail: + return 0; + } + ++static struct multipath * ++add_map_without_path (struct vectors * vecs, char * alias) ++{ ++ struct multipath * mpp = alloc_multipath(); ++ ++ if (!mpp) ++ return NULL; ++ if (!alias) { ++ FREE(mpp); ++ return NULL; ++ } ++ ++ mpp->alias = STRDUP(alias); ++ ++ if (dm_get_info(mpp->alias, &mpp->dmi)) { ++ condlog(3, "%s: cannot access table", mpp->alias); ++ goto out; ++ } ++ set_multipath_wwid(mpp); ++ mpp->mpe = find_mpe(mpp->wwid); ++ ++ if (update_multipath_table(mpp, vecs->pathvec)) ++ goto out; ++ if (update_multipath_status(mpp)) ++ goto out; ++ ++ if (!vector_alloc_slot(vecs->mpvec)) ++ goto out; ++ ++ vector_set_slot(vecs->mpvec, mpp); ++ ++ if (update_map(mpp, vecs) != 0) /* map removed */ ++ return NULL; ++ ++ if (start_waiter_thread(mpp, vecs)) ++ goto out; ++ ++ return mpp; ++out: ++ remove_map(mpp, vecs, 1); ++ return NULL; ++} ++ + static int + uev_add_map (struct uevent * uev, struct vectors * vecs) + { +@@ -569,6 +613,7 @@ rescan: + verify_paths(mpp, vecs, NULL); + mpp->flush_on_last_del = FLUSH_UNDEF; + mpp->action = ACT_RELOAD; ++ extract_hwe_from_path(mpp); + } else { + if (!should_multipath(pp, vecs->pathvec)) { + orphan_path(pp); +@@ -855,8 +900,11 @@ map_discovery (struct vectors * vecs) + return 1; + + vector_foreach_slot (vecs->mpvec, mpp, i) +- if (setup_multipath(vecs, mpp)) ++ if (update_multipath_table(mpp, vecs->pathvec) || ++ update_multipath_status(mpp)) { ++ remove_map(mpp, vecs, 1); + i--; ++ } + + return 0; + } diff --git a/SOURCES/0251-RHBZ-1614011-discovery-timeout.patch b/SOURCES/0251-RHBZ-1614011-discovery-timeout.patch new file mode 100644 index 0000000..0a7bda7 --- /dev/null +++ b/SOURCES/0251-RHBZ-1614011-discovery-timeout.patch @@ -0,0 +1,34 @@ +--- + libmultipath/discovery.c | 5 ++++- + libmultipath/discovery.h | 2 +- + 2 files changed, 5 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -749,7 +749,10 @@ do_inq(int sg_fd, int cmddt, int evpd, u + io_hdr.dxferp = resp; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_b; +- io_hdr.timeout = DEF_TIMEOUT; ++ if (conf->checker_timeout) ++ io_hdr.timeout = conf->checker_timeout * 1000; ++ else ++ io_hdr.timeout = DEF_TIMEOUT; + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) + return -1; +Index: multipath-tools-130222/libmultipath/discovery.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.h ++++ multipath-tools-130222/libmultipath/discovery.h +@@ -14,7 +14,7 @@ + #endif + + #ifndef DEF_TIMEOUT +-#define DEF_TIMEOUT 300000 ++#define DEF_TIMEOUT 60000 + #endif + + /* diff --git a/SOURCES/0252-RHBZ-1623595-cmd-error-status.patch b/SOURCES/0252-RHBZ-1623595-cmd-error-status.patch new file mode 100644 index 0000000..aaf06c4 --- /dev/null +++ b/SOURCES/0252-RHBZ-1623595-cmd-error-status.patch @@ -0,0 +1,85 @@ +--- + multipathd/main.c | 6 ++---- + multipathd/uxclnt.c | 22 +++++++++++++--------- + 2 files changed, 15 insertions(+), 13 deletions(-) + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -2234,8 +2234,7 @@ main (int argc, char *argv[]) + conf->verbosity = atoi(optarg); + break; + case 'k': +- uxclnt(optarg); +- exit(0); ++ return(uxclnt(optarg)); + case 'B': + conf->bindings_read_only = 1; + break; +@@ -2256,8 +2255,7 @@ main (int argc, char *argv[]) + optind++; + } + c += snprintf(c, s + CMDSIZE - c, "\n"); +- uxclnt(s); +- exit(0); ++ return(uxclnt(s)); + } + + if (!logsink) +Index: multipath-tools-130222/multipathd/uxclnt.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/uxclnt.c ++++ multipath-tools-130222/multipathd/uxclnt.c +@@ -74,20 +74,24 @@ static void process(int fd) + } + } + +-static void process_req(int fd, char * inbuf) ++static int process_req(int fd, char * inbuf) + { + char *reply; ++ int ret; + + if (send_packet(fd, inbuf) != 0) { + printf("cannot send packet\n"); +- return; ++ return 1; + } +- if (recv_packet(fd, &reply) != 0) ++ if (recv_packet(fd, &reply) != 0) { + printf("error receiving packet\n"); +- else { +- printf("%s", reply); +- FREE(reply); ++ return 1; + } ++ printf("%s", reply); ++ ret = (strcmp(reply, "fail\n") == 0); ++ FREE(reply); ++ /* Need to do better about getting return value */ ++ return ret; + } + + /* +@@ -95,7 +99,7 @@ static void process_req(int fd, char * i + */ + int uxclnt(char * inbuf) + { +- int fd; ++ int fd, ret = 0; + + fd = mpath_connect(); + if (fd == -1) { +@@ -104,9 +108,9 @@ int uxclnt(char * inbuf) + } + + if (inbuf) +- process_req(fd, inbuf); ++ ret = process_req(fd, inbuf); + else + process(fd); + +- return 0; ++ return ret; + } diff --git a/SOURCES/0253-RHBZ-1618549-mix-hw-handler.patch b/SOURCES/0253-RHBZ-1618549-mix-hw-handler.patch new file mode 100644 index 0000000..0ff9346 --- /dev/null +++ b/SOURCES/0253-RHBZ-1618549-mix-hw-handler.patch @@ -0,0 +1,104 @@ +--- + libmultipath/configure.c | 2 - + libmultipath/propsel.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 59 insertions(+), 1 deletion(-) + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -282,6 +282,7 @@ setup_map (struct multipath * mpp, char + select_pgpolicy(mpp); + select_selector(mpp); + select_features(mpp); ++ select_retain_hwhandler(mpp); + select_hwhandler(mpp); + select_rr_weight(mpp); + select_minio(mpp); +@@ -293,7 +294,6 @@ setup_map (struct multipath * mpp, char + select_fast_io_fail(mpp); + select_dev_loss(mpp); + select_reservation_key(mpp); +- select_retain_hwhandler(mpp); + select_deferred_remove(mpp); + select_delay_watch_checks(mpp); + select_delay_wait_checks(mpp); +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -19,6 +19,8 @@ + #include "discovery.h" + #include "prioritizers/alua_rtpg.h" + #include "prkey.h" ++#include "sysfs.h" ++#include "util.h" + #include + #include + #include +@@ -317,9 +319,65 @@ select_features (struct multipath * mp) + return 0; + } + ++static int get_dh_state(struct path *pp, char *value, size_t value_len) ++{ ++ int ret; ++ struct udev_device *ud; ++ ++ if (pp->udev == NULL) ++ return -1; ++ ++ ud = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", ++ "scsi_device"); ++ if (ud == NULL) ++ return -1; ++ ++ ret = sysfs_attr_get_value(ud, "dh_state", value, value_len); ++ if (ret > 0) ++ strchop(value); ++ return ret; ++} ++ ++static int ++use_attached_hwhandler(struct multipath * mp) ++{ ++ int i; ++ struct path *pp; ++ int attached_hwhandler = 0; ++ /* dh_state is no longer than "detached" */ ++ char dh_state[10]; ++ ++ vector_foreach_slot (mp->paths, pp, i) { ++ if (get_dh_state(pp, dh_state, sizeof(dh_state)) > 0 && ++ strcmp(dh_state, "detached") != 0) { ++ if (!attached_hwhandler) { ++ if (asprintf(&mp->hwhandler, "1 %s", ++ dh_state) < 0) ++ return 0; ++ attached_hwhandler = 1; ++ /* if we find 2 different hardware handlers, disable ++ * retain_attached_hw_handler, and use the configured ++ * handler */ ++ } else if (strcmp(dh_state, &mp->hwhandler[2]) != 0) { ++ FREE(mp->hwhandler); ++ mp->hwhandler = NULL; ++ mp->retain_hwhandler = RETAIN_HWHANDLER_OFF; ++ condlog(0, "%s: retain_attached_hw_hander disabled (inconsistent handlers on paths)", mp->alias); ++ return 0; ++ } ++ } ++ } ++ return attached_hwhandler; ++} ++ + extern int + select_hwhandler (struct multipath * mp) + { ++ if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON && ++ use_attached_hwhandler(mp)) { ++ condlog(3, "%s: hwhandler = %s (setting: retained by kernel driver)", mp->alias, mp->hwhandler); ++ return 0; ++ } + if (mp->hwe && mp->hwe->hwhandler) { + mp->hwhandler = mp->hwe->hwhandler; + condlog(3, "%s: hwhandler = %s (controller setting)", diff --git a/SOURCES/0254-RHBZ-1635819-fix-mpathpersist-crash.patch b/SOURCES/0254-RHBZ-1635819-fix-mpathpersist-crash.patch new file mode 100644 index 0000000..5a41381 --- /dev/null +++ b/SOURCES/0254-RHBZ-1635819-fix-mpathpersist-crash.patch @@ -0,0 +1,36 @@ +--- + libmpathpersist/mpath_persist.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -524,10 +524,10 @@ int mpath_prout_reg(struct multipath *mp + if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){ + rollback = 1; + sa_key = 0; +- for (i = 0; i < 8; ++i){ +- if (i > 0) ++ for (j = 0; j < 8; ++j){ ++ if (j > 0) + sa_key <<= 8; +- sa_key |= paramp->sa_key[i]; ++ sa_key |= paramp->sa_key[j]; + } + status = MPATH_PR_RESERV_CONFLICT ; + } +@@ -537,11 +537,10 @@ int mpath_prout_reg(struct multipath *mp + } + if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){ + condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid); ++ memcpy(¶mp->key, ¶mp->sa_key, 8); ++ memset(¶mp->sa_key, 0, 8); + for( i=0 ; i < count ; i++){ + if (thread[i].param.status == MPATH_PR_SUCCESS) { +- memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8); +- memset(&thread[i].param.paramp->sa_key, 0, 8); +- thread[i].param.status = MPATH_PR_SUCCESS; + rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn, + (void *)(&thread[i].param)); + if (rc){ diff --git a/SOURCES/0255-RHBZ-1638651-marginal-path.patch b/SOURCES/0255-RHBZ-1638651-marginal-path.patch new file mode 100644 index 0000000..93521b4 --- /dev/null +++ b/SOURCES/0255-RHBZ-1638651-marginal-path.patch @@ -0,0 +1,2028 @@ +--- + libmultipath/Makefile | 7 + libmultipath/config.h | 12 + libmultipath/configure.c | 18 - + libmultipath/configure.h | 3 + libmultipath/defaults.h | 1 + libmultipath/dict.c | 410 ++++++++++++++++++++++++ + libmultipath/io_err_stat.c | 763 +++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/io_err_stat.h | 15 + libmultipath/propsel.c | 98 +++++ + libmultipath/propsel.h | 4 + libmultipath/structs.h | 14 + libmultipath/time-util.c | 42 ++ + libmultipath/time-util.h | 13 + libmultipath/uevent.c | 38 ++ + libmultipath/uevent.h | 2 + multipath/multipath.conf.5 | 108 ++++++ + multipathd/cli_handlers.c | 2 + multipathd/main.c | 64 +++ + 18 files changed, 1599 insertions(+), 15 deletions(-) + +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -7,16 +7,17 @@ include ../Makefile.inc + SONAME=0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) +-LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd ++LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd -laio + CFLAGS += -fPIC -I$(mpathcmddir) -I$(mpathpersistdir) + + OBJS = memory.o parser.o vector.o devmapper.o \ + hwtable.o blacklist.o util.o dmparser.o config.o \ + structs.o discovery.o propsel.o dict.o \ +- pgpolicies.o debug.o regex.o defaults.o uevent.o \ ++ pgpolicies.o debug.o regex.o defaults.o uevent.o time-util.o \ + switchgroup.o uxsock.o print.o alias.o log_pthread.o \ + log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \ +- lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o ++ lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \ ++ io_err_stat.o + + LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h) + +Index: multipath-tools-130222/libmultipath/config.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/config.h ++++ multipath-tools-130222/libmultipath/config.h +@@ -67,6 +67,10 @@ struct hwentry { + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; ++ int marginal_path_err_sample_time; ++ int marginal_path_err_rate_threshold; ++ int marginal_path_err_recheck_gap_time; ++ int marginal_path_double_failed_time; + int skip_kpartx; + int max_sectors_kb; + int unpriv_sgio; +@@ -100,6 +104,10 @@ struct mpentry { + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; ++ int marginal_path_err_sample_time; ++ int marginal_path_err_rate_threshold; ++ int marginal_path_err_recheck_gap_time; ++ int marginal_path_double_failed_time; + int skip_kpartx; + int max_sectors_kb; + int unpriv_sgio; +@@ -153,6 +161,10 @@ struct config { + int processed_main_config; + int delay_watch_checks; + int delay_wait_checks; ++ int marginal_path_err_sample_time; ++ int marginal_path_err_rate_threshold; ++ int marginal_path_err_recheck_gap_time; ++ int marginal_path_double_failed_time; + int retrigger_tries; + int retrigger_delay; + int new_bindings_in_boot; +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -42,6 +42,7 @@ + #include "uxsock.h" + #include "wwids.h" + #include "sysfs.h" ++#include "io_err_stat.h" + + /* group paths in pg by host adapter + */ +@@ -257,7 +258,8 @@ int rr_optimize_path_order(struct pathgr + } + + extern int +-setup_map (struct multipath * mpp, char * params, int params_size) ++setup_map (struct multipath * mpp, char * params, int params_size, ++ struct vectors *vecs) + { + struct pathgroup * pgp; + int i, old_nr_active; +@@ -297,11 +299,21 @@ setup_map (struct multipath * mpp, char + select_deferred_remove(mpp); + select_delay_watch_checks(mpp); + select_delay_wait_checks(mpp); ++ select_marginal_path_err_sample_time(mpp); ++ select_marginal_path_err_rate_threshold(mpp); ++ select_marginal_path_err_recheck_gap_time(mpp); ++ select_marginal_path_double_failed_time(mpp); + select_skip_kpartx(mpp); + select_max_sectors_kb(mpp); + select_unpriv_sgio(mpp); + + sysfs_set_scsi_tmo(mpp); ++ ++ if (mpp->marginal_path_double_failed_time > 0 && ++ mpp->marginal_path_err_sample_time > 0 && ++ mpp->marginal_path_err_recheck_gap_time > 0 && ++ mpp->marginal_path_err_rate_threshold >= 0) ++ start_io_err_stat_thread(vecs); + /* + * assign paths to path groups -- start with no groups and all paths + * in mpp->paths +@@ -867,7 +879,7 @@ coalesce_paths (struct vectors * vecs, v + verify_paths(mpp, vecs, NULL); + + params[0] = '\0'; +- if (setup_map(mpp, params, PARAMS_SIZE)) { ++ if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + remove_map(mpp, vecs, 0); + continue; + } +@@ -1118,7 +1130,7 @@ extern int reload_map(struct vectors *ve + vector_foreach_slot (mpp->paths, pp, i) + pathinfo(pp, conf->hwtable, DI_PRIO); + } +- if (setup_map(mpp, params, PARAMS_SIZE)) { ++ if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + condlog(0, "%s: failed to setup map", mpp->alias); + return 1; + } +Index: multipath-tools-130222/libmultipath/configure.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.h ++++ multipath-tools-130222/libmultipath/configure.h +@@ -24,7 +24,8 @@ enum actions { + #define FLUSH_ONE 1 + #define FLUSH_ALL 2 + +-int setup_map (struct multipath * mpp, char * params, int params_size ); ++int setup_map (struct multipath * mpp, char * params, int params_size, ++ struct vectors *vecs); + int domap (struct multipath * mpp, char * params); + int reinstate_paths (struct multipath *mpp); + int check_daemon(void); +Index: multipath-tools-130222/libmultipath/defaults.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/defaults.h ++++ multipath-tools-130222/libmultipath/defaults.h +@@ -22,6 +22,7 @@ + #define DEFAULT_DETECT_CHECKER DETECT_CHECKER_OFF + #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF + #define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF ++#define DEFAULT_MARGINAL_PATH MARGINAL_PATH_OFF + #define DEFAULT_RETRIGGER_DELAY 10 + #define DEFAULT_RETRIGGER_TRIES 3 + #define DEFAULT_UEV_WAIT_TIMEOUT 30 +Index: multipath-tools-130222/libmultipath/dict.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/dict.c ++++ multipath-tools-130222/libmultipath/dict.c +@@ -1077,6 +1077,81 @@ def_all_tg_pt_handler(vector strvec) + return 0; + } + ++static int ++def_marginal_path_err_sample_time_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->marginal_path_err_sample_time = MARGINAL_PATH_OFF; ++ else if ((conf->marginal_path_err_sample_time = atoi(buff)) < 1) ++ conf->marginal_path_err_sample_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++def_marginal_path_err_rate_threshold_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->marginal_path_err_rate_threshold = MARGINAL_PATH_OFF; ++ else if ((conf->marginal_path_err_rate_threshold = atoi(buff)) < 1) ++ conf->marginal_path_err_rate_threshold = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++def_marginal_path_err_recheck_gap_time_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->marginal_path_err_recheck_gap_time = MARGINAL_PATH_OFF; ++ else if ((conf->marginal_path_err_recheck_gap_time = atoi(buff)) < 1) ++ conf->marginal_path_err_recheck_gap_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++def_marginal_path_double_failed_time_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->marginal_path_double_failed_time = MARGINAL_PATH_OFF; ++ else if ((conf->marginal_path_double_failed_time = atoi(buff)) < 1) ++ conf->marginal_path_double_failed_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} + + /* + * blacklist block handlers +@@ -2055,6 +2130,98 @@ hw_all_tg_pt_handler(vector strvec) + return 0; + } + ++static int ++hw_marginal_path_err_sample_time_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->marginal_path_err_sample_time = MARGINAL_PATH_OFF; ++ else if ((hwe->marginal_path_err_sample_time = atoi(buff)) < 1) ++ hwe->marginal_path_err_sample_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++hw_marginal_path_err_rate_threshold_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->marginal_path_err_rate_threshold = MARGINAL_PATH_OFF; ++ else if ((hwe->marginal_path_err_rate_threshold = atoi(buff)) < 1) ++ hwe->marginal_path_err_rate_threshold = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++hw_marginal_path_err_recheck_gap_time_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->marginal_path_err_recheck_gap_time = MARGINAL_PATH_OFF; ++ else if ((hwe->marginal_path_err_recheck_gap_time = atoi(buff)) < 1) ++ hwe->marginal_path_err_recheck_gap_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++hw_marginal_path_double_failed_time_handler(vector strvec) ++{ ++ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable); ++ char * buff; ++ ++ if (!hwe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ hwe->marginal_path_double_failed_time = MARGINAL_PATH_OFF; ++ else if ((hwe->marginal_path_double_failed_time = atoi(buff)) < 1) ++ hwe->marginal_path_double_failed_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * multipaths block handlers + */ +@@ -2659,6 +2826,98 @@ mp_ghost_delay_handler(vector strvec) + return 0; + } + ++static int ++mp_marginal_path_err_sample_time_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->marginal_path_err_sample_time = MARGINAL_PATH_OFF; ++ else if ((mpe->marginal_path_err_sample_time = atoi(buff)) < 1) ++ mpe->marginal_path_err_sample_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++mp_marginal_path_err_rate_threshold_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->marginal_path_err_rate_threshold = MARGINAL_PATH_OFF; ++ else if ((mpe->marginal_path_err_rate_threshold = atoi(buff)) < 1) ++ mpe->marginal_path_err_rate_threshold = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++mp_marginal_path_err_recheck_gap_time_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->marginal_path_err_recheck_gap_time = MARGINAL_PATH_OFF; ++ else if ((mpe->marginal_path_err_recheck_gap_time = atoi(buff)) < 1) ++ mpe->marginal_path_err_recheck_gap_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int ++mp_marginal_path_double_failed_time_handler(vector strvec) ++{ ++ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); ++ char * buff; ++ ++ if (!mpe) ++ return 1; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ mpe->marginal_path_double_failed_time = MARGINAL_PATH_OFF; ++ else if ((mpe->marginal_path_double_failed_time = atoi(buff)) < 1) ++ mpe->marginal_path_double_failed_time = MARGINAL_PATH_OFF; ++ ++ FREE(buff); ++ return 0; ++} ++ + /* + * config file keywords printing + */ +@@ -2989,6 +3248,56 @@ snprint_mp_ghost_delay (char * buff, int + } + + static int ++snprint_mp_marginal_path_err_sample_time (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->marginal_path_err_sample_time == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (mpe->marginal_path_err_sample_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", mpe->marginal_path_err_sample_time); ++} ++ ++static int ++snprint_mp_marginal_path_err_rate_threshold (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->marginal_path_err_rate_threshold == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (mpe->marginal_path_err_rate_threshold == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", mpe->marginal_path_err_rate_threshold); ++} ++ ++static int ++snprint_mp_marginal_path_err_recheck_gap_time (char * buff, int len, ++ void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->marginal_path_err_recheck_gap_time == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (mpe->marginal_path_err_recheck_gap_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", ++ mpe->marginal_path_err_recheck_gap_time); ++} ++ ++static int ++snprint_mp_marginal_path_double_failed_time (char * buff, int len, void * data) ++{ ++ struct mpentry * mpe = (struct mpentry *)data; ++ ++ if (mpe->marginal_path_double_failed_time == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (mpe->marginal_path_double_failed_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", mpe->marginal_path_double_failed_time); ++} ++ ++static int + snprint_hw_fast_io_fail(char * buff, int len, void * data) + { + struct hwentry * hwe = (struct hwentry *)data; +@@ -3429,6 +3738,55 @@ snprint_hw_all_tg_pt(char * buff, int le + } + + static int ++snprint_hw_marginal_path_err_sample_time(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->marginal_path_err_sample_time == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (hwe->marginal_path_err_sample_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", hwe->marginal_path_err_sample_time); ++} ++ ++static int ++snprint_hw_marginal_path_err_rate_threshold(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->marginal_path_err_rate_threshold == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (hwe->marginal_path_err_rate_threshold == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", hwe->marginal_path_err_rate_threshold); ++} ++ ++static int ++snprint_hw_marginal_path_err_recheck_gap_time(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->marginal_path_err_recheck_gap_time == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (hwe->marginal_path_err_recheck_gap_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", ++ hwe->marginal_path_err_recheck_gap_time); ++} ++ ++static int ++snprint_hw_marginal_path_double_failed_time(char * buff, int len, void * data) ++{ ++ struct hwentry * hwe = (struct hwentry *)data; ++ ++ if (hwe->marginal_path_double_failed_time == MARGINAL_PATH_UNDEF) ++ return 0; ++ if (hwe->marginal_path_double_failed_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", hwe->marginal_path_double_failed_time); ++} ++ ++static int + snprint_def_polling_interval (char * buff, int len, void * data) + { + return snprintf(buff, len, "%i", conf->checkint); +@@ -3945,6 +4303,46 @@ snprint_def_all_tg_pt(char * buff, int l + } + + static int ++snprint_def_marginal_path_err_sample_time(char * buff, int len, void * data) ++{ ++ if (conf->marginal_path_err_sample_time == MARGINAL_PATH_UNDEF || ++ conf->marginal_path_err_sample_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", conf->marginal_path_err_sample_time); ++} ++ ++static int ++snprint_def_marginal_path_err_rate_threshold(char * buff, int len, void * data) ++{ ++ if (conf->marginal_path_err_rate_threshold == MARGINAL_PATH_UNDEF || ++ conf->marginal_path_err_rate_threshold == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", ++ conf->marginal_path_err_rate_threshold); ++} ++ ++static int ++snprint_def_marginal_path_err_recheck_gap_time(char * buff, int len, ++ void * data) ++{ ++ if (conf->marginal_path_err_recheck_gap_time == MARGINAL_PATH_UNDEF || ++ conf->marginal_path_err_recheck_gap_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", ++ conf->marginal_path_err_recheck_gap_time); ++} ++ ++static int ++snprint_def_marginal_path_double_failed_time(char * buff, int len, void * data) ++{ ++ if (conf->marginal_path_double_failed_time == MARGINAL_PATH_UNDEF || ++ conf->marginal_path_double_failed_time == MARGINAL_PATH_OFF) ++ return snprintf(buff, len, "no"); ++ return snprintf(buff, len, "%d", ++ conf->marginal_path_double_failed_time); ++} ++ ++static int + snprint_ble_simple (char * buff, int len, void * data) + { + struct blentry * ble = (struct blentry *)data; +@@ -4043,6 +4441,10 @@ init_keywords(void) + install_keyword("unpriv_sgio", &def_unpriv_sgio_handler, &snprint_def_unpriv_sgio); + install_keyword("ghost_delay", &def_ghost_delay_handler, &snprint_def_ghost_delay); + install_keyword("all_tg_pt", &def_all_tg_pt_handler, &snprint_def_all_tg_pt); ++ install_keyword("marginal_path_err_sample_time", &def_marginal_path_err_sample_time_handler, &snprint_def_marginal_path_err_sample_time); ++ install_keyword("marginal_path_err_rate_threshold", &def_marginal_path_err_rate_threshold_handler, &snprint_def_marginal_path_err_rate_threshold); ++ install_keyword("marginal_path_err_recheck_gap_time", &def_marginal_path_err_recheck_gap_time_handler, &snprint_def_marginal_path_err_recheck_gap_time); ++ install_keyword("marginal_path_double_failed_time", &def_marginal_path_double_failed_time_handler, &snprint_def_marginal_path_double_failed_time); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +@@ -4120,6 +4522,10 @@ init_keywords(void) + install_keyword("unpriv_sgio", &hw_unpriv_sgio_handler, &snprint_hw_unpriv_sgio); + install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay); + install_keyword("all_tg_pt", &hw_all_tg_pt_handler, &snprint_hw_all_tg_pt); ++ install_keyword("marginal_path_err_sample_time", &hw_marginal_path_err_sample_time_handler, &snprint_hw_marginal_path_err_sample_time); ++ install_keyword("marginal_path_err_rate_threshold", &hw_marginal_path_err_rate_threshold_handler, &snprint_hw_marginal_path_err_rate_threshold); ++ install_keyword("marginal_path_err_recheck_gap_time", &hw_marginal_path_err_recheck_gap_time_handler, &snprint_hw_marginal_path_err_recheck_gap_time); ++ install_keyword("marginal_path_double_failed_time", &hw_marginal_path_double_failed_time_handler, &snprint_hw_marginal_path_double_failed_time); + install_sublevel_end(); + + install_keyword_root("overrides", &nop_handler); +@@ -4184,5 +4590,9 @@ init_keywords(void) + install_keyword("max_sectors_kb", &mp_max_sectors_kb_handler, &snprint_mp_max_sectors_kb); + install_keyword("unpriv_sgio", &mp_unpriv_sgio_handler, &snprint_mp_unpriv_sgio); + install_keyword("ghost_delay", &mp_ghost_delay_handler, &snprint_mp_ghost_delay); ++ install_keyword("marginal_path_err_sample_time", &mp_marginal_path_err_sample_time_handler, &snprint_mp_marginal_path_err_sample_time); ++ install_keyword("marginal_path_err_rate_threshold", &mp_marginal_path_err_rate_threshold_handler, &snprint_mp_marginal_path_err_rate_threshold); ++ install_keyword("marginal_path_err_recheck_gap_time", &mp_marginal_path_err_recheck_gap_time_handler, &snprint_mp_marginal_path_err_recheck_gap_time); ++ install_keyword("marginal_path_double_failed_time", &mp_marginal_path_double_failed_time_handler, &snprint_mp_marginal_path_double_failed_time); + install_sublevel_end(); + } +Index: multipath-tools-130222/libmultipath/io_err_stat.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/io_err_stat.c +@@ -0,0 +1,763 @@ ++/* ++ * (C) Copyright HUAWEI Technology Corp. 2017, All Rights Reserved. ++ * ++ * io_err_stat.c ++ * version 1.0 ++ * ++ * IO error stream statistic process for path failure event from kernel ++ * ++ * Author(s): Guan Junxiong 2017 ++ * ++ * This file is released under the GPL version 2, or any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vector.h" ++#include "memory.h" ++#include "checkers.h" ++#include "config.h" ++#include "structs.h" ++#include "structs_vec.h" ++#include "devmapper.h" ++#include "debug.h" ++#include "lock.h" ++#include "time-util.h" ++#include "io_err_stat.h" ++ ++#define IOTIMEOUT_SEC 60 ++#define TIMEOUT_NO_IO_NSEC 10000000 /*10ms = 10000000ns*/ ++#define FLAKY_PATHFAIL_THRESHOLD 2 ++#define CONCUR_NR_EVENT 32 ++ ++#define PATH_IO_ERR_IN_CHECKING -1 ++#define PATH_IO_ERR_WAITING_TO_CHECK -2 ++ ++#define io_err_stat_log(prio, fmt, args...) \ ++ condlog(prio, "io error statistic: " fmt, ##args) ++ ++ ++struct io_err_stat_pathvec { ++ pthread_mutex_t mutex; ++ vector pathvec; ++}; ++ ++struct dio_ctx { ++ struct timespec io_starttime; ++ int blksize; ++ void *buf; ++ struct iocb io; ++}; ++ ++struct io_err_stat_path { ++ char devname[FILE_NAME_SIZE]; ++ int fd; ++ struct dio_ctx *dio_ctx_array; ++ int io_err_nr; ++ int io_nr; ++ struct timespec start_time; ++ ++ int total_time; ++ int err_rate_threshold; ++}; ++ ++pthread_t io_err_stat_thr; ++pthread_attr_t io_err_stat_attr; ++ ++static pthread_mutex_t io_err_thread_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t io_err_thread_cond = PTHREAD_COND_INITIALIZER; ++static int io_err_thread_running = 0; ++ ++#define uatomic_read(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) ++#define uatomic_set(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) ++ ++static struct io_err_stat_pathvec *paths; ++struct vectors *vecs; ++io_context_t ioctx; ++ ++static void cancel_inflight_io(struct io_err_stat_path *pp); ++ ++struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev) ++{ ++ int i; ++ struct io_err_stat_path *pp; ++ ++ if (!pathvec) ++ return NULL; ++ vector_foreach_slot(pathvec, pp, i) ++ if (!strcmp(pp->devname, dev)) ++ return pp; ++ ++ io_err_stat_log(4, "%s: not found in check queue", dev); ++ ++ return NULL; ++} ++ ++static int init_each_dio_ctx(struct dio_ctx *ct, int blksize, ++ unsigned long pgsize) ++{ ++ ct->blksize = blksize; ++ if (posix_memalign(&ct->buf, pgsize, blksize)) ++ return 1; ++ memset(ct->buf, 0, blksize); ++ ct->io_starttime.tv_sec = 0; ++ ct->io_starttime.tv_nsec = 0; ++ ++ return 0; ++} ++ ++static void deinit_each_dio_ctx(struct dio_ctx *ct) ++{ ++ if (ct->buf) ++ free(ct->buf); ++} ++ ++static int setup_directio_ctx(struct io_err_stat_path *p) ++{ ++ unsigned long pgsize = getpagesize(); ++ char fpath[PATH_MAX]; ++ int blksize = 0; ++ int i; ++ ++ if (snprintf(fpath, PATH_MAX, "/dev/%s", p->devname) >= PATH_MAX) ++ return 1; ++ if (p->fd < 0) ++ p->fd = open(fpath, O_RDONLY | O_DIRECT); ++ if (p->fd < 0) ++ return 1; ++ ++ p->dio_ctx_array = MALLOC(sizeof(struct dio_ctx) * CONCUR_NR_EVENT); ++ if (!p->dio_ctx_array) ++ goto fail_close; ++ ++ if (ioctl(p->fd, BLKBSZGET, &blksize) < 0) { ++ io_err_stat_log(4, "%s:cannot get blocksize, set default 512", ++ p->devname); ++ blksize = 512; ++ } ++ if (!blksize) ++ goto free_pdctx; ++ ++ for (i = 0; i < CONCUR_NR_EVENT; i++) { ++ if (init_each_dio_ctx(p->dio_ctx_array + i, blksize, pgsize)) ++ goto deinit; ++ } ++ return 0; ++ ++deinit: ++ for (i = 0; i < CONCUR_NR_EVENT; i++) ++ deinit_each_dio_ctx(p->dio_ctx_array + i); ++free_pdctx: ++ FREE(p->dio_ctx_array); ++fail_close: ++ close(p->fd); ++ ++ return 1; ++} ++ ++static void destroy_directio_ctx(struct io_err_stat_path *p) ++{ ++ int i; ++ ++ if (!p || !p->dio_ctx_array) ++ return; ++ cancel_inflight_io(p); ++ ++ for (i = 0; i < CONCUR_NR_EVENT; i++) ++ deinit_each_dio_ctx(p->dio_ctx_array + i); ++ FREE(p->dio_ctx_array); ++ ++ if (p->fd > 0) ++ close(p->fd); ++} ++ ++static struct io_err_stat_path *alloc_io_err_stat_path(void) ++{ ++ struct io_err_stat_path *p; ++ ++ p = (struct io_err_stat_path *)MALLOC(sizeof(*p)); ++ if (!p) ++ return NULL; ++ ++ memset(p->devname, 0, sizeof(p->devname)); ++ p->io_err_nr = 0; ++ p->io_nr = 0; ++ p->total_time = 0; ++ p->start_time.tv_sec = 0; ++ p->start_time.tv_nsec = 0; ++ p->err_rate_threshold = 0; ++ p->fd = -1; ++ ++ return p; ++} ++ ++static void free_io_err_stat_path(struct io_err_stat_path *p) ++{ ++ FREE(p); ++} ++ ++static struct io_err_stat_pathvec *alloc_pathvec(void) ++{ ++ struct io_err_stat_pathvec *p; ++ int r; ++ ++ p = (struct io_err_stat_pathvec *)MALLOC(sizeof(*p)); ++ if (!p) ++ return NULL; ++ p->pathvec = vector_alloc(); ++ if (!p->pathvec) ++ goto out_free_struct_pathvec; ++ r = pthread_mutex_init(&p->mutex, NULL); ++ if (r) ++ goto out_free_member_pathvec; ++ ++ return p; ++ ++out_free_member_pathvec: ++ vector_free(p->pathvec); ++out_free_struct_pathvec: ++ FREE(p); ++ return NULL; ++} ++ ++static void free_io_err_pathvec(struct io_err_stat_pathvec *p) ++{ ++ struct io_err_stat_path *path; ++ int i; ++ ++ if (!p) ++ return; ++ pthread_mutex_destroy(&p->mutex); ++ if (!p->pathvec) { ++ vector_foreach_slot(p->pathvec, path, i) { ++ destroy_directio_ctx(path); ++ free_io_err_stat_path(path); ++ } ++ vector_free(p->pathvec); ++ } ++ FREE(p); ++} ++ ++/* ++ * return value ++ * 0: enqueue OK ++ * 1: fails because of internal error ++ */ ++static int enqueue_io_err_stat_by_path(struct path *path) ++{ ++ struct io_err_stat_path *p; ++ ++ pthread_mutex_lock(&paths->mutex); ++ p = find_err_path_by_dev(paths->pathvec, path->dev); ++ if (p) { ++ pthread_mutex_unlock(&paths->mutex); ++ return 0; ++ } ++ pthread_mutex_unlock(&paths->mutex); ++ ++ p = alloc_io_err_stat_path(); ++ if (!p) ++ return 1; ++ ++ memcpy(p->devname, path->dev, sizeof(p->devname)); ++ p->total_time = path->mpp->marginal_path_err_sample_time; ++ p->err_rate_threshold = path->mpp->marginal_path_err_rate_threshold; ++ ++ if (setup_directio_ctx(p)) ++ goto free_ioerr_path; ++ pthread_mutex_lock(&paths->mutex); ++ if (!vector_alloc_slot(paths->pathvec)) ++ goto unlock_destroy; ++ vector_set_slot(paths->pathvec, p); ++ pthread_mutex_unlock(&paths->mutex); ++ ++ io_err_stat_log(2, "%s: enqueue path %s to check", ++ path->mpp->alias, path->dev); ++ return 0; ++ ++unlock_destroy: ++ pthread_mutex_unlock(&paths->mutex); ++ destroy_directio_ctx(p); ++free_ioerr_path: ++ free_io_err_stat_path(p); ++ ++ return 1; ++} ++ ++int io_err_stat_handle_pathfail(struct path *path) ++{ ++ struct timespec curr_time; ++ ++ if (uatomic_read(&io_err_thread_running) == 0) ++ return 1; ++ ++ if (path->io_err_disable_reinstate) { ++ io_err_stat_log(3, "%s: reinstate is already disabled", ++ path->dev); ++ return 1; ++ } ++ if (path->io_err_pathfail_cnt < 0) ++ return 1; ++ ++ if (!path->mpp) ++ return 1; ++ if (path->mpp->marginal_path_double_failed_time <= 0 || ++ path->mpp->marginal_path_err_sample_time <= 0 || ++ path->mpp->marginal_path_err_recheck_gap_time <= 0 || ++ path->mpp->marginal_path_err_rate_threshold < 0) { ++ io_err_stat_log(4, "%s: parameter not set", path->mpp->alias); ++ return 1; ++ } ++ if (path->mpp->marginal_path_err_sample_time < (2 * IOTIMEOUT_SEC)) { ++ io_err_stat_log(2, "%s: marginal_path_err_sample_time should not less than %d", ++ path->mpp->alias, 2 * IOTIMEOUT_SEC); ++ return 1; ++ } ++ /* ++ * The test should only be started for paths that have failed ++ * repeatedly in a certain time frame, so that we have reason ++ * to assume they're flaky. Without bother the admin to configure ++ * the repeated count threshold and time frame, we assume a path ++ * which fails at least twice within 60 seconds is flaky. ++ */ ++ if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) ++ return 1; ++ if (path->io_err_pathfail_cnt == 0) { ++ path->io_err_pathfail_cnt++; ++ path->io_err_pathfail_starttime = curr_time.tv_sec; ++ io_err_stat_log(5, "%s: start path flakiness pre-checking", ++ path->dev); ++ return 0; ++ } ++ if ((curr_time.tv_sec - path->io_err_pathfail_starttime) > ++ path->mpp->marginal_path_double_failed_time) { ++ path->io_err_pathfail_cnt = 0; ++ path->io_err_pathfail_starttime = curr_time.tv_sec; ++ io_err_stat_log(5, "%s: restart path flakiness pre-checking", ++ path->dev); ++ } ++ path->io_err_pathfail_cnt++; ++ if (path->io_err_pathfail_cnt >= FLAKY_PATHFAIL_THRESHOLD) { ++ path->io_err_disable_reinstate = 1; ++ path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; ++ /* enqueue path as soon as it comes up */ ++ path->io_err_dis_reinstate_time = 0; ++ if (path->state != PATH_DOWN) { ++ int oldstate = path->state; ++ io_err_stat_log(2, "%s: mark as failed", path->dev); ++ path->mpp->stat_path_failures++; ++ path->state = PATH_DOWN; ++ path->dmstate = PSTATE_FAILED; ++ if (oldstate == PATH_UP || oldstate == PATH_GHOST) ++ update_queue_mode_del_path(path->mpp); ++ if (path->tick > conf->checkint) ++ path->tick = conf->checkint; ++ } ++ } ++ ++ return 0; ++} ++ ++int need_io_err_check(struct path *pp) ++{ ++ struct timespec curr_time; ++ int r; ++ ++ if (uatomic_read(&io_err_thread_running) == 0) ++ return 0; ++ if (pp->mpp->nr_active <= 0) { ++ io_err_stat_log(2, "%s: recover path early", pp->dev); ++ goto recover; ++ } ++ if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) ++ return 1; ++ if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 || ++ (curr_time.tv_sec - pp->io_err_dis_reinstate_time) > ++ pp->mpp->marginal_path_err_recheck_gap_time) { ++ io_err_stat_log(4, "%s: reschedule checking after %d seconds", ++ pp->dev, ++ pp->mpp->marginal_path_err_recheck_gap_time); ++ r = enqueue_io_err_stat_by_path(pp); ++ /* ++ * Enqueue fails because of internal error. ++ * In this case , we recover this path ++ * Or else, return 1 to set path state to PATH_SHAKY ++ */ ++ if (r == 1) { ++ io_err_stat_log(3, "%s: enqueue fails, recovering", ++ pp->dev); ++ goto recover; ++ } else ++ pp->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; ++ } ++ ++ return 1; ++ ++recover: ++ pp->io_err_pathfail_cnt = 0; ++ pp->io_err_disable_reinstate = 0; ++ return 0; ++} ++ ++static int delete_io_err_stat_by_addr(struct io_err_stat_path *p) ++{ ++ int i; ++ ++ i = find_slot(paths->pathvec, p); ++ if (i != -1) ++ vector_del_slot(paths->pathvec, i); ++ ++ destroy_directio_ctx(p); ++ free_io_err_stat_path(p); ++ ++ return 0; ++} ++ ++static void account_async_io_state(struct io_err_stat_path *pp, int rc) ++{ ++ switch (rc) { ++ case PATH_DOWN: ++ pp->io_err_nr++; ++ break; ++ case PATH_UNCHECKED: ++ case PATH_UP: ++ case PATH_PENDING: ++ break; ++ default: ++ break; ++ } ++} ++ ++static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) ++{ ++ struct timespec currtime, difftime; ++ struct path *path; ++ double err_rate; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) ++ return 1; ++ timespecsub(&currtime, &pp->start_time, &difftime); ++ if (difftime.tv_sec < pp->total_time) ++ return 0; ++ ++ io_err_stat_log(4, "%s: check end", pp->devname); ++ ++ err_rate = pp->io_nr == 0 ? 0 : (pp->io_err_nr * 1000.0f) / pp->io_nr; ++ io_err_stat_log(3, "%s: IO error rate (%.1f/1000)", ++ pp->devname, err_rate); ++ pthread_cleanup_push(cleanup_lock, &vecs->lock); ++ lock(vecs->lock); ++ pthread_testcancel(); ++ path = find_path_by_dev(vecs->pathvec, pp->devname); ++ if (!path) { ++ io_err_stat_log(4, "path %s not found'", pp->devname); ++ } else if (err_rate <= pp->err_rate_threshold) { ++ path->io_err_pathfail_cnt = 0; ++ path->io_err_disable_reinstate = 0; ++ io_err_stat_log(3, "%s: (%d/%d) good to enable reinstating", ++ pp->devname, pp->io_err_nr, pp->io_nr); ++ /* ++ * schedule path check as soon as possible to ++ * update path state. Do NOT reinstate dm path here ++ */ ++ path->tick = 1; ++ ++ } else if (path->mpp && path->mpp->nr_active > 0) { ++ io_err_stat_log(3, "%s: keep failing the dm path %s", ++ path->mpp->alias, path->dev); ++ path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; ++ path->io_err_disable_reinstate = 1; ++ path->io_err_dis_reinstate_time = currtime.tv_sec; ++ io_err_stat_log(3, "%s: disable reinstating of %s", ++ path->mpp->alias, path->dev); ++ } else { ++ path->io_err_pathfail_cnt = 0; ++ path->io_err_disable_reinstate = 0; ++ io_err_stat_log(3, "%s: there is orphan path, enable reinstating", ++ pp->devname); ++ } ++ lock_cleanup_pop(vecs->lock); ++ ++ delete_io_err_stat_by_addr(pp); ++ ++ return 0; ++} ++ ++static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev) ++{ ++ int rc = -1; ++ ++ if (ct->io_starttime.tv_nsec == 0 && ++ ct->io_starttime.tv_sec == 0) { ++ struct iocb *ios[1] = { &ct->io }; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &ct->io_starttime) != 0) { ++ ct->io_starttime.tv_sec = 0; ++ ct->io_starttime.tv_nsec = 0; ++ return rc; ++ } ++ io_prep_pread(&ct->io, fd, ct->buf, ct->blksize, 0); ++ if (io_submit(ioctx, 1, ios) != 1) { ++ io_err_stat_log(5, "%s: io_submit error %i", ++ dev, errno); ++ return rc; ++ } ++ rc = 0; ++ } ++ ++ return rc; ++} ++ ++static void send_batch_async_ios(struct io_err_stat_path *pp) ++{ ++ int i; ++ struct dio_ctx *ct; ++ struct timespec currtime, difftime; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) ++ return; ++ /* ++ * Give a free time for all IO to complete or timeout ++ */ ++ if (pp->start_time.tv_sec != 0) { ++ timespecsub(&currtime, &pp->start_time, &difftime); ++ if (difftime.tv_sec + IOTIMEOUT_SEC >= pp->total_time) ++ return; ++ } ++ ++ for (i = 0; i < CONCUR_NR_EVENT; i++) { ++ ct = pp->dio_ctx_array + i; ++ if (!send_each_async_io(ct, pp->fd, pp->devname)) ++ pp->io_nr++; ++ } ++ if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0 && ++ clock_gettime(CLOCK_MONOTONIC, &pp->start_time)) { ++ pp->start_time.tv_sec = 0; ++ pp->start_time.tv_nsec = 0; ++ } ++} ++ ++static int try_to_cancel_timeout_io(struct dio_ctx *ct, struct timespec *t, ++ char *dev) ++{ ++ struct timespec difftime; ++ struct io_event event; ++ int rc = PATH_UNCHECKED; ++ int r; ++ ++ if (ct->io_starttime.tv_sec == 0) ++ return rc; ++ timespecsub(t, &ct->io_starttime, &difftime); ++ if (difftime.tv_sec > IOTIMEOUT_SEC) { ++ struct iocb *ios[1] = { &ct->io }; ++ ++ io_err_stat_log(5, "%s: abort check on timeout", dev); ++ r = io_cancel(ioctx, ios[0], &event); ++ if (r) ++ io_err_stat_log(5, "%s: io_cancel error %i", ++ dev, errno); ++ ct->io_starttime.tv_sec = 0; ++ ct->io_starttime.tv_nsec = 0; ++ rc = PATH_DOWN; ++ } else { ++ rc = PATH_PENDING; ++ } ++ ++ return rc; ++} ++ ++static void poll_async_io_timeout(void) ++{ ++ struct io_err_stat_path *pp; ++ struct timespec curr_time; ++ int rc = PATH_UNCHECKED; ++ int i, j; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) ++ return; ++ vector_foreach_slot(paths->pathvec, pp, i) { ++ for (j = 0; j < CONCUR_NR_EVENT; j++) { ++ rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j, ++ &curr_time, pp->devname); ++ account_async_io_state(pp, rc); ++ } ++ } ++} ++ ++static void cancel_inflight_io(struct io_err_stat_path *pp) ++{ ++ struct io_event event; ++ int i, r; ++ ++ for (i = 0; i < CONCUR_NR_EVENT; i++) { ++ struct dio_ctx *ct = pp->dio_ctx_array + i; ++ struct iocb *ios[1] = { &ct->io }; ++ ++ if (ct->io_starttime.tv_sec == 0 ++ && ct->io_starttime.tv_nsec == 0) ++ continue; ++ io_err_stat_log(5, "%s: abort infligh io", ++ pp->devname); ++ r = io_cancel(ioctx, ios[0], &event); ++ if (r) ++ io_err_stat_log(5, "%s: io_cancel error %d, %i", ++ pp->devname, r, errno); ++ ct->io_starttime.tv_sec = 0; ++ ct->io_starttime.tv_nsec = 0; ++ } ++} ++ ++static inline int handle_done_dio_ctx(struct dio_ctx *ct, struct io_event *ev) ++{ ++ ct->io_starttime.tv_sec = 0; ++ ct->io_starttime.tv_nsec = 0; ++ return (ev->res == ct->blksize) ? PATH_UP : PATH_DOWN; ++} ++ ++static void handle_async_io_done_event(struct io_event *io_evt) ++{ ++ struct io_err_stat_path *pp; ++ struct dio_ctx *ct; ++ int rc = PATH_UNCHECKED; ++ int i, j; ++ ++ vector_foreach_slot(paths->pathvec, pp, i) { ++ for (j = 0; j < CONCUR_NR_EVENT; j++) { ++ ct = pp->dio_ctx_array + j; ++ if (&ct->io == io_evt->obj) { ++ rc = handle_done_dio_ctx(ct, io_evt); ++ account_async_io_state(pp, rc); ++ return; ++ } ++ } ++ } ++} ++ ++static void process_async_ios_event(int timeout_nsecs, char *dev) ++{ ++ struct io_event events[CONCUR_NR_EVENT]; ++ int i, n; ++ struct timespec timeout = { .tv_nsec = timeout_nsecs }; ++ ++ errno = 0; ++ n = io_getevents(ioctx, 1L, CONCUR_NR_EVENT, events, &timeout); ++ if (n < 0) { ++ io_err_stat_log(3, "%s: async io events returned %d (errno=%s)", ++ dev, n, strerror(errno)); ++ } else { ++ for (i = 0; i < n; i++) ++ handle_async_io_done_event(&events[i]); ++ } ++} ++ ++static void service_paths(void) ++{ ++ struct io_err_stat_path *pp; ++ int i; ++ ++ pthread_mutex_lock(&paths->mutex); ++ vector_foreach_slot(paths->pathvec, pp, i) { ++ send_batch_async_ios(pp); ++ process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname); ++ poll_async_io_timeout(); ++ poll_io_err_stat(vecs, pp); ++ } ++ pthread_mutex_unlock(&paths->mutex); ++} ++ ++static void cleanup_unlock(void *arg) ++{ ++ pthread_mutex_unlock((pthread_mutex_t*) arg); ++} ++ ++static void cleanup_exited(void *arg) ++{ ++ uatomic_set(&io_err_thread_running, 0); ++} ++ ++static void *io_err_stat_loop(void *data) ++{ ++ vecs = (struct vectors *)data; ++ ++ pthread_cleanup_push(cleanup_exited, NULL); ++ ++ mlockall(MCL_CURRENT | MCL_FUTURE); ++ ++ pthread_mutex_lock(&io_err_thread_lock); ++ uatomic_set(&io_err_thread_running, 1); ++ pthread_cond_broadcast(&io_err_thread_cond); ++ pthread_mutex_unlock(&io_err_thread_lock); ++ ++ while (1) { ++ service_paths(); ++ usleep(100000); ++ } ++ ++ pthread_cleanup_pop(1); ++ return NULL; ++} ++ ++int start_io_err_stat_thread(void *data) ++{ ++ int ret; ++ ++ if (uatomic_read(&io_err_thread_running) == 1) ++ return 0; ++ ++ if (io_setup(CONCUR_NR_EVENT, &ioctx) != 0) { ++ io_err_stat_log(4, "io_setup failed"); ++ return 1; ++ } ++ paths = alloc_pathvec(); ++ if (!paths) ++ goto destroy_ctx; ++ ++ pthread_mutex_lock(&io_err_thread_lock); ++ pthread_cleanup_push(cleanup_unlock, &io_err_thread_lock); ++ ++ ret = pthread_create(&io_err_stat_thr, &io_err_stat_attr, ++ io_err_stat_loop, data); ++ ++ while (!ret && !uatomic_read(&io_err_thread_running) && ++ pthread_cond_wait(&io_err_thread_cond, ++ &io_err_thread_lock) == 0); ++ ++ pthread_cleanup_pop(1); ++ ++ if (ret) { ++ io_err_stat_log(0, "cannot create io_error statistic thread"); ++ goto out_free; ++ } ++ ++ io_err_stat_log(2, "io_error statistic thread started"); ++ return 0; ++ ++out_free: ++ free_io_err_pathvec(paths); ++destroy_ctx: ++ io_destroy(ioctx); ++ io_err_stat_log(0, "failed to start io_error statistic thread"); ++ return 1; ++} ++ ++void stop_io_err_stat_thread(void) ++{ ++ if (io_err_stat_thr == (pthread_t)0) ++ return; ++ ++ if (uatomic_read(&io_err_thread_running) == 1) ++ pthread_cancel(io_err_stat_thr); ++ ++ pthread_join(io_err_stat_thr, NULL); ++ free_io_err_pathvec(paths); ++ io_destroy(ioctx); ++} +Index: multipath-tools-130222/libmultipath/io_err_stat.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/io_err_stat.h +@@ -0,0 +1,15 @@ ++#ifndef _IO_ERR_STAT_H ++#define _IO_ERR_STAT_H ++ ++#include "vector.h" ++#include "lock.h" ++ ++ ++extern pthread_attr_t io_err_stat_attr; ++ ++int start_io_err_stat_thread(void *data); ++void stop_io_err_stat_thread(void); ++int io_err_stat_handle_pathfail(struct path *path); ++int need_io_err_check(struct path *pp); ++ ++#endif /* _IO_ERR_STAT_H */ +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -956,6 +956,104 @@ select_delay_wait_checks (struct multipa + } + + extern int ++select_marginal_path_err_sample_time(struct multipath * mp) ++{ ++ if (mp->mpe && ++ mp->mpe->marginal_path_err_sample_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_sample_time = mp->mpe->marginal_path_err_sample_time; ++ condlog(3, "marginal_path_err_sample_time = %i (multipath setting)", mp->marginal_path_err_sample_time); ++ return 0; ++ } ++ if (mp->hwe && ++ mp->hwe->marginal_path_err_sample_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_sample_time = mp->hwe->marginal_path_err_sample_time; ++ condlog(3, "marginal_path_err_sample_time = %i (controler setting)", mp->marginal_path_err_sample_time); ++ return 0; ++ } ++ if (conf->marginal_path_err_sample_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_sample_time = conf->marginal_path_err_sample_time; ++ condlog(3, "marginal_path_err_sample_time = %i (config file default)", mp->marginal_path_err_sample_time); ++ return 0; ++ } ++ mp->marginal_path_err_sample_time = DEFAULT_DELAY_CHECKS; ++ condlog(3, "marginal_path_err_sample_time = DISABLED (internal default)"); ++ return 0; ++} ++ ++extern int ++select_marginal_path_err_rate_threshold(struct multipath * mp) ++{ ++ if (mp->mpe && ++ mp->mpe->marginal_path_err_rate_threshold != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_rate_threshold = mp->mpe->marginal_path_err_rate_threshold; ++ condlog(3, "marginal_path_err_rate_threshold = %i (multipath setting)", mp->marginal_path_err_rate_threshold); ++ return 0; ++ } ++ if (mp->hwe && ++ mp->hwe->marginal_path_err_rate_threshold != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_rate_threshold = mp->hwe->marginal_path_err_rate_threshold; ++ condlog(3, "marginal_path_err_rate_threshold = %i (controler setting)", mp->marginal_path_err_rate_threshold); ++ return 0; ++ } ++ if (conf->marginal_path_err_rate_threshold != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_rate_threshold = conf->marginal_path_err_rate_threshold; ++ condlog(3, "marginal_path_err_rate_threshold = %i (config file default)", mp->marginal_path_err_rate_threshold); ++ return 0; ++ } ++ mp->marginal_path_err_rate_threshold = DEFAULT_DELAY_CHECKS; ++ condlog(3, "marginal_path_err_rate_threshold = DISABLED (internal default)"); ++ return 0; ++} ++ ++extern int ++select_marginal_path_err_recheck_gap_time(struct multipath * mp) ++{ ++ if (mp->mpe && mp->mpe->marginal_path_err_recheck_gap_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_recheck_gap_time = mp->mpe->marginal_path_err_recheck_gap_time; ++ condlog(3, "marginal_path_err_recheck_gap_time = %i (multipath setting)", mp->marginal_path_err_recheck_gap_time); ++ return 0; ++ } ++ if (mp->hwe && mp->hwe->marginal_path_err_recheck_gap_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_recheck_gap_time = mp->hwe->marginal_path_err_recheck_gap_time; ++ condlog(3, "marginal_path_err_recheck_gap_time = %i (controler setting)", mp->marginal_path_err_recheck_gap_time); ++ return 0; ++ } ++ if (conf->marginal_path_err_recheck_gap_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_err_recheck_gap_time = conf->marginal_path_err_recheck_gap_time; ++ condlog(3, "marginal_path_err_recheck_gap_time = %i (config file default)", mp->marginal_path_err_recheck_gap_time); ++ return 0; ++ } ++ mp->marginal_path_err_recheck_gap_time = DEFAULT_DELAY_CHECKS; ++ condlog(3, "marginal_path_err_recheck_gap_time = DISABLED (internal default)"); ++ return 0; ++} ++ ++extern int ++select_marginal_path_double_failed_time(struct multipath * mp) ++{ ++ if (mp->mpe && ++ mp->mpe->marginal_path_double_failed_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_double_failed_time = mp->mpe->marginal_path_double_failed_time; ++ condlog(3, "marginal_path_double_failed_time = %i (multipath setting)", mp->marginal_path_double_failed_time); ++ return 0; ++ } ++ if (mp->hwe && ++ mp->hwe->marginal_path_double_failed_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_double_failed_time = mp->hwe->marginal_path_double_failed_time; ++ condlog(3, "marginal_path_double_failed_time = %i (controler setting)", mp->marginal_path_double_failed_time); ++ return 0; ++ } ++ if (conf->marginal_path_double_failed_time != MARGINAL_PATH_UNDEF) { ++ mp->marginal_path_double_failed_time = conf->marginal_path_double_failed_time; ++ condlog(3, "marginal_path_double_failed_time = %i (config file default)", mp->marginal_path_double_failed_time); ++ return 0; ++ } ++ mp->marginal_path_double_failed_time = DEFAULT_DELAY_CHECKS; ++ condlog(3, "marginal_path_double_failed_time = DISABLED (internal default)"); ++ return 0; ++} ++ ++extern int + select_skip_kpartx (struct multipath * mp) + { + if (mp->mpe && mp->mpe->skip_kpartx != SKIP_KPARTX_UNDEF) { +Index: multipath-tools-130222/libmultipath/propsel.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.h ++++ multipath-tools-130222/libmultipath/propsel.h +@@ -24,6 +24,10 @@ int select_detect_checker(struct path * + int select_deferred_remove(struct multipath *mp); + int select_delay_watch_checks (struct multipath * mp); + int select_delay_wait_checks (struct multipath * mp); ++int select_marginal_path_err_sample_time(struct multipath *mp); ++int select_marginal_path_err_rate_threshold(struct multipath *mp); ++int select_marginal_path_err_recheck_gap_time(struct multipath *mp); ++int select_marginal_path_double_failed_time(struct multipath *mp); + int select_skip_kpartx (struct multipath * mp); + int select_max_sectors_kb (struct multipath * mp); + int select_unpriv_sgio (struct multipath * mp); +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -3,6 +3,7 @@ + + #include + #include ++#include + + #include "prio.h" + #include "byteorder.h" +@@ -176,6 +177,11 @@ enum delay_checks_states { + DELAY_CHECKS_UNDEF = 0, + }; + ++enum marginal_path_states { ++ MARGINAL_PATH_OFF = -1, ++ MARGINAL_PATH_UNDEF = 0, ++}; ++ + enum missing_udev_info_states { + INFO_OK, + INFO_MISSING, +@@ -252,6 +258,10 @@ struct path { + int missing_udev_info; + int retriggers; + int wwid_changed; ++ time_t io_err_dis_reinstate_time; ++ int io_err_disable_reinstate; ++ int io_err_pathfail_cnt; ++ int io_err_pathfail_starttime; + + /* configlet pointers */ + struct hwentry * hwe; +@@ -285,6 +295,10 @@ struct multipath { + int deferred_remove; + int delay_watch_checks; + int delay_wait_checks; ++ int marginal_path_err_sample_time; ++ int marginal_path_err_rate_threshold; ++ int marginal_path_err_recheck_gap_time; ++ int marginal_path_double_failed_time; + int force_udev_reload; + int skip_kpartx; + int max_sectors_kb; +Index: multipath-tools-130222/libmultipath/time-util.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/time-util.c +@@ -0,0 +1,42 @@ ++#include ++#include ++#include ++#include "time-util.h" ++ ++/* Initialize @cond as a condition variable that uses the monotonic clock */ ++void pthread_cond_init_mono(pthread_cond_t *cond) ++{ ++ pthread_condattr_t attr; ++ int res; ++ ++ res = pthread_condattr_init(&attr); ++ assert(res == 0); ++ res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); ++ assert(res == 0); ++ res = pthread_cond_init(cond, &attr); ++ assert(res == 0); ++ res = pthread_condattr_destroy(&attr); ++ assert(res == 0); ++} ++ ++/* Ensure that 0 <= ts->tv_nsec && ts->tv_nsec < 1000 * 1000 * 1000. */ ++void normalize_timespec(struct timespec *ts) ++{ ++ while (ts->tv_nsec < 0) { ++ ts->tv_nsec += 1000UL * 1000 * 1000; ++ ts->tv_sec--; ++ } ++ while (ts->tv_nsec >= 1000UL * 1000 * 1000) { ++ ts->tv_nsec -= 1000UL * 1000 * 1000; ++ ts->tv_sec++; ++ } ++} ++ ++/* Compute *res = *a - *b */ ++void timespecsub(const struct timespec *a, const struct timespec *b, ++ struct timespec *res) ++{ ++ res->tv_sec = a->tv_sec - b->tv_sec; ++ res->tv_nsec = a->tv_nsec - b->tv_nsec; ++ normalize_timespec(res); ++} +Index: multipath-tools-130222/libmultipath/time-util.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/time-util.h +@@ -0,0 +1,13 @@ ++#ifndef _TIME_UTIL_H_ ++#define _TIME_UTIL_H_ ++ ++#include ++ ++struct timespec; ++ ++void pthread_cond_init_mono(pthread_cond_t *cond); ++void normalize_timespec(struct timespec *ts); ++void timespecsub(const struct timespec *a, const struct timespec *b, ++ struct timespec *res); ++ ++#endif /* _TIME_UTIL_H_ */ +Index: multipath-tools-130222/libmultipath/uevent.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.c ++++ multipath-tools-130222/libmultipath/uevent.c +@@ -616,12 +616,46 @@ uevent_get_dm_name(struct uevent *uev) + int i; + + for (i = 0; uev->envp[i] != NULL; i++) { +- if (!strncmp(uev->envp[i], "DM_NAME", 6) && +- strlen(uev->envp[i]) > 7) { ++ if (!strncmp(uev->envp[i], "DM_NAME", 7) && ++ strlen(uev->envp[i]) > 8) { + p = MALLOC(strlen(uev->envp[i] + 8) + 1); + strcpy(p, uev->envp[i] + 8); + break; + } + } ++ return p; ++} ++ ++extern char * ++uevent_get_dm_path(struct uevent *uev) ++{ ++ char *p = NULL; ++ int i; ++ ++ for (i = 0; uev->envp[i] != NULL; i++) { ++ if (!strncmp(uev->envp[i], "DM_PATH", 7) && ++ strlen(uev->envp[i]) > 8) { ++ p = MALLOC(strlen(uev->envp[i] + 8) + 1); ++ strcpy(p, uev->envp[i] + 8); ++ break; ++ } ++ } ++ return p; ++} ++ ++extern char * ++uevent_get_dm_action(struct uevent *uev) ++{ ++ char *p = NULL; ++ int i; ++ ++ for (i = 0; uev->envp[i] != NULL; i++) { ++ if (!strncmp(uev->envp[i], "DM_ACTION", 9) && ++ strlen(uev->envp[i]) > 10) { ++ p = MALLOC(strlen(uev->envp[i] + 10) + 1); ++ strcpy(p, uev->envp[i] + 10); ++ break; ++ } ++ } + return p; + } +Index: multipath-tools-130222/libmultipath/uevent.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/uevent.h ++++ multipath-tools-130222/libmultipath/uevent.h +@@ -36,5 +36,7 @@ int uevent_get_major(struct uevent *uev) + int uevent_get_minor(struct uevent *uev); + int uevent_get_disk_ro(struct uevent *uev); + char *uevent_get_dm_name(struct uevent *uev); ++char *uevent_get_dm_path(struct uevent *uev); ++char *uevent_get_dm_action(struct uevent *uev); + + #endif /* _UEVENT_H */ +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -527,7 +527,7 @@ recently become valid for this many chec + being watched, when they next become valid, they will not be used until they + have stayed up for + .I delay_wait_checks +-checks. Default is ++checks. See "Shaky paths detection" below. Default is + .I no + .TP + .B delay_wait_checks +@@ -537,9 +537,56 @@ online fails again within + checks, the next time it comes back online, it will marked and delayed, and not + used until it has passed + .I delay_wait_checks +-checks. Default is ++checks. See "Shaky paths detection" below. Default is + .I no + .TP ++.B marginal_path_double_failed_time ++One of the four parameters of supporting path check based on accounting IO ++error such as intermittent error. When a path failed event occurs twice in ++\fImarginal_path_double_failed_time\fR seconds due to an IO error and all the ++other three parameters are set, multipathd will fail the path and enqueue ++this path into a queue of which members are sent a couple of continuous ++direct reading asynchronous IOs at a fixed sample rate of 10HZ to start IO ++error accounting process. See "Shaky paths detection" below. Default is ++\fIno\fR ++.TP ++.B marginal_path_err_sample_time ++One of the four parameters of supporting path check based on accounting IO ++error such as intermittent error. If it is set to a value no less than 120, ++when a path fail event occurs twice in \fImarginal_path_double_failed_time\fR ++second due to an IO error, multipathd will fail the path and enqueue this ++path into a queue of which members are sent a couple of continuous direct ++reading asynchronous IOs at a fixed sample rate of 10HZ to start the IO ++accounting process for the path will last for ++\fImarginal_path_err_sample_time\fR. ++If the rate of IO error on a particular path is greater than the ++\fImarginal_path_err_rate_threshold\fR, then the path will not reinstate for ++\fImarginal_path_err_recheck_gap_time\fR seconds unless there is only one ++active path. After \fImarginal_path_err_recheck_gap_time\fR expires, the path ++will be requeueed for rechecking. If checking result is good enough, the ++path will be reinstated. See "Shaky paths detection" below. Default is ++\fIno\fR ++.TP ++.B marginal_path_err_rate_threshold ++The error rate threshold as a permillage (1/1000). One of the four parameters ++of supporting path check based on accounting IO error such as intermittent ++error. Refer to \fImarginal_path_err_sample_time\fR. If the rate of IO errors ++on a particular path is greater than this parameter, then the path will not ++reinstate for \fImarginal_path_err_recheck_gap_time\fR seconds unless there is ++only one active path. See "Shaky paths detection" below. Default is \fIno\fR ++.TP ++.B marginal_path_err_recheck_gap_time ++One of the four parameters of supporting path check based on accounting IO ++error such as intermittent error. Refer to ++\fImarginal_path_err_sample_time\fR. If this parameter is set to a positive ++value, the failed path of which the IO error rate is larger than ++\fImarginal_path_err_rate_threshold\fR will be kept in failed state for ++\fImarginal_path_err_recheck_gap_time\fR seconds. When ++\fImarginal_path_err_recheck_gap_time\fR seconds expires, the path will be ++requeueed for checking. If checking result is good enough, the path will be ++reinstated, or else it will keep failed. See "Shaky paths detection" below. ++Default is \fIno\fR ++.TP + .B missing_uev_wait_timeout + Controls how many seconds multipathd will wait, after a new multipath device + is created, to receive a change event from udev for the device, before +@@ -771,6 +818,14 @@ section: + .TP + .B delay_wait_checks + .TP ++.B marginal_path_err_sample_time ++.TP ++.B marginal_path_err_rate_threshold ++.TP ++.B marginal_path_err_recheck_gap_time ++.TP ++.B marginal_path_double_failed_time ++.TP + .B skip_kpartx + .TP + .B max_sectors_kb +@@ -877,6 +932,14 @@ section: + .TP + .B delay_wait_checks + .TP ++.B marginal_path_err_sample_time ++.TP ++.B marginal_path_err_rate_threshold ++.TP ++.B marginal_path_err_recheck_gap_time ++.TP ++.B marginal_path_double_failed_time ++.TP + .B skip_kpartx + .TP + .B max_sectors_kb +@@ -887,6 +950,47 @@ section: + .RE + .PD + .LP ++.SH "Shaky paths detection" ++A common problem in SAN setups is the occurence 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 ++events. \fImultipathd\fR supports two different methods for detecting this ++situation and dealing with it. Both methods share the same basic mode of ++operation: If a path is found to be \(dqshaky\(dq or \(dqflipping\(dq, ++and appears to be in healthy status, it is not reinstated (put back to use) ++immediately. Instead, it is watched for some time, and only reinstated ++if the healthy state appears to be stable. The logic of determining ++\(dqshaky\(dq condition, as well as the logic when to reinstate, ++differs between the two methods. ++.TP 8 ++.B \(dqdelay_checks\(dq failure tracking ++If a path fails again within a ++\fIdelay_watch_checks\fR interval after a failure, don't ++reinstate it until it passes a \fIdelay_wait_checks\fR interval ++in always good status. ++The intervals are measured in \(dqticks\(dq, i.e. 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 \(dqmarginal_path\(dq failure tracking ++If a second failure event (good->bad transition) occurs within ++\fImarginal_path_double_failed_time\fR seconds after a failure, high-frequency ++monitoring is started for the affected path: I/O is sent at a rate of 10 per ++second. This is done for \fImarginal_path_err_sample_time\fR seconds. During ++this period, the path is not reinstated. If the ++rate of errors remains below \fImarginal_path_err_rate_threshold\fR during the ++monitoring period, the path is reinstated. Otherwise, it ++is kept in failed state for \fImarginal_path_err_recheck_gap_time\fR, and ++after that, it is monitored again. For this method, time intervals are measured ++in seconds. ++.RE ++.LP ++See the documentation ++of the individual options above for details. ++It is \fBstrongly discouraged\fR to use more than one of these methods for any ++given multipath map, because the two concurrent methods may interact in ++unpredictable ways. + .SH "KNOWN ISSUES" + The usage of + .B queue_if_no_path +Index: multipath-tools-130222/multipathd/cli_handlers.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/cli_handlers.c ++++ multipath-tools-130222/multipathd/cli_handlers.c +@@ -721,7 +721,7 @@ int resize_map(struct multipath *mpp, un + + mpp->size = size; + update_mpp_paths(mpp, vecs->pathvec); +- setup_map(mpp, params, PARAMS_SIZE); ++ setup_map(mpp, params, PARAMS_SIZE, vecs); + mpp->action = ACT_RESIZE; + if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed to resize map : %s", mpp->alias, +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "pidfile.h" +@@ -274,7 +275,7 @@ retry: + mpp->action = ACT_RELOAD; + + extract_hwe_from_path(mpp); +- if (setup_map(mpp, params, PARAMS_SIZE)) { ++ if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + condlog(0, "%s: failed to setup new map in update", mpp->alias); + retries = -1; + goto fail; +@@ -638,7 +639,7 @@ rescan: + /* + * push the map to the device-mapper + */ +- if (setup_map(mpp, params, PARAMS_SIZE)) { ++ if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + condlog(0, "%s: failed to setup map for addition of new " + "path %s", mpp->alias, pp->dev); + goto fail_map; +@@ -771,7 +772,7 @@ ev_remove_path (struct path *pp, struct + */ + } + +- if (setup_map(mpp, params, PARAMS_SIZE)) { ++ if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + condlog(0, "%s: failed to setup map for" + " removal of path %s", mpp->alias, pp->dev); + goto fail; +@@ -891,6 +892,41 @@ uev_update_path (struct uevent *uev, str + } + + static int ++uev_pathfail_check(struct uevent *uev, struct vectors *vecs) ++{ ++ char *action = NULL, *devt = NULL; ++ struct path *pp; ++ int r = 1; ++ ++ action = uevent_get_dm_action(uev); ++ if (!action) ++ return 1; ++ if (strncmp(action, "PATH_FAILED", 11)) ++ goto out; ++ devt = uevent_get_dm_path(uev); ++ if (!devt) { ++ condlog(3, "%s: No DM_PATH in uevent", uev->kernel); ++ goto out; ++ } ++ ++ pp = find_path_by_devt(vecs->pathvec, devt); ++ if (!pp) ++ goto out_devt; ++ r = io_err_stat_handle_pathfail(pp); ++ ++ if (r) ++ condlog(3, "io_err_stat: %s: cannot handle pathfail uevent", ++ pp->dev); ++out_devt: ++ FREE(devt); ++ FREE(action); ++ return r; ++out: ++ FREE(action); ++ return 1; ++} ++ ++static int + map_discovery (struct vectors * vecs) + { + struct multipath * mpp; +@@ -974,6 +1010,14 @@ uev_trigger (struct uevent * uev, void * + if (!strncmp(uev->kernel, "dm-", 3)) { + if (!strncmp(uev->action, "change", 6)) { + r = uev_add_map(uev, vecs); ++ ++ /* ++ * the kernel-side dm-mpath issues a PATH_FAILED event ++ * when it encounters a path IO error. It is reason- ++ * able be the entry of path IO error accounting pro- ++ * cess. ++ */ ++ uev_pathfail_check(uev, vecs); + goto out; + } + if (!strncmp(uev->action, "remove", 6)) { +@@ -1405,6 +1449,17 @@ check_path (struct vectors * vecs, struc + return; + + if ((newstate == PATH_UP || newstate == PATH_GHOST) && ++ pp->io_err_disable_reinstate && need_io_err_check(pp)) { ++ pp->state = PATH_SHAKY; ++ /* ++ * to reschedule as soon as possible,so that this path can ++ * be recoverd in time ++ */ ++ pp->tick = 1; ++ return; ++ } ++ ++ if ((newstate == PATH_UP || newstate == PATH_GHOST) && + pp->wait_checks > 0) { + if (pp->mpp && pp->mpp->nr_active > 0) { + pp->state = PATH_DELAYED; +@@ -1955,6 +2010,7 @@ child (void * param) + setup_thread_attr(&misc_attr, 64 * 1024, 1); + setup_thread_attr(&uevent_attr, 128 * 1024, 1); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); ++ setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + + if (logsink) { + setup_thread_attr(&log_attr, 64 * 1024, 0); +@@ -2097,6 +2153,8 @@ child (void * param) + */ + cleanup_checkers(); + cleanup_prio(); ++ stop_io_err_stat_thread(); ++ pthread_attr_destroy(&io_err_stat_attr); + + dm_lib_release(); + dm_lib_exit(); diff --git a/SOURCES/0256-RHBZ-1672175-retry-no-fd-paths.patch b/SOURCES/0256-RHBZ-1672175-retry-no-fd-paths.patch new file mode 100644 index 0000000..a4e9632 --- /dev/null +++ b/SOURCES/0256-RHBZ-1672175-retry-no-fd-paths.patch @@ -0,0 +1,215 @@ +--- + libmultipath/discovery.c | 10 ++++++-- + libmultipath/structs.h | 1 + libmultipath/structs_vec.c | 4 ++- + multipathd/main.c | 52 ++++++++++++++++++++++++++++++++------------- + 4 files changed, 49 insertions(+), 18 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1425,10 +1425,13 @@ pathinfo (struct path *pp, vector hwtabl + pp->fd = open(udev_device_get_devnode(pp->udev), O_RDONLY); + + if (pp->fd < 0) { ++ pp->missing_udev_info = INFO_REINIT; + condlog(4, "Couldn't open node for %s: %s", + pp->dev, strerror(errno)); + goto blank; + } ++ if (pp->missing_udev_info == INFO_REINIT) ++ pp->missing_udev_info = INFO_OK; + + if (mask & DI_SERIAL) + get_geometry(pp); +@@ -1443,8 +1446,11 @@ pathinfo (struct path *pp, vector hwtabl + + if (mask & DI_CHECKER) { + if (path_state == PATH_UP) { +- pp->chkrstate = pp->state = get_state(pp, 0, +- path_state); ++ int newstate = get_state(pp, 0, path_state); ++ if (newstate != PATH_PENDING || ++ pp->state == PATH_UNCHECKED || ++ pp->state == PATH_WILD) ++ pp->chkrstate = pp->state = newstate; + if (pp->state == PATH_UNCHECKED || + pp->state == PATH_WILD) + goto blank; +Index: multipath-tools-130222/libmultipath/structs.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs.h ++++ multipath-tools-130222/libmultipath/structs.h +@@ -184,6 +184,7 @@ enum marginal_path_states { + + enum missing_udev_info_states { + INFO_OK, ++ INFO_REINIT, + INFO_MISSING, + INFO_REQUESTED, + }; +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1381,7 +1381,7 @@ int update_path_groups(struct multipath + return 0; + } + +-void ++int + check_path (struct vectors * vecs, struct path * pp) + { + int newstate; +@@ -1390,19 +1390,20 @@ check_path (struct vectors * vecs, struc + int disable_reinstate = 0; + int oldchkrstate = pp->chkrstate; + +- if (!pp->mpp && (pp->missing_udev_info != INFO_MISSING || +- pp->retriggers >= conf->retrigger_tries)) +- return; ++ if (!pp->mpp && pp->missing_udev_info != INFO_REINIT && ++ (pp->missing_udev_info != INFO_MISSING || ++ pp->retriggers >= conf->retrigger_tries)) ++ return 0; + + if (pp->tick && --pp->tick) +- return; /* don't check this path yet */ ++ return 0; /* don't check this path yet */ + +- if (!pp->mpp) { ++ if (!pp->mpp && pp->missing_udev_info == INFO_MISSING) { + pp->missing_udev_info = INFO_REQUESTED; + pp->retriggers++; + sysfs_attr_set_value(pp->udev, "uevent", "change", + strlen("change")); +- return; ++ return 0; + } + + /* +@@ -1412,6 +1413,21 @@ check_path (struct vectors * vecs, struc + pp->tick = conf->checkint; + + newstate = path_offline(pp); ++ if (!pp->mpp) { ++ if (newstate == PATH_UP && ++ pp->missing_udev_info == INFO_REINIT) { ++ int ret; ++ condlog(3, "%s: add missing path", pp->dev); ++ ret = pathinfo(pp, conf->hwtable, ++ DI_ALL | DI_BLACKLIST); ++ if (ret == PATHINFO_OK && strlen(pp->wwid)) { ++ ev_add_path(pp, vecs); ++ pp->tick = 1; ++ } else if (ret == PATHINFO_SKIPPED) ++ return -1; ++ } ++ return 0; ++ } + if (newstate == PATH_UP) + newstate = get_state(pp, 1, newstate); + else +@@ -1426,7 +1442,7 @@ check_path (struct vectors * vecs, struc + if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { + condlog(2, "%s: unusable path", pp->dev); + pathinfo(pp, conf->hwtable, 0); +- return; ++ return 0; + } + /* + * Async IO in flight. Keep the previous path state +@@ -1434,7 +1450,7 @@ check_path (struct vectors * vecs, struc + */ + if (newstate == PATH_PENDING) { + pp->tick = 1; +- return; ++ return 0; + } + /* + * Synchronize with kernel state +@@ -1446,7 +1462,7 @@ check_path (struct vectors * vecs, struc + } + /* if update_multipath_strings orphaned the path, quit early */ + if (!pp->mpp) +- return; ++ return 0; + + if ((newstate == PATH_UP || newstate == PATH_GHOST) && + pp->io_err_disable_reinstate && need_io_err_check(pp)) { +@@ -1456,7 +1472,7 @@ check_path (struct vectors * vecs, struc + * be recoverd in time + */ + pp->tick = 1; +- return; ++ return 0; + } + + if ((newstate == PATH_UP || newstate == PATH_GHOST) && +@@ -1464,7 +1480,7 @@ check_path (struct vectors * vecs, struc + if (pp->mpp && pp->mpp->nr_active > 0) { + pp->state = PATH_DELAYED; + pp->wait_checks--; +- return; ++ return 0; + } else + pp->wait_checks = 0; + } +@@ -1512,7 +1528,7 @@ check_path (struct vectors * vecs, struc + pp->mpp->failback_tick = 0; + + pp->mpp->stat_path_failures++; +- return; ++ return 0; + } + + if(newstate == PATH_UP || newstate == PATH_GHOST){ +@@ -1594,7 +1610,7 @@ check_path (struct vectors * vecs, struc + + + if (pp->mpp->wait_for_udev) +- return; ++ return 0; + /* + * path prio refreshing + */ +@@ -1613,6 +1629,7 @@ check_path (struct vectors * vecs, struc + (chkr_new_path_up && followover_should_failback(pp))) + switch_pathgroup(pp->mpp); + } ++ return 0; + } + + static void * +@@ -1642,7 +1659,12 @@ checkerloop (void *ap) + + if (vecs->pathvec) { + vector_foreach_slot (vecs->pathvec, pp, i) { +- check_path(vecs, pp); ++ int rc = check_path(vecs, pp); ++ if (rc < 0) { ++ vector_del_slot(vecs->pathvec, i); ++ free_path(pp); ++ i--; ++ } + } + } + if (vecs->mpvec) { +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -274,9 +274,11 @@ void sync_paths(struct multipath *mpp, v + } + } + if (!found) { +- condlog(3, "%s dropped path %s", mpp->alias, pp->dev); ++ condlog(2, "%s dropped path %s", mpp->alias, pp->dev); + vector_del_slot(mpp->paths, i--); + orphan_path(pp); ++ memset(pp->wwid, 0, WWID_SIZE); ++ pp->missing_udev_info = INFO_REINIT; + } + } + update_mpp_paths(mpp, pathvec); diff --git a/SOURCES/0257-RHBZ-1679556-dont-check-dm-devices.patch b/SOURCES/0257-RHBZ-1679556-dont-check-dm-devices.patch new file mode 100644 index 0000000..bb1168b --- /dev/null +++ b/SOURCES/0257-RHBZ-1679556-dont-check-dm-devices.patch @@ -0,0 +1,16 @@ +--- + multipath/multipath.rules | 1 + + 1 file changed, 1 insertion(+) + +Index: multipath-tools-130222/multipath/multipath.rules +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.rules ++++ multipath-tools-130222/multipath/multipath.rules +@@ -15,6 +15,7 @@ LABEL="test_dev" + ENV{MPATH_SBIN_PATH}="/sbin" + TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" + TEST!="/etc/multipath.conf", GOTO="check_kpartx" ++KERNEL=="dm-*", GOTO="check_kpartx" + + ACTION=="add", ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ + PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \ diff --git a/SOURCES/0258-RHBZ-1634183-ANA-prioritizer.patch b/SOURCES/0258-RHBZ-1634183-ANA-prioritizer.patch new file mode 100644 index 0000000..8657022 --- /dev/null +++ b/SOURCES/0258-RHBZ-1634183-ANA-prioritizer.patch @@ -0,0 +1,3458 @@ +--- + Makefile.inc | 1 + libmultipath/Makefile | 7 + libmultipath/hwtable.c | 1 + libmultipath/nvme-ioctl.c | 869 ++++++++++++++++++++ + libmultipath/nvme-ioctl.h | 139 +++ + libmultipath/nvme-lib.c | 49 + + libmultipath/nvme-lib.h | 39 + libmultipath/nvme/argconfig.h | 99 ++ + libmultipath/nvme/json.h | 87 ++ + libmultipath/nvme/linux/nvme.h | 1450 +++++++++++++++++++++++++++++++++++ + libmultipath/nvme/linux/nvme_ioctl.h | 67 + + libmultipath/nvme/nvme.h | 163 +++ + libmultipath/nvme/plugin.h | 36 + libmultipath/prio.h | 1 + libmultipath/prioritizers/Makefile | 4 + libmultipath/prioritizers/ana.c | 236 +++++ + libmultipath/propsel.c | 10 + libmultipath/util.h | 2 + multipath/multipath.conf.5 | 3 + 19 files changed, 3258 insertions(+), 5 deletions(-) + +Index: multipath-tools-130222/libmultipath/nvme/argconfig.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme/argconfig.h +@@ -0,0 +1,99 @@ ++//////////////////////////////////////////////////////////////////////// ++// ++// Copyright 2014 PMC-Sierra, Inc. ++// ++// This program is free software; you can redistribute it and/or ++// modify it under the terms of the GNU General Public License ++// as published by the Free Software Foundation; either version 2 ++// of the License, or (at your option) any later version. ++// ++// This program is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++// GNU General Public License for more details. ++// ++// You should have received a copy of the GNU General Public License ++// along with this program; if not, write to the Free Software ++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++// ++//////////////////////////////////////////////////////////////////////// ++ ++//////////////////////////////////////////////////////////////////////// ++// ++// Author: Logan Gunthorpe ++// Logan Gunthorpe ++// ++// Date: Oct 23 2014 ++// ++// Description: ++// Header file for argconfig.c ++// ++//////////////////////////////////////////////////////////////////////// ++ ++#ifndef argconfig_H ++#define argconfig_H ++ ++#include ++#include ++#include ++ ++enum argconfig_types { ++ CFG_NONE, ++ CFG_STRING, ++ CFG_INT, ++ CFG_SIZE, ++ CFG_LONG, ++ CFG_LONG_SUFFIX, ++ CFG_DOUBLE, ++ CFG_BOOL, ++ CFG_BYTE, ++ CFG_SHORT, ++ CFG_POSITIVE, ++ CFG_INCREMENT, ++ CFG_SUBOPTS, ++ CFG_FILE_A, ++ CFG_FILE_W, ++ CFG_FILE_R, ++ CFG_FILE_AP, ++ CFG_FILE_WP, ++ CFG_FILE_RP, ++}; ++ ++struct argconfig_commandline_options { ++ const char *option; ++ const char short_option; ++ const char *meta; ++ enum argconfig_types config_type; ++ void *default_value; ++ int argument_type; ++ const char *help; ++}; ++ ++#define CFG_MAX_SUBOPTS 500 ++#define MAX_HELP_FUNC 20 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef void argconfig_help_func(void); ++void argconfig_append_usage(const char *str); ++void argconfig_print_help(const char *program_desc, ++ const struct argconfig_commandline_options *options); ++int argconfig_parse(int argc, char *argv[], const char *program_desc, ++ const struct argconfig_commandline_options *options, ++ void *config_out, size_t config_size); ++int argconfig_parse_subopt_string(char *string, char **options, ++ size_t max_options); ++unsigned argconfig_parse_comma_sep_array(char *string, int *ret, ++ unsigned max_length); ++unsigned argconfig_parse_comma_sep_array_long(char *string, ++ unsigned long long *ret, ++ unsigned max_length); ++void argconfig_register_help_func(argconfig_help_func * f); ++ ++void print_word_wrapped(const char *s, int indent, int start); ++#ifdef __cplusplus ++} ++#endif ++#endif +Index: multipath-tools-130222/libmultipath/nvme/json.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme/json.h +@@ -0,0 +1,87 @@ ++#ifndef __JSON__H ++#define __JSON__H ++ ++struct json_object; ++struct json_array; ++struct json_pair; ++ ++#define JSON_TYPE_STRING 0 ++#define JSON_TYPE_INTEGER 1 ++#define JSON_TYPE_FLOAT 2 ++#define JSON_TYPE_OBJECT 3 ++#define JSON_TYPE_ARRAY 4 ++#define JSON_TYPE_UINT 5 ++#define JSON_PARENT_TYPE_PAIR 0 ++#define JSON_PARENT_TYPE_ARRAY 1 ++struct json_value { ++ int type; ++ union { ++ long long integer_number; ++ unsigned long long uint_number; ++ long double float_number; ++ char *string; ++ struct json_object *object; ++ struct json_array *array; ++ }; ++ int parent_type; ++ union { ++ struct json_pair *parent_pair; ++ struct json_array *parent_array; ++ }; ++}; ++ ++struct json_array { ++ struct json_value **values; ++ int value_cnt; ++ struct json_value *parent; ++}; ++ ++struct json_object { ++ struct json_pair **pairs; ++ int pair_cnt; ++ struct json_value *parent; ++}; ++ ++struct json_pair { ++ char *name; ++ struct json_value *value; ++ struct json_object *parent; ++}; ++ ++struct json_object *json_create_object(void); ++struct json_array *json_create_array(void); ++ ++void json_free_object(struct json_object *obj); ++ ++int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...); ++#define json_object_add_value_int(obj, name, val) \ ++ json_object_add_value_type((obj), name, JSON_TYPE_INTEGER, (long long) (val)) ++#define json_object_add_value_uint(obj, name, val) \ ++ json_object_add_value_type((obj), name, JSON_TYPE_UINT, (unsigned long long) (val)) ++#define json_object_add_value_float(obj, name, val) \ ++ json_object_add_value_type((obj), name, JSON_TYPE_FLOAT, (val)) ++#define json_object_add_value_string(obj, name, val) \ ++ json_object_add_value_type((obj), name, JSON_TYPE_STRING, (val)) ++#define json_object_add_value_object(obj, name, val) \ ++ json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val)) ++#define json_object_add_value_array(obj, name, val) \ ++ json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val)) ++int json_array_add_value_type(struct json_array *array, int type, ...); ++#define json_array_add_value_int(obj, val) \ ++ json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val)) ++#define json_array_add_value_uint(obj, val) \ ++ json_array_add_value_type((obj), JSON_TYPE_UINT, (val)) ++#define json_array_add_value_float(obj, val) \ ++ json_array_add_value_type((obj), JSON_TYPE_FLOAT, (val)) ++#define json_array_add_value_string(obj, val) \ ++ json_array_add_value_type((obj), JSON_TYPE_STRING, (val)) ++#define json_array_add_value_object(obj, val) \ ++ json_array_add_value_type((obj), JSON_TYPE_OBJECT, (val)) ++#define json_array_add_value_array(obj, val) \ ++ json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val)) ++ ++#define json_array_last_value_object(obj) \ ++ (obj->values[obj->value_cnt - 1]->object) ++ ++void json_print_object(struct json_object *obj, void *); ++#endif +Index: multipath-tools-130222/libmultipath/nvme/nvme.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme/nvme.h +@@ -0,0 +1,163 @@ ++/* ++ * Definitions for the NVM Express interface ++ * Copyright (c) 2011-2014, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _NVME_H ++#define _NVME_H ++ ++#include ++#include ++#include ++#include "plugin.h" ++#include "json.h" ++ ++#define unlikely(x) x ++ ++#ifdef LIBUUID ++#include ++#else ++typedef struct { ++ uint8_t b[16]; ++} uuid_t; ++#endif ++ ++#include "linux/nvme.h" ++ ++struct nvme_effects_log_page { ++ __le32 acs[256]; ++ __le32 iocs[256]; ++ __u8 resv[2048]; ++}; ++ ++struct nvme_error_log_page { ++ __u64 error_count; ++ __u16 sqid; ++ __u16 cmdid; ++ __u16 status_field; ++ __u16 parm_error_location; ++ __u64 lba; ++ __u32 nsid; ++ __u8 vs; ++ __u8 resv[3]; ++ __u64 cs; ++ __u8 resv2[24]; ++}; ++ ++struct nvme_firmware_log_page { ++ __u8 afi; ++ __u8 resv[7]; ++ __u64 frs[7]; ++ __u8 resv2[448]; ++}; ++ ++/* idle and active power scales occupy the last 2 bits of the field */ ++#define POWER_SCALE(s) ((s) >> 6) ++ ++struct nvme_host_mem_buffer { ++ __u32 hsize; ++ __u32 hmdlal; ++ __u32 hmdlau; ++ __u32 hmdlec; ++ __u8 rsvd16[4080]; ++}; ++ ++struct nvme_auto_pst { ++ __u32 data; ++ __u32 rsvd32; ++}; ++ ++struct nvme_timestamp { ++ __u8 timestamp[6]; ++ __u8 attr; ++ __u8 rsvd; ++}; ++ ++struct nvme_controller_list { ++ __le16 num; ++ __le16 identifier[]; ++}; ++ ++struct nvme_bar_cap { ++ __u16 mqes; ++ __u8 ams_cqr; ++ __u8 to; ++ __u16 bps_css_nssrs_dstrd; ++ __u8 mpsmax_mpsmin; ++ __u8 reserved; ++}; ++ ++#ifdef __CHECKER__ ++#define __force __attribute__((force)) ++#else ++#define __force ++#endif ++ ++#define cpu_to_le16(x) \ ++ ((__force __le16)htole16(x)) ++#define cpu_to_le32(x) \ ++ ((__force __le32)htole32(x)) ++#define cpu_to_le64(x) \ ++ ((__force __le64)htole64(x)) ++ ++#define le16_to_cpu(x) \ ++ le16toh((__force __u16)(x)) ++#define le32_to_cpu(x) \ ++ le32toh((__force __u32)(x)) ++#define le64_to_cpu(x) \ ++ le64toh((__force __u64)(x)) ++ ++#define MAX_LIST_ITEMS 256 ++struct list_item { ++ char node[1024]; ++ struct nvme_id_ctrl ctrl; ++ int nsid; ++ struct nvme_id_ns ns; ++ unsigned block; ++}; ++ ++struct ctrl_list_item { ++ char *name; ++ char *address; ++ char *transport; ++ char *state; ++ char *ana_state; ++}; ++ ++struct subsys_list_item { ++ char *name; ++ char *subsysnqn; ++ int nctrls; ++ struct ctrl_list_item *ctrls; ++}; ++ ++enum { ++ NORMAL, ++ JSON, ++ BINARY, ++}; ++ ++void register_extension(struct plugin *plugin); ++ ++#include "argconfig.h" ++int parse_and_open(int argc, char **argv, const char *desc, ++ const struct argconfig_commandline_options *clo, void *cfg, size_t size); ++ ++extern const char *devicename; ++ ++int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root)); ++int validate_output_format(char *format); ++ ++struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn, __u32 nsid); ++void free_subsys_list(struct subsys_list_item *slist, int n); ++char *nvme_char_from_block(char *block); ++#endif /* _NVME_H */ +Index: multipath-tools-130222/libmultipath/nvme/plugin.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme/plugin.h +@@ -0,0 +1,36 @@ ++#ifndef PLUGIN_H ++#define PLUGIN_H ++ ++#include ++ ++struct program { ++ const char *name; ++ const char *version; ++ const char *usage; ++ const char *desc; ++ const char *more; ++ struct command **commands; ++ struct plugin *extensions; ++}; ++ ++struct plugin { ++ const char *name; ++ const char *desc; ++ struct command **commands; ++ struct program *parent; ++ struct plugin *next; ++ struct plugin *tail; ++}; ++ ++struct command { ++ char *name; ++ char *help; ++ int (*fn)(int argc, char **argv, struct command *command, struct plugin *plugin); ++ char *alias; ++}; ++ ++void usage(struct plugin *plugin); ++void general_help(struct plugin *plugin); ++int handle_plugin(int argc, char **argv, struct plugin *plugin); ++ ++#endif +Index: multipath-tools-130222/libmultipath/nvme/linux/nvme.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme/linux/nvme.h +@@ -0,0 +1,1450 @@ ++/* ++ * Definitions for the NVM Express interface ++ * Copyright (c) 2011-2014, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _LINUX_NVME_H ++#define _LINUX_NVME_H ++ ++#include ++#include ++ ++/* NQN names in commands fields specified one size */ ++#define NVMF_NQN_FIELD_LEN 256 ++ ++/* However the max length of a qualified name is another size */ ++#define NVMF_NQN_SIZE 223 ++ ++#define NVMF_TRSVCID_SIZE 32 ++#define NVMF_TRADDR_SIZE 256 ++#define NVMF_TSAS_SIZE 256 ++ ++#define NVME_DISC_SUBSYS_NAME "nqn.2014-08.org.nvmexpress.discovery" ++ ++#define NVME_RDMA_IP_PORT 4420 ++ ++#define NVME_NSID_ALL 0xffffffff ++ ++enum nvme_subsys_type { ++ NVME_NQN_DISC = 1, /* Discovery type target subsystem */ ++ NVME_NQN_NVME = 2, /* NVME type target subsystem */ ++}; ++ ++/* Address Family codes for Discovery Log Page entry ADRFAM field */ ++enum { ++ NVMF_ADDR_FAMILY_PCI = 0, /* PCIe */ ++ NVMF_ADDR_FAMILY_IP4 = 1, /* IP4 */ ++ NVMF_ADDR_FAMILY_IP6 = 2, /* IP6 */ ++ NVMF_ADDR_FAMILY_IB = 3, /* InfiniBand */ ++ NVMF_ADDR_FAMILY_FC = 4, /* Fibre Channel */ ++}; ++ ++/* Transport Type codes for Discovery Log Page entry TRTYPE field */ ++enum { ++ NVMF_TRTYPE_RDMA = 1, /* RDMA */ ++ NVMF_TRTYPE_FC = 2, /* Fibre Channel */ ++ NVMF_TRTYPE_TCP = 3, /* TCP */ ++ NVMF_TRTYPE_LOOP = 254, /* Reserved for host usage */ ++ NVMF_TRTYPE_MAX, ++}; ++ ++/* Transport Requirements codes for Discovery Log Page entry TREQ field */ ++enum { ++ NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */ ++ NVMF_TREQ_REQUIRED = 1, /* Required */ ++ NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */ ++ NVMF_TREQ_DISABLE_SQFLOW = (1 << 2), /* SQ flow control disable supported */ ++}; ++ ++/* RDMA QP Service Type codes for Discovery Log Page entry TSAS ++ * RDMA_QPTYPE field ++ */ ++enum { ++ NVMF_RDMA_QPTYPE_CONNECTED = 1, /* Reliable Connected */ ++ NVMF_RDMA_QPTYPE_DATAGRAM = 2, /* Reliable Datagram */ ++}; ++ ++/* RDMA QP Service Type codes for Discovery Log Page entry TSAS ++ * RDMA_QPTYPE field ++ */ ++enum { ++ NVMF_RDMA_PRTYPE_NOT_SPECIFIED = 1, /* No Provider Specified */ ++ NVMF_RDMA_PRTYPE_IB = 2, /* InfiniBand */ ++ NVMF_RDMA_PRTYPE_ROCE = 3, /* InfiniBand RoCE */ ++ NVMF_RDMA_PRTYPE_ROCEV2 = 4, /* InfiniBand RoCEV2 */ ++ NVMF_RDMA_PRTYPE_IWARP = 5, /* IWARP */ ++}; ++ ++/* RDMA Connection Management Service Type codes for Discovery Log Page ++ * entry TSAS RDMA_CMS field ++ */ ++enum { ++ NVMF_RDMA_CMS_RDMA_CM = 1, /* Sockets based endpoint addressing */ ++}; ++ ++/* TCP port security type for Discovery Log Page entry TSAS ++ */ ++enum { ++ NVMF_TCP_SECTYPE_NONE = 0, /* No Security */ ++ NVMF_TCP_SECTYPE_TLS = 1, /* Transport Layer Security */ ++}; ++ ++#define NVME_AQ_DEPTH 32 ++#define NVME_NR_AEN_COMMANDS 1 ++#define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS) ++ ++/* ++ * Subtract one to leave an empty queue entry for 'Full Queue' condition. See ++ * NVM-Express 1.2 specification, section 4.1.2. ++ */ ++#define NVME_AQ_MQ_TAG_DEPTH (NVME_AQ_BLK_MQ_DEPTH - 1) ++ ++enum { ++ NVME_REG_CAP = 0x0000, /* Controller Capabilities */ ++ NVME_REG_VS = 0x0008, /* Version */ ++ NVME_REG_INTMS = 0x000c, /* Interrupt Mask Set */ ++ NVME_REG_INTMC = 0x0010, /* Interrupt Mask Clear */ ++ NVME_REG_CC = 0x0014, /* Controller Configuration */ ++ NVME_REG_CSTS = 0x001c, /* Controller Status */ ++ NVME_REG_NSSR = 0x0020, /* NVM Subsystem Reset */ ++ NVME_REG_AQA = 0x0024, /* Admin Queue Attributes */ ++ NVME_REG_ASQ = 0x0028, /* Admin SQ Base Address */ ++ NVME_REG_ACQ = 0x0030, /* Admin CQ Base Address */ ++ NVME_REG_CMBLOC = 0x0038, /* Controller Memory Buffer Location */ ++ NVME_REG_CMBSZ = 0x003c, /* Controller Memory Buffer Size */ ++ NVME_REG_BPINFO = 0x0040, /* Boot Partition Information */ ++ NVME_REG_BPRSEL = 0x0044, /* Boot Partition Read Select */ ++ NVME_REG_BPMBL = 0x0048, /* Boot Partition Memory Buffer Location */ ++ NVME_REG_DBS = 0x1000, /* SQ 0 Tail Doorbell */ ++}; ++ ++#define NVME_CAP_MQES(cap) ((cap) & 0xffff) ++#define NVME_CAP_TIMEOUT(cap) (((cap) >> 24) & 0xff) ++#define NVME_CAP_STRIDE(cap) (((cap) >> 32) & 0xf) ++#define NVME_CAP_NSSRC(cap) (((cap) >> 36) & 0x1) ++#define NVME_CAP_MPSMIN(cap) (((cap) >> 48) & 0xf) ++#define NVME_CAP_MPSMAX(cap) (((cap) >> 52) & 0xf) ++ ++#define NVME_CMB_BIR(cmbloc) ((cmbloc) & 0x7) ++#define NVME_CMB_OFST(cmbloc) (((cmbloc) >> 12) & 0xfffff) ++#define NVME_CMB_SZ(cmbsz) (((cmbsz) >> 12) & 0xfffff) ++#define NVME_CMB_SZU(cmbsz) (((cmbsz) >> 8) & 0xf) ++ ++#define NVME_CMB_WDS(cmbsz) ((cmbsz) & 0x10) ++#define NVME_CMB_RDS(cmbsz) ((cmbsz) & 0x8) ++#define NVME_CMB_LISTS(cmbsz) ((cmbsz) & 0x4) ++#define NVME_CMB_CQS(cmbsz) ((cmbsz) & 0x2) ++#define NVME_CMB_SQS(cmbsz) ((cmbsz) & 0x1) ++ ++/* ++ * Submission and Completion Queue Entry Sizes for the NVM command set. ++ * (In bytes and specified as a power of two (2^n)). ++ */ ++#define NVME_NVM_IOSQES 6 ++#define NVME_NVM_IOCQES 4 ++ ++enum { ++ NVME_CC_ENABLE = 1 << 0, ++ NVME_CC_CSS_NVM = 0 << 4, ++ NVME_CC_EN_SHIFT = 0, ++ NVME_CC_CSS_SHIFT = 4, ++ NVME_CC_MPS_SHIFT = 7, ++ NVME_CC_AMS_SHIFT = 11, ++ NVME_CC_SHN_SHIFT = 14, ++ NVME_CC_IOSQES_SHIFT = 16, ++ NVME_CC_IOCQES_SHIFT = 20, ++ NVME_CC_AMS_RR = 0 << NVME_CC_AMS_SHIFT, ++ NVME_CC_AMS_WRRU = 1 << NVME_CC_AMS_SHIFT, ++ NVME_CC_AMS_VS = 7 << NVME_CC_AMS_SHIFT, ++ NVME_CC_SHN_NONE = 0 << NVME_CC_SHN_SHIFT, ++ NVME_CC_SHN_NORMAL = 1 << NVME_CC_SHN_SHIFT, ++ NVME_CC_SHN_ABRUPT = 2 << NVME_CC_SHN_SHIFT, ++ NVME_CC_SHN_MASK = 3 << NVME_CC_SHN_SHIFT, ++ NVME_CC_IOSQES = NVME_NVM_IOSQES << NVME_CC_IOSQES_SHIFT, ++ NVME_CC_IOCQES = NVME_NVM_IOCQES << NVME_CC_IOCQES_SHIFT, ++ NVME_CSTS_RDY = 1 << 0, ++ NVME_CSTS_CFS = 1 << 1, ++ NVME_CSTS_NSSRO = 1 << 4, ++ NVME_CSTS_PP = 1 << 5, ++ NVME_CSTS_SHST_NORMAL = 0 << 2, ++ NVME_CSTS_SHST_OCCUR = 1 << 2, ++ NVME_CSTS_SHST_CMPLT = 2 << 2, ++ NVME_CSTS_SHST_MASK = 3 << 2, ++}; ++ ++struct nvme_id_power_state { ++ __le16 max_power; /* centiwatts */ ++ __u8 rsvd2; ++ __u8 flags; ++ __le32 entry_lat; /* microseconds */ ++ __le32 exit_lat; /* microseconds */ ++ __u8 read_tput; ++ __u8 read_lat; ++ __u8 write_tput; ++ __u8 write_lat; ++ __le16 idle_power; ++ __u8 idle_scale; ++ __u8 rsvd19; ++ __le16 active_power; ++ __u8 active_work_scale; ++ __u8 rsvd23[9]; ++}; ++ ++enum { ++ NVME_PS_FLAGS_MAX_POWER_SCALE = 1 << 0, ++ NVME_PS_FLAGS_NON_OP_STATE = 1 << 1, ++}; ++ ++struct nvme_id_ctrl { ++ __le16 vid; ++ __le16 ssvid; ++ char sn[20]; ++ char mn[40]; ++ char fr[8]; ++ __u8 rab; ++ __u8 ieee[3]; ++ __u8 cmic; ++ __u8 mdts; ++ __le16 cntlid; ++ __le32 ver; ++ __le32 rtd3r; ++ __le32 rtd3e; ++ __le32 oaes; ++ __le32 ctratt; ++ __le16 rrls; ++ __u8 rsvd102[154]; ++ __le16 oacs; ++ __u8 acl; ++ __u8 aerl; ++ __u8 frmw; ++ __u8 lpa; ++ __u8 elpe; ++ __u8 npss; ++ __u8 avscc; ++ __u8 apsta; ++ __le16 wctemp; ++ __le16 cctemp; ++ __le16 mtfa; ++ __le32 hmpre; ++ __le32 hmmin; ++ __u8 tnvmcap[16]; ++ __u8 unvmcap[16]; ++ __le32 rpmbs; ++ __le16 edstt; ++ __u8 dsto; ++ __u8 fwug; ++ __le16 kas; ++ __le16 hctma; ++ __le16 mntmt; ++ __le16 mxtmt; ++ __le32 sanicap; ++ __le32 hmminds; ++ __le16 hmmaxd; ++ __le16 nsetidmax; ++ __u8 rsvd340[2]; ++ __u8 anatt; ++ __u8 anacap; ++ __le32 anagrpmax; ++ __le32 nanagrpid; ++ __u8 rsvd352[160]; ++ __u8 sqes; ++ __u8 cqes; ++ __le16 maxcmd; ++ __le32 nn; ++ __le16 oncs; ++ __le16 fuses; ++ __u8 fna; ++ __u8 vwc; ++ __le16 awun; ++ __le16 awupf; ++ __u8 nvscc; ++ __u8 nwpc; ++ __le16 acwu; ++ __u8 rsvd534[2]; ++ __le32 sgls; ++ __le32 mnan; ++ __u8 rsvd544[224]; ++ char subnqn[256]; ++ __u8 rsvd1024[768]; ++ __le32 ioccsz; ++ __le32 iorcsz; ++ __le16 icdoff; ++ __u8 ctrattr; ++ __u8 msdbd; ++ __u8 rsvd1804[244]; ++ struct nvme_id_power_state psd[32]; ++ __u8 vs[1024]; ++}; ++ ++enum { ++ NVME_CTRL_ONCS_COMPARE = 1 << 0, ++ NVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 1 << 1, ++ NVME_CTRL_ONCS_DSM = 1 << 2, ++ NVME_CTRL_ONCS_WRITE_ZEROES = 1 << 3, ++ NVME_CTRL_ONCS_TIMESTAMP = 1 << 6, ++ NVME_CTRL_VWC_PRESENT = 1 << 0, ++ NVME_CTRL_OACS_SEC_SUPP = 1 << 0, ++ NVME_CTRL_OACS_DIRECTIVES = 1 << 5, ++ NVME_CTRL_OACS_DBBUF_SUPP = 1 << 8, ++ NVME_CTRL_LPA_CMD_EFFECTS_LOG = 1 << 1, ++ NVME_CTRL_CTRATT_128_ID = 1 << 0, ++ NVME_CTRL_CTRATT_NON_OP_PSP = 1 << 1, ++ NVME_CTRL_CTRATT_NVM_SETS = 1 << 2, ++ NVME_CTRL_CTRATT_READ_RECV_LVLS = 1 << 3, ++ NVME_CTRL_CTRATT_ENDURANCE_GROUPS = 1 << 4, ++ NVME_CTRL_CTRATT_PREDICTABLE_LAT = 1 << 5, ++}; ++ ++struct nvme_lbaf { ++ __le16 ms; ++ __u8 ds; ++ __u8 rp; ++}; ++ ++struct nvme_id_ns { ++ __le64 nsze; ++ __le64 ncap; ++ __le64 nuse; ++ __u8 nsfeat; ++ __u8 nlbaf; ++ __u8 flbas; ++ __u8 mc; ++ __u8 dpc; ++ __u8 dps; ++ __u8 nmic; ++ __u8 rescap; ++ __u8 fpi; ++ __u8 dlfeat; ++ __le16 nawun; ++ __le16 nawupf; ++ __le16 nacwu; ++ __le16 nabsn; ++ __le16 nabo; ++ __le16 nabspf; ++ __le16 noiob; ++ __u8 nvmcap[16]; ++ __u8 rsvd64[28]; ++ __le32 anagrpid; ++ __u8 rsvd96[3]; ++ __u8 nsattr; ++ __le16 nvmsetid; ++ __le16 endgid; ++ __u8 nguid[16]; ++ __u8 eui64[8]; ++ struct nvme_lbaf lbaf[16]; ++ __u8 rsvd192[192]; ++ __u8 vs[3712]; ++}; ++ ++enum { ++ NVME_ID_CNS_NS = 0x00, ++ NVME_ID_CNS_CTRL = 0x01, ++ NVME_ID_CNS_NS_ACTIVE_LIST = 0x02, ++ NVME_ID_CNS_NS_DESC_LIST = 0x03, ++ NVME_ID_CNS_NVMSET_LIST = 0x04, ++ NVME_ID_CNS_NS_PRESENT_LIST = 0x10, ++ NVME_ID_CNS_NS_PRESENT = 0x11, ++ NVME_ID_CNS_CTRL_NS_LIST = 0x12, ++ NVME_ID_CNS_CTRL_LIST = 0x13, ++}; ++ ++enum { ++ NVME_DIR_IDENTIFY = 0x00, ++ NVME_DIR_STREAMS = 0x01, ++ NVME_DIR_SND_ID_OP_ENABLE = 0x01, ++ NVME_DIR_SND_ST_OP_REL_ID = 0x01, ++ NVME_DIR_SND_ST_OP_REL_RSC = 0x02, ++ NVME_DIR_RCV_ID_OP_PARAM = 0x01, ++ NVME_DIR_RCV_ST_OP_PARAM = 0x01, ++ NVME_DIR_RCV_ST_OP_STATUS = 0x02, ++ NVME_DIR_RCV_ST_OP_RESOURCE = 0x03, ++ NVME_DIR_ENDIR = 0x01, ++}; ++ ++enum { ++ NVME_NS_FEAT_THIN = 1 << 0, ++ NVME_NS_FLBAS_LBA_MASK = 0xf, ++ NVME_NS_FLBAS_META_EXT = 0x10, ++ NVME_LBAF_RP_BEST = 0, ++ NVME_LBAF_RP_BETTER = 1, ++ NVME_LBAF_RP_GOOD = 2, ++ NVME_LBAF_RP_DEGRADED = 3, ++ NVME_NS_DPC_PI_LAST = 1 << 4, ++ NVME_NS_DPC_PI_FIRST = 1 << 3, ++ NVME_NS_DPC_PI_TYPE3 = 1 << 2, ++ NVME_NS_DPC_PI_TYPE2 = 1 << 1, ++ NVME_NS_DPC_PI_TYPE1 = 1 << 0, ++ NVME_NS_DPS_PI_FIRST = 1 << 3, ++ NVME_NS_DPS_PI_MASK = 0x7, ++ NVME_NS_DPS_PI_TYPE1 = 1, ++ NVME_NS_DPS_PI_TYPE2 = 2, ++ NVME_NS_DPS_PI_TYPE3 = 3, ++}; ++ ++struct nvme_ns_id_desc { ++ __u8 nidt; ++ __u8 nidl; ++ __le16 reserved; ++}; ++ ++#define NVME_NIDT_EUI64_LEN 8 ++#define NVME_NIDT_NGUID_LEN 16 ++#define NVME_NIDT_UUID_LEN 16 ++ ++enum { ++ NVME_NIDT_EUI64 = 0x01, ++ NVME_NIDT_NGUID = 0x02, ++ NVME_NIDT_UUID = 0x03, ++}; ++ ++#define NVME_MAX_NVMSET 31 ++ ++struct nvme_nvmset_attr_entry { ++ __le16 id; ++ __le16 endurance_group_id; ++ __u8 rsvd4[4]; ++ __le32 random_4k_read_typical; ++ __le32 opt_write_size; ++ __u8 total_nvmset_cap[16]; ++ __u8 unalloc_nvmset_cap[16]; ++ __u8 rsvd48[80]; ++}; ++ ++struct nvme_id_nvmset { ++ __u8 nid; ++ __u8 rsvd1[127]; ++ struct nvme_nvmset_attr_entry ent[NVME_MAX_NVMSET]; ++}; ++ ++/* Derived from 1.3a Figure 101: Get Log Page – Telemetry Host ++ * -Initiated Log (Log Identifier 07h) ++ */ ++struct nvme_telemetry_log_page_hdr { ++ __u8 lpi; /* Log page identifier */ ++ __u8 rsvd[4]; ++ __u8 iee_oui[3]; ++ __u16 dalb1; /* Data area 1 last block */ ++ __u16 dalb2; /* Data area 2 last block */ ++ __u16 dalb3; /* Data area 3 last block */ ++ __u8 rsvd1[368]; /* TODO verify */ ++ __u8 ctrlavail; /* Controller initiated data avail?*/ ++ __u8 ctrldgn; /* Controller initiated telemetry Data Gen # */ ++ __u8 rsnident[128]; ++ /* We'll have to double fetch so we can get the header, ++ * parse dalb1->3 determine how much size we need for the ++ * log then alloc below. Or just do a secondary non-struct ++ * allocation. ++ */ ++ __u8 telemetry_dataarea[0]; ++}; ++ ++struct nvme_endurance_group_log { ++ __u32 rsvd0; ++ __u8 avl_spare_threshold; ++ __u8 percent_used; ++ __u8 rsvd6[26]; ++ __u8 endurance_estimate[16]; ++ __u8 data_units_read[16]; ++ __u8 data_units_written[16]; ++ __u8 media_units_written[16]; ++ __u8 rsvd96[416]; ++}; ++ ++struct nvme_smart_log { ++ __u8 critical_warning; ++ __u8 temperature[2]; ++ __u8 avail_spare; ++ __u8 spare_thresh; ++ __u8 percent_used; ++ __u8 rsvd6[26]; ++ __u8 data_units_read[16]; ++ __u8 data_units_written[16]; ++ __u8 host_reads[16]; ++ __u8 host_writes[16]; ++ __u8 ctrl_busy_time[16]; ++ __u8 power_cycles[16]; ++ __u8 power_on_hours[16]; ++ __u8 unsafe_shutdowns[16]; ++ __u8 media_errors[16]; ++ __u8 num_err_log_entries[16]; ++ __le32 warning_temp_time; ++ __le32 critical_comp_time; ++ __le16 temp_sensor[8]; ++ __le32 thm_temp1_trans_count; ++ __le32 thm_temp2_trans_count; ++ __le32 thm_temp1_total_time; ++ __le32 thm_temp2_total_time; ++ __u8 rsvd232[280]; ++}; ++ ++struct nvme_self_test_res { ++ __u8 device_self_test_status; ++ __u8 segment_num; ++ __u8 valid_diagnostic_info; ++ __u8 rsvd; ++ __le64 power_on_hours; ++ __le32 nsid; ++ __le64 failing_lba; ++ __u8 status_code_type; ++ __u8 status_code; ++ __u8 vendor_specific[2]; ++} __attribute__((packed)); ++ ++struct nvme_self_test_log { ++ __u8 crnt_dev_selftest_oprn; ++ __u8 crnt_dev_selftest_compln; ++ __u8 rsvd[2]; ++ struct nvme_self_test_res result[20]; ++} __attribute__((packed)); ++ ++struct nvme_fw_slot_info_log { ++ __u8 afi; ++ __u8 rsvd1[7]; ++ __le64 frs[7]; ++ __u8 rsvd64[448]; ++}; ++ ++/* NVMe Namespace Write Protect State */ ++enum { ++ NVME_NS_NO_WRITE_PROTECT = 0, ++ NVME_NS_WRITE_PROTECT, ++ NVME_NS_WRITE_PROTECT_POWER_CYCLE, ++ NVME_NS_WRITE_PROTECT_PERMANENT, ++}; ++ ++#define NVME_MAX_CHANGED_NAMESPACES 1024 ++ ++struct nvme_changed_ns_list_log { ++ __le32 log[NVME_MAX_CHANGED_NAMESPACES]; ++}; ++ ++enum { ++ NVME_CMD_EFFECTS_CSUPP = 1 << 0, ++ NVME_CMD_EFFECTS_LBCC = 1 << 1, ++ NVME_CMD_EFFECTS_NCC = 1 << 2, ++ NVME_CMD_EFFECTS_NIC = 1 << 3, ++ NVME_CMD_EFFECTS_CCC = 1 << 4, ++ NVME_CMD_EFFECTS_CSE_MASK = 3 << 16, ++}; ++ ++struct nvme_effects_log { ++ __le32 acs[256]; ++ __le32 iocs[256]; ++ __u8 resv[2048]; ++}; ++ ++enum nvme_ana_state { ++ NVME_ANA_OPTIMIZED = 0x01, ++ NVME_ANA_NONOPTIMIZED = 0x02, ++ NVME_ANA_INACCESSIBLE = 0x03, ++ NVME_ANA_PERSISTENT_LOSS = 0x04, ++ NVME_ANA_CHANGE = 0x0f, ++}; ++ ++struct nvme_ana_group_desc { ++ __le32 grpid; ++ __le32 nnsids; ++ __le64 chgcnt; ++ __u8 state; ++ __u8 rsvd17[15]; ++ __le32 nsids[]; ++}; ++ ++/* flag for the log specific field of the ANA log */ ++#define NVME_ANA_LOG_RGO (1 << 0) ++ ++struct nvme_ana_rsp_hdr { ++ __le64 chgcnt; ++ __le16 ngrps; ++ __le16 rsvd10[3]; ++}; ++ ++enum { ++ NVME_SMART_CRIT_SPARE = 1 << 0, ++ NVME_SMART_CRIT_TEMPERATURE = 1 << 1, ++ NVME_SMART_CRIT_RELIABILITY = 1 << 2, ++ NVME_SMART_CRIT_MEDIA = 1 << 3, ++ NVME_SMART_CRIT_VOLATILE_MEMORY = 1 << 4, ++}; ++ ++enum { ++ NVME_AER_ERROR = 0, ++ NVME_AER_SMART = 1, ++ NVME_AER_CSS = 6, ++ NVME_AER_VS = 7, ++ NVME_AER_NOTICE_NS_CHANGED = 0x0002, ++ NVME_AER_NOTICE_ANA = 0x0003, ++ NVME_AER_NOTICE_FW_ACT_STARTING = 0x0102, ++}; ++ ++struct nvme_lba_range_type { ++ __u8 type; ++ __u8 attributes; ++ __u8 rsvd2[14]; ++ __u64 slba; ++ __u64 nlb; ++ __u8 guid[16]; ++ __u8 rsvd48[16]; ++}; ++ ++enum { ++ NVME_LBART_TYPE_FS = 0x01, ++ NVME_LBART_TYPE_RAID = 0x02, ++ NVME_LBART_TYPE_CACHE = 0x03, ++ NVME_LBART_TYPE_SWAP = 0x04, ++ ++ NVME_LBART_ATTRIB_TEMP = 1 << 0, ++ NVME_LBART_ATTRIB_HIDE = 1 << 1, ++}; ++ ++struct nvme_plm_config { ++ __u16 enable_event; ++ __u8 rsvd2[30]; ++ __u64 dtwin_reads_thresh; ++ __u64 dtwin_writes_thresh; ++ __u64 dtwin_time_thresh; ++ __u8 rsvd56[456]; ++}; ++ ++struct nvme_reservation_status { ++ __le32 gen; ++ __u8 rtype; ++ __u8 regctl[2]; ++ __u8 resv5[2]; ++ __u8 ptpls; ++ __u8 resv10[13]; ++ struct { ++ __le16 cntlid; ++ __u8 rcsts; ++ __u8 resv3[5]; ++ __le64 hostid; ++ __le64 rkey; ++ } regctl_ds[]; ++}; ++ ++struct nvme_reservation_status_ext { ++ __le32 gen; ++ __u8 rtype; ++ __u8 regctl[2]; ++ __u8 resv5[2]; ++ __u8 ptpls; ++ __u8 resv10[14]; ++ __u8 resv24[40]; ++ struct { ++ __le16 cntlid; ++ __u8 rcsts; ++ __u8 resv3[5]; ++ __le64 rkey; ++ __u8 hostid[16]; ++ __u8 resv32[32]; ++ } regctl_eds[]; ++}; ++ ++enum nvme_async_event_type { ++ NVME_AER_TYPE_ERROR = 0, ++ NVME_AER_TYPE_SMART = 1, ++ NVME_AER_TYPE_NOTICE = 2, ++}; ++ ++/* I/O commands */ ++ ++enum nvme_opcode { ++ nvme_cmd_flush = 0x00, ++ nvme_cmd_write = 0x01, ++ nvme_cmd_read = 0x02, ++ nvme_cmd_write_uncor = 0x04, ++ nvme_cmd_compare = 0x05, ++ nvme_cmd_write_zeroes = 0x08, ++ nvme_cmd_dsm = 0x09, ++ nvme_cmd_resv_register = 0x0d, ++ nvme_cmd_resv_report = 0x0e, ++ nvme_cmd_resv_acquire = 0x11, ++ nvme_cmd_resv_release = 0x15, ++}; ++ ++/* ++ * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier ++ * ++ * @NVME_SGL_FMT_ADDRESS: absolute address of the data block ++ * @NVME_SGL_FMT_OFFSET: relative offset of the in-capsule data block ++ * @NVME_SGL_FMT_TRANSPORT_A: transport defined format, value 0xA ++ * @NVME_SGL_FMT_INVALIDATE: RDMA transport specific remote invalidation ++ * request subtype ++ */ ++enum { ++ NVME_SGL_FMT_ADDRESS = 0x00, ++ NVME_SGL_FMT_OFFSET = 0x01, ++ NVME_SGL_FMT_TRANSPORT_A = 0x0A, ++ NVME_SGL_FMT_INVALIDATE = 0x0f, ++}; ++ ++/* ++ * Descriptor type - upper 4 bits of nvme_(keyed_)sgl_desc identifier ++ * ++ * For struct nvme_sgl_desc: ++ * @NVME_SGL_FMT_DATA_DESC: data block descriptor ++ * @NVME_SGL_FMT_SEG_DESC: sgl segment descriptor ++ * @NVME_SGL_FMT_LAST_SEG_DESC: last sgl segment descriptor ++ * ++ * For struct nvme_keyed_sgl_desc: ++ * @NVME_KEY_SGL_FMT_DATA_DESC: keyed data block descriptor ++ * ++ * Transport-specific SGL types: ++ * @NVME_TRANSPORT_SGL_DATA_DESC: Transport SGL data dlock descriptor ++ */ ++enum { ++ NVME_SGL_FMT_DATA_DESC = 0x00, ++ NVME_SGL_FMT_SEG_DESC = 0x02, ++ NVME_SGL_FMT_LAST_SEG_DESC = 0x03, ++ NVME_KEY_SGL_FMT_DATA_DESC = 0x04, ++ NVME_TRANSPORT_SGL_DATA_DESC = 0x05, ++}; ++ ++struct nvme_sgl_desc { ++ __le64 addr; ++ __le32 length; ++ __u8 rsvd[3]; ++ __u8 type; ++}; ++ ++struct nvme_keyed_sgl_desc { ++ __le64 addr; ++ __u8 length[3]; ++ __u8 key[4]; ++ __u8 type; ++}; ++ ++union nvme_data_ptr { ++ struct { ++ __le64 prp1; ++ __le64 prp2; ++ }; ++ struct nvme_sgl_desc sgl; ++ struct nvme_keyed_sgl_desc ksgl; ++}; ++ ++/* ++ * Lowest two bits of our flags field (FUSE field in the spec): ++ * ++ * @NVME_CMD_FUSE_FIRST: Fused Operation, first command ++ * @NVME_CMD_FUSE_SECOND: Fused Operation, second command ++ * ++ * Highest two bits in our flags field (PSDT field in the spec): ++ * ++ * @NVME_CMD_PSDT_SGL_METABUF: Use SGLS for this transfer, ++ * If used, MPTR contains addr of single physical buffer (byte aligned). ++ * @NVME_CMD_PSDT_SGL_METASEG: Use SGLS for this transfer, ++ * If used, MPTR contains an address of an SGL segment containing ++ * exactly 1 SGL descriptor (qword aligned). ++ */ ++enum { ++ NVME_CMD_FUSE_FIRST = (1 << 0), ++ NVME_CMD_FUSE_SECOND = (1 << 1), ++ ++ NVME_CMD_SGL_METABUF = (1 << 6), ++ NVME_CMD_SGL_METASEG = (1 << 7), ++ NVME_CMD_SGL_ALL = NVME_CMD_SGL_METABUF | NVME_CMD_SGL_METASEG, ++}; ++ ++struct nvme_common_command { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __le32 cdw2[2]; ++ __le64 metadata; ++ union nvme_data_ptr dptr; ++ __le32 cdw10[6]; ++}; ++ ++struct nvme_rw_command { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2; ++ __le64 metadata; ++ union nvme_data_ptr dptr; ++ __le64 slba; ++ __le16 length; ++ __le16 control; ++ __le32 dsmgmt; ++ __le32 reftag; ++ __le16 apptag; ++ __le16 appmask; ++}; ++ ++enum { ++ NVME_RW_LR = 1 << 15, ++ NVME_RW_FUA = 1 << 14, ++ NVME_RW_DEAC = 1 << 9, ++ NVME_RW_DSM_FREQ_UNSPEC = 0, ++ NVME_RW_DSM_FREQ_TYPICAL = 1, ++ NVME_RW_DSM_FREQ_RARE = 2, ++ NVME_RW_DSM_FREQ_READS = 3, ++ NVME_RW_DSM_FREQ_WRITES = 4, ++ NVME_RW_DSM_FREQ_RW = 5, ++ NVME_RW_DSM_FREQ_ONCE = 6, ++ NVME_RW_DSM_FREQ_PREFETCH = 7, ++ NVME_RW_DSM_FREQ_TEMP = 8, ++ NVME_RW_DSM_LATENCY_NONE = 0 << 4, ++ NVME_RW_DSM_LATENCY_IDLE = 1 << 4, ++ NVME_RW_DSM_LATENCY_NORM = 2 << 4, ++ NVME_RW_DSM_LATENCY_LOW = 3 << 4, ++ NVME_RW_DSM_SEQ_REQ = 1 << 6, ++ NVME_RW_DSM_COMPRESSED = 1 << 7, ++ NVME_RW_PRINFO_PRCHK_REF = 1 << 10, ++ NVME_RW_PRINFO_PRCHK_APP = 1 << 11, ++ NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12, ++ NVME_RW_PRINFO_PRACT = 1 << 13, ++ NVME_RW_DTYPE_STREAMS = 1 << 4, ++}; ++ ++struct nvme_dsm_cmd { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2[2]; ++ union nvme_data_ptr dptr; ++ __le32 nr; ++ __le32 attributes; ++ __u32 rsvd12[4]; ++}; ++ ++enum { ++ NVME_DSMGMT_IDR = 1 << 0, ++ NVME_DSMGMT_IDW = 1 << 1, ++ NVME_DSMGMT_AD = 1 << 2, ++}; ++ ++#define NVME_DSM_MAX_RANGES 256 ++ ++struct nvme_dsm_range { ++ __le32 cattr; ++ __le32 nlb; ++ __le64 slba; ++}; ++ ++struct nvme_write_zeroes_cmd { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2; ++ __le64 metadata; ++ union nvme_data_ptr dptr; ++ __le64 slba; ++ __le16 length; ++ __le16 control; ++ __le32 dsmgmt; ++ __le32 reftag; ++ __le16 apptag; ++ __le16 appmask; ++}; ++ ++/* Features */ ++ ++struct nvme_feat_auto_pst { ++ __le64 entries[32]; ++}; ++ ++enum { ++ NVME_HOST_MEM_ENABLE = (1 << 0), ++ NVME_HOST_MEM_RETURN = (1 << 1), ++}; ++ ++/* Admin commands */ ++ ++enum nvme_admin_opcode { ++ nvme_admin_delete_sq = 0x00, ++ nvme_admin_create_sq = 0x01, ++ nvme_admin_get_log_page = 0x02, ++ nvme_admin_delete_cq = 0x04, ++ nvme_admin_create_cq = 0x05, ++ nvme_admin_identify = 0x06, ++ nvme_admin_abort_cmd = 0x08, ++ nvme_admin_set_features = 0x09, ++ nvme_admin_get_features = 0x0a, ++ nvme_admin_async_event = 0x0c, ++ nvme_admin_ns_mgmt = 0x0d, ++ nvme_admin_activate_fw = 0x10, ++ nvme_admin_download_fw = 0x11, ++ nvme_admin_dev_self_test = 0x14, ++ nvme_admin_ns_attach = 0x15, ++ nvme_admin_keep_alive = 0x18, ++ nvme_admin_directive_send = 0x19, ++ nvme_admin_directive_recv = 0x1a, ++ nvme_admin_virtual_mgmt = 0x1c, ++ nvme_admin_nvme_mi_send = 0x1d, ++ nvme_admin_nvme_mi_recv = 0x1e, ++ nvme_admin_dbbuf = 0x7C, ++ nvme_admin_format_nvm = 0x80, ++ nvme_admin_security_send = 0x81, ++ nvme_admin_security_recv = 0x82, ++ nvme_admin_sanitize_nvm = 0x84, ++}; ++ ++enum { ++ NVME_QUEUE_PHYS_CONTIG = (1 << 0), ++ NVME_CQ_IRQ_ENABLED = (1 << 1), ++ NVME_SQ_PRIO_URGENT = (0 << 1), ++ NVME_SQ_PRIO_HIGH = (1 << 1), ++ NVME_SQ_PRIO_MEDIUM = (2 << 1), ++ NVME_SQ_PRIO_LOW = (3 << 1), ++ NVME_FEAT_ARBITRATION = 0x01, ++ NVME_FEAT_POWER_MGMT = 0x02, ++ NVME_FEAT_LBA_RANGE = 0x03, ++ NVME_FEAT_TEMP_THRESH = 0x04, ++ NVME_FEAT_ERR_RECOVERY = 0x05, ++ NVME_FEAT_VOLATILE_WC = 0x06, ++ NVME_FEAT_NUM_QUEUES = 0x07, ++ NVME_FEAT_IRQ_COALESCE = 0x08, ++ NVME_FEAT_IRQ_CONFIG = 0x09, ++ NVME_FEAT_WRITE_ATOMIC = 0x0a, ++ NVME_FEAT_ASYNC_EVENT = 0x0b, ++ NVME_FEAT_AUTO_PST = 0x0c, ++ NVME_FEAT_HOST_MEM_BUF = 0x0d, ++ NVME_FEAT_TIMESTAMP = 0x0e, ++ NVME_FEAT_KATO = 0x0f, ++ NVME_FEAT_HCTM = 0X10, ++ NVME_FEAT_NOPSC = 0X11, ++ NVME_FEAT_RRL = 0x12, ++ NVME_FEAT_PLM_CONFIG = 0x13, ++ NVME_FEAT_PLM_WINDOW = 0x14, ++ NVME_FEAT_SW_PROGRESS = 0x80, ++ NVME_FEAT_HOST_ID = 0x81, ++ NVME_FEAT_RESV_MASK = 0x82, ++ NVME_FEAT_RESV_PERSIST = 0x83, ++ NVME_FEAT_WRITE_PROTECT = 0x84, ++ NVME_LOG_ERROR = 0x01, ++ NVME_LOG_SMART = 0x02, ++ NVME_LOG_FW_SLOT = 0x03, ++ NVME_LOG_CHANGED_NS = 0x04, ++ NVME_LOG_CMD_EFFECTS = 0x05, ++ NVME_LOG_DEVICE_SELF_TEST = 0x06, ++ NVME_LOG_TELEMETRY_HOST = 0x07, ++ NVME_LOG_TELEMETRY_CTRL = 0x08, ++ NVME_LOG_ENDURANCE_GROUP = 0x09, ++ NVME_LOG_ANA = 0x0c, ++ NVME_LOG_DISC = 0x70, ++ NVME_LOG_RESERVATION = 0x80, ++ NVME_LOG_SANITIZE = 0x81, ++ NVME_FWACT_REPL = (0 << 3), ++ NVME_FWACT_REPL_ACTV = (1 << 3), ++ NVME_FWACT_ACTV = (2 << 3), ++}; ++ ++enum { ++ NVME_NO_LOG_LSP = 0x0, ++ NVME_NO_LOG_LPO = 0x0, ++ NVME_LOG_ANA_LSP_RGO = 0x1, ++ NVME_TELEM_LSP_CREATE = 0x1, ++}; ++ ++/* Sanitize and Sanitize Monitor/Log */ ++enum { ++ /* Sanitize */ ++ NVME_SANITIZE_NO_DEALLOC = 0x00000200, ++ NVME_SANITIZE_OIPBP = 0x00000100, ++ NVME_SANITIZE_OWPASS_SHIFT = 0x00000004, ++ NVME_SANITIZE_AUSE = 0x00000008, ++ NVME_SANITIZE_ACT_CRYPTO_ERASE = 0x00000004, ++ NVME_SANITIZE_ACT_OVERWRITE = 0x00000003, ++ NVME_SANITIZE_ACT_BLOCK_ERASE = 0x00000002, ++ NVME_SANITIZE_ACT_EXIT = 0x00000001, ++ ++ /* Sanitize Monitor/Log */ ++ NVME_SANITIZE_LOG_DATA_LEN = 0x0014, ++ NVME_SANITIZE_LOG_GLOBAL_DATA_ERASED = 0x0100, ++ NVME_SANITIZE_LOG_NUM_CMPLTED_PASS_MASK = 0x00F8, ++ NVME_SANITIZE_LOG_STATUS_MASK = 0x0007, ++ NVME_SANITIZE_LOG_NEVER_SANITIZED = 0x0000, ++ NVME_SANITIZE_LOG_COMPLETED_SUCCESS = 0x0001, ++ NVME_SANITIZE_LOG_IN_PROGESS = 0x0002, ++ NVME_SANITIZE_LOG_COMPLETED_FAILED = 0x0003, ++}; ++ ++enum { ++ /* Self-test log Validation bits */ ++ NVME_SELF_TEST_VALID_NSID = 1 << 0, ++ NVME_SELF_TEST_VALID_FLBA = 1 << 1, ++ NVME_SELF_TEST_VALID_SCT = 1 << 2, ++ NVME_SELF_TEST_VALID_SC = 1 << 3, ++ NVME_SELF_TEST_REPORTS = 20, ++}; ++ ++struct nvme_identify { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2[2]; ++ union nvme_data_ptr dptr; ++ __u8 cns; ++ __u8 rsvd3; ++ __le16 ctrlid; ++ __u32 rsvd11[5]; ++}; ++ ++#define NVME_IDENTIFY_DATA_SIZE 4096 ++ ++struct nvme_features { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2[2]; ++ union nvme_data_ptr dptr; ++ __le32 fid; ++ __le32 dword11; ++ __le32 dword12; ++ __le32 dword13; ++ __le32 dword14; ++ __le32 dword15; ++}; ++ ++struct nvme_host_mem_buf_desc { ++ __le64 addr; ++ __le32 size; ++ __u32 rsvd; ++}; ++ ++struct nvme_create_cq { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __u32 rsvd1[5]; ++ __le64 prp1; ++ __u64 rsvd8; ++ __le16 cqid; ++ __le16 qsize; ++ __le16 cq_flags; ++ __le16 irq_vector; ++ __u32 rsvd12[4]; ++}; ++ ++struct nvme_create_sq { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __u32 rsvd1[5]; ++ __le64 prp1; ++ __u64 rsvd8; ++ __le16 sqid; ++ __le16 qsize; ++ __le16 sq_flags; ++ __le16 cqid; ++ __u32 rsvd12[4]; ++}; ++ ++struct nvme_delete_queue { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __u32 rsvd1[9]; ++ __le16 qid; ++ __u16 rsvd10; ++ __u32 rsvd11[5]; ++}; ++ ++struct nvme_abort_cmd { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __u32 rsvd1[9]; ++ __le16 sqid; ++ __u16 cid; ++ __u32 rsvd11[5]; ++}; ++ ++struct nvme_download_firmware { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __u32 rsvd1[5]; ++ union nvme_data_ptr dptr; ++ __le32 numd; ++ __le32 offset; ++ __u32 rsvd12[4]; ++}; ++ ++struct nvme_format_cmd { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2[4]; ++ __le32 cdw10; ++ __u32 rsvd11[5]; ++}; ++ ++struct nvme_get_log_page_command { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2[2]; ++ union nvme_data_ptr dptr; ++ __u8 lid; ++ __u8 lsp; ++ __le16 numdl; ++ __le16 numdu; ++ __u16 rsvd11; ++ __le32 lpol; ++ __le32 lpou; ++ __u32 rsvd14[2]; ++}; ++ ++struct nvme_directive_cmd { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __le32 nsid; ++ __u64 rsvd2[2]; ++ union nvme_data_ptr dptr; ++ __le32 numd; ++ __u8 doper; ++ __u8 dtype; ++ __le16 dspec; ++ __u8 endir; ++ __u8 tdtype; ++ __u16 rsvd15; ++ ++ __u32 rsvd16[3]; ++}; ++ ++/* Sanitize Log Page */ ++struct nvme_sanitize_log_page { ++ __le16 progress; ++ __le16 status; ++ __le32 cdw10_info; ++ __le32 est_ovrwrt_time; ++ __le32 est_blk_erase_time; ++ __le32 est_crypto_erase_time; ++}; ++ ++/* ++ * Fabrics subcommands. ++ */ ++enum nvmf_fabrics_opcode { ++ nvme_fabrics_command = 0x7f, ++}; ++ ++enum nvmf_capsule_command { ++ nvme_fabrics_type_property_set = 0x00, ++ nvme_fabrics_type_connect = 0x01, ++ nvme_fabrics_type_property_get = 0x04, ++}; ++ ++struct nvmf_common_command { ++ __u8 opcode; ++ __u8 resv1; ++ __u16 command_id; ++ __u8 fctype; ++ __u8 resv2[35]; ++ __u8 ts[24]; ++}; ++ ++/* ++ * The legal cntlid range a NVMe Target will provide. ++ * Note that cntlid of value 0 is considered illegal in the fabrics world. ++ * Devices based on earlier specs did not have the subsystem concept; ++ * therefore, those devices had their cntlid value set to 0 as a result. ++ */ ++#define NVME_CNTLID_MIN 1 ++#define NVME_CNTLID_MAX 0xffef ++#define NVME_CNTLID_DYNAMIC 0xffff ++ ++#define MAX_DISC_LOGS 255 ++ ++/* Discovery log page entry */ ++struct nvmf_disc_rsp_page_entry { ++ __u8 trtype; ++ __u8 adrfam; ++ __u8 subtype; ++ __u8 treq; ++ __le16 portid; ++ __le16 cntlid; ++ __le16 asqsz; ++ __u8 resv8[22]; ++ char trsvcid[NVMF_TRSVCID_SIZE]; ++ __u8 resv64[192]; ++ char subnqn[NVMF_NQN_FIELD_LEN]; ++ char traddr[NVMF_TRADDR_SIZE]; ++ union tsas { ++ char common[NVMF_TSAS_SIZE]; ++ struct rdma { ++ __u8 qptype; ++ __u8 prtype; ++ __u8 cms; ++ __u8 resv3[5]; ++ __u16 pkey; ++ __u8 resv10[246]; ++ } rdma; ++ struct tcp { ++ __u8 sectype; ++ } tcp; ++ } tsas; ++}; ++ ++/* Discovery log page header */ ++struct nvmf_disc_rsp_page_hdr { ++ __le64 genctr; ++ __le64 numrec; ++ __le16 recfmt; ++ __u8 resv14[1006]; ++ struct nvmf_disc_rsp_page_entry entries[0]; ++}; ++ ++struct nvmf_connect_command { ++ __u8 opcode; ++ __u8 resv1; ++ __u16 command_id; ++ __u8 fctype; ++ __u8 resv2[19]; ++ union nvme_data_ptr dptr; ++ __le16 recfmt; ++ __le16 qid; ++ __le16 sqsize; ++ __u8 cattr; ++ __u8 resv3; ++ __le32 kato; ++ __u8 resv4[12]; ++}; ++ ++struct nvmf_connect_data { ++ uuid_t hostid; ++ __le16 cntlid; ++ char resv4[238]; ++ char subsysnqn[NVMF_NQN_FIELD_LEN]; ++ char hostnqn[NVMF_NQN_FIELD_LEN]; ++ char resv5[256]; ++}; ++ ++struct nvmf_property_set_command { ++ __u8 opcode; ++ __u8 resv1; ++ __u16 command_id; ++ __u8 fctype; ++ __u8 resv2[35]; ++ __u8 attrib; ++ __u8 resv3[3]; ++ __le32 offset; ++ __le64 value; ++ __u8 resv4[8]; ++}; ++ ++struct nvmf_property_get_command { ++ __u8 opcode; ++ __u8 resv1; ++ __u16 command_id; ++ __u8 fctype; ++ __u8 resv2[35]; ++ __u8 attrib; ++ __u8 resv3[3]; ++ __le32 offset; ++ __u8 resv4[16]; ++}; ++ ++struct nvme_dbbuf { ++ __u8 opcode; ++ __u8 flags; ++ __u16 command_id; ++ __u32 rsvd1[5]; ++ __le64 prp1; ++ __le64 prp2; ++ __u32 rsvd12[6]; ++}; ++ ++struct streams_directive_params { ++ __le16 msl; ++ __le16 nssa; ++ __le16 nsso; ++ __u8 rsvd[10]; ++ __le32 sws; ++ __le16 sgs; ++ __le16 nsa; ++ __le16 nso; ++ __u8 rsvd2[6]; ++}; ++ ++struct nvme_command { ++ union { ++ struct nvme_common_command common; ++ struct nvme_rw_command rw; ++ struct nvme_identify identify; ++ struct nvme_features features; ++ struct nvme_create_cq create_cq; ++ struct nvme_create_sq create_sq; ++ struct nvme_delete_queue delete_queue; ++ struct nvme_download_firmware dlfw; ++ struct nvme_format_cmd format; ++ struct nvme_dsm_cmd dsm; ++ struct nvme_write_zeroes_cmd write_zeroes; ++ struct nvme_abort_cmd abort; ++ struct nvme_get_log_page_command get_log_page; ++ struct nvmf_common_command fabrics; ++ struct nvmf_connect_command connect; ++ struct nvmf_property_set_command prop_set; ++ struct nvmf_property_get_command prop_get; ++ struct nvme_dbbuf dbbuf; ++ struct nvme_directive_cmd directive; ++ }; ++}; ++ ++static inline bool nvme_is_write(struct nvme_command *cmd) ++{ ++ /* ++ * What a mess... ++ * ++ * Why can't we simply have a Fabrics In and Fabrics out command? ++ */ ++ if (unlikely(cmd->common.opcode == nvme_fabrics_command)) ++ return cmd->fabrics.fctype & 1; ++ return cmd->common.opcode & 1; ++} ++ ++enum { ++ /* ++ * Generic Command Status: ++ */ ++ NVME_SC_SUCCESS = 0x0, ++ NVME_SC_INVALID_OPCODE = 0x1, ++ NVME_SC_INVALID_FIELD = 0x2, ++ NVME_SC_CMDID_CONFLICT = 0x3, ++ NVME_SC_DATA_XFER_ERROR = 0x4, ++ NVME_SC_POWER_LOSS = 0x5, ++ NVME_SC_INTERNAL = 0x6, ++ NVME_SC_ABORT_REQ = 0x7, ++ NVME_SC_ABORT_QUEUE = 0x8, ++ NVME_SC_FUSED_FAIL = 0x9, ++ NVME_SC_FUSED_MISSING = 0xa, ++ NVME_SC_INVALID_NS = 0xb, ++ NVME_SC_CMD_SEQ_ERROR = 0xc, ++ NVME_SC_SGL_INVALID_LAST = 0xd, ++ NVME_SC_SGL_INVALID_COUNT = 0xe, ++ NVME_SC_SGL_INVALID_DATA = 0xf, ++ NVME_SC_SGL_INVALID_METADATA = 0x10, ++ NVME_SC_SGL_INVALID_TYPE = 0x11, ++ ++ NVME_SC_SGL_INVALID_OFFSET = 0x16, ++ NVME_SC_SGL_INVALID_SUBTYPE = 0x17, ++ ++ NVME_SC_SANITIZE_FAILED = 0x1C, ++ NVME_SC_SANITIZE_IN_PROGRESS = 0x1D, ++ ++ NVME_SC_NS_WRITE_PROTECTED = 0x20, ++ ++ NVME_SC_LBA_RANGE = 0x80, ++ NVME_SC_CAP_EXCEEDED = 0x81, ++ NVME_SC_NS_NOT_READY = 0x82, ++ NVME_SC_RESERVATION_CONFLICT = 0x83, ++ ++ /* ++ * Command Specific Status: ++ */ ++ NVME_SC_CQ_INVALID = 0x100, ++ NVME_SC_QID_INVALID = 0x101, ++ NVME_SC_QUEUE_SIZE = 0x102, ++ NVME_SC_ABORT_LIMIT = 0x103, ++ NVME_SC_ABORT_MISSING = 0x104, ++ NVME_SC_ASYNC_LIMIT = 0x105, ++ NVME_SC_FIRMWARE_SLOT = 0x106, ++ NVME_SC_FIRMWARE_IMAGE = 0x107, ++ NVME_SC_INVALID_VECTOR = 0x108, ++ NVME_SC_INVALID_LOG_PAGE = 0x109, ++ NVME_SC_INVALID_FORMAT = 0x10a, ++ NVME_SC_FW_NEEDS_CONV_RESET = 0x10b, ++ NVME_SC_INVALID_QUEUE = 0x10c, ++ NVME_SC_FEATURE_NOT_SAVEABLE = 0x10d, ++ NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e, ++ NVME_SC_FEATURE_NOT_PER_NS = 0x10f, ++ NVME_SC_FW_NEEDS_SUBSYS_RESET = 0x110, ++ NVME_SC_FW_NEEDS_RESET = 0x111, ++ NVME_SC_FW_NEEDS_MAX_TIME = 0x112, ++ NVME_SC_FW_ACIVATE_PROHIBITED = 0x113, ++ NVME_SC_OVERLAPPING_RANGE = 0x114, ++ NVME_SC_NS_INSUFFICENT_CAP = 0x115, ++ NVME_SC_NS_ID_UNAVAILABLE = 0x116, ++ NVME_SC_NS_ALREADY_ATTACHED = 0x118, ++ NVME_SC_NS_IS_PRIVATE = 0x119, ++ NVME_SC_NS_NOT_ATTACHED = 0x11a, ++ NVME_SC_THIN_PROV_NOT_SUPP = 0x11b, ++ NVME_SC_CTRL_LIST_INVALID = 0x11c, ++ NVME_SC_BP_WRITE_PROHIBITED = 0x11e, ++ ++ /* ++ * I/O Command Set Specific - NVM commands: ++ */ ++ NVME_SC_BAD_ATTRIBUTES = 0x180, ++ NVME_SC_INVALID_PI = 0x181, ++ NVME_SC_READ_ONLY = 0x182, ++ NVME_SC_ONCS_NOT_SUPPORTED = 0x183, ++ ++ /* ++ * I/O Command Set Specific - Fabrics commands: ++ */ ++ NVME_SC_CONNECT_FORMAT = 0x180, ++ NVME_SC_CONNECT_CTRL_BUSY = 0x181, ++ NVME_SC_CONNECT_INVALID_PARAM = 0x182, ++ NVME_SC_CONNECT_RESTART_DISC = 0x183, ++ NVME_SC_CONNECT_INVALID_HOST = 0x184, ++ ++ NVME_SC_DISCOVERY_RESTART = 0x190, ++ NVME_SC_AUTH_REQUIRED = 0x191, ++ ++ /* ++ * Media and Data Integrity Errors: ++ */ ++ NVME_SC_WRITE_FAULT = 0x280, ++ NVME_SC_READ_ERROR = 0x281, ++ NVME_SC_GUARD_CHECK = 0x282, ++ NVME_SC_APPTAG_CHECK = 0x283, ++ NVME_SC_REFTAG_CHECK = 0x284, ++ NVME_SC_COMPARE_FAILED = 0x285, ++ NVME_SC_ACCESS_DENIED = 0x286, ++ NVME_SC_UNWRITTEN_BLOCK = 0x287, ++ ++ /* ++ * Path-related Errors: ++ */ ++ NVME_SC_ANA_PERSISTENT_LOSS = 0x301, ++ NVME_SC_ANA_INACCESSIBLE = 0x302, ++ NVME_SC_ANA_TRANSITION = 0x303, ++ ++ NVME_SC_DNR = 0x4000, ++}; ++ ++struct nvme_completion { ++ /* ++ * Used by Admin and Fabrics commands to return data: ++ */ ++ union nvme_result { ++ __le16 u16; ++ __le32 u32; ++ __le64 u64; ++ } result; ++ __le16 sq_head; /* how much of this queue may be reclaimed */ ++ __le16 sq_id; /* submission queue that generated this entry */ ++ __u16 command_id; /* of the command which completed */ ++ __le16 status; /* did the command fail, and if so, why? */ ++}; ++ ++#define NVME_VS(major, minor, tertiary) \ ++ (((major) << 16) | ((minor) << 8) | (tertiary)) ++ ++#define NVME_MAJOR(ver) ((ver) >> 16) ++#define NVME_MINOR(ver) (((ver) >> 8) & 0xff) ++#define NVME_TERTIARY(ver) ((ver) & 0xff) ++ ++#endif /* _LINUX_NVME_H */ +Index: multipath-tools-130222/libmultipath/nvme/linux/nvme_ioctl.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme/linux/nvme_ioctl.h +@@ -0,0 +1,67 @@ ++/* ++ * Definitions for the NVM Express ioctl interface ++ * Copyright (c) 2011-2014, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#ifndef _UAPI_LINUX_NVME_IOCTL_H ++#define _UAPI_LINUX_NVME_IOCTL_H ++ ++#include ++#include ++ ++struct nvme_user_io { ++ __u8 opcode; ++ __u8 flags; ++ __u16 control; ++ __u16 nblocks; ++ __u16 rsvd; ++ __u64 metadata; ++ __u64 addr; ++ __u64 slba; ++ __u32 dsmgmt; ++ __u32 reftag; ++ __u16 apptag; ++ __u16 appmask; ++}; ++ ++struct nvme_passthru_cmd { ++ __u8 opcode; ++ __u8 flags; ++ __u16 rsvd1; ++ __u32 nsid; ++ __u32 cdw2; ++ __u32 cdw3; ++ __u64 metadata; ++ __u64 addr; ++ __u32 metadata_len; ++ __u32 data_len; ++ __u32 cdw10; ++ __u32 cdw11; ++ __u32 cdw12; ++ __u32 cdw13; ++ __u32 cdw14; ++ __u32 cdw15; ++ __u32 timeout_ms; ++ __u32 result; ++}; ++ ++#define nvme_admin_cmd nvme_passthru_cmd ++ ++#define NVME_IOCTL_ID _IO('N', 0x40) ++#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd) ++#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io) ++#define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd) ++#define NVME_IOCTL_RESET _IO('N', 0x44) ++#define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) ++#define NVME_IOCTL_RESCAN _IO('N', 0x46) ++ ++#endif /* _UAPI_LINUX_NVME_IOCTL_H */ +Index: multipath-tools-130222/Makefile.inc +=================================================================== +--- multipath-tools-130222.orig/Makefile.inc ++++ multipath-tools-130222/Makefile.inc +@@ -37,6 +37,7 @@ mpathpersistdir = $(TOPDIR)/libmpathpers + includedir = $(prefix)/usr/include + mpathcmddir = $(TOPDIR)/libmpathcmd + libdmmpdir = $(TOPDIR)/libdmmp ++nvmedir = $(TOPDIR)/libmultipath/nvme + pkgconfdir = $(prefix)/usr/$(LIB)/pkgconfig + + GZIP = /bin/gzip -9 -c +Index: multipath-tools-130222/libmultipath/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/Makefile ++++ multipath-tools-130222/libmultipath/Makefile +@@ -8,7 +8,7 @@ SONAME=0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) + LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd -laio +-CFLAGS += -fPIC -I$(mpathcmddir) -I$(mpathpersistdir) ++CFLAGS += -fPIC -I$(mpathcmddir) -I$(mpathpersistdir) -I$(nvmedir) + + OBJS = memory.o parser.o vector.o devmapper.o \ + hwtable.o blacklist.o util.o dmparser.o config.o \ +@@ -17,7 +17,7 @@ OBJS = memory.o parser.o vector.o devmap + switchgroup.o uxsock.o print.o alias.o log_pthread.o \ + log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \ + lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \ +- io_err_stat.o ++ io_err_stat.o nvme-lib.o + + LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h) + +@@ -46,6 +46,9 @@ endif + + all: $(LIBS) + ++nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h ++ $(CC) $(CFLAGS) -Wno-unused-function -c -o $@ $< ++ + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS) + ln -sf $@ $(DEVLIB) +Index: multipath-tools-130222/libmultipath/nvme-ioctl.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme-ioctl.c +@@ -0,0 +1,869 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "nvme-ioctl.h" ++ ++static int nvme_verify_chr(int fd) ++{ ++ static struct stat nvme_stat; ++ int err = fstat(fd, &nvme_stat); ++ ++ if (err < 0) { ++ perror("fstat"); ++ return errno; ++ } ++ if (!S_ISCHR(nvme_stat.st_mode)) { ++ fprintf(stderr, ++ "Error: requesting reset on non-controller handle\n"); ++ return ENOTBLK; ++ } ++ return 0; ++} ++ ++static int nvme_subsystem_reset(int fd) ++{ ++ int ret; ++ ++ ret = nvme_verify_chr(fd); ++ if (ret) ++ return ret; ++ return ioctl(fd, NVME_IOCTL_SUBSYS_RESET); ++} ++ ++static int nvme_reset_controller(int fd) ++{ ++ int ret; ++ ++ ret = nvme_verify_chr(fd); ++ if (ret) ++ return ret; ++ return ioctl(fd, NVME_IOCTL_RESET); ++} ++ ++static int nvme_ns_rescan(int fd) ++{ ++ int ret; ++ ++ ret = nvme_verify_chr(fd); ++ if (ret) ++ return ret; ++ return ioctl(fd, NVME_IOCTL_RESCAN); ++} ++ ++static int nvme_get_nsid(int fd) ++{ ++ static struct stat nvme_stat; ++ int err = fstat(fd, &nvme_stat); ++ ++ if (err < 0) ++ return -errno; ++ ++ if (!S_ISBLK(nvme_stat.st_mode)) { ++ fprintf(stderr, ++ "Error: requesting namespace-id from non-block device\n"); ++ errno = ENOTBLK; ++ return -errno; ++ } ++ return ioctl(fd, NVME_IOCTL_ID); ++} ++ ++static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, ++ struct nvme_passthru_cmd *cmd) ++{ ++ return ioctl(fd, ioctl_cmd, cmd); ++} ++ ++static int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd) ++{ ++ return ioctl(fd, NVME_IOCTL_ADMIN_CMD, cmd); ++} ++ ++static int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd) ++{ ++ return ioctl(fd, NVME_IOCTL_IO_CMD, cmd); ++} ++ ++static int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, ++ __u8 flags, __u16 rsvd, ++ __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, ++ __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, ++ __u32 data_len, void *data, __u32 metadata_len, ++ void *metadata, __u32 timeout_ms, __u32 *result) ++{ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = opcode, ++ .flags = flags, ++ .rsvd1 = rsvd, ++ .nsid = nsid, ++ .cdw2 = cdw2, ++ .cdw3 = cdw3, ++ .metadata = (__u64)(uintptr_t) metadata, ++ .addr = (__u64)(uintptr_t) data, ++ .metadata_len = metadata_len, ++ .data_len = data_len, ++ .cdw10 = cdw10, ++ .cdw11 = cdw11, ++ .cdw12 = cdw12, ++ .cdw13 = cdw13, ++ .cdw14 = cdw14, ++ .cdw15 = cdw15, ++ .timeout_ms = timeout_ms, ++ .result = 0, ++ }; ++ int err; ++ ++ err = nvme_submit_passthru(fd, ioctl_cmd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control, ++ __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data, ++ void *metadata) ++{ ++ struct nvme_user_io io = { ++ .opcode = opcode, ++ .flags = 0, ++ .control = control, ++ .nblocks = nblocks, ++ .rsvd = 0, ++ .metadata = (__u64)(uintptr_t) metadata, ++ .addr = (__u64)(uintptr_t) data, ++ .slba = slba, ++ .dsmgmt = dsmgmt, ++ .reftag = reftag, ++ .appmask = appmask, ++ .apptag = apptag, ++ }; ++ return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io); ++} ++ ++static int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt, ++ __u32 reftag, __u16 apptag, __u16 appmask, void *data, ++ void *metadata) ++{ ++ return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt, ++ reftag, apptag, appmask, data, metadata); ++} ++ ++static int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt, ++ __u32 reftag, __u16 apptag, __u16 appmask, void *data, ++ void *metadata) ++{ ++ return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt, ++ reftag, apptag, appmask, data, metadata); ++} ++ ++static int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt, ++ __u32 reftag, __u16 apptag, __u16 appmask, void *data, ++ void *metadata) ++{ ++ return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt, ++ reftag, apptag, appmask, data, metadata); ++} ++ ++static int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd, ++ __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, ++ __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, ++ __u32 cdw15, __u32 data_len, void *data, ++ __u32 metadata_len, void *metadata, __u32 timeout_ms) ++{ ++ return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid, ++ cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, ++ cdw15, data_len, data, metadata_len, metadata, ++ timeout_ms, NULL); ++} ++ ++static int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb, ++ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask) ++{ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_write_zeroes, ++ .nsid = nsid, ++ .cdw10 = slba & 0xffffffff, ++ .cdw11 = slba >> 32, ++ .cdw12 = nlb | (control << 16), ++ .cdw14 = reftag, ++ .cdw15 = apptag | (appmask << 16), ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb) ++{ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_write_uncor, ++ .nsid = nsid, ++ .cdw10 = slba & 0xffffffff, ++ .cdw11 = slba >> 32, ++ .cdw12 = nlb, ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_flush(int fd, __u32 nsid) ++{ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_flush, ++ .nsid = nsid, ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm, ++ __u16 nr_ranges) ++{ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_dsm, ++ .nsid = nsid, ++ .addr = (__u64)(uintptr_t) dsm, ++ .data_len = nr_ranges * sizeof(*dsm), ++ .cdw10 = nr_ranges - 1, ++ .cdw11 = cdw11, ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas, ++ __u64 *slbas, __u16 nr_ranges) ++{ ++ int i; ++ struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm)); ++ ++ if (!dsm) { ++ fprintf(stderr, "malloc: %s\n", strerror(errno)); ++ return NULL; ++ } ++ for (i = 0; i < nr_ranges; i++) { ++ dsm[i].cattr = cpu_to_le32(ctx_attrs[i]); ++ dsm[i].nlb = cpu_to_le32(llbas[i]); ++ dsm[i].slba = cpu_to_le64(slbas[i]); ++ } ++ return dsm; ++} ++ ++static int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa, ++ bool iekey, __u64 crkey, __u64 nrkey) ++{ ++ __le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) }; ++ __u32 cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8; ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_resv_acquire, ++ .nsid = nsid, ++ .cdw10 = cdw10, ++ .addr = (__u64)(uintptr_t) (payload), ++ .data_len = sizeof(payload), ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl, ++ bool iekey, __u64 crkey, __u64 nrkey) ++{ ++ __le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) }; ++ __u32 cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | cptpl << 30; ++ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_resv_register, ++ .nsid = nsid, ++ .cdw10 = cdw10, ++ .addr = (__u64)(uintptr_t) (payload), ++ .data_len = sizeof(payload), ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela, ++ bool iekey, __u64 crkey) ++{ ++ __le64 payload[1] = { cpu_to_le64(crkey) }; ++ __u32 cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8; ++ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_resv_release, ++ .nsid = nsid, ++ .cdw10 = cdw10, ++ .addr = (__u64)(uintptr_t) (payload), ++ .data_len = sizeof(payload), ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data) ++{ ++ struct nvme_passthru_cmd cmd = { ++ .opcode = nvme_cmd_resv_report, ++ .nsid = nsid, ++ .cdw10 = numd, ++ .cdw11 = cdw11, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = (numd + 1) << 2, ++ }; ++ ++ return nvme_submit_io_passthru(fd, &cmd); ++} ++ ++static int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_identify, ++ .nsid = nsid, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = NVME_IDENTIFY_DATA_SIZE, ++ .cdw10 = cdw10, ++ .cdw11 = cdw11, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data) ++{ ++ return nvme_identify13(fd, nsid, cdw10, 0, data); ++} ++ ++static int nvme_identify_ctrl(int fd, void *data) ++{ ++ return nvme_identify(fd, 0, 1, data); ++} ++ ++static int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data) ++{ ++ int cns = present ? NVME_ID_CNS_NS_PRESENT : NVME_ID_CNS_NS; ++ ++ return nvme_identify(fd, nsid, cns, data); ++} ++ ++static int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data) ++{ ++ int cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST; ++ ++ return nvme_identify(fd, nsid, cns, data); ++} ++ ++static int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data) ++{ ++ int cns = nsid ? NVME_ID_CNS_CTRL_NS_LIST : NVME_ID_CNS_CTRL_LIST; ++ ++ return nvme_identify(fd, nsid, (cntid << 16) | cns, data); ++} ++ ++static int nvme_identify_ns_descs(int fd, __u32 nsid, void *data) ++{ ++ ++ return nvme_identify(fd, nsid, NVME_ID_CNS_NS_DESC_LIST, data); ++} ++ ++static int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data) ++{ ++ return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data); ++} ++ ++static int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, ++ __u16 lsi, bool rae, __u32 data_len, void *data) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_get_log_page, ++ .nsid = nsid, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ }; ++ __u32 numd = (data_len >> 2) - 1; ++ __u16 numdu = numd >> 16, numdl = numd & 0xffff; ++ ++ cmd.cdw10 = log_id | (numdl << 16) | (rae ? 1 << 15 : 0); ++ if (lsp) ++ cmd.cdw10 |= lsp << 8; ++ ++ cmd.cdw11 = numdu | (lsi << 16); ++ cmd.cdw12 = lpo; ++ cmd.cdw13 = (lpo >> 32); ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++ ++} ++ ++static int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae, ++ __u32 data_len, void *data) ++{ ++ void *ptr = data; ++ __u32 offset = 0, xfer_len = data_len; ++ int ret; ++ ++ /* ++ * 4k is the smallest possible transfer unit, so by ++ * restricting ourselves for 4k transfers we avoid having ++ * to check the MDTS value of the controller. ++ */ ++ do { ++ xfer_len = data_len - offset; ++ if (xfer_len > 4096) ++ xfer_len = 4096; ++ ++ ret = nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP, ++ offset, 0, rae, xfer_len, ptr); ++ if (ret) ++ return ret; ++ ++ offset += xfer_len; ++ ptr += xfer_len; ++ } while (offset < data_len); ++ ++ return 0; ++} ++ ++static int nvme_get_telemetry_log(int fd, void *lp, int generate_report, ++ int ctrl_init, size_t log_page_size, __u64 offset) ++{ ++ if (ctrl_init) ++ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_CTRL, ++ NVME_NO_LOG_LSP, offset, ++ 0, 1, log_page_size, lp); ++ if (generate_report) ++ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST, ++ NVME_TELEM_LSP_CREATE, offset, ++ 0, 1, log_page_size, lp); ++ else ++ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST, ++ NVME_NO_LOG_LSP, offset, ++ 0, 1, log_page_size, lp); ++} ++ ++static int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log) ++{ ++ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT, true, ++ sizeof(*fw_log), fw_log); ++} ++ ++static int nvme_changed_ns_list_log(int fd, struct nvme_changed_ns_list_log *changed_ns_list_log) ++{ ++ return nvme_get_log(fd, 0, NVME_LOG_CHANGED_NS, true, ++ sizeof(changed_ns_list_log->log), ++ changed_ns_list_log->log); ++} ++ ++static int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log) ++{ ++ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_ERROR, false, ++ entries * sizeof(*err_log), err_log); ++} ++ ++static int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log) ++{ ++ return nvme_get_log13(fd, 0, NVME_LOG_ENDURANCE_GROUP, 0, 0, group_id, 0, ++ sizeof(*endurance_log), endurance_log); ++} ++ ++static int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log) ++{ ++ return nvme_get_log(fd, nsid, NVME_LOG_SMART, false, ++ sizeof(*smart_log), smart_log); ++} ++ ++static int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo) ++{ ++ __u64 lpo = 0; ++ ++ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_ANA, rgo, lpo, 0, ++ true, ana_log_len, ana_log); ++} ++ ++static int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log) ++{ ++ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_DEVICE_SELF_TEST, false, ++ sizeof(*self_test_log), self_test_log); ++} ++ ++static int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log) ++{ ++ return nvme_get_log(fd, 0, NVME_LOG_CMD_EFFECTS, false, ++ sizeof(*effects_log), effects_log); ++} ++ ++static int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size) ++{ ++ return nvme_get_log(fd, 0, NVME_LOG_DISC, false, size, log); ++} ++ ++static int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log) ++{ ++ return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, false, ++ sizeof(*sanitize_log), sanitize_log); ++} ++ ++static int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11, ++ __u32 cdw12, __u32 data_len, void *data, __u32 *result) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = opcode, ++ .nsid = nsid, ++ .cdw10 = cdw10, ++ .cdw11 = cdw11, ++ .cdw12 = cdw12, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ }; ++ int err; ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12, ++ bool save, __u32 data_len, void *data, __u32 *result) ++{ ++ __u32 cdw10 = fid | (save ? 0x80000000 : 0); ++ ++ return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value, ++ cdw12, data_len, data, result); ++} ++ ++static int nvme_property(int fd, __u8 fctype, __le32 off, __le64 *value, __u8 attrib) ++{ ++ int err; ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_fabrics_command, ++ .cdw10 = attrib, ++ .cdw11 = off, ++ }; ++ ++ if (!value) { ++ errno = EINVAL; ++ return -errno; ++ } ++ ++ if (fctype == nvme_fabrics_type_property_get){ ++ cmd.nsid = nvme_fabrics_type_property_get; ++ } else if(fctype == nvme_fabrics_type_property_set) { ++ cmd.nsid = nvme_fabrics_type_property_set; ++ cmd.cdw12 = *value; ++ } else { ++ errno = EINVAL; ++ return -errno; ++ } ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && fctype == nvme_fabrics_type_property_get) ++ *value = cpu_to_le64(cmd.result); ++ return err; ++} ++ ++static int get_property_helper(int fd, int offset, void *value, int *advance) ++{ ++ __le64 value64; ++ int err = -EINVAL; ++ ++ switch (offset) { ++ case NVME_REG_CAP: ++ case NVME_REG_ASQ: ++ case NVME_REG_ACQ: ++ *advance = 8; ++ break; ++ default: ++ *advance = 4; ++ } ++ ++ if (!value) ++ return err; ++ ++ err = nvme_property(fd, nvme_fabrics_type_property_get, ++ cpu_to_le32(offset), &value64, (*advance == 8)); ++ ++ if (!err) { ++ if (*advance == 8) ++ *((uint64_t *)value) = le64_to_cpu(value64); ++ else ++ *((uint32_t *)value) = le32_to_cpu(value64); ++ } ++ ++ return err; ++} ++ ++static int nvme_get_property(int fd, int offset, uint64_t *value) ++{ ++ int advance; ++ return get_property_helper(fd, offset, value, &advance); ++} ++ ++static int nvme_get_properties(int fd, void **pbar) ++{ ++ int offset, advance; ++ int err, ret = -EINVAL; ++ int size = getpagesize(); ++ ++ *pbar = malloc(size); ++ if (!*pbar) { ++ fprintf(stderr, "malloc: %s\n", strerror(errno)); ++ return -ENOMEM; ++ } ++ ++ memset(*pbar, 0xff, size); ++ for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ; offset += advance) { ++ err = get_property_helper(fd, offset, *pbar + offset, &advance); ++ if (!err) ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static int nvme_set_property(int fd, int offset, int value) ++{ ++ __le64 val = cpu_to_le64(value); ++ __le32 off = cpu_to_le32(offset); ++ bool is64bit; ++ ++ switch (off) { ++ case NVME_REG_CAP: ++ case NVME_REG_ASQ: ++ case NVME_REG_ACQ: ++ is64bit = true; ++ break; ++ default: ++ is64bit = false; ++ } ++ ++ return nvme_property(fd, nvme_fabrics_type_property_set, ++ off, &val, is64bit ? 1: 0); ++} ++ ++static int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11, ++ __u32 data_len, void *data, __u32 *result) ++{ ++ __u32 cdw10 = fid | sel << 8; ++ ++ return nvme_feature(fd, nvme_admin_get_features, nsid, cdw10, cdw11, ++ 0, data_len, data, result); ++} ++ ++static int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi, ++ __u8 pil, __u8 ms, __u32 timeout) ++{ ++ __u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9; ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_format_nvm, ++ .nsid = nsid, ++ .cdw10 = cdw10, ++ .timeout_ms = timeout, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, ++ __u8 dps, __u8 nmic, __u32 *result) ++{ ++ struct nvme_id_ns ns = { ++ .nsze = cpu_to_le64(nsze), ++ .ncap = cpu_to_le64(ncap), ++ .flbas = flbas, ++ .dps = dps, ++ .nmic = nmic, ++ }; ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_ns_mgmt, ++ .addr = (__u64)(uintptr_t) ((void *)&ns), ++ .cdw10 = 0, ++ .data_len = 0x1000, ++ }; ++ int err; ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_ns_delete(int fd, __u32 nsid) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_ns_mgmt, ++ .nsid = nsid, ++ .cdw10 = 1, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist, ++ bool attach) ++{ ++ int i; ++ __u8 buf[0x1000]; ++ struct nvme_controller_list *cntlist = ++ (struct nvme_controller_list *)buf; ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_ns_attach, ++ .nsid = nsid, ++ .addr = (__u64)(uintptr_t) cntlist, ++ .cdw10 = attach ? 0 : 1, ++ .data_len = 0x1000, ++ }; ++ ++ memset(buf, 0, sizeof(buf)); ++ cntlist->num = cpu_to_le16(num_ctrls); ++ for (i = 0; i < num_ctrls; i++) ++ cntlist->identifier[i] = cpu_to_le16(ctrlist[i]); ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist) ++{ ++ return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, true); ++} ++ ++static int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist) ++{ ++ return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, false); ++} ++ ++static int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_download_fw, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ .cdw10 = (data_len >> 2) - 1, ++ .cdw11 = offset >> 2, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_activate_fw, ++ .cdw10 = (bpid << 31) | (action << 3) | slot, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp, ++ __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_security_send, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ .nsid = nsid, ++ .cdw10 = secp << 24 | spsp << 8 | nssf, ++ .cdw11 = tl, ++ }; ++ int err; ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp, ++ __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_security_recv, ++ .nsid = nsid, ++ .cdw10 = secp << 24 | spsp << 8 | nssf, ++ .cdw11 = al, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ }; ++ int err; ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, ++ __u32 data_len, __u32 dw12, void *data, __u32 *result) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_directive_send, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ .nsid = nsid, ++ .cdw10 = data_len? (data_len >> 2) - 1 : 0, ++ .cdw11 = dspec << 16 | dtype << 8 | doper, ++ .cdw12 = dw12, ++ }; ++ int err; ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, ++ __u32 data_len, __u32 dw12, void *data, __u32 *result) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_directive_recv, ++ .addr = (__u64)(uintptr_t) data, ++ .data_len = data_len, ++ .nsid = nsid, ++ .cdw10 = data_len? (data_len >> 2) - 1 : 0, ++ .cdw11 = dspec << 16 | dtype << 8 | doper, ++ .cdw12 = dw12, ++ }; ++ int err; ++ ++ err = nvme_submit_admin_passthru(fd, &cmd); ++ if (!err && result) ++ *result = cmd.result; ++ return err; ++} ++ ++static int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp, ++ __u8 no_dealloc, __u32 ovrpat) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_sanitize_nvm, ++ .cdw10 = no_dealloc << 9 | oipbp << 8 | ++ owpass << NVME_SANITIZE_OWPASS_SHIFT | ++ ause << 3 | sanact, ++ .cdw11 = ovrpat, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} ++ ++static int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10) ++{ ++ struct nvme_admin_cmd cmd = { ++ .opcode = nvme_admin_dev_self_test, ++ .nsid = nsid, ++ .cdw10 = cdw10, ++ }; ++ ++ return nvme_submit_admin_passthru(fd, &cmd); ++} +Index: multipath-tools-130222/libmultipath/nvme-ioctl.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme-ioctl.h +@@ -0,0 +1,139 @@ ++#ifndef _NVME_LIB_H ++#define _NVME_LIB_H ++ ++#include ++#include ++#include "linux/nvme_ioctl.h" ++#include "nvme.h" ++ ++static int nvme_get_nsid(int fd); ++ ++/* Generic passthrough */ ++static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, ++ struct nvme_passthru_cmd *cmd); ++ ++static int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, __u8 flags, ++ __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, ++ __u32 cdw10, __u32 cdw11, __u32 cdw12, ++ __u32 cdw13, __u32 cdw14, __u32 cdw15, ++ __u32 data_len, void *data, __u32 metadata_len, ++ void *metadata, __u32 timeout_ms, __u32 *result); ++ ++/* NVME_SUBMIT_IO */ ++static int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control, ++ __u32 dsmgmt, __u32 reftag, __u16 apptag, ++ __u16 appmask, void *data, void *metadata); ++ ++static int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, ++ __u32 dsmgmt, __u32 reftag, __u16 apptag, ++ __u16 appmask, void *data, void *metadata); ++ ++static int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, ++ __u32 dsmgmt, __u32 reftag, __u16 apptag, ++ __u16 appmask, void *data, void *metadata); ++ ++static int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, ++ __u32 dsmgmt, __u32 reftag, __u16 apptag, ++ __u16 appmask, void *data, void *metadata); ++ ++/* NVME_IO_CMD */ ++static int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd, ++ __u32 nsid, __u32 cdw2, __u32 cdw3, ++ __u32 cdw10, __u32 cdw11, __u32 cdw12, ++ __u32 cdw13, __u32 cdw14, __u32 cdw15, ++ __u32 data_len, void *data, __u32 metadata_len, ++ void *metadata, __u32 timeout); ++ ++static int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb, ++ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask); ++ ++static int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb); ++ ++static int nvme_flush(int fd, __u32 nsid); ++ ++static int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm, ++ __u16 nr_ranges); ++static struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, ++ __u32 *llbas, __u64 *slbas, ++ __u16 nr_ranges); ++ ++static int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa, ++ bool iekey, __u64 crkey, __u64 nrkey); ++static int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl, ++ bool iekey, __u64 crkey, __u64 nrkey); ++static int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela, ++ bool iekey, __u64 crkey); ++static int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data); ++ ++static int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data); ++static int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data); ++static int nvme_identify_ctrl(int fd, void *data); ++static int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data); ++static int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data); ++static int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data); ++static int nvme_identify_ns_descs(int fd, __u32 nsid, void *data); ++static int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data); ++static int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, ++ __u16 group_id, bool rae, __u32 data_len, void *data); ++static int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae, ++ __u32 data_len, void *data); ++ ++ ++static int nvme_get_telemetry_log(int fd, void *lp, int generate_report, ++ int ctrl_gen, size_t log_page_size, __u64 offset); ++static int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log); ++static int nvme_changed_ns_list_log(int fd, ++ struct nvme_changed_ns_list_log *changed_ns_list_log); ++static int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log); ++static int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log); ++static int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo); ++static int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log); ++static int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size); ++static int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log); ++static int nvme_endurance_log(int fd, __u16 group_id, ++ struct nvme_endurance_group_log *endurance_log); ++ ++static int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, ++ __u32 cdw11, __u32 cdw12, __u32 data_len, void *data, ++ __u32 *result); ++static int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12, ++ bool save, __u32 data_len, void *data, __u32 *result); ++static int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, ++ __u32 cdw11, __u32 data_len, void *data, __u32 *result); ++ ++static int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi, ++ __u8 pil, __u8 ms, __u32 timeout); ++ ++static int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, ++ __u8 dps, __u8 nmic, __u32 *result); ++static int nvme_ns_delete(int fd, __u32 nsid); ++ ++static int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, ++ __u16 *ctrlist, bool attach); ++static int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist); ++static int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist); ++ ++static int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data); ++static int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid); ++ ++static int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp, ++ __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result); ++static int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp, ++ __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result); ++ ++static int nvme_subsystem_reset(int fd); ++static int nvme_reset_controller(int fd); ++static int nvme_ns_rescan(int fd); ++ ++static int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, ++ __u32 data_len, __u32 dw12, void *data, __u32 *result); ++static int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, ++ __u32 data_len, __u32 dw12, void *data, __u32 *result); ++static int nvme_get_properties(int fd, void **pbar); ++static int nvme_set_property(int fd, int offset, int value); ++static int nvme_get_property(int fd, int offset, uint64_t *value); ++static int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp, ++ __u8 no_dealloc, __u32 ovrpat); ++static int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10); ++static int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log); ++#endif /* _NVME_LIB_H */ +Index: multipath-tools-130222/libmultipath/nvme-lib.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme-lib.c +@@ -0,0 +1,49 @@ ++#include ++/* avoid inclusion of standard API */ ++#define _NVME_LIB_C 1 ++#include "nvme-lib.h" ++#include "nvme-ioctl.c" ++#include "debug.h" ++ ++int log_nvme_errcode(int err, const char *dev, const char *msg) ++{ ++ if (err > 0) ++ condlog(3, "%s: %s: NVMe status %d", dev, msg, err); ++ else if (err < 0) ++ condlog(3, "%s: %s: %s", dev, msg, strerror(errno)); ++ return err; ++} ++ ++int libmp_nvme_get_nsid(int fd) ++{ ++ return nvme_get_nsid(fd); ++} ++ ++int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl) ++{ ++ return nvme_identify_ctrl(fd, ctrl); ++} ++ ++int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present, ++ struct nvme_id_ns *ns) ++{ ++ return nvme_identify_ns(fd, nsid, present, ns); ++} ++ ++int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo) ++{ ++ return nvme_ana_log(fd, ana_log, ana_log_len, rgo); ++} ++ ++int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl) ++{ ++ int rc; ++ struct nvme_id_ctrl c; ++ ++ rc = nvme_identify_ctrl(fd, &c); ++ if (rc < 0) ++ return rc; ++ if (ctrl) ++ *ctrl = c; ++ return c.cmic & (1 << 3) ? 1 : 0; ++} +Index: multipath-tools-130222/libmultipath/nvme-lib.h +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/nvme-lib.h +@@ -0,0 +1,39 @@ ++#ifndef NVME_LIB_H ++#define NVME_LIB_H ++ ++#include "nvme.h" ++ ++int log_nvme_errcode(int err, const char *dev, const char *msg); ++int libmp_nvme_get_nsid(int fd); ++int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl); ++int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present, ++ struct nvme_id_ns *ns); ++int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo); ++/* ++ * Identify controller, and return true if ANA is supported ++ * ctrl will be filled in if controller is identified, even w/o ANA ++ * ctrl may be NULL ++ */ ++int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl); ++ ++#ifndef _NVME_LIB_C ++/* ++ * In all files except nvme-lib.c, the nvme functions can be called ++ * by their usual name. ++ */ ++#define nvme_get_nsid libmp_nvme_get_nsid ++#define nvme_identify_ctrl libmp_nvme_identify_ctrl ++#define nvme_identify_ns libmp_nvme_identify_ns ++#define nvme_ana_log libmp_nvme_ana_log ++/* ++ * Undefine these to avoid clashes with libmultipath's byteorder.h ++ */ ++#undef cpu_to_le16 ++#undef cpu_to_le32 ++#undef cpu_to_le64 ++#undef le16_to_cpu ++#undef le32_to_cpu ++#undef le64_to_cpu ++#endif ++ ++#endif /* NVME_LIB_H */ +Index: multipath-tools-130222/libmultipath/prio.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prio.h ++++ multipath-tools-130222/libmultipath/prio.h +@@ -29,6 +29,7 @@ struct path; + #define PRIO_RDAC "rdac" + #define PRIO_DATACORE "datacore" + #define PRIO_WEIGHTED_PATH "weightedpath" ++#define PRIO_ANA "ana" + + /* + * Value used to mark the fact prio was not defined +Index: multipath-tools-130222/libmultipath/prioritizers/Makefile +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/Makefile ++++ multipath-tools-130222/libmultipath/prioritizers/Makefile +@@ -2,6 +2,7 @@ + # + # Copyright (C) 2007 Christophe Varoqui, + # ++TOPDIR = ../.. + include ../../Makefile.inc + + LIBS = \ +@@ -15,9 +16,10 @@ LIBS = \ + libpriodatacore.so \ + libpriohds.so \ + libprioweightedpath.so \ ++ libprioana.so \ + libprioiet.so + +-CFLAGS += -fPIC -I.. ++CFLAGS += -fPIC -I.. -I$(nvmedir) + + all: $(LIBS) + +Index: multipath-tools-130222/libmultipath/prioritizers/ana.c +=================================================================== +--- /dev/null ++++ multipath-tools-130222/libmultipath/prioritizers/ana.c +@@ -0,0 +1,236 @@ ++/* ++ * (C) Copyright HUAWEI Technology Corp. 2017 All Rights Reserved. ++ * ++ * ana.c ++ * Version 1.00 ++ * ++ * Tool to make use of a NVMe-feature called Asymmetric Namespace Access. ++ * It determines the ANA state of a device and prints a priority value to stdout. ++ * ++ * Author(s): Cheng Jike ++ * Li Jie ++ * ++ * This file is released under the GPL version 2, or any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "debug.h" ++#include "nvme-lib.h" ++#include "prio.h" ++#include "util.h" ++#include "structs.h" ++#include "def_func.h" ++ ++enum { ++ ANA_ERR_GETCTRL_FAILED = 1, ++ ANA_ERR_NOT_NVME, ++ ANA_ERR_NOT_SUPPORTED, ++ ANA_ERR_GETANAS_OVERFLOW, ++ ANA_ERR_GETANAS_NOTFOUND, ++ ANA_ERR_GETANALOG_FAILED, ++ ANA_ERR_GETNSID_FAILED, ++ ANA_ERR_GETNS_FAILED, ++ ANA_ERR_NO_MEMORY, ++ ANA_ERR_NO_INFORMATION, ++}; ++ ++static const char *ana_errmsg[] = { ++ [ANA_ERR_GETCTRL_FAILED] = "couldn't get ctrl info", ++ [ANA_ERR_NOT_NVME] = "not an NVMe device", ++ [ANA_ERR_NOT_SUPPORTED] = "ANA not supported", ++ [ANA_ERR_GETANAS_OVERFLOW] = "buffer overflow in ANA log", ++ [ANA_ERR_GETANAS_NOTFOUND] = "NSID or ANAGRPID not found", ++ [ANA_ERR_GETANALOG_FAILED] = "couldn't get ana log", ++ [ANA_ERR_GETNSID_FAILED] = "couldn't get NSID", ++ [ANA_ERR_GETNS_FAILED] = "couldn't get namespace info", ++ [ANA_ERR_NO_MEMORY] = "out of memory", ++ [ANA_ERR_NO_INFORMATION] = "invalid fd", ++}; ++ ++static const char *anas_string[] = { ++ [NVME_ANA_OPTIMIZED] = "ANA Optimized State", ++ [NVME_ANA_NONOPTIMIZED] = "ANA Non-Optimized State", ++ [NVME_ANA_INACCESSIBLE] = "ANA Inaccessible State", ++ [NVME_ANA_PERSISTENT_LOSS] = "ANA Persistent Loss State", ++ [NVME_ANA_CHANGE] = "ANA Change state", ++}; ++ ++static const char *aas_print_string(int rc) ++{ ++ rc &= 0xff; ++ if (rc >= 0 && rc < ARRAY_SIZE(anas_string) && ++ anas_string[rc] != NULL) ++ return anas_string[rc]; ++ ++ return "invalid ANA state"; ++} ++ ++static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log, ++ size_t ana_log_len) ++{ ++ void *base = ana_log; ++ struct nvme_ana_rsp_hdr *hdr = base; ++ struct nvme_ana_group_desc *ana_desc; ++ size_t offset = sizeof(struct nvme_ana_rsp_hdr); ++ __u32 nr_nsids; ++ size_t nsid_buf_size; ++ int i, j; ++ ++ for (i = 0; i < le16_to_cpu(hdr->ngrps); i++) { ++ ana_desc = base + offset; ++ ++ offset += sizeof(*ana_desc); ++ if (offset > ana_log_len) ++ return -ANA_ERR_GETANAS_OVERFLOW; ++ ++ nr_nsids = le32_to_cpu(ana_desc->nnsids); ++ nsid_buf_size = nr_nsids * sizeof(__le32); ++ ++ offset += nsid_buf_size; ++ if (offset > ana_log_len) ++ return -ANA_ERR_GETANAS_OVERFLOW; ++ ++ for (j = 0; j < nr_nsids; j++) { ++ if (nsid == le32_to_cpu(ana_desc->nsids[j])) ++ return ana_desc->state; ++ } ++ ++ if (anagrpid != 0 && anagrpid == le32_to_cpu(ana_desc->grpid)) ++ return ana_desc->state; ++ ++ } ++ return -ANA_ERR_GETANAS_NOTFOUND; ++} ++ ++int get_ana_info(struct path * pp, unsigned int timeout) ++{ ++ int rc; ++ __u32 nsid; ++ struct nvme_id_ctrl ctrl; ++ struct nvme_id_ns ns; ++ void *ana_log; ++ size_t ana_log_len; ++ bool is_anagrpid_const; ++ ++ rc = nvme_id_ctrl_ana(pp->fd, &ctrl); ++ if (rc < 0) { ++ log_nvme_errcode(rc, pp->dev, "nvme_identify_ctrl"); ++ return -ANA_ERR_GETCTRL_FAILED; ++ } else if (rc == 0) ++ return -ANA_ERR_NOT_SUPPORTED; ++ ++ nsid = nvme_get_nsid(pp->fd); ++ if (nsid <= 0) { ++ log_nvme_errcode(rc, pp->dev, "nvme_get_nsid"); ++ return -ANA_ERR_GETNSID_FAILED; ++ } ++ is_anagrpid_const = ctrl.anacap & (1 << 6); ++ ++ /* ++ * Code copied from nvme-cli/nvme.c. We don't need to allocate an ++ * [nanagrpid*mnan] array of NSIDs because each NSID can occur at most ++ * in one ANA group. ++ */ ++ ana_log_len = sizeof(struct nvme_ana_rsp_hdr) + ++ le32_to_cpu(ctrl.nanagrpid) ++ * sizeof(struct nvme_ana_group_desc); ++ ++ if (is_anagrpid_const) { ++ rc = nvme_identify_ns(pp->fd, nsid, 0, &ns); ++ if (rc) { ++ log_nvme_errcode(rc, pp->dev, "nvme_identify_ns"); ++ return -ANA_ERR_GETNS_FAILED; ++ } ++ } else ++ ana_log_len += le32_to_cpu(ctrl.mnan) * sizeof(__le32); ++ ++ ana_log = malloc(ana_log_len); ++ if (!ana_log) ++ return -ANA_ERR_NO_MEMORY; ++ pthread_cleanup_push(free, ana_log); ++ rc = nvme_ana_log(pp->fd, ana_log, ana_log_len, ++ is_anagrpid_const ? NVME_ANA_LOG_RGO : 0); ++ if (rc) { ++ log_nvme_errcode(rc, pp->dev, "nvme_ana_log"); ++ rc = -ANA_ERR_GETANALOG_FAILED; ++ } else ++ rc = get_ana_state(nsid, ++ is_anagrpid_const ? ++ le32_to_cpu(ns.anagrpid) : 0, ++ ana_log, ana_log_len); ++ pthread_cleanup_pop(1); ++ if (rc >= 0) ++ condlog(3, "%s: ana state = %02x [%s]", pp->dev, rc, ++ aas_print_string(rc)); ++ return rc; ++} ++ ++/* ++ * Priorities modeled roughly after the ALUA model (alua.c/sysfs.c) ++ * Reference: ANA Base Protocol (NVMe TP 4004a, 11/13/2018). ++ * ++ * Differences: ++ * ++ * - The ANA base spec defines no implicit or explicit (STPG) state management. ++ * If a state is encountered that doesn't allow normal I/O (all except ++ * OPTIMIZED and NON_OPTIMIZED), we can't do anything but either wait for a ++ * Access State Change Notice (can't do that in multipathd as we don't receive ++ * those), or retry commands in regular time intervals until ANATT is expired ++ * (not implemented). Mapping UNAVAILABLE state to ALUA STANDBY is the best we ++ * can currently do. ++ * ++ * FIXME: Waiting for ANATT could be implemented with a "delayed failback" ++ * mechanism. The current "failback" method can't be used, as it would ++ * affect failback to every state, and here only failback to UNAVAILABLE ++ * should be delayed. ++ * ++ * - PERSISTENT_LOSS state is even below ALUA's UNAVAILABLE state. ++ * FIXME: According to the ANA TP, accessing paths in PERSISTENT_LOSS state ++ * in any way makes no sense (e.g. §8.19.6 - paths in this state shouldn't ++ * even be checked under "all paths down" conditions). Device mapper can, ++ * and will, select a PG for IO if it has non-failed paths, even if the ++ * PG has priority 0. We could avoid that only with an "ANA path checker". ++ * ++ * - ALUA has no CHANGE state. The ANA TP §8.18.3 / §8.19.4 suggests ++ * that CHANGE state should be treated in roughly the same way as ++ * INACCESSIBLE. Therefore we assign the same prio to it. ++ * ++ * - ALUA's LBA-dependent state has no ANA equivalent. ++ */ ++ ++int getprio(struct path *pp, char *args) ++{ ++ int rc; ++ ++ if (pp->fd < 0) ++ rc = -ANA_ERR_NO_INFORMATION; ++ else ++ rc = get_ana_info(pp, get_prio_timeout(60000)); ++ ++ switch (rc) { ++ case NVME_ANA_OPTIMIZED: ++ return 50; ++ case NVME_ANA_NONOPTIMIZED: ++ return 10; ++ case NVME_ANA_INACCESSIBLE: ++ case NVME_ANA_CHANGE: ++ return 1; ++ case NVME_ANA_PERSISTENT_LOSS: ++ return 0; ++ default: ++ break; ++ } ++ if (rc < 0 && -rc < ARRAY_SIZE(ana_errmsg)) ++ condlog(2, "%s: ANA error: %s", pp->dev, ana_errmsg[-rc]); ++ else ++ condlog(1, "%s: invalid ANA rc code %d", pp->dev, rc); ++ return -1; ++} ++ ++declare_nop_prio(initprio) ++declare_nop_prio(freeprio) +Index: multipath-tools-130222/libmultipath/util.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/util.h ++++ multipath-tools-130222/libmultipath/util.h +@@ -18,6 +18,8 @@ int parse_prkey(char *ptr, uint64_t *prk + int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags); + int safe_write(int fd, const void *buf, size_t count); + ++#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) ++ + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) + #define safe_snprintf(var, size, format, args...) \ +Index: multipath-tools-130222/multipath/multipath.conf.5 +=================================================================== +--- multipath-tools-130222.orig/multipath/multipath.conf.5 ++++ multipath-tools-130222/multipath/multipath.conf.5 +@@ -196,6 +196,9 @@ Generate the path priority for LSI/Engen + Generate the path priority for Compaq/HP controller in + active/standby mode. + .TP ++.B ana ++Generate the path priority based on the NVMe ANA settings. ++.TP + .B hds + Generate the path priority for Hitachi HDS Modular storage arrays. + .TP +Index: multipath-tools-130222/libmultipath/propsel.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/propsel.c ++++ multipath-tools-130222/libmultipath/propsel.c +@@ -5,6 +5,7 @@ + */ + #include + ++#include "nvme-lib.h" + #include "checkers.h" + #include "memory.h" + #include "vector.h" +@@ -489,8 +490,13 @@ select_getuid (struct path * pp) + void + detect_prio(struct path * pp) + { +- if (detect_alua(pp)) +- prio_get(&pp->prio, PRIO_ALUA, DEFAULT_PRIO_ARGS); ++ if (pp->bus == SYSFS_BUS_NVME) { ++ if (nvme_id_ctrl_ana(pp->fd, NULL) == 1) ++ prio_get(&pp->prio, PRIO_ANA, DEFAULT_PRIO_ARGS); ++ } else if (pp->bus == SYSFS_BUS_SCSI) { ++ if (detect_alua(pp)) ++ prio_get(&pp->prio, PRIO_ALUA, DEFAULT_PRIO_ARGS); ++ } + } + + extern int +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1178,6 +1178,7 @@ static struct hwentry default_hw[] = { + .vendor = "NVME", + .product = ".*", + .uid_attribute = "ID_WWN", ++ .detect_prio = DETECT_PRIO_ON, + .checker_name = NONE, + }, + /* diff --git a/SOURCES/0259-RHBZ-1701604-fix-nr-active.patch b/SOURCES/0259-RHBZ-1701604-fix-nr-active.patch new file mode 100644 index 0000000..e6973bb --- /dev/null +++ b/SOURCES/0259-RHBZ-1701604-fix-nr-active.patch @@ -0,0 +1,71 @@ +--- + libmultipath/structs_vec.c | 24 +++++++++++++++++------- + multipathd/main.c | 2 ++ + 2 files changed, 19 insertions(+), 7 deletions(-) + +Index: multipath-tools-130222/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/structs_vec.c ++++ multipath-tools-130222/libmultipath/structs_vec.c +@@ -312,24 +312,33 @@ update_multipath_strings (struct multipa + extern void + set_no_path_retry(struct multipath *mpp) + { +- mpp->retry_tick = 0; ++ char is_queueing = 0; ++ + mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST); +- select_no_path_retry(mpp); ++ if (mpp->features && strstr(mpp->features, "queue_if_no_path")) ++ is_queueing = 1; + + switch (mpp->no_path_retry) { + case NO_PATH_RETRY_UNDEF: + break; + case NO_PATH_RETRY_FAIL: +- dm_queue_if_no_path(mpp->alias, 0); ++ if (is_queueing) ++ dm_queue_if_no_path(mpp->alias, 0); + break; + case NO_PATH_RETRY_QUEUE: +- dm_queue_if_no_path(mpp->alias, 1); ++ if (!is_queueing) ++ dm_queue_if_no_path(mpp->alias, 1); + break; + default: +- dm_queue_if_no_path(mpp->alias, 1); +- if (mpp->nr_active == 0) { ++ if (mpp->nr_active > 0) { ++ mpp->retry_tick = 0; ++ if (!is_queueing) ++ dm_queue_if_no_path(mpp->alias, 1); ++ } else if (is_queueing && mpp->retry_tick == 0) { + /* Enter retry mode */ +- mpp->retry_tick = mpp->no_path_retry * conf->checkint; ++ mpp->stat_queueing_timeouts++; ++ mpp->retry_tick = mpp->no_path_retry * ++ conf->checkint + 1; + condlog(1, "%s: Entering recovery mode: max_retries=%d", + mpp->alias, mpp->no_path_retry); + } +@@ -360,6 +369,7 @@ __setup_multipath (struct vectors * vecs + if (reset) { + select_rr_weight(mpp); + select_pgfailback(mpp); ++ select_no_path_retry(mpp); + set_no_path_retry(mpp); + select_pg_timeout(mpp); + select_flush_on_last_del(mpp); +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1464,6 +1464,8 @@ check_path (struct vectors * vecs, struc + if (!pp->mpp) + return 0; + ++ set_no_path_retry(pp->mpp); ++ + if ((newstate == PATH_UP || newstate == PATH_GHOST) && + pp->io_err_disable_reinstate && need_io_err_check(pp)) { + pp->state = PATH_SHAKY; diff --git a/SOURCES/0260-RHBZ-1634183-prio-fixes.patch b/SOURCES/0260-RHBZ-1634183-prio-fixes.patch new file mode 100644 index 0000000..cddeae0 --- /dev/null +++ b/SOURCES/0260-RHBZ-1634183-prio-fixes.patch @@ -0,0 +1,67 @@ +--- + libmultipath/discovery.c | 15 +++++++++++++-- + libmultipath/pgpolicies.c | 2 +- + libmultipath/prioritizers/ana.c | 2 +- + 3 files changed, 15 insertions(+), 4 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1234,6 +1234,7 @@ get_state (struct path * pp, int daemon, + static int + get_prio (struct path * pp) + { ++ int old_prio; + if (!pp) + return 0; + +@@ -1247,10 +1248,20 @@ get_prio (struct path * pp) + return 1; + } + } ++ old_prio = pp->priority; + pp->priority = prio_getprio(p, pp); + if (pp->priority < 0) { +- condlog(3, "%s: %s prio error", pp->dev, prio_name(p)); +- pp->priority = PRIO_UNDEF; ++ /* this changes pp->offline, but why not */ ++ int state = path_offline(pp); ++ ++ if (state == PATH_DOWN || state == PATH_PENDING) { ++ pp->priority = old_prio; ++ condlog(3, "%s: %s prio error in state %d, keeping prio = %d", pp->dev, prio_name(p), state, pp->priority); ++ } else { ++ condlog(3, "%s: %s prio error in state %d", ++ pp->dev, prio_name(p), state); ++ pp->priority = PRIO_UNDEF; ++ } + return 1; + } + condlog(3, "%s: %s prio = %u", +Index: multipath-tools-130222/libmultipath/pgpolicies.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/pgpolicies.c ++++ multipath-tools-130222/libmultipath/pgpolicies.c +@@ -308,7 +308,7 @@ extern int + group_by_prio (struct multipath * mp) + { + int i; +- unsigned int prio; ++ int prio; + struct path * pp; + struct pathgroup * pgp; + +Index: multipath-tools-130222/libmultipath/prioritizers/ana.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/prioritizers/ana.c ++++ multipath-tools-130222/libmultipath/prioritizers/ana.c +@@ -165,7 +165,7 @@ int get_ana_info(struct path * pp, unsig + ana_log, ana_log_len); + pthread_cleanup_pop(1); + if (rc >= 0) +- condlog(3, "%s: ana state = %02x [%s]", pp->dev, rc, ++ condlog(4, "%s: ana state = %02x [%s]", pp->dev, rc, + aas_print_string(rc)); + return rc; + } diff --git a/SOURCES/0262-RHBZ-1699486-reload-with-failed-paths.patch b/SOURCES/0262-RHBZ-1699486-reload-with-failed-paths.patch new file mode 100644 index 0000000..0d560bd --- /dev/null +++ b/SOURCES/0262-RHBZ-1699486-reload-with-failed-paths.patch @@ -0,0 +1,67 @@ +--- + libmultipath/configure.c | 12 ++++++------ + libmultipath/discovery.c | 8 ++++++-- + multipathd/main.c | 1 + + 3 files changed, 13 insertions(+), 8 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1264,8 +1264,12 @@ get_prio (struct path * pp) + } + return 1; + } +- condlog(3, "%s: %s prio = %u", +- pp->dev, prio_name(p), pp->priority); ++ if (old_prio != PRIO_UNDEF && old_prio != pp->priority) ++ condlog(2, "%s: prio changed from %d to %d", pp->dev, ++ old_prio, pp->priority); ++ else ++ condlog(3, "%s: %s prio = %u", ++ pp->dev, prio_name(p), pp->priority); + return 0; + } + +Index: multipath-tools-130222/multipathd/main.c +=================================================================== +--- multipath-tools-130222.orig/multipathd/main.c ++++ multipath-tools-130222/multipathd/main.c +@@ -1370,6 +1370,7 @@ int update_prio(struct path *pp, int ref + + int update_path_groups(struct multipath *mpp, struct vectors *vecs, int refresh) + { ++ condlog(2, "%s: updating path groups %d", mpp->alias, refresh); + if (reload_map(vecs, mpp, refresh)) + return 1; + +Index: multipath-tools-130222/libmultipath/configure.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/configure.c ++++ multipath-tools-130222/libmultipath/configure.c +@@ -453,12 +453,6 @@ select_action (struct multipath * mpp, v + return; + } + +- if (pathcount(mpp, PATH_UP) == 0) { +- mpp->action = ACT_NOTHING; +- condlog(3, "%s: set ACT_NOTHING (no usable path)", +- mpp->alias); +- return; +- } + if (force_reload) { + mpp->force_udev_reload = 1; + mpp->action = ACT_RELOAD; +@@ -466,6 +460,12 @@ select_action (struct multipath * mpp, v + mpp->alias); + return; + } ++ if (pathcount(mpp, PATH_UP) == 0) { ++ mpp->action = ACT_NOTHING; ++ condlog(3, "%s: set ACT_NOTHING (no usable path)", ++ mpp->alias); ++ return; ++ } + if (cmpp->size != mpp->size) { + mpp->force_udev_reload = 1; + mpp->action = ACT_RESIZE; diff --git a/SOURCES/0263-RHBZ-1686708-nvme-hcil.patch b/SOURCES/0263-RHBZ-1686708-nvme-hcil.patch new file mode 100644 index 0000000..f7b1d2b --- /dev/null +++ b/SOURCES/0263-RHBZ-1686708-nvme-hcil.patch @@ -0,0 +1,36 @@ +--- + libmultipath/discovery.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -889,7 +889,7 @@ nvme_sysfs_pathinfo (struct path * pp) + { + struct udev_device *parent; + const char *attr_path = NULL; +- ++ const char *attr; + + attr_path = udev_device_get_sysname(pp->udev); + if (!attr_path) +@@ -902,10 +902,17 @@ nvme_sysfs_pathinfo (struct path * pp) + pp->sg_id.channel = 0; + pp->sg_id.lun = 0; + +- parent = udev_device_get_parent(pp->udev); ++ parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, ++ "nvme", NULL); + if (!parent) + return 1; + ++ attr = udev_device_get_sysattr_value(pp->udev, "nsid"); ++ pp->sg_id.lun = attr ? atoi(attr) : 0; ++ ++ attr = udev_device_get_sysattr_value(parent, "cntlid"); ++ pp->sg_id.channel = attr ? atoi(attr) : 0; ++ + snprintf(pp->vendor_id, SCSI_VENDOR_SIZE, "NVME"); + snprintf(pp->product_id, PATH_PRODUCT_SIZE, "%s", + udev_device_get_sysattr_value(parent, "model")); diff --git a/SOURCES/0264-RHBZ-1699441-de-series-config.patch b/SOURCES/0264-RHBZ-1699441-de-series-config.patch new file mode 100644 index 0000000..d05e5da --- /dev/null +++ b/SOURCES/0264-RHBZ-1699441-de-series-config.patch @@ -0,0 +1,28 @@ +--- + libmultipath/hwtable.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -748,6 +748,19 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_RDAC, + .prio_args = NULL, + }, ++ { ++ .vendor = "LENOVO", ++ .product = "DE_Series", ++ .bl_product = "Universal Xport", ++ .features = "2 pg_init_retries 50", ++ .hwhandler = "1 rdac", ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .no_path_retry = 30, ++ .checker_name = RDAC, ++ .prio_name = PRIO_RDAC, ++ .prio_args = NULL, ++ }, + /* + * NETAPP controller family + * diff --git a/SOURCES/0265-RHBZ-1721855-mpathpersist-speedup.patch b/SOURCES/0265-RHBZ-1721855-mpathpersist-speedup.patch new file mode 100644 index 0000000..70e2c3b --- /dev/null +++ b/SOURCES/0265-RHBZ-1721855-mpathpersist-speedup.patch @@ -0,0 +1,1175 @@ +--- + libmpathpersist/mpath_persist.c | 230 +++++++++++------------ + libmpathpersist/mpath_persist.h | 40 ++++ + mpathpersist/main.c | 223 ++++++++++++++++++----- + mpathpersist/main.h | 1 + mpathpersist/mpathpersist.8 | 385 ++++++++++++++++++++++++++++++---------- + 5 files changed, 616 insertions(+), 263 deletions(-) + +Index: multipath-tools-130222/mpathpersist/main.c +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.c ++++ multipath-tools-130222/mpathpersist/main.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + static const char * pr_type_strs[] = { + "obsolete [0]", +@@ -46,9 +47,101 @@ int construct_transportid(const char * i + int logsink; + unsigned int mpath_mx_alloc_len; + +-int main (int argc, char * argv[]) ++static int verbose, loglevel, noisy; ++ ++static int handle_args(int argc, char * argv[], int line); ++ ++static int do_batch_file(const char *batch_fn) + { +- int fd, c, res; ++ char command[] = "mpathpersist"; ++ const int ARGV_CHUNK = 2; ++ const char delims[] = " \t\n"; ++ size_t len = 0; ++ char *line = NULL; ++ ssize_t n; ++ int nline = 0; ++ int argl = ARGV_CHUNK; ++ FILE *fl; ++ char **argv = calloc(argl, sizeof(*argv)); ++ int ret = MPATH_PR_SUCCESS; ++ ++ if (argv == NULL) ++ return MPATH_PR_OTHER; ++ ++ fl = fopen(batch_fn, "r"); ++ if (fl == NULL) { ++ fprintf(stderr, "unable to open %s: %s\n", ++ batch_fn, strerror(errno)); ++ free(argv); ++ return MPATH_PR_SYNTAX_ERROR; ++ } else { ++ if (verbose >= 2) ++ fprintf(stderr, "running batch file %s\n", ++ batch_fn); ++ } ++ ++ while ((n = getline(&line, &len, fl)) != -1) { ++ char *_token, *token; ++ int argc = 0; ++ int rv; ++ ++ nline++; ++ argv[argc++] = command; ++ ++ if (line[n-1] == '\n') ++ line[n-1] = '\0'; ++ if (verbose >= 3) ++ fprintf(stderr, "processing line %d: %s\n", ++ nline, line); ++ ++ for (token = strtok_r(line, delims, &_token); ++ token != NULL && *token != '#'; ++ token = strtok_r(NULL, delims, &_token)) { ++ ++ if (argc >= argl) { ++ int argn = argl + ARGV_CHUNK; ++ char **tmp; ++ ++ tmp = realloc(argv, argn * sizeof(*argv)); ++ if (tmp == NULL) ++ break; ++ argv = tmp; ++ argl = argn; ++ } ++ ++ if (argc == 1 && !strcmp(token, command)) ++ continue; ++ ++ argv[argc++] = token; ++ } ++ ++ if (argc <= 1) ++ continue; ++ ++ if (verbose >= 2) { ++ int i; ++ ++ fprintf(stderr, "## file %s line %d:", batch_fn, nline); ++ for (i = 0; i < argc; i++) ++ fprintf(stderr, " %s", argv[i]); ++ fprintf(stderr, "\n"); ++ } ++ ++ optind = 0; ++ rv = handle_args(argc, argv, nline); ++ if (rv != MPATH_PR_SUCCESS) ++ ret = rv; ++ } ++ ++ fclose(fl); ++ free(argv); ++ free(line); ++ return ret; ++} ++ ++static int handle_args(int argc, char * argv[], int nline) ++{ ++ int fd, c; + const char *device_name = NULL; + int num_prin_sa = 0; + int num_prout_sa = 0; +@@ -69,45 +162,41 @@ int main (int argc, char * argv[]) + int prin = 1; + int prin_sa = -1; + int prout_sa = -1; +- int verbose = 0; +- int loglevel = 0; +- int noisy = 0; + int num_transport =0; ++ char *batch_fn = NULL; + void *resp = NULL; + struct transportid * tmp; +- struct udev *udev = NULL; + +- if (optind == argc) +- { +- +- fprintf (stderr, "No parameter used\n"); +- usage (); +- exit (1); +- } +- +- if (getuid () != 0) +- { +- fprintf (stderr, "need to be root\n"); +- exit (1); +- } +- +- udev = udev_new(); +- mpath_lib_init(udev); +- memset(transportids,0,MPATH_MX_TIDS); ++ memset(transportids, 0, MPATH_MX_TIDS * sizeof(struct transportid)); + + while (1) + { + int option_index = 0; + +- c = getopt_long (argc, argv, "v:Cd:hHioZK:S:PAT:skrGILcRX:l:", ++ c = getopt_long (argc, argv, "v:Cd:hHioZK:S:PAT:skrGILcRX:l:f:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { ++ case 'f': ++ if (nline != 0) { ++ fprintf(stderr, ++ "ERROR: -f option not allowed in batch file\n"); ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; ++ } ++ if (batch_fn != NULL) { ++ fprintf(stderr, ++ "ERROR: -f option can be used at most once\n"); ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; ++ } ++ batch_fn = strdup(optarg); ++ break; + case 'v': +- if (1 != sscanf (optarg, "%d", &loglevel)) ++ if (nline == 0 && 1 != sscanf (optarg, "%d", &loglevel)) + { + fprintf (stderr, "bad argument to '--verbose'\n"); + return MPATH_PR_SYNTAX_ERROR; +@@ -241,8 +330,7 @@ int main (int argc, char * argv[]) + break; + + default: +- fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c); +- usage (); ++ fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c); + ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } +@@ -260,27 +348,29 @@ int main (int argc, char * argv[]) + { + for (; optind < argc; ++optind) + fprintf (stderr, "Unexpected extra argument: %s\n", argv[optind]); +- usage (); + ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } + } + +- /* set verbosity */ +- noisy = (loglevel >= 3) ? 1 : hex; +- verbose = (loglevel >= 4)? 4 : loglevel; ++ if (nline == 0) { ++ /* set verbosity */ ++ noisy = (loglevel >= 3) ? 1 : hex; ++ verbose = (loglevel >= 4)? 4 : loglevel; ++ ret = mpath_persistent_reserve_init_vecs(verbose); ++ if (ret != MPATH_PR_SUCCESS) ++ goto out; ++ } + +- if ((prout_flag + prin_flag) == 0) ++ if ((prout_flag + prin_flag) == 0 && batch_fn == NULL) + { + fprintf (stderr, "choose either '--in' or '--out' \n"); +- usage (); + ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } + if ((prout_flag + prin_flag) > 1) + { + fprintf (stderr, "choose either '--in' or '--out' \n"); +- usage (); + ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } +@@ -311,21 +401,19 @@ int main (int argc, char * argv[]) + { + fprintf (stderr, + " No service action given for Persistent Reserve IN\n"); +- usage(); + ret = MPATH_PR_SYNTAX_ERROR; + } + else if (num_prin_sa > 1) + { + fprintf (stderr, " Too many service actions given; choose " + "one only\n"); +- usage(); + ret = MPATH_PR_SYNTAX_ERROR; + } + } + else + { +- usage (); +- ret = MPATH_PR_SYNTAX_ERROR; ++ if (batch_fn == NULL) ++ ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } + +@@ -333,7 +421,6 @@ int main (int argc, char * argv[]) + { + fprintf (stderr, " --relative-target-port" + " only useful with --register-move\n"); +- usage (); + ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } +@@ -355,7 +442,6 @@ int main (int argc, char * argv[]) + if (device_name == NULL) + { + fprintf (stderr, "No device name given \n"); +- usage (); + ret = MPATH_PR_SYNTAX_ERROR; + goto out; + } +@@ -382,7 +468,7 @@ int main (int argc, char * argv[]) + goto out; + } + +- ret = mpath_persistent_reserve_in (fd, prin_sa, resp, noisy, verbose); ++ ret = __mpath_persistent_reserve_in (fd, prin_sa, resp, noisy); + if (ret != MPATH_PR_SUCCESS ) + { + fprintf (stderr, "Persistent Reserve IN command failed\n"); +@@ -442,8 +528,8 @@ int main (int argc, char * argv[]) + } + + /* PROUT commands other than 'register and move' */ +- ret = mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type, +- paramp, noisy, verbose); ++ ret = __mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type, ++ paramp, noisy); + for (j = 0 ; j < num_transport; j++) + { + tmp = paramp->trnptid_list[j]; +@@ -466,17 +552,57 @@ int main (int argc, char * argv[]) + printf("PR out: command failed\n"); + } + +- res = close (fd); +- if (res < 0) ++ close (fd); ++ ++out : ++ if (ret == MPATH_PR_SYNTAX_ERROR) { ++ free(batch_fn); ++ if (nline == 0) ++ usage(); ++ else ++ fprintf(stderr, "syntax error on line %d in batch file\n", ++ nline); ++ } else if (batch_fn != NULL) { ++ int rv = do_batch_file(batch_fn); ++ ++ free(batch_fn); ++ ret = ret == 0 ? rv : ret; ++ } ++ if (nline == 0) ++ mpath_persistent_reserve_free_vecs(); ++ return (ret >= 0) ? ret : MPATH_PR_OTHER; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct udev *udev; ++ int ret; ++ ++ if (optind == argc) ++ { ++ ++ fprintf (stderr, "No parameter used\n"); ++ usage (); ++ exit (1); ++ } ++ ++ if (getuid () != 0) + { +- mpath_lib_exit(); ++ fprintf (stderr, "need to be root\n"); ++ exit (1); ++ } ++ ++ udev = udev_new(); ++ if(mpath_lib_init(udev) != 0) { + udev_unref(udev); +- return MPATH_PR_FILE_ERROR; ++ exit(1); + } + +-out : ++ ret = handle_args(argc, argv, 0); ++ + mpath_lib_exit(); + udev_unref(udev); ++ + return (ret >= 0) ? ret : MPATH_PR_OTHER; + } + +@@ -677,6 +803,7 @@ static void usage() + " 4 Informational messages with trace enabled\n" + " --clear|-C PR Out: Clear\n" + " --device=DEVICE|-d DEVICE query or change DEVICE\n" ++ " --batch-file|-f FILE run commands from FILE\n" + " --help|-h output this usage message\n" + " --hex|-H output response in hex\n" + " --in|-i request PR In command \n" +Index: multipath-tools-130222/mpathpersist/main.h +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.h ++++ multipath-tools-130222/mpathpersist/main.h +@@ -2,6 +2,7 @@ static struct option long_options[] = { + {"verbose", 1, 0, 'v'}, + {"clear", 0, 0, 'C'}, + {"device", 1, 0, 'd'}, ++ {"batch-file", 1, 0, 'f' }, + {"help", 0, 0, 'h'}, + {"hex", 0, 0, 'H'}, + {"in", 0, 0, 'i'}, +Index: multipath-tools-130222/libmpathpersist/mpath_persist.c +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.c ++++ multipath-tools-130222/libmpathpersist/mpath_persist.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -80,17 +81,21 @@ updatepaths (struct multipath * mpp) + pp->state = PATH_DOWN; + continue; + } +- pp->mpp = mpp; +- pathinfo(pp, conf->hwtable, DI_ALL); +- continue; + } + pp->mpp = mpp; ++ if (pp->udev == NULL) { ++ pp->udev = udev_device_new_from_devnum(conf->udev, 'b', parse_devt(pp->dev_t)); ++ if (pp->udev == NULL) { ++ pp->state = PATH_DOWN; ++ continue; ++ } ++ pathinfo(pp, conf->hwtable, ++ DI_SYSFS|DI_CHECKER); ++ continue; ++ } + if (pp->state == PATH_UNCHECKED || + pp->state == PATH_WILD) + pathinfo(pp, conf->hwtable, DI_CHECKER); +- +- if (pp->priority == PRIO_UNDEF) +- pathinfo(pp, conf->hwtable, DI_PRIO); + } + } + return 0; +@@ -129,45 +134,44 @@ mpath_prin_activepath (struct multipath + + int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose) + { +- struct stat info; +- vector curmp = NULL; +- vector pathvec = NULL; +- char * alias; +- struct multipath * mpp; +- int map_present; +- int major, minor; +- int ret; ++ int ret = mpath_persistent_reserve_init_vecs(verbose); + +- conf->verbosity = verbose; ++ if (ret != MPATH_PR_SUCCESS) ++ return ret; ++ ret = __mpath_persistent_reserve_in(fd, rq_servact, resp, noisy); ++ mpath_persistent_reserve_free_vecs(); ++ return ret; ++} + +- if (fstat( fd, &info) != 0){ +- condlog(0, "stat error %d", fd); +- return MPATH_PR_FILE_ERROR; +- } +- if(!S_ISBLK(info.st_mode)){ +- condlog(0, "Failed to get major:minor. fd = %d", fd); +- return MPATH_PR_FILE_ERROR; +- } ++int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, ++ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose) ++{ ++ int ret = mpath_persistent_reserve_init_vecs(verbose); + +- major = (int)MAJOR(info.st_rdev); +- minor = (int)MINOR(info.st_rdev); +- condlog(4, "Device %d:%d: ", major, minor); ++ if (ret != MPATH_PR_SUCCESS) ++ return ret; ++ ret = __mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, ++ paramp, noisy); ++ mpath_persistent_reserve_free_vecs(); ++ return ret; ++} + +- /* 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; +- } ++static vector curmp; ++static vector pathvec; + +- condlog(3, "alias = %s", alias); +- map_present = dm_map_present(alias); +- if (map_present && !dm_is_mpath(alias)){ +- condlog( 0, "%s: not a multipath device.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out; +- } ++void mpath_persistent_reserve_free_vecs(void) ++{ ++ free_multipathvec(curmp, KEEP_PATHS); ++ free_pathvec(pathvec, FREE_PATHS); ++ curmp = pathvec = NULL; ++} ++ ++int mpath_persistent_reserve_init_vecs(int verbose) ++{ ++ conf->verbosity = verbose; + ++ if (curmp) ++ return MPATH_PR_SUCCESS; + /* + * allocate core vectors to store paths and multipaths + */ +@@ -175,63 +179,32 @@ int mpath_persistent_reserve_in (int fd, + pathvec = vector_alloc (); + + if (!curmp || !pathvec){ +- condlog (0, "%s: vector allocation failed.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out; +- } +- +- if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) { +- ret = MPATH_PR_DMMP_ERROR; +- goto out1; +- } +- +- /* get info of all paths from the dm device */ +- if (get_mpvec (curmp, pathvec, alias)){ +- condlog(0, "%s: failed to get device info.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out1; ++ condlog (0, "vector allocation failed."); ++ goto err; + } + +- mpp = find_mp_by_alias(curmp, alias); +- if (!mpp){ +- condlog(0, "%s: devmap not registered.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out1; +- } ++ if (dm_get_maps(curmp)) ++ goto err; + +- ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy); ++ return MPATH_PR_SUCCESS; + +-out1: +- free_multipathvec(curmp, KEEP_PATHS); +- free_pathvec(pathvec, FREE_PATHS); +-out: +- FREE(alias); +- return ret; ++err: ++ mpath_persistent_reserve_free_vecs(); ++ return MPATH_PR_DMMP_ERROR; + } + +-int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, +- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose) ++static int mpath_get_map(int fd, char **palias, struct multipath **pmpp) + { +- ++ int ret = MPATH_PR_DMMP_ERROR; + struct stat info; +- +- vector curmp = NULL; +- vector pathvec = NULL; +- +- char * alias; +- struct multipath * mpp; +- int map_present; + int major, minor; +- int ret; +- uint64_t prkey; +- +- conf->verbosity = verbose; ++ char *alias; ++ struct multipath *mpp; + +- if (fstat( fd, &info) != 0){ ++ 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; +@@ -241,53 +214,72 @@ int mpath_persistent_reserve_out ( int f + minor = (int)MINOR(info.st_rdev); + condlog(4, "Device %d:%d", major, minor); + +- /* get WWN of the device from 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); +- map_present = dm_map_present(alias); + +- if (map_present && !dm_is_mpath(alias)){ ++ if (dm_map_present(alias) && !dm_is_mpath(alias)){ + condlog(3, "%s: not a multipath device.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out; +- } +- +- /* +- * allocate core vectors to store paths and multipaths +- */ +- curmp = vector_alloc (); +- pathvec = vector_alloc (); +- +- if (!curmp || !pathvec){ +- condlog (0, "%s: vector allocation failed.", alias); +- ret = MPATH_PR_DMMP_ERROR; + goto out; + } + +- if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) { +- ret = MPATH_PR_DMMP_ERROR; +- goto out1; +- } +- + /* get info of all paths from the dm device */ + if (get_mpvec(curmp, pathvec, alias)){ + condlog(0, "%s: failed to get device info.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out1; ++ goto out; + } + + mpp = find_mp_by_alias(curmp, alias); + + if (!mpp) { + condlog(0, "%s: devmap not registered.", alias); +- ret = MPATH_PR_DMMP_ERROR; +- goto out1; ++ goto out; + } + ++ ret = MPATH_PR_SUCCESS; ++ if (pmpp) ++ *pmpp = mpp; ++ if (palias) { ++ *palias = alias; ++ alias = NULL; ++ } ++out: ++ FREE(alias); ++ return ret; ++} ++ ++int __mpath_persistent_reserve_in (int fd, int rq_servact, ++ struct prin_resp *resp, int noisy) ++{ ++ struct multipath *mpp; ++ int ret; ++ ++ ret = mpath_get_map(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_out ( 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; ++ ++ ret = mpath_get_map(fd, &alias, &mpp); ++ if (ret != MPATH_PR_SUCCESS) ++ return ret; ++ + select_reservation_key(mpp); + select_all_tg_pt(mpp); + +@@ -350,10 +342,6 @@ int mpath_persistent_reserve_out ( int f + } + } + out1: +- free_multipathvec(curmp, KEEP_PATHS); +- free_pathvec(pathvec, FREE_PATHS); +- +-out: + FREE(alias); + return ret; + } +@@ -365,21 +353,22 @@ get_mpvec (vector curmp, vector pathvec, + struct multipath *mpp; + char params[PARAMS_SIZE], status[PARAMS_SIZE]; + +- if (dm_get_maps (curmp)){ +- return 1; +- } +- + vector_foreach_slot (curmp, mpp, i){ + /* + * discard out of scope maps + */ +- if (mpp->alias && refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE)){ +- free_multipath (mpp, KEEP_PATHS); +- vector_del_slot (curmp, i); +- i--; ++ 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; ++ + dm_get_map(mpp->alias, &mpp->size, params); + condlog(3, "params = %s", params); + dm_get_status(mpp->alias, status); +@@ -392,7 +381,6 @@ get_mpvec (vector curmp, vector pathvec, + * about them + */ + updatepaths(mpp); +- mpp->bestpg = select_path_group (mpp); + disassemble_status (status, mpp); + + } +Index: multipath-tools-130222/libmpathpersist/mpath_persist.h +=================================================================== +--- multipath-tools-130222.orig/libmpathpersist/mpath_persist.h ++++ multipath-tools-130222/libmpathpersist/mpath_persist.h +@@ -212,6 +212,15 @@ extern int mpath_persistent_reserve_in ( + + /* + * DESCRIPTION : ++ * This function is like mpath_persistent_reserve_in(), except that it doesn't call ++ * mpath_persistent_reserve_init_vecs() and mpath_persistent_reserve_free_vecs() ++ * before and after the actual PR call. ++ */ ++extern int __mpath_persistent_reserve_in(int fd, int rq_servact, ++ struct prin_resp *resp, int noisy); ++ ++/* ++ * DESCRIPTION : + * This function sends PROUT command to the DM device and get the response. + * + * @fd: The file descriptor of a multipath device. Input argument. +@@ -235,6 +244,37 @@ extern int mpath_persistent_reserve_in ( + extern int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, + int verbose); ++/* ++ * DESCRIPTION : ++ * This function is like mpath_persistent_reserve_out(), except that it doesn't call ++ * mpath_persistent_reserve_init_vecs() and mpath_persistent_reserve_free_vecs() ++ * before and after the actual PR call. ++ */ ++extern int __mpath_persistent_reserve_out( int fd, int rq_servact, int rq_scope, ++ unsigned int rq_type, struct prout_param_descriptor *paramp, ++ int noisy); ++ ++/* ++ * DESCRIPTION : ++ * This function allocates data structures and performs basic initialization and ++ * device discovery for later calls of __mpath_persistent_reserve_in() or ++ * __mpath_persistent_reserve_out(). ++ * @verbose: Set verbosity level. Input argument. value:0 to 3. 0->disabled, 3->Max verbose ++ * ++ * RESTRICTIONS: ++ * ++ * RETURNS: MPATH_PR_SUCCESS if successful else returns any of the status specified ++ * above in RETURN_STATUS. ++ */ ++int mpath_persistent_reserve_init_vecs(int verbose); ++ ++/* ++ * DESCRIPTION : ++ * This function frees data structures allocated by ++ * mpath_persistent_reserve_init_vecs(). ++ */ ++void mpath_persistent_reserve_free_vecs(void); ++ + + #ifdef __cplusplus + } +Index: multipath-tools-130222/mpathpersist/mpathpersist.8 +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/mpathpersist.8 ++++ multipath-tools-130222/mpathpersist/mpathpersist.8 +@@ -1,99 +1,296 @@ +-.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.39.2. +-.TH MPATHPERSIST "8" "April 2011" "mpathpersist" "User Commands" ++.\" ---------------------------------------------------------------------------- ++.\" Update the date below if you make any significant change. ++.\" Make sure there are no errors with: ++.\" groff -z -wall -b -e -t mpathpersist/mpathpersist.8 ++.\" ++.\" ---------------------------------------------------------------------------- ++. ++.TH MPATHPERSIST 8 2019-05-27 "Linux" ++. ++. ++.\" ---------------------------------------------------------------------------- + .SH NAME +-mpathpersist ++.\" ---------------------------------------------------------------------------- ++. ++mpathpersist \- Manages SCSI persistent reservations on dm multipath devices. ++. ++. ++.\" ---------------------------------------------------------------------------- + .SH SYNOPSIS ++.\" ---------------------------------------------------------------------------- ++. + .B mpathpersist +-[\fIOPTIONS\fR] [\fIDEVICE\fR] ++.RB [\| OPTIONS \|] ++.I device ++. ++. ++.\" ---------------------------------------------------------------------------- + .SH DESCRIPTION +-.IP +-Options: +-.TP +-\fB\-\-verbose\fR|\-v level +-verbosity level +-.TP +-0 +-Critical and error messages +-.TP +-1 +-Warning messages +-.TP +-2 +-Informational messages +-.TP +-3 +-Informational messages with trace enabled +-.TP +-\fB\-\-clear\fR|\-C +-PR Out: Clear +-.TP +-\fB\-\-device\fR=\fIDEVICE\fR|\-d DEVICE +-query or change DEVICE +-.TP +-\fB\-\-help\fR|\-h +-output this usage message +-.TP +-\fB\-\-hex\fR|\-H +-output response in hex +-.TP +-\fB\-\-in\fR|\-i +-request PR In command +-.TP +-\fB\-\-out\fR|\-o +-request PR Out command +-.TP +-\fB\-\-param\-aptpl\fR|\-Z +-PR Out parameter 'APTPL' +-.TP +-\fB\-\-read\-keys\fR|\-k +-PR In: Read Keys +-.TP +-\fB\-\-param\-rk\fR=\fIRK\fR|\-K RK +-PR Out parameter reservation key (RK is in hex) +-.TP +-\fB\-\-param\-sark\fR=\fISARK\fR|\-S SARK +-PR Out parameter service action +-reservation key (SARK is in hex) +-.TP +-\fB\-\-preempt\fR|\-P +-PR Out: Preempt +-.TP +-\fB\-\-preempt\-abort\fR|\-A +-PR Out: Preempt and Abort +-.TP +-\fB\-\-prout\-type\fR=\fITYPE\fR|\-T TYPE +-PR Out command type +-.TP +-\fB\-\-read\-status\fR|\-s +-PR In: Read Full Status +-.TP +-\fB\-\-read\-keys\fR|\-k +-PR In: Read Keys +-.TP +-\fB\-\-read\-reservation\fR|\-r +-PR In: Read Reservation +-.TP +-\fB\-\-register\fR|\-G +-PR Out: Register +-.TP +-\fB\-\-register\-ignore\fR|\-I +-PR Out: Register and Ignore +-.TP +-\fB\-\-release\fR|\-L +-PR Out: Release +-.TP +-\fB\-\-report\-capabilities\fR|\-c +-PR In: Report Capabilities +-.TP +-\fB\-\-reserve\fR|\-R +-PR Out: Reserve +-.TP +-\fB\-\-transport\-id\fR=\fITIDS\fR|\-X TIDS +-TransportIDs can be mentioned +-in several forms +-.IP +-Examples: +-.IP +-mpathpersist \fB\-\-out\fR \fB\-\-register\fR \fB\-\-param\-sark\fR=\fI123abc\fR \fB\-\-prout\-type\fR=\fI5\fR /dev/mapper/mpath9 +-mpathpersist \fB\-i\fR \fB\-k\fR /dev/mapper/mpath9 ++.\" ---------------------------------------------------------------------------- ++. ++This utility is used to manage SCSI persistent reservations on Device Mapper ++Multipath devices. To be able to use this functionality, the \fIreservation_key\fR ++attribute must be defined in the \fI/etc/multipath.conf\fR file. Otherwise the ++\fBmultipathd\fR daemon will not check for persistent reservation for newly ++discovered paths or reinstated paths. ++. ++.LP ++\fBmpathpersist\fR supports the same command-line options as the ++\fBsg_persist\fR utility. ++. ++Consult the \fBsg_persist (8)\fR manual page for an in-depth discussion of the ++various options. ++. ++.\" ---------------------------------------------------------------------------- ++.SH OPTIONS ++.\" ---------------------------------------------------------------------------- ++. ++.TP ++.BI \-verbose|\-v " level" ++Verbosity: ++.RS ++.TP 5 ++.I 0 ++Critical messages. ++.TP ++.I 1 ++Error messages. ++.TP ++.I 2 ++Warning messages. ++.TP ++.I 3 ++Informational messages. ++.TP ++.I 4 ++Informational messages with trace enabled. ++.RE ++. ++.TP ++.BI \--device=\fIDEVICE\fB|\-d " DEVICE" ++Query or change DEVICE. ++. ++.TP ++.BI \--batch-file=\fIDEVICE\fB|\-f " FILE" ++Read commands from \fIFILE\fR. See section \(dqBATCH FILES\(dq below. This ++option can be given at most once. ++. ++.TP ++.B \--help|\-h ++Output this usage message. ++. ++.TP ++.B \--hex|\-H ++Output response in hex. ++. ++.TP ++.B \--in|\-i ++Request PR In command. ++. ++.TP ++.B \--out|\-o ++Request PR Out command. ++. ++.TP ++.B \--param-aptpl|\-Z ++PR Out parameter 'APTPL'. ++. ++.TP ++.B \--read-keys|\-k ++PR In: Read Keys. ++. ++.TP ++.BI \--param-rk=\fIRK\fB|\-K " RK" ++PR Out parameter reservation key (RK is in hex, up to 8 bytes). ++. ++.TP ++.BI \--param-sark=\fISARK\fB|\-S " SARK" ++PR Out parameter service action reservation key (SARK is in hex). ++. ++.TP ++.B \--preempt|\-P ++PR Out: Preempt. ++. ++.TP ++.B \--clear|\-C ++PR Out: Clear registrations. ++. ++.TP ++.B \--preempt-abort|\-A ++PR Out: Preempt and Abort. ++. ++.TP ++.BI \--prout-type=\fITYPE\fB|\-T " TYPE" ++PR Out command type. ++. ++.TP ++.B \--read-full-status|\-s ++PR In: Read Full Status. ++. ++.TP ++.B \--read-keys|\-k ++PR In: Read Keys. ++. ++.TP ++.B \--read-reservation|\-r ++PR In: Read Reservation. ++. ++.TP ++.B \--register|\-G ++PR Out: Register. ++. ++.TP ++.B \--register-ignore|\-I ++PR Out: Register and Ignore. ++. ++.TP ++.B \--release|\-L ++PR Out: Release. ++. ++.TP ++.B \--report-capabilities|\-c ++PR In: Report Capabilities. ++. ++.TP ++.B \--reserve|\-R ++PR Out: Reserve. ++. ++.TP ++.BI \--transport-id=\fITIDS\fB|\-X " TIDS" ++TransportIDs can be mentioned in several forms. ++. ++.TP ++.BI \--alloc-length=\fILEN\fB|\-l " LEN" ++PR In: maximum allocation length. LEN is a decimal number between 0 and 8192. ++. ++. ++.\" ---------------------------------------------------------------------------- ++.SH EXAMPLE ++.\" ---------------------------------------------------------------------------- ++. ++.PP ++Register the key \(dq123abc\(dq for the /dev/mapper/mpath9 device: ++.RS ++\fBmpathpersist --out --register --param-sark=\fI123abc /dev/mapper/mpath9\fR ++.RE ++.PP ++Read registered reservation keys for the /dev/mapper/mpath9 device: ++.RS ++\fBmpathpersist -i -k \fI/dev/mapper/mpath9\fR ++.RE ++.PP ++Create a reservation for the /dev/mapper/mpath9 device with the given ++reservation key: ++.RS ++\fBmpathpersist --out --reserve --param-rk=\fI123abc \fB--prout-type=\fI8 \fB-d \fI/dev/mapper/mpath9\fR ++.RE ++.PP ++Read the reservation status of the /dev/mapper/mpath9 device: ++.RS ++\fBmpathpersist -i -s -d \fI/dev/mapper/mpath9\fR ++.RE ++.PP ++Release the previously created reservation (note that the prout-type needs to ++be the same as above): ++.RS ++\fBmpathpersist --out --release --param-rk=\fI123abc \fB--prout-type=\fI8 \fB-d \fI/dev/mapper/mpath9\fR ++.RE ++.PP ++Remove the current key registered for this host (i.e. reset it to 0): ++.RS ++\fBmpathpersist --out --register-ignore -K \fI123abc\fB -S \fI0\fB \fI/dev/mapper/mpath9\fR ++.RE ++.PP ++Remove current reservation, and unregister all registered keys from all I_T nexuses: ++.RS ++\fBmpathpersist -oCK \fI123abc \fI/dev/mapper/mpath9\fR ++.RE ++. ++. ++.\" ---------------------------------------------------------------------------- ++.SH BATCH FILES ++.\" ---------------------------------------------------------------------------- ++. ++.PP ++The option \fI--batch-file\fR (\fI-f\fR) sets an input file to be processed ++by \fBmpathpersist\fR. Grouping commands in batch files can provide a speed ++improvement in particular on large installments, because \fBmpathpersist\fR ++needs to scan existing paths and maps only once during startup. ++. ++.PP ++The input file is a text file that is parsed ++line by line. Every line of the file is interpreted as a command line ++(i.e. list of options and parameters) for \fBmpathpersist\fR. Options ++and parameters are separated by one or more whitespace characters (space or TAB). ++Lines can, but do not have to, begin with the word \(dqmpathpersist\(dq. ++The \(dq#\(dq character, either at the beginning of the line or following ++some whitespace, denotes the start of a comment that lasts until the end of the ++line. Empty lines are allowed. Continuation of mpathpersist commands over ++multiple lines is not supported. ++. ++.PP ++All options listed in this man page, except \fI-f\fR and ++\fI-v\fR, are allowed in batch files. Both short and long option formats may be used. ++Using the \fI-f\fR option inside the batch file is an error. The \fI-v\fR ++option is ignored in batch files. ++. ++.PP ++The multipath map on which to act must be specified on every input line, e.g. using the \fI-d\fR option. ++Commands acting on different multipath maps may be combined in a ++batch file, and multiple commands may act on the same multipath ++map. Commands are executed one by one, so ++that commands further down in the file see status changes caused by previous ++commands. ++If \fBmpathpersist\fR encounters an error while processing a line in the ++batch file, batch file processing is \fBnot\fR aborted; subsequent commands ++are executed nonetheless. The exit status of \fBmpathpersist\fR is the status ++of the first failed command, or 0 if all commands succeeded. ++. ++.PP ++If other options and parameters are used along with ++\fI-f\fR on the \fBmpathpersist\fR command line, the command line will be executed first, followed ++by the commands from the the batch file. ++. ++.PP ++Below is an example of a valid batch input file. ++. + .PP ++.RS ++.EX ++# This is an mpathpersist input file. ++# Short and long forms of the same command ++-i -k /dev/dm-1 # short form, this comment is ignored ++mpathpersist --in --read-keys --device=/dev/dm-1 ++ ++# Mixing of long and short options, variable white space ++ --out --register -S abcde /dev/dm-1 ++ ++# Mixing of commands for different maps ++-ir /dev/dm-0 ++-ir /dev/dm-1 ++ ++mpathpersist --out --param-rk abcde --reserve --prout-type 5 /dev/dm-1 ++# This should now show a reservation ++-ir /dev/dm-1 ++-oCK abcde /dev/dm-1 ++--in --read-reservation /dev/dm-1 ++.EE ++.RE ++. ++. ++.\" ---------------------------------------------------------------------------- ++.SH "SEE ALSO" ++.\" ---------------------------------------------------------------------------- ++. ++.BR multipath (8), ++.BR multipathd (8), ++.BR sg_persist (8). ++. ++. ++.\" ---------------------------------------------------------------------------- ++.SH AUTHORS ++.\" ---------------------------------------------------------------------------- ++. ++\fImultipath-tools\fR was developed by Christophe Varoqui ++and others. ++.\" EOF diff --git a/SOURCES/0266-RHBZ-1696817-fix-emc-checker.patch b/SOURCES/0266-RHBZ-1696817-fix-emc-checker.patch new file mode 100644 index 0000000..c7bf33a --- /dev/null +++ b/SOURCES/0266-RHBZ-1696817-fix-emc-checker.patch @@ -0,0 +1,219 @@ +--- + libmultipath/checkers.c | 29 +++++++++++++++++++++++++++-- + libmultipath/checkers.h | 2 ++ + libmultipath/checkers/cciss_tur.c | 5 +++++ + libmultipath/checkers/directio.c | 5 +++++ + libmultipath/checkers/emc_clariion.c | 7 +++++++ + libmultipath/checkers/hp_sw.c | 5 +++++ + libmultipath/checkers/rdac.c | 5 +++++ + libmultipath/checkers/readsector0.c | 5 +++++ + libmultipath/checkers/tur.c | 5 +++++ + libmultipath/discovery.c | 2 ++ + 10 files changed, 68 insertions(+), 2 deletions(-) + +Index: multipath-tools-130222/libmultipath/checkers.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.c ++++ multipath-tools-130222/libmultipath/checkers.c +@@ -132,6 +132,13 @@ struct checker * add_checker (char * nam + if (!c->init) + goto out; + ++ c->mp_init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_mp_init"); ++ errstr = dlerror(); ++ if (errstr != NULL) ++ condlog(0, "A dynamic linking error occurred: (%s)", errstr); ++ if (!c->mp_init) ++ goto out; ++ + c->free = (void (*)(struct checker *)) dlsym(c->handle, "libcheck_free"); + errstr = dlerror(); + if (errstr != NULL) +@@ -189,8 +196,25 @@ int checker_init (struct checker * c, vo + if (!c) + return 1; + c->mpcontext = mpctxt_addr; +- if (c->init) +- return c->init(c); ++ if (c->init && c->init(c) != 0) ++ return 1; ++ if (mpctxt_addr && *mpctxt_addr == NULL && c->mp_init && ++ c->mp_init(c) != 0) /* for now, continue even if mp_init fails */ ++ c->mpcontext = NULL; ++ return 0; ++} ++ ++int checker_mp_init(struct checker * c, void ** mpctxt_addr) ++{ ++ if (!c) ++ return 1; ++ if (c->mp_init && !c->mpcontext && mpctxt_addr) { ++ c->mpcontext = mpctxt_addr; ++ if (c->mp_init(c) != 0) { ++ c->mpcontext = NULL; ++ return 1; ++ } ++ } + return 0; + } + +@@ -277,6 +301,7 @@ void checker_get (struct checker * dst, + strncpy(dst->message, src->message, CHECKER_MSG_LEN); + dst->check = src->check; + dst->init = src->init; ++ dst->mp_init = src->mp_init; + dst->free = src->free; + dst->handle = NULL; + src->refcount++; +Index: multipath-tools-130222/libmultipath/checkers.h +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers.h ++++ multipath-tools-130222/libmultipath/checkers.h +@@ -107,6 +107,7 @@ struct checker { + you want to stuff data in. */ + int (*check)(struct checker *); + int (*init)(struct checker *); /* to allocate the context */ ++ int (*mp_init)(struct checker *); /* to allocate the mpcontext */ + void (*free)(struct checker *); /* to free the context */ + }; + +@@ -118,6 +119,7 @@ void cleanup_checkers (void); + struct checker * add_checker (char *); + struct checker * checker_lookup (char *); + int checker_init (struct checker *, void **); ++int checker_mp_init (struct checker *, void **); + void checker_put (struct checker *); + void checker_reset (struct checker *); + void checker_set_sync (struct checker *); +Index: multipath-tools-130222/libmultipath/discovery.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/discovery.c ++++ multipath-tools-130222/libmultipath/discovery.c +@@ -1217,6 +1217,8 @@ get_state (struct path * pp, int daemon, + return PATH_UNCHECKED; + } + } ++ if (pp->mpp && !c->mpcontext) ++ checker_mp_init(c, &pp->mpp->mpcontext); + checker_clear_message(c); + if (daemon) { + if (conf->force_sync == 0) +Index: multipath-tools-130222/libmultipath/checkers/cciss_tur.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/cciss_tur.c ++++ multipath-tools-130222/libmultipath/checkers/cciss_tur.c +@@ -58,6 +58,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init (struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +Index: multipath-tools-130222/libmultipath/checkers/directio.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/directio.c ++++ multipath-tools-130222/libmultipath/checkers/directio.c +@@ -94,6 +94,11 @@ out: + return 1; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + struct directio_context * ct = (struct directio_context *)c->context; +Index: multipath-tools-130222/libmultipath/checkers/emc_clariion.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/emc_clariion.c ++++ multipath-tools-130222/libmultipath/checkers/emc_clariion.c +@@ -73,11 +73,18 @@ int libcheck_init (struct checker * c) + return 1; + ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0; + ++ return 0; ++} ++ ++int libcheck_mp_init (struct checker * c) ++{ + /* + * Allocate and initialize the multi-path global context. + */ + if (c->mpcontext && *c->mpcontext == NULL) { + void * mpctxt = malloc(sizeof(int)); ++ if (!mpctxt) ++ return 1; + *c->mpcontext = mpctxt; + CLR_INACTIVE_SNAP(c); + } +Index: multipath-tools-130222/libmultipath/checkers/hp_sw.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/hp_sw.c ++++ multipath-tools-130222/libmultipath/checkers/hp_sw.c +@@ -39,6 +39,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +Index: multipath-tools-130222/libmultipath/checkers/rdac.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/rdac.c ++++ multipath-tools-130222/libmultipath/checkers/rdac.c +@@ -134,6 +134,11 @@ out: + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +Index: multipath-tools-130222/libmultipath/checkers/readsector0.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/readsector0.c ++++ multipath-tools-130222/libmultipath/checkers/readsector0.c +@@ -18,6 +18,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +Index: multipath-tools-130222/libmultipath/checkers/tur.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/checkers/tur.c ++++ multipath-tools-130222/libmultipath/checkers/tur.c +@@ -158,6 +158,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void cleanup_context(struct tur_checker_context *ct) + { + pthread_mutex_destroy(&ct->lock); diff --git a/SOURCES/0267-RHBZ-1661156-powermax-config.patch b/SOURCES/0267-RHBZ-1661156-powermax-config.patch new file mode 100644 index 0000000..5b90501 --- /dev/null +++ b/SOURCES/0267-RHBZ-1661156-powermax-config.patch @@ -0,0 +1,23 @@ +--- + libmultipath/hwtable.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +Index: multipath-tools-130222/libmultipath/hwtable.c +=================================================================== +--- multipath-tools-130222.orig/libmultipath/hwtable.c ++++ multipath-tools-130222/libmultipath/hwtable.c +@@ -1194,6 +1194,14 @@ static struct hwentry default_hw[] = { + .detect_prio = DETECT_PRIO_ON, + .checker_name = NONE, + }, ++ { ++ .vendor = "NVME", ++ .product = "^EMC PowerMax_", ++ .uid_attribute = "ID_WWN", ++ .pgpolicy = MULTIBUS, ++ .checker_name = NONE, ++ .prio_name = DEFAULT_PRIO, ++ }, + /* + * EOL + */ diff --git a/SOURCES/0268-RHBZ-1721855-mpathpersist-fixes.patch b/SOURCES/0268-RHBZ-1721855-mpathpersist-fixes.patch new file mode 100644 index 0000000..da7923a --- /dev/null +++ b/SOURCES/0268-RHBZ-1721855-mpathpersist-fixes.patch @@ -0,0 +1,122 @@ +--- + mpathpersist/main.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +Index: multipath-tools-130222/mpathpersist/main.c +=================================================================== +--- multipath-tools-130222.orig/mpathpersist/main.c ++++ multipath-tools-130222/mpathpersist/main.c +@@ -141,7 +141,8 @@ static int do_batch_file(const char *bat + + static int handle_args(int argc, char * argv[], int nline) + { +- int fd, c; ++ int c; ++ int fd = -1; + const char *device_name = NULL; + int num_prin_sa = 0; + int num_prout_sa = 0; +@@ -199,7 +200,8 @@ static int handle_args(int argc, char * + if (nline == 0 && 1 != sscanf (optarg, "%d", &loglevel)) + { + fprintf (stderr, "bad argument to '--verbose'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + break; + +@@ -214,6 +216,7 @@ static int handle_args(int argc, char * + + case 'h': + usage (); ++ free(batch_fn); + return 0; + + case 'H': +@@ -236,7 +239,8 @@ static int handle_args(int argc, char * + if (parse_prkey(optarg, ¶m_rk) != 0) + { + fprintf (stderr, "bad argument to '--param-rk'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + ++num_prout_param; + break; +@@ -245,7 +249,8 @@ static int handle_args(int argc, char * + if (parse_prkey(optarg, ¶m_sark) != 0) + { + fprintf (stderr, "bad argument to '--param-sark'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + ++num_prout_param; + break; +@@ -264,7 +269,8 @@ static int handle_args(int argc, char * + if (1 != sscanf (optarg, "%x", &prout_type)) + { + fprintf (stderr, "bad argument to '--prout-type'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + ++num_prout_param; + break; +@@ -312,7 +318,8 @@ static int handle_args(int argc, char * + case 'X': + if (0 != construct_transportid(optarg, transportids, num_transport)) { + fprintf(stderr, "bad argument to '--transport-id'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + + ++num_transport; +@@ -320,12 +327,13 @@ static int handle_args(int argc, char * + + case 'l': + if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) { +- fprintf(stderr, "bad argument to '--alloc-length'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ fprintf(stderr, "bad argument to '--alloc-length'\n"); ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) { +- fprintf(stderr, "'--alloc-length' argument exceeds maximum" +- " limit(%d)\n", MPATH_MAX_PARAM_LEN); +- return MPATH_PR_SYNTAX_ERROR; ++ fprintf(stderr, "'--alloc-length' argument exceeds maximum limit(%d)\n", MPATH_MAX_PARAM_LEN); ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + break; + +@@ -465,14 +473,14 @@ static int handle_args(int argc, char * + { + fprintf (stderr, "failed to allocate PRIN response buffer\n"); + ret = MPATH_PR_OTHER; +- goto out; ++ goto out_fd; + } + + ret = __mpath_persistent_reserve_in (fd, prin_sa, resp, noisy); + if (ret != MPATH_PR_SUCCESS ) + { + fprintf (stderr, "Persistent Reserve IN command failed\n"); +- goto out; ++ goto out_fd; + } + + switch(prin_sa) +@@ -552,8 +560,8 @@ static int handle_args(int argc, char * + printf("PR out: command failed\n"); + } + ++out_fd: + close (fd); +- + out : + if (ret == MPATH_PR_SYNTAX_ERROR) { + free(batch_fn); diff --git a/SOURCES/multipath.conf b/SOURCES/multipath.conf new file mode 100644 index 0000000..32589c3 --- /dev/null +++ b/SOURCES/multipath.conf @@ -0,0 +1,92 @@ +# This is a basic configuration file with some examples, for device mapper +# multipath. +# +# For a complete list of the default configuration values, run either +# multipath -t +# or +# multipathd show config +# +# For a list of configuration options with descriptions, see the multipath.conf +# man page + +## By default, devices with vendor = "IBM" and product = "S/390.*" are +## blacklisted. To enable mulitpathing on these devies, uncomment the +## following lines. +#blacklist_exceptions { +# device { +# vendor "IBM" +# product "S/390.*" +# } +#} + +## Use user friendly names, instead of using WWIDs as names. +defaults { + user_friendly_names yes + find_multipaths yes +} +## +## Here is an example of how to configure some standard options. +## +# +#defaults { +# polling_interval 10 +# path_selector "round-robin 0" +# path_grouping_policy multibus +# uid_attribute ID_SERIAL +# prio alua +# path_checker readsector0 +# rr_min_io 100 +# max_fds 8192 +# rr_weight priorities +# failback immediate +# no_path_retry fail +# user_friendly_names yes +#} +## +## The wwid line in the following blacklist section is shown as an example +## of how to blacklist devices by wwid. The 2 devnode lines are the +## compiled in default blacklist. If you want to blacklist entire types +## of devices, such as all scsi devices, you should use a devnode line. +## However, if you want to blacklist specific devices, you should use +## a wwid line. Since there is no guarantee that a specific device will +## not change names on reboot (from /dev/sda to /dev/sdb for example) +## devnode lines are not recommended for blacklisting specific devices. +## +#blacklist { +# wwid 26353900f02796769 +# devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" +# devnode "^hd[a-z]" +#} +#multipaths { +# multipath { +# wwid 3600508b4000156d700012000000b0000 +# alias yellow +# path_grouping_policy multibus +# path_selector "round-robin 0" +# failback manual +# rr_weight priorities +# no_path_retry 5 +# } +# multipath { +# wwid 1DEC_____321816758474 +# alias red +# } +#} +#devices { +# device { +# vendor "COMPAQ " +# product "HSV110 (C)COMPAQ" +# path_grouping_policy multibus +# path_checker readsector0 +# path_selector "round-robin 0" +# hardware_handler "0" +# failback 15 +# rr_weight priorities +# no_path_retry queue +# } +# device { +# vendor "COMPAQ " +# product "MSA1000 " +# path_grouping_policy multibus +# } +#} diff --git a/SPECS/device-mapper-multipath.spec b/SPECS/device-mapper-multipath.spec new file mode 100644 index 0000000..78482c0 --- /dev/null +++ b/SPECS/device-mapper-multipath.spec @@ -0,0 +1,2161 @@ +Summary: Tools to manage multipath devices using device-mapper +Name: device-mapper-multipath +Version: 0.4.9 +Release: 130%{?dist} +License: GPL+ +Group: System Environment/Base +URL: http://christophe.varoqui.free.fr/ + +Source0: multipath-tools-130222.tgz +Source1: multipath.conf +Patch0001: 0001-RH-dont_start_with_no_config.patch +Patch0002: 0002-RH-multipath.rules.patch +Patch0003: 0003-RH-Make-build-system-RH-Fedora-friendly.patch +Patch0004: 0004-RH-multipathd-blacklist-all-by-default.patch +Patch0005: 0005-RH-add-mpathconf.patch +Patch0006: 0006-RH-add-find-multipaths.patch +Patch0007: 0007-RH-add-hp_tur-checker.patch +Patch0008: 0008-RH-revert-partition-changes.patch +Patch0009: 0009-RH-RHEL5-style-partitions.patch +Patch0010: 0010-RH-dont-remove-map-on-enomem.patch +Patch0011: 0011-RH-deprecate-uid-gid-mode.patch +Patch0012: 0012-RH-kpartx-msg.patch +Patch0013: 0013-RHBZ-883981-cleanup-rpmdiff-issues.patch +Patch0014: 0014-RH-handle-other-sector-sizes.patch +Patch0015: 0015-RH-fix-output-buffer.patch +Patch0016: 0016-RH-dont-print-ghost-messages.patch +#Patch0017: 0017-RH-fix-sigusr1.patch +Patch0018: 0018-RH-fix-factorize.patch +Patch0019: 0019-RH-fix-sockets.patch +Patch0020: 0020-RHBZ-907360-static-pthread-init.patch +Patch0021: 0021-RHBZ-919119-respect-kernel-cmdline.patch +Patch0022: 0022-RH-multipathd-check-wwids.patch +Patch0023: 0023-RH-multipath-wipe-wwid.patch +Patch0024: 0024-RH-multipath-wipe-wwids.patch +Patch0025: 0025-UPBZ-916668_add_maj_min.patch +Patch0026: 0026-fix-checker-time.patch +Patch0027: 0027-RH-get-wwid.patch +Patch0028: 0028-RHBZ-929078-refresh-udev-dev.patch +Patch0029: 0029-RH-no-prio-put-msg.patch +Patch0030: 0030-RHBZ-916528-override-queue-no-daemon.patch +Patch0031: 0031-RHBZ-957188-kpartx-use-dm-name.patch +Patch0032: 0032-RHBZ-956464-mpathconf-defaults.patch +Patch0033: 0033-RHBZ-829963-e-series-conf.patch +Patch0034: 0034-RHBZ-851416-mpathconf-display.patch +Patch0035: 0035-RHBZ-891921-list-mpp.patch +Patch0036: 0036-RHBZ-949239-load-multipath-module.patch +Patch0037: 0037-RHBZ-768873-fix-rename.patch +Patch0038: 0038-RHBZ-799860-netapp-config.patch +Patch0039: 0039-RH-detect-prio-fix.patch +Patch0040: 0040-RH-bindings-fix.patch +Patch0041: 0041-RH-check-for-erofs.patch +Patch0042: 0042-UP-fix-signal-handling.patch +Patch0043: 0043-RH-signal-waiter.patch +Patch0044: 0044-RHBZ-976688-fix-wipe-wwids.patch +Patch0045: 0045-RHBZ-977297-man-page-fix.patch +Patch0046: 0046-RHBZ-883981-move-udev-rules.patch +Patch0047: 0047-RHBZ-kpartx-read-only-loop-devs.patch +Patch0048: 0048-RH-print-defaults.patch +Patch0049: 0049-RH-remove-ID_FS_TYPE.patch +Patch0050: 0050-RH-listing-speedup.patch +Patch0051: 0051-UP-fix-cli-resize.patch +Patch0052: 0052-RH-fix-bad-derefs.patch +Patch0053: 0053-UP-fix-failback.patch +Patch0054: 0054-UP-keep-udev-ref.patch +Patch0055: 0055-UP-handle-quiesced-paths.patch +Patch0056: 0056-UP-alua-prio-fix.patch +Patch0057: 0057-UP-fix-tmo.patch +Patch0058: 0058-UP-fix-failback.patch +Patch0059: 0059-UP-flush-failure-queueing.patch +Patch0060: 0060-UP-uevent-loop-udev.patch +Patch0061: 0061-RH-display-find-mpaths.patch +Patch0062: 0062-RH-dont-free-vecs.patch +Patch0063: 0063-RH-fix-warning.patch +Patch0064: 0064-RHBZ-1010040-fix-ID_FS-attrs.patch +Patch0065: 0065-UPBZ-995538-fail-rdac-on-unavailable.patch +Patch0066: 0066-UP-dos-4k-partition-fix.patch +Patch0067: 0067-RHBZ-1022899-fix-udev-partition-handling.patch +Patch0068: 0068-RHBZ-1034578-label-partition-devices.patch +Patch0069: 0069-UPBZ-1033791-improve-rdac-checker.patch +Patch0070: 0070-RHBZ-1036503-blacklist-td-devs.patch +Patch0071: 0071-RHBZ-1031546-strip-dev.patch +Patch0072: 0072-RHBZ-1039199-check-loop-control.patch +Patch0073: 0073-RH-update-build-flags.patch +Patch0074: 0074-RHBZ-1056976-dm-mpath-rules.patch +Patch0075: 0075-RHBZ-1056976-reload-flag.patch +Patch0076: 0076-RHBZ-1056686-add-hw_str_match.patch +Patch0077: 0077-RHBZ-1054806-mpathconf-always-reload.patch +Patch0078: 0078-RHBZ-1054044-fix-mpathconf-manpage.patch +Patch0079: 0079-RHBZ-1070581-add-wwid-option.patch +Patch0080: 0080-RHBZ-1075796-cmdline-wwid.patch +Patch0081: 0081-RHBZ-1066264-check-prefix-on-rename.patch +Patch0082: 0082-UPBZ-1109995-no-sync-turs-on-pthread_cancel.patch +Patch0083: 0083-RHBZ-1080055-orphan-paths-on-reload.patch +Patch0084: 0084-RHBZ-1110000-multipath-man.patch +Patch0085: 0085-UPBZ-1110006-datacore-config.patch +Patch0086: 0086-RHBZ-1110007-orphan-path-on-failed-add.patch +Patch0087: 0087-RHBZ-1110013-config-error-checking.patch +Patch0088: 0088-RHBZ-1069811-configurable-prio-timeout.patch +Patch0089: 0089-RHBZ-1110016-add-noasync-option.patch +Patch0090: 0090-UPBZ-1080038-reorder-paths-for-round-robin.patch +Patch0091: 0091-RHBZ-1069584-fix-empty-values-fast-io-fail-and-dev-loss.patch +Patch0092: 0092-UPBZ-1104605-reload-on-rename.patch +Patch0093: 0093-UPBZ-1086825-user-friendly-name-remap.patch +Patch0094: 0094-RHBZ-1086825-cleanup-remap.patch +Patch0095: 0095-RHBZ-1127944-xtremIO-config.patch +Patch0096: 0096-RHBZ-979474-new-wildcards.patch +Patch0097: 0097-RH-fix-coverity-errors.patch +Patch0098: 0098-UPBZ-1067171-mutipath-i.patch +Patch0099: 0099-RH-add-all-devs.patch +Patch0100: 0100-RHBZ-1067171-multipath-i-update.patch +Patch0101: 0101-RH-cleanup-partmaps-code.patch +Patch0102: 0102-RHBZ-631009-deferred-remove.patch +Patch0103: 0103-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch +Patch0104: 0104-RHBZ-1159337-fix-double-free.patch +Patch0105: 0105-RHBZ-1180032-find-multipaths-man.patch +Patch0106: 0106-RHBZ-1169935-no-new-devs.patch +Patch0107: 0107-RH-adapter-name-wildcard.patch +Patch0108: 0108-RHBZ-1153832-kpartx-remove-devs.patch +Patch0109: 0109-RH-read-only-bindings.patch +Patch0110: 0110-RHBZ-blacklist-vd-devs.patch +Patch0111: 0111-RH-dont-show-pg-timeout.patch +Patch0112: 0112-RHBZ-1194917-add-config_dir-option.patch +Patch0113: 0113-RHBZ-1194917-cleanup.patch +Patch0114: 0114-RHBZ-1196394-delayed-reintegration.patch +Patch0115: 0115-RHBZ-1198418-fix-double-free.patch +Patch0116: 0116-UPBZ-1188179-dell-36xxi.patch +Patch0117: 0117-RHBZ-1198424-autodetect-clariion-alua.patch +Patch0118: 0118-UPBZ-1200738-update-eternus-config.patch +Patch0119: 0119-RHBZ-1081397-save-alua-info.patch +Patch0120: 0120-RHBZ-1043093-realloc-fix.patch +Patch0121: 0121-RHBZ-1197234-rules-fix.patch +Patch0122: 0122-RHBZ-1212590-dont-use-var.patch +Patch0123: 0123-UPBZ-1166072-fix-path-offline.patch +Patch0124: 0124-RHBZ-1209275-retrigger-uevents.patch +Patch0125: 0125-RHBZ-1153832-kpartx-delete.patch +Patch0126: 0126-RHBZ-1211383-alias-collision.patch +Patch0127: 0127-RHBZ-1201030-use-blk-availability.patch +Patch0128: 0128-RHBZ-1222123-mpathconf-allow.patch +Patch0129: 0129-UPBZ-1254292-iscsi-targetname.patch +Patch0130: 0130-RHBZ-1259523-host_name_len.patch +Patch0131: 0131-UPBZ-1259831-lock-retry.patch +Patch0132: 0132-RHBZ-1296979-fix-define.patch +Patch0133: 0133-RHBZ-1241774-sun-partition-numbering.patch +Patch0134: 0134-RHBZ-1241528-check-mpath-prefix.patch +Patch0135: 0135-RHBZ-1299600-path-dev-uevents.patch +Patch0136: 0136-RHBZ-1304687-wait-for-map-add.patch +Patch0137: 0137-RHBZ-1280524-clear-chkr-msg.patch +Patch0138: 0138-RHBZ-1288660-fix-mpathconf-allow.patch +Patch0139: 0139-RHBZ-1273173-queue-no-daemon-doc.patch +Patch0140: 0140-RHBZ-1299647-fix-help.patch +Patch0141: 0141-RHBZ-1303953-mpathpersist-typo.patch +Patch0142: 0142-RHBZ-1283750-kpartx-fix.patch +Patch0143: 0143-RHBZ-1299648-kpartx-sync.patch +Patch0144: 0144-RHBZ-1299652-alua-pref-arg.patch +Patch0145: 0145-UP-resize-help-msg.patch +Patch0146: 0146-UPBZ-1299651-raw-output.patch +Patch0147: 0147-RHBZ-1272620-fail-rm-msg.patch +Patch0148: 0148-RHBZ-1292599-verify-before-remove.patch +Patch0149: 0149-RHBZ-1292599-restore-removed-parts.patch +Patch0150: 0150-RHBZ-1253913-fix-startup-msg.patch +Patch0151: 0151-RHBZ-1297456-weighted-fix.patch +Patch0152: 0152-RHBZ-1269293-fix-blk-unit-file.patch +Patch0153: 0153-RH-fix-i686-size-bug.patch +Patch0154: 0154-UPBZ-1291406-disable-reinstate.patch +Patch0155: 0155-UPBZ-1300415-PURE-config.patch +Patch0156: 0156-UPBZ-1313324-dont-fail-discovery.patch +Patch0157: 0157-RHBZ-1319853-multipath-c-error-msg.patch +Patch0158: 0158-RHBZ-1318581-timestamp-doc-fix.patch +Patch0159: 0159-UPBZ-1255885-udev-waits.patch +Patch0160: 0160-RH-udev-flags.patch +Patch0161: 0161-RHBZ-1311659-no-kpartx.patch +Patch0162: 0162-RHBZ-1333331-huawei-config.patch +Patch0163: 0163-UPBZ-1333492-resize-map.patch +Patch0164: 0164-RHBZ-1311463-dos-part-rollover.patch +Patch0165: 0165-UPBZ-1341748-MSA-2040-conf.patch +Patch0166: 0166-RHBZ-1323429-dont-allow-new-wwid.patch +Patch0167: 0167-RHBZ-1335176-fix-show-cmds.patch +Patch0168: 0168-RHBZ-1347769-shared-lock.patch +Patch0169: 0169-UPBZ-1353357-json-output.patch +Patch0170: 0170-UPBZ-1352925-fix-typo.patch +Patch0171: 0171-UPBZ-1356651-allow-zero-size.patch +Patch0172: 0172-RHBZ-1350931-no-active-add.patch +Patch0173: 0173-RH-update-man-page.patch +Patch0174: 0174-RHBZ-1362396-modprobe.patch +Patch0175: 0175-RHBZ-1357382-ordering.patch +Patch0176: 0176-RHBZ-1363830-fix-rename.patch +Patch0177: 0177-libmultipath-correctly-initialize-pp-sg_id.patch +Patch0178: 0178-libmultipath-add-rbd-discovery.patch +Patch0179: 0179-multipath-tools-add-checker-callout-to-repair-path.patch +Patch0180: 0180-multipath-tools-Add-rbd-checker.patch +Patch0181: 0181-multipath-tools-Add-rbd-to-the-hwtable.patch +Patch0182: 0182-multipath-tools-check-for-initialized-checker-before.patch +Patch0183: 0183-multipathd-Don-t-call-repair-on-blacklisted-path.patch +Patch0184: 0184-rbd-fix-sync-repair-support.patch +Patch0185: 0185-rbd-check-for-nonshared-clients.patch +Patch0186: 0186-rbd-check-for-exclusive-lock-enabled.patch +Patch0187: 0187-rbd-fixup-log-messages.patch +Patch0188: 0188-RHBZ-1368501-dont-exit.patch +Patch0189: 0189-RHBZ-1368211-remove-retries.patch +Patch0190: 0190-RHBZ-1380602-rbd-lock-on-read.patch +Patch0191: 0191-RHBZ-1169168-disable-changed-paths.patch +Patch0192: 0192-RHBZ-1362409-infinibox-config.patch +Patch0194: 0194-RHBZ-1351964-kpartx-recurse.patch +Patch0195: 0195-RHBZ-1359510-no-daemon-msg.patch +Patch0196: 0196-RHBZ-1239173-dont-set-flag.patch +Patch0197: 0197-RHBZ-1394059-max-sectors-kb.patch +Patch0198: 0198-RHBZ-1372032-detect-path-checker.patch +Patch0199: 0199-RHBZ-1279355-3pardata-config.patch +Patch0200: 0200-RHBZ-1402092-orphan-status.patch +Patch0201: 0201-RHBZ-1403552-silence-warning.patch +Patch0202: 0202-RHBZ-1362120-skip-prio.patch +Patch0203: 0203-RHBZ-1363718-add-msgs.patch +Patch0204: 0204-RHBZ-1406226-nimble-config.patch +Patch0205: 0205-RHBZ-1416569-reset-stats.patch +Patch0206: 0206-RHBZ-1239173-pt2-no-paths.patch +Patch0207: 0207-UP-add-libmpathcmd.patch +Patch0208: 0208-UPBZ-1430097-multipathd-IPC-changes.patch +Patch0209: 0209-UPBZ-1430097-multipath-C-API.patch +Patch0210: 0210-RH-fix-uninstall.patch +Patch0211: 0211-RH-strlen-fix.patch +Patch0212: 0212-RHBZ-1431562-for-read-only.patch +Patch0213: 0213-RHBZ-1430908-merge-dell-configs.patch +Patch0214: 0214-RHBZ-1392115-set-paths-not-ready.patch +Patch0215: 0215-RHBZ-1444194-fix-check-partitions.patch +Patch0216: 0216-RHBZ-1448562-fix-reserve.patch +Patch0217: 0217-RHBZ-1448576-3PAR-config.patch +Patch0218: 0218-RHBZ-1459370-add-feature-fix.patch +Patch0219: 0219-RHBZ-1448970-fix-resize.patch +Patch0220: 0220-RHBZ-1448223-fix-kpartx.patch +Patch0221: 0221-RH-harden-files.patch +Patch0222: 0222-RHBZ-1457288-fix-show-maps-json.patch +Patch0223: 0223-RHBZ-1452210-unpriv-sgio.patch +Patch0224: 0224-RHBZ-1452210-prkey.patch +Patch0225: 0225-RH-udevdir.patch +Patch0226: 0226-RH-allow-overrides-section.patch +Patch0227: 0227-RHBZ-1465773-fix-path-delay-msg.patch +Patch0228: 0228-RHBZ-1464634-hauwei-config-update.patch +Patch0229: 0229-RHBZ-1467987-poll-on-udev-monitor.patch +Patch0230: 0230-UP-allow-invalid-creates.patch +Patch0231: 0231-RHBZ-1458852-delay-readying.patch +Patch0232: 0232-RHBZ-1456955-property-blacklist.patch +Patch0233: 0233-RHBZ-1451852-1482629-nimble-config.patch +Patch0234: 0234-RHBZ-1500109-doc-typo.patch +Patch0235: 0235-RHBZ-1480638-NVMe-support.patch +Patch0236: 0236-RHBZ-1525348-fix-msg.patch +Patch0237: 0237-RHBZ-1526876-show-sysfs-state.patch +Patch0238: 0238-RHBZ-1508483-mpathconf-info.patch +Patch0239: 0239-RHBZ-1544958-client-timeout.patch +Patch0240: 0240-UPBZ-1568902-id_size.patch +Patch0241: 0241-RHBZ-1554516-show-path-failures.patch +Patch0242: 0242-RHBZ-1541116-all-tg-pt.patch +Patch0243: 0243-RHBZ-1498724-save-persist-options.patch +Patch0244: 0244-RHBZ-1562247-remove-rbd.patch +Patch0245: 0245-RHBZ-1584228-fix-readsector0_size.patch +Patch0246: 0246-RHBZ-1593459-add-transport-blacklist.patch +Patch0247: 0247-RHBZ-1585824-mpathconf-allow-doc.patch +Patch0248: 0248-RHBZ-1594360-fix-param-rk-doc.patch +Patch0249: 0249-RHBZ-1610263-mpathpersist-max-fds.patch +Patch0250: 0250-RHBZ-1610867-rescan-change.patch +Patch0251: 0251-RHBZ-1614011-discovery-timeout.patch +Patch0252: 0252-RHBZ-1623595-cmd-error-status.patch +Patch0253: 0253-RHBZ-1618549-mix-hw-handler.patch +Patch0254: 0254-RHBZ-1635819-fix-mpathpersist-crash.patch +Patch0255: 0255-RHBZ-1638651-marginal-path.patch +Patch0256: 0256-RHBZ-1672175-retry-no-fd-paths.patch +Patch0257: 0257-RHBZ-1679556-dont-check-dm-devices.patch +Patch0258: 0258-RHBZ-1634183-ANA-prioritizer.patch +Patch0259: 0259-RHBZ-1701604-fix-nr-active.patch +Patch0260: 0260-RHBZ-1634183-prio-fixes.patch +#Patch0261: 0261-RHBZ-1714506-skip-blacklisted-paths.patch +Patch0262: 0262-RHBZ-1699486-reload-with-failed-paths.patch +Patch0263: 0263-RHBZ-1686708-nvme-hcil.patch +Patch0264: 0264-RHBZ-1699441-de-series-config.patch +Patch0265: 0265-RHBZ-1721855-mpathpersist-speedup.patch +Patch0266: 0266-RHBZ-1696817-fix-emc-checker.patch +Patch0267: 0267-RHBZ-1661156-powermax-config.patch +Patch0268: 0268-RHBZ-1721855-mpathpersist-fixes.patch + +# runtime +Requires: %{name}-libs = %{version}-%{release} +Requires: kpartx = %{version}-%{release} +Requires: device-mapper >= 7:1.02.96 +Requires: initscripts +Requires(post): systemd-units systemd-sysv chkconfig +Requires(preun): systemd-units +Requires(postun): systemd-units + +# build/setup +BuildRequires: libaio-devel, device-mapper-devel >= 1.02.89 +BuildRequires: libselinux-devel, libsepol-devel +BuildRequires: readline-devel, ncurses-devel +BuildRequires: systemd-units, systemd-devel +BuildRequires: json-c-devel, perl, pkgconfig +%ifarch x86_64 +BuildRequires: librados2-devel +%endif + +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +%description +%{name} provides tools to manage multipath devices by +instructing the device-mapper multipath kernel module what to do. +The tools are : +* multipath - Scan the system for multipath devices and assemble them. +* multipathd - Detects when paths fail and execs multipath to update things. + +%package libs +Summary: The %{name} modules and shared library +License: GPL+ +Group: System Environment/Libraries + +%description libs +The %{name}-libs provides the path checker +and prioritizer modules. It also contains the libmpathpersist and +libmpathcmd shared libraries, as well as multipath's internal library, +libmultipath. + +%package devel +Summary: Development libraries and headers for %{name} +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} + +%description devel +This package contains the files need to develop applications that use +device-mapper-multipath's lbmpathpersist and libmpathcmd libraries. + +%package sysvinit +Summary: SysV init script for device-mapper-multipath +Group: System Environment/Libraries + +%description sysvinit +SysV style init script for device-mapper-multipth. It needs to be +installed only if systemd is not used as the system init process. + +%package -n kpartx +Summary: Partition device manager for device-mapper devices +Group: System Environment/Base + +%description -n kpartx +kpartx manages partition creation and removal for device-mapper devices. + +%package -n libdmmp +Summary: device-mapper-multipath C API library +Group: System Environment/Libraries +Requires: json-c +Requires: %{name} = %{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} + +%description -n libdmmp +This package contains the shared library for the device-mapper-multipath +C API library. + +%package -n libdmmp-devel +Summary: device-mapper-multipath C API library headers +Group: Development/Libraries +Requires: pkgconfig +Requires: libdmmp = %{version}-%{release} + +%description -n libdmmp-devel +This package contains the files needed to develop applications that use +device-mapper-multipath's libdmmp C API library + +%prep +%setup -q -n multipath-tools-130222 +%patch0001 -p1 +%patch0002 -p1 +%patch0003 -p1 +%patch0004 -p1 +%patch0005 -p1 +%patch0006 -p1 +%patch0007 -p1 +%patch0008 -p1 +%patch0009 -p1 +%patch0010 -p1 +%patch0011 -p1 +%patch0012 -p1 +%patch0013 -p1 +%patch0014 -p1 +%patch0015 -p1 +%patch0016 -p1 +# %%patch0017 -p1 +%patch0018 -p1 +%patch0019 -p1 +%patch0020 -p1 +%patch0021 -p1 +%patch0022 -p1 +%patch0023 -p1 +%patch0024 -p1 +%patch0025 -p1 +%patch0026 -p1 +%patch0027 -p1 +%patch0028 -p1 +%patch0029 -p1 +%patch0030 -p1 +%patch0031 -p1 +%patch0032 -p1 +%patch0033 -p1 +%patch0034 -p1 +%patch0035 -p1 +%patch0036 -p1 +%patch0037 -p1 +%patch0038 -p1 +%patch0039 -p1 +%patch0040 -p1 +%patch0041 -p1 +%patch0042 -p1 +%patch0043 -p1 +%patch0044 -p1 +%patch0045 -p1 +%patch0046 -p1 +%patch0047 -p1 +%patch0048 -p1 +%patch0049 -p1 +%patch0050 -p1 +%patch0051 -p1 +%patch0052 -p1 +%patch0053 -p1 +%patch0054 -p1 +%patch0055 -p1 +%patch0056 -p1 +%patch0057 -p1 +%patch0058 -p1 +%patch0059 -p1 +%patch0060 -p1 +%patch0061 -p1 +%patch0062 -p1 +%patch0063 -p1 +%patch0064 -p1 +%patch0065 -p1 +%patch0066 -p1 +%patch0067 -p1 +%patch0068 -p1 +%patch0069 -p1 +%patch0070 -p1 +%patch0071 -p1 +%patch0072 -p1 +%patch0073 -p1 +%patch0074 -p1 +%patch0075 -p1 +%patch0076 -p1 +%patch0077 -p1 +%patch0078 -p1 +%patch0079 -p1 +%patch0080 -p1 +%patch0081 -p1 +%patch0082 -p1 +%patch0083 -p1 +%patch0084 -p1 +%patch0085 -p1 +%patch0086 -p1 +%patch0087 -p1 +%patch0088 -p1 +%patch0089 -p1 +%patch0090 -p1 +%patch0091 -p1 +%patch0092 -p1 +%patch0093 -p1 +%patch0094 -p1 +%patch0095 -p1 +%patch0096 -p1 +%patch0097 -p1 +%patch0098 -p1 +%patch0099 -p1 +%patch0100 -p1 +%patch0101 -p1 +%patch0102 -p1 +%patch0103 -p1 +%patch0104 -p1 +%patch0105 -p1 +%patch0106 -p1 +%patch0107 -p1 +%patch0108 -p1 +%patch0109 -p1 +%patch0110 -p1 +%patch0111 -p1 +%patch0112 -p1 +%patch0113 -p1 +%patch0114 -p1 +%patch0115 -p1 +%patch0116 -p1 +%patch0117 -p1 +%patch0118 -p1 +%patch0119 -p1 +%patch0120 -p1 +%patch0121 -p1 +%patch0122 -p1 +%patch0123 -p1 +%patch0124 -p1 +%patch0125 -p1 +%patch0126 -p1 +%patch0127 -p1 +%patch0128 -p1 +%patch0129 -p1 +%patch0130 -p1 +%patch0131 -p1 +%patch0132 -p1 +%patch0133 -p1 +%patch0134 -p1 +%patch0135 -p1 +%patch0136 -p1 +%patch0137 -p1 +%patch0138 -p1 +%patch0139 -p1 +%patch0140 -p1 +%patch0141 -p1 +%patch0142 -p1 +%patch0143 -p1 +%patch0144 -p1 +%patch0145 -p1 +%patch0146 -p1 +%patch0147 -p1 +%patch0148 -p1 +%patch0149 -p1 +%patch0150 -p1 +%patch0151 -p1 +%patch0152 -p1 +%patch0153 -p1 +%patch0154 -p1 +%patch0155 -p1 +%patch0156 -p1 +%patch0157 -p1 +%patch0158 -p1 +%patch0159 -p1 +%patch0160 -p1 +%patch0161 -p1 +%patch0162 -p1 +%patch0163 -p1 +%patch0164 -p1 +%patch0165 -p1 +%patch0166 -p1 +%patch0167 -p1 +%patch0168 -p1 +%patch0169 -p1 +%patch0170 -p1 +%patch0171 -p1 +%patch0172 -p1 +%patch0173 -p1 +%patch0174 -p1 +%patch0175 -p1 +%patch0176 -p1 +%patch0177 -p1 +%patch0178 -p1 +%patch0179 -p1 +%patch0180 -p1 +%patch0181 -p1 +%patch0182 -p1 +%patch0183 -p1 +%patch0184 -p1 +%patch0185 -p1 +%patch0186 -p1 +%patch0187 -p1 +%patch0188 -p1 +%patch0189 -p1 +%patch0190 -p1 +%patch0191 -p1 +%patch0192 -p1 +%patch0194 -p1 +%patch0195 -p1 +%patch0196 -p1 +%patch0197 -p1 +%patch0198 -p1 +%patch0199 -p1 +%patch0200 -p1 +%patch0201 -p1 +%patch0202 -p1 +%patch0203 -p1 +%patch0204 -p1 +%patch0205 -p1 +%patch0206 -p1 +%patch0207 -p1 +%patch0208 -p1 +%patch0209 -p1 +%patch0210 -p1 +%patch0211 -p1 +%patch0212 -p1 +%patch0213 -p1 +%patch0214 -p1 +%patch0215 -p1 +%patch0216 -p1 +%patch0217 -p1 +%patch0218 -p1 +%patch0219 -p1 +%patch0220 -p1 +%patch0221 -p1 +%patch0222 -p1 +%patch0223 -p1 +%patch0224 -p1 +%patch0225 -p1 +%patch0226 -p1 +%patch0227 -p1 +%patch0228 -p1 +%patch0229 -p1 +%patch0230 -p1 +%patch0231 -p1 +%patch0232 -p1 +%patch0233 -p1 +%patch0234 -p1 +%patch0235 -p1 +%patch0236 -p1 +%patch0237 -p1 +%patch0238 -p1 +%patch0239 -p1 +%patch0240 -p1 +%patch0241 -p1 +%patch0242 -p1 +%patch0243 -p1 +%patch0244 -p1 +%patch0245 -p1 +%patch0246 -p1 +%patch0247 -p1 +%patch0248 -p1 +%patch0249 -p1 +%patch0250 -p1 +%patch0251 -p1 +%patch0252 -p1 +%patch0253 -p1 +%patch0254 -p1 +%patch0255 -p1 +%patch0256 -p1 +%patch0257 -p1 +%patch0258 -p1 +%patch0259 -p1 +%patch0260 -p1 +# %patch0261 -p1 +%patch0262 -p1 +%patch0263 -p1 +%patch0264 -p1 +%patch0265 -p1 +%patch0266 -p1 +%patch0267 -p1 +%patch0268 -p1 +cp %{SOURCE1} . + +%build +%define _udevdir %{_prefix}/lib/udev/rules.d +%define _libmpathdir %{_libdir}/multipath +%define _pkgconfdir %{_libdir}/pkgconfig +make %{?_smp_mflags} LIB=%{_lib} + +%install +rm -rf %{buildroot} + +make install \ + DESTDIR=%{buildroot} \ + bindir=%{_sbindir} \ + syslibdir=%{_libdir} \ + libdir=%{_libmpathdir} \ + rcdir=%{_initrddir} \ + unitdir=%{_unitdir} \ + includedir=%{_includedir} \ + pkgconfdir=%{_pkgconfdir} + +# tree fix up +install -d %{buildroot}/etc/multipath + +%clean +rm -rf %{buildroot} + +%post +%systemd_post multipathd.service + +%preun +%systemd_preun multipathd.service + +%postun +if [ $1 -ge 1 ] ; then + /sbin/multipathd forcequeueing daemon > /dev/null 2>&1 || : +fi +%systemd_postun_with_restart multipathd.service + +%triggerun -- %{name} < 0.4.9-37 +# make sure old systemd symlinks are removed after changing the [Install] +# section in multipathd.service from multi-user.target to sysinit.target +/bin/systemctl --quiet is-enabled multipathd.service >/dev/null 2>&1 && /bin/systemctl reenable multipathd.service ||: + +%triggerpostun -n %{name}-sysvinit -- %{name} < 0.4.9-16 +/sbin/chkconfig --add mdmonitor >/dev/null 2>&1 || : + +%files +%defattr(-,root,root,-) +%{_sbindir}/multipath +%{_sbindir}/multipathd +%{_sbindir}/mpathconf +%{_sbindir}/mpathpersist +%{_unitdir}/multipathd.service +%{_mandir}/man5/multipath.conf.5.gz +%{_mandir}/man8/multipath.8.gz +%{_mandir}/man8/multipathd.8.gz +%{_mandir}/man8/mpathconf.8.gz +%{_mandir}/man8/mpathpersist.8.gz +%config %{_udevdir}/62-multipath.rules +%config %{_udevdir}/11-dm-mpath.rules +%doc AUTHOR COPYING FAQ +%doc multipath.conf +%dir /etc/multipath + +%files libs +%defattr(-,root,root,-) +%doc AUTHOR COPYING +%{_libdir}/libmultipath.so +%{_libdir}/libmultipath.so.* +%{_libdir}/libmpathpersist.so.* +%{_libdir}/libmpathcmd.so.* +%dir %{_libmpathdir} +%{_libmpathdir}/* + +%post libs -p /sbin/ldconfig + +%postun libs -p /sbin/ldconfig + +%files devel +%defattr(-,root,root,-) +%doc AUTHOR COPYING +%{_libdir}/libmpathpersist.so +%{_libdir}/libmpathcmd.so +%{_includedir}/mpath_cmd.h +%{_includedir}/mpath_persist.h +%{_mandir}/man3/mpath_persistent_reserve_in.3.gz +%{_mandir}/man3/mpath_persistent_reserve_out.3.gz + +%files sysvinit +%{_initrddir}/multipathd + +%files -n kpartx +%defattr(-,root,root,-) +%{_sbindir}/kpartx +%{_mandir}/man8/kpartx.8.gz + +%files -n libdmmp +%defattr(-,root,root,-) +%doc AUTHOR COPYING +%{_libdir}/libdmmp.so.* + +%post -n libdmmp -p /sbin/ldconfig + +%postun -n libdmmp -p /sbin/ldconfig + +%files -n libdmmp-devel +%defattr(-,root,root,-) +%doc AUTHOR COPYING +%{_libdir}/libdmmp.so +%dir %{_includedir}/libdmmp +%{_includedir}/libdmmp/* +%{_mandir}/man3/dmmp_* +%{_mandir}/man3/libdmmp.h.3.gz +%{_pkgconfdir}/libdmmp.pc + +%changelog +* Fri Aug 30 2019 Benjamin Marzinski 0.4.9-130 +- Add 0268-RHBZ-1721855-mpathpersist-fixes.patch + * Fix issues in the mpathpersist speedup code +- Resolves: bz #1721855 + +* Thu Aug 29 2019 Benjamin Marzinski 0.4.9-129 +- Add 0265-RHBZ-1721855-mpathpersist-speedup.patch + * only grab path information from necessary devices, and allow batch files. +- Add 0266-RHBZ-1696817-fix-emc-checker.patch + * fix detection of inactive snapshots +- Add 0267-RHBZ-1661156-powermax-config.patch +- Remove 0261-RHBZ-1714506-skip-blacklisted-paths.patch + * This fix is superseded by 0265-RHBZ-1721855-mpathpersist-speedup.patch +- Resolves: bz #1661156, #1696817, #1721855 + +* Mon Aug 12 2019 Benjamin Marzinski 0.4.9-128 +- Modify 0258-RHBZ-1634183-ANA-prioritizer.patch + * minor change +- Add 0259-RHBZ-1701604-fix-nr-active.patch + * recalculate the number of active paths whenever a path is checked +- Add 0260-RHBZ-1634183-prio-fixes.patch +- Add 0261-RHBZ-1714506-skip-blacklisted-paths.patch + * ignore blacklisted paths in mpathpersist +- Add 0262-RHBZ-1699486-reload-with-failed-paths.patch + * allow forced reloads even if there are no reusable paths +- Add 0263-RHBZ-1686708-nvme-hcil.patch + * make nvme ids work like in upstream +- Add 0264-RHBZ-1699441-de-series-config.patch +- Resolves: bz #1686708, #1699441, #1699486, #1701604, #1714506 + +* Thu Mar 14 2019 Benjamin Marzinski 0.4.9-127 +- Add 0256-RHBZ-1672175-retry-no-fd-paths.patch + * retry adding paths if they couldn't be opened initially +- Add 0257-RHBZ-1679556-dont-check-dm-devices.patch + * don't check if dm devices are multipath paths +- Add 0258-RHBZ-1634183-ANA-prioritizer.patch + * Add NVMe ANA path prioritizer +- Resolves: bz #1634183, #1672175, #1679556 + +* Wed Feb 13 2019 Benjamin Marzinski 0.4.9-126 +- Modify 0255-RHBZ-1638651-marginal-path.patch + * Fix memory leak +- Resolves: bz #1638651 + +* Wed Feb 13 2019 Benjamin Marzinski 0.4.9-125 +- Modify 0250-RHBZ-1610867-rescan-change.patch + * Fix memory Leak +- Modify 0255-RHBZ-1638651-marginal-path.patch + * Fix NULL dereference +- Refresh 0252-RHBZ-1623595-cmd-error-status.patch +- Resolves: bz #1610867, #1638651 + +* Fri Feb 1 2019 Benjamin Marzinski 0.4.9-124 +- Add 0250-RHBZ-1610867-rescan-change.patch + * Update multipath devices on change events. +- Add 0251-RHBZ-1614011-discovery-timeout.patch +- Add 0252-RHBZ-1623595-cmd-error-status.patch +- Add 0253-RHBZ-1618549-mix-hw-handler.patch + * Don't retain attached hw handler when different hw handlers are + attached to different paths +- Add 0254-RHBZ-1635819-fix-mpathpersist-crash.patch +- Add 0255-RHBZ-1638651-marginal-path.patch + * backport marginal_path options from upstream +- Resolves: bz #1610867, #1614011, #1618549, #1623595, #1635819, #1638651 + +* Fri Aug 10 2018 Benjamin Marzinski 0.4.9-123 +- Add 0249-RHBZ-1610263-mpathpersist-max-fds.patch + * make mpathpersist honor max_fds multipath.conf parameter +- Resolves: bz #1610263 + +* Wed Aug 1 2018 Benjamin Marzinski 0.4.9-122 +- Add 0248-RHBZ-1594360-fix-param-rk-doc.patch +- Resolves: bz #1594360 + +* Thu Jun 21 2018 Benjamin Marzinski 0.4.9-121 +- Add 0245-RHBZ-1584228-fix-readsector0_size.patch + * correctly figure IO size +- Add 0246-RHBZ-1593459-add-transport-blacklist.patch + * and new blacklist option, "protocol" +- Add 0247-RHBZ-1585824-mpathconf-allow-doc.patch +- Resolves: bz #1584228, #1585824, #1593459 + +* Wed Jun 6 2018 Benjamin Marzinski 0.4.9-120 +- Add 0237-RHBZ-1526876-show-sysfs-state.patch + * Correctly get sysfs state for multipath -l output +- Add 0238-RHBZ-1508483-mpathconf-info.patch +- Add 0239-RHBZ-1544958-client-timeout.patch + * increase maximum multipathd client reply timeout to 60 seconds +- Add 0240-UPBZ-1568902-id_size.patch + * increase maximum size of product and revision strings to deal with nvme +- Add 0241-RHBZ-1554516-show-path-failures.patch + * add a path failures multipathd path format wildcard +- Add 0242-RHBZ-1541116-all-tg-pt.patch + * add all_tg_pt configuration option to make mpathpersist send only + one registration per host +- Add 0243-RHBZ-1498724-save-persist-options.patch + * allow ":aptpl" to be added to the reservation_key to fix multipathd + aptpl persistent reservation handling +- Add 0244-RHBZ-1562247-remove-rbd.patch + * remove multipath support for rbd +- Resolves: bz #1498724, #1508483, #1526876, #1541116, #1544958, #1554516 +- Resolves: bz #1562247, #1568902 + +* Wed Jan 31 2018 Benjamin Marzinski 0.4.9-119 +- Add 0236-RHBZ-1525348-fix-msg.patch + * reduced message serverity level +- Resolves: bz #1525348 + +* Fri Nov 17 2017 Benjamin Marzinski 0.4.9-118 +- Modify 0224-RHBZ-1452210-prkey.patch + * Improve error checking for mpathpersist +- Resolves: bz #1452210 + +* Thu Nov 16 2017 Benjamin Marzinski 0.4.9-117 +- Modify 0235-RHBZ-1480638-NVMe-support.patch + * remove overly-restrictive uevent filtering +- Resolves: bz #1480638 + +* Tue Oct 31 2017 Benjamin Marzinski 0.4.9-116 +- Add 0235-RHBZ-1480638-NVMe-support.patch + * adds support for multipathing NVMe devices +- Resolves: bz #1480638 + +* Tue Oct 10 2017 Benjamin Marzinski 0.4.9-115 +- Add 0233-RHBZ-1451852-1482629-nimble-config.patch +- Add 0234-RHBZ-1500109-doc-typo.patch +- Remove old triggerun scriptlet (bz1470384) +- Resolves: bz #1451852, #1470384, #1482629, #1500109 + +* Tue Oct 3 2017 Benjamin Marzinski 0.4.9-114 +- Add 0226-RH-allow-overrides-section.patch + * This is a dummy section that exists to help the transition to RHEL8 +- Add 0227-RHBZ-1465773-fix-path-delay-msg.patch +- Add 0228-RHBZ-1464634-hauwei-config-update.patch +- Add 0229-RHBZ-1467987-poll-on-udev-monitor.patch + * Do poll first, so udev_monitor_receive_device doesn't return error when + there is no uevent +- Add 0230-UP-allow-invalid-creates.patch + * Allow creation of devices with no valid paths. +- Add 0231-RHBZ-1458852-delay-readying.patch + * Add ghost_delay configuration option to delay device activation when only + ghost paths exist. +- Add 0232-RHBZ-1456955-property-blacklist.patch + * Add the "property" blacklist type. +- Resolves: bz #1456955, #1458852, #1464634, #1465773, #1467987 + +* Wed Sep 20 2017 Benjamin Marzinski 0.4.9-113 +- Modify 0224-RHBZ-1452210-prkey.patch + * fix errow with telling multipathd to set prkeys +- Add 0225-RH-udevdir.patch + * fix rpmdiff complaint about udev rules installation +- Resolves: bz #1452210 + +* Tue Sep 19 2017 Benjamin Marzinski 0.4.9-112 +- Modify 0191-RHBZ-1169168-disable-changed-paths.patch + * man page fixup +- Modfiy 0197-RHBZ-1394059-max-sectors-kb.patch + * man page fixup +- Modify 0205-RHBZ-1416569-reset-stats.patch + * man page fixup +- Add 0218-RHBZ-1459370-add-feature-fix.patch + * handle null feature string +- Add 0219-RHBZ-1448970-fix-resize.patch + * if the resize fails, try to resume again with the old table. +- Add 0220-RHBZ-1448223-fix-kpartx.patch + * gracefully fail when run on something other than a file or block device +- Add 0221-RH-harden-files.patch + * change build parameters to use position independent code +- Add 0222-RHBZ-1457288-fix-show-maps-json.patch + * handle running "show maps json" with no multipath devices present +- Add 0223-RHBZ-1452210-unpriv-sgio.patch + * add unpriv_sgio configuration option to set unpriv_sgio on multipath device + and paths +- Add 0224-RHBZ-1452210-prkey.patch + * allow setting reservation_key to "file" to set and read keys from + prkey_file. Also add new multipathd commands to modify the prkey file. +- Resolves: bz #1459370, #1448970, #1448223, #1457288, #1452210 + +* Mon May 15 2017 Benjamin Marzinski 0.4.9-111 +- Remove 0217-RHBZ-1437329-blacklist-oracle-devs.patch + * Incorrect change, and the bug is already fixed. +- Move 0218-RHBZ-1448576-3PAR-config.patch to + 0217-RHBZ-1448576-3PAR-config.patch +- Resolves: bz #1448576 + +* Fri May 12 2017 Benjamin Marzinski 0.4.9-110 +- Add 0215-RHBZ-1444194-fix-check-partitions.patch + * make sure kpartx partions match the correct device +- Add 0216-RHBZ-1448562-fix-reserve.patch + * don't join threads that haven't been created +- Add 0217-RHBZ-1437329-blacklist-oracle-devs.patch + * blacklist db2.* devices +- Add 0218-RHBZ-1448576-3PAR-config.patch +- Resolves: bz #1444194, #1448562, #1437329, #1448576 + +* Tue Apr 25 2017 Benjamin Marzinski 0.4.9-109 +- Add 0214-RHBZ-1392115-set-paths-not-ready.patch + * Set ENV{SYSTEMD_READY}="0" on multipath path devices +- Resolves: bz #1392115 + +* Tue Apr 25 2017 Benjamin Marzinski 0.4.9-108 +- Add 0213-RHBZ-1430908-merge-dell-configs.patch +- Resolves: bz #1430908 + +* Mon Apr 3 2017 Benjamin Marzinski 0.4.9-107 +- Modify 0197-RHBZ-1394059-max-sectors-kb.patch + * Make multipath only change max_sectors_kb on creates. On reloads, it + just makes sure the new path matches the multipath device. +- Refresh 0198-RHBZ-1372032-detect-path-checker.patch +- Refresh 0201-RHBZ-1403552-silence-warning.patch +- Refresh 0206-RHBZ-1239173-pt2-no-paths.patch +- Refresh 0207-UP-add-libmpathcmd.patch +- Refresh 0212-RHBZ-1431562-for-read-only.patch +- Resolves: bz #1394059 + + +* Fri Mar 24 2017 Benjamin Marzinski 0.4.9-106 +- Add 0212-RHBZ-1431562-for-read-only.patch +- Resolves: bz #1431562 + +* Fri Mar 10 2017 Benjamin Marzinski 0.4.9-105 +- fix specfile issue +- Related: bz #1430097 + +* Thu Mar 9 2017 Benjamin Marzinski 0.4.9-104 +- Change _pkgconfdir from /usr/share/pkgconfig to /usr/lib/pkgconfig +- Modify 0209-UPBZ-1430097-multipath-C-API.patch + * change _pkgconfdir and fixed double-closing fd +- Add 0211-RH-strlen-fix.patch + * checks that variables are not NULL before passing them to strlen +- Related: bz #1430097 + +* Thu Mar 9 2017 Benjamin Marzinski 0.4.9-103 +- Add more explicit Requires to subpackages to make rpmdiff happy +- Related: bz #1430097 + +* Tue Mar 7 2017 Benjamin Marzinski 0.4.9-102 +- Add 0207-UP-add-libmpathcmd.patch + * New shared library, libmpathcmd, that sends and receives messages from + multipathd. device-mapper-multipath now uses this library internally. +- Add 0208-UPBZ-1430097-multipathd-IPC-changes.patch + * validation that modifying commands are coming from root. +- Add 0209-UPBZ-1430097-multipath-C-API.patch + * New shared library. libdmmp, that presents the information from multipathd + in a structured manner to make it easier for callers to use +- Add 0210-RH-fix-uninstall.patch + * Minor compilation fixes +- Make 3 new subpackages + * device-mapper-multipath-devel, libdmmp, and libdmmp-devel. libmpathcmd + and libmpathprio are in device-mapper-multipath-libs and + device-mapper-multipath-devel. libdmmp is in its own subpackages +- Move libmpathprio devel files to device-mapper-multipath-devel +- Resolves: bz #1430097 + +* Wed Feb 15 2017 Benjamin Marzinski 0.4.9-101 +- Modify 0166-RHBZ-1323429-dont-allow-new-wwid.patch + * change print message +- Add 0191-RHBZ-1169168-disable-changed-paths.patch + * add "disabled_changed_wwids" multipath.conf parameter to disable + paths whose wwid changes +- Add 0192-RHBZ-1362409-infinibox-config.patch +- Add 0194-RHBZ-1351964-kpartx-recurse.patch + * fix recursion on corrupt dos partitions +- Add 0195-RHBZ-1359510-no-daemon-msg.patch + * print a messages when multipathd isn't running +- Add 0196-RHBZ-1239173-dont-set-flag.patch + * don't set reload flag on reloads when you gain your first + valid path +- Add 0197-RHBZ-1394059-max-sectors-kb.patch + * add "max_sectors_kb" multipath.conf parameter to set max_sectors_kb + on a multipath device and all its path devices +- Add 0198-RHBZ-1372032-detect-path-checker.patch + * add "detect_checker" multipath.conf parameter to detect ALUA arrays + and set the path checker to TUR +- Add 0199-RHBZ-1279355-3pardata-config.patch +- Add 0200-RHBZ-1402092-orphan-status.patch + * clear status on orphan paths +- Add 0201-RHBZ-1403552-silence-warning.patch +- Add 0202-RHBZ-1362120-skip-prio.patch + * don't run prio on failed paths +- Add 0203-RHBZ-1363718-add-msgs.patch +- Add 0204-RHBZ-1406226-nimble-config.patch +- Add 0205-RHBZ-1416569-reset-stats.patch + * add "reset maps stats" and "reset map stats" multipathd + interactive commands to reset the stats tracked by multipathd +- Add 0206-RHBZ-1239173-pt2-no-paths.patch + * make multipath correctly disable scanning and rules running when + it gets a uevent and there are not valid paths. +- Resolves: bz #1169168, #1239173, #1279355, #1359510, #1362120, #1362409 +- Resolves: bz #1363718, #1394059, #1351964, #1372032, #1402092, #1403552 +- Resolves: bz #1406226, #1416569 + +* Wed Sep 7 2016 Benjamin Marzinski 0.4.9-100 +- Add 0189-RHBZ-1368211-remove-retries.patch + * add "remove_retries" multipath.conf parameter to make multiple attempts + to remove a multipath device if it is busy. +- Add 0190-RHBZ-1380602-rbd-lock-on-read.patch + * pass lock_on_read when remapping image +- Resolves: bz #1368211, #1380602 + +* Wed Sep 7 2016 Benjamin Marzinski 0.4.9-99 +- Add 0188-RHBZ-1368501-dont-exit.patch + * make multipathd not exit if it encounters recoverable errors on startup +- Resolves: bz #1368501 + +* Thu Sep 1 2016 Benjamin Marzinski 0.4.9-98 +- Modified 0180-multipath-tools-Add-rbd-checker.patch + * make the rbd path checker only compile if librados2-devel is installed +- Make librados2-devel only be BuildRequired on x86_64 +- Resolves: bz #1348372 + +* Thu Sep 1 2016 Benjamin Marzinski 0.4.9-97 +- Add 0177-libmultipath-correctly-initialize-pp-sg_id.patch + * This and all the following patches add the rbd patch checker +- Add 0178-libmultipath-add-rbd-discovery.patch +- Add 0179-multipath-tools-add-checker-callout-to-repair-path.patch +- Add 0180-multipath-tools-Add-rbd-checker.patch +- Add 0181-multipath-tools-Add-rbd-to-the-hwtable.patch +- Add 0182-multipath-tools-check-for-initialized-checker-before.patch +- Add 0183-multipathd-Don-t-call-repair-on-blacklisted-path.patch +- Add 0184-rbd-fix-sync-repair-support.patch +- Add 0185-rbd-check-for-nonshared-clients.patch +- Add 0186-rbd-check-for-exclusive-lock-enabled.patch +- Add 0187-rbd-fixup-log-messages.patch +- Added BuildRequires on librados2-devel +- Resolves: bz #1348372 + + +* Mon Aug 8 2016 Benjamin Marzinski 0.4.9-96 +- Modify 0136-RHBZ-1304687-wait-for-map-add.patch + * change missing_uev_msg_delay to missing_uev_msg_timeout, and make + multipathd re-enable table loads if the timeout has passed +- Refresh 0137-RHBZ-1280524-clear-chkr-msg.patch +- Refresh 0139-RHBZ-1273173-queue-no-daemon-doc.patch +- Refresh 0150-RHBZ-1253913-fix-startup-msg.patch +- Refresh 0154-UPBZ-1291406-disable-reinstate.patch +- Refresh 0155-UPBZ-1300415-PURE-config.patch +- Refresh 0156-UPBZ-1313324-dont-fail-discovery.patch +- Refresh 0161-RHBZ-1311659-no-kpartx.patch +- Refresh 0167-RHBZ-1335176-fix-show-cmds.patch +- Add 0173-RH-update-man-page.patch +- Add 0174-RHBZ-1362396-modprobe.patch + * make starting the multipathd service modprobe dm-multipath in the + sysvinit scripts +- Add 0175-RHBZ-1357382-ordering.patch + * force multipathd.service to start after systemd-udev-trigger.service +- Add 0176-RHBZ-1363830-fix-rename.patch + * initialized a variable to make dm_rename not fail randomly +- Resolves: bz #1304687, #1362396, #1357382, #1363830 + +* Wed Jul 20 2016 Benjamin Marzinski 0.4.9-95 +- Add 0170-UPBZ-1352925-fix-typo.patch +- Add 0171-UPBZ-1356651-allow-zero-size.patch + * Allow zero-sized paths to be added to a multipath device +- Add 0172-RHBZ-1350931-no-active-add.patch + * Allow paths to be added to a new map if no active paths exist. Also + fixes 1351430 +- Resolves: bz #1350931, #1351430, #1352925, #1356651 + + +* Mon Jul 18 2016 Benjamin Marzinski 0.4.9-94 +- Modify 0169-UPBZ-1353357-json-output.patch + * Add manpage documentation +- Resolves: bz #1353357 + +* Fri Jul 15 2016 Benjamin Marzinski 0.4.9-93 +- Modify 0135-RHBZ-1299600-path-dev-uevents.patch + * trigger uevents when adding wwids for existing devices during startup +- Refresh 0136-RHBZ-1304687-wait-for-map-add.patch +- Refresh 0150-RHBZ-1253913-fix-startup-msg.patch +- Add 0168-RHBZ-1347769-shared-lock.patch + * make multipath lock the path devices with a shared lock +- Add 0169-UPBZ-1353357-json-output.patch + * add mulitpathd json output command +- Resolves: bz #1299600, #1347769, #1353357 + +* Tue Jul 5 2016 Benjamin Marzinski 0.4.9-92 +- Add 0166-RHBZ-1323429-dont-allow-new-wwid.patch + * don't allow path wwid to change while it is in use +- Add 0167-RHBZ-1335176-fix-show-cmds.patch + * and new show multipath format wildcard, 'f' to sho number of failures. + This will hopefully be useful for tracking what happens to multipath + devices for bz #1335176 +- Resolves: bz #1323429 + +* Thu Jun 2 2016 Benjamin Marzinski 0.4.9-91 +- Add 0165-UPBZ-1341748-MSA-2040-conf.patch + * Add default config for MSA 2040 array +- Resolves: bz #1341748 + +* Wed Jun 1 2016 Benjamin Marzinski 0.4.9-90 +- Modify 0159-UPBZ-1255885-udev-waits.patch + * fix bug in failure path +- Add 0160-RH-udev-flags.patch +- Add 0161-RHBZ-1311659-no-kpartx.patch + * skip_kpartx option disables kpartx running on multipath devices +- Add 0162-RHBZ-1333331-huawei-config.patch + * Add default config for Huawei XSG1 array +- Add 0163-UPBZ-1333492-resize-map.patch + * restore old size if resize fails +- Add 0164-RHBZ-1311463-dos-part-rollover.patch + * fix incorrect partition size due to 4k device size rollover +- Resolves: bz #1255885, #1311463, #1311659, #1333331, #1333492 + +* Wed Apr 20 2016 Benjamin Marzinski 0.4.9-89 +- Modify 0151-RHBZ-1297456-weighted-fix.patch + * add documentation +- Add 0157-RHBZ-1319853-multipath-c-error-msg.patch + * better error reporting for multipath -c +- Add 0158-RHBZ-1318581-timestamp-doc-fix.patch + * add documentation for -T +- Add 0159-UPBZ-1255885-udev-waits.patch + * make multipath and kpartx wait after for udev after each command +- Resolves: bz #1297456, #1319853, #1318581, #1255885 + +* Tue Mar 29 2016 Benjamin Marzinski 0.4.9-88 +- Add 0151-RHBZ-1297456-weighted-fix.patch + * add wwn keyword to weighted prioritizer for persistent naming +- Add 0152-RHBZ-1269293-fix-blk-unit-file.patch + * use "Wants" instead of "Requires" +- Add 0153-RH-fix-i686-size-bug.patch + * use 64-bit keycodes for multipathd client commands +- Add 0154-UPBZ-1291406-disable-reinstate.patch + * don't automatically reinstate ghost paths for implicit alua devices +- Add 0155-UPBZ-1300415-PURE-config.patch + * Add default config for PURE FlashArray +- Add 0156-UPBZ-1313324-dont-fail-discovery.patch + * don't fail discovery because individual paths failed. +- Resolves: bz #1297456, #1269293, #1291406, #1300415, #1313324 + +* Fri Feb 26 2016 Benjamin Marzinski 0.4.9-87 +- Add 0133-RHBZ-1241774-sun-partition-numbering.patch + * makr kpartx device numbers match partition numbers +- Add 0134-RHBZ-1241528-check-mpath-prefix.patch + * only touch devices with a "mpath-" dm uuid prefix +- Add 0135-RHBZ-1299600-path-dev-uevents.patch + * trigger path uevent the first time a path is claimed by multipath +- Add 0136-RHBZ-1304687-wait-for-map-add.patch + * wait for the device to finish being added before reloading it. +- Add 0137-RHBZ-1280524-clear-chkr-msg.patch +- Add 0138-RHBZ-1288660-fix-mpathconf-allow.patch + * don't remove existing lines from blacklist_exceptions section +- Add 0139-RHBZ-1273173-queue-no-daemon-doc.patch +- Add 0140-RHBZ-1299647-fix-help.patch +- Add 0141-RHBZ-1303953-mpathpersist-typo.patch +- Add 0142-RHBZ-1283750-kpartx-fix.patch + * only remove devices if their uuid says that they are the correct + partition device +- Add 0143-RHBZ-1299648-kpartx-sync.patch + * default to using udev sync mode +- Add 0144-RHBZ-1299652-alua-pref-arg.patch + * allow "exclusive_pref_bit" argument to alua prioritizer +- Add 0145-UP-resize-help-msg.patch +- Add 0146-UPBZ-1299651-raw-output.patch + * allow raw format mutipathd show commands, that remove headers and padding +- Add 0147-RHBZ-1272620-fail-rm-msg.patch +- Add 0148-RHBZ-1292599-verify-before-remove.patch + * verify that all partitions are unused before attempting to remove a device +- Add 0149-RHBZ-1292599-restore-removed-parts.patch + * don't disable kpartx when restoring the first path of a device. +- Add 0150-RHBZ-1253913-fix-startup-msg.patch + * wait for multipathd daemon to write pidfile before returning +- Resolves: bz #1241528, #1241774, #1253913, #1272620, #1273173, #1280524 +- Resolves: bz #1283750, #1288660, #1292599, #1299600, #1299647, #1299648 +- Resolves: bz #1299651, #1299652, #1303953, #1304687 + +* Wed Jan 27 2016 Benjamin Marzinski 0.4.9-86 +- Add 0132-RHBZ-1296979-fix-define.patch + * look for the correct libudev function to set define +- Resolves: bz # 1296979 + +* Thu Sep 17 2015 Benjamin Marzinski 0.4.9-85 +- Fix device-mapper Requires line in spec file +- Resolves: bz# 1260728 + +* Mon Sep 14 2015 Benjamin Marzinski 0.4.9-84 +- 0131-UPBZ-1259831-lock-retry.patch + * retry locking when creating multipath devices +- Resolves: bz# 1259831 + +* Tue Sep 8 2015 Benjmain Marzinski 0.4.9-83 +- Add 0130-RHBZ-1259523-host_name_len.patch + * increase size of host string +- Resolves: bz# 1259523 + +* Wed Aug 19 2015 Benjmain Marzinski 0.4.9-82 +- Add 0129-UPBZ-1254292-iscsi-targetname.patch + * check for targetname iscsi sysfs value +- Resolves: bz #1254292 + +* Wed Jul 8 2015 Benjamin Marzinski 0.4.9-81 +- Modify 0128-RHBZ-1222123-mpathconf-allow.patch + * Fix up covscan complaints. +- Related: bz #1222123 + +* Tue Jul 7 2015 Benjamin Marzinski 0.4.9-80 +- Add 0127-RHBZ-1201030-use-blk-availability.patch + * Make multipath use blk-availability.service +- Add 0128-RHBZ-1222123-mpathconf-allow.patch + * Add mpathconf --allow for creating specialized config files. +- Resolves: bz #1201030, #1222123 + +* Fri Jun 5 2015 Benjamin Marzinski 0.4.9-79 +- Add 0124-RHBZ-1209275-retrigger-uevents.patch + * Make multipathd retrigger uevents when paths haven't successfully had + their udev_attribute environment variable set by udev and add + "retrigger_ties" and "retrigger_delay" to control this +- Add 0125-RHBZ-1153832-kpartx-delete.patch + * Delete all partition devices with -d (not just the ones in the partition + table) +- Add 0126-RHBZ-1211383-alias-collision.patch + * make multipathd use the old alias, if rename failed and add + "new_bindings_in_boot" to determine if new bindings can be added to + the bindings file in the initramfs +- Resolves: bz #1153832, #1209275, #1211383 + +* Thu May 7 2015 Benjamin Marzinski 0.4.9-78 +- Modify 0102-RHBZ-631009-deferred-remove.patch + * Code refactor and minor fix. +- Add 0106-RHBZ-1169935-no-new-devs.patch + * add new configuration option "ignore_new_boot_devs" +- Add 0107-RH-adapter-name-wildcard.patch + * add new paths wildcard to show the host adapter +- Add 0108-RHBZ-1153832-kpartx-remove-devs.patch + * switch to kpartx -u in 62-multipath.rules to delete removed partitions +- Add 0109-RH-read-only-bindings.patch + * add -B support to multipathd +- Add 0110-RHBZ-blacklist-vd-devs.patch + * virtio-blk devices don't report a WWID so multipath can't use them +- Add 0111-RH-dont-show-pg-timeout.patch + * remove pg_timeout setting and displaying code +- Add 0112-RHBZ-1194917-add-config_dir-option.patch + * add new configuration option "config_dir" +- Add 0113-RHBZ-1194917-cleanup.patch + * code refactoring +- Add 0114-RHBZ-1196394-delayed-reintegration.patch + * add new configuration options "delay_watch_checks" and + "delay_wait_checks" +- Add 0115-RHBZ-1198418-fix-double-free.patch + * fix crash when multipath fails adding a multipath device +- Add 0116-UPBZ-1188179-dell-36xxi.patch + * New builtin config +- Add 0117-RHBZ-1198424-autodetect-clariion-alua.patch + * update default config +- Add 0118-UPBZ-1200738-update-eternus-config.patch + * update default config +- Add 0119-RHBZ-1081397-save-alua-info.patch + * make prioritizers save information between calls to speed them up. +- Add 0120-RHBZ-1043093-realloc-fix.patch + * free old memory if realloc fails. +- Add 0121-RHBZ-1197234-rules-fix.patch + * make sure kpartx runs after an DM_ACTIVATION event occurs. +- Add 0122-RHBZ-1212590-dont-use-var.patch + * use /run instead of /var/run +- Add 0123-UPBZ-1166072-fix-path-offline.patch + * Don't mark quiesce and transport-offline paths as offline +- Modify mulfipth.conf default config file (bz #1194794) +- Related: bz #1153832 +- Resolves: bz #631009, #1043093, #1081397, #1166072, #1169935, #1188179 +- Resolves: bz #1194794, #1194917, #1196394, #1197234, #1198418, #1198424 +- Resolves: bz #1200738, #1212590 + +* Fri Jan 9 2015 Benjamin Marzinski 0.4.9-77 +- Add 0105-RHBZ-1180032-find-multipaths-man.patch + * add find_multipaths to man page +- Modify multipath.conf (bz #1069360) + * add uid_attribute example +- Resolves: bz #1180032 + +* Fri Nov 14 2014 Benjamin Marzinski 0.4.9-76 +- Modify 0102-RHBZ-631009-deferred-remove.patch + * Fixed compiler warning message for builds with old device-mapper versions +- Add 0104-RHBZ-1159337-fix-double-free.patch + * made ev_remove_path exit immediately after failing setup_multipath, since + it handles cleaning up the device +- Resolves: bz #1159337 +- Related: bz #631009 + +* Thu Nov 6 2014 Benjamin Marzinski 0.4.9-75 +- Add 0103-RHBZ-1148979-fix-partition-mapping-creation-race-with-kpartx.patch + * Only run kpartx on device activation +- Resolves: bz #1148979 + +* Tue Oct 28 2014 Benjamin Marzinski 0.4.9-74 +- Respin again to let buildroot catch up. +- Related: bz #631009 + +* Tue Oct 28 2014 Benjamin Marzinski 0.4.9-73 +- Respin to pick up latest lvm2 code +- Related: bz #631009 + +* Tue Oct 28 2014 Benjamin Marzinski 0.4.9-72 +- Add 0101-RH-cleanup-partmaps-code.patch + * code refactoring to prepare for next patch +- Add 0102-RHBZ-631009-deferred-remove.patch + * add deferred_remove option to /etc/multipath.conf +- Resolves: bz #631009 + +* Fri Sep 5 2014 Benjamin Marzinski 0.4.9-71 +- Re-add 0050-RH-listing-speedup.patch +- Modify 0098-UPBZ-1067171-mutipath-i.patch + * add dry_run cleanup code from upstream +- Refresh 0099-RH-add-all-devs.patch +- Add 0100-RHBZ-1067171-multipath-i-update.patch + * make -i work correctly with find_multipaths +- Resolves: bz #1067171 + +* Wed Sep 3 2014 Benjamin Marzinski 0.4.9-70 +- Modify 0096-RHBZ-979474-new-wildcards.patch + * Fix a faulty check +- Add 0098-UPBZ-1067171-mutipath-i.patch + * Add -i option to ignore wwids file when checking for valid paths +- Add 0099-RH-add-all-devs.patch + * Add new devices config option all_devs. This makes the configuration + overwrite the specified values in all builtin configs +- Related: bz #979474 +- Resolves: bz #1067171 + +* Thu Aug 28 2014 Benjamin Marzinski 0.4.9-69 +- Add 0096-RHBZ-979474-new-wildcards.patch + * Add N, n, R, and r path wildcards to print World Wide ids +- Add 0097-RH-fix-coverity-errors.patch + * Fix a number of unterminated strings and memory leaks on failure + paths. +- Resolves: bz #979474 + +* Tue Aug 12 2014 Benjamin Marzinski 0.4.9-68 +- Add 0091-RHBZ-1069584-fix-empty-values-fast-io-fail-and-dev-loss.patch + * check for null pointers in configuration reading code. +- Add 0092-UPBZ-1104605-reload-on-rename.patch + * Reload table on rename if necessary +- Add 0093-UPBZ-1086825-user-friendly-name-remap.patch + * Keep existing user_friend_name if possible +- Add 0094-RHBZ-1086825-cleanup-remap.patch + * Cleanup issues with upstream patch +- Add 0095-RHBZ-1127944-xtremIO-config.patch + * Add support for EMC ExtremIO devices +- Resolves: bz #1069584, #1104605, #1086825, #1086825, #1127944 + +* Tue Aug 12 2014 Benjamin Marzinski 0.4.9-67 +- Modify multipath.conf (bz #1069360) + * remove getuid_callout example +- Add 0081-RHBZ-1066264-check-prefix-on-rename.patch + * make multipath check the prefix on kpartx partitions during rename, and + copy the existing behaviour +- Add 0082-UPBZ-1109995-no-sync-turs-on-pthread_cancel.patch + * If async tur checker fails on threads, don't retry with the sync version +- Add 0083-RHBZ-1080055-orphan-paths-on-reload.patch + * Fix case where pathlist wasn't getting updated properly +- Add 0084-RHBZ-1110000-multipath-man.patch + * fix errors in multipath man page +- Add 0085-UPBZ-1110006-datacore-config.patch + * Add support for DataCore Virtual Disk +- Add 0086-RHBZ-1110007-orphan-path-on-failed-add.patch + * If multipathd fails to add path correctly, it now fully orphans the path +- Add 0087-RHBZ-1110013-config-error-checking.patch + * Improve multipath.conf error checking. +- Add 0088-RHBZ-1069811-configurable-prio-timeout.patch + * checker_timeout now adjusts the timeouts of the prioritizers as well. +- Add 0089-RHBZ-1110016-add-noasync-option.patch + * Add a new defaults option, "force_sync", that disables the async mode + of the path checkers. This is for cases where to many parallel checkers + hog the CPU +- Add 0090-UPBZ-1080038-reorder-paths-for-round-robin.patch + * make multipathd order paths for better throughput in round-robin mode +- Resolves: bz #1069360, #1066264, #1109995, #1080055, #1110000, #1110006 +- Resolves: bz #1110007, #1110013, #1069811, #1110016, #1080038 + +* Wed Mar 12 2014 Benjamin Marzinski 0.4.9-66 +- Add 0080-RHBZ-1075796-cmdline-wwid.patch + * add multipath option "-A" to add wwids specified by the kernel + command line mapth.wwid options. +- Resolves: bz #1075796 + +* Mon Mar 3 2014 Benjamin Marzinski 0.4.9-65 +- Add 0078-RHBZ-1054044-fix-mpathconf-manpage.patch + * Fix typo +- Add 0079-RHBZ-1070581-add-wwid-option.patch + * add multipath option "-a". To add a device's wwid to the wwids file +- Resolves: bz #1054044, #1070581 + +* Thu Jan 30 2014 Benjamin Marzinski 0.4.9-64 +- Modify 0076-RHBZ-1056686-add-hw_str_match.patch + * Fix memory leak +- Resolves: bz #1056686 + +* Wed Jan 29 2014 Benjamin Marzinski 0.4.9-63 +- Modify 0072-RHBZ-1039199-check-loop-control.patch + * only call close on the /dev/loop-control fd the open succeeds +- Add 0073-RH-update-build-flags.patch + * fix print call to work with -Werror=format-security compile flag, and + change compilation flags for non-rpmbuild compiles +- Add 0074-RHBZ-1056976-dm-mpath-rules.patch + * Add rules to keep from doing work in udev if there are no + active paths, or if the event was for a multipath device + reloading its table due to a path change. +- Add 0075-RHBZ-1056976-reload-flag.patch + * multipath code to identify reloads that the new rules can + ignore +- Add 0076-RHBZ-1056686-add-hw_str_match.patch + * add a new default config paramter, "hw_str_match", to make user + device configs only overwrite builtin device configs if the + identifier strings match exactly, like the default in RHEL6. +- Add 0077-RHBZ-1054806-mpathconf-always-reload.patch + * Make mpathconf always reconfgure multipathd when you run it with + a reconfigure option and --with-multipathd=y, even if the + configuration doesn't change. +- Update Requires and BuildRequires for device-mapper to 1.02.82-2 +- Install new udev rules file /usr/lib/udev/rules.d/11-dm-mpath.rules +- Related: bz #1039199 +- Resolves: bz #1054806, #1056686, #1056976 + +* Fri Jan 24 2014 Daniel Mach - 0.4.9-62 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 0.4.9-61 +- Mass rebuild 2013-12-27 + +* Wed Dec 11 2013 Benjamin Marzinski 0.4.9-60 +- Add 0072-RHBZ-1039199-check-loop-control.patch + * Make kpartx use LOOP_CTL_GET_FREE and loop-control to find a free + loop device. This will autoload the loop module. +- Resolves: bz #1039199 + +* Mon Dec 9 2013 Benjamin Marzinski 0.4.9-59 +- Add 0067-RHBZ-1022899-fix-udev-partition-handling.patch + * Make sure to wipe partition devices on change event if they weren't + wiped on the device add event +- Add 0068-RHBZ-1034578-label-partition-devices.patch + * Make sure that partition devices are labeled like the whole device +- Add 0069-UPBZ-1033791-improve-rdac-checker.patch + * Use RTPG data in RDAC checker +- Add 0070-RHBZ-1036503-blacklist-td-devs.patch +- Add 0071-RHBZ-1031546-strip-dev.patch + * make multipathd interactive commands able to handle /dev/ + instead of just +- Resolves: bz #1022899, #1031546, #1033791, #1034578, #1036503 + +* Thu Oct 24 2013 Benjamin Marzinski 0.4.9-58 +- 0066-UP-dos-4k-partition-fix.patch + * Make kpartx correctly handle 4K sector size devices with dos partitions. +- Resolves: bz #1018439 + +* Fri Sep 27 2013 Benjamin Marzinski 0.4.9-57 +- Add 0065-UPBZ-995538-fail-rdac-on-unavailable.patch + * make rdac checker always mark paths with asymmetric access state of + unavailable as down +- Resolves: bz #995538 + +* Wed Sep 25 2013 Benjamin Marzinski 0.4.9-56 +- Add 0064-RHBZ-1010040-fix-ID_FS-attrs.patch + * make multipath create a timestamp file /run/multipathd/timestamp, and + add -T: option to shortcut processing if the + timestamp hasn't changed +- Resolves: bz #1010040 + +* Fri Sep 6 2013 Benjamin Marzinski 0.4.9-55 +- Add 0061-RH-display-find-mpaths.patch +- Add 0062-RH-dont-free-vecs.patch + * freeing vecs causes a number of races which can crash multipathd on + shutdown. +- Add 0063-RH-fix-warning.patch + +* Thu Jul 25 2013 Benjamin Marzinski 0.4.9-54 +- Modify 0015-RH-fix-output-buffer.patch + * Fix memory leak +- Add 0047-RHBZ-kpartx-read-only-loop-devs.patch + * Fix read only loop device handling +- Add 0048-RH-print-defaults.patch +- Add 0049-RH-remove-ID_FS_TYPE.patch + * remove ID_FS_TYPE udev enviroment variable for multipath devices +- Add 0051-UP-fix-cli-resize.patch + * check before dereferencing variables +- Add 0052-RH-fix-bad-derefs.patch + * setup multipath free the multipath device when it fails, so don't keep + using it. +- Add 0053-UP-fix-failback.patch + * setting failback in the devices section was broken +- Add 0054-UP-keep-udev-ref.patch + * multipathd needs to keep the same udev object across reconfigures +- Add 0055-UP-handle-quiesced-paths.patch + * quiesced paths should be treated as down +- Add 0056-UP-alua-prio-fix.patch + * Don't count the preferred bit for paths that are active/optimized +- Add 0057-UP-fix-tmo.patch + * Cleanup how multipath sets dev_loss_tmo and fast_io_fail_tmo. Also + make multipath get changing values directly from sysfs, instead of + from udev, which caches them. +- Add 0058-UP-fix-failback.patch + * make failback print the default value when you show configs. +- Add 0059-UP-flush-failure-queueing.patch + * If you can't flush a multipath device, restore the queue_if_no_paths + value +- Add 0060-UP-uevent-loop-udev.patch + * make ueventloop grab it's own udev reference, since it is cancelled + asychnrously. + +* Wed Jul 3 2013 Benjamin Marzinski 0.4.9-53 +- Add 0044-RHBZ-976688-fix-wipe-wwids.patch + * Seek back to the start of the file after truncating it +- Add 0045-RHBZ-977297-man-page-fix.patch + * update man page to match actual defaults +- Add 0046-RHBZ-883981-move-udev-rules.patch + * move udev rules file from /lib to /usr/lib +- Resolves: bz #883981, #976688, #977297 + +* Fri Jun 21 2013 Benjamin Marzinski 0.4.9-52 +- Add 0038-RHBZ-799860-netapp-config.patch +- Add 0039-RH-detect-prio-fix.patch + * Don't autodetect ALUA prioritizer unless it actually can get a priority +- Add 0040-RH-bindings-fix.patch + * Do a better job of trying to get the first free user_friendly_name +- Add 0041-RH-check-for-erofs.patch + * Don't create/reload a device read-only unless doing it read/write fails + with EROFS +- Remove 0017-RH-fix-sigusr1.patch + * fix signal handling upstream way instead +- Add 0042-UP-fix-signal-handling.patch + * uxlsnr now handles all the signals sent to multipathd. This makes its + signal handling posix compliant, and harder to mess up. +- Add 0043-RH-signal-waiter.patch + * ioctl isn't a pthread cancellation point. Send a signal to the waiter + thread to break out of waiting in ioctl for a dm event. + +* Fri May 17 2013 Benjamin Marzinski 0.4.9-51 +- Add 0032-RHBZ-956464-mpathconf-defaults.patch + * fix defaults listed in usage +- Add 0033-RHBZ-829963-e-series-conf.patch +- Add 0034-RHBZ-851416-mpathconf-display.patch + * display whether or not multipathd is running in the status +- Add 0035-RHBZ-891921-list-mpp.patch + * add a new path format wilcard to list the multipath device associated + with a path +- Add 0036-RHBZ-949239-load-multipath-module.patch + * load the dm-multipath kernel module when multipathd starts +- Add 0037-RHBZ-768873-fix-rename.patch + * When deciding on a multipth devices name on reload, don't default to + the existing name if there is no config file alias and user_friendly_names + isn't set. Use the wwid. +- Modify multipath.conf +- Resolves: bz #768873, #950252 + +* Tue Apr 30 2013 Benjamin Marzinski 0.4.9-50 +- Add 0031-RHBZ-957188-kpartx-use-dm-name.patch + * use the basename of the devices that will be created to choose the + delimiter instead of using the device name from the command line +- Resolves: bz #957188 + +* Fri Apr 26 2013 Benjamin Marzinski 0.4.9-49 +- Modify 0020-RHBZ-907360-static-pthread-init.patch + * Don't initialize uevent list twice +- Add 0029-RH-no-prio-put-msg.patch +- Add 0030-RHBZ-916528-override-queue-no-daemon.patch + * Default to "queue_without_daemon no" + * Add "forcequeueing daemon" and "restorequeueing daemon" cli commands +- Modify spec file to force queue_without_daemon when restarting + multipathd on upgrades. + +* Thu Apr 4 2013 Benjamin Marzinski 0.4.9-48 +- Add 0026-fix-checker-time.patch + * Once multipathd hit it max checker interval, it was reverting to + to shortest checker interval +- Add 0027-RH-get-wwid.patch + * Multipath wasn't correctly setting the multipath wwid when it read devices + in from the kernel +- Add 0028-RHBZ-929078-refresh-udev-dev.patch + * Make multipath try to get the UID of down devices. Also, on ev_add_path, + make multipathd reinitialize existing devices that weren't fully + initialized before. + +* Mon Apr 1 2013 Benjamin Marzinski 0.4.9-47 +- Add 0021-RHBZ-919119-respect-kernel-cmdline.patch + * keep the multipath.rules udev file from running and multipathd from + starting if nompath is on the kernel command line +- Add 0022-RH-multipathd-check-wwids.patch + * Whenever multipath runs configure, it will check the wwids, and + add any missing ones to the wwids file +- Add 0023-RH-multipath-wipe-wwid.patch + * multipath's -w command will remove a wwid from the wwids file +- Add 0024-RH-multipath-wipe-wwids.patch + * multipath's -W command will set reset the wwids file to just the current + devices +- Add 0025-UPBZ-916668_add_maj_min.patch +- Resolves: bz #919119 + +* Thu Mar 28 2013 Benjamin Marzinski 0.4.9-46 +- Add 0020-RHBZ-907360-static-pthread-init.patch + * statically initialize the uevent pthread structures + +* Sat Mar 2 2013 Benjamin Marzinski 0.4.9-45 +- Updated to latest upstrem 0.4.9 code: multipath-tools-130222 + (git commit id: 67b82ad6fe280caa1770025a6bb8110b633fa136) +- Refresh 0001-RH-dont_start_with_no_config.patch +- Modify 0002-RH-multipath.rules.patch +- Modify 0003-RH-Make-build-system-RH-Fedora-friendly.patch +- Refresh 0004-RH-multipathd-blacklist-all-by-default.patch +- Refresh 0005-RH-add-mpathconf.patch +- Refresh 0006-RH-add-find-multipaths.patch +- Add 0008-RH-revert-partition-changes.patch +- Rename 0008-RH-RHEL5-style-partitions.patch to + 0009-RH-RHEL5-style-partitions.patch +- Rename 0009-RH-dont-remove-map-on-enomem.patch to + 0010-RH-dont-remove-map-on-enomem.patch +- Rename 0010-RH-deprecate-uid-gid-mode.patch to + 0011-RH-deprecate-uid-gid-mode.patch +- Rename 0013-RH-kpartx-msg.patch to 0012-RH-kpartx-msg.patch +- Rename 0035-RHBZ-883981-cleanup-rpmdiff-issues.patch to + 0013-RHBZ-883981-cleanup-rpmdiff-issues.patch +- Rename 0039-RH-handle-other-sector-sizes.patch to + 0014-RH-handle-other-sector-sizes.patch +- Rename 0040-RH-fix-output-buffer.patch to 0015-RH-fix-output-buffer.patch +- Add 0016-RH-dont-print-ghost-messages.patch +- Add 0017-RH-fix-sigusr1.patch + * Actually this fixes a number of issues related to signals +- Rename 0018-RH-remove-config-dups.patch to 0018-RH-fix-factorize.patch + * just the part that isn't upstream +- Add 0019-RH-fix-sockets.patch + * makes abstract multipathd a cli sockets use the correct name. +- Set find_multipaths in the default config + +* Wed Feb 20 2013 Benjamin Marzinski 0.4.9-44 +- Add 0036-UP-fix-state-handling.patch + * handle transport-offline and quiesce sysfs state +- Add 0037-UP-fix-params-size.patch +- Add 0038-RH-fix-multipath.rules.patch + * make sure multipath's link priority gets increased +- Add 0039-RH-handle-other-sector-sizes.patch + * allow gpt partitions on 4k sector size block devices. +- Add 0040-RH-fix-output-buffer.patch + * fix multipath -ll for large configuration. + +* Wed Feb 13 2013 Fedora Release Engineering - 0.4.9-43 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Fri Dec 21 2012 Benjamin Marzinski 0.4.9-42 +- Add 0034-RHBZ-887737-check-for-null-key.patch +- Add 0035-RHBZ-883981-cleanup-rpmdiff-issues.patch + * Compile multipathd with full RELRO and PIE and install to /usr + +* Mon Dec 17 2012 Benjamin Marzinski 0.4.9-41 +- Add 0033-RH-dont-disable-libdm-failback-for-sync-case.patch + * make kpartx -s and multipath use libdm failback device creation, so + that they work in environments without udev + +* Fri Nov 30 2012 Benjamin Marzinski 0.4.9-40 +- Add 0032-RH-make-path-fd-readonly.patch + * revert change made when adding persistent reservations, so that path fds + are again opened O_RDONLY + +* Fri Nov 30 2012 Benjamin Marzinski 0.4.9-39 +- Add 0031-RHBZ-882060-fix-null-strncmp.patch + +* Fri Nov 30 2012 Benjamin Marzinski 0.4.9-38 +- Add 0026-RH-fix-mpathpersist-fns.patch +- Add 0027-RH-default-partition-delimiters.patch + * Only use the -p delimiter when the device name ends in a number +- Add 0028-RH-storagetek-config.patch +- Add 0029-RH-kpartx-retry.patch + * retry delete on busy loop devices +- Add 0030-RH-early-blacklist.patch + * multipath will now blacklist devices by device type and wwid in + store_pathinfo, so that it doesn't do a bunch of unnecessary work + on paths that it would only be removing later on. + +* Sat Nov 03 2012 Peter Rajnoha 0.4.9-37 +- Install multipathd.service for sysinit.target instead of multi-user.target. + +* Thu Nov 01 2012 Peter Rajnoha 0.4.9-36 +- Start multipathd.service systemd unit before LVM units. + +* Wed Oct 24 2012 Benjamin Marzinski 0.4.9-35 +- Add 0022-RHBZ-864368-disable-libdm-failback.patch + * make kpartx and multiapthd disable libdm failback device creation +- Add 0023-RHBZ-866291-update-documentation.patch +- Resolves: bz #864368, #866291 + +* Tue Oct 23 2012 Benjamin Marzinski 0.4.9-34 +- Add 0021-RH-fix-oom-adj.patch + * don't use OOM_ADJUST_MIN unless you're sure it's defined + +* Tue Oct 23 2012 Benjamin Marzinski 0.4.9-33 +- Modify 0016-RH-retain_hwhandler.patch + * Check the dm-multipath module version, and don't enable + retain_attached_hw_handler if the kernel doesn't support it +- Add 0019-RH-detect-prio.patch + * add detect_prio option, to make multipath check if the device + supports the ALUA prio, before defaulting to the configured prio +- Remove 0017-RH-netapp_config.patch +- Add 0020-RH-netapp-config.patch + * new netapp config that uses retain_attached_hw_handler and + detect_prio to autoconfigure ALUA and non-ALUA devices. + +* Tue Oct 2 2012 Benjamin Marzinski 0.4.9-32 +- Modified 0018-RH-remove-config-dups.patch + * Made modified config remove original only if the vendor/product + exactly match + +* Thu Sep 27 2012 Benjamin Marzinski 0.4.9-31 +- Add 0014-RH-dm_reassign.patch + * Fix reassign_maps option +- Add 0015-RH-selector_change.patch + * devices default to using service-time selector +- Add 0016-RH-retain_hwhandler.patch + * add retain_attached_hw_handler option, to let multipath keep an + already attached scsi device handler +- Add 0017-RH-netapp_config.patch +- Add 0018-RH-remove-config-dups.patch + * Clean up duplicates in the devices and blacklist sections + +* Wed Sep 05 2012 Václav Pavlín - 0.4.9-30 +- Scriptlets replaced with new systemd macros (#850088) + +* Tue Aug 21 2012 Benjamin Marzinski 0.4.9-29 +- Updated to latest upstrem 0.4.9 code: multipath-tools-120821.tgz + (git commit id: 050b24b33d3c60e29f7820d2fb75e84a9edde528) + * includes 0001-RH-remove_callout.patch, 0002-RH-add-wwids-file.patch, + 0003-RH-add-followover.patch, 0004-RH-fix-cciss-names.patch +- Add 0013-RH-kpartx-msg.patch +- Modify 0002-RH-multipath.rules.patch + * removed socket call from rules file + +* Wed Jul 18 2012 Fedora Release Engineering - 0.4.9-28 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Jun 28 2012 Benjamin Marzinski 0.4.9-27 +- Updated to latest upstream 0.4.9 code : multipath-tools-120613.tgz + (git commit id: cb0f7127ba90ab5e8e71fc534a0a16cdbe96a88f) +- Add 0001-RH-remove_callout.patch + * multipath no longer uses the getuid callout. It now gets the + wwid from the udev database or the environment variables +- Add 0004-RH-fix-cciss-names.patch + * convert cciss device names from cciss/cXdY to sysfs style cciss!cXdY +- Split 0009-RH-add-find-multipaths.patch into 0002-RH-add-wwids-file.patch + and 0010-RH-add-find-multipaths.patch +- Add 0016-RH-change-configs.patch + * default fast_io_fail to 5 and don't set the path selector in the + builtin configs. +Resolves: bz #831978 + + +* Thu May 17 2012 Benjamin Marzinski 0.4.9-26 +- Add 0025-RHBZ-822714-update-nodes.patch +- Resolves: bz #822714 + +* Mon Apr 30 2012 Benjamin Marzinski 0.4.9-25 +- Modify 0024-RH-libudev-monitor.patch +- Resolves: bz #805493 + +* Mon Apr 30 2012 Benjamin Marzinski 0.4.9-24 +- Add requirements on libudev to spec file +- Resolves: bz #805493 + +* Mon Apr 30 2012 Benjamin Marzinski 0.4.9-23 +- Add 0024-RH-libudev-monitor.patch + +* Fri Feb 10 2012 Benjamin Marzinski 0.4.9-22 +- Add 0012-RH-update-on-show-topology.patch +- Add 0013-RH-manpage-update.patch +- Add 0014-RH-RHEL5-style-partitions.patch +- Add 0015-RH-add-followover.patch +- Add 0016-RH-dont-remove-map-on-enomem.patch +- Add 0017-RH-fix-shutdown-crash.patch +- Add 0018-RH-warn-on-bad-dev-loss-tmo.patch +- Add 0019-RH-deprecate-uid-gid-mode.patch +- Add 0020-RH-dont-remove-map-twice.patch +- Add 0021-RH-validate-guid-partitions.patch +- Add 0022-RH-adjust-messages.patch +- Add 0023-RH-manpage-update.patch + +* Tue Jan 24 2012 Benjamin Marzinski 0.4.9-21 +- Updated to latest upstream 0.4.9 code : multipath-tools-120123.tgz + (git commit id: 63704387009443bdb37d9deaaafa9ab121d45bfb) +- Add 0001-RH-fix-async-tur.patch +- Add 0002-RH-dont_start_with_no_config.patch +- Add 0003-RH-multipath.rules.patch +- Add 0004-RH-update-init-script.patch +- Add 0005-RH-cciss_id.patch +- Add 0006-RH-Make-build-system-RH-Fedora-friendly.patch +- Add 0007-RH-multipathd-blacklist-all-by-default.patch +- Add 0008-RH-add-mpathconf.patch +- Add 0009-RH-add-find-multipaths.patch +- Add 0010-RH-check-if-multipath-owns-path.patch +- Add 0011-RH-add-hp_tur-checker.patch + +* Fri Jan 13 2012 Fedora Release Engineering - 0.4.9-20 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Sep 20 2011 Benjamin Marzinski -0.4.9-19 +- Modify 0103-add-disable-sync-option.patch +- Add 0104-RHBZ-737989-systemd-unit-fix.patch + * systemd will only start multipathd if /etc/multipath.conf exists +- Add 0105-fix-oom-adj.patch + * first try setting oom_score_adj + +* Mon Aug 15 2011 Kalev Lember - 0.4.9-18 +- Rebuilt for rpm bug #728707 + +* Tue Jul 19 2011 Benjamin Marzinski -0.4.9-17 +- Add 0103-add-disable-sync-option.patch + * add a -n (nosync) option to multipath. This disables synchronous + file creation with udev. + +* Fri Jul 15 2011 Benjamin Marzinski -0.4.9-16 +- Modify 0012-RH-udev-sync-support.patch +- Modify 0021-RHBZ-548874-add-find-multipaths.patch +- Modify 0022-RHBZ-557845-RHEL5-style-partitions.patch +- Add 0025-RHBZ-508827-update-multipathd-manpage.patch through + 0101-RHBZ-631009-disable-udev-disk-rules-on-reload.patch + * sync with current state of RHEL6. Next release should include a updated + source tarball with most of these fixes rolled in. +- Add 0102-RHBZ-690828-systemd-unit-file.patch + * Add Jóhann B. Guðmundsson's unit file for systemd. + * Add sub-package sysvinit for SysV init script. +- Resolves: bz #690828 + +* Tue Feb 08 2011 Fedora Release Engineering - 0.4.9-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Feb 16 2010 Benjamin Marzinski -0.4.9-14 +- Modify 0021-RHBZ-548874-add-find-multipaths.patch + * fix bug where mpathconf wouldn't create a multpath.conf file unless one + already existed. + +* Tue Feb 16 2010 Benjamin Marzinski -0.4.9-13 +- Replace 0012-RH-explicitly-disable-dm-udev-sync-support-in-kpartx.patch + with 0012-RH-udev-sync-support.patch + * Add udev sync support to kpartx and multipath. In kpartx it is disabled + unless you use the -s option. +- Refresh 0013-RH-add-weighted_prio-prioritizer.patch +- Refresh 0021-RHBZ-548874-add-find-multipaths.patch +- Modify 0022-RHBZ-557845-RHEL5-style-partitions.patch + * kpartx now creates a 2 sector large device for dos extended + partitions, just like the kernel does on the regular block devices. +- Add 0023-RHBZ-557810-emc-invista-config.patch +- Add 0024-RHBZ-565933-checker-timeout.patch + * Multipath has a new option checker_timeout. If this is not set, + all path checker functions with explicit timeouts use + /sys/block/sd/device/timeout. If this is set, they use it instead. + +* Fri Jan 22 2010 Benjamin Marzinski -0.4.9-12 +- Refresh 0001-RH-queue-without-daemon.patch +- Refresh 0002-RH-path-checker.patch +- Modify 0010-RH-multipath-rules-udev-changes.patch + * Fix udev rules to use DM_SBIN_PATH when calling kpartx + * install udev rules to /lib/udev/rules.d instead of /etc/udev/rules.d +- Modify 0014-RH-add-hp_tur-checker.patch +- Add 0003-for-upstream-default-configs.patch +- Add 0016-RHBZ-554561-fix-init-error-msg.patch +- Add 0017-RHBZ-554592-man-page-note.patch +- Add 0018-RHBZ-554596-SUN-6540-config.patch +- Add 0019-RHBZ-554598-fix-multipath-locking.patch +- Add 0020-RHBZ-554605-fix-manual-failover.patch +- Add 0021-RHBZ-548874-add-find-multipaths.patch + * Added find_multipaths multipath.conf option + * Added /sbin/mpathconf for simple editting of multipath.conf +- Add 0022-RHBZ-557845-RHEL5-style-partitions.patch + * Make kpartx deal with logical partitions like it did in RHEL5. + Don't create a dm-device for the extended partition itself. + Create the logical partitions on top of the dm-device for the whole disk. + +* Mon Nov 16 2009 Benjamin Marzinski -0.4.9-11 +- Add 0002-for-upstream-add-tmo-config-options.patch + * Add fail_io_fail_tmo and dev_loss_tmo multipath.conf options +- Add 0013-RH-add-weighted_prio-prioritizer.patch +- Add 0014-RH-add-hp_tur-checker.patch +- Add 0015-RH-add-multipathd-count-paths-cmd.patch +- rename multipath.conf.redhat to multipath.conf, and remove the default + blacklist. + +* Tue Oct 27 2009 Fabio M. Di Nitto - 0.4.9-10 +- Updated to latest upstream 0.4.9 code : multipath-tools-091027.tar.gz + (git commit id: a946bd4e2a529e5fba9c9547d03d3f91806618a3) +- Drop unrequired for-upstream patches. +- BuildRequires and Requires new device-mapper version for udev sync support. + +* Tue Oct 20 2009 Fabio M. Di Nitto - 0.4.9-9 +- 0012-RH-explicitly-disable-dm-udev-sync-support-in-kpartx.patch + +* Mon Oct 19 2009 Fabio M. Di Nitto - 0.4.9-8 +- Split patches in "for-upstream" and "RH" series. +- Replace 0011-RH-multipathd-blacklist-all-by-default.patch with + version from Benjamin Marzinski. +- Update udev rules 0010-RH-multipath-rules-udev-changes.patch. +- rpmlint cleanup: + * Drop useless-provides kpartx. + * Cleanup tab vs spaces usage. + * Summary not capitalized. + * Missing docs in libs package. + * Fix init script LSB headers. +- Drop README* files from doc sections (they are empty). + +* Thu Oct 15 2009 Fabio M. Di Nitto - 0.4.9-7 +- Add patch 0010-RH-Set-friendly-defaults.patch: + * set rcdir to fedora default. + * do not install kpartx udev bits. + * install redhat init script. + * Cleanup spec file install target. +- Add patch 0011-RH-multipathd-blacklist-all-by-default.patch: + * Fix BZ#528059 + * Stop installing default config in /etc and move it to the doc dir. + +* Tue Oct 13 2009 Fabio M. Di Nitto - 0.4.9-6 +- Updated to latest upstream 0.4.9 code : multipath-tools-091013.tar.gz + (git commit id: aa0a885e1f19359c41b63151bfcface38ccca176) +- Drop, now upstream, patches: + * fix_missed_uevs.patch. + * log_all_messages.patch. + * uninstall.patch. + * select_lib.patch. + * directio_message_cleanup.patch. + * stop_warnings.patch. +- Drop redhatification.patch in favour of spec file hacks. +- Drop mpath_wait.patch: no longer required. +- Merge multipath_rules.patch and udev_change.patch. +- Rename all patches based on source. +- Add patch 0009-RH-fix-hp-sw-hardware-table-entries.patch to fix + default entry for hp_sw and match current kernel. +- Add multipath.conf.redhat as source instead of patch. +- spec file: + * divide runtime and build/setup bits. + * update BuildRoot. + * update install section to apply all the little hacks here and there, + in favour of patches against upstream. + * move ldconfig invokation to libs package where it belong. + * fix libs package directory ownership and files. + +* Thu Aug 20 2009 Benjamin Marzinski - 0.4.9-5 +- Fixed problem where maps were being added and then removed. +- Changed the udev rules to fix some issues. + +* Thu Jul 30 2009 Benjamin Marzinski - 0.4.9-4 +- Fixed build issue on i686 machines. + +* Wed Jul 29 2009 Benjamin Marzinski - 0.4.9-3 +- Updated to latest upstream 0.4.9 code : multipath-tools-090729.tgz + (git commit id: d678c139719d5631194b50e49f16ca97162ecd0f) +- moved multipath bindings file from /var/lib/multipath to /etc/multipath +- Fixed 354961, 432520 + +* Fri Jul 24 2009 Fedora Release Engineering - 0.4.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed May 6 2009 Mike Snitzer - 0.4.9-1 +- Updated to latest upstream 0.4.9 code: multipath-tools-090429.tgz + (git commit id: 7395bcda3a218df2eab1617df54628af0dc3456e) +- split the multipath libs out to a device-mapper-multipath-libs package +- if appropriate, install multipath libs in /lib64 and /lib64/multipath + +* Tue Apr 7 2009 Milan Broz - 0.4.8-10 +- Fix insecure permissions on multipathd.sock (CVE-2009-0115) + +* Fri Mar 6 2009 Milan Broz - 0.4.8-9 +- Fix kpartx extended partition handling (475283) + +* Tue Feb 24 2009 Fedora Release Engineering - 0.4.8-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Sep 26 2008 Benjamin Marzinski 0.4.8-7 +- Since libaio is now in /lib, not /usr/lib, multipath no longer needs to + statically link against it. Fixed an error with binding file and WWIDs + that include spaces. Cleaned up the messages from the directio checker + function. Fixed the udev rules. Fixed a regression in multipath.conf + parsing +- Fixed 457530, 457589 + +* Wed Aug 20 2008 Benjamin Marzinski 0.4.8-6 +- Updated to latest upstream 0.4.8 code: multipath-tools-080804.tgz + (git commit id: eb87cbd0df8adf61d1c74c025f7326d833350f78) +- fixed 451817, 456397 (scsi_id_change.patch), 457530 (config_space_fix.patch) + 457589 (static_libaio.patch) + +* Fri Jun 13 2008 Alasdair Kergon - 0.4.8-5 +- Rebuild (rogue vendor tag). (451292) + +* Mon May 19 2008 Benjamin Marzinksi 0.4.8-4 +- Fixed Makefile issues. + +* Mon May 19 2008 Benjamin Marzinksi 0.4.8-3 +- Fixed ownership build error. + +* Mon May 19 2008 Benjamin Marzinksi 0.4.8-2 +- Forgot to commit some patches. + +* Mon May 19 2008 Benjamin Marzinski 0.4.8-1 +- Updated to latest Upstream 0.4.8 code: multipath-tools-080519.tgz + (git commit id: 42704728855376d2f7da2de1967d7bc71bc54a2f) + +* Tue May 06 2008 Alasdair Kergon - 0.4.7-15 +- Remove unnecessary multipath & kpartx static binaries. (bz 234928) + +* Fri Feb 29 2008 Tom "spot" Callaway - 0.4.7-14 +- fix sparc64 +- fix license tag + +* Tue Feb 19 2008 Fedora Release Engineering - 0.4.7-13 +- Autorebuild for GCC 4.3 + +* Wed Nov 14 2007 Benjamin Marzinski - 0.4.7-12 +- Fixed the dist tag so building will work properly. + +* Mon Feb 05 2007 Alasdair Kergon - 0.4.7-11.fc7 +- Add build dependency on new device-mapper-devel package. +- Add dependency on device-mapper. + +* Wed Jan 31 2007 Benjamin Marzinksi - 0.4.7-10.fc7 +- Update BuildRoot and PreReq lines. + +* Mon Jan 15 2007 Benjamin Marzinksi - 0.4.7-9.fc7 +- Fixed spec file. + +* Mon Jan 15 2007 Benjamin Marzinski - 0.4.7-8.fc7 +- Update to latest code (t0_4_7_head2) + +* Wed Dec 13 2006 Benjamin Marzinski - 0.4.7-7.fc7 +- Update to latest code (t0_4_7_head1) + +* Thu Sep 7 2006 Peter Jones - 0.4.7-5 +- Fix kpartx to handle with drives >2TB correctly. + +* Thu Aug 31 2006 Peter Jones - 0.4.7-4.1 +- Split kpartx out into its own package so dmraid can use it without + installing multipathd +- Fix a segfault in kpartx + +* Mon Jul 17 2006 Benjamin Marzinski 0.4.7-4.0 +- Updated to latest source. Fixes bug in default multipath.conf + +* Wed Jul 12 2006 Benjamin Marzinski 0.4.7-3.1 +- Added ncurses-devel to BuildRequires + +* Wed Jul 12 2006 Benjamin Marzinski 0.4.7-3.0 +- Updated to latest source. deals with change in libsysfs API + +* Wed Jul 12 2006 Jesse Keating - 0.4.7-2.2.1 +- rebuild + +* Mon Jul 10 2006 Benjamin Marzinski 0.4.7-2.2 +- fix tagging issue. + +* Mon Jul 10 2006 Benjamin Marzinski 0.4.7-2.1 +- changed BuildRequires from sysfsutils-devel to libsysfs-devel + +* Wed Jun 28 2006 Benjamin Marzinski 0.4.7-2.0 +- Updated to latest upstream source, fixes kpartx udev rule issue + +* Tue Jun 06 2006 Benjamin Marzinski 0.4.7-1.0 +- Updated to Christophe's latest source + +* Mon May 22 2006 Alasdair Kergon - 0.4.5-16.0 +- Newer upstream source (t0_4_5_post59). + +* Mon May 22 2006 Alasdair Kergon - 0.4.5-12.3 +- BuildRequires: libsepol-devel, readline-devel + +* Mon Feb 27 2006 Benjamin Marzinski 0.4.5-12.2 +- Prereq: chkconfig + +* Mon Feb 20 2006 Karsten Hopp 0.4.5-12.1 +- BuildRequires: libselinux-devel + +* Fri Feb 10 2006 Jesse Keating - 0.4.5-12.0.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Benjamin Marzinski -0.4.5-12.0 +- Updated to latest upstream source (t0_4_5_post56) + +* Tue Feb 07 2006 Jesse Keating - 0.4.5-9.1.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Dec 19 2005 Benjamin Marzinski - 0.4.5-9.1 +- added patch for fedora changes + +* Fri Dec 16 2005 Benjamin Marzinski - 0.4.5-9.0 +- Updated to latest upstream source (t)_4_5_post52) + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Sun Dec 4 2005 Peter Jones - 0.4.4-2.6 +- rebuild for newer libs + +* Tue Nov 15 2005 Peter Jones - 0.4.4-2.5 +- unsplit kpartx. parted knows how to do this now, so we don't + need this in a separate package. + +* Tue Nov 15 2005 Peter Jones - 0.4.4-2.4 +- split kpartx out into its own package + +* Fri May 06 2005 Bill Nottingham - 0.4.4-2.3 +- Fix last fix. + +* Thu May 05 2005 Alasdair Kergon - 0.4.4-2.2 +- Fix last fix. + +* Wed May 04 2005 Alasdair Kergon - 0.4.4-2.1 +- By default, disable the multipathd service. + +* Tue Apr 19 2005 Alasdair Kergon - 0.4.4-2.0 +- Fix core dump from last build. + +* Tue Apr 19 2005 Alasdair Kergon - 0.4.4-1.0 +- Move cache file into /var/cache/multipath. + +* Fri Apr 08 2005 Alasdair Kergon - 0.4.4-0.pre8.1 +- Remove pp_balance_units. + +* Mon Apr 04 2005 Alasdair Kergon - 0.4.4-0.pre8.0 +- Incorporate numerous upstream fixes. +- Update init script to distribution standards. + +* Tue Mar 01 2005 Alasdair Kergon - 0.4.2-1.0 +- Initial import based on Christophe Varoqui's spec file.