RHEL 9.0.0 Alpha bootstrap

The content of this branch was automatically imported from Fedora ELN
with the following as its source:
https://src.fedoraproject.org/rpms/device-mapper-multipath#2cf40b2f98808e3533e915c0a204b885d9da5e43
This commit is contained in:
Petr Šabata 2020-10-14 23:36:17 +02:00
parent 295eb4a3cc
commit de5fe16817
131 changed files with 19792 additions and 0 deletions

22
.gitignore vendored
View File

@ -0,0 +1,22 @@
multipath-tools-091027.tar.gz
/multipath-tools-120123.tgz
/multipath-tools-120613.tgz
/multipath-tools-120821.tgz
/multipath-tools-130222.tgz
/multipath-tools-f21166a.tgz
/multipath.conf
/multipath-tools-git847cc43.tgz
/multipath-tools-0.7.3.tgz
/multipath-tools-07e7bd5.tgz
/multipath-tools-1cb704b.tgz
/multipath-tools-0.7.7.tgz
/multipath-tools-ef6d98b.tgz
/multipath-tools-1a8625a.tgz
/multipath-tools-b80318b.tgz
/multipath-tools-0.7.8.tgz
/multipath-tools-0.7.9.tgz
/multipath-tools-17a6101.tgz
/multipath-tools-2df6110.tgz
/multipath-tools-0.8.0.tgz
/multipath-tools-0.8.2.tgz
/multipath-tools-0.8.4.tgz

View File

@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 6 Mar 2020 21:50:30 +0100
Subject: [PATCH] libmpathpersist: limit PRIN allocation length to 8192 bytes
Some targets (notably the qemu-pr-helper) don't support PERSISTENT
RESERVE IN commands with more than 8192 bytes allocation length.
While I have found no explicit requirement in the SCSI specs that
the allocation lengh may not exceed 8k, an 8k limit is also enforced
by sg_persist(8), and actually by mpathpersist itself for the
--allocation-length option, but not for the auto-determined length.
Fix that.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_pr_ioctl.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
index 74b26b0c..1a28cba7 100644
--- a/libmpathpersist/mpath_pr_ioctl.c
+++ b/libmpathpersist/mpath_pr_ioctl.c
@@ -543,5 +543,7 @@ int get_prin_length(int rq_servact)
mx_resp_len = 0;
break;
}
+ if (mx_resp_len > MPATH_MAX_PARAM_LEN)
+ mx_resp_len = MPATH_MAX_PARAM_LEN;
return mx_resp_len;
}
--
2.17.2

View File

@ -0,0 +1,93 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 6 Mar 2020 23:33:04 +0100
Subject: [PATCH] libmpathpersist: format_transportids(): avoid PROUT overflow
This limits the PERSISTENT RESERVE OUT data size to max. 8192 bytes.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_pr_ioctl.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
index 1a28cba7..c78e8000 100644
--- a/libmpathpersist/mpath_pr_ioctl.c
+++ b/libmpathpersist/mpath_pr_ioctl.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -138,38 +139,64 @@ retry :
return status;
}
+/*
+ * Helper macro to avoid overflow of prout_param_descriptor in
+ * format_transportids(). Data must not be written past
+ * MPATH_MAX_PARAM_LEN bytes from struct prout_param_descriptor.
+ */
+#define check_overflow(ofs, n, start, label) \
+ do { \
+ if ((ofs) + (n) + \
+ offsetof(struct prout_param_descriptor, private_buffer) \
+ > MPATH_MAX_PARAM_LEN) \
+ { \
+ (ofs) = (start); \
+ goto label; \
+ } \
+ } while(0)
+
uint32_t format_transportids(struct prout_param_descriptor *paramp)
{
unsigned int i = 0, len;
uint32_t buff_offset = 4;
- memset(paramp->private_buffer, 0, MPATH_MAX_PARAM_LEN);
+ memset(paramp->private_buffer, 0, sizeof(paramp->private_buffer));
for (i=0; i < paramp->num_transportid; i++ )
{
+ uint32_t start_offset = buff_offset;
+
+ check_overflow(buff_offset, 1, start_offset, end_loop);
paramp->private_buffer[buff_offset] = (uint8_t)((paramp->trnptid_list[i]->format_code & 0xff)|
(paramp->trnptid_list[i]->protocol_id & 0xff));
buff_offset += 1;
switch(paramp->trnptid_list[i]->protocol_id)
{
case MPATH_PROTOCOL_ID_FC:
+ check_overflow(buff_offset, 7 + 8 + 8,
+ start_offset, end_loop);
buff_offset += 7;
memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->n_port_name, 8);
buff_offset +=8 ;
buff_offset +=8 ;
break;
case MPATH_PROTOCOL_ID_SAS:
+ check_overflow(buff_offset, 3 + 12,
+ start_offset, end_loop);
buff_offset += 3;
memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->sas_address, 8);
buff_offset += 12;
break;
case MPATH_PROTOCOL_ID_ISCSI:
- buff_offset += 1;
len = (paramp->trnptid_list[i]->iscsi_name[1] & 0xff)+2;
+ check_overflow(buff_offset, 1 + len,
+ start_offset, end_loop);
+ buff_offset += 1;
memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->iscsi_name,len);
buff_offset += len ;
break;
}
}
+end_loop:
buff_offset -= 4;
paramp->private_buffer[0] = (unsigned char)((buff_offset >> 24) & 0xff);
paramp->private_buffer[1] = (unsigned char)((buff_offset >> 16) & 0xff);
--
2.17.2

View File

@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 6 Mar 2020 23:46:47 +0100
Subject: [PATCH] libmpathpersist: mpath_format_readfullstatus(): use real
buffer size
This changes no semantics, but it will allow changing the size of
prin_readfd.private_buffer in a follow-up patch.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_pr_ioctl.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
index c78e8000..fadc9e10 100644
--- a/libmpathpersist/mpath_pr_ioctl.c
+++ b/libmpathpersist/mpath_pr_ioctl.c
@@ -238,6 +238,8 @@ static void mpath_format_readfullstatus(struct prin_resp *pr_buff)
uint32_t additional_length, k, tid_len_len = 0;
char tempbuff[MPATH_MAX_PARAM_LEN];
struct prin_fulldescr fdesc;
+ static const int pbuf_size =
+ sizeof(pr_buff->prin_descriptor.prin_readfd.private_buffer);
convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readfd.prgeneration);
convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readfd.number_of_descriptor);
@@ -249,16 +251,18 @@ static void mpath_format_readfullstatus(struct prin_resp *pr_buff)
}
additional_length = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
- if (additional_length > MPATH_MAX_PARAM_LEN) {
+ if (additional_length > pbuf_size) {
condlog(3, "PRIN length %u exceeds max length %d", additional_length,
- MPATH_MAX_PARAM_LEN);
+ pbuf_size);
return;
}
memset(&fdesc, 0, sizeof(struct prin_fulldescr));
- memcpy( tempbuff, pr_buff->prin_descriptor.prin_readfd.private_buffer,MPATH_MAX_PARAM_LEN );
- memset(&pr_buff->prin_descriptor.prin_readfd.private_buffer, 0, MPATH_MAX_PARAM_LEN);
+ memcpy( tempbuff, pr_buff->prin_descriptor.prin_readfd.private_buffer,
+ pbuf_size);
+ memset(&pr_buff->prin_descriptor.prin_readfd.private_buffer, 0,
+ pbuf_size);
p =(unsigned char *)tempbuff;
ppbuff = (char *)pr_buff->prin_descriptor.prin_readfd.private_buffer;
--
2.17.2

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 25 Mar 2020 23:22:46 -0500
Subject: [PATCH] libmultipath: assign variable to make gcc happy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There is nothing wrong with is_queueing not being set at the start
of __set_no_path_retry(), it will always get set before it is accessed,
but gcc 8.2.1 is failing with
structs_vec.c: In function __set_no_path_retry:
structs_vec.c:339:7: error: is_queueing may be used uninitialized in
this function [-Werror=maybe-uninitialized]
bool is_queueing;
^~~~~~~~~~~
so, assign a value to make it happy.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 3dbbaa0f..077f2e42 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -336,7 +336,7 @@ static void leave_recovery_mode(struct multipath *mpp)
void __set_no_path_retry(struct multipath *mpp, bool check_features)
{
- bool is_queueing;
+ bool is_queueing = false; /* assign a value to make gcc happy */
check_features = check_features && mpp->features != NULL;
if (check_features)
--
2.17.2

View File

@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 25 Mar 2020 23:22:47 -0500
Subject: [PATCH] libmutipath: don't close fd on dm_lib_release
If dm_hold_control_open() isn't set, when dm_lib_release() is called, it
will close the control fd. The control fd will get re-opened on the next
dm_task_run() call, but if there is a dm_task_run() call already
in progress in another thread, it can fail. Since many of the
device-mapper callouts happen with the vecs lock held, this wasn't too
noticeable, but there is code that calls dm_task_run() without the
vecs lock held, notably the dmevent waiter code.
Since, as Martin pointed out, dm_hold_control_open() hasn't always
existed in libdevmapper, check if it's supported on compilation,
and update the version requirements if so.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/Makefile | 4 ++++
libmultipath/devmapper.c | 7 ++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index e5651e49..ad690a49 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -36,6 +36,10 @@ ifneq ($(call check_func,dm_task_deferred_remove,/usr/include/libdevmapper.h),0)
CFLAGS += -DLIBDM_API_DEFERRED
endif
+ifneq ($(call check_func,dm_hold_control_dev,/usr/include/libdevmapper.h),0)
+ CFLAGS += -DLIBDM_API_HOLD_CONTROL
+endif
+
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o discovery.o propsel.o dict.o \
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index bed8ddc6..13a1cf53 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -108,7 +108,9 @@ dm_lib_prereq (void)
{
char version[64];
int v[3];
-#if defined(LIBDM_API_DEFERRED)
+#if defined(LIBDM_API_HOLD_CONTROL)
+ int minv[3] = {1, 2, 111};
+#elif defined(LIBDM_API_DEFERRED)
int minv[3] = {1, 2, 89};
#elif defined(DM_SUBSYSTEM_UDEV_FLAG0)
int minv[3] = {1, 2, 82};
@@ -254,6 +256,9 @@ void libmp_dm_init(void)
memcpy(conf->version, version, sizeof(version));
put_multipath_config(conf);
dm_init(verbosity);
+#ifdef LIBDM_API_HOLD_CONTROL
+ dm_hold_control_dev(1);
+#endif
dm_udev_set_sync_support(libmp_dm_udev_sync);
}
--
2.17.2

View File

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 25 Mar 2020 23:22:48 -0500
Subject: [PATCH] libmultipath: allow force reload with no active paths
If the partition information has changed on multipath devices (say,
because it was updated on another node that has access to the same
storage), users expect that running "multipathd reconfigure" will update
that. However, if the checkers for the multipath device are pending for
too long when the the device is reconfigured, multipathd will give up
waiting for them, and refuse to reload the device, since there are no
active paths. This means that no kpartx update will be triggered.
Multipath is fully capable of reloading a multipath device that has no
active paths. This has been possible for years. If multipath is supposed
to reload the device, it should do so, even if there are no active paths.
Generally, when multipath is force reloaded, kpartx will be updated.
However when a device is reloaded with no paths, the udev rules won't
run kpartx. But they also weren't running kpartx when the first valid
path appeared, even though the dm activation rules get run in this case.
This changes 11-dm-mpath.rules to run kpartx when a device goes from no
usable paths to having usable paths.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/configure.c | 6 ------
multipath/11-dm-mpath.rules | 2 +-
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index c95848a0..96c79610 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -710,12 +710,6 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
return;
}
- if (pathcount(mpp, PATH_UP) == 0) {
- mpp->action = ACT_IMPOSSIBLE;
- condlog(3, "%s: set ACT_IMPOSSIBLE (no usable path)",
- mpp->alias);
- return;
- }
if (force_reload) {
mpp->force_udev_reload = 1;
mpp->action = ACT_RELOAD;
diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
index 07320a14..cd522e8c 100644
--- a/multipath/11-dm-mpath.rules
+++ b/multipath/11-dm-mpath.rules
@@ -75,7 +75,7 @@ ENV{MPATH_DEVICE_READY}=="0", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="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"
+ ENV{DM_ACTIVATION}="1", ENV{MPATH_UNCHANGED}="0"
# The code to check multipath state ends here. We need to set
# properties and symlinks regardless whether the map is usable or
--
2.17.2

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 3 Apr 2020 13:03:01 +0200
Subject: [PATCH] kpartx.rules: honor DM_UDEV_DISABLE_OTHER_RULES_FLAG
10-dm.rules sets DM_UDEV_DISABLE_OTHER_RULES_FLAG for spurious
events that should be ignored by other layers. This means devices
with DISK_RO set, and devices that have never been set up properly
by device-mapper before. This flag should be respected by kpartx.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/kpartx.rules | 1 +
1 file changed, 1 insertion(+)
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
index 8f990494..f1bf31ca 100644
--- a/kpartx/kpartx.rules
+++ b/kpartx/kpartx.rules
@@ -7,6 +7,7 @@
KERNEL!="dm-*", GOTO="kpartx_end"
ACTION!="add|change", GOTO="kpartx_end"
ENV{DM_UUID}!="?*", GOTO="kpartx_end"
+ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="kpartx_end"
# Create dm tables for partitions on multipath devices.
ENV{DM_UUID}!="mpath-?*", GOTO="mpath_kpartx_end"
--
2.17.2

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 2 Apr 2020 18:12:48 +0200
Subject: [PATCH] kpartx.rules: check for skip_kpartx on synthetic uevents
The current test to detect "spurious" uevents, and thus whether to
import DM_SUBSYSTEM_UDEV_FLAG1 (the flag for the "skip_kpartx" option)
from the udev db is wrong. In 10-dm.rules, DM_UDEV_PRIMARY_SOURCE_FLAG
is imported from the db if it isn't set, meaning that it's always 1
for active maps. The only events for which DM_SUBSYSTEM_UDEV_FLAG1
must not be loaded from the db are the real "primary" events, which
are "change" events with DM_ACTIVATION=="1".
11-dm-mpath.rules resets DM_ACTIVATION to 0 if nothing should change in upper
layers. In this case importing DM_SUBSYSTEM_UDEV_FLAG1 is correct, too. kpartx
will not be called anyway, because 11-dm-mpath.rules also sets MPATH_UNCHANGED=1.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/kpartx.rules | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
index f1bf31ca..d7527d7d 100644
--- a/kpartx/kpartx.rules
+++ b/kpartx/kpartx.rules
@@ -13,8 +13,11 @@ ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="kpartx_end"
ENV{DM_UUID}!="mpath-?*", GOTO="mpath_kpartx_end"
# DM_SUBSYSTEM_UDEV_FLAG1 is the "skip_kpartx" flag.
-# For events not generated by libdevmapper, we need to fetch it from db.
-ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1"
+# For events not generated by libdevmapper, we need to fetch it from db:
+# - "change" events with DM_ACTIVATION!="1" (e.g. partition table changes)
+# - "add" events for which rules are not disabled ("coldplug" case)
+ENV{DM_ACTIVATION}!="1", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1"
+ACTION=="add", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1"
ENV{DM_SUBSYSTEM_UDEV_FLAG1}=="1", GOTO="mpath_kpartx_end"
# 11-dm-mpath.rules sets MPATH_UNCHANGED for events that can be ignored.
--
2.17.2

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Christian Hesse <mail@eworm.de>
Date: Wed, 6 May 2020 09:35:47 +0200
Subject: [PATCH] libmpathpersist: depend on libmultipath
Without this the build fails with:
/usr/bin/ld: cannot find -lmultipath
Signed-off-by: Christian Hesse <mail@eworm.de>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1dee3680..ba1d73ba 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ all: $(BUILDDIRS)
$(BUILDDIRS):
$(MAKE) -C $@
-multipath multipathd mpathpersist: libmultipath
+libmpathpersist multipath multipathd mpathpersist: libmultipath
mpathpersist: libmpathpersist
$(BUILDDIRS.clean):
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 14:24:37 +0200
Subject: [PATCH] multipath-tools: Makefile: more dependency fixes for parallel
build
Extend the late fixes from Christian.
Cc: Christian Hesse <mail@eworm.de>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index ba1d73ba..fec3b73b 100644
--- a/Makefile
+++ b/Makefile
@@ -28,8 +28,9 @@ all: $(BUILDDIRS)
$(BUILDDIRS):
$(MAKE) -C $@
-libmpathpersist multipath multipathd mpathpersist: libmultipath
-mpathpersist: libmpathpersist
+libmultipath libdmmp: libmpathcmd
+libmpathpersist multipath multipathd: libmultipath
+mpathpersist multipathd: libmpathpersist
$(BUILDDIRS.clean):
$(MAKE) -C ${@:.clean=} clean
--
2.17.2

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 15:27:34 +0200
Subject: [PATCH] multipath-tools: Makefile.inc: separate out OPTFLAGS
OPTFLAGS is what distribution builds would typically override. That
should not include the warning flags we use.
Moreover, in the definition of CFLAGS, put $(CFLAGS) first to make it
easier for the user to spot her input in the build logs.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index d4d1e0dd..7a59db85 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -93,14 +93,14 @@ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered,)
-OPTFLAGS = -O2 -g -pipe -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
+OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4
+WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
-Werror=implicit-function-declaration -Werror=format-security \
- $(WNOCLOBBERED) \
- -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
- $(STACKPROT) --param=ssp-buffer-size=4
+ $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS)
CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2
-CFLAGS := $(OPTFLAGS) -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
- -MMD -MP $(CFLAGS)
+CFLAGS := $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
+ -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
+ -MMD -MP
BIN_CFLAGS = -fPIE -DPIE
LIB_CFLAGS = -fPIC
SHARED_FLAGS = -shared
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 16:00:04 +0200
Subject: [PATCH] multipath-tools: Makefile.inc: allow user settings for
LDFLAGS
This allows e.g. setting LDFLAGS="-m32 -Wl,-b,elf32-i386" to compile
for a 32bit target on a 64bit system.
Note that, like CFLAGS, the variable needs to be set in the environment,
not on the "make" command line.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.inc b/Makefile.inc
index 7a59db85..671dd1ca 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -104,7 +104,7 @@ CFLAGS := $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
BIN_CFLAGS = -fPIE -DPIE
LIB_CFLAGS = -fPIC
SHARED_FLAGS = -shared
-LDFLAGS = -Wl,-z,relro -Wl,-z,now
+LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now
BIN_LDFLAGS = -pie
# Check whether a function with name $1 has been declared in header file $2.
--
2.17.2

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 17:19:37 +0200
Subject: [PATCH] multipath-tools: Makefile.inc: set -Wno-error=clobbered
We need to ignore -Wclobbered because gcc has trouble dealing with glibc's
implementation of pthread_cleanup_push().
For some variants of gcc, -Wno-clobbered alone isn't enough if -Werror is also
set. Compilation with -Wno-error=clobbered works, though.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.inc b/Makefile.inc
index 671dd1ca..e7256e3a 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -91,7 +91,7 @@ TEST_CC_OPTION = $(shell \
STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
-WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered,)
+WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4
WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
--
2.17.2

View File

@ -0,0 +1,90 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 16:02:25 +0200
Subject: [PATCH] libmultipath: discovery.c: use %z qualifier for size_t
Otherwise compilation for 32bit targets spits out warnings.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index ee3290cd..ffec5162 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -986,7 +986,7 @@ parse_vpd_pg80(const unsigned char *in, char *out, size_t out_len)
}
if (len >= out_len) {
- condlog(2, "vpd pg80 overflow, %lu/%lu bytes required",
+ condlog(2, "vpd pg80 overflow, %zu/%zu bytes required",
len + 1, out_len);
len = out_len - 1;
}
@@ -1087,7 +1087,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
len = sprintf(out, "%d", vpd_type);
if (2 * vpd_len >= out_len - len) {
- condlog(1, "%s: WWID overflow, type %d, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type %d, %zu/%zu bytes required",
__func__, vpd_type,
2 * vpd_len + len + 1, out_len);
vpd_len = (out_len - len - 1) / 2;
@@ -1096,7 +1096,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
len += sprintf(out + len,
"%02x", vpd[i]);
} else if (vpd_type == 0x8 && vpd_len < 4) {
- condlog(1, "%s: VPD length %lu too small for designator type 8",
+ condlog(1, "%s: VPD length %zu too small for designator type 8",
__func__, vpd_len);
return -EINVAL;
} else if (vpd_type == 0x8) {
@@ -1112,7 +1112,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
while (len > 2 && vpd[len - 2] == '\0')
--len;
if (len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 8/%c, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type 8/%c, %zu/%zu bytes required",
__func__, out[0], len + 1, out_len);
len = out_len - 1;
}
@@ -1136,7 +1136,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
while ((p = memchr(vpd, ' ', vpd_len))) {
p_len = p - vpd;
if (len + p_len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 1, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
__func__, len + p_len, out_len);
p_len = out_len - len - 1;
}
@@ -1162,7 +1162,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
p_len = vpd_len;
if (p_len > 0 && len < out_len - 1) {
if (len + p_len > out_len - 1) {
- condlog(1, "%s: WWID overflow, type 1, %lu/%lu bytes required",
+ condlog(1, "%s: WWID overflow, type 1, %zu/%zu bytes required",
__func__, len + p_len + 1, out_len);
p_len = out_len - len - 1;
}
@@ -1186,14 +1186,14 @@ parse_vpd_c0_hp3par(const unsigned char *in, size_t in_len,
memset(out, 0x0, out_len);
if (in_len <= 4 || (in[4] > 3 && in_len < 44)) {
- condlog(3, "HP/3PAR vendor specific VPD page length too short: %lu", in_len);
+ condlog(3, "HP/3PAR vendor specific VPD page length too short: %zu", in_len);
return -EINVAL;
}
if (in[4] <= 3) /* revision must be > 3 to have Vomlume Name */
return -ENODATA;
len = get_unaligned_be32(&in[40]);
if (len > out_len || len + 44 > in_len) {
- condlog(3, "HP/3PAR vendor specific Volume name too long: %lu",
+ condlog(3, "HP/3PAR vendor specific Volume name too long: %zu",
len);
return -EINVAL;
}
--
2.17.2

View File

@ -0,0 +1,198 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 16:03:58 +0200
Subject: [PATCH] libmultipath: eliminate more signed/unsigned comparisons
Fix some more compiler warnings about signed/unsigned comparison.
I've observed these only on 32bit builds, therefore they went unnoticed
before.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_pr_ioctl.c | 2 +-
libmultipath/print.c | 12 ++++++------
libmultipath/prioritizers/alua_spc3.h | 2 +-
multipathd/cli_handlers.c | 20 ++++++++++----------
multipathd/main.c | 2 +-
5 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
index fadc9e10..126601c3 100644
--- a/libmpathpersist/mpath_pr_ioctl.c
+++ b/libmpathpersist/mpath_pr_ioctl.c
@@ -238,7 +238,7 @@ static void mpath_format_readfullstatus(struct prin_resp *pr_buff)
uint32_t additional_length, k, tid_len_len = 0;
char tempbuff[MPATH_MAX_PARAM_LEN];
struct prin_fulldescr fdesc;
- static const int pbuf_size =
+ static const unsigned int pbuf_size =
sizeof(pr_buff->prin_descriptor.prin_readfd.private_buffer);
convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readfd.prgeneration);
diff --git a/libmultipath/print.c b/libmultipath/print.c
index b944ef32..298b3764 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -1958,25 +1958,25 @@ char *snprint_config(const struct config *conf, int *len,
}
c = reply + snprint_defaults(conf, reply, maxlen);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_blacklist(conf, c, reply + maxlen - c);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_blacklist_except(conf, c, reply + maxlen - c);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_hwtable(conf, c, reply + maxlen - c,
hwtable ? hwtable : conf->hwtable);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
c += snprint_overrides(conf, c, reply + maxlen - c,
conf->overrides);
- if ((c - reply) == maxlen)
+ if (c == reply + maxlen)
continue;
if (VECTOR_SIZE(conf->mptable) > 0 ||
@@ -1984,7 +1984,7 @@ char *snprint_config(const struct config *conf, int *len,
c += snprint_mptable(conf, c, reply + maxlen - c,
mpvec);
- if ((c - reply) < maxlen) {
+ if (c < reply + maxlen) {
if (len)
*len = c - reply;
return reply;
diff --git a/libmultipath/prioritizers/alua_spc3.h b/libmultipath/prioritizers/alua_spc3.h
index 18b495ef..7ba2cf4c 100644
--- a/libmultipath/prioritizers/alua_spc3.h
+++ b/libmultipath/prioritizers/alua_spc3.h
@@ -284,7 +284,7 @@ struct rtpg_data {
#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
for( \
g = &(p->data[0]); \
- (((char *) g) - ((char *) p)) < get_unaligned_be32(p->length); \
+ ((char *) g) < ((char *) p) + get_unaligned_be32(p->length); \
g = (struct rtpg_tpg_dscr *) ( \
((char *) g) + \
sizeof(struct rtpg_tpg_dscr) + \
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 7d878c88..31c3d9fd 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -66,7 +66,7 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
c += snprint_foreign_paths(c, reply + maxlen - c,
style, pretty);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -102,7 +102,7 @@ show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
c += snprint_path(c, reply + maxlen - c, style, pp, 0);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -131,7 +131,7 @@ show_map_topology (char ** r, int * len, struct multipath * mpp,
c = reply;
c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -171,7 +171,7 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
}
c += snprint_foreign_topology(c, reply + maxlen - c, 2);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -209,7 +209,7 @@ show_maps_json (char ** r, int * len, struct vectors * vecs)
c = reply;
c += snprint_multipath_topology_json(c, maxlen, vecs);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -238,7 +238,7 @@ show_map_json (char ** r, int * len, struct multipath * mpp,
c = reply;
c += snprint_multipath_map_json(c, maxlen, mpp);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -487,7 +487,7 @@ show_map (char ** r, int *len, struct multipath * mpp, char * style,
c += snprint_multipath(c, reply + maxlen - c, style,
mpp, pretty);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -533,7 +533,7 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
}
c += snprint_foreign_multipaths(c, reply + maxlen - c,
style, pretty);
- again = ((c - reply) == (maxlen - 1));
+ again = (c == reply + maxlen - 1);
REALLOC_REPLY(reply, again, maxlen);
}
@@ -1297,7 +1297,7 @@ show_blacklist (char ** r, int * len)
c = reply;
c += snprint_blacklist_report(conf, c, maxlen);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
pthread_cleanup_pop(1);
@@ -1339,7 +1339,7 @@ show_devices (char ** r, int * len, struct vectors *vecs)
c = reply;
c += snprint_devices(conf, c, maxlen, vecs);
- again = ((c - reply) == maxlen);
+ again = (c == reply + maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
pthread_cleanup_pop(1);
diff --git a/multipathd/main.c b/multipathd/main.c
index 8baf9abe..6b7db2c0 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2374,7 +2374,7 @@ checkerloop (void *ap)
conf = get_multipath_config();
max_checkint = conf->max_checkint;
put_multipath_config(conf);
- if (diff_time.tv_sec > max_checkint)
+ if (diff_time.tv_sec > (time_t)max_checkint)
condlog(1, "path checkers took longer "
"than %lu seconds, consider "
"increasing max_polling_interval",
--
2.17.2

View File

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 22:22:25 +0200
Subject: [PATCH] libmultipath: set_uint: fix parsing for 32bit
On architectures where sizeof(long) == sizeof(int), the code wouldn't
work as intended. Use strtoul instead. As strtoul happily parses
negative numbers as input, require the number to begin with a digit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 3e25e74f..0e9ea387 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -60,19 +60,22 @@ static int
set_uint(vector strvec, void *ptr)
{
unsigned int *uint_ptr = (unsigned int *)ptr;
- char *buff, *eptr;
- long res;
+ char *buff, *eptr, *p;
+ unsigned long res;
int rc;
buff = set_value(strvec);
if (!buff)
return 1;
- res = strtol(buff, &eptr, 10);
+ p = buff;
+ while (isspace(*p))
+ p++;
+ res = strtoul(p, &eptr, 10);
if (eptr > buff)
while (isspace(*eptr))
eptr++;
- if (*buff == '\0' || *eptr != '\0' || res < 0 || res > UINT_MAX) {
+ if (*buff == '\0' || *eptr != '\0' || !isdigit(*p) || res > UINT_MAX) {
condlog(1, "%s: invalid value for %s: \"%s\"",
__func__, (char*)VECTOR_SLOT(strvec, 0), buff);
rc = 1;
--
2.17.2

View File

@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 18:24:19 +0200
Subject: [PATCH] multipath-tools tests/Makefile: add -lmpathcmd to LIBDEPS
Make sure the linker finds libmpathcmd.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
tests/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Makefile b/tests/Makefile
index 77ff3249..028c9ea7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -10,7 +10,7 @@ W_MISSING_INITIALIZERS := $(call TEST_MISSING_INITIALIZERS)
CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \
-Wno-unused-parameter $(W_MISSING_INITIALIZERS)
-LIBDEPS += -L$(multipathdir) -lmultipath -lcmocka
+LIBDEPS += -L$(multipathdir) -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka
TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
alias directio
--
2.17.2

View File

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 23:44:19 +0200
Subject: [PATCH] multipath tools tests/Makefile: Fix OBJDEPS for hwtable-test
OBJDEPS needs to list object files that _call_ functions we want
to wrap, but it should _not_ list the object files where these
functions are defined; otherwise the linker might resolve these
symbols before they can be wrapped.
(Observed on i586 with gcc 9.3.1, ld 2.34.0, where wrapping
prio_getprio() doesn't work with prio.o in OBJDEPS).
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
tests/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Makefile b/tests/Makefile
index 028c9ea7..1b8706a7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -41,7 +41,7 @@ endif
dmevents-test_LIBDEPS = -lpthread -ldevmapper -lurcu
hwtable-test_TESTDEPS := test-lib.o
hwtable-test_OBJDEPS := ../libmultipath/discovery.o ../libmultipath/blacklist.o \
- ../libmultipath/prio.o ../libmultipath/callout.o ../libmultipath/structs.o
+ ../libmultipath/structs.o
hwtable-test_LIBDEPS := -ludev -lpthread -ldl
blacklist-test_TESTDEPS := test-log.o
blacklist-test_OBJDEPS := ../libmultipath/blacklist.o
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 11 May 2020 23:43:02 +0200
Subject: [PATCH] multipath-tools tests/test-lib.c: drop
__wrap_is_claimed_by_foreign
is_claimed_by_foreign() is an inline function and can't be wrapped.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
tests/test-lib.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/tests/test-lib.c b/tests/test-lib.c
index 59275163..00bae58e 100644
--- a/tests/test-lib.c
+++ b/tests/test-lib.c
@@ -56,12 +56,6 @@ int __wrap_execute_program(char *path, char *value, int len)
return 0;
}
-bool __wrap_is_claimed_by_foreign(struct udev_device *ud)
-{
- condlog(5, "%s: %p", __func__, ud);
- return false;
-}
-
struct udev_list_entry
*__wrap_udev_device_get_properties_list_entry(struct udev_device *ud)
{
--
2.17.2

View File

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 00:11:39 +0200
Subject: [PATCH] multipath-tools tests/directio: fix -Wmaybe-uninitalized
warning
Initialize aio_grp to satisfy gcc.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
tests/directio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/directio.c b/tests/directio.c
index 3cd7a520..66aaf0eb 100644
--- a/tests/directio.c
+++ b/tests/directio.c
@@ -316,7 +316,7 @@ static void test_init_free(void **state)
{
int i, count = 0;
struct checker c[4096] = {0};
- struct aio_group *aio_grp;
+ struct aio_group *aio_grp = NULL;
assert_true(list_empty(&aio_grp_list));
will_return(__wrap_io_setup, 0);
--
2.17.2

View File

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 16:46:15 +0200
Subject: [PATCH] libmultipath: move libsg into libmultipath
sg_read() is called from readsector0 and emc_clariion. Move it
to libmultipath/, where all common code resides.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/Makefile | 3 ++-
libmultipath/checkers/Makefile | 6 +++---
libmultipath/{checkers => }/libsg.c | 0
libmultipath/{checkers => }/libsg.h | 0
libmultipath/prioritizers/Makefile | 2 +-
5 files changed, 6 insertions(+), 5 deletions(-)
rename libmultipath/{checkers => }/libsg.c (100%)
rename libmultipath/{checkers => }/libsg.h (100%)
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index ad690a49..f19b7ad2 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -47,7 +47,8 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.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 file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
- io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o
+ io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o \
+ libsg.o
all: $(LIBS)
diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile
index 02caea64..01c04510 100644
--- a/libmultipath/checkers/Makefile
+++ b/libmultipath/checkers/Makefile
@@ -17,10 +17,10 @@ LIBS= \
all: $(LIBS)
-libcheckdirectio.so: libsg.o directio.o
+libcheckdirectio.so: directio.o
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio
-libcheck%.so: libsg.o %.o
+libcheck%.so: %.o
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^
install:
@@ -32,7 +32,7 @@ uninstall:
clean: dep_clean
$(RM) core *.a *.o *.gz *.so
-OBJS := $(LIBS:libcheck%.so=%.o) libsg.o directio.o
+OBJS := $(LIBS:libcheck%.so=%.o)
.SECONDARY: $(OBJS)
include $(wildcard $(OBJS:.o=.d))
diff --git a/libmultipath/checkers/libsg.c b/libmultipath/libsg.c
similarity index 100%
rename from libmultipath/checkers/libsg.c
rename to libmultipath/libsg.c
diff --git a/libmultipath/checkers/libsg.h b/libmultipath/libsg.h
similarity index 100%
rename from libmultipath/checkers/libsg.h
rename to libmultipath/libsg.h
diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile
index 9d0fe03c..fc6e0e0c 100644
--- a/libmultipath/prioritizers/Makefile
+++ b/libmultipath/prioritizers/Makefile
@@ -28,7 +28,7 @@ endif
all: $(LIBS)
-libpriopath_latency.so: path_latency.o ../checkers/libsg.o
+libpriopath_latency.so: path_latency.o
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lm
libprio%.so: %.o
--
2.17.2

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 12 May 2020 22:13:51 +0200
Subject: [PATCH] multipath-tools Makefile: add install dependency
$(libdir) must exist before running "make install" on prioritizer, checker,
and foreign libraries.
Cc: Christian Hesse <mail@eworm.de>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Makefile b/Makefile
index fec3b73b..8bcaba66 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,10 @@ libmultipath libdmmp: libmpathcmd
libmpathpersist multipath multipathd: libmultipath
mpathpersist multipathd: libmpathpersist
+libmultipath/checkers.install \
+ libmultipath/prioritizers.install \
+ libmultipath/foreign.install: libmultipath.install
+
$(BUILDDIRS.clean):
$(MAKE) -C ${@:.clean=} clean
--
2.17.2

View File

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 19 May 2020 12:08:40 -0500
Subject: [PATCH] libmultipath: make libmp_dm_init optional
Move dm_initialized out of libmp_dm_task_create(), and add
a function skip_libmp_dm_init() so that users of libmultipath can skip
initializing device-mapper. This is needed for other programs that
use libmultipath (or a library that depends on it) but want to control
how device-mapper is set up.
Also make dm_prereq a global function.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 17 +++++++++++++----
libmultipath/devmapper.h | 3 ++-
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 13a1cf53..7ed494a1 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -33,6 +33,8 @@
#define MAX_WAIT 5
#define LOOPS_PER_SEC 5
+static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT;
+
static int dm_conf_verbosity;
#ifdef LIBDM_API_DEFERRED
@@ -229,7 +231,7 @@ dm_tgt_prereq (unsigned int *ver)
return 1;
}
-static int dm_prereq(unsigned int *v)
+int dm_prereq(unsigned int *v)
{
if (dm_lib_prereq())
return 1;
@@ -243,7 +245,7 @@ void libmp_udev_set_sync_support(int on)
libmp_dm_udev_sync = !!on;
}
-void libmp_dm_init(void)
+static void libmp_dm_init(void)
{
struct config *conf;
int verbosity;
@@ -262,11 +264,18 @@ void libmp_dm_init(void)
dm_udev_set_sync_support(libmp_dm_udev_sync);
}
+static void _do_skip_libmp_dm_init(void)
+{
+}
+
+void skip_libmp_dm_init(void)
+{
+ pthread_once(&dm_initialized, _do_skip_libmp_dm_init);
+}
+
struct dm_task*
libmp_dm_task_create(int task)
{
- static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT;
-
pthread_once(&dm_initialized, libmp_dm_init);
return dm_task_create(task);
}
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 7557a86b..17fc9faf 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -28,7 +28,8 @@
#define UUID_PREFIX_LEN (sizeof(UUID_PREFIX) - 1)
void dm_init(int verbosity);
-void libmp_dm_init(void);
+int dm_prereq(unsigned int *v);
+void skip_libmp_dm_init(void);
void libmp_udev_set_sync_support(int on);
struct dm_task *libmp_dm_task_create(int task);
int dm_drv_version (unsigned int * version);
--
2.17.2

View File

@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 19 May 2020 12:08:41 -0500
Subject: [PATCH] libmultipath: make sysfs_is_multipathed able to return wwid
sysfs_is_multipathed reads the wwid of the dm device holding a path to
check if its a multipath device. Add code to optinally set pp->wwid to
that wwid. This will be used by a future patch.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/sysfs.c | 24 +++++++++++++++++++-----
libmultipath/sysfs.h | 2 +-
multipath/main.c | 7 ++++---
3 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
index 62ec2ed7..12a82d95 100644
--- a/libmultipath/sysfs.c
+++ b/libmultipath/sysfs.c
@@ -295,7 +295,7 @@ static int select_dm_devs(const struct dirent *di)
return fnmatch("dm-*", di->d_name, FNM_FILE_NAME) == 0;
}
-bool sysfs_is_multipathed(const struct path *pp)
+bool sysfs_is_multipathed(struct path *pp, bool set_wwid)
{
char pathbuf[PATH_MAX];
struct scandir_result sr;
@@ -325,7 +325,7 @@ bool sysfs_is_multipathed(const struct path *pp)
for (i = 0; i < r && !found; i++) {
long fd;
int nr;
- char uuid[6];
+ char uuid[WWID_SIZE + UUID_PREFIX_LEN];
if (safe_snprintf(pathbuf + n, sizeof(pathbuf) - n,
"/%s/dm/uuid", di[i]->d_name))
@@ -339,12 +339,26 @@ bool sysfs_is_multipathed(const struct path *pp)
pthread_cleanup_push(close_fd, (void *)fd);
nr = read(fd, uuid, sizeof(uuid));
- if (nr == sizeof(uuid) && !memcmp(uuid, "mpath-", sizeof(uuid)))
+ if (nr > (int)UUID_PREFIX_LEN &&
+ !memcmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
found = true;
else if (nr < 0) {
- condlog(1, "%s: error reading from %s: %s",
- __func__, pathbuf, strerror(errno));
+ condlog(1, "%s: error reading from %s: %m",
+ __func__, pathbuf);
}
+ if (found && set_wwid) {
+ nr -= UUID_PREFIX_LEN;
+ memcpy(pp->wwid, uuid + UUID_PREFIX_LEN, nr);
+ if (nr == WWID_SIZE) {
+ condlog(4, "%s: overflow while reading from %s",
+ __func__, pathbuf);
+ pp->wwid[0] = '\0';
+ } else {
+ pp->wwid[nr] = '\0';
+ strchop(pp->wwid);
+ }
+ }
+
pthread_cleanup_pop(1);
}
pthread_cleanup_pop(1);
diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h
index 9ae30b39..72b39ab2 100644
--- a/libmultipath/sysfs.h
+++ b/libmultipath/sysfs.h
@@ -14,5 +14,5 @@ ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name,
unsigned 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);
-bool sysfs_is_multipathed(const struct path *pp);
+bool sysfs_is_multipathed(struct path *pp, bool set_wwid);
#endif
diff --git a/multipath/main.c b/multipath/main.c
index cf9d2a28..545ead87 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -638,7 +638,8 @@ configure (struct config *conf, enum mpath_cmds cmd,
* Shortcut for find_multipaths smart:
* Quick check if path is already multipathed.
*/
- if (sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0))) {
+ if (sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0),
+ false)) {
r = RTVL_YES;
goto print_valid;
}
@@ -747,8 +748,8 @@ configure (struct config *conf, enum mpath_cmds cmd,
/*
* Check if we raced with multipathd
*/
- r = sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0)) ?
- RTVL_YES : RTVL_NO;
+ r = sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0),
+ false) ? RTVL_YES : RTVL_NO;
}
goto print_valid;
}
--
2.17.2

View File

@ -0,0 +1,777 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 19 May 2020 12:08:42 -0500
Subject: [PATCH] multipath: centralize validation code
This code pulls the multipath path validation code out of configure(),
and puts it into its own function, check_path_valid(). This function
calls a new libmultipath function, is_path_valid() to check just path
requested. This seperation exists so that is_path_valid() can be reused
by future code. This code will give almost the same answer as the
existing code, with the exception that now, if a device is currently
multipathed, it will always be a valid multipath path.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/Makefile | 2 +-
libmultipath/devmapper.c | 45 ++++++
libmultipath/devmapper.h | 1 +
libmultipath/structs.h | 24 +---
libmultipath/valid.c | 118 ++++++++++++++++
libmultipath/valid.h | 42 ++++++
libmultipath/wwids.c | 10 +-
multipath/main.c | 296 +++++++++++++++++----------------------
8 files changed, 343 insertions(+), 195 deletions(-)
create mode 100644 libmultipath/valid.c
create mode 100644 libmultipath/valid.h
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index f19b7ad2..e5dac5ea 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -48,7 +48,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \
log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o \
- libsg.o
+ libsg.o valid.o
all: $(LIBS)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 7ed494a1..27d52398 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -770,6 +770,51 @@ out:
return r;
}
+/*
+ * Return
+ * 1 : map with uuid exists
+ * 0 : map with uuid doesn't exist
+ * -1 : error
+ */
+int
+dm_map_present_by_uuid(const char *uuid)
+{
+ struct dm_task *dmt;
+ struct dm_info info;
+ char prefixed_uuid[WWID_SIZE + UUID_PREFIX_LEN];
+ int r = -1;
+
+ if (!uuid || uuid[0] == '\0')
+ return 0;
+
+ if (safe_sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid))
+ goto out;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ goto out;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_set_uuid(dmt, prefixed_uuid))
+ goto out_task;
+
+ if (!dm_task_run(dmt))
+ goto out_task;
+
+ if (!dm_task_get_info(dmt, &info))
+ goto out_task;
+
+ r = !!info.exists;
+
+out_task:
+ dm_task_destroy(dmt);
+out:
+ if (r < 0)
+ condlog(3, "%s: dm command failed in %s: %s", uuid,
+ __FUNCTION__, strerror(errno));
+ return r;
+}
+
static int
dm_dev_t (const char * mapname, char * dev_t, int len)
{
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 17fc9faf..5ed7edc5 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -39,6 +39,7 @@ 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 flush);
int dm_map_present (const char *);
+int dm_map_present_by_uuid(const char *uuid);
int dm_get_map(const char *, unsigned long long *, char *);
int dm_get_status(const char *, char *);
int dm_type(const char *, char *);
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 9bd39eb1..d69bc2e9 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -101,29 +101,13 @@ enum yes_no_undef_states {
YNU_YES,
};
-#define _FIND_MULTIPATHS_F (1 << 1)
-#define _FIND_MULTIPATHS_I (1 << 2)
-#define _FIND_MULTIPATHS_N (1 << 3)
-/*
- * _FIND_MULTIPATHS_F must have the same value as YNU_YES.
- * Generate a compile time error if that isn't the case.
- */
-extern char ___error1___[-(_FIND_MULTIPATHS_F != YNU_YES)];
-
-#define find_multipaths_on(conf) \
- (!!((conf)->find_multipaths & _FIND_MULTIPATHS_F))
-#define ignore_wwids_on(conf) \
- (!!((conf)->find_multipaths & _FIND_MULTIPATHS_I))
-#define ignore_new_devs_on(conf) \
- (!!((conf)->find_multipaths & _FIND_MULTIPATHS_N))
-
enum find_multipaths_states {
FIND_MULTIPATHS_UNDEF = YNU_UNDEF,
FIND_MULTIPATHS_OFF = YNU_NO,
- FIND_MULTIPATHS_ON = _FIND_MULTIPATHS_F,
- FIND_MULTIPATHS_GREEDY = _FIND_MULTIPATHS_I,
- FIND_MULTIPATHS_SMART = _FIND_MULTIPATHS_F|_FIND_MULTIPATHS_I,
- FIND_MULTIPATHS_STRICT = _FIND_MULTIPATHS_F|_FIND_MULTIPATHS_N,
+ FIND_MULTIPATHS_ON = YNU_YES,
+ FIND_MULTIPATHS_GREEDY,
+ FIND_MULTIPATHS_SMART,
+ FIND_MULTIPATHS_STRICT,
__FIND_MULTIPATHS_LAST,
};
diff --git a/libmultipath/valid.c b/libmultipath/valid.c
new file mode 100644
index 00000000..456b1f6e
--- /dev/null
+++ b/libmultipath/valid.c
@@ -0,0 +1,118 @@
+/*
+ Copyright (c) 2020 Benjamin Marzinski, IBM
+
+ 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, see <https://www.gnu.org/licenses/>.
+ */
+#include <stddef.h>
+#include <errno.h>
+#include <libudev.h>
+
+#include "vector.h"
+#include "config.h"
+#include "debug.h"
+#include "util.h"
+#include "devmapper.h"
+#include "discovery.h"
+#include "wwids.h"
+#include "sysfs.h"
+#include "blacklist.h"
+#include "mpath_cmd.h"
+#include "valid.h"
+
+int
+is_path_valid(const char *name, struct config *conf, struct path *pp,
+ bool check_multipathd)
+{
+ int r;
+ int fd;
+
+ if (!pp || !name || !conf)
+ return PATH_IS_ERROR;
+
+ if (conf->find_multipaths <= FIND_MULTIPATHS_UNDEF ||
+ conf->find_multipaths >= __FIND_MULTIPATHS_LAST)
+ return PATH_IS_ERROR;
+
+ if (safe_sprintf(pp->dev, "%s", name))
+ return PATH_IS_ERROR;
+
+ if (sysfs_is_multipathed(pp, true)) {
+ if (pp->wwid[0] == '\0')
+ return PATH_IS_ERROR;
+ return PATH_IS_VALID_NO_CHECK;
+ }
+
+ /*
+ * "multipath -u" may be run before the daemon is started. In this
+ * case, systemd might own the socket but might delay multipathd
+ * startup until some other unit (udev settle!) has finished
+ * starting. With many LUNs, the listen backlog may be exceeded, which
+ * would cause connect() to block. This causes udev workers calling
+ * "multipath -u" to hang, and thus creates a deadlock, until "udev
+ * settle" times out. To avoid this, call connect() in non-blocking
+ * mode here, and take EAGAIN as indication for a filled-up systemd
+ * backlog.
+ */
+
+ if (check_multipathd) {
+ fd = __mpath_connect(1);
+ if (fd < 0) {
+ if (errno != EAGAIN && !systemd_service_enabled(name)) {
+ condlog(3, "multipathd not running or enabled");
+ return PATH_IS_NOT_VALID;
+ }
+ } else
+ mpath_disconnect(fd);
+ }
+
+ pp->udev = udev_device_new_from_subsystem_sysname(udev, "block", name);
+ if (!pp->udev)
+ return PATH_IS_ERROR;
+
+ r = pathinfo(pp, conf, DI_SYSFS | DI_WWID | DI_BLACKLIST);
+ if (r == PATHINFO_SKIPPED)
+ return PATH_IS_NOT_VALID;
+ else if (r)
+ return PATH_IS_ERROR;
+
+ if (pp->wwid[0] == '\0')
+ return PATH_IS_NOT_VALID;
+
+ if (pp->udev && pp->uid_attribute &&
+ filter_property(conf, pp->udev, 3, pp->uid_attribute) > 0)
+ return PATH_IS_NOT_VALID;
+
+ r = is_failed_wwid(pp->wwid);
+ if (r != WWID_IS_NOT_FAILED) {
+ if (r == WWID_IS_FAILED)
+ return PATH_IS_NOT_VALID;
+ return PATH_IS_ERROR;
+ }
+
+ if (conf->find_multipaths == FIND_MULTIPATHS_GREEDY)
+ return PATH_IS_VALID;
+
+ if (check_wwids_file(pp->wwid, 0) == 0)
+ return PATH_IS_VALID_NO_CHECK;
+
+ if (dm_map_present_by_uuid(pp->wwid) == 1)
+ return PATH_IS_VALID;
+
+ /* all these act like FIND_MULTIPATHS_STRICT for finding if a
+ * path is valid */
+ if (conf->find_multipaths != FIND_MULTIPATHS_SMART)
+ return PATH_IS_NOT_VALID;
+
+ return PATH_IS_MAYBE_VALID;
+}
diff --git a/libmultipath/valid.h b/libmultipath/valid.h
new file mode 100644
index 00000000..ce1c7cbf
--- /dev/null
+++ b/libmultipath/valid.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (c) 2020 Benjamin Marzinski, IBM
+
+ 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, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef _VALID_H
+#define _VALID_H
+
+/*
+ * PATH_IS_VALID_NO_CHECK is returned when multipath should claim
+ * the path, regardless of whether is has been released to systemd
+ * already.
+ * PATH_IS_VALID is returned by is_path_valid, when the path is
+ * valid only if it hasn't been released to systemd already.
+ * PATH_IS_MAYBE_VALID is returned when the the path would be valid
+ * if other paths with the same wwid existed. It is up to the caller
+ * to check for these other paths.
+ */
+enum is_path_valid_result {
+ PATH_IS_ERROR = -1,
+ PATH_IS_NOT_VALID,
+ PATH_IS_VALID,
+ PATH_IS_VALID_NO_CHECK,
+ PATH_IS_MAYBE_VALID,
+ PATH_MAX_VALID_RESULT, /* only for bounds checking */
+};
+
+int is_path_valid(const char *name, struct config *conf, struct path *pp,
+ bool check_multipathd);
+
+#endif /* _VALID_D */
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index 28a2150d..637cb0ab 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -289,19 +289,19 @@ out:
int
should_multipath(struct path *pp1, vector pathvec, vector mpvec)
{
- int i, ignore_new_devs, find_multipaths;
+ int i, find_multipaths;
struct path *pp2;
struct config *conf;
conf = get_multipath_config();
- ignore_new_devs = ignore_new_devs_on(conf);
- find_multipaths = find_multipaths_on(conf);
+ find_multipaths = conf->find_multipaths;
put_multipath_config(conf);
- if (!find_multipaths && !ignore_new_devs)
+ if (find_multipaths == FIND_MULTIPATHS_OFF ||
+ find_multipaths == FIND_MULTIPATHS_GREEDY)
return 1;
condlog(4, "checking if %s should be multipathed", pp1->dev);
- if (!ignore_new_devs) {
+ if (find_multipaths != FIND_MULTIPATHS_STRICT) {
char tmp_wwid[WWID_SIZE];
struct multipath *mp = find_mp_by_wwid(mpvec, pp1->wwid);
diff --git a/multipath/main.c b/multipath/main.c
index 545ead87..953fab27 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -63,21 +63,18 @@
#include "propsel.h"
#include "time-util.h"
#include "file.h"
+#include "valid.h"
int logsink;
struct udev *udev;
struct config *multipath_conf;
/*
- * Return values of configure(), print_cmd_valid(), and main().
- * RTVL_{YES,NO} are synonyms for RTVL_{OK,FAIL} for the CMD_VALID_PATH case.
+ * Return values of configure(), check_path_valid(), and main().
*/
enum {
RTVL_OK = 0,
- RTVL_YES = RTVL_OK,
RTVL_FAIL = 1,
- RTVL_NO = RTVL_FAIL,
- RTVL_MAYBE, /* only used internally, never returned */
RTVL_RETRY, /* returned by configure(), not by main() */
};
@@ -269,9 +266,6 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
continue;
}
- if (cmd == CMD_VALID_PATH)
- continue;
-
dm_get_map(mpp->alias, &mpp->size, params);
condlog(3, "params = %s", params);
dm_get_status(mpp->alias, status);
@@ -491,10 +485,11 @@ static int print_cmd_valid(int k, const vector pathvec,
struct timespec until;
struct path *pp;
- if (k != RTVL_YES && k != RTVL_NO && k != RTVL_MAYBE)
- return RTVL_NO;
+ if (k != PATH_IS_VALID && k != PATH_IS_NOT_VALID &&
+ k != PATH_IS_MAYBE_VALID)
+ return PATH_IS_NOT_VALID;
- if (k == RTVL_MAYBE) {
+ if (k == PATH_IS_MAYBE_VALID) {
/*
* Caller ensures that pathvec[0] is the path to
* examine.
@@ -504,7 +499,7 @@ static int print_cmd_valid(int k, const vector pathvec,
wait = find_multipaths_check_timeout(
pp, pp->find_multipaths_timeout, &until);
if (wait != FIND_MULTIPATHS_WAITING)
- k = RTVL_NO;
+ k = PATH_IS_NOT_VALID;
} else if (pathvec != NULL && (pp = VECTOR_SLOT(pathvec, 0)))
wait = find_multipaths_check_timeout(pp, 0, &until);
if (wait == FIND_MULTIPATHS_WAITING)
@@ -513,9 +508,9 @@ static int print_cmd_valid(int k, const vector pathvec,
else if (wait == FIND_MULTIPATHS_WAIT_DONE)
printf("FIND_MULTIPATHS_WAIT_UNTIL=\"0\"\n");
printf("DM_MULTIPATH_DEVICE_PATH=\"%d\"\n",
- k == RTVL_MAYBE ? 2 : k == RTVL_YES ? 1 : 0);
+ k == PATH_IS_MAYBE_VALID ? 2 : k == PATH_IS_VALID ? 1 : 0);
/* Never return RTVL_MAYBE */
- return k == RTVL_NO ? RTVL_NO : RTVL_YES;
+ return k == PATH_IS_NOT_VALID ? PATH_IS_NOT_VALID : PATH_IS_VALID;
}
/*
@@ -548,7 +543,6 @@ configure (struct config *conf, enum mpath_cmds cmd,
int di_flag = 0;
char * refwwid = NULL;
char * dev = NULL;
- bool released = released_to_systemd();
/*
* allocate core vectors to store paths and multipaths
@@ -573,7 +567,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
cmd != CMD_REMOVE_WWID &&
(filter_devnode(conf->blist_devnode,
conf->elist_devnode, dev) > 0)) {
- goto print_valid;
+ goto out;
}
/*
@@ -581,14 +575,10 @@ configure (struct config *conf, enum mpath_cmds cmd,
* failing the translation is fatal (by policy)
*/
if (devpath) {
- int failed = get_refwwid(cmd, devpath, dev_type,
- pathvec, &refwwid);
+ get_refwwid(cmd, devpath, dev_type, pathvec, &refwwid);
if (!refwwid) {
condlog(4, "%s: failed to get wwid", devpath);
- if (failed == 2 && cmd == CMD_VALID_PATH)
- goto print_valid;
- else
- condlog(3, "scope is null");
+ condlog(3, "scope is null");
goto out;
}
if (cmd == CMD_REMOVE_WWID) {
@@ -614,53 +604,6 @@ configure (struct config *conf, enum mpath_cmds cmd,
goto out;
}
condlog(3, "scope limited to %s", refwwid);
- /* 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.
- * Paths listed in the wwids file are always considered valid.
- */
- if (cmd == CMD_VALID_PATH) {
- if (is_failed_wwid(refwwid) == WWID_IS_FAILED) {
- r = RTVL_NO;
- goto print_valid;
- }
- if ((!find_multipaths_on(conf) &&
- ignore_wwids_on(conf)) ||
- check_wwids_file(refwwid, 0) == 0)
- r = RTVL_YES;
- if (!ignore_wwids_on(conf))
- goto print_valid;
- /* At this point, either r==0 or find_multipaths_on. */
-
- /*
- * Shortcut for find_multipaths smart:
- * Quick check if path is already multipathed.
- */
- if (sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0),
- false)) {
- r = RTVL_YES;
- goto print_valid;
- }
-
- /*
- * DM_MULTIPATH_DEVICE_PATH=="0" means that we have
- * been called for this device already, and have
- * released it to systemd. Unless the device is now
- * already multipathed (see above), we can't try to
- * grab it, because setting SYSTEMD_READY=0 would
- * cause file systems to be unmounted.
- * Leave DM_MULTIPATH_DEVICE_PATH="0".
- */
- if (released) {
- r = RTVL_NO;
- goto print_valid;
- }
- if (r == RTVL_YES)
- goto print_valid;
- /* find_multipaths_on: Fall through to path detection */
- }
}
/*
@@ -701,59 +644,6 @@ configure (struct config *conf, enum mpath_cmds cmd,
goto out;
}
- if (cmd == CMD_VALID_PATH) {
- struct path *pp;
- int fd;
-
- /* This only happens if find_multipaths and
- * ignore_wwids is set, and the path is not in WWIDs
- * file, not currently multipathed, and has
- * never been released to systemd.
- * 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) {
- r = RTVL_YES;
- goto print_valid;
- } else if (VECTOR_SIZE(pathvec) > 1)
- r = RTVL_YES;
- else
- r = RTVL_MAYBE;
-
- /*
- * If opening the path with O_EXCL fails, the path
- * is in use (e.g. mounted during initramfs processing).
- * We know that it's not used by dm-multipath.
- * We may not set SYSTEMD_READY=0 on such devices, it
- * might cause systemd to umount the device.
- * Use O_RDONLY, because udevd would trigger another
- * uevent for close-after-write.
- *
- * The O_EXCL check is potentially dangerous, because it may
- * race with other tasks trying to access the device. Therefore
- * this code is only executed if the path hasn't been released
- * to systemd earlier (see above).
- *
- * get_refwwid() above stores the path we examine in slot 0.
- */
- pp = VECTOR_SLOT(pathvec, 0);
- fd = open(udev_device_get_devnode(pp->udev),
- O_RDONLY|O_EXCL);
- if (fd >= 0)
- close(fd);
- else {
- condlog(3, "%s: path %s is in use: %s",
- __func__, pp->dev,
- strerror(errno));
- /*
- * Check if we raced with multipathd
- */
- r = sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0),
- false) ? RTVL_YES : RTVL_NO;
- }
- goto print_valid;
- }
-
if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
r = RTVL_OK;
goto out;
@@ -766,10 +656,6 @@ configure (struct config *conf, enum mpath_cmds cmd,
conf->force_reload, cmd);
r = rc == CP_RETRY ? RTVL_RETRY : rc == CP_OK ? RTVL_OK : RTVL_FAIL;
-print_valid:
- if (cmd == CMD_VALID_PATH)
- r = print_cmd_valid(r, pathvec, conf);
-
out:
if (refwwid)
FREE(refwwid);
@@ -780,6 +666,112 @@ out:
return r;
}
+static int
+check_path_valid(const char *name, struct config *conf, bool is_uevent)
+{
+ int fd, r = PATH_IS_ERROR;
+ struct path *pp = NULL;
+ vector pathvec = NULL;
+
+ pp = alloc_path();
+ if (!pp)
+ return RTVL_FAIL;
+
+ r = is_path_valid(name, conf, pp, is_uevent);
+ if (r <= PATH_IS_ERROR || r >= PATH_MAX_VALID_RESULT)
+ goto fail;
+
+ /* set path values if is_path_valid() didn't */
+ if (!pp->udev)
+ pp->udev = udev_device_new_from_subsystem_sysname(udev, "block",
+ name);
+ if (!pp->udev)
+ goto fail;
+
+ if (!strlen(pp->dev_t)) {
+ dev_t devt = udev_device_get_devnum(pp->udev);
+ if (major(devt) == 0 && minor(devt) == 0)
+ goto fail;
+ snprintf(pp->dev_t, BLK_DEV_SIZE, "%d:%d", major(devt),
+ minor(devt));
+ }
+
+ pathvec = vector_alloc();
+ if (!pathvec)
+ goto fail;
+
+ if (store_path(pathvec, pp) != 0) {
+ free_path(pp);
+ goto fail;
+ }
+
+ if ((r == PATH_IS_VALID || r == PATH_IS_MAYBE_VALID) &&
+ released_to_systemd())
+ r = PATH_IS_NOT_VALID;
+
+ /* This state is only used to skip the released_to_systemd() check */
+ if (r == PATH_IS_VALID_NO_CHECK)
+ r = PATH_IS_VALID;
+
+ if (r != PATH_IS_MAYBE_VALID)
+ goto out;
+
+ /*
+ * If opening the path with O_EXCL fails, the path
+ * is in use (e.g. mounted during initramfs processing).
+ * We know that it's not used by dm-multipath.
+ * We may not set SYSTEMD_READY=0 on such devices, it
+ * might cause systemd to umount the device.
+ * Use O_RDONLY, because udevd would trigger another
+ * uevent for close-after-write.
+ *
+ * The O_EXCL check is potentially dangerous, because it may
+ * race with other tasks trying to access the device. Therefore
+ * this code is only executed if the path hasn't been released
+ * to systemd earlier (see above).
+ */
+ fd = open(udev_device_get_devnode(pp->udev), O_RDONLY|O_EXCL);
+ if (fd >= 0)
+ close(fd);
+ else {
+ condlog(3, "%s: path %s is in use: %m", __func__, pp->dev);
+ /* Check if we raced with multipathd */
+ if (sysfs_is_multipathed(pp, false))
+ r = PATH_IS_VALID;
+ else
+ r = PATH_IS_NOT_VALID;
+ goto out;
+ }
+
+ /* For find_multipaths = SMART, if there is more than one path
+ * matching the refwwid, then the path is valid */
+ if (path_discovery(pathvec, DI_SYSFS | DI_WWID) < 0)
+ goto fail;
+ filter_pathvec(pathvec, pp->wwid);
+ if (VECTOR_SIZE(pathvec) > 1)
+ r = PATH_IS_VALID;
+ else
+ r = PATH_IS_MAYBE_VALID;
+
+out:
+ r = print_cmd_valid(r, pathvec, conf);
+ free_pathvec(pathvec, FREE_PATHS);
+ /*
+ * multipath -u must exit with status 0, otherwise udev won't
+ * import its output.
+ */
+ if (!is_uevent && r == PATH_IS_NOT_VALID)
+ return RTVL_FAIL;
+ return RTVL_OK;
+
+fail:
+ if (pathvec)
+ free_pathvec(pathvec, FREE_PATHS);
+ else
+ free_path(pp);
+ return RTVL_FAIL;
+}
+
static int
get_dev_type(char *dev) {
struct stat buf;
@@ -861,32 +853,6 @@ out:
return r;
}
-static int test_multipathd_socket(void)
-{
- int fd;
- /*
- * "multipath -u" may be run before the daemon is started. In this
- * case, systemd might own the socket but might delay multipathd
- * startup until some other unit (udev settle!) has finished
- * starting. With many LUNs, the listen backlog may be exceeded, which
- * would cause connect() to block. This causes udev workers calling
- * "multipath -u" to hang, and thus creates a deadlock, until "udev
- * settle" times out. To avoid this, call connect() in non-blocking
- * mode here, and take EAGAIN as indication for a filled-up systemd
- * backlog.
- */
-
- fd = __mpath_connect(1);
- if (fd == -1) {
- if (errno == EAGAIN)
- condlog(3, "daemon backlog exceeded");
- else
- return 0;
- } else
- close(fd);
- return 1;
-}
-
int
main (int argc, char *argv[])
{
@@ -970,7 +936,11 @@ main (int argc, char *argv[])
conf->force_reload = FORCE_RELOAD_YES;
break;
case 'i':
- conf->find_multipaths |= _FIND_MULTIPATHS_I;
+ if (conf->find_multipaths == FIND_MULTIPATHS_ON ||
+ conf->find_multipaths == FIND_MULTIPATHS_STRICT)
+ conf->find_multipaths = FIND_MULTIPATHS_SMART;
+ else if (conf->find_multipaths == FIND_MULTIPATHS_OFF)
+ conf->find_multipaths = FIND_MULTIPATHS_GREEDY;
break;
case 't':
r = dump_config(conf, NULL, NULL) ? RTVL_FAIL : RTVL_OK;
@@ -1064,15 +1034,10 @@ main (int argc, char *argv[])
condlog(0, "the -c option requires a path to check");
goto out;
}
- if (cmd == CMD_VALID_PATH &&
- dev_type == DEV_UEVENT) {
- if (!test_multipathd_socket()) {
- condlog(3, "%s: daemon is not running", dev);
- if (!systemd_service_enabled(dev)) {
- r = print_cmd_valid(RTVL_NO, NULL, conf);
- goto out;
- }
- }
+ if (cmd == CMD_VALID_PATH) {
+ char * name = convert_dev(dev, (dev_type == DEV_DEVNODE));
+ r = check_path_valid(name, conf, dev_type == DEV_UEVENT);
+ goto out;
}
if (cmd == CMD_REMOVE_WWID && !dev) {
@@ -1136,13 +1101,6 @@ out:
cleanup_prio();
cleanup_checkers();
- /*
- * multipath -u must exit with status 0, otherwise udev won't
- * import its output.
- */
- if (cmd == CMD_VALID_PATH && dev_type == DEV_UEVENT && r == RTVL_NO)
- r = RTVL_OK;
-
if (dev_type == DEV_UEVENT)
closelog();
--
2.17.2

View File

@ -0,0 +1,530 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 19 May 2020 12:08:43 -0500
Subject: [PATCH] Unit tests for is_path_valid()
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
tests/Makefile | 4 +-
tests/valid.c | 486 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 489 insertions(+), 1 deletion(-)
create mode 100644 tests/valid.c
diff --git a/tests/Makefile b/tests/Makefile
index 1b8706a7..125553b8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \
LIBDEPS += -L$(multipathdir) -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka
TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
- alias directio
+ alias directio valid
.SILENT: $(TESTS:%=%.o)
.PRECIOUS: $(TESTS:%=%-test)
@@ -50,6 +50,8 @@ vpd-test_OBJDEPS := ../libmultipath/discovery.o
vpd-test_LIBDEPS := -ludev -lpthread -ldl
alias-test_TESTDEPS := test-log.o
alias-test_LIBDEPS := -lpthread -ldl
+valid-test_OBJDEPS := ../libmultipath/valid.o
+valid-test_LIBDEPS := -ludev -lpthread -ldl
ifneq ($(DIO_TEST_DEV),)
directio-test_LIBDEPS := -laio
endif
diff --git a/tests/valid.c b/tests/valid.c
new file mode 100644
index 00000000..693c72c5
--- /dev/null
+++ b/tests/valid.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2020 Benjamin Marzinski, Redhat
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cmocka.h>
+#include "globals.c"
+#include "util.h"
+#include "discovery.h"
+#include "wwids.h"
+#include "blacklist.h"
+#include "valid.h"
+
+int test_fd;
+struct udev_device {
+ int unused;
+} test_udev;
+
+bool __wrap_sysfs_is_multipathed(struct path *pp, bool set_wwid)
+{
+ bool is_multipathed = mock_type(bool);
+ assert_non_null(pp);
+ assert_int_not_equal(strlen(pp->dev), 0);
+ if (is_multipathed && set_wwid)
+ strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE);
+ return is_multipathed;
+}
+
+int __wrap___mpath_connect(int nonblocking)
+{
+ bool connected = mock_type(bool);
+ assert_int_equal(nonblocking, 1);
+ if (connected)
+ return test_fd;
+ errno = mock_type(int);
+ return -1;
+}
+
+int __wrap_systemd_service_enabled(const char *dev)
+{
+ return (int)mock_type(bool);
+}
+
+/* There's no point in checking the return value here */
+int __wrap_mpath_disconnect(int fd)
+{
+ assert_int_equal(fd, test_fd);
+ return 0;
+}
+
+struct udev_device *__wrap_udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
+{
+ bool passed = mock_type(bool);
+ assert_string_equal(sysname, mock_ptr_type(char *));
+ if (passed)
+ return &test_udev;
+ return NULL;
+}
+
+int __wrap_pathinfo(struct path *pp, struct config *conf, int mask)
+{
+ int ret = mock_type(int);
+ assert_string_equal(pp->dev, mock_ptr_type(char *));
+ assert_int_equal(mask, DI_SYSFS | DI_WWID | DI_BLACKLIST);
+ if (ret == PATHINFO_OK) {
+ pp->uid_attribute = "ID_TEST";
+ strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE);
+ } else
+ memset(pp->wwid, 0, WWID_SIZE);
+ return ret;
+}
+
+int __wrap_filter_property(struct config *conf, struct udev_device *udev,
+ int lvl, const char *uid_attribute)
+{
+ int ret = mock_type(int);
+ assert_string_equal(uid_attribute, "ID_TEST");
+ return ret;
+}
+
+int __wrap_is_failed_wwid(const char *wwid)
+{
+ int ret = mock_type(int);
+ assert_string_equal(wwid, mock_ptr_type(char *));
+ return ret;
+}
+
+int __wrap_check_wwids_file(char *wwid, int write_wwid)
+{
+ bool passed = mock_type(bool);
+ assert_int_equal(write_wwid, 0);
+ assert_string_equal(wwid, mock_ptr_type(char *));
+ if (passed)
+ return 0;
+ else
+ return -1;
+}
+
+int __wrap_dm_map_present_by_uuid(const char *uuid)
+{
+ int ret = mock_type(int);
+ assert_string_equal(uuid, mock_ptr_type(char *));
+ return ret;
+}
+
+enum {
+ STAGE_IS_MULTIPATHED,
+ STAGE_CHECK_MULTIPATHD,
+ STAGE_GET_UDEV_DEVICE,
+ STAGE_PATHINFO,
+ STAGE_FILTER_PROPERTY,
+ STAGE_IS_FAILED,
+ STAGE_CHECK_WWIDS,
+ STAGE_UUID_PRESENT,
+};
+
+enum {
+ CHECK_MPATHD_RUNNING,
+ CHECK_MPATHD_EAGAIN,
+ CHECK_MPATHD_ENABLED,
+ CHECK_MPATHD_SKIP,
+};
+
+/* setup the test to continue past the given stage in is_path_valid() */
+static void setup_passing(char *name, char *wwid, unsigned int check_multipathd,
+ unsigned int stage)
+{
+ will_return(__wrap_sysfs_is_multipathed, false);
+ if (stage == STAGE_IS_MULTIPATHED)
+ return;
+ if (check_multipathd == CHECK_MPATHD_RUNNING)
+ will_return(__wrap___mpath_connect, true);
+ else if (check_multipathd == CHECK_MPATHD_EAGAIN) {
+ will_return(__wrap___mpath_connect, false);
+ will_return(__wrap___mpath_connect, EAGAIN);
+ } else if (check_multipathd == CHECK_MPATHD_ENABLED) {
+ will_return(__wrap___mpath_connect, false);
+ will_return(__wrap___mpath_connect, ECONNREFUSED);
+ will_return(__wrap_systemd_service_enabled, true);
+ }
+ /* nothing for CHECK_MPATHD_SKIP */
+ if (stage == STAGE_CHECK_MULTIPATHD)
+ return;
+ will_return(__wrap_udev_device_new_from_subsystem_sysname, true);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname,
+ name);
+ if (stage == STAGE_GET_UDEV_DEVICE)
+ return;
+ will_return(__wrap_pathinfo, PATHINFO_OK);
+ will_return(__wrap_pathinfo, name);
+ will_return(__wrap_pathinfo, wwid);
+ if (stage == STAGE_PATHINFO)
+ return;
+ will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST_EXCEPT);
+ if (stage == STAGE_FILTER_PROPERTY)
+ return;
+ will_return(__wrap_is_failed_wwid, WWID_IS_NOT_FAILED);
+ will_return(__wrap_is_failed_wwid, wwid);
+ if (stage == STAGE_IS_FAILED)
+ return;
+ will_return(__wrap_check_wwids_file, false);
+ will_return(__wrap_check_wwids_file, wwid);
+ if (stage == STAGE_CHECK_WWIDS)
+ return;
+ will_return(__wrap_dm_map_present_by_uuid, 0);
+ will_return(__wrap_dm_map_present_by_uuid, wwid);
+}
+
+static void test_bad_arguments(void **state)
+{
+ struct path pp;
+ char too_long[FILE_NAME_SIZE + 1];
+
+ memset(&pp, 0, sizeof(pp));
+ /* test NULL pointers */
+ assert_int_equal(is_path_valid("test", &conf, NULL, true),
+ PATH_IS_ERROR);
+ assert_int_equal(is_path_valid("test", NULL, &pp, true),
+ PATH_IS_ERROR);
+ assert_int_equal(is_path_valid(NULL, &conf, &pp, true),
+ PATH_IS_ERROR);
+ /* test undefined find_multipaths */
+ conf.find_multipaths = FIND_MULTIPATHS_UNDEF;
+ assert_int_equal(is_path_valid("test", &conf, &pp, true),
+ PATH_IS_ERROR);
+ /* test name too long */
+ memset(too_long, 'x', sizeof(too_long));
+ too_long[sizeof(too_long) - 1] = '\0';
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ assert_int_equal(is_path_valid(too_long, &conf, &pp, true),
+ PATH_IS_ERROR);
+}
+
+static void test_sysfs_is_multipathed(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test_wwid";
+
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ /* test for already existing multiapthed device */
+ will_return(__wrap_sysfs_is_multipathed, true);
+ will_return(__wrap_sysfs_is_multipathed, wwid);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_VALID_NO_CHECK);
+ assert_string_equal(pp.dev, name);
+ assert_string_equal(pp.wwid, wwid);
+ /* test for wwid device with empty wwid */
+ will_return(__wrap_sysfs_is_multipathed, true);
+ will_return(__wrap_sysfs_is_multipathed, "");
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_ERROR);
+}
+
+static void test_check_multipathd(void **state)
+{
+ struct path pp;
+ char *name = "test";
+
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ /* test failed check to see if multipathd is active */
+ will_return(__wrap_sysfs_is_multipathed, false);
+ will_return(__wrap___mpath_connect, false);
+ will_return(__wrap___mpath_connect, ECONNREFUSED);
+ will_return(__wrap_systemd_service_enabled, false);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_NOT_VALID);
+ assert_string_equal(pp.dev, name);
+ /* test pass because service is enabled. fail getting udev */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, NULL, CHECK_MPATHD_ENABLED, STAGE_CHECK_MULTIPATHD);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname, false);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname,
+ name);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_ERROR);
+ assert_string_equal(pp.dev, name);
+ /* test pass because connect returned EAGAIN. fail getting udev */
+ setup_passing(name, NULL, CHECK_MPATHD_EAGAIN, STAGE_CHECK_MULTIPATHD);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname, false);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname,
+ name);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_ERROR);
+ /* test pass because connect succeeded. fail getting udev */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, NULL, CHECK_MPATHD_RUNNING, STAGE_CHECK_MULTIPATHD);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname, false);
+ will_return(__wrap_udev_device_new_from_subsystem_sysname,
+ name);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_ERROR);
+ assert_string_equal(pp.dev, name);
+}
+
+static void test_pathinfo(void **state)
+{
+ struct path pp;
+ char *name = "test";
+
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ /* Test pathinfo blacklisting device */
+ setup_passing(name, NULL, CHECK_MPATHD_SKIP, STAGE_GET_UDEV_DEVICE);
+ will_return(__wrap_pathinfo, PATHINFO_SKIPPED);
+ will_return(__wrap_pathinfo, name);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ /* Test pathinfo failing */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, NULL, CHECK_MPATHD_SKIP, STAGE_GET_UDEV_DEVICE);
+ will_return(__wrap_pathinfo, PATHINFO_FAILED);
+ will_return(__wrap_pathinfo, name);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_ERROR);
+ /* Test blank wwid */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, NULL, CHECK_MPATHD_SKIP, STAGE_GET_UDEV_DEVICE);
+ will_return(__wrap_pathinfo, PATHINFO_OK);
+ will_return(__wrap_pathinfo, name);
+ will_return(__wrap_pathinfo, "");
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+}
+
+static void test_filter_property(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test-wwid";
+
+ /* test blacklist property */
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO);
+ will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+ /* test missing property */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO);
+ will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST_MISSING);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ /* test MATCH_NOTHING fail on is_failed_wwid */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO);
+ will_return(__wrap_filter_property, MATCH_NOTHING);
+ will_return(__wrap_is_failed_wwid, WWID_IS_FAILED);
+ will_return(__wrap_is_failed_wwid, wwid);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+}
+
+static void test_is_failed_wwid(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test-wwid";
+
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ /* Test wwid failed */
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_FILTER_PROPERTY);
+ will_return(__wrap_is_failed_wwid, WWID_IS_FAILED);
+ will_return(__wrap_is_failed_wwid, wwid);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+ /* test is_failed_wwid error */
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_FILTER_PROPERTY);
+ will_return(__wrap_is_failed_wwid, WWID_FAILED_ERROR);
+ will_return(__wrap_is_failed_wwid, wwid);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_ERROR);
+}
+
+static void test_greedy(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test-wwid";
+
+ /* test greedy success with checking multipathd */
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_GREEDY;
+ setup_passing(name, wwid, CHECK_MPATHD_RUNNING, STAGE_IS_FAILED);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_VALID);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+ /* test greedy success without checking multiapthd */
+ memset(&pp, 0, sizeof(pp));
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_IS_FAILED);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_VALID);
+}
+
+static void test_check_wwids(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test-wwid";
+
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ setup_passing(name, wwid, CHECK_MPATHD_EAGAIN, STAGE_IS_FAILED);
+ will_return(__wrap_check_wwids_file, true);
+ will_return(__wrap_check_wwids_file, wwid);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_VALID_NO_CHECK);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+}
+
+static void test_check_uuid_present(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test-wwid";
+
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ setup_passing(name, wwid, CHECK_MPATHD_ENABLED, STAGE_CHECK_WWIDS);
+ will_return(__wrap_dm_map_present_by_uuid, 1);
+ will_return(__wrap_dm_map_present_by_uuid, wwid);
+ assert_int_equal(is_path_valid(name, &conf, &pp, true),
+ PATH_IS_VALID);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+}
+
+
+static void test_find_multipaths(void **state)
+{
+ struct path pp;
+ char *name = "test";
+ char *wwid = "test-wwid";
+
+ /* test find_multipaths = FIND_MULTIPATHS_STRICT */
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+ /* test find_multipaths = FIND_MULTIPATHS_OFF */
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_OFF;
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ /* test find_multipaths = FIND_MULTIPATHS_ON */
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_ON;
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_NOT_VALID);
+ /* test find_multipaths = FIND_MULTIPATHS_SMART */
+ memset(&pp, 0, sizeof(pp));
+ conf.find_multipaths = FIND_MULTIPATHS_SMART;
+ setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+ assert_int_equal(is_path_valid(name, &conf, &pp, false),
+ PATH_IS_MAYBE_VALID);
+ assert_string_equal(pp.dev, name);
+ assert_ptr_equal(pp.udev, &test_udev);
+ assert_string_equal(pp.wwid, wwid);
+}
+
+int test_valid(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_bad_arguments),
+ cmocka_unit_test(test_sysfs_is_multipathed),
+ cmocka_unit_test(test_check_multipathd),
+ cmocka_unit_test(test_pathinfo),
+ cmocka_unit_test(test_filter_property),
+ cmocka_unit_test(test_is_failed_wwid),
+ cmocka_unit_test(test_greedy),
+ cmocka_unit_test(test_check_wwids),
+ cmocka_unit_test(test_check_uuid_present),
+ cmocka_unit_test(test_find_multipaths),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+int main(void)
+{
+ int ret = 0;
+ ret += test_valid();
+ return ret;
+}
--
2.17.2

View File

@ -0,0 +1,205 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 19 May 2020 12:08:44 -0500
Subject: [PATCH] libmultipath: simplify failed wwid code
The (is|mark|unmark)_failed_wwid code is needlessly complicated.
Locking a file is necssary if multiple processes could otherwise be
writing to it at the same time. That is not the case with the
failed_wwids files. They can simply be empty files in a directory. Even
with all the locking in place, two processes accessing or modifying a
file at the same time will still race. And even without the locking, if
two processes try to access or modify a file at the same time, they will
both see a reasonable result, and will leave the files in a valid state
afterwards.
Instead of doing all the locking work (which made it necessary to write
a file, even just to check if a file existed), simply check for files
with lstat(), create them with open(), and remove them with unlink().
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/wwids.c | 131 ++++++++++++++++++-------------------------
1 file changed, 56 insertions(+), 75 deletions(-)
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index 637cb0ab..aab5da8a 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include "util.h"
#include "checkers.h"
@@ -348,109 +349,89 @@ remember_wwid(char *wwid)
}
static const char shm_dir[] = MULTIPATH_SHM_BASE "failed_wwids";
-static const char shm_lock[] = ".lock";
-static const char shm_header[] = "multipath shm lock file, don't edit";
-static char _shm_lock_path[sizeof(shm_dir)+sizeof(shm_lock)];
-static const char *shm_lock_path = &_shm_lock_path[0];
-static void init_shm_paths(void)
+static void print_failed_wwid_result(const char * msg, const char *wwid, int r)
{
- snprintf(_shm_lock_path, sizeof(_shm_lock_path),
- "%s/%s", shm_dir, shm_lock);
+ switch(r) {
+ case WWID_FAILED_ERROR:
+ condlog(1, "%s: %s: %m", msg, wwid);
+ return;
+ case WWID_IS_FAILED:
+ case WWID_IS_NOT_FAILED:
+ condlog(4, "%s: %s is %s", msg, wwid,
+ r == WWID_IS_FAILED ? "failed" : "good");
+ return;
+ case WWID_FAILED_CHANGED:
+ condlog(3, "%s: %s", msg, wwid);
+ }
}
-static pthread_once_t shm_path_once = PTHREAD_ONCE_INIT;
-
-static int multipath_shm_open(bool rw)
+int is_failed_wwid(const char *wwid)
{
- int fd;
- int can_write;
-
- pthread_once(&shm_path_once, init_shm_paths);
- fd = open_file(shm_lock_path, &can_write, shm_header);
+ struct stat st;
+ char path[PATH_MAX];
+ int r;
- if (fd >= 0 && rw && !can_write) {
- close(fd);
- condlog(1, "failed to open %s for writing", shm_dir);
+ if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) {
+ condlog(1, "%s: path name overflow", __func__);
return -1;
}
- return fd;
-}
-
-static void multipath_shm_close(void *arg)
-{
- long fd = (long)arg;
+ if (lstat(path, &st) == 0)
+ r = WWID_IS_FAILED;
+ else if (errno == ENOENT)
+ r = WWID_IS_NOT_FAILED;
+ else
+ r = WWID_FAILED_ERROR;
- close(fd);
- unlink(shm_lock_path);
+ print_failed_wwid_result("is_failed", wwid, r);
+ return r;
}
-static int _failed_wwid_op(const char *wwid, bool rw,
- int (*func)(const char *), const char *msg)
+int mark_failed_wwid(const char *wwid)
{
char path[PATH_MAX];
- long lockfd;
- int r = -1;
+ int r, fd;
if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) {
condlog(1, "%s: path name overflow", __func__);
return -1;
}
-
- lockfd = multipath_shm_open(rw);
- if (lockfd == -1)
+ if (ensure_directories_exist(path, 0700) < 0) {
+ condlog(1, "%s: can't setup directories", __func__);
return -1;
+ }
- pthread_cleanup_push(multipath_shm_close, (void *)lockfd);
- r = func(path);
- pthread_cleanup_pop(1);
-
- if (r == WWID_FAILED_ERROR)
- condlog(1, "%s: %s: %s", msg, wwid, strerror(errno));
- else if (r == WWID_FAILED_CHANGED)
- condlog(3, "%s: %s", msg, wwid);
- else if (!rw)
- condlog(4, "%s: %s is %s", msg, wwid,
- r == WWID_IS_FAILED ? "failed" : "good");
+ fd = open(path, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR);
+ if (fd >= 0) {
+ close(fd);
+ r = WWID_FAILED_CHANGED;
+ } else if (errno == EEXIST)
+ r = WWID_FAILED_UNCHANGED;
+ else
+ r = WWID_FAILED_ERROR;
+ print_failed_wwid_result("mark_failed", wwid, r);
return r;
}
-static int _is_failed(const char *path)
+int unmark_failed_wwid(const char *wwid)
{
- struct stat st;
+ char path[PATH_MAX];
+ int r;
- if (lstat(path, &st) == 0)
- return WWID_IS_FAILED;
+ if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) {
+ condlog(1, "%s: path name overflow", __func__);
+ return -1;
+ }
+
+ if (unlink(path) == 0)
+ r = WWID_FAILED_CHANGED;
else if (errno == ENOENT)
- return WWID_IS_NOT_FAILED;
+ r = WWID_FAILED_UNCHANGED;
else
- return WWID_FAILED_ERROR;
-}
-
-static int _mark_failed(const char *path)
-{
- /* Called from _failed_wwid_op: we know that shm_lock_path exists */
- if (_is_failed(path) == WWID_IS_FAILED)
- return WWID_FAILED_UNCHANGED;
- return (link(shm_lock_path, path) == 0 ? WWID_FAILED_CHANGED :
- WWID_FAILED_ERROR);
-}
+ r = WWID_FAILED_ERROR;
-static int _unmark_failed(const char *path)
-{
- if (_is_failed(path) == WWID_IS_NOT_FAILED)
- return WWID_FAILED_UNCHANGED;
- return (unlink(path) == 0 ? WWID_FAILED_CHANGED : WWID_FAILED_ERROR);
-}
-
-#define declare_failed_wwid_op(op, rw) \
-int op ## _wwid(const char *wwid) \
-{ \
- return _failed_wwid_op(wwid, (rw), _ ## op, #op); \
+ print_failed_wwid_result("unmark_failed", wwid, r);
+ return r;
}
-
-declare_failed_wwid_op(is_failed, false)
-declare_failed_wwid_op(mark_failed, true)
-declare_failed_wwid_op(unmark_failed, true)
--
2.17.2

View File

@ -0,0 +1,96 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 19 May 2020 12:08:45 -0500
Subject: [PATCH] libmultipath: use atomic linkat() in mark_failed_wwid()
This keeps (almost) the simplicity of the previous patch, while
making sure that the return value of mark_failed_wwid()
(WWID_FAILED_CHANGED vs. WWID_FAILED_UNCHANGED) is correct, even
if several processes access this WWID at the same time.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/wwids.c | 42 +++++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index aab5da8a..61d9c39e 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -374,7 +374,7 @@ int is_failed_wwid(const char *wwid)
if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) {
condlog(1, "%s: path name overflow", __func__);
- return -1;
+ return WWID_FAILED_ERROR;
}
if (lstat(path, &st) == 0)
@@ -390,27 +390,43 @@ int is_failed_wwid(const char *wwid)
int mark_failed_wwid(const char *wwid)
{
- char path[PATH_MAX];
- int r, fd;
+ char tmpfile[WWID_SIZE + 2 * sizeof(long) + 1];
+ int r = WWID_FAILED_ERROR, fd, dfd;
- if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) {
- condlog(1, "%s: path name overflow", __func__);
- return -1;
+ dfd = open(shm_dir, O_RDONLY|O_DIRECTORY);
+ if (dfd == -1 && errno == ENOENT) {
+ char path[sizeof(shm_dir) + 2];
+
+ /* arg for ensure_directories_exist() must not end with "/" */
+ safe_sprintf(path, "%s/_", shm_dir);
+ ensure_directories_exist(path, 0700);
+ dfd = open(shm_dir, O_RDONLY|O_DIRECTORY);
}
- if (ensure_directories_exist(path, 0700) < 0) {
- condlog(1, "%s: can't setup directories", __func__);
- return -1;
+ if (dfd == -1) {
+ condlog(1, "%s: can't setup %s: %m", __func__, shm_dir);
+ return WWID_FAILED_ERROR;
}
- fd = open(path, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR);
- if (fd >= 0) {
+ safe_sprintf(tmpfile, "%s.%lx", wwid, (long)getpid());
+ fd = openat(dfd, tmpfile, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR);
+ if (fd >= 0)
close(fd);
+ else
+ goto out_closedir;
+
+ if (linkat(dfd, tmpfile, dfd, wwid, 0) == 0)
r = WWID_FAILED_CHANGED;
- } else if (errno == EEXIST)
+ else if (errno == EEXIST)
r = WWID_FAILED_UNCHANGED;
else
r = WWID_FAILED_ERROR;
+ if (unlinkat(dfd, tmpfile, 0) == -1)
+ condlog(2, "%s: failed to unlink %s/%s: %m",
+ __func__, shm_dir, tmpfile);
+
+out_closedir:
+ close(dfd);
print_failed_wwid_result("mark_failed", wwid, r);
return r;
}
@@ -422,7 +438,7 @@ int unmark_failed_wwid(const char *wwid)
if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) {
condlog(1, "%s: path name overflow", __func__);
- return -1;
+ return WWID_FAILED_ERROR;
}
if (unlink(path) == 0)
--
2.17.2

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "mail@eworm.de" <mail@eworm.de>
Date: Sat, 25 Apr 2020 21:11:13 +0200
Subject: [PATCH] fix boolean value with json-c 0.14
Upstream json-c removed the TRUE and FALSE defines in commit
0992aac61f8b087efd7094e9ac2b84fa9c040fcd.
[mwilck]: Use stdbool.h, and keep the log message unchanged.
Signed-off-by: Christian Hesse <mail@eworm.de>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libdmmp/libdmmp_private.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libdmmp/libdmmp_private.h b/libdmmp/libdmmp_private.h
index ac85b63f..b1a6ddea 100644
--- a/libdmmp/libdmmp_private.h
+++ b/libdmmp/libdmmp_private.h
@@ -30,6 +30,7 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
+#include <stdbool.h>
#include <json.h>
#include "libdmmp/libdmmp.h"
@@ -82,7 +83,7 @@ static out_type func_name(struct dmmp_context *ctx, const char *var_name) { \
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) { \
+ 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; \
--
2.17.2

View File

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 4 Jun 2020 18:20:06 -0500
Subject: [PATCH] libmultipath: fix condlog NULL argument in uevent_get_env_var
uevent_get_env_var() could call condlog with p == NULL. On gcc 10,
this triggers warnings like:
In file included from uevent.c:47:
In function 'uevent_get_env_var',
inlined from 'uevent_get_wwid' at uevent.c:170:8:
debug.h:13:2: error: '%s' directive argument is null
[-Werror=format-overflow=]
13 | dlog(logsink, prio, fmt "\n", ##args)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uevent.c:132:2: note: in expansion of macro 'condlog'
132 | condlog(4, "%s: %s -> '%s'", __func__, attr, p);
| ^~~~~~~
uevent.c: In function 'uevent_get_wwid':
uevent.c:132:25: note: format string is defined here
132 | condlog(4, "%s: %s -> '%s'", __func__, attr, p);
| ^~
If p is NULL, use "(null)" instead.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/uevent.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index d38e8a7f..e0d13b11 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -129,7 +129,7 @@ static const char* uevent_get_env_var(const struct uevent *uev,
}
}
- condlog(4, "%s: %s -> '%s'", __func__, attr, p);
+ condlog(4, "%s: %s -> '%s'", __func__, attr, p ?: "(null)");
return p;
invalid:
--
2.17.2

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 21 Aug 2019 16:07:12 +0200
Subject: [PATCH] libmultipath: set "enable_foreign" to NONE by default
This has been requested by NetApp.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/defaults.h | 4 ++--
multipath/multipath.conf.5 | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index e5ee6afe..01a501bd 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -50,8 +50,8 @@
#define DEFAULT_FIND_MULTIPATHS_TIMEOUT -10
#define DEFAULT_UNKNOWN_FIND_MULTIPATHS_TIMEOUT 1
#define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF
-/* Enable all foreign libraries by default */
-#define DEFAULT_ENABLE_FOREIGN ""
+/* Enable no foreign libraries by default */
+#define DEFAULT_ENABLE_FOREIGN "NONE"
#define CHECKINT_UNDEF UINT_MAX
#define DEFAULT_CHECKINT 5
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 05a5e8ff..28cea88c 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1228,10 +1228,11 @@ Enables or disables foreign libraries (see section
.I FOREIGN MULTIPATH SUPPORT
below). The value is a regular expression; foreign libraries are loaded
if their name (e.g. \(dqnvme\(dq) matches the expression. By default,
-all foreign libraries are enabled.
+no foreign libraries are enabled. Set this to \(dqnvme\(dq to enable NVMe native
+multipath support, or \(dq.*\(dq to enable all foreign libraries.
.RS
.TP
-The default is: \fB\(dq\(dq\fR (the empty regular expression)
+The default is: \fB\(dqNONE\(dq\fR
.RE
.
.
--
2.17.2

View File

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 2 Mar 2020 22:43:27 +0100
Subject: [PATCH] multipath: add "-e" option to enable foreign libraries
As we have set "enable_foreign" to "NONE" now by default, users
may find it useful to be able to switch on foreign multipath display
with an extra command line option even if foreign libraries are
not enabled in multipath.conf. Currently this makes only sense
with "multipath -ll", as the nvme library (and foreign libraries
in general) support only the display of status information.
Suggested-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 11 ++++++++++-
multipath/multipath.8 | 6 ++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/multipath/main.c b/multipath/main.c
index 953fab27..c4740fab 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -145,6 +145,7 @@ usage (char * progname)
" -h print this usage text\n"
" -l show multipath topology (sysfs and DM info)\n"
" -ll show multipath topology (maximum info)\n"
+ " -e enable foreign libraries with -l/-ll\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"
@@ -865,6 +866,7 @@ main (int argc, char *argv[])
char *dev = NULL;
struct config *conf;
int retries = -1;
+ bool enable_foreign = false;
udev = udev_new();
logsink = 0;
@@ -874,7 +876,7 @@ main (int argc, char *argv[])
multipath_conf = conf;
conf->retrigger_tries = 0;
conf->force_sync = 1;
- while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":adcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -971,6 +973,9 @@ main (int argc, char *argv[])
case 'R':
retries = atoi(optarg);
break;
+ case 'e':
+ enable_foreign = true;
+ break;
case ':':
fprintf(stderr, "Missing option argument\n");
usage(argv[0]);
@@ -1022,6 +1027,10 @@ main (int argc, char *argv[])
condlog(0, "failed to initialize prioritizers");
goto out;
}
+
+ if ((cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) && enable_foreign)
+ conf->enable_foreign = "";
+
/* Failing here is non-fatal */
init_foreign(conf->multipath_dir, conf->enable_foreign);
if (cmd == CMD_USABLE_PATHS) {
diff --git a/multipath/multipath.8 b/multipath/multipath.8
index 9cdd05a3..6fb8645a 100644
--- a/multipath/multipath.8
+++ b/multipath/multipath.8
@@ -223,6 +223,12 @@ The verbosity level also controls the level of log and debug messages printed to
Dry run, do not create or update devmaps.
.
.TP
+.B \-e
+Enable all foreign libraries. This overrides the
+.I enable_foreign
+option from \fBmultipath.conf(5)\fR.
+.
+.TP
.B \-i
Ignore WWIDs file when processing devices. If
\fIfind_multipaths strict\fR or \fIfind_multipaths no\fR is set in
--
2.17.2

View File

@ -0,0 +1,139 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 9 Jun 2020 16:35:27 -0500
Subject: [PATCH] libmultipath: remove _blacklist_exceptions functions
_blacklist_exceptions() and _blacklist_exceptions_device() are exactly
the same as _blacklist() and _blacklist_device(), so remove them, and
give the remaining functions to a more general name.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/blacklist.c | 62 ++++++++++------------------------------
1 file changed, 15 insertions(+), 47 deletions(-)
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index 00e8dbdb..c21a0e27 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -101,21 +101,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
return 0;
}
-int
-_blacklist_exceptions (vector elist, const char * str)
-{
- int i;
- struct blentry * ele;
-
- vector_foreach_slot (elist, ele, i) {
- if (!regexec(&ele->regex, str, 0, NULL, 0))
- return 1;
- }
- return 0;
-}
-
-int
-_blacklist (vector blist, const char * str)
+static int
+match_reglist (vector blist, const char * str)
{
int i;
struct blentry * ble;
@@ -127,28 +114,9 @@ _blacklist (vector blist, const char * str)
return 0;
}
-int
-_blacklist_exceptions_device(const struct _vector *elist, const char * vendor,
- const char * product)
-{
- int i;
- struct blentry_device * ble;
-
- vector_foreach_slot (elist, ble, i) {
- if (!ble->vendor && !ble->product)
- continue;
- if ((!ble->vendor ||
- !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
- (!ble->product ||
- !regexec(&ble->product_reg, product, 0, NULL, 0)))
- return 1;
- }
- return 0;
-}
-
-int
-_blacklist_device (const struct _vector *blist, const char * vendor,
- const char * product)
+static int
+match_reglist_device (const struct _vector *blist, const char * vendor,
+ const char * product)
{
int i;
struct blentry_device * ble;
@@ -300,9 +268,9 @@ filter_device (vector blist, vector elist, char * vendor, char * product,
int r = MATCH_NOTHING;
if (vendor && product) {
- if (_blacklist_exceptions_device(elist, vendor, product))
+ if (match_reglist_device(elist, vendor, product))
r = MATCH_DEVICE_BLIST_EXCEPT;
- else if (_blacklist_device(blist, vendor, product))
+ else if (match_reglist_device(blist, vendor, product))
r = MATCH_DEVICE_BLIST;
}
@@ -316,9 +284,9 @@ filter_devnode (vector blist, vector elist, char * dev)
int r = MATCH_NOTHING;
if (dev) {
- if (_blacklist_exceptions(elist, dev))
+ if (match_reglist(elist, dev))
r = MATCH_DEVNODE_BLIST_EXCEPT;
- else if (_blacklist(blist, dev))
+ else if (match_reglist(blist, dev))
r = MATCH_DEVNODE_BLIST;
}
@@ -332,9 +300,9 @@ filter_wwid (vector blist, vector elist, char * wwid, char * dev)
int r = MATCH_NOTHING;
if (wwid) {
- if (_blacklist_exceptions(elist, wwid))
+ if (match_reglist(elist, wwid))
r = MATCH_WWID_BLIST_EXCEPT;
- else if (_blacklist(blist, wwid))
+ else if (match_reglist(blist, wwid))
r = MATCH_WWID_BLIST;
}
@@ -351,9 +319,9 @@ filter_protocol(vector blist, vector elist, struct path * pp)
if (pp) {
snprint_path_protocol(buf, sizeof(buf), pp);
- if (_blacklist_exceptions(elist, buf))
+ if (match_reglist(elist, buf))
r = MATCH_PROTOCOL_BLIST_EXCEPT;
- else if (_blacklist(blist, buf))
+ else if (match_reglist(blist, buf))
r = MATCH_PROTOCOL_BLIST;
}
@@ -422,11 +390,11 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl,
if (check_missing_prop && !strcmp(env, uid_attribute))
uid_attr_seen = true;
- if (_blacklist_exceptions(conf->elist_property, env)) {
+ if (match_reglist(conf->elist_property, env)) {
r = MATCH_PROPERTY_BLIST_EXCEPT;
break;
}
- if (_blacklist(conf->blist_property, env)) {
+ if (match_reglist(conf->blist_property, env)) {
r = MATCH_PROPERTY_BLIST;
break;
}
--
2.17.2

View File

@ -0,0 +1,95 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 9 Jun 2020 16:35:28 -0500
Subject: [PATCH] libmultipath: fix parser issue with comments in strings
If a quoted string starts with '#' or '!', the parser will stop
parsing the line, thinking that it's a comment. It should only
be checking for comments outside of quoted strings. Fixed this and
added unit tests to verify it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/parser.c | 4 +++-
tests/parser.c | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index d478b177..11a6168c 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -300,8 +300,10 @@ alloc_strvec(char *string)
(isspace((int) *cp) || !isascii((int) *cp)))
&& *cp != '\0')
cp++;
- if (*cp == '\0' || *cp == '!' || *cp == '#')
+ if (*cp == '\0' ||
+ (!in_string && (*cp == '!' || *cp == '#'))) {
return strvec;
+ }
}
out:
vector_free(strvec);
diff --git a/tests/parser.c b/tests/parser.c
index 29859dac..5772391e 100644
--- a/tests/parser.c
+++ b/tests/parser.c
@@ -440,6 +440,46 @@ static void test18(void **state)
free_strvec(v);
}
+static void test19(void **state)
+{
+#define QUOTED19 "!value"
+ vector v = alloc_strvec("key \"" QUOTED19 "\"");
+ char *val;
+
+ assert_int_equal(VECTOR_SIZE(v), 4);
+ assert_string_equal(VECTOR_SLOT(v, 0), "key");
+ assert_true(is_quote(VECTOR_SLOT(v, 1)));
+ assert_string_equal(VECTOR_SLOT(v, 2), QUOTED19);
+ assert_true(is_quote(VECTOR_SLOT(v, 3)));
+ assert_int_equal(validate_config_strvec(v, test_file), 0);
+
+ val = set_value(v);
+ assert_string_equal(val, QUOTED19);
+
+ free(val);
+ free_strvec(v);
+}
+
+static void test20(void **state)
+{
+#define QUOTED20 "#value"
+ vector v = alloc_strvec("key \"" QUOTED20 "\"");
+ char *val;
+
+ assert_int_equal(VECTOR_SIZE(v), 4);
+ assert_string_equal(VECTOR_SLOT(v, 0), "key");
+ assert_true(is_quote(VECTOR_SLOT(v, 1)));
+ assert_string_equal(VECTOR_SLOT(v, 2), QUOTED20);
+ assert_true(is_quote(VECTOR_SLOT(v, 3)));
+ assert_int_equal(validate_config_strvec(v, test_file), 0);
+
+ val = set_value(v);
+ assert_string_equal(val, QUOTED20);
+
+ free(val);
+ free_strvec(v);
+}
+
int test_config_parser(void)
{
const struct CMUnitTest tests[] = {
@@ -461,6 +501,8 @@ int test_config_parser(void)
cmocka_unit_test(test16),
cmocka_unit_test(test17),
cmocka_unit_test(test18),
+ cmocka_unit_test(test19),
+ cmocka_unit_test(test20),
};
return cmocka_run_group_tests(tests, setup, teardown);
}
--
2.17.2

View File

@ -0,0 +1,435 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 9 Jun 2020 16:35:29 -0500
Subject: [PATCH] libmultipath: invert regexes that start with exclamation
point
The number of devices that multipath needs to blacklist keeps growing,
and the udev rules already have
KERNEL!="sd*|dasd*|nvme*", GOTO="end_mpath"
so they only work correctly with these device types. Instead of
individually blacklisting every type of device that can't be
multipathed, multipath's default blacklist should work like the udev
rule, and blacklist all devices that aren't scsi, dasd, or nvme.
Unfortunately, the c regex library doesn't support negative lookahead.
Instead, multipath should treat "!" at the beginning of
blacklist/exceptions regexes as inverse matching the rest of the regex.
If users need to match a literal '!' as the first character of their
regex, they can use "\!" instead. This allows multipath to change the
default devnode blacklist regex to "!^(sd[a-z]|dasd[a-z]|nvme[0-9])".
Extra tests have been added to the blacklist unit tests to verify the
inverse matching code and the new default blacklist.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/blacklist.c | 41 +++++++++-----
libmultipath/blacklist.h | 3 +
multipath/multipath.conf.5 | 17 ++++--
tests/blacklist.c | 110 +++++++++++++++++++++++++++++++++++++
tests/test-lib.c | 2 +-
5 files changed, 155 insertions(+), 18 deletions(-)
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index c21a0e27..db58ccca 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -15,9 +15,24 @@
#include "structs_vec.h"
#include "print.h"
+char *check_invert(char *str, bool *invert)
+{
+ if (str[0] == '!') {
+ *invert = true;
+ return str + 1;
+ }
+ if (str[0] == '\\' && str[1] == '!') {
+ *invert = false;
+ return str + 1;
+ }
+ *invert = false;
+ return str;
+}
+
int store_ble(vector blist, char * str, int origin)
{
struct blentry * ble;
+ char *regex_str;
if (!str)
return 0;
@@ -30,7 +45,8 @@ int store_ble(vector blist, char * str, int origin)
if (!ble)
goto out;
- if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
+ regex_str = check_invert(str, &ble->invert);
+ if (regcomp(&ble->regex, regex_str, REG_EXTENDED|REG_NOSUB))
goto out1;
if (!vector_alloc_slot(blist))
@@ -66,6 +82,7 @@ int alloc_ble_device(vector blist)
int set_ble_device(vector blist, char * vendor, char * product, int origin)
{
struct blentry_device * ble;
+ char *regex_str;
if (!blist)
return 1;
@@ -76,7 +93,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
return 1;
if (vendor) {
- if (regcomp(&ble->vendor_reg, vendor,
+ regex_str = check_invert(vendor, &ble->vendor_invert);
+ if (regcomp(&ble->vendor_reg, regex_str,
REG_EXTENDED|REG_NOSUB)) {
FREE(vendor);
if (product)
@@ -86,7 +104,8 @@ int set_ble_device(vector blist, char * vendor, char * product, int origin)
ble->vendor = vendor;
}
if (product) {
- if (regcomp(&ble->product_reg, product,
+ regex_str = check_invert(product, &ble->product_invert);
+ if (regcomp(&ble->product_reg, regex_str,
REG_EXTENDED|REG_NOSUB)) {
FREE(product);
if (vendor) {
@@ -108,7 +127,7 @@ match_reglist (vector blist, const char * str)
struct blentry * ble;
vector_foreach_slot (blist, ble, i) {
- if (!regexec(&ble->regex, str, 0, NULL, 0))
+ if (!!regexec(&ble->regex, str, 0, NULL, 0) == ble->invert)
return 1;
}
return 0;
@@ -125,9 +144,11 @@ match_reglist_device (const struct _vector *blist, const char * vendor,
if (!ble->vendor && !ble->product)
continue;
if ((!ble->vendor ||
- !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
+ !!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) ==
+ ble->vendor_invert) &&
(!ble->product ||
- !regexec(&ble->product_reg, product, 0, NULL, 0)))
+ !!regexec(&ble->product_reg, product, 0, NULL, 0) ==
+ ble->product_invert))
return 1;
}
return 0;
@@ -160,13 +181,7 @@ setup_default_blist (struct config * conf)
char * str;
int i;
- str = STRDUP("^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]");
- if (!str)
- return 1;
- if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
- return 1;
-
- str = STRDUP("^(td|hd|vd)[a-z]");
+ str = STRDUP("!^(sd[a-z]|dasd[a-z]|nvme[0-9])");
if (!str)
return 1;
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
diff --git a/libmultipath/blacklist.h b/libmultipath/blacklist.h
index 2d721f60..4305857d 100644
--- a/libmultipath/blacklist.h
+++ b/libmultipath/blacklist.h
@@ -20,6 +20,7 @@
struct blentry {
char * str;
regex_t regex;
+ bool invert;
int origin;
};
@@ -28,6 +29,8 @@ struct blentry_device {
char * product;
regex_t vendor_reg;
regex_t product_reg;
+ bool vendor_invert;
+ bool product_invert;
int origin;
};
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 28cea88c..5adaced6 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1249,6 +1249,16 @@ being handled by multipath-tools.
.LP
.
.
+In the \fIblacklist\fR and \fIblacklist_exceptions\fR sections, starting a
+quoted value with an exclamation mark \fB"!"\fR will invert the matching
+of the rest of the regular expression. For instance, \fB"!^sd[a-z]"\fR will
+match all values that do not start with \fB"sd[a-z]"\fR. The exclamation mark
+can be escaped \fB"\\!"\fR to match a literal \fB!\fR at the start of a
+regular expression. \fBNote:\fR The exclamation mark must be inside quotes,
+otherwise it will be treated as starting a comment.
+.LP
+.
+.
The \fIblacklist_exceptions\fR section is used to revert the actions of the
\fIblacklist\fR section. This allows one to selectively include ("whitelist") devices which
would normally be excluded via the \fIblacklist\fR section. A common usage is
@@ -1265,10 +1275,9 @@ unless explicitly stated.
Regular expression matching the device nodes to be excluded/included.
.RS
.PP
-The default \fIblacklist\fR consists of the regular expressions
-"^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st|dcssblk)[0-9]" and
-"^(td|hd|vd)[a-z]". This causes virtual devices, non-disk devices, and some other
-device types to be excluded from multipath handling by default.
+The default \fIblacklist\fR consists of the regular expression
+\fB"!^(sd[a-z]|dasd[a-z]|nvme[0-9])"\fR. This causes all device types other
+than scsi, dasd, and nvme to be excluded from multipath handling by default.
.RE
.TP
.B wwid
diff --git a/tests/blacklist.c b/tests/blacklist.c
index 6e7c1864..d5c40898 100644
--- a/tests/blacklist.c
+++ b/tests/blacklist.c
@@ -60,20 +60,46 @@ __wrap_udev_list_entry_get_name(struct udev_list_entry *list_entry)
return *(const char **)list_entry;
}
+vector elist_property_default;
+vector blist_devnode_default;
vector blist_devnode_sdb;
+vector blist_devnode_sdb_inv;
vector blist_all;
vector blist_device_foo_bar;
+vector blist_device_foo_inv_bar;
+vector blist_device_foo_bar_inv;
vector blist_device_all;
vector blist_wwid_xyzzy;
+vector blist_wwid_xyzzy_inv;
vector blist_protocol_fcp;
+vector blist_protocol_fcp_inv;
vector blist_property_wwn;
+vector blist_property_wwn_inv;
static int setup(void **state)
{
+ struct config conf;
+
+ memset(&conf, 0, sizeof(conf));
+ conf.blist_devnode = vector_alloc();
+ if (!conf.blist_devnode)
+ return -1;
+ conf.elist_property = vector_alloc();
+ if (!conf.elist_property)
+ return -1;
+ if (setup_default_blist(&conf) != 0)
+ return -1;
+ elist_property_default = conf.elist_property;
+ blist_devnode_default = conf.blist_devnode;
+
blist_devnode_sdb = vector_alloc();
if (!blist_devnode_sdb ||
store_ble(blist_devnode_sdb, strdup("sdb"), ORIGIN_CONFIG))
return -1;
+ blist_devnode_sdb_inv = vector_alloc();
+ if (!blist_devnode_sdb_inv ||
+ store_ble(blist_devnode_sdb_inv, strdup("!sdb"), ORIGIN_CONFIG))
+ return -1;
blist_all = vector_alloc();
if (!blist_all || store_ble(blist_all, strdup(".*"), ORIGIN_CONFIG))
@@ -84,6 +110,18 @@ static int setup(void **state)
set_ble_device(blist_device_foo_bar, strdup("foo"), strdup("bar"),
ORIGIN_CONFIG))
return -1;
+ blist_device_foo_inv_bar = vector_alloc();
+ if (!blist_device_foo_inv_bar ||
+ alloc_ble_device(blist_device_foo_inv_bar) ||
+ set_ble_device(blist_device_foo_inv_bar, strdup("!foo"),
+ strdup("bar"), ORIGIN_CONFIG))
+ return -1;
+ blist_device_foo_bar_inv = vector_alloc();
+ if (!blist_device_foo_bar_inv ||
+ alloc_ble_device(blist_device_foo_bar_inv) ||
+ set_ble_device(blist_device_foo_bar_inv, strdup("foo"),
+ strdup("!bar"), ORIGIN_CONFIG))
+ return -1;
blist_device_all = vector_alloc();
if (!blist_device_all || alloc_ble_device(blist_device_all) ||
@@ -95,29 +133,50 @@ static int setup(void **state)
if (!blist_wwid_xyzzy ||
store_ble(blist_wwid_xyzzy, strdup("xyzzy"), ORIGIN_CONFIG))
return -1;
+ blist_wwid_xyzzy_inv = vector_alloc();
+ if (!blist_wwid_xyzzy_inv ||
+ store_ble(blist_wwid_xyzzy_inv, strdup("!xyzzy"), ORIGIN_CONFIG))
+ return -1;
blist_protocol_fcp = vector_alloc();
if (!blist_protocol_fcp ||
store_ble(blist_protocol_fcp, strdup("scsi:fcp"), ORIGIN_CONFIG))
return -1;
+ blist_protocol_fcp_inv = vector_alloc();
+ if (!blist_protocol_fcp_inv ||
+ store_ble(blist_protocol_fcp_inv, strdup("!scsi:fcp"),
+ ORIGIN_CONFIG))
+ return -1;
blist_property_wwn = vector_alloc();
if (!blist_property_wwn ||
store_ble(blist_property_wwn, strdup("ID_WWN"), ORIGIN_CONFIG))
return -1;
+ blist_property_wwn_inv = vector_alloc();
+ if (!blist_property_wwn_inv ||
+ store_ble(blist_property_wwn_inv, strdup("!ID_WWN"), ORIGIN_CONFIG))
+ return -1;
return 0;
}
static int teardown(void **state)
{
+ free_blacklist(elist_property_default);
+ free_blacklist(blist_devnode_default);
free_blacklist(blist_devnode_sdb);
+ free_blacklist(blist_devnode_sdb_inv);
free_blacklist(blist_all);
free_blacklist_device(blist_device_foo_bar);
+ free_blacklist_device(blist_device_foo_inv_bar);
+ free_blacklist_device(blist_device_foo_bar_inv);
free_blacklist_device(blist_device_all);
free_blacklist(blist_wwid_xyzzy);
+ free_blacklist(blist_wwid_xyzzy_inv);
free_blacklist(blist_protocol_fcp);
+ free_blacklist(blist_protocol_fcp_inv);
free_blacklist(blist_property_wwn);
+ free_blacklist(blist_property_wwn_inv);
return 0;
}
@@ -141,6 +200,11 @@ static void test_devnode_blacklist(void **state)
expect_condlog(3, "sdb: device node name blacklisted\n");
assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdb"),
MATCH_DEVNODE_BLIST);
+ assert_int_equal(filter_devnode(blist_devnode_sdb_inv, NULL, "sdb"),
+ MATCH_NOTHING);
+ expect_condlog(3, "sdc: device node name blacklisted\n");
+ assert_int_equal(filter_devnode(blist_devnode_sdb_inv, NULL, "sdc"),
+ MATCH_DEVNODE_BLIST);
}
static void test_devnode_whitelist(void **state)
@@ -159,12 +223,39 @@ static void test_devnode_missing(void **state)
MATCH_NOTHING);
}
+static void test_devnode_default(void **state)
+{
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "sdaa"),
+ MATCH_NOTHING);
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "nvme0n1"),
+ MATCH_NOTHING);
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "dasda"),
+ MATCH_NOTHING);
+ expect_condlog(3, "hda: device node name blacklisted\n");
+ assert_int_equal(filter_devnode(blist_devnode_default, NULL, "hda"),
+ MATCH_DEVNODE_BLIST);
+}
+
static void test_device_blacklist(void **state)
{
expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
"bar", "sdb"),
MATCH_DEVICE_BLIST);
+ assert_int_equal(filter_device(blist_device_foo_inv_bar, NULL, "foo",
+ "bar", "sdb"),
+ MATCH_NOTHING);
+ assert_int_equal(filter_device(blist_device_foo_bar_inv, NULL, "foo",
+ "bar", "sdb"),
+ MATCH_NOTHING);
+ expect_condlog(3, "sdb: (baz:bar) vendor/product blacklisted\n");
+ assert_int_equal(filter_device(blist_device_foo_inv_bar, NULL, "baz",
+ "bar", "sdb"),
+ MATCH_DEVICE_BLIST);
+ expect_condlog(3, "sdb: (foo:baz) vendor/product blacklisted\n");
+ assert_int_equal(filter_device(blist_device_foo_bar_inv, NULL, "foo",
+ "baz", "sdb"),
+ MATCH_DEVICE_BLIST);
}
static void test_device_whitelist(void **state)
@@ -191,6 +282,11 @@ static void test_wwid_blacklist(void **state)
expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "xyzzy", "sdb"),
MATCH_WWID_BLIST);
+ assert_int_equal(filter_wwid(blist_wwid_xyzzy_inv, NULL, "xyzzy",
+ "sdb"), MATCH_NOTHING);
+ expect_condlog(3, "sdb: wwid plugh blacklisted\n");
+ assert_int_equal(filter_wwid(blist_wwid_xyzzy_inv, NULL, "plugh",
+ "sdb"), MATCH_WWID_BLIST);
}
static void test_wwid_whitelist(void **state)
@@ -218,6 +314,12 @@ static void test_protocol_blacklist(void **state)
expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
MATCH_PROTOCOL_BLIST);
+ assert_int_equal(filter_protocol(blist_protocol_fcp_inv, NULL, &pp),
+ MATCH_NOTHING);
+ pp.sg_id.proto_id = SCSI_PROTOCOL_ATA;
+ expect_condlog(3, "sdb: protocol scsi:ata blacklisted\n");
+ assert_int_equal(filter_protocol(blist_protocol_fcp_inv, NULL, &pp),
+ MATCH_PROTOCOL_BLIST);
}
static void test_protocol_whitelist(void **state)
@@ -245,10 +347,17 @@ static void test_protocol_missing(void **state)
static void test_property_blacklist(void **state)
{
static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
+ static struct udev_device udev_inv = { "sdb", { "ID_WWN", NULL } };
conf.blist_property = blist_property_wwn;
expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
MATCH_PROPERTY_BLIST);
+ conf.blist_property = blist_property_wwn_inv;
+ expect_condlog(3, "sdb: udev property ID_FOO blacklisted\n");
+ assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
+ MATCH_PROPERTY_BLIST);
+ assert_int_equal(filter_property(&conf, &udev_inv, 3, "ID_SERIAL"),
+ MATCH_NOTHING);
}
/* the property check works different in that you check all the property
@@ -484,6 +593,7 @@ int test_blacklist(void)
cmocka_unit_test(test_devnode_blacklist),
cmocka_unit_test(test_devnode_whitelist),
cmocka_unit_test(test_devnode_missing),
+ cmocka_unit_test(test_devnode_default),
cmocka_unit_test(test_device_blacklist),
cmocka_unit_test(test_device_whitelist),
cmocka_unit_test(test_device_missing),
diff --git a/tests/test-lib.c b/tests/test-lib.c
index 00bae58e..b7c09cc2 100644
--- a/tests/test-lib.c
+++ b/tests/test-lib.c
@@ -15,7 +15,7 @@
#include "test-lib.h"
const int default_mask = (DI_SYSFS|DI_BLACKLIST|DI_WWID|DI_CHECKER|DI_PRIO);
-const char default_devnode[] = "sdTEST";
+const char default_devnode[] = "sdxTEST";
const char default_wwid[] = "TEST-WWID";
/* default_wwid should be a substring of default_wwid_1! */
const char default_wwid_1[] = "TEST-WWID-1";
--
2.17.2

View File

@ -0,0 +1,111 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marius Bakke <marius@devup.no>
Date: Wed, 17 Jun 2020 01:11:26 +0200
Subject: [PATCH] multipath: Fix compiler warnings when built without systemd.
Add ifdef guards for code that is unused when systemd is not available.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 6 ++++--
multipathd/main.c | 10 +++++++++-
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index b4d87689..658bec8b 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -696,9 +696,9 @@ process_config_dir(struct config *conf, char *dir)
pthread_cleanup_pop(1);
}
+#ifdef USE_SYSTEMD
static void set_max_checkint_from_watchdog(struct config *conf)
{
-#ifdef USE_SYSTEMD
char *envp = getenv("WATCHDOG_USEC");
unsigned long checkint;
@@ -714,8 +714,8 @@ static void set_max_checkint_from_watchdog(struct config *conf)
condlog(3, "enabling watchdog, interval %ld", checkint);
conf->use_watchdog = true;
}
-#endif
}
+#endif
struct config *
load_config (char * file)
@@ -789,7 +789,9 @@ load_config (char * file)
/*
* fill the voids left in the config file
*/
+#ifdef USE_SYSTEMD
set_max_checkint_from_watchdog(conf);
+#endif
if (conf->max_checkint == 0) {
if (conf->checkint == CHECKINT_UNDEF)
conf->checkint = DEFAULT_CHECKINT;
diff --git a/multipathd/main.c b/multipathd/main.c
index 6b7db2c0..205ddb32 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -176,6 +176,7 @@ daemon_status(void)
/*
* I love you too, systemd ...
*/
+#ifdef USE_SYSTEMD
static const char *
sd_notify_status(enum daemon_status state)
{
@@ -195,7 +196,6 @@ sd_notify_status(enum daemon_status state)
return NULL;
}
-#ifdef USE_SYSTEMD
static void do_sd_notify(enum daemon_status old_state,
enum daemon_status new_state)
{
@@ -247,7 +247,9 @@ enum daemon_status wait_for_state_change_if(enum daemon_status oldstate,
static void __post_config_state(enum daemon_status state)
{
if (state != running_state && running_state != DAEMON_SHUTDOWN) {
+#ifdef USE_SYSTEMD
enum daemon_status old_state = running_state;
+#endif
running_state = state;
pthread_cond_broadcast(&config_cond);
@@ -272,7 +274,9 @@ int set_config_state(enum daemon_status state)
pthread_cleanup_push(config_cleanup, NULL);
pthread_mutex_lock(&config_lock);
if (running_state != state) {
+#ifdef USE_SYSTEMD
enum daemon_status old_state = running_state;
+#endif
if (running_state == DAEMON_SHUTDOWN)
rc = EINVAL;
@@ -2280,7 +2284,9 @@ checkerloop (void *ap)
struct timespec last_time;
struct config *conf;
int foreign_tick = 0;
+#ifdef USE_SYSTEMD
bool use_watchdog;
+#endif
pthread_cleanup_push(rcu_unregister, NULL);
rcu_register_thread();
@@ -2294,7 +2300,9 @@ checkerloop (void *ap)
/* use_watchdog is set from process environment and never changes */
conf = get_multipath_config();
+#ifdef USE_SYSTEMD
use_watchdog = conf->use_watchdog;
+#endif
put_multipath_config(conf);
while (1) {
--
2.17.2

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:38:24 -0500
Subject: [PATCH] libmultipath: fix sysfs dev_loss_tmo parsing
dev_loss_tmo is a u32 value. However the kernel sysfs code prints it as
a signed integer. This means that if dev_loss_tmo is above INT_MAX, the
sysfs value will be a negative number. Parsing this was causing
sysfs_set_rport_tmo() to fail.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/discovery.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index ffec5162..83a41a4a 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -583,7 +583,7 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
struct udev_device *rport_dev = NULL;
char value[16], *eptr;
char rport_id[32];
- unsigned long long tmo = 0;
+ unsigned int tmo;
int ret;
sprintf(rport_id, "rport-%d:%d-%d",
@@ -607,8 +607,8 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
"error %d", rport_id, -ret);
goto out;
}
- tmo = strtoull(value, &eptr, 0);
- if (value == eptr || tmo == ULLONG_MAX) {
+ tmo = strtoul(value, &eptr, 0);
+ if (value == eptr) {
condlog(0, "%s: Cannot parse dev_loss_tmo "
"attribute '%s'", rport_id, value);
goto out;
--
2.17.2

View File

@ -0,0 +1,267 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:38:25 -0500
Subject: [PATCH] kpartx: read devices with direct IO
If kpartx is used on top of shared storage, and a device has its
partition table changed on one machine, and then kpartx is run on
another, it may not see the new data, because the cache still contains
the old data, and there is nothing to tell the machine running kpartx to
invalidate it. To solve this, kpartx should read the devices using
direct io.
One issue with how this code has been updated is that the original code
for getblock() always read 1024 bytes. The new code reads a logical
sector size chunk of the device, and returns a pointer to the 512 byte
sector that the caller asked for, within that (possibly larger) chunk.
This means that if the logical sector size is 512, then the code is now
only reading 512 bytes. Looking through the code for the various
partition types, I can't see a case where more than 512 bytes is needed
and getblock() is used. If anyone has a reason why this code should be
reading 1024 bytes at minmum, I can certainly change this. But when I
looked, I couldn't find a case where reading 512 bytes would cause a
problem.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/dasd.c | 7 ++++---
kpartx/gpt.c | 22 +++++++++----------
kpartx/kpartx.c | 56 +++++++++++++++++++++++++++++++++++++++----------
kpartx/kpartx.h | 2 ++
4 files changed, 61 insertions(+), 26 deletions(-)
diff --git a/kpartx/dasd.c b/kpartx/dasd.c
index 14b9d3aa..f0398645 100644
--- a/kpartx/dasd.c
+++ b/kpartx/dasd.c
@@ -22,6 +22,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -117,13 +118,13 @@ read_dasd_pt(int fd, __attribute__((unused)) struct slice all,
sprintf(pathname, "/dev/.kpartx-node-%u-%u",
(unsigned int)major(dev), (unsigned int)minor(dev));
- if ((fd_dasd = open(pathname, O_RDONLY)) == -1) {
+ if ((fd_dasd = open(pathname, O_RDONLY | O_DIRECT)) == -1) {
/* Devicenode does not exist. Try to create one */
if (mknod(pathname, 0600 | S_IFBLK, dev) == -1) {
/* Couldn't create a device node */
return -1;
}
- fd_dasd = open(pathname, O_RDONLY);
+ fd_dasd = open(pathname, O_RDONLY | O_DIRECT);
/*
* The file will vanish when the last process (we)
* has ceased to access it.
@@ -175,7 +176,7 @@ read_dasd_pt(int fd, __attribute__((unused)) struct slice all,
* Get volume label, extract name and type.
*/
- if (!(data = (unsigned char *)malloc(blocksize)))
+ if (aligned_malloc((void **)&data, blocksize, NULL))
goto out;
diff --git a/kpartx/gpt.c b/kpartx/gpt.c
index 785b34ea..f7fefb70 100644
--- a/kpartx/gpt.c
+++ b/kpartx/gpt.c
@@ -243,8 +243,7 @@ alloc_read_gpt_entries(int fd, gpt_header * gpt)
if (!count) return NULL;
- pte = (gpt_entry *)malloc(count);
- if (!pte)
+ if (aligned_malloc((void **)&pte, get_sector_size(fd), &count))
return NULL;
memset(pte, 0, count);
@@ -269,12 +268,11 @@ static gpt_header *
alloc_read_gpt_header(int fd, uint64_t lba)
{
gpt_header *gpt;
- gpt = (gpt_header *)
- malloc(sizeof (gpt_header));
- if (!gpt)
+ size_t size = sizeof (gpt_header);
+ if (aligned_malloc((void **)&gpt, get_sector_size(fd), &size))
return NULL;
- memset(gpt, 0, sizeof (*gpt));
- if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
+ memset(gpt, 0, size);
+ if (!read_lba(fd, lba, gpt, size)) {
free(gpt);
return NULL;
}
@@ -498,6 +496,7 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
gpt_header *pgpt = NULL, *agpt = NULL;
gpt_entry *pptes = NULL, *aptes = NULL;
legacy_mbr *legacymbr = NULL;
+ size_t size = sizeof(legacy_mbr);
uint64_t lastlba;
if (!gpt || !ptes)
return 0;
@@ -526,11 +525,10 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
}
/* This will be added to the EFI Spec. per Intel after v1.02. */
- legacymbr = malloc(sizeof (*legacymbr));
- if (legacymbr) {
- memset(legacymbr, 0, sizeof (*legacymbr));
- read_lba(fd, 0, (uint8_t *) legacymbr,
- sizeof (*legacymbr));
+ if (aligned_malloc((void **)&legacymbr, get_sector_size(fd),
+ &size) == 0) {
+ memset(legacymbr, 0, size);
+ read_lba(fd, 0, (uint8_t *) legacymbr, size);
good_pmbr = is_pmbr_valid(legacymbr);
free(legacymbr);
legacymbr=NULL;
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index d3620c5c..c24ad6d9 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -19,6 +19,7 @@
* cva, 2002-10-26
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
@@ -41,7 +42,6 @@
#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
-#define READ_SIZE 1024
#define MAXTYPES 64
#define MAXSLICES 256
#define DM_TARGET "linear"
@@ -388,7 +388,7 @@ main(int argc, char **argv){
set_delimiter(mapname, delim);
}
- fd = open(device, O_RDONLY);
+ fd = open(device, O_RDONLY | O_DIRECT);
if (fd == -1) {
perror(device);
@@ -690,9 +690,9 @@ xmalloc (size_t size) {
*/
static int
-sseek(int fd, unsigned int secnr) {
+sseek(int fd, unsigned int secnr, int secsz) {
off64_t in, out;
- in = ((off64_t) secnr << 9);
+ in = ((off64_t) secnr * secsz);
out = 1;
if ((out = lseek64(fd, in, SEEK_SET)) != in)
@@ -703,6 +703,31 @@ sseek(int fd, unsigned int secnr) {
return 0;
}
+int
+aligned_malloc(void **mem_p, size_t align, size_t *size_p)
+{
+ static size_t pgsize = 0;
+ size_t size;
+ int err;
+
+ if (!mem_p || !align || (size_p && !*size_p))
+ return EINVAL;
+
+ if (!pgsize)
+ pgsize = getpagesize();
+
+ if (size_p)
+ size = ((*size_p + align - 1) / align) * align;
+ else
+ size = pgsize;
+
+ err = posix_memalign(mem_p, pgsize, size);
+ if (!err && size_p)
+ *size_p = size;
+ return err;
+}
+
+/* always in sector size blocks */
static
struct block {
unsigned int secnr;
@@ -710,30 +735,39 @@ struct block {
struct block *next;
} *blockhead;
+/* blknr is always in 512 byte blocks */
char *
-getblock (int fd, unsigned int secnr) {
+getblock (int fd, unsigned int blknr) {
+ unsigned int secsz = get_sector_size(fd);
+ unsigned int blks_per_sec = secsz / 512;
+ unsigned int secnr = blknr / blks_per_sec;
+ unsigned int blk_off = (blknr % blks_per_sec) * 512;
struct block *bp;
for (bp = blockhead; bp; bp = bp->next)
if (bp->secnr == secnr)
- return bp->block;
+ return bp->block + blk_off;
- if (sseek(fd, secnr))
+ if (sseek(fd, secnr, secsz))
return NULL;
bp = xmalloc(sizeof(struct block));
bp->secnr = secnr;
bp->next = blockhead;
blockhead = bp;
- bp->block = (char *) xmalloc(READ_SIZE);
+ if (aligned_malloc((void **)&bp->block, secsz, NULL)) {
+ fprintf(stderr, "aligned_malloc failed\n");
+ exit(1);
+ }
- if (read(fd, bp->block, READ_SIZE) != READ_SIZE) {
+ if (read(fd, bp->block, secsz) != secsz) {
fprintf(stderr, "read error, sector %d\n", secnr);
- bp->block = NULL;
+ blockhead = bp->next;
+ return NULL;
}
- return bp->block;
+ return bp->block + blk_off;
}
int
diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h
index 67edeb82..727632c1 100644
--- a/kpartx/kpartx.h
+++ b/kpartx/kpartx.h
@@ -1,6 +1,7 @@
#ifndef _KPARTX_H
#define _KPARTX_H
+#include <stddef.h>
#include <stdint.h>
#include <sys/ioctl.h>
@@ -61,6 +62,7 @@ extern ptreader read_mac_pt;
extern ptreader read_sun_pt;
extern ptreader read_ps3_pt;
+int aligned_malloc(void **mem_p, size_t align, size_t *size_p);
char *getblock(int fd, unsigned int secnr);
static inline unsigned int
--
2.17.2

View File

@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:38:26 -0500
Subject: [PATCH] kpartx: handle alternate bsd disklabel location
bsd disk labels can either be at the start of the second sector, or 64
bytes into the first sector, but kpartx only handled the first case.
However the second case is what parted creates, and what the linux
kernel partition code expects. kpartx should handle both cases.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/bsd.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/kpartx/bsd.c b/kpartx/bsd.c
index 0e661fbc..950b0f92 100644
--- a/kpartx/bsd.c
+++ b/kpartx/bsd.c
@@ -1,6 +1,7 @@
#include "kpartx.h"
#include <stdio.h>
+#define BSD_LABEL_OFFSET 64
#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
#define XBSD_MAXPARTITIONS 16
#define BSD_FS_UNUSED 0
@@ -60,8 +61,19 @@ read_bsd_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) {
return -1;
l = (struct bsd_disklabel *) bp;
- if (l->d_magic != BSD_DISKMAGIC)
- return -1;
+ if (l->d_magic != BSD_DISKMAGIC) {
+ /*
+ * BSD disklabels can also start 64 bytes offset from the
+ * start of the first sector
+ */
+ bp = getblock(fd, offset);
+ if (bp == NULL)
+ return -1;
+
+ l = (struct bsd_disklabel *)(bp + 64);
+ if (l->d_magic != BSD_DISKMAGIC)
+ return -1;
+ }
max_partitions = 16;
if (l->d_npartitions < max_partitions)
--
2.17.2

View File

@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:38:27 -0500
Subject: [PATCH] libmultipath: fix checker detection for nvme devices
In order to fix hwhandler autodetection, commit 8794a776 made
detect_alua() differentiate between failures to detect whether alua was
supported, and successfully detecting that it was not supported.
However, this causes nvme devices to get the TUR checker assigned to
them. This is because there is nothing in detect_alua() to make it only
work on scsi devices, and select_checker wasn't updated to handle
detect_alua() failing without setting pp->tpgs to TPGS_NONE.
detect_alua() should automatically set pp->tpgs to TPGS_NONE and exit on
non-scsi devices. Also, select_checker() should not assume that a
devices is ALUA, simply because if failed to detect if alua was
supported.
Fixes: 8794a776 "libmultipath: fix ALUA autodetection when paths are
down"
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 6 ++++++
libmultipath/propsel.c | 4 +++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 83a41a4a..aa5942c3 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -887,6 +887,12 @@ detect_alua(struct path * pp)
int tpgs;
unsigned int timeout;
+
+ if (pp->bus != SYSFS_BUS_SCSI) {
+ pp->tpgs = TPGS_NONE;
+ return;
+ }
+
if (sysfs_get_timeout(pp, &timeout) <= 0)
timeout = DEF_TIMEOUT;
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 897e48ca..d362beb4 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -521,7 +521,9 @@ int select_checker(struct config *conf, struct path *pp)
if (check_rdac(pp)) {
ckr_name = RDAC;
goto out;
- } else if (path_get_tpgs(pp) != TPGS_NONE) {
+ }
+ path_get_tpgs(pp);
+ if (pp->tpgs != TPGS_NONE && pp->tpgs != TPGS_UNDEF) {
ckr_name = TUR;
goto out;
}
--
2.17.2

View File

@ -0,0 +1,322 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:00 -0500
Subject: [PATCH] libmultipath: make dm_get_map/status return codes symbolic
dm_get_map() and dm_get_status() now use symbolic return codes. They
also differentiate between failing to get information from device-mapper
and not finding the requested device. These symboilc return codes are
also used by update_multipath_* functions.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 51 +++++++++++++++++++++++++-------------
libmultipath/devmapper.h | 6 +++++
libmultipath/structs_vec.c | 45 +++++++++++++++++++--------------
multipathd/main.c | 12 ++++-----
4 files changed, 72 insertions(+), 42 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 27d52398..24cc616a 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -534,36 +534,43 @@ int dm_map_present(const char * str)
int dm_get_map(const char *name, unsigned long long *size, char *outparams)
{
- int r = 1;
+ int r = DMP_ERR;
struct dm_task *dmt;
uint64_t start, length;
char *target_type = NULL;
char *params = NULL;
if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
- return 1;
+ return r;
if (!dm_task_set_name(dmt, name))
goto out;
dm_task_no_open_count(dmt);
- if (!dm_task_run(dmt))
+ errno = 0;
+ if (!dm_task_run(dmt)) {
+ if (dm_task_get_errno(dmt) == ENXIO)
+ r = DMP_NOT_FOUND;
goto out;
+ }
+ r = DMP_NOT_FOUND;
/* Fetch 1st target */
- dm_get_next_target(dmt, NULL, &start, &length,
- &target_type, &params);
+ if (dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, &params) != NULL)
+ /* more than one target */
+ goto out;
if (size)
*size = length;
if (!outparams) {
- r = 0;
+ r = DMP_OK;
goto out;
}
if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
- r = 0;
+ r = DMP_OK;
out:
dm_task_destroy(dmt);
return r;
@@ -637,35 +644,45 @@ is_mpath_part(const char *part_name, const char *map_name)
int dm_get_status(const char *name, char *outstatus)
{
- int r = 1;
+ int r = DMP_ERR;
struct dm_task *dmt;
uint64_t start, length;
char *target_type = NULL;
char *status = NULL;
if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
- return 1;
+ return r;
if (!dm_task_set_name(dmt, name))
goto out;
dm_task_no_open_count(dmt);
- if (!dm_task_run(dmt))
+ errno = 0;
+ if (!dm_task_run(dmt)) {
+ if (dm_task_get_errno(dmt) == ENXIO)
+ r = DMP_NOT_FOUND;
goto out;
+ }
+ r = DMP_NOT_FOUND;
/* Fetch 1st target */
- dm_get_next_target(dmt, NULL, &start, &length,
- &target_type, &status);
+ if (dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, &status) != NULL)
+ goto out;
+
+ if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
+ goto out;
+
if (!status) {
condlog(2, "get null status.");
goto out;
}
if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
- r = 0;
+ r = DMP_OK;
out:
- if (r)
+ if (r != DMP_OK)
condlog(0, "%s: error getting map status string", name);
dm_task_destroy(dmt);
@@ -920,7 +937,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
return 1;
if (need_suspend &&
- !dm_get_map(mapname, &mapsize, params) &&
+ dm_get_map(mapname, &mapsize, params) == DMP_OK &&
strstr(params, "queue_if_no_path")) {
if (!dm_queue_if_no_path(mapname, 0))
queue_if_no_path = 1;
@@ -1129,7 +1146,7 @@ struct multipath *dm_get_multipath(const char *name)
if (!mpp->alias)
goto out;
- if (dm_get_map(name, &mpp->size, NULL))
+ if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
goto out;
dm_get_uuid(name, mpp->wwid, WWID_SIZE);
@@ -1313,7 +1330,7 @@ do_foreach_partmaps (const char * mapname,
/*
* and we can fetch the map table from the kernel
*/
- !dm_get_map(names->name, &size, &params[0]) &&
+ dm_get_map(names->name, &size, &params[0]) == DMP_OK &&
/*
* and the table maps over the multipath map
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 5ed7edc5..b2108638 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -27,6 +27,12 @@
#define UUID_PREFIX "mpath-"
#define UUID_PREFIX_LEN (sizeof(UUID_PREFIX) - 1)
+enum {
+ DMP_ERR,
+ DMP_OK,
+ DMP_NOT_FOUND,
+};
+
void dm_init(int verbosity);
int dm_prereq(unsigned int *v);
void skip_libmp_dm_init(void);
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 077f2e42..8137ea21 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -196,43 +196,47 @@ extract_hwe_from_path(struct multipath * mpp)
int
update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
{
+ int r = DMP_ERR;
char params[PARAMS_SIZE] = {0};
if (!mpp)
- return 1;
+ return r;
- if (dm_get_map(mpp->alias, &mpp->size, params)) {
- condlog(3, "%s: cannot get map", mpp->alias);
- return 1;
+ r = dm_get_map(mpp->alias, &mpp->size, params);
+ if (r != DMP_OK) {
+ condlog(3, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting table" : "map not present");
+ return r;
}
if (disassemble_map(pathvec, params, mpp, is_daemon)) {
condlog(3, "%s: cannot disassemble map", mpp->alias);
- return 1;
+ return DMP_ERR;
}
- return 0;
+ return DMP_OK;
}
int
update_multipath_status (struct multipath *mpp)
{
+ int r = DMP_ERR;
char status[PARAMS_SIZE] = {0};
if (!mpp)
- return 1;
+ return r;
- if (dm_get_status(mpp->alias, status)) {
- condlog(3, "%s: cannot get status", mpp->alias);
- return 1;
+ r = dm_get_status(mpp->alias, status);
+ if (r != DMP_OK) {
+ condlog(3, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting status" : "map not present");
+ return r;
}
if (disassemble_status(status, mpp)) {
condlog(3, "%s: cannot disassemble status", mpp->alias);
- return 1;
+ return DMP_ERR;
}
- return 0;
+ return DMP_OK;
}
void sync_paths(struct multipath *mpp, vector pathvec)
@@ -264,10 +268,10 @@ int
update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
{
struct pathgroup *pgp;
- int i;
+ int i, r = DMP_ERR;
if (!mpp)
- return 1;
+ return r;
update_mpp_paths(mpp, pathvec);
condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
@@ -276,18 +280,21 @@ update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
free_pgvec(mpp->pg, KEEP_PATHS);
mpp->pg = NULL;
- if (update_multipath_table(mpp, pathvec, is_daemon))
- return 1;
+ r = update_multipath_table(mpp, pathvec, is_daemon);
+ if (r != DMP_OK)
+ return r;
+
sync_paths(mpp, pathvec);
- if (update_multipath_status(mpp))
- return 1;
+ r = update_multipath_status(mpp);
+ if (r != DMP_OK)
+ return r;
vector_foreach_slot(mpp->pg, pgp, i)
if (pgp->paths)
path_group_prio_update(pgp);
- return 0;
+ return DMP_OK;
}
static void enter_recovery_mode(struct multipath *mpp)
diff --git a/multipathd/main.c b/multipathd/main.c
index 205ddb32..ab141fed 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -418,7 +418,7 @@ int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
goto out;
}
- if (update_multipath_strings(mpp, vecs->pathvec, 1)) {
+ if (update_multipath_strings(mpp, vecs->pathvec, 1) != DMP_OK) {
condlog(0, "%s: failed to setup multipath", mpp->alias);
goto out;
}
@@ -557,9 +557,9 @@ add_map_without_path (struct vectors *vecs, const char *alias)
mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
put_multipath_config(conf);
- if (update_multipath_table(mpp, vecs->pathvec, 1))
+ if (update_multipath_table(mpp, vecs->pathvec, 1) != DMP_OK)
goto out;
- if (update_multipath_status(mpp))
+ if (update_multipath_status(mpp) != DMP_OK)
goto out;
if (!vector_alloc_slot(vecs->mpvec))
@@ -1350,8 +1350,8 @@ map_discovery (struct vectors * vecs)
return 1;
vector_foreach_slot (vecs->mpvec, mpp, i)
- if (update_multipath_table(mpp, vecs->pathvec, 1) ||
- update_multipath_status(mpp)) {
+ if (update_multipath_table(mpp, vecs->pathvec, 1) != DMP_OK ||
+ update_multipath_status(mpp) != DMP_OK) {
remove_map(mpp, vecs, 1);
i--;
}
@@ -2091,7 +2091,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
/*
* Synchronize with kernel state
*/
- if (update_multipath_strings(pp->mpp, vecs->pathvec, 1)) {
+ if (update_multipath_strings(pp->mpp, vecs->pathvec, 1) != DMP_OK) {
condlog(1, "%s: Could not synchronize with kernel state",
pp->dev);
pp->dmstate = PSTATE_UNDEF;
--
2.17.2

View File

@ -0,0 +1,116 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:01 -0500
Subject: [PATCH] multipathd: fix check_path errors with removed map
If a multipath device is removed during, or immediately before the call
to check_path(), multipathd can behave incorrectly. A missing multpath
device will cause update_multipath_strings() to fail, setting
pp->dmstate to PSTATE_UNDEF. If the path is up, this state will cause
reinstate_path() to be called, which will also fail. This will trigger
a reload, restoring the recently removed device.
If update_multipath_strings() fails because there is no multipath
device, check_path should just quit, since the remove dmevent and uevent
are likely already queued up. Also, I don't see any reason to reload the
multipath device if reinstate fails. This code was added by
fac68d7a99ef17d496079538a5c6836acd7911ab, which clamined that reinstate
could fail if the path was disabled. Looking through the current kernel
code, I can't see any reason why a reinstate would fail, where a reload
would help. If the path was missing from the multipath device,
update_multipath_strings() would already catch that, and quit
check_path() early, which make more sense to me than reloading does.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 44 +++++++++++++++++++-------------------------
1 file changed, 19 insertions(+), 25 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index ab141fed..daf19a4e 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1615,22 +1615,18 @@ fail_path (struct path * pp, int del_active)
/*
* caller must have locked the path list before calling that function
*/
-static int
+static void
reinstate_path (struct path * pp)
{
- int ret = 0;
-
if (!pp->mpp)
- return 0;
+ return;
- if (dm_reinstate_path(pp->mpp->alias, pp->dev_t)) {
+ if (dm_reinstate_path(pp->mpp->alias, pp->dev_t))
condlog(0, "%s: reinstate failed", pp->dev_t);
- ret = 1;
- } else {
+ else {
condlog(2, "%s: reinstated", pp->dev_t);
update_queue_mode_add_path(pp->mpp);
}
- return ret;
}
static void
@@ -2091,9 +2087,16 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
/*
* Synchronize with kernel state
*/
- if (update_multipath_strings(pp->mpp, vecs->pathvec, 1) != DMP_OK) {
- condlog(1, "%s: Could not synchronize with kernel state",
- pp->dev);
+ ret = update_multipath_strings(pp->mpp, vecs->pathvec, 1);
+ if (ret != DMP_OK) {
+ if (ret == DMP_NOT_FOUND) {
+ /* multipath device missing. Likely removed */
+ condlog(1, "%s: multipath device '%s' not found",
+ pp->dev, pp->mpp->alias);
+ return 0;
+ } else
+ condlog(1, "%s: Couldn't synchronize with kernel state",
+ pp->dev);
pp->dmstate = PSTATE_UNDEF;
}
/* if update_multipath_strings orphaned the path, quit early */
@@ -2183,12 +2186,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
/*
* reinstate this path
*/
- if (!disable_reinstate && reinstate_path(pp)) {
- condlog(3, "%s: reload map", pp->dev);
- ev_add_path(pp, vecs, 1);
- pp->tick = 1;
- return 0;
- }
+ if (!disable_reinstate)
+ reinstate_path(pp);
new_path_up = 1;
if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
@@ -2204,15 +2203,10 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
else if (newstate == PATH_UP || newstate == PATH_GHOST) {
if ((pp->dmstate == PSTATE_FAILED ||
pp->dmstate == PSTATE_UNDEF) &&
- !disable_reinstate) {
+ !disable_reinstate)
/* Clear IO errors */
- if (reinstate_path(pp)) {
- condlog(3, "%s: reload map", pp->dev);
- ev_add_path(pp, vecs, 1);
- pp->tick = 1;
- return 0;
- }
- } else {
+ reinstate_path(pp);
+ else {
LOG_MSG(4, verbosity, pp);
if (pp->checkint != max_checkint) {
/*
--
2.17.2

View File

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:02 -0500
Subject: [PATCH] libmultipath: make dm_flush_maps only return 0 on success
dm_flush_maps() returned both 0 and 1 on error, depending on which part
of the function it was in, but the caller was always treating 0 as a
success. Make dm_flush_maps() always return 1 on error and 0 on success.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 24cc616a..4c86b6d4 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1007,13 +1007,13 @@ dm_flush_map_nopaths(const char * mapname, int deferred_remove)
int dm_flush_maps (int retries)
{
- int r = 0;
+ int r = 1;
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
if (!(dmt = libmp_dm_task_create (DM_DEVICE_LIST)))
- return 0;
+ return r;
dm_task_no_open_count(dmt);
@@ -1026,6 +1026,7 @@ int dm_flush_maps (int retries)
if (!names->dev)
goto out;
+ r = 0;
do {
r |= dm_suspend_and_flush_map(names->name, retries);
next = names->next;
--
2.17.2

View File

@ -0,0 +1,161 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:03 -0500
Subject: [PATCH] multipathd: add "del maps" multipathd command
This will flush all multipath devices.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 7 +++++--
libmultipath/devmapper.h | 2 +-
multipath/main.c | 2 +-
multipathd/cli.c | 1 +
multipathd/cli_handlers.c | 19 +++++++++++++++++++
multipathd/cli_handlers.h | 1 +
multipathd/main.c | 3 ++-
multipathd/main.h | 1 +
8 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 4c86b6d4..f597ff8b 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1005,7 +1005,7 @@ dm_flush_map_nopaths(const char * mapname, int deferred_remove)
#endif
-int dm_flush_maps (int retries)
+int dm_flush_maps (int need_suspend, int retries)
{
int r = 1;
struct dm_task *dmt;
@@ -1028,7 +1028,10 @@ int dm_flush_maps (int retries)
r = 0;
do {
- r |= dm_suspend_and_flush_map(names->name, retries);
+ if (need_suspend)
+ r |= dm_suspend_and_flush_map(names->name, retries);
+ else
+ r |= dm_flush_map(names->name);
next = names->next;
names = (void *) names + next;
} while (next);
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index b2108638..6dd178c8 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -57,7 +57,7 @@ int dm_flush_map_nopaths(const char * mapname, int deferred_remove);
#define dm_suspend_and_flush_map(mapname, retries) \
_dm_flush_map(mapname, 1, 0, 1, retries)
int dm_cancel_deferred_remove(struct multipath *mpp);
-int dm_flush_maps (int retries);
+int dm_flush_maps (int need_suspend, int retries);
int dm_fail_path(const char * mapname, char * path);
int dm_reinstate_path(const char * mapname, char * path);
int dm_queue_if_no_path(const char *mapname, int enable);
diff --git a/multipath/main.c b/multipath/main.c
index c4740fab..d89f0a91 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -1096,7 +1096,7 @@ main (int argc, char *argv[])
goto out;
}
else if (conf->remove == FLUSH_ALL) {
- r = dm_flush_maps(retries) ? RTVL_FAIL : RTVL_OK;
+ r = dm_flush_maps(1, retries) ? RTVL_FAIL : RTVL_OK;
goto out;
}
while ((r = configure(conf, cmd, dev_type, dev)) == RTVL_RETRY)
diff --git a/multipathd/cli.c b/multipathd/cli.c
index 800c0fbe..bdc9fb10 100644
--- a/multipathd/cli.c
+++ b/multipathd/cli.c
@@ -568,6 +568,7 @@ cli_init (void) {
add_handler(DEL+PATH, NULL);
add_handler(ADD+MAP, NULL);
add_handler(DEL+MAP, NULL);
+ add_handler(DEL+MAPS, NULL);
add_handler(SWITCH+MAP+GROUP, NULL);
add_handler(RECONFIGURE, NULL);
add_handler(SUSPEND+MAP, NULL);
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 31c3d9fd..782bb003 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -852,6 +852,25 @@ cli_del_map (void * v, char ** reply, int * len, void * data)
return rc;
}
+int
+cli_del_maps (void *v, char **reply, int *len, void *data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+ struct multipath *mpp;
+ int i, ret = 0;
+
+ condlog(2, "remove maps (operator)");
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ if (flush_map(mpp, vecs, 0))
+ ret++;
+ else
+ i--;
+ }
+ /* flush any multipath maps that aren't currently known by multipathd */
+ ret |= dm_flush_maps(0, 0);
+ return ret;
+}
+
int
cli_reload(void *v, char **reply, int *len, void *data)
{
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
index 0f451064..6f57b429 100644
--- a/multipathd/cli_handlers.h
+++ b/multipathd/cli_handlers.h
@@ -26,6 +26,7 @@ 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);
int cli_del_map (void * v, char ** reply, int * len, void * data);
+int cli_del_maps (void * v, char ** reply, int * len, void * data);
int cli_switch_group(void * v, char ** reply, int * len, void * data);
int cli_reconfigure(void * v, char ** reply, int * len, void * data);
int cli_resize(void * v, char ** reply, int * len, void * data);
diff --git a/multipathd/main.c b/multipathd/main.c
index daf19a4e..f014d2a1 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -635,7 +635,7 @@ sync_maps_state(vector mpvec)
sync_map_state(mpp);
}
-static int
+int
flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
{
int r;
@@ -1555,6 +1555,7 @@ uxlsnrloop (void * ap)
set_handler_callback(DEL+PATH, cli_del_path);
set_handler_callback(ADD+MAP, cli_add_map);
set_handler_callback(DEL+MAP, cli_del_map);
+ set_handler_callback(DEL+MAPS, cli_del_maps);
set_handler_callback(SWITCH+MAP+GROUP, cli_switch_group);
set_unlocked_handler_callback(RECONFIGURE, cli_reconfigure);
set_handler_callback(SUSPEND+MAP, cli_suspend);
diff --git a/multipathd/main.h b/multipathd/main.h
index 7bb8463f..5dff17e5 100644
--- a/multipathd/main.h
+++ b/multipathd/main.h
@@ -28,6 +28,7 @@ int ev_add_path (struct path *, struct vectors *, int);
int ev_remove_path (struct path *, struct vectors *, int);
int ev_add_map (char *, const char *, struct vectors *);
int ev_remove_map (char *, char *, int, struct vectors *);
+int flush_map(struct multipath *, struct vectors *, int);
int set_config_state(enum daemon_status);
void * mpath_alloc_prin_response(int prin_sa);
int prin_do_scsi_ioctl(char *, int rq_servact, struct prin_resp * resp,
--
2.17.2

View File

@ -0,0 +1,104 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:04 -0500
Subject: [PATCH] multipath: make flushing maps work like other commands
The config structure doesn't need a special variable just for removes.
Multipath can just use the cmd variable, like it does for the other
commands.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 3 ++-
libmultipath/configure.h | 3 ---
multipath/main.c | 20 ++++++++++----------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index ceecff2d..55569360 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -38,6 +38,8 @@ enum mpath_cmds {
CMD_ADD_WWID,
CMD_USABLE_PATHS,
CMD_DUMP_CONFIG,
+ CMD_FLUSH_ONE,
+ CMD_FLUSH_ALL,
};
enum force_reload_types {
@@ -142,7 +144,6 @@ struct config {
unsigned int max_checkint;
bool use_watchdog;
int pgfailback;
- int remove;
int rr_weight;
int no_path_retry;
int user_friendly_names;
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index d7509000..0e33bf40 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -45,9 +45,6 @@ enum {
CP_RETRY,
};
-#define FLUSH_ONE 1
-#define FLUSH_ALL 2
-
struct vectors;
int setup_map (struct multipath * mpp, char * params, int params_size,
diff --git a/multipath/main.c b/multipath/main.c
index d89f0a91..101fd656 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -909,10 +909,10 @@ main (int argc, char *argv[])
cmd = CMD_DRY_RUN;
break;
case 'f':
- conf->remove = FLUSH_ONE;
+ cmd = CMD_FLUSH_ONE;
break;
case 'F':
- conf->remove = FLUSH_ALL;
+ cmd = CMD_FLUSH_ALL;
break;
case 'l':
if (optarg && !strncmp(optarg, "l", 1))
@@ -1053,6 +1053,10 @@ main (int argc, char *argv[])
condlog(0, "the -w option requires a device");
goto out;
}
+ if (cmd == CMD_FLUSH_ONE && dev_type != DEV_DEVMAP) {
+ condlog(0, "the -f option requires a map name to remove");
+ goto out;
+ }
switch(delegate_to_multipathd(cmd, dev, dev_type, conf)) {
case DELEGATE_OK:
@@ -1086,16 +1090,12 @@ main (int argc, char *argv[])
}
if (retries < 0)
retries = conf->remove_retries;
- if (conf->remove == FLUSH_ONE) {
- if (dev_type == DEV_DEVMAP) {
- r = dm_suspend_and_flush_map(dev, retries) ?
- RTVL_FAIL : RTVL_OK;
- } else
- condlog(0, "must provide a map name to remove");
-
+ if (cmd == CMD_FLUSH_ONE) {
+ r = dm_suspend_and_flush_map(dev, retries) ?
+ RTVL_FAIL : RTVL_OK;
goto out;
}
- else if (conf->remove == FLUSH_ALL) {
+ else if (cmd == CMD_FLUSH_ALL) {
r = dm_flush_maps(1, retries) ? RTVL_FAIL : RTVL_OK;
goto out;
}
--
2.17.2

View File

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:05 -0500
Subject: [PATCH] multipath: delegate flushing maps to multipathd
Since there can be problems with removing maps outside of multipathd,
multipath should attempt to delegate this command to multipathd.
However, multipathd doesn't attempt to suspend the device, in order
to avoid potential hangs. If delegating to multipathd fails, multipath
should try the remove itself.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 14 ++++++++++++++
multipath/multipath.8 | 4 ++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/multipath/main.c b/multipath/main.c
index 101fd656..6a24e483 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -820,6 +820,20 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
p += snprintf(p, n, "reconfigure");
}
+ else if (cmd == CMD_FLUSH_ONE && dev && dev_type == DEV_DEVMAP) {
+ p += snprintf(p, n, "del map %s", dev);
+ /* multipathd doesn't try as hard, to avoid potentially
+ * hanging. If it fails, retry with the regular multipath
+ * command */
+ r = NOT_DELEGATED;
+ }
+ else if (cmd == CMD_FLUSH_ALL) {
+ p += snprintf(p, n, "del maps");
+ /* multipathd doesn't try as hard, to avoid potentially
+ * hanging. If it fails, retry with the regular multipath
+ * command */
+ r = NOT_DELEGATED;
+ }
/* Add other translations here */
if (strlen(command) == 0)
diff --git a/multipath/multipath.8 b/multipath/multipath.8
index 6fb8645a..5b29a5d9 100644
--- a/multipath/multipath.8
+++ b/multipath/multipath.8
@@ -125,11 +125,11 @@ the system.
Other operation modes are chosen by using one of the following command line switches:
.TP
.B \-f
-Flush (remove) a multipath device map specified as parameter, if unused.
+Flush (remove) a multipath device map specified as parameter, if unused. This operation is delegated to the multipathd daemon if it's running.
.
.TP
.B \-F
-Flush (remove) all unused multipath device maps.
+Flush (remove) all unused multipath device maps. This operation is delegated to the multipathd daemon if it's running.
.
.TP
.B \-l
--
2.17.2

View File

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 2 Jul 2020 19:07:06 -0500
Subject: [PATCH] multipath: add option to skip multipathd delegation
Add the -D option to allow users to skip delegating commands to
multipathd.
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 1 +
multipath/main.c | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 55569360..92c61a0d 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -190,6 +190,7 @@ struct config {
int ghost_delay;
int find_multipaths_timeout;
int marginal_pathgroups;
+ int skip_delegate;
unsigned int version[3];
unsigned int sequence_nr;
diff --git a/multipath/main.c b/multipath/main.c
index 6a24e483..4c43314e 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -817,6 +817,9 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
*p = '\0';
n = sizeof(command);
+ if (conf->skip_delegate)
+ return NOT_DELEGATED;
+
if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
p += snprintf(p, n, "reconfigure");
}
@@ -890,7 +893,7 @@ main (int argc, char *argv[])
multipath_conf = conf;
conf->retrigger_tries = 0;
conf->force_sync = 1;
- while ((arg = getopt(argc, argv, ":adcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -922,6 +925,9 @@ main (int argc, char *argv[])
if (cmd == CMD_CREATE)
cmd = CMD_DRY_RUN;
break;
+ case 'D':
+ conf->skip_delegate = 1;
+ break;
case 'f':
cmd = CMD_FLUSH_ONE;
break;
--
2.17.2

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Steve Schremmer <steve.schremmer@netapp.com>
Date: Mon, 6 Jul 2020 20:22:35 +0000
Subject: [PATCH] libmultipath: add device to hwtable.c
Add FUJITSU ETERNUS_AHB defaults.
Signed-off-by: Steve Schremmer <steve.schremmer@netapp.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/hwtable.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index d1fcfdb3..d680bdfc 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -428,6 +428,22 @@ static struct hwentry default_hw[] = {
.pgpolicy = MULTIBUS,
.no_path_retry = 10,
},
+ {
+ /*
+ * ETERNUS AB/HB
+ * Maintainer: NetApp RDAC team <ng-eseries-upstream-maintainers@netapp.com>
+ */
+ .vendor = "FUJITSU",
+ .product = "ETERNUS_AHB",
+ .bl_product = "Universal Xport",
+ .pgpolicy = GROUP_BY_PRIO,
+ .checker_name = RDAC,
+ .features = "2 pg_init_retries 50",
+ .hwhandler = "1 rdac",
+ .prio_name = PRIO_RDAC,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 30,
+ },
/*
* Hitachi Vantara
*
--
2.17.2

View File

@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
Date: Mon, 13 Jul 2020 13:07:40 +0200
Subject: [PATCH] master - libmultipath: fix use after free when iscsi logs in
When two iscsi ips log in and out alternately and the following scripts run
at the same time,
#!/bin/bash
interval=5
while true
do
iscsiadm -m node -p 9.41.147.171 &> /dev/null
iscsiadm -m node -p 9.41.148.172 &> /dev/null
iscsiadm -m session &> /dev/null
rescan-scsi-bus.sh &> /dev/null
multipath -v2 &> /dev/null
multipath -ll &> /dev/null
sleep $interval
done
multipathd will have a segfault after about 30 mins.
The reason is that mpp->hwe is accessed after hwe is already freed. In
extract_hwe_from_path func, mpp->hwe is set to pp->hwe, so they points to the
same hwe. For some reasons, pp->mpp will be set to NULL in orphan_path func.
Then, pp and hwe will be freed with (pp->mpp == NULL) in free_path func
called by ev_remove_path func. However, mpp->hwe is not set to NULL while hwe
is already freed. So, when iscsi device logs in and new path is added to mpp,
mpp->hwe will be accessed in select_pgfailback func. Finally, use-after-free
problem occurs.
The procedure details given as follows,
1.wait_dmevents thread
wait_dmevents
->dmevent_loop
->update_multipath
->__setup_multipath
->update_multipath_strings
-> sync_paths
->orphan_path
2.uevqloop thread (iscsi log out, remove path)
uevqloop
->uevent_dispatch
->service_uevq
->uev_remove_path
->ev_remove_path //pp->mpp is NULL
->free_path(pp)
//pp->hew are freed but mpp->hwe is not set to NULL
3.ev_remove_path (iscsi log in, add path)
uevqloop
->uevent_dispatch
->service_uevq
->ev_add_path
->select_pgfailback //mpp->hwe is accessed
Here, we will set mpp->hwe to NULL before setting pp->map to NULL in orphan_path
func.
Signed-off-by: Tianxiong Lu <lutianxiong@huawei.com>
Signed-off-by: lixiaokeng <lixiaokeng@huawei.com>
Signed-off-by: Zhiqiang Liu <liuzhiqiang26@huawei.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 8137ea21..430eaad7 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -93,6 +93,8 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
void orphan_path(struct path *pp, const char *reason)
{
condlog(3, "%s: orphan path, %s", pp->dev, reason);
+ if (pp->mpp && pp->mpp->hwe == pp->hwe)
+ pp->mpp->hwe = NULL;
pp->mpp = NULL;
pp->dmstate = PSTATE_UNDEF;
pp->uid_attribute = NULL;
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 13 Jul 2020 13:07:41 +0200
Subject: [PATCH] libmultipath: warn if freeing path that holds mpp->hwe
This just adds an error message to the previous patch.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 430eaad7..cde4dbe6 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -93,8 +93,11 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
void orphan_path(struct path *pp, const char *reason)
{
condlog(3, "%s: orphan path, %s", pp->dev, reason);
- if (pp->mpp && pp->mpp->hwe == pp->hwe)
+ if (pp->mpp && pp->hwe && pp->mpp->hwe == pp->hwe) {
+ condlog(0, "BUG: orphaning path %s that holds hwe of %s",
+ pp->dev, pp->mpp->alias);
pp->mpp->hwe = NULL;
+ }
pp->mpp = NULL;
pp->dmstate = PSTATE_UNDEF;
pp->uid_attribute = NULL;
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 13 Jul 2020 13:07:42 +0200
Subject: [PATCH] libmultipath: warn about NULL value of mpp->hwe
mpp->hwe is only accessed in propsel.c. It may become unset if
all paths of the mpp have been deleted. Access to mpp->hwe in this
case should be avoided.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/propsel.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index d362beb4..68228272 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -65,7 +65,9 @@ do { \
__do_set_from_vec(struct hwentry, var, (src)->hwe, dest)
#define do_set_from_hwe(var, src, dest, msg) \
- if (__do_set_from_hwe(var, src, dest)) { \
+ if (!src->hwe) { \
+ condlog(0, "BUG: do_set_from_hwe called with hwe == NULL"); \
+ } else if (__do_set_from_hwe(var, src, dest)) { \
origin = msg; \
goto out; \
}
--
2.17.2

View File

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Mon, 13 Jul 2020 13:07:43 +0200
Subject: [PATCH] libmultipath: fix mpp->hwe handling in sync_paths()
This is anologous to
1f96269 ("multipathd: fix mpp->hwe handling on path removal")
f6839eb ("multipathd: fix mpp->hwe handling when paths are freed")
When paths are removed from a map, we need to make sure that
mpp->hwe doesn't become stale.
Reported-by: Lixiaokeng <lixiaokeng@huawei.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index cde4dbe6..ede14297 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -260,6 +260,8 @@ void sync_paths(struct multipath *mpp, vector pathvec)
}
if (!found) {
condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
+ if (mpp->hwe == pp->hwe)
+ mpp->hwe = NULL;
vector_del_slot(mpp->paths, i--);
orphan_path(pp, "path removed externally");
}
@@ -267,6 +269,8 @@ void sync_paths(struct multipath *mpp, vector pathvec)
update_mpp_paths(mpp, pathvec);
vector_foreach_slot (mpp->paths, pp, i)
pp->mpp = mpp;
+ if (mpp->hwe == NULL)
+ extract_hwe_from_path(mpp);
}
int
--
2.17.2

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 6 Jul 2020 13:21:12 -0500
Subject: [PATCH] Makefile.inc: trim extra information from systemd version
Some systemd versions print extra information in the
"pkg-config --modversion" output, which confuses make. Trim this
off.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.inc b/Makefile.inc
index e7256e3a..8ea3352d 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -37,7 +37,7 @@ endif
ifndef SYSTEMD
ifeq ($(shell pkg-config --modversion libsystemd >/dev/null 2>&1 && echo 1), 1)
- SYSTEMD = $(shell pkg-config --modversion libsystemd)
+ SYSTEMD = $(shell pkg-config --modversion libsystemd | awk '{print $$1}')
else
ifeq ($(shell systemctl --version >/dev/null 2>&1 && echo 1), 1)
SYSTEMD = $(shell systemctl --version 2> /dev/null | \
--
2.17.2

View File

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 6 Jul 2020 17:28:46 -0500
Subject: [PATCH] kpartx: fix -Wsign-compare error
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
kpartx/kpartx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index c24ad6d9..653ce0c8 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -738,7 +738,7 @@ struct block {
/* blknr is always in 512 byte blocks */
char *
getblock (int fd, unsigned int blknr) {
- unsigned int secsz = get_sector_size(fd);
+ int secsz = get_sector_size(fd);
unsigned int blks_per_sec = secsz / 512;
unsigned int secnr = blknr / blks_per_sec;
unsigned int blk_off = (blknr % blks_per_sec) * 512;
--
2.17.2

View File

@ -0,0 +1,129 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 21 Jul 2020 01:12:05 -0500
Subject: [PATCH] libmultipath: remove code duplication in path counting
pathcountgr() is never used except by pathcount(), and neither is the
special case for PATH_WILD. Simplify this and make one function that is
used by both pathcount() and count_active_paths(). This will be used
again in a future patch.
Also use count_active_paths() in mpath_persist.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_persist.c | 4 +--
libmultipath/structs.c | 47 +++++++++++++--------------------
libmultipath/structs.h | 1 -
3 files changed, 21 insertions(+), 31 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 3da7a6cf..a132f4e9 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -436,7 +436,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
all_tg_pt = (mpp->all_tg_pt == ALL_TG_PT_ON ||
paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK);
- active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
+ active_pathcount = count_active_paths(mpp);
if (active_pathcount == 0) {
condlog (0, "%s: no path available", mpp->wwid);
@@ -648,7 +648,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
if (!mpp)
return MPATH_PR_DMMP_ERROR;
- active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST);
+ active_pathcount = count_active_paths(mpp);
struct threadinfo thread[active_pathcount];
memset(thread, 0, sizeof(thread));
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 2dd378c4..3eac3d61 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -455,49 +455,40 @@ find_path_by_devt (const struct _vector *pathvec, const char * dev_t)
return NULL;
}
-int pathcountgr(const struct pathgroup *pgp, int state)
+static int do_pathcount(const struct multipath *mpp, const int *states,
+ unsigned int nr_states)
{
+ struct pathgroup *pgp;
struct path *pp;
int count = 0;
- int i;
+ unsigned int i, j, k;
- vector_foreach_slot (pgp->paths, pp, i)
- if ((pp->state == state) || (state == PATH_WILD))
- count++;
+ if (!mpp->pg || !nr_states)
+ return count;
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ for (k = 0; k < nr_states; k++) {
+ if (pp->state == states[k]) {
+ count++;
+ break;
+ }
+ }
+ }
+ }
return count;
}
int pathcount(const struct multipath *mpp, int state)
{
- struct pathgroup *pgp;
- int count = 0;
- int i;
-
- if (mpp->pg) {
- vector_foreach_slot (mpp->pg, pgp, i)
- count += pathcountgr(pgp, state);
- }
- return count;
+ return do_pathcount(mpp, &state, 1);
}
int count_active_paths(const struct multipath *mpp)
{
- struct pathgroup *pgp;
- struct path *pp;
- int count = 0;
- int i, j;
-
- if (!mpp->pg)
- return 0;
+ int states[] = {PATH_UP, PATH_GHOST};
- vector_foreach_slot (mpp->pg, pgp, i) {
- vector_foreach_slot (pgp->paths, pp, j) {
- if (pp->state == PATH_UP || pp->state == PATH_GHOST)
- count++;
- }
- }
- return count;
+ return do_pathcount(mpp, states, 2);
}
int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index d69bc2e9..0c03e711 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -446,7 +446,6 @@ struct path * find_path_by_devt (const struct _vector *pathvec, const char *devt
struct path * find_path_by_dev (const struct _vector *pathvec, const char *dev);
struct path * first_path (const struct multipath *mpp);
-int pathcountgr (const struct pathgroup *, int);
int pathcount (const struct multipath *, int);
int count_active_paths(const struct multipath *);
int pathcmp (const struct pathgroup *, const struct pathgroup *);
--
2.17.2

View File

@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 21 Jul 2020 01:19:30 -0500
Subject: [PATCH] libmultipath: count pending paths as active on loads
When multipath loads a table, it signals to udev if there are no active
paths. Multipath wasn't counting pending paths as active. This meant
that if all the paths were pending, udev would treat the device as not
ready, and not run kpartx on it. Even if the pending paths later
because active and were reinstated, the kernel would not send a new
uevent, because from its point of view, they were always up.
The alternative would be to continue to treat them as failed in the udev
rules, but then also tell the kernel that they were down, so that it
would trigger a uevent when they were reinstated. However, this could
lead to newly created multipath devices failing IO, simply because the
path checkers hadn't returned yet. Having udev assume that the the
device is up, like the kernel does, seems like the safer option.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 3 ++-
libmultipath/structs.c | 7 +++++++
libmultipath/structs.h | 1 +
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index f597ff8b..126cd728 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -417,7 +417,8 @@ 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) |
- ((count_active_paths(mpp) == 0 || mpp->ghost_delay_tick > 0) ?
+ ((count_active_pending_paths(mpp) == 0 ||
+ mpp->ghost_delay_tick > 0) ?
MPATH_UDEV_NO_PATHS_FLAG : 0) |
(reload && !mpp->force_udev_reload ?
MPATH_UDEV_RELOAD_FLAG : 0);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 3eac3d61..0d1f969d 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -491,6 +491,13 @@ int count_active_paths(const struct multipath *mpp)
return do_pathcount(mpp, states, 2);
}
+int count_active_pending_paths(const struct multipath *mpp)
+{
+ int states[] = {PATH_UP, PATH_GHOST, PATH_PENDING};
+
+ return do_pathcount(mpp, states, 3);
+}
+
int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
{
int i, j;
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 0c03e711..917e4083 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -448,6 +448,7 @@ struct path * first_path (const struct multipath *mpp);
int pathcount (const struct multipath *, int);
int count_active_paths(const struct multipath *);
+int count_active_pending_paths(const struct multipath *);
int pathcmp (const struct pathgroup *, const struct pathgroup *);
int add_feature (char **, const char *);
int remove_feature (char **, const char *);
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 21 Jul 2020 01:28:22 -0500
Subject: [PATCH] libmultipath: deal with flushing no maps
dm_flush_maps() was failing if there were no device-mapper devices at
all, instead of returning success, since there is nothing to do.
Fixes: "libmultipath: make dm_flush_maps only return 0 on success"
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/devmapper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 126cd728..b8199cb5 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1024,10 +1024,10 @@ int dm_flush_maps (int need_suspend, int retries)
if (!(names = dm_task_get_names (dmt)))
goto out;
+ r = 0;
if (!names->dev)
goto out;
- r = 0;
do {
if (need_suspend)
r |= dm_suspend_and_flush_map(names->name, retries);
--
2.17.2

View File

@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 21 Jul 2020 01:37:18 -0500
Subject: [PATCH] multipath: deal with delegation failures correctly
delegate_to_multipathd() was returning success, even if the multipathd
command failed. Also, if the command was set to fail with NOT_DELEGATED,
it shouldn't print any errors, since multipath will try to issue to
command itself.
Fixes: "multipath: delegate flushing maps to multipathd"
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/multipath/main.c b/multipath/main.c
index 4c43314e..3da692dc 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -861,9 +861,12 @@ int delegate_to_multipathd(enum mpath_cmds cmd,
goto out;
}
- if (reply != NULL && *reply != '\0' && strcmp(reply, "ok\n"))
- printf("%s", reply);
- r = DELEGATE_OK;
+ if (reply != NULL && *reply != '\0') {
+ if (strcmp(reply, "fail\n"))
+ r = DELEGATE_OK;
+ if (r != NOT_DELEGATED && strcmp(reply, "ok\n"))
+ printf("%s", reply);
+ }
out:
FREE(reply);
--
2.17.2

View File

@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 13 Apr 2017 07:22:23 -0500
Subject: [PATCH] RH: fixup udev rules for redhat
The multipath rules need to run after scsi_id is run. This means moving
them after 60-persistent-storage.rules for redhat. Redhat also uses a
different naming scheme for partitions than SuSE.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
kpartx/kpartx.rules | 2 +-
multipath/Makefile | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 8ea3352d..873fb62f 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -53,7 +53,7 @@ endif
prefix =
exec_prefix = $(prefix)
usr_prefix = $(prefix)
-bindir = $(exec_prefix)/sbin
+bindir = $(exec_prefix)/usr/sbin
libudevdir = $(prefix)/$(SYSTEMDPATH)/udev
udevrulesdir = $(libudevdir)/rules.d
multipathdir = $(TOPDIR)/libmultipath
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
index d7527d7d..0e0d70d5 100644
--- a/kpartx/kpartx.rules
+++ b/kpartx/kpartx.rules
@@ -36,6 +36,6 @@ LABEL="mpath_kpartx_end"
GOTO="kpartx_end"
LABEL="run_kpartx"
-RUN+="/sbin/kpartx -un -p -part /dev/$name"
+RUN+="/sbin/kpartx -un /dev/$name"
LABEL="kpartx_end"
diff --git a/multipath/Makefile b/multipath/Makefile
index 0828a8f7..b9bbb3cf 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -24,7 +24,7 @@ install:
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
- $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
@@ -33,7 +33,7 @@ install:
uninstall:
$(RM) $(DESTDIR)$(bindir)/$(EXEC)
$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
- $(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
+ $(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
$(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
$(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
--
2.17.2

View File

@ -0,0 +1,105 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 2 Jul 2014 12:49:53 -0500
Subject: [PATCH] RH: Remove the property blacklist exception builtin
Multipath set the default property blacklist exceptions to
(ID_SCSI_VPD|ID_WWN). This has the effect of blacklisting some internal
devices. These devices may never have multiple paths, but it is nice
to be able to set multipath up on them all the same. This patch simply
removes the default, and makes it so that if no property
blacklist_exception is given, then devices aren't failed for not matching
it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/blacklist.c | 9 ++-------
multipath/multipath.conf.5 | 11 ++++++-----
tests/blacklist.c | 6 ++----
3 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index db58ccca..0c58aa32 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -187,12 +187,6 @@ setup_default_blist (struct config * conf)
if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
return 1;
- str = STRDUP("(SCSI_IDENT_|ID_WWN)");
- if (!str)
- return 1;
- if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
- return 1;
-
vector_foreach_slot (conf->hwtable, hwe, i) {
if (hwe->bl_product) {
if (find_blacklist_device(conf->blist_device,
@@ -394,7 +388,8 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl,
*uid_attribute != '\0';
bool uid_attr_seen = false;
- r = MATCH_PROPERTY_BLIST_MISSING;
+ if (VECTOR_SIZE(conf->elist_property))
+ r = MATCH_PROPERTY_BLIST_MISSING;
udev_list_entry_foreach(list_entry,
udev_device_get_properties_list_entry(udev)) {
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 5adaced6..42a192f6 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1296,9 +1296,14 @@ keywords. Both are regular expressions. For a full description of these keywords
Regular expression for an udev property. All
devices that have matching udev properties will be excluded/included.
The handling of the \fIproperty\fR keyword is special,
-because devices \fBmust\fR have at least one whitelisted udev property;
+because if a property blacklist_exception is set, devices \fBmust\fR have at
+least one whitelisted udev property;
otherwise they're treated as blacklisted, and the message
"\fIblacklisted, udev property missing\fR" is displayed in the logs.
+For example, setting the property blacklist_exception to
+\fB(SCSI_IDENT_|ID_WWN)\fR, will cause well-behaved SCSI devices and devices
+that provide a WWN (World Wide Number) to be included, and all others to be
+excluded. This works to exclude most non-multipathable devices.
.
.RS
.PP
@@ -1309,10 +1314,6 @@ Blacklisting by missing properties is only applied to devices which do have the
property specified by \fIuid_attribute\fR (e.g. \fIID_SERIAL\fR)
set. Previously, it was applied to every device, possibly causing devices to be
blacklisted because of temporary I/O error conditions.
-.PP
-The default \fIblacklist exception\fR is: \fB(SCSI_IDENT_|ID_WWN)\fR, causing
-well-behaved SCSI devices and devices that provide a WWN (World Wide Number)
-to be included, and all others to be excluded.
.RE
.TP
.B protocol
diff --git a/tests/blacklist.c b/tests/blacklist.c
index d5c40898..d20e97af 100644
--- a/tests/blacklist.c
+++ b/tests/blacklist.c
@@ -380,7 +380,7 @@ static void test_property_missing(void **state)
conf.blist_property = blist_property_wwn;
expect_condlog(3, "sdb: blacklisted, udev property missing\n");
assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"),
- MATCH_PROPERTY_BLIST_MISSING);
+ MATCH_NOTHING);
assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"),
MATCH_NOTHING);
assert_int_equal(filter_property(&conf, &udev, 3, ""),
@@ -472,9 +472,7 @@ static void test_filter_path_missing1(void **state)
conf.blist_device = blist_device_foo_bar;
conf.blist_protocol = blist_protocol_fcp;
conf.blist_wwid = blist_wwid_xyzzy;
- expect_condlog(3, "sdb: blacklisted, udev property missing\n");
- assert_int_equal(filter_path(&conf, &miss1_pp),
- MATCH_PROPERTY_BLIST_MISSING);
+ assert_int_equal(filter_path(&conf, &miss1_pp), MATCH_NOTHING);
}
/* This one matches the property whitelist, to test the other missing
--
2.17.2

View File

@ -0,0 +1,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 15 Oct 2014 10:39:30 -0500
Subject: [PATCH] RH: don't start without a config file
If /etc/multipath.conf doesn't exist, don't start multipathd and blacklist
all devices when running multipath. A completely blank configuration file
is almost never what users want. Also, people may have the multipath
packages installed but don't want to use them. This patch provides a
simple way to disable multipath. Simply removing or renaming
/etc/multipath.conf will keep multipath from doing anything.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 15 +++++++++++++++
libmultipath/config.h | 1 +
multipath/multipath.rules | 1 +
multipathd/multipathd.8 | 2 ++
multipathd/multipathd.service | 1 +
5 files changed, 20 insertions(+)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 658bec8b..1c02e230 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -26,6 +26,7 @@
#include "devmapper.h"
#include "mpath_cmd.h"
#include "propsel.h"
+#include "version.h"
static int
hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2)
@@ -778,6 +779,20 @@ load_config (char * file)
goto out;
}
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
+ } else {
+ condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
+ 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;
+ }
}
conf->processed_main_config = 1;
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 92c61a0d..160867cd 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -9,6 +9,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/multipath/multipath.rules b/multipath/multipath.rules
index 9df11a95..0486bf70 100644
--- a/multipath/multipath.rules
+++ b/multipath/multipath.rules
@@ -9,6 +9,7 @@ IMPORT{cmdline}="nompath"
ENV{nompath}=="?*", GOTO="end_mpath"
IMPORT{cmdline}="multipath"
ENV{multipath}=="off", GOTO="end_mpath"
+TEST!="/etc/multipath.conf", GOTO="end_mpath"
ENV{DEVTYPE}!="partition", GOTO="test_dev"
IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH"
diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8
index 048a838d..8bd47a80 100644
--- a/multipathd/multipathd.8
+++ b/multipathd/multipathd.8
@@ -39,6 +39,8 @@ map regains its maximum performance and redundancy.
This daemon executes the external \fBmultipath\fR tool when events occur.
In turn, the multipath tool signals the multipathd daemon when it is done with
devmap reconfiguration, so that it can refresh its failed path list.
+
+In this Linux distribution, multipathd does not run unless a /etc/multipath.conf file exists.
.
.
.\" ----------------------------------------------------------------------------
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
index ba24983e..17434cef 100644
--- a/multipathd/multipathd.service
+++ b/multipathd/multipathd.service
@@ -4,6 +4,7 @@ Wants=systemd-udev-trigger.service systemd-udev-settle.service
Before=iscsi.service iscsid.service lvm2-activation-early.service
Before=local-fs-pre.target blk-availability.service
After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service
+ConditionPathExists=/etc/multipath.conf
DefaultDependencies=no
Conflicts=shutdown.target
ConditionKernelCommandLine=!nompath
--
2.17.2

View File

@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 19 Apr 2017 06:10:01 -0500
Subject: [PATCH] RH: use rpm optflags if present
Use the passed in optflags when compiling as an RPM, and keep the
default flags as close as possible to the current fedora flags, while
still being generic.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc
index 873fb62f..479523bc 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -89,15 +89,27 @@ TEST_CC_OPTION = $(shell \
echo "$(2)"; \
fi)
-STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
-OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4
-WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
+ifndef RPM_OPT_FLAGS
+ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
+ OPTFLAGS := -O2 -g -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \
+ $(STACKPROT) -grecord-gcc-switches \
+ -fasynchronous-unwind-tables --param=ssp-buffer-size=4
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-hardened-cc1 && echo 1),1)
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
+ endif
+ ifeq ($(shell test -f /usr/lib/rpm/redhat/redhat-annobin-cc1 && echo 1),1)
+ OPTFLAGS += -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
+ endif
+else
+ OPTFLAGS := $(RPM_OPT_FLAGS) --param=ssp-buffer-size=4
+endif
+WARNFLAGS := -Werror -Wextra -Wformat=2 -Werror=implicit-int \
-Werror=implicit-function-declaration -Werror=format-security \
- $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS)
-CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2
+ $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
+ -Wstrict-prototypes
CFLAGS := $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
-DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
-MMD -MP
@@ -135,4 +147,4 @@ check_file = $(shell \
%.o: %.c
@echo building $@ because of $?
- $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS) -c -o $@ $<
--
2.17.2

784
0063-RH-add-mpathconf.patch Normal file
View File

@ -0,0 +1,784 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 16 Oct 2014 15:49:01 -0500
Subject: [PATCH] RH: add mpathconf
mpathconf is a program (largely based on lvmcomf) to help users
configure /etc/multipath.conf and enable or disable multipathing. It
has a couple of built-in options that can be set directly from the
command line. But, mostly it is used to get a multipath.conf file
with the OS defaults, and to enable and disable multipathing via
a single command.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 2 +
multipath/Makefile | 5 +
multipath/mpathconf | 565 ++++++++++++++++++++++++++++++++++++++++++
multipath/mpathconf.8 | 135 ++++++++++
4 files changed, 707 insertions(+)
create mode 100644 multipath/mpathconf
create mode 100644 multipath/mpathconf.8
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 1c02e230..a253a936 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -781,6 +781,8 @@ load_config (char * file)
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
} else {
condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
+ 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) {
diff --git a/multipath/Makefile b/multipath/Makefile
index b9bbb3cf..e720c7f6 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -18,10 +18,12 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
+ $(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)$(udevrulesdir)
$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
@@ -29,13 +31,16 @@ install:
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
+ $(INSTALL_PROGRAM) -m 644 mpathconf.8.gz $(DESTDIR)$(man8dir)
uninstall:
$(RM) $(DESTDIR)$(bindir)/$(EXEC)
$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
$(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules
+ $(RM) $(DESTDIR)$(bindir)/mpathconf
$(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz
$(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
+ $(RM) $(DESTDIR)$(man8dir)/mpathconf.8.gz
clean: dep_clean
$(RM) core *.o $(EXEC) *.gz
diff --git a/multipath/mpathconf b/multipath/mpathconf
new file mode 100644
index 00000000..f0d09cbb
--- /dev/null
+++ b/multipath/mpathconf
@@ -0,0 +1,565 @@
+#!/bin/bash
+#
+# 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 PROPERTY FOREIGN MODULE MULTIPATHD HAVE_DISABLE HAVE_WWID_DISABLE HAVE_FIND HAVE_BLACKLIST HAVE_EXCEPTIONS HAVE_DEFAULTS HAVE_FRIENDLY HAVE_PROPERTY HAVE_FOREIGN HAVE_MULTIPATHD HAVE_MODULE HAVE_OUTFILE SHOW_STATUS CHANGED_CONFIG WWID_LIST
+
+DEFAULT_CONFIG="# device-mapper-multipath configuration file
+
+# 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.
+
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+}"
+
+CONFIGFILE="/etc/multipath.conf"
+OUTPUTFILE="/etc/multipath.conf"
+MULTIPATHDIR="/etc/multipath"
+TMPFILE="/etc/multipath/.multipath.conf.tmp"
+WWIDS=0
+
+function usage
+{
+ echo "usage: $0 <command>"
+ echo ""
+ echo "Commands:"
+ echo "Enable: --enable "
+ echo "Disable: --disable"
+ echo "Only allow certain wwids (instead of enable): --allow <WWID>"
+ echo "Set user_friendly_names (Default y): --user_friendly_names <y|n>"
+ echo "Set find_multipaths (Default y): --find_multipaths <y|n>"
+ echo "Set default property blacklist (Default n): --property_blacklist <y|n>"
+ echo "Set enable_foreign to show foreign devices (Default n): --enable_foreign <y|n>"
+ echo "Load the dm-multipath modules on enable (Default y): --with_module <y|n>"
+ echo "start/stop/reload multipathd (Default n): --with_multipathd <y|n>"
+ echo "select output file (Default /etc/multipath.conf): --outfile <FILE>"
+ 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
+ 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
+ add_wwid "${1##part*-mpath-}"
+ elif [[ "$1" =~ ^mpath- ]] ; then
+ add_wwid "${1##mpath-}"
+ 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
+ add_wwid "$1"
+ fi
+}
+
+function parse_args
+{
+ while [ -n "$1" ]; do
+ case $1 in
+ --enable)
+ ENABLE=1
+ shift
+ ;;
+ --disable)
+ 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
+ shift 2
+ else
+ usage
+ exit 1
+ fi
+ ;;
+ --find_multipaths)
+ if [ -n "$2" ]; then
+ FIND=$2
+ shift 2
+ else
+ usage
+ exit 1
+ fi
+ ;;
+ --property_blacklist)
+ if [ -n "$2" ]; then
+ PROPERTY=$2
+ shift 2
+ else
+ usage
+ exit 1
+ fi
+ ;;
+ --enable_foreign)
+ if [ -n "$2" ]; then
+ FOREIGN=$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
+ ;;
+ --outfile)
+ if [ -n "$2" ]; then
+ OUTPUTFILE=$2
+ HAVE_OUTFILE=1
+ shift 2
+ else
+ usage
+ exit 1
+ fi
+ ;;
+ *)
+ usage
+ exit
+ esac
+ done
+}
+
+function validate_args
+{
+ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$PROPERTY" -o -n "$MODULE" -o -n "$FOREIGN" ]; then
+ echo "ignoring extra parameters on disable"
+ FRIENDLY=""
+ FIND=""
+ PROPERTY=""
+ MODULE=""
+ FOREIGN=""
+ 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 [ -n "$PROPERTY" ] && [ "$PROPERTY" != "y" -a "$PROPERTY" != "n" ]; then
+ echo "--property_blacklist must be either 'y' or 'n'"
+ exit 1
+ fi
+ if [ -n "$FOREIGN" ] && [ "$FOREIGN" != "y" -a "$FOREIGN" != "n" ]; then
+ echo "--enable_foreign must be either 'y' or 'n'"
+ exit 1
+ fi
+ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" -a -z "$FOREIGN" ]; 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
+ 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
+{
+ INDEX=0
+ while [ "$INDEX" -lt "$WWIDS" ] ; do
+ sed -i '/^blacklist_exceptions[[:space:]]*{/ a\
+ wwid '"\"${WWID_LIST[$INDEX]}\""'
+' $TMPFILE
+ ((INDEX++))
+ done
+}
+
+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
+echo "$DEFAULT_CONFIG" > $TMPFILE
+if [ -f "$CONFIGFILE" ]; then
+ cp $CONFIGFILE $TMPFILE
+fi
+
+if grep -q "^blacklist[[:space:]]*{" $TMPFILE ; then
+ 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
+
+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 /bin/systemctl status multipathd.service > /dev/null 2>&1 ; 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_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
+ 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
+ if sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*enable_foreign" ; then
+ HAVE_FOREIGN=0
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]]*\"\^\$\"" ; then
+ HAVE_FOREIGN=1
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]]*\"NONE\"" ; then
+ HAVE_FOREIGN=1
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign[[:space:]] \"\.\?\*\"" ; then
+ HAVE_FOREIGN=2
+ elif sed -n '/^defaults[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*enable_foreign" ; then
+ HAVE_FOREIGN=3
+ fi
+fi
+
+if [ "$HAVE_EXCEPTIONS" = "1" ]; then
+ if sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
+ HAVE_PROPERTY=1
+ elif sed -n '/^blacklist_exceptions[[:space:]]*{/,/^}/ p' $TMPFILE | grep -q "^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"" ; then
+ HAVE_PROPERTY=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 [ -z "$HAVE_PROPERTY" -o "$HAVE_PROPERTY" = 0 ]; then
+ echo "default property blacklist is disabled"
+ else
+ echo "default property blacklist is enabled"
+ fi
+ if [ -z "$HAVE_FOREIGN" -o "$HAVE_FOREIGN" = 0 ]; then
+ echo "enable_foreign is not set (no foreign multipath devices will be shown)"
+ elif [ "$HAVE_FOREIGN" = 1 ]; then
+ echo "enable_foreign is set (no foreign multipath devices will be shown)"
+ elif [ "$HAVE_FOREIGN" = 2 ]; then
+ echo "enable_foreign is set (all foreign multipath devices will be shown)"
+ else
+ echo "enable_foreign is set (foreign multipath devices may not be shown)"
+ 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 [ -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
+
+if [ -z "$HAVE_BLACKLIST" ]; then
+ cat >> $TMPFILE <<- _EOF_
+
+blacklist {
+}
+_EOF_
+fi
+
+if [ -z "$HAVE_DEFAULTS" ]; then
+ cat >> $TMPFILE <<- _EOF_
+
+defaults {
+}
+_EOF_
+fi
+
+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:]]*{/,/^}/ {/^[[:space:]]*wwid/ d}' $TMPFILE
+ else
+ cat >> $TMPFILE <<- _EOF_
+
+blacklist_exceptions {
+}
+_EOF_
+ fi
+ 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 ".*"
+' $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 [ "$PROPERTY" = "n" ]; then
+ if [ "$HAVE_PROPERTY" = 1 ]; then
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/# property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
+ CHANGED_CONFIG=1
+ fi
+elif [ "$PROPERTY" = "y" ]; then
+ if [ -z "$HAVE_PROPERTY" -a -z "$HAVE_EXCEPTIONS" ]; then
+ cat >> $TMPFILE << _EOF_
+
+blacklist_exceptions {
+ property "(SCSI_IDENT_|ID_WWN)"
+}
+_EOF_
+ CHANGED_CONFIG=1
+ elif [ -z "$HAVE_PROPERTY" ]; then
+ sed -i '/^blacklist_exceptions[[:space:]]*{/ a\
+ property "(SCSI_IDENT_|ID_WWN)"
+' $TMPFILE
+ CHANGED_CONFIG=1
+ elif [ "$HAVE_PROPERTY" = 0 ]; then
+ sed -i '/^blacklist_exceptions[[:space:]]*{/,/^}/ s/^[[:space:]]*#[[:space:]]*property[[:space:]]*\"(SCSI_IDENT_|ID_WWN)\"/ property \"(SCSI_IDENT_|ID_WWN)\"/' $TMPFILE
+ CHANGED_CONFIG=1
+ fi
+fi
+
+if [ "$FOREIGN" = "y" ]; then
+ if [ -z "$HAVE_FOREIGN" ]; then
+ sed -i '/^defaults[[:space:]]*{/ a\
+ enable_foreign ".*"
+' $TMPFILE
+ CHANGED_CONFIG=1
+ elif [ "$HAVE_FOREIGN" = 0 -o "$HAVE_FOREIGN" = 1 -o "$HAVE_FOREIGN" = 3 ]; then
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*#\?[[:space:]]*enable_foreign.*$/ enable_foreign ".*"/' $TMPFILE
+ CHANGED_CONFIG=1
+ fi
+elif [ "$FOREIGN" = "n" ]; then
+ if [ "$HAVE_FOREIGN" = 2 -o "$HAVE_FOREIGN" = 3 ]; then
+ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*enable_foreign/# enable_foreign/' $TMPFILE
+ CHANGED_CONFIG=1
+ fi
+fi
+
+if [ -f "$OUTPUTFILE" ]; then
+ cp $OUTPUTFILE $OUTPUTFILE.old
+ if [ $? != 0 ]; then
+ echo "failed to backup old config file, $OUTPUTFILE not updated"
+ exit 1
+ fi
+fi
+
+cp $TMPFILE $OUTPUTFILE
+if [ $? != 0 ]; then
+ echo "failed to copy new config file into place, check $OUTPUTFILE 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
+ systemctl start multipathd.service
+ fi
+elif [ "$ENABLE" = 0 ]; then
+ if [ "$HAVE_MULTIPATHD" = 1 ]; then
+ systemctl stop multipathd.service
+ fi
+elif [ -n "$CHANGED_CONFIG" -a "$HAVE_MULTIPATHD" = 1 ]; then
+ systemctl reload multipathd.service
+fi
diff --git a/multipath/mpathconf.8 b/multipath/mpathconf.8
new file mode 100644
index 00000000..b82961d6
--- /dev/null
+++ b/multipath/mpathconf.8
@@ -0,0 +1,135 @@
+.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, but
+will not create of modify
+.B /etc/multipath.conf
+
+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
+create a default file with
+.B user_friendly_names
+and
+.B find_multipaths
+set. To disable these, use the
+.B --user_friendly_names n
+and
+.B --find_multipaths n
+options
+.SH COMMANDS
+.TP
+.B --enable
+Removes any line that blacklists all device nodes from the
+.B /etc/multipath.conf
+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
+.B /etc/multipath.conf
+blacklist section. If no blacklist section exists, it will create one.
+.TP
+.B --allow \fB<device>\fP
+Modifies the \fB/etc/multipath/conf\fP blacklist to blacklist all
+wwids and the blacklist_exceptions to whitelist \fB<device>\fP. \fB<device>\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_names \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 along with any other command.
+.TP
+.B --property_blacklist \fP { \fBy\fP | \fBn\fP }
+If set to \fBy\fP, this adds the line
+.B property "(SCSI_IDENT_|ID_WWN)"
+to the
+.B /etc/multipath.conf
+blacklist_exceptions section. If set to \fBn\fP, this removes the line, if
+present. This command can be used along with any other command.
+.TP
+.B --enable_foreign\fP { \fBy\fP | \fBn\fP }
+If set to \fBn\fP, this adds the line
+.B enable_foreign "^$"
+to the
+.B /etc/multipath.conf
+defaults section. if set to \fBy\fP, this removes the line, if present. This
+command can be used along with any other command.
+.TP
+.B --outfile \fB<filename>\fP
+Write the resulting multipath configuration to \fB<filename>\fP instead of
+\fB/etc/multipath.conf\fP.
+.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 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.
+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 <bmarzins@redhat.com>
--
2.17.2

View File

@ -0,0 +1,169 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 17 Oct 2014 11:20:34 -0500
Subject: [PATCH] RH: add wwids from kernel cmdline mpath.wwids with -A
This patch adds another option to multipath, "-A", which reads
/proc/cmdline for mpath.wwid=<WWID> options, and adds any wwids it finds
to /etc/multipath/wwids. While this isn't usually important during
normal operation, since these wwids should already be added, it can be
helpful during installation, to make sure that multipath can claim
devices as its own, before LVM or something else makes use of them. The
patch also execs "/sbin/multipath -A" before running multipathd in
multipathd.service
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/wwids.c | 44 +++++++++++++++++++++++++++++++++++
libmultipath/wwids.h | 1 +
multipath/main.c | 10 ++++++--
multipath/multipath.8 | 7 +++++-
multipathd/multipathd.service | 1 +
5 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index 61d9c39e..c7a16636 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -451,3 +451,47 @@ int unmark_failed_wwid(const char *wwid)
print_failed_wwid_result("unmark_failed", wwid, r);
return r;
}
+
+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;
+}
diff --git a/libmultipath/wwids.h b/libmultipath/wwids.h
index 0c6ee54d..e32a0b0e 100644
--- a/libmultipath/wwids.h
+++ b/libmultipath/wwids.h
@@ -17,6 +17,7 @@ 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);
enum {
WWID_IS_NOT_FAILED = 0,
diff --git a/multipath/main.c b/multipath/main.c
index 3da692dc..ce48a932 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -135,7 +135,7 @@ usage (char * progname)
fprintf (stderr, " %s [-v level] [-R retries] -F\n", progname);
fprintf (stderr, " %s [-v level] [-l|-ll] [device]\n", progname);
fprintf (stderr, " %s [-v level] [-a|-w] device\n", progname);
- fprintf (stderr, " %s [-v level] -W\n", progname);
+ fprintf (stderr, " %s [-v level] [-A|-W]\n", progname);
fprintf (stderr, " %s [-v level] [-i] [-c|-C] device\n", progname);
fprintf (stderr, " %s [-v level] [-i] [-u|-U]\n", progname);
fprintf (stderr, " %s [-h|-t|-T]\n", progname);
@@ -149,6 +149,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"
" -C check if a multipath device has usable paths\n"
" -q allow queue_if_no_path when multipathd is not running\n"
@@ -896,7 +898,7 @@ main (int argc, char *argv[])
multipath_conf = conf;
conf->retrigger_tries = 0;
conf->force_sync = 1;
- while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":aAdDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -973,6 +975,10 @@ main (int argc, char *argv[])
case 'T':
cmd = CMD_DUMP_CONFIG;
break;
+ case 'A':
+ if (remember_cmdline_wwid() != 0)
+ exit(RTVL_FAIL);
+ exit(RTVL_OK);
case 'h':
usage(argv[0]);
exit(RTVL_OK);
diff --git a/multipath/multipath.8 b/multipath/multipath.8
index 5b29a5d9..0478f4e7 100644
--- a/multipath/multipath.8
+++ b/multipath/multipath.8
@@ -63,7 +63,7 @@ multipath \- Device mapper target autoconfig.
.B multipath
.RB [\| \-v\ \c
.IR level \|]
-.B -W
+.RB [\| \-A | \-W \|]
.
.LP
.B multipath
@@ -145,6 +145,11 @@ device mapper, path checkers ...).
Add the WWID for the specified device to the WWIDs file.
.
.TP
+.B \-A
+Add the WWIDs from any kernel command line \fImpath.wwid\fR parameters to the
+WWIDs file.
+.
+.TP
.B \-w
Remove the WWID for the specified device from the WWIDs file.
.
diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service
index 17434cef..0fbcc46b 100644
--- a/multipathd/multipathd.service
+++ b/multipathd/multipathd.service
@@ -15,6 +15,7 @@ Type=notify
NotifyAccess=main
LimitCORE=infinity
ExecStartPre=-/sbin/modprobe -a scsi_dh_alua scsi_dh_emc scsi_dh_rdac dm-multipath
+ExecStartPre=-/sbin/multipath -A
ExecStart=/sbin/multipathd -d -s
ExecReload=/sbin/multipathd reconfigure
TasksMax=infinity
--
2.17.2

View File

@ -0,0 +1,121 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Mon, 6 Nov 2017 21:39:28 -0600
Subject: [PATCH] RH: warn on invalid regex instead of failing
multipath.conf used to allow "*" as a match everything regular expression,
instead of requiring ".*". Instead of erroring when the old style
regular expressions are used, it should print a warning and convert
them.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dict.c | 27 +++++++++++++++++++++------
libmultipath/parser.c | 13 +++++++++++++
libmultipath/parser.h | 1 +
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 0e9ea387..184d4b22 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -103,6 +103,21 @@ set_str(vector strvec, void *ptr)
return 0;
}
+static int
+set_regex(vector strvec, void *ptr)
+{
+ char **str_ptr = (char **)ptr;
+
+ if (*str_ptr)
+ FREE(*str_ptr);
+ *str_ptr = set_regex_value(strvec);
+
+ if (!*str_ptr)
+ return 1;
+
+ return 0;
+}
+
static int
set_yes_no(vector strvec, void *ptr)
{
@@ -1504,7 +1519,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
- buff = set_value(strvec); \
+ buff = set_regex_value(strvec); \
if (!buff) \
return 1; \
\
@@ -1520,7 +1535,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
if (!conf->option) \
return 1; \
\
- buff = set_value(strvec); \
+ buff = set_regex_value(strvec); \
if (!buff) \
return 1; \
\
@@ -1623,16 +1638,16 @@ device_handler(struct config *conf, vector strvec)
return 0;
}
-declare_hw_handler(vendor, set_str)
+declare_hw_handler(vendor, set_regex)
declare_hw_snprint(vendor, print_str)
-declare_hw_handler(product, set_str)
+declare_hw_handler(product, set_regex)
declare_hw_snprint(product, print_str)
-declare_hw_handler(revision, set_str)
+declare_hw_handler(revision, set_regex)
declare_hw_snprint(revision, print_str)
-declare_hw_handler(bl_product, set_str)
+declare_hw_handler(bl_product, set_regex)
declare_hw_snprint(bl_product, print_str)
declare_hw_handler(hwhandler, set_str)
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index 11a6168c..a7285a35 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -384,6 +384,19 @@ oom:
return NULL;
}
+void *
+set_regex_value(vector strvec)
+{
+ char *buff = set_value(strvec);
+
+ if (buff && strcmp("*", buff) == 0) {
+ condlog(0, "Invalid regular expression \"*\" in multipath.conf. Using \".*\"");
+ FREE(buff);
+ return strdup(".*");
+ }
+ return buff;
+}
+
/* non-recursive configuration stream handler */
static int kw_level = 0;
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
index 62906e98..b7917052 100644
--- a/libmultipath/parser.h
+++ b/libmultipath/parser.h
@@ -77,6 +77,7 @@ extern void dump_keywords(vector keydump, int level);
extern void free_keywords(vector keywords);
extern vector alloc_strvec(char *string);
extern void *set_value(vector strvec);
+extern void *set_regex_value(vector strvec);
extern int process_file(struct config *conf, char *conf_file);
extern struct keyword * find_keyword(vector keywords, vector v, char * name);
int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
--
2.17.2

View File

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 7 Jun 2018 17:43:52 -0500
Subject: [PATCH] RH: reset default find_mutipaths value to off
Upstream has changed to default find_multipaths to "strict". For now
Redhat will retain the previous default of "off".
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/defaults.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index 01a501bd..984d8dd8 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -22,7 +22,7 @@
#define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF
#define DEFAULT_VERBOSITY 2
#define DEFAULT_REASSIGN_MAPS 0
-#define DEFAULT_FIND_MULTIPATHS FIND_MULTIPATHS_STRICT
+#define DEFAULT_FIND_MULTIPATHS FIND_MULTIPATHS_OFF
#define DEFAULT_FAST_IO_FAIL 5
#define DEFAULT_DEV_LOSS_TMO 600
#define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_ON
--
2.17.2

View File

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 25 Jan 2019 14:54:56 -0600
Subject: [PATCH] RH: Fix nvme compilation warning
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/nvme/argconfig.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmultipath/nvme/argconfig.h b/libmultipath/nvme/argconfig.h
index adb192b6..bfd10ef8 100644
--- a/libmultipath/nvme/argconfig.h
+++ b/libmultipath/nvme/argconfig.h
@@ -76,7 +76,7 @@ struct argconfig_commandline_options {
extern "C" {
#endif
-typedef void argconfig_help_func();
+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);
--
2.17.2

View File

@ -0,0 +1,87 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Thu, 11 Apr 2019 13:25:42 -0500
Subject: [PATCH] RH: attempt to get ANA info via sysfs first
When the ANA prioritizer is run, first see if the "ana_state" sysfs file
exists, and if it does, try to read the state from there. If that fails,
fallback to using an ioctl.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/prioritizers/ana.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/libmultipath/prioritizers/ana.c b/libmultipath/prioritizers/ana.c
index b5c7873d..e139360c 100644
--- a/libmultipath/prioritizers/ana.c
+++ b/libmultipath/prioritizers/ana.c
@@ -24,6 +24,7 @@
#include "prio.h"
#include "util.h"
#include "structs.h"
+#include "sysfs.h"
enum {
ANA_ERR_GETCTRL_FAILED = 1,
@@ -36,6 +37,7 @@ enum {
ANA_ERR_GETNS_FAILED,
ANA_ERR_NO_MEMORY,
ANA_ERR_NO_INFORMATION,
+ ANA_ERR_INVALID_STATE,
};
static const char *ana_errmsg[] = {
@@ -49,6 +51,7 @@ static const char *ana_errmsg[] = {
[ANA_ERR_GETNS_FAILED] = "couldn't get namespace info",
[ANA_ERR_NO_MEMORY] = "out of memory",
[ANA_ERR_NO_INFORMATION] = "invalid fd",
+ [ANA_ERR_INVALID_STATE] = "invalid state",
};
static const char *anas_string[] = {
@@ -107,6 +110,27 @@ static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log,
return -ANA_ERR_GETANAS_NOTFOUND;
}
+static int get_ana_info_sysfs(struct path *pp)
+{
+ char state[32];
+
+ if (!pp->udev || sysfs_attr_get_value(pp->udev, "ana_state", state,
+ sizeof(state)) <= 0)
+ return -ANA_ERR_NO_INFORMATION;
+
+ if (strcmp(state, "optimized") == 0)
+ return NVME_ANA_OPTIMIZED;
+ if (strcmp(state, "non-optimized") == 0)
+ return NVME_ANA_NONOPTIMIZED;
+ if (strcmp(state, "inaccessible") == 0)
+ return NVME_ANA_INACCESSIBLE;
+ if (strcmp(state, "persistent-loss") == 0)
+ return NVME_ANA_PERSISTENT_LOSS;
+ if (strcmp(state, "change") == 0)
+ return NVME_ANA_CHANGE;
+ return -ANA_ERR_INVALID_STATE;
+}
+
static int get_ana_info(struct path * pp)
{
int rc;
@@ -210,8 +234,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args,
if (pp->fd < 0)
rc = -ANA_ERR_NO_INFORMATION;
- else
- rc = get_ana_info(pp);
+ else {
+ rc = get_ana_info_sysfs(pp);
+ if (rc < 0)
+ rc = get_ana_info(pp);
+ }
switch (rc) {
case NVME_ANA_OPTIMIZED:
--
2.17.2

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 29 May 2020 17:21:21 -0500
Subject: [PATCH] RH: work around gcc 10 format-truncation issue
gcc 10 was returning false positives on some architectures, when trying
to determine if a snprintf() function could silently truncate its
output. Instead of changing the code to pretend that this is possible,
make these warnings, instead of errors.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.inc b/Makefile.inc
index 479523bc..e2f5d0dc 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -109,7 +109,7 @@ endif
WARNFLAGS := -Werror -Wextra -Wformat=2 -Werror=implicit-int \
-Werror=implicit-function-declaration -Werror=format-security \
$(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \
- -Wstrict-prototypes
+ -Wstrict-prototypes -Wno-error=format-truncation
CFLAGS := $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
-DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
-MMD -MP
--
2.17.2

View File

@ -0,0 +1,369 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 13 May 2020 17:04:24 -0500
Subject: [PATCH] multipath: add libmpathvalid library
This library allows other programs to check if a path should be claimed
by multipath. It exports an init and exit function, that need to be
called before any other functions can be called, a pointer to a struct
config, that stores the configuration which is dealt with in the
init and exit functions, and two more functions.
mpath_get_mode() get the configured find_multipaths mode.
mpath_is_path() returns whether the device is claimed by multipath, and
optionally returns the wwid. This code works slightly different than
the multipath -c/u code for SMART mode. Instead of checking all the
existing paths to see if another has the same wwid, it expects the
caller to pass in an array of the already known path wwids, and checks
if the current path matches any of those.
The library also doesn't set up the device-mapper log fuctions. It
leaves this up to the caller.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Makefile | 3 +-
Makefile.inc | 1 +
libmpathvalid/Makefile | 38 +++++++
libmpathvalid/libmpathvalid.version | 10 ++
libmpathvalid/mpath_valid.c | 168 ++++++++++++++++++++++++++++
libmpathvalid/mpath_valid.h | 57 ++++++++++
6 files changed, 276 insertions(+), 1 deletion(-)
create mode 100644 libmpathvalid/Makefile
create mode 100644 libmpathvalid/libmpathvalid.version
create mode 100644 libmpathvalid/mpath_valid.c
create mode 100644 libmpathvalid/mpath_valid.h
diff --git a/Makefile b/Makefile
index 8bcaba66..f157a549 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,7 @@ BUILDDIRS := \
libmultipath/checkers \
libmultipath/foreign \
libmpathpersist \
+ libmpathvalid \
multipath \
multipathd \
mpathpersist \
@@ -29,7 +30,7 @@ $(BUILDDIRS):
$(MAKE) -C $@
libmultipath libdmmp: libmpathcmd
-libmpathpersist multipath multipathd: libmultipath
+libmpathpersist libmpathvalid multipath multipathd: libmultipath
mpathpersist multipathd: libmpathpersist
libmultipath/checkers.install \
diff --git a/Makefile.inc b/Makefile.inc
index e2f5d0dc..936e5833 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -66,6 +66,7 @@ libdir = $(prefix)/$(LIB)/multipath
unitdir = $(prefix)/$(SYSTEMDPATH)/systemd/system
mpathpersistdir = $(TOPDIR)/libmpathpersist
mpathcmddir = $(TOPDIR)/libmpathcmd
+mpathvaliddir = $(TOPDIR)/libmpathvalid
thirdpartydir = $(TOPDIR)/third-party
libdmmpdir = $(TOPDIR)/libdmmp
nvmedir = $(TOPDIR)/libmultipath/nvme
diff --git a/libmpathvalid/Makefile b/libmpathvalid/Makefile
new file mode 100644
index 00000000..70b97eca
--- /dev/null
+++ b/libmpathvalid/Makefile
@@ -0,0 +1,38 @@
+include ../Makefile.inc
+
+SONAME = 0
+DEVLIB = libmpathvalid.so
+LIBS = $(DEVLIB).$(SONAME)
+
+CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathcmddir)
+
+LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) \
+ -lmultipath -L$(mpathcmddir) -lmpathcmd -ludev
+
+OBJS = mpath_valid.o
+
+all: $(LIBS)
+
+$(LIBS): $(OBJS)
+ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) -Wl,--version-script=libmpathvalid.version
+ $(LN) $(LIBS) $(DEVLIB)
+
+install: $(LIBS)
+ $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir)
+ $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
+ $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+ $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(includedir)
+ $(INSTALL_PROGRAM) -m 644 mpath_valid.h $(DESTDIR)$(includedir)
+
+uninstall:
+ $(RM) $(DESTDIR)$(syslibdir)/$(LIBS)
+ $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+ $(RM) $(DESTDIR)$(includedir)/mpath_valid.h
+
+clean: dep_clean
+ $(RM) core *.a *.o *.so *.so.* *.gz
+
+include $(wildcard $(OBJS:.o=.d))
+
+dep_clean:
+ $(RM) $(OBJS:.o=.d)
diff --git a/libmpathvalid/libmpathvalid.version b/libmpathvalid/libmpathvalid.version
new file mode 100644
index 00000000..4d8a8ba4
--- /dev/null
+++ b/libmpathvalid/libmpathvalid.version
@@ -0,0 +1,10 @@
+MPATH_1.0 {
+ global:
+ mpathvalid_conf;
+ mpathvalid_init;
+ mpathvalid_exit;
+ mpathvalid_is_path;
+ mpathvalid_get_mode;
+ local:
+ *;
+};
diff --git a/libmpathvalid/mpath_valid.c b/libmpathvalid/mpath_valid.c
new file mode 100644
index 00000000..6153e8b7
--- /dev/null
+++ b/libmpathvalid/mpath_valid.c
@@ -0,0 +1,168 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <libdevmapper.h>
+#include <libudev.h>
+#include <errno.h>
+
+#include "devmapper.h"
+#include "structs.h"
+#include "util.h"
+#include "config.h"
+#include "discovery.h"
+#include "wwids.h"
+#include "sysfs.h"
+#include "mpath_cmd.h"
+#include "valid.h"
+#include "mpath_valid.h"
+
+static struct config default_config = { .verbosity = -1 };
+struct config *mpathvalid_conf = &default_config;
+
+static unsigned int get_conf_mode(struct config *conf)
+{
+ if (conf->find_multipaths == FIND_MULTIPATHS_SMART)
+ return MPATH_SMART;
+ if (conf->find_multipaths == FIND_MULTIPATHS_GREEDY)
+ return MPATH_GREEDY;
+ return MPATH_STRICT;
+}
+
+static void set_conf_mode(struct config *conf, unsigned int mode)
+{
+ if (mode == MPATH_SMART)
+ conf->find_multipaths = FIND_MULTIPATHS_SMART;
+ else if (mode == MPATH_GREEDY)
+ conf->find_multipaths = FIND_MULTIPATHS_GREEDY;
+ else
+ conf->find_multipaths = FIND_MULTIPATHS_STRICT;
+}
+
+unsigned int mpathvalid_get_mode(void)
+{
+ int mode;
+ struct config *conf;
+
+ conf = get_multipath_config();
+ if (!conf)
+ return -1;
+ mode = get_conf_mode(conf);
+ put_multipath_config(conf);
+ return mode;
+}
+
+static int convert_result(int result) {
+ switch (result) {
+ case PATH_IS_ERROR:
+ return MPATH_IS_ERROR;
+ case PATH_IS_NOT_VALID:
+ return MPATH_IS_NOT_VALID;
+ case PATH_IS_VALID:
+ return MPATH_IS_VALID;
+ case PATH_IS_VALID_NO_CHECK:
+ return MPATH_IS_VALID_NO_CHECK;
+ case PATH_IS_MAYBE_VALID:
+ return MPATH_IS_MAYBE_VALID;
+ }
+ return MPATH_IS_ERROR;
+}
+
+int
+mpathvalid_init(int verbosity)
+{
+ unsigned int version[3];
+ struct config *conf;
+
+ default_config.verbosity = verbosity;
+ skip_libmp_dm_init();
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf)
+ return -1;
+ conf->verbosity = verbosity;
+ if (dm_prereq(version))
+ goto fail;
+ memcpy(conf->version, version, sizeof(version));
+
+ mpathvalid_conf = conf;
+ return 0;
+fail:
+ free_config(conf);
+ return -1;
+}
+
+int
+mpathvalid_exit(void)
+{
+ struct config *conf = mpathvalid_conf;
+
+ default_config.verbosity = -1;
+ if (mpathvalid_conf == &default_config)
+ return 0;
+ mpathvalid_conf = &default_config;
+ free_config(conf);
+ return 0;
+}
+
+/*
+ * name: name of path to check
+ * mode: mode to use for determination. MPATH_DEFAULT uses configured mode
+ * info: on success, contains the path wwid
+ * paths: array of the returned mpath_info from other claimed paths
+ * nr_paths: the size of the paths array
+ */
+int
+mpathvalid_is_path(const char *name, unsigned int mode, char **wwid,
+ const char **path_wwids, unsigned int nr_paths)
+{
+ struct config *conf;
+ int r = MPATH_IS_ERROR;
+ unsigned int i;
+ struct path *pp;
+
+ if (!name || mode >= MPATH_MAX_MODE)
+ return r;
+
+ if (nr_paths > 0 && !path_wwids)
+ return r;
+
+ pp = alloc_path();
+ if (!pp)
+ return r;
+
+ if (wwid) {
+ *wwid = (char *)malloc(WWID_SIZE);
+ if (!*wwid)
+ goto out;
+ }
+
+ conf = get_multipath_config();
+ if (!conf || conf == &default_config)
+ goto out_wwid;
+ if (mode != MPATH_DEFAULT)
+ set_conf_mode(conf, mode);
+ r = convert_result(is_path_valid(name, conf, pp, true));
+ put_multipath_config(conf);
+
+ if (r == MPATH_IS_MAYBE_VALID) {
+ for (i = 0; i < nr_paths; i++) {
+ if (strncmp(path_wwids[i], pp->wwid, WWID_SIZE) == 0) {
+ r = MPATH_IS_VALID;
+ break;
+ }
+ }
+ }
+
+out_wwid:
+ if (wwid) {
+ if (r == MPATH_IS_VALID || r == MPATH_IS_VALID_NO_CHECK ||
+ r == MPATH_IS_MAYBE_VALID)
+ strlcpy(*wwid, pp->wwid, WWID_SIZE);
+ else {
+ free(*wwid);
+ *wwid = NULL;
+ }
+ }
+out:
+ free_path(pp);
+ return r;
+}
diff --git a/libmpathvalid/mpath_valid.h b/libmpathvalid/mpath_valid.h
new file mode 100644
index 00000000..7fd8aa47
--- /dev/null
+++ b/libmpathvalid/mpath_valid.h
@@ -0,0 +1,57 @@
+/*
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIB_MPATH_VALID_H
+#define LIB_MPATH_VALID_H
+
+#ifdef __cpluscplus
+extern "C" {
+#endif
+
+enum mpath_valid_mode {
+ MPATH_DEFAULT,
+ MPATH_STRICT,
+ MPATH_SMART,
+ MPATH_GREEDY,
+ MPATH_MAX_MODE, /* used only for bounds checking */
+};
+
+/* MPATH_IS_VALID_NO_CHECK is used to skip checks to see if the device
+ * has already been unclaimed by multipath in the past */
+enum mpath_valid_result {
+ MPATH_IS_ERROR = -1,
+ MPATH_IS_NOT_VALID,
+ MPATH_IS_VALID,
+ MPATH_IS_VALID_NO_CHECK,
+ MPATH_IS_MAYBE_VALID,
+};
+
+struct config;
+extern struct config *mpathvalid_conf;
+int mpathvalid_init(int verbosity);
+int mpathvalid_exit(void);
+unsigned int mpathvalid_get_mode(void);
+int mpathvalid_is_path(const char *name, unsigned int mode, char **wwid,
+ const char **path_wwids, unsigned int nr_paths);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIB_PATH_VALID_H */
--
2.17.2

View File

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 19 May 2020 15:55:15 -0500
Subject: [PATCH] libmultipath: add uid failback for dasd devices
Add failback code to get the uid for dasd devices from sysfs. Copied
from dasdinfo
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/defaults.h | 1 +
libmultipath/discovery.c | 37 ++++++++++++++++++++++++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index 984d8dd8..6a678a83 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -8,6 +8,7 @@
*/
#define DEFAULT_UID_ATTRIBUTE "ID_SERIAL"
#define DEFAULT_NVME_UID_ATTRIBUTE "ID_WWN"
+#define DEFAULT_DASD_UID_ATTRIBUTE "ID_UID"
#define DEFAULT_UDEVDIR "/dev"
#define DEFAULT_MULTIPATHDIR "/" LIB_STRING "/multipath"
#define DEFAULT_SELECTOR "service-time 0"
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index aa5942c3..002d3d18 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1920,12 +1920,44 @@ get_vpd_uid(struct path * pp)
return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE);
}
+/* based on code from s390-tools/dasdinfo/dasdinfo.c */
+static ssize_t dasd_get_uid(struct path *pp)
+{
+ struct udev_device *parent;
+ char value[80];
+ char *p;
+ int i;
+
+ parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "ccw",
+ NULL);
+ if (!parent)
+ return -1;
+
+ if (sysfs_attr_get_value(parent, "uid", value, 80) < 0)
+ return -1;
+
+ p = value - 1;
+ /* look for the 4th '.' and cut there */
+ for (i = 0; i < 4; i++) {
+ p = index(p + 1, '.');
+ if (!p)
+ break;
+ }
+ if (p)
+ *p = '\0';
+
+ return strlcpy(pp->wwid, value, WWID_SIZE);
+}
+
static ssize_t uid_fallback(struct path *pp, int path_state,
const char **origin)
{
ssize_t len = -1;
- if (pp->bus == SYSFS_BUS_SCSI) {
+ if (pp->bus == SYSFS_BUS_CCW) {
+ len = dasd_get_uid(pp);
+ *origin = "sysfs";
+ } else if (pp->bus == SYSFS_BUS_SCSI) {
len = get_vpd_uid(pp);
*origin = "sysfs";
if (len < 0 && path_state == PATH_UP) {
@@ -1970,6 +2002,9 @@ static bool has_uid_fallback(struct path *pp)
!strcmp(pp->uid_attribute, ""))) ||
(pp->bus == SYSFS_BUS_NVME &&
(!strcmp(pp->uid_attribute, DEFAULT_NVME_UID_ATTRIBUTE) ||
+ !strcmp(pp->uid_attribute, ""))) ||
+ (pp->bus == SYSFS_BUS_CCW &&
+ (!strcmp(pp->uid_attribute, DEFAULT_DASD_UID_ATTRIBUTE) ||
!strcmp(pp->uid_attribute, ""))));
}
--
2.17.2

View File

@ -0,0 +1,192 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 20 May 2020 16:46:55 -0500
Subject: [PATCH] libmultipath: add ignore_udev_uid option
Setting this option to yes will force multipath to get the uid by using
the fallback sysfs methods, instead of getting it from udev. This will
cause devices that can't get their uid from the standard locations to
not get a uid. It will also disable uevent merging.
It will not stop uevents from being resent for device that failed to
get a WWID, although I'm on the fence about the benefit of this.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 1 +
libmultipath/dict.c | 4 ++++
libmultipath/discovery.c | 17 +++++++++++------
libmultipath/discovery.h | 8 +++++++-
libmultipath/uevent.c | 2 +-
multipath/multipath.conf.5 | 13 +++++++++++++
multipathd/main.c | 7 ++++++-
7 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 160867cd..c7a73fba 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -192,6 +192,7 @@ struct config {
int find_multipaths_timeout;
int marginal_pathgroups;
int skip_delegate;
+ int ignore_udev_uid;
unsigned int version[3];
unsigned int sequence_nr;
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 184d4b22..9a0729bf 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -1406,6 +1406,9 @@ declare_hw_snprint(all_tg_pt, print_yes_no_undef)
declare_def_handler(marginal_pathgroups, set_yes_no)
declare_def_snprint(marginal_pathgroups, print_yes_no)
+declare_def_handler(ignore_udev_uid, set_yes_no)
+declare_def_snprint(ignore_udev_uid, print_yes_no)
+
static int
def_uxsock_timeout_handler(struct config *conf, vector strvec)
{
@@ -1816,6 +1819,7 @@ init_keywords(vector keywords)
install_keyword("enable_foreign", &def_enable_foreign_handler,
&snprint_def_enable_foreign);
install_keyword("marginal_pathgroups", &def_marginal_pathgroups_handler, &snprint_def_marginal_pathgroups);
+ install_keyword("ignore_udev_uid", &def_ignore_udev_uid_handler, &snprint_def_ignore_udev_uid);
__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/libmultipath/discovery.c b/libmultipath/discovery.c
index 002d3d18..f0e92227 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -2010,7 +2010,7 @@ static bool has_uid_fallback(struct path *pp)
int
get_uid (struct path * pp, int path_state, struct udev_device *udev,
- int allow_fallback)
+ int fallback)
{
char *c;
const char *origin = "unknown";
@@ -2043,7 +2043,9 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
} else
len = strlen(pp->wwid);
origin = "callout";
- } else {
+ } else if (fallback == UID_FALLBACK_FORCE)
+ len = uid_fallback(pp, path_state, &origin);
+ else {
bool udev_available = udev && pp->uid_attribute
&& *pp->uid_attribute;
@@ -2056,8 +2058,9 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
else
origin = "udev";
}
- if ((!udev_available || (len <= 0 && allow_fallback))
- && has_uid_fallback(pp)) {
+ if ((!udev_available ||
+ (len <= 0 && fallback == UID_FALLBACK_ALLOW)) &&
+ has_uid_fallback(pp)) {
used_fallback = 1;
len = uid_fallback(pp, path_state, &origin);
}
@@ -2197,8 +2200,10 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
}
if ((mask & DI_WWID) && !strlen(pp->wwid)) {
- get_uid(pp, path_state, pp->udev,
- (pp->retriggers >= conf->retrigger_tries));
+ int fallback = conf->ignore_udev_uid? UID_FALLBACK_FORCE :
+ (pp->retriggers >= conf->retrigger_tries)?
+ UID_FALLBACK_ALLOW : UID_FALLBACK_NONE;
+ get_uid(pp, path_state, pp->udev, fallback);
if (!strlen(pp->wwid)) {
if (pp->bus == SYSFS_BUS_UNDEF)
return PATHINFO_SKIPPED;
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index 6444887d..ca8542d6 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -54,8 +54,14 @@ ssize_t sysfs_get_inquiry(struct udev_device *udev,
unsigned char *buff, size_t len);
int sysfs_get_asymmetric_access_state(struct path *pp,
char *buff, int buflen);
+
+enum {
+ UID_FALLBACK_NONE,
+ UID_FALLBACK_ALLOW,
+ UID_FALLBACK_FORCE,
+};
int get_uid(struct path * pp, int path_state, struct udev_device *udev,
- int allow_fallback);
+ int fallback);
/*
* discovery bitmask
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index e0d13b11..d67129d1 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -179,7 +179,7 @@ uevent_need_merge(void)
bool need_merge = false;
conf = get_multipath_config();
- if (VECTOR_SIZE(&conf->uid_attrs) > 0)
+ if (!conf->ignore_udev_uid && VECTOR_SIZE(&conf->uid_attrs) > 0)
need_merge = true;
put_multipath_config(conf);
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 42a192f6..175ca095 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -286,6 +286,19 @@ The default is: \fB<unset>\fR
.
.
.TP
+.B ignore_udev_uid
+Setting this option to yes will force multipath to ignore the the uid_attrs
+and uid_attribute settings, and generate the WWID by the \fIsysfs\fR
+method. This will cause devices that cannot get their WWID from the standard
+locations for their device type to not get a WWID; see \fBWWID generation\fR
+below.
+.RS
+.TP
+The default is: \fBno\fR
+.RE
+.
+.
+.TP
.B prio
The name of the path priority routine. The specified routine
should return a numeric value specifying the relative priority
diff --git a/multipathd/main.c b/multipathd/main.c
index f014d2a1..48b62937 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1226,6 +1226,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
if (pp) {
struct multipath *mpp = pp->mpp;
char wwid[WWID_SIZE];
+ int fallback;
if (pp->initialized == INIT_REQUESTED_UDEV) {
needs_reinit = 1;
@@ -1237,7 +1238,11 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
goto out;
strcpy(wwid, pp->wwid);
- rc = get_uid(pp, pp->state, uev->udev, 0);
+ conf = get_multipath_config();
+ fallback = conf->ignore_udev_uid? UID_FALLBACK_FORCE:
+ UID_FALLBACK_NONE;
+ put_multipath_config(conf);
+ rc = get_uid(pp, pp->state, uev->udev, fallback);
if (rc != 0)
strcpy(pp->wwid, wwid);
--
2.17.2

View File

@ -0,0 +1,111 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Wed, 8 Jul 2020 09:23:20 +0200
Subject: [PATCH] libmultipath: util: constify function arguments
Use "const" for function arguments where possible.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/dmparser.c | 2 +-
libmultipath/util.c | 12 ++++++------
libmultipath/util.h | 10 +++++-----
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index b856a07f..27581cde 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -18,7 +18,7 @@
#define WORD_SIZE 64
static int
-merge_words(char **dst, char *word)
+merge_words(char **dst, const char *word)
{
char * p = *dst;
int len, dstlen;
diff --git a/libmultipath/util.c b/libmultipath/util.c
index 51c38c87..67e7a42f 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -52,7 +52,7 @@ basenamecpy (const char *src, char *dst, size_t size)
}
int
-filepresent (char * run) {
+filepresent (const char *run) {
struct stat buf;
if(!stat(run, &buf))
@@ -60,7 +60,7 @@ filepresent (char * run) {
return 0;
}
-char *get_next_string(char **temp, char *split_char)
+char *get_next_string(char **temp, const char *split_char)
{
char *token = NULL;
token = strsep(temp, split_char);
@@ -70,9 +70,9 @@ char *get_next_string(char **temp, char *split_char)
}
int
-get_word (char * sentence, char ** word)
+get_word (const char *sentence, char **word)
{
- char * p;
+ const char *p;
int len;
int skip = 0;
@@ -381,7 +381,7 @@ int get_linux_version_code(void)
return _linux_version_code;
}
-int parse_prkey(char *ptr, uint64_t *prkey)
+int parse_prkey(const char *ptr, uint64_t *prkey)
{
if (!ptr)
return 1;
@@ -398,7 +398,7 @@ int parse_prkey(char *ptr, uint64_t *prkey)
return 0;
}
-int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags)
+int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags)
{
char *flagstr;
diff --git a/libmultipath/util.h b/libmultipath/util.h
index 56bd78c7..c19c5ac3 100644
--- a/libmultipath/util.h
+++ b/libmultipath/util.h
@@ -9,9 +9,9 @@
size_t strchop(char *);
int basenamecpy (const char *src, char *dst, size_t size);
-int filepresent (char * run);
-char *get_next_string(char **temp, char *split_char);
-int get_word (char * sentence, char ** word);
+int filepresent (const char *run);
+char *get_next_string(char **temp, const char *split_char);
+int get_word (const char * sentence, char ** word);
size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size);
int devt2devname (char *, int, char *);
@@ -20,8 +20,8 @@ char *convert_dev(char *dev, int is_path_device);
void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached);
int systemd_service_enabled(const char *dev);
int get_linux_version_code(void);
-int parse_prkey(char *ptr, uint64_t *prkey);
-int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags);
+int parse_prkey(const char *ptr, uint64_t *prkey);
+int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags);
int safe_write(int fd, const void *buf, size_t count);
void set_max_fds(rlim_t max_fds);
--
2.17.2

View File

@ -0,0 +1,99 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:07 +0200
Subject: [PATCH] libmultipath: constify file argument in config parser
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 3 +--
libmultipath/config.h | 2 +-
libmultipath/parser.c | 9 +++++----
libmultipath/parser.h | 2 +-
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index a253a936..1818f8b9 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -718,8 +718,7 @@ static void set_max_checkint_from_watchdog(struct config *conf)
}
#endif
-struct config *
-load_config (char * file)
+struct config *load_config(const char *file)
{
struct config *conf = alloc_config();
diff --git a/libmultipath/config.h b/libmultipath/config.h
index c7a73fba..78375f2f 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -253,7 +253,7 @@ void free_mptable (vector mptable);
int store_hwe (vector hwtable, struct hwentry *);
-struct config *load_config (char * file);
+struct config *load_config (const char *file);
struct config * alloc_config (void);
void free_config (struct config * conf);
extern struct config *get_multipath_config(void);
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index a7285a35..d150e7b2 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -400,7 +400,7 @@ set_regex_value(vector strvec)
/* non-recursive configuration stream handler */
static int kw_level = 0;
-int warn_on_duplicates(vector uniques, char *str, char *file)
+int warn_on_duplicates(vector uniques, char *str, const char *file)
{
char *tmp;
int i;
@@ -444,7 +444,7 @@ is_sublevel_keyword(char *str)
}
int
-validate_config_strvec(vector strvec, char *file)
+validate_config_strvec(vector strvec, const char *file)
{
char *str;
int i;
@@ -507,7 +507,8 @@ validate_config_strvec(vector strvec, char *file)
}
static int
-process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
+process_stream(struct config *conf, FILE *stream, vector keywords,
+ const char *file)
{
int i;
int r = 0, t;
@@ -592,7 +593,7 @@ out:
/* Data initialization */
int
-process_file(struct config *conf, char *file)
+process_file(struct config *conf, const char *file)
{
int r;
FILE *stream;
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
index b7917052..b385fb9e 100644
--- a/libmultipath/parser.h
+++ b/libmultipath/parser.h
@@ -78,7 +78,7 @@ extern void free_keywords(vector keywords);
extern vector alloc_strvec(char *string);
extern void *set_value(vector strvec);
extern void *set_regex_value(vector strvec);
-extern int process_file(struct config *conf, char *conf_file);
+extern int process_file(struct config *conf, const char *conf_file);
extern struct keyword * find_keyword(vector keywords, vector v, char * name);
int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
const void *data);
--
2.17.2

View File

@ -0,0 +1,182 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:08 +0200
Subject: [PATCH] libmultipath: provide defaults for {get,put}_multipath_config
Add an implementation of get_multipath_config() and put_multipath_config()
to libmultipath. The linker's symbol lookup rules will make sure that
applications can override these functions if they need to. Defining
these functions in libmultipath avoids the need to provide stubs
for these functions in every appliation linking to libmultipath.
libmultipath's internal functions simply refer to a static "struct config".
It must be initialized with init_config() rather than load_config(),
which always allocates a new struct for backward compatibility, and must
be teared down using uninit_config().
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 72 +++++++++++++++++++++++++++++++++++++------
libmultipath/config.h | 21 +++++++++++--
2 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 1818f8b9..422e923d 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -28,6 +28,23 @@
#include "propsel.h"
#include "version.h"
+static struct config __internal_config;
+struct config *libmp_get_multipath_config(void)
+{
+ return &__internal_config;
+}
+
+struct config *get_multipath_config(void)
+ __attribute__((weak, alias("libmp_get_multipath_config")));
+
+void libmp_put_multipath_config(void *conf __attribute__((unused)))
+{
+ /* empty */
+}
+
+void put_multipath_config(void *conf)
+ __attribute__((weak, alias("libmp_put_multipath_config")));
+
static int
hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2)
{
@@ -575,17 +592,15 @@ restart:
return;
}
-struct config *
-alloc_config (void)
+static struct config *alloc_config (void)
{
return (struct config *)MALLOC(sizeof(struct config));
}
-void
-free_config (struct config * conf)
+static void _uninit_config(struct config *conf)
{
if (!conf)
- return;
+ conf = &__internal_config;
if (conf->multipath_dir)
FREE(conf->multipath_dir);
@@ -649,7 +664,27 @@ free_config (struct config * conf)
free_hwtable(conf->hwtable);
free_hwe(conf->overrides);
free_keywords(conf->keywords);
- FREE(conf);
+
+ memset(conf, 0, sizeof(*conf));
+}
+
+void uninit_config(void)
+{
+ _uninit_config(&__internal_config);
+}
+
+void free_config(struct config *conf)
+{
+ if (!conf)
+ return;
+ else if (conf == &__internal_config) {
+ condlog(0, "ERROR: %s called for internal config. Use uninit_config() instead",
+ __func__);
+ return;
+ }
+
+ _uninit_config(conf);
+ free(conf);
}
/* if multipath fails to process the config directory, it should continue,
@@ -718,12 +753,29 @@ static void set_max_checkint_from_watchdog(struct config *conf)
}
#endif
+static int _init_config (const char *file, struct config *conf);
+
+int init_config(const char *file)
+{
+ return _init_config(file, &__internal_config);
+}
+
struct config *load_config(const char *file)
{
struct config *conf = alloc_config();
+ if (conf && !_init_config(file, conf))
+ return conf;
+
+ free(conf);
+ return NULL;
+}
+
+int _init_config (const char *file, struct config *conf)
+{
+
if (!conf)
- return NULL;
+ conf = &__internal_config;
/*
* internal defaults
@@ -911,10 +963,10 @@ struct config *load_config(const char *file)
!conf->wwids_file || !conf->prkeys_file)
goto out;
- return conf;
+ return 0;
out:
- free_config(conf);
- return NULL;
+ _uninit_config(conf);
+ return 1;
}
char *get_uid_attribute_by_attrs(struct config *conf,
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 78375f2f..83d179ac 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -254,10 +254,25 @@ void free_mptable (vector mptable);
int store_hwe (vector hwtable, struct hwentry *);
struct config *load_config (const char *file);
-struct config * alloc_config (void);
void free_config (struct config * conf);
-extern struct config *get_multipath_config(void);
-extern void put_multipath_config(void *);
+int init_config(const char *file);
+void uninit_config(void);
+
+/*
+ * libmultipath provides default implementations of
+ * get_multipath_config() and put_multipath_config().
+ * Applications using these should use init_config(file, NULL)
+ * to load the configuration, rather than load_config(file).
+ * Likewise, uninit_config() should be used for teardown, but
+ * using free_config() for that is supported, too.
+ * Applications can define their own {get,put}_multipath_config()
+ * functions, which override the library-internal ones, but
+ * could still call libmp_{get,put}_multipath_config().
+ */
+struct config *libmp_get_multipath_config(void);
+struct config *get_multipath_config(void);
+void libmp_put_multipath_config(void *);
+void put_multipath_config(void *);
int parse_uid_attrs(char *uid_attrs, struct config *conf);
char *get_uid_attribute_by_attrs(struct config *conf,
--
2.17.2

View File

@ -0,0 +1,142 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:09 +0200
Subject: [PATCH] libmpathpersist: allow using libmultipath
{get,put}_multipath_config
Provide an alternative init function libmpathpersist_init() which
avoids allocating a new struct config, simply using libmultipath's
internal implementation.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_persist.c | 42 ++++++++++++++++++++++++++++-----
libmpathpersist/mpath_persist.h | 28 ++++++++++++++++++++++
2 files changed, 64 insertions(+), 6 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index a132f4e9..9dfc98cd 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -37,6 +37,27 @@
extern struct udev *udev;
+static void adapt_config(struct config *conf)
+{
+ conf->force_sync = 1;
+ set_max_fds(conf->max_fds);
+}
+
+int libmpathpersist_init(void)
+{
+ struct config *conf;
+ int rc = 0;
+
+ if (init_config(DEFAULT_CONFIGFILE)) {
+ condlog(0, "Failed to initialize multipath config.");
+ return 1;
+ }
+ conf = libmp_get_multipath_config();
+ adapt_config(conf);
+ libmp_put_multipath_config(conf);
+ return rc;
+}
+
struct config *
mpath_lib_init (void)
{
@@ -47,21 +68,30 @@ mpath_lib_init (void)
condlog(0, "Failed to initialize multipath config.");
return NULL;
}
- conf->force_sync = 1;
- set_max_fds(conf->max_fds);
-
+ adapt_config(conf);
return conf;
}
-int
-mpath_lib_exit (struct config *conf)
+static void libmpathpersist_cleanup(void)
{
dm_lib_release();
dm_lib_exit();
cleanup_prio();
cleanup_checkers();
+}
+
+int
+mpath_lib_exit (struct config *conf)
+{
+ libmpathpersist_cleanup();
free_config(conf);
- conf = NULL;
+ return 0;
+}
+
+int libmpathpersist_exit(void)
+{
+ libmpathpersist_cleanup();
+ uninit_config();
return 0;
}
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
index 7cf4faf9..91606efc 100644
--- a/libmpathpersist/mpath_persist.h
+++ b/libmpathpersist/mpath_persist.h
@@ -175,6 +175,22 @@ struct prout_param_descriptor { /* PROUT parameter descriptor */
* DESCRIPTION :
* Initialize device mapper multipath configuration. This function must be invoked first
* before performing reservation management functions.
+ * Either this function or mpath_lib_init() may be used.
+ * Use this function to work with libmultipath's internal "struct config".
+ * Call libmpathpersist_exit() for cleanup.
+ * RESTRICTIONS:
+ *
+ * RETURNS: 0->Success, 1->Failed.
+ */
+extern int libmpathpersist_init (void);
+
+/*
+ * DESCRIPTION :
+ * Initialize device mapper multipath configuration. This function must be invoked first
+ * before performing reservation management functions.
+ * Either this function or libmpathpersist_init() may be used.
+ * Use this function to work with an application-specific "struct config".
+ * Call mpath_lib_exit() for cleanup.
* RESTRICTIONS:
*
* RETURNS: struct config ->Success, NULL->Failed.
@@ -186,12 +202,24 @@ extern struct config * mpath_lib_init (void);
* DESCRIPTION :
* Release device mapper multipath configuration. This function must be invoked after
* performing reservation management functions.
+ * Use this after initialization with mpath_lib_init().
* RESTRICTIONS:
*
* RETURNS: 0->Success, 1->Failed.
*/
extern int mpath_lib_exit (struct config *conf);
+/*
+ * DESCRIPTION :
+ * Release device mapper multipath configuration. This function must be invoked after
+ * performing reservation management functions.
+ * Use this after initialization with libmpathpersist_init().
+ * RESTRICTIONS:
+ *
+ * RETURNS: 0->Success, 1->Failed.
+ */
+extern int libmpathpersist_exit (void);
+
/*
* DESCRIPTION :
--
2.17.2

View File

@ -0,0 +1,68 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:10 +0200
Subject: [PATCH] multipath: use {get_put}_multipath_config from libmultipath
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/multipath/main.c b/multipath/main.c
index ce48a932..879d7ac9 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -67,7 +67,6 @@
int logsink;
struct udev *udev;
-struct config *multipath_conf;
/*
* Return values of configure(), check_path_valid(), and main().
@@ -78,16 +77,6 @@ enum {
RTVL_RETRY, /* returned by configure(), not by main() */
};
-struct config *get_multipath_config(void)
-{
- return multipath_conf;
-}
-
-void put_multipath_config(__attribute__((unused)) void *arg)
-{
- /* Noop for now */
-}
-
static int
dump_config (struct config *conf, vector hwes, vector mpvec)
{
@@ -892,10 +881,9 @@ main (int argc, char *argv[])
udev = udev_new();
logsink = 0;
- conf = load_config(DEFAULT_CONFIGFILE);
- if (!conf)
+ if (init_config(DEFAULT_CONFIGFILE))
exit(RTVL_FAIL);
- multipath_conf = conf;
+ conf = get_multipath_config();
conf->retrigger_tries = 0;
conf->force_sync = 1;
while ((arg = getopt(argc, argv, ":aAdDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
@@ -1148,8 +1136,8 @@ out_free_config:
* the logging function (dm_write_log()), which is called there,
* references the config.
*/
- free_config(conf);
- conf = NULL;
+ put_multipath_config(conf);
+ uninit_config();
udev_unref(udev);
if (dev)
FREE(dev);
--
2.17.2

View File

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:11 +0200
Subject: [PATCH] mpathpersist: use {get,put}_multipath_config() from
libmultipath
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
mpathpersist/main.c | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
index 28bfe410..0f0db4b8 100644
--- a/mpathpersist/main.c
+++ b/mpathpersist/main.c
@@ -43,17 +43,6 @@ void mpath_print_transport_id(struct prin_fulldescr *fdesc);
int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
int logsink;
-struct config *multipath_conf;
-
-struct config *get_multipath_config(void)
-{
- return multipath_conf;
-}
-
-void put_multipath_config(__attribute__((unused)) void * arg)
-{
- /* Noop for now */
-}
void rcu_register_thread_memb(void) {}
@@ -620,15 +609,14 @@ int main(int argc, char *argv[])
}
udev = udev_new();
- multipath_conf = mpath_lib_init();
- if(!multipath_conf) {
+ if (libmpathpersist_init()) {
udev_unref(udev);
exit(1);
}
ret = handle_args(argc, argv, 0);
- mpath_lib_exit(multipath_conf);
+ libmpathpersist_exit();
udev_unref(udev);
return (ret >= 0) ? ret : MPATH_PR_OTHER;
--
2.17.2

View File

@ -0,0 +1,156 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:12 +0200
Subject: [PATCH] libmultipath: add udev and logsink symbols
With these symbols added, applications using libmultipath don't
need to define global variables "udev" and "logsink" any more.
This comes at the cost of having to call an init function.
Currently, libmultipath_init() does nothing but initialize
"udev".
The linker's symbol lookup order still allows applications to use
their own "logsink" and "udev" variables, which will take precendence
over libmultipath's internal ones. In this case, calling
libmultipath_init() can be skipped, but like before,
udev should be initialized (using udev_new()) before making any
libmultipath calls.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.c | 46 +++++++++++++++++++++++++++++++++++++++++++
libmultipath/config.h | 46 ++++++++++++++++++++++++++++++++++++++++++-
libmultipath/debug.c | 2 ++
3 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 422e923d..b3809433 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -28,6 +28,52 @@
#include "propsel.h"
#include "version.h"
+/*
+ * We don't support re-initialization after
+ * libmultipath_exit().
+ */
+static bool libmultipath_exit_called;
+static pthread_once_t _init_once = PTHREAD_ONCE_INIT;
+static pthread_once_t _exit_once = PTHREAD_ONCE_INIT;
+struct udev *udev;
+
+static void _udev_init(void)
+{
+ if (udev)
+ udev_ref(udev);
+ else
+ udev = udev_new();
+ if (!udev)
+ condlog(0, "%s: failed to initialize udev", __func__);
+}
+
+static void _libmultipath_init(void)
+{
+ _udev_init();
+}
+
+static bool _is_libmultipath_initialized(void)
+{
+ return !libmultipath_exit_called && !!udev;
+}
+
+int libmultipath_init(void)
+{
+ pthread_once(&_init_once, _libmultipath_init);
+ return !_is_libmultipath_initialized();
+}
+
+static void _libmultipath_exit(void)
+{
+ libmultipath_exit_called = true;
+ udev_unref(udev);
+}
+
+void libmultipath_exit(void)
+{
+ pthread_once(&_exit_once, _libmultipath_exit);
+}
+
static struct config __internal_config;
struct config *libmp_get_multipath_config(void)
{
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 83d179ac..089b2ac2 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -235,7 +235,51 @@ struct config {
char *enable_foreign;
};
-extern struct udev * udev;
+/**
+ * extern variable: udev
+ *
+ * A &struct udev instance used by libmultipath. libmultipath expects
+ * a valid, initialized &struct udev in this variable.
+ * An application can define this variable itself, in which case
+ * the applications's instance will take precedence.
+ * The application can initialize and destroy this variable by
+ * calling libmultipath_init() and libmultipath_exit(), respectively,
+ * whether or not it defines the variable itself.
+ * An application can initialize udev with udev_new() before calling
+ * libmultipath_init(), e.g. if it has to make libudev calls before
+ * libmultipath calls. If an application wants to keep using the
+ * udev variable after calling libmultipath_exit(), it should have taken
+ * an additional reference on it beforehand. This is the case e.g.
+ * after initiazing udev with udev_new().
+ */
+extern struct udev *udev;
+
+/**
+ * libmultipath_init() - library initialization
+ *
+ * This function initializes libmultipath data structures.
+ * It is light-weight; some other initializations, like device-mapper
+ * initialization, are done lazily when the respective functionality
+ * is required.
+ *
+ * Clean up by libmultipath_exit() when the program terminates.
+ * It is an error to call libmultipath_init() after libmultipath_exit().
+ * Return: 0 on success, 1 on failure.
+ */
+int libmultipath_init(void);
+
+/**
+ * libmultipath_exit() - library un-initialization
+ *
+ * This function un-initializes libmultipath data structures.
+ * It is recommended to call this function at program exit.
+ *
+ * Calls to libmultipath_init() after libmultipath_exit() will fail
+ * (in other words, libmultipath can't be re-initialized).
+ * Any other libmultipath calls after libmultipath_exit() may cause
+ * undefined behavior.
+ */
+void libmultipath_exit(void);
int find_hwe (const struct _vector *hwtable,
const char * vendor, const char * product, const char *revision,
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
index 4128cb90..b3a1de9e 100644
--- a/libmultipath/debug.c
+++ b/libmultipath/debug.c
@@ -15,6 +15,8 @@
#include "defaults.h"
#include "debug.h"
+int logsink;
+
void dlog (int sink, int prio, const char * fmt, ...)
{
va_list ap;
--
2.17.2

View File

@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:13 +0200
Subject: [PATCH] multipath: remove logsink and udev
We can use libmultipath's symbols now.
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipath/main.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/multipath/main.c b/multipath/main.c
index 879d7ac9..322b30e0 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -65,9 +65,6 @@
#include "file.h"
#include "valid.h"
-int logsink;
-struct udev *udev;
-
/*
* Return values of configure(), check_path_valid(), and main().
*/
@@ -879,7 +876,7 @@ main (int argc, char *argv[])
int retries = -1;
bool enable_foreign = false;
- udev = udev_new();
+ libmultipath_init();
logsink = 0;
if (init_config(DEFAULT_CONFIGFILE))
exit(RTVL_FAIL);
@@ -1138,7 +1135,7 @@ out_free_config:
*/
put_multipath_config(conf);
uninit_config();
- udev_unref(udev);
+ libmultipath_exit();
if (dev)
FREE(dev);
#ifdef _DEBUG_
--
2.17.2

View File

@ -0,0 +1,98 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:14 +0200
Subject: [PATCH] libmpathpersist: call libmultipath_{init,exit}()
Have libmpathpersist_{init,exit} do the udev initialization, too.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathpersist/mpath_persist.c | 13 +++++++++----
libmpathpersist/mpath_persist.h | 9 ++++++---
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index 9dfc98cd..d1538195 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -48,6 +48,10 @@ int libmpathpersist_init(void)
struct config *conf;
int rc = 0;
+ if (libmultipath_init()) {
+ condlog(0, "Failed to initialize libmultipath.");
+ return 1;
+ }
if (init_config(DEFAULT_CONFIGFILE)) {
condlog(0, "Failed to initialize multipath config.");
return 1;
@@ -74,24 +78,25 @@ mpath_lib_init (void)
static void libmpathpersist_cleanup(void)
{
- dm_lib_release();
- dm_lib_exit();
cleanup_prio();
cleanup_checkers();
+ libmultipath_exit();
+ dm_lib_release();
+ dm_lib_exit();
}
int
mpath_lib_exit (struct config *conf)
{
- libmpathpersist_cleanup();
free_config(conf);
+ libmpathpersist_cleanup();
return 0;
}
int libmpathpersist_exit(void)
{
- libmpathpersist_cleanup();
uninit_config();
+ libmpathpersist_cleanup();
return 0;
}
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
index 91606efc..5435eae4 100644
--- a/libmpathpersist/mpath_persist.h
+++ b/libmpathpersist/mpath_persist.h
@@ -176,7 +176,8 @@ struct prout_param_descriptor { /* PROUT parameter descriptor */
* Initialize device mapper multipath configuration. This function must be invoked first
* before performing reservation management functions.
* Either this function or mpath_lib_init() may be used.
- * Use this function to work with libmultipath's internal "struct config".
+ * Use this function to work with libmultipath's internal "struct config"
+ * and "struct udev". The latter will be initialized automatically.
* Call libmpathpersist_exit() for cleanup.
* RESTRICTIONS:
*
@@ -189,7 +190,8 @@ extern int libmpathpersist_init (void);
* Initialize device mapper multipath configuration. This function must be invoked first
* before performing reservation management functions.
* Either this function or libmpathpersist_init() may be used.
- * Use this function to work with an application-specific "struct config".
+ * Use this function to work with an application-specific "struct config"
+ * and "struct udev". The latter must be initialized by the application.
* Call mpath_lib_exit() for cleanup.
* RESTRICTIONS:
*
@@ -211,9 +213,10 @@ extern int mpath_lib_exit (struct config *conf);
/*
* DESCRIPTION :
- * Release device mapper multipath configuration. This function must be invoked after
+ * Release device mapper multipath configuration a. This function must be invoked after
* performing reservation management functions.
* Use this after initialization with libmpathpersist_init().
+ * Calling libmpathpersist_init() after libmpathpersist_exit() will fail.
* RESTRICTIONS:
*
* RETURNS: 0->Success, 1->Failed.
--
2.17.2

View File

@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:15 +0200
Subject: [PATCH] mpathpersist: remove logsink and udev
We can use libmultipath's internal symbols now. The libmultipath
initialization is taken care of by libmpathpersist_init().
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
mpathpersist/main.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
index 0f0db4b8..a25b08f0 100644
--- a/mpathpersist/main.c
+++ b/mpathpersist/main.c
@@ -42,13 +42,10 @@ void * mpath_alloc_prin_response(int prin_sa);
void mpath_print_transport_id(struct prin_fulldescr *fdesc);
int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
-int logsink;
-
void rcu_register_thread_memb(void) {}
void rcu_unregister_thread_memb(void) {}
-struct udev *udev;
static int verbose, loglevel, noisy;
@@ -608,16 +605,13 @@ int main(int argc, char *argv[])
exit (1);
}
- udev = udev_new();
if (libmpathpersist_init()) {
- udev_unref(udev);
exit(1);
}
ret = handle_args(argc, argv, 0);
libmpathpersist_exit();
- udev_unref(udev);
return (ret >= 0) ? ret : MPATH_PR_OTHER;
}
--
2.17.2

View File

@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 24 Sep 2020 15:37:16 +0200
Subject: [PATCH] multipathd: remove logsink and udev
We can use the symbols from libmultipath now.
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
multipathd/main.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 48b62937..6a4b8b83 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -113,7 +113,6 @@ struct mpath_event_param
struct multipath *mpp;
};
-int logsink;
int uxsock_timeout;
int verbosity;
int bindings_read_only;
@@ -144,8 +143,6 @@ static inline enum daemon_status get_running_state(void)
*/
struct vectors * gvecs;
-struct udev * udev;
-
struct config *multipath_conf;
/* Local variables */
@@ -3009,8 +3006,6 @@ child (__attribute__((unused)) void *param)
conf = rcu_dereference(multipath_conf);
rcu_assign_pointer(multipath_conf, NULL);
call_rcu(&conf->rcu, rcu_free_config);
- udev_unref(udev);
- udev = NULL;
pthread_attr_destroy(&waiter_attr);
pthread_attr_destroy(&io_err_stat_attr);
#ifdef _DEBUG_
@@ -3114,7 +3109,9 @@ main (int argc, char *argv[])
pthread_cond_init_mono(&config_cond);
- udev = udev_new();
+ libmultipath_init();
+ if (atexit(libmultipath_exit))
+ condlog(3, "failed to register exit handler for libmultipath");
libmp_udev_set_sync_support(0);
while ((arg = getopt(argc, argv, ":dsv:k::Bniw")) != EOF ) {
--
2.17.2

View File

@ -0,0 +1,180 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Sat, 26 Sep 2020 23:25:46 -0500
Subject: [PATCH] libmpathvalid: use default *_multipath_config, udev, and
logsink
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmpathvalid/libmpathvalid.version | 2 +-
libmpathvalid/mpath_valid.c | 73 ++++++++++++++++++++---------
libmpathvalid/mpath_valid.h | 12 +++--
3 files changed, 61 insertions(+), 26 deletions(-)
diff --git a/libmpathvalid/libmpathvalid.version b/libmpathvalid/libmpathvalid.version
index 4d8a8ba4..3bd0d3c5 100644
--- a/libmpathvalid/libmpathvalid.version
+++ b/libmpathvalid/libmpathvalid.version
@@ -1,7 +1,7 @@
MPATH_1.0 {
global:
- mpathvalid_conf;
mpathvalid_init;
+ mpathvalid_reload_config;
mpathvalid_exit;
mpathvalid_is_path;
mpathvalid_get_mode;
diff --git a/libmpathvalid/mpath_valid.c b/libmpathvalid/mpath_valid.c
index 6153e8b7..d839dbac 100644
--- a/libmpathvalid/mpath_valid.c
+++ b/libmpathvalid/mpath_valid.c
@@ -15,9 +15,7 @@
#include "mpath_cmd.h"
#include "valid.h"
#include "mpath_valid.h"
-
-static struct config default_config = { .verbosity = -1 };
-struct config *mpathvalid_conf = &default_config;
+#include "debug.h"
static unsigned int get_conf_mode(struct config *conf)
{
@@ -68,38 +66,70 @@ static int convert_result(int result) {
}
int
-mpathvalid_init(int verbosity)
+mpathvalid_init(int verbosity, int log_style)
{
unsigned int version[3];
struct config *conf;
- default_config.verbosity = verbosity;
- skip_libmp_dm_init();
- conf = load_config(DEFAULT_CONFIGFILE);
- if (!conf)
+ logsink = log_style;
+ if (libmultipath_init())
return -1;
+ conf = get_multipath_config();
conf->verbosity = verbosity;
- if (dm_prereq(version))
+ put_multipath_config(conf);
+
+ skip_libmp_dm_init();
+ if (init_config(DEFAULT_CONFIGFILE))
goto fail;
- memcpy(conf->version, version, sizeof(version));
+ if (dm_prereq(version))
+ goto fail_config;
- mpathvalid_conf = conf;
+ conf = get_multipath_config();
+ conf->verbosity = verbosity;
+ memcpy(conf->version, version, sizeof(version));
+ put_multipath_config(conf);
return 0;
+
+fail_config:
+ uninit_config();
fail:
- free_config(conf);
+ libmultipath_exit();
return -1;
}
int
-mpathvalid_exit(void)
+mpathvalid_reload_config(void)
{
- struct config *conf = mpathvalid_conf;
+ int verbosity;
+ unsigned int version[3];
+ struct config *conf;
+
+ conf = get_multipath_config();
+ memcpy(version, conf->version, sizeof(version));
+ verbosity = conf->verbosity;
+ put_multipath_config(conf);
- default_config.verbosity = -1;
- if (mpathvalid_conf == &default_config)
- return 0;
- mpathvalid_conf = &default_config;
- free_config(conf);
+ uninit_config();
+
+ conf = get_multipath_config();
+ conf->verbosity = verbosity;
+ put_multipath_config(conf);
+
+ if (init_config(DEFAULT_CONFIGFILE))
+ return -1;
+
+ conf = get_multipath_config();
+ conf->verbosity = verbosity;
+ memcpy(conf->version, version, sizeof(version));
+ put_multipath_config(conf);
+ return 0;
+}
+
+int
+mpathvalid_exit(void)
+{
+ uninit_config();
+ libmultipath_exit();
return 0;
}
@@ -121,9 +151,10 @@ mpathvalid_is_path(const char *name, unsigned int mode, char **wwid,
if (!name || mode >= MPATH_MAX_MODE)
return r;
-
if (nr_paths > 0 && !path_wwids)
return r;
+ if (!udev)
+ return r;
pp = alloc_path();
if (!pp)
@@ -136,7 +167,7 @@ mpathvalid_is_path(const char *name, unsigned int mode, char **wwid,
}
conf = get_multipath_config();
- if (!conf || conf == &default_config)
+ if (!conf)
goto out_wwid;
if (mode != MPATH_DEFAULT)
set_conf_mode(conf, mode);
diff --git a/libmpathvalid/mpath_valid.h b/libmpathvalid/mpath_valid.h
index 7fd8aa47..c83b8da5 100644
--- a/libmpathvalid/mpath_valid.h
+++ b/libmpathvalid/mpath_valid.h
@@ -42,15 +42,19 @@ enum mpath_valid_result {
MPATH_IS_MAYBE_VALID,
};
-struct config;
-extern struct config *mpathvalid_conf;
-int mpathvalid_init(int verbosity);
+enum mpath_valid_log_style {
+ MPATH_LOG_STDIO = -1,
+ MPATH_LOG_STDIO_TIMESTAMP,
+ MPATH_LOG_SYSLOG,
+};
+
+int mpathvalid_init(int verbosity, int log_style);
+int mpathvalid_reload_config(void);
int mpathvalid_exit(void);
unsigned int mpathvalid_get_mode(void);
int mpathvalid_is_path(const char *name, unsigned int mode, char **wwid,
const char **path_wwids, unsigned int nr_paths);
-
#ifdef __cplusplus
}
#endif
--
2.17.2

View File

@ -0,0 +1,186 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Sat, 26 Sep 2020 23:26:32 -0500
Subject: [PATCH] Revert "libmultipath: add ignore_udev_uid option"
This reverts commit f1350bc5c4aa445804f3f4fc8968fb46d581336e.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/config.h | 1 -
libmultipath/dict.c | 4 ----
libmultipath/discovery.c | 17 ++++++-----------
libmultipath/discovery.h | 8 +-------
libmultipath/uevent.c | 2 +-
multipath/multipath.conf.5 | 13 -------------
multipathd/main.c | 7 +------
7 files changed, 9 insertions(+), 43 deletions(-)
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 089b2ac2..576f15d1 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -192,7 +192,6 @@ struct config {
int find_multipaths_timeout;
int marginal_pathgroups;
int skip_delegate;
- int ignore_udev_uid;
unsigned int version[3];
unsigned int sequence_nr;
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 9a0729bf..184d4b22 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -1406,9 +1406,6 @@ declare_hw_snprint(all_tg_pt, print_yes_no_undef)
declare_def_handler(marginal_pathgroups, set_yes_no)
declare_def_snprint(marginal_pathgroups, print_yes_no)
-declare_def_handler(ignore_udev_uid, set_yes_no)
-declare_def_snprint(ignore_udev_uid, print_yes_no)
-
static int
def_uxsock_timeout_handler(struct config *conf, vector strvec)
{
@@ -1819,7 +1816,6 @@ init_keywords(vector keywords)
install_keyword("enable_foreign", &def_enable_foreign_handler,
&snprint_def_enable_foreign);
install_keyword("marginal_pathgroups", &def_marginal_pathgroups_handler, &snprint_def_marginal_pathgroups);
- install_keyword("ignore_udev_uid", &def_ignore_udev_uid_handler, &snprint_def_ignore_udev_uid);
__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/libmultipath/discovery.c b/libmultipath/discovery.c
index f0e92227..002d3d18 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -2010,7 +2010,7 @@ static bool has_uid_fallback(struct path *pp)
int
get_uid (struct path * pp, int path_state, struct udev_device *udev,
- int fallback)
+ int allow_fallback)
{
char *c;
const char *origin = "unknown";
@@ -2043,9 +2043,7 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
} else
len = strlen(pp->wwid);
origin = "callout";
- } else if (fallback == UID_FALLBACK_FORCE)
- len = uid_fallback(pp, path_state, &origin);
- else {
+ } else {
bool udev_available = udev && pp->uid_attribute
&& *pp->uid_attribute;
@@ -2058,9 +2056,8 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
else
origin = "udev";
}
- if ((!udev_available ||
- (len <= 0 && fallback == UID_FALLBACK_ALLOW)) &&
- has_uid_fallback(pp)) {
+ if ((!udev_available || (len <= 0 && allow_fallback))
+ && has_uid_fallback(pp)) {
used_fallback = 1;
len = uid_fallback(pp, path_state, &origin);
}
@@ -2200,10 +2197,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
}
if ((mask & DI_WWID) && !strlen(pp->wwid)) {
- int fallback = conf->ignore_udev_uid? UID_FALLBACK_FORCE :
- (pp->retriggers >= conf->retrigger_tries)?
- UID_FALLBACK_ALLOW : UID_FALLBACK_NONE;
- get_uid(pp, path_state, pp->udev, fallback);
+ get_uid(pp, path_state, pp->udev,
+ (pp->retriggers >= conf->retrigger_tries));
if (!strlen(pp->wwid)) {
if (pp->bus == SYSFS_BUS_UNDEF)
return PATHINFO_SKIPPED;
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index ca8542d6..6444887d 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -54,14 +54,8 @@ ssize_t sysfs_get_inquiry(struct udev_device *udev,
unsigned char *buff, size_t len);
int sysfs_get_asymmetric_access_state(struct path *pp,
char *buff, int buflen);
-
-enum {
- UID_FALLBACK_NONE,
- UID_FALLBACK_ALLOW,
- UID_FALLBACK_FORCE,
-};
int get_uid(struct path * pp, int path_state, struct udev_device *udev,
- int fallback);
+ int allow_fallback);
/*
* discovery bitmask
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index d67129d1..e0d13b11 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -179,7 +179,7 @@ uevent_need_merge(void)
bool need_merge = false;
conf = get_multipath_config();
- if (!conf->ignore_udev_uid && VECTOR_SIZE(&conf->uid_attrs) > 0)
+ if (VECTOR_SIZE(&conf->uid_attrs) > 0)
need_merge = true;
put_multipath_config(conf);
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 175ca095..42a192f6 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -286,19 +286,6 @@ The default is: \fB<unset>\fR
.
.
.TP
-.B ignore_udev_uid
-Setting this option to yes will force multipath to ignore the the uid_attrs
-and uid_attribute settings, and generate the WWID by the \fIsysfs\fR
-method. This will cause devices that cannot get their WWID from the standard
-locations for their device type to not get a WWID; see \fBWWID generation\fR
-below.
-.RS
-.TP
-The default is: \fBno\fR
-.RE
-.
-.
-.TP
.B prio
The name of the path priority routine. The specified routine
should return a numeric value specifying the relative priority
diff --git a/multipathd/main.c b/multipathd/main.c
index 6a4b8b83..94926b57 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1223,7 +1223,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
if (pp) {
struct multipath *mpp = pp->mpp;
char wwid[WWID_SIZE];
- int fallback;
if (pp->initialized == INIT_REQUESTED_UDEV) {
needs_reinit = 1;
@@ -1235,11 +1234,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
goto out;
strcpy(wwid, pp->wwid);
- conf = get_multipath_config();
- fallback = conf->ignore_udev_uid? UID_FALLBACK_FORCE:
- UID_FALLBACK_NONE;
- put_multipath_config(conf);
- rc = get_uid(pp, pp->state, uev->udev, fallback);
+ rc = get_uid(pp, pp->state, uev->udev, 0);
if (rc != 0)
strcpy(pp->wwid, wwid);
--
2.17.2

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 22 Sep 2020 16:03:31 -0500
Subject: [PATCH] libmultipath: change log level for null uid_attribute
If uid_attribute is explicitly set to an empty string, multipath should
log the uid at the default log level, since using the fallback code is
the expected behavior.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/discovery.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 002d3d18..77468524 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -2058,7 +2058,8 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
}
if ((!udev_available || (len <= 0 && allow_fallback))
&& has_uid_fallback(pp)) {
- used_fallback = 1;
+ if (udev_available || !(udev && pp->uid_attribute))
+ used_fallback = 1;
len = uid_fallback(pp, path_state, &origin);
}
}
--
2.17.2

View File

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Tue, 11 Aug 2020 21:08:27 +0200
Subject: [PATCH] libmultipath: orphan_paths(): avoid BUG message
Since c44d769, we print a BUG message when we orphan a path that
holds the mpp->hwe pointer. But if this called via orphan_paths(),
this is expected and we shouldn't warn.
Fixes: c44d769 ("libmultipath: warn if freeing path that holds mpp->hwe")
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index ede14297..d70bb6ad 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -114,6 +114,8 @@ void orphan_paths(vector pathvec, struct multipath *mpp, const char *reason)
int i;
struct path * pp;
+ /* Avoid BUG message from orphan_path() */
+ mpp->hwe = NULL;
vector_foreach_slot (pathvec, pp, i) {
if (pp->mpp == mpp) {
orphan_path(pp, reason);
--
2.17.2

1898
device-mapper-multipath.spec Normal file

File diff suppressed because it is too large Load Diff

2
sources Normal file
View File

@ -0,0 +1,2 @@
SHA512 (multipath-tools-0.8.4.tgz) = 130308e61d6dce31085fc2763219f4df0f3ad9153e0e6e7a5a1c3c948a2305cff9413699025c28f9b81dd24d2a9263f9fa825253060e44232c3bb6600cd1f07f
SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942

1
tests/.fmf/version Normal file
View File

@ -0,0 +1 @@
1

675
tests/bindings/LICENSE Normal file
View File

@ -0,0 +1,675 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

7
tests/bindings/PURPOSE Normal file
View File

@ -0,0 +1,7 @@
make sure modify /etc/multipath/bindings changes alias
steps:
1. edit the /etc/multipath/bindings
2. multipath -r
check if the mpath is changed

57
tests/bindings/main.sh Executable file
View File

@ -0,0 +1,57 @@
#!/bin/bash
# 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 <http://www.gnu.org/licenses/>.
# Author: Lin Li <lilin@redhat.com>
#set -x
source ../include/ec.sh || exit 200
tlog "running $0"
trun "service multipathd stop"
rpm -q device-mapper-multipath || yum install -y device-mapper-multipath
trun "mpathconf --enable --with_multipathd y --user_friendly_names y"
trun "service multipathd status"
sleep 5
trun "multipath -F"
sleep 5
terr "modprobe -r scsi_debug"
terr "modprobe scsi_debug num_tgts=1 vpd_use_hostno=0 add_host=2 delay=20 \
max_luns=2 no_lun_0=1"
sleep 60
disk_path=$(get_scsi_debug_devices)
disk=$(basename $disk_path)
mpath_name=$(get_mpath_disk_by_scsi_device $disk)
new_alias="mpath_test_$$"
trun "sed -i 's/$mpath_name/$new_alias/' /etc/multipath/bindings"
trun "multipath -r"
sleep 5
tok "[[ -b /dev/mapper/$new_alias ]]"
tok is_mpath $new_alias
sleep 5
trun "multipath -F"
sleep 5
trun "modprobe -r scsi_debug"
trun "service multipathd stop"
sleep 3
trun "multipath -W"
trun "rm /etc/multipath/bindings"
tend

View File

@ -0,0 +1,675 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,49 @@
#!/bin/bash
# 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 <http://www.gnu.org/licenses/>.
#
# # Author: Lin Li <lilin@redhat.com>
.PHONY: all install download clean
BUILT_FILES=
FILES=$(METADATA) Makefile PURPOSE main.sh
run: $(FILES) build
./main.sh
build: $(BUILT_FILES)
chmod a+x ./main.sh
clean:
rm -f *~ *.rpm $(BUILT_FILES)
include /usr/share/rhts/lib/rhts-make.include
$(METADATA): Makefile
@touch $(METADATA)
@echo "Owner: LiLin <lilin@redhat.com>" > $(METADATA)
@echo "Name: $(TEST)" >> $(METADATA)
@echo "Path: $(TEST_DIR)" >> $(METADATA)
@echo "License: GPLv3" >> $(METADATA)
@echo "TestVersion: $(TESTVERSION)" >> $(METADATA)
@echo "Description: find_multipaths" >> $(METADATA)
@echo "TestTime: 15m" >> $(METADATA)
@echo "RunFor: device-mapper-multipath" >> $(METADATA)
@echo "Requires: device-mapper-multipath" >> $(METADATA)
rhts-lint $(METADATA)

View File

@ -0,0 +1,10 @@
testing environment:
1. enable|disable find_multipaths and do multipath reload
mpathconf --find_multipaths y|n --with_multipathd y
test cases:
1. find_multipaths = no
multipath will not blacklist the single devices
2. find_multipaths = yes
multipath will blacklist the single devices
multipath will not blacklist the non-single devices

94
tests/find_multipaths/main.sh Executable file
View File

@ -0,0 +1,94 @@
#!/bin/bash
# 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 <http://www.gnu.org/licenses/>.
# Author: Lin Li <lilin@redhat.com>
#set -x
source ../include/ec.sh || exit 200
tlog "running $0"
# which not set find_multipaths yes, so multipath always create a multipath device for single device
# so stop service and reconfig with --find_multipaths y, and reload/start the service again.
trun "service multipathd stop"
rpm -q device-mapper-multipath || yum install -y device-mapper-multipath
# test with find_multipath=y, will not multipath for the single device; reload/start the service to enable the config
trun "mpathconf --enable --user_friendly_names y --find_multipaths y --with_multipathd y"
trun "service multipathd status"
# use scsi_debug to simulate a drive
trun "multipath -F"
terr "modprobe -r scsi_debug"
trun "modprobe scsi_debug"
sleep 3
trun "multipath -W"
cat /etc/multipath/wwids
trun "multipath"
disk_path=$(get_scsi_debug_devices)
disk_node=$(basename $disk_path)
mpath_name=$(get_mpath_disk_by_scsi_device $disk_node)
tok '[[ -z $mpath_name ]]'
# test with find_multipath=n, will multipath for the single device
trun "mpathconf --enable --user_friendly_names y --find_multipaths n --with_multipathd y"
sleep 5
trun "multipath"
mpath_name=$(get_mpath_disk_by_scsi_device $disk_node)
tok "is_mpath $mpath_name"
# flush new created path
sleep 3
trun "multipath -F"
sleep 3
# test with find_multipath=y, A path has the same WWID as a multipath device that was previously created
trun "mpathconf --enable --user_friendly_names y --find_multipaths y --with_multipathd y"
sleep 5
trun "multipath"
mpath_name=$(get_mpath_disk_by_scsi_device $disk_node)
tok "is_mpath $mpath_name"
# Clear wwid, test with find_multipath=y, will not multipath for the single device
trun "multipath -W"
trun "mpathconf --disable --with_multipathd y"
sleep 5
mpath_name=$(get_mpath_disk_by_scsi_device $disk_node)
tok '[[ -z $mpath_name ]]'
trun "multipath -F"
sleep 5
trun "modprobe -r scsi_debug"
# test find_multipaths=y create device for paths have same wwid
tok "modprobe scsi_debug num_tgts=1 vpd_use_hostno=0 add_host=2 delay=20 max_luns=2 no_lun_0=1"
sleep 10
disk_paths=$(get_scsi_debug_devices)
disk_node=$(basename $disk_paths)
mpath_name=$(get_mpath_disk_by_scsi_device $disk_node)
tok "is_mpath $mpath_name"
sleep 10
trun "multipath -F"
sleep 5
trun "modprobe -r scsi_debug"
# remove the scsi_debug wwid
trun "service multipathd stop"
sleep 3
trun "multipath -W"
cat /etc/multipath/wwids
tend

256
tests/include/ec.sh Executable file
View File

@ -0,0 +1,256 @@
#!/bin/bash
# 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 <http://www.gnu.org/licenses/>.
# Author: Lin Li <lilin@redhat.com>
path=$(pwd)
source ../include/utils.sh || exit 1
source ../include/include.sh || exit 1
source ../include/tc.sh || exit 1
source ../include/mpath.sh || exit 1
source ../include/scsi_debug.sh || exit 1
#this script usually is only used by current case
#private global variables, lower case and no under line is okay
mpath=
function _isconfig (){
[ -z $mpath ] && return 2
Cmd "multipath -ll $mpath"
}
function _init (){
#will improve this function
#should return the multipathed disk created by scsi_debug, don't consider the other mutipathed disks
#olnly append the black list exception to /etc/multipath.conf not override
Setup_Multipath || Fail "failed to create multipathed device via scsi_debug"
mpath=$RETURN_STR
_isconfig
}
function _destroy (){
sleep 10
Cmd "multipath -F"
sleep 5
Cmd "modprobe -r scsi_debug"
}
# ---------------------------------------------------------#
# Mutipath_installation()
# Usage:
# check if multipath starts, if not install it with yum
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Multipath_installation (){
Cmd "rpm -qi device-mapper-multipath" && return 0
Cmd "yum install -y device-mapper-multipath"
}
# ---------------------------------------------------------#
# Print_kernel_info()
# Usage:
# print the detail running kernel information.
# Parameter: # NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Print_kernel_info (){
Cmd "lsb_release -a"
Cmd "uname -a"
}
# ---------------------------------------------------------#
# Print_multipath_pkginfo()()
# Usage:
# print the multipath pacakge information
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Print_multipath_pkginfo (){
Cmd "rpm -qi device-mapper-multipath"
Cmd "rpm -qi kpartx"
}
# ---------------------------------------------------------#
# Setup_Multipath ()
# Usage:
# return mpath_name if we have multipath devices, if not,
# we use scsi_debug to create a multipath device.
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# Return string:
# RETURN_STR # $mpath_name_list, like "mpath0 mpath1"
# ---------------------------------------------------------#
function Setup_Multipath (){
RETURN_STR=''
local mpath_name_list=$(dmsetup table \
| perl -ne 'print "$1 " if /(mpath[a-z0-9]+):[0-9 ]+multipath.*/')
if [ "CHK${mpath_name_list}" != "CHK" ];then
mpath_name_list="$(echo ${mpath_name_list} | sed -e 's/ $//')"
echo "INFO: Found multipath devices: ${mpath_name_list}"
#RHEL 5 will disable some wwn mpath if we install OS with ondisk=mapper/mpath0
# option, so we need to enable them all
if [ "CHK$(uname -r | egrep "2\.6\.18.*el5")" != "CHK" ];then
cat << AA > /etc/multipath.conf
defaults {
user_friendly_names yes
}
blacklist {
device {
vendor .*
product .*
}
}
blacklist_exceptions {
device {
vendor Linux
product scsi_debug
}
device {
vendor IQSTOR
product .*
}
device {
vendor NETAPP
product .*
}
device {
vendor HITACHI
product .*
}
}
AA
service multipathd start
sleep 5s #multipathd return premature
multipath -r
multipathd -k'reconfigure'
sleep 5s
mpath_name_list=$(dmsetup table \
| perl -ne 'print "$1 " if /(mpath[a-z0-9]+):[0-9 ]+multipath.*/')
fi
if [ "CHK${mpath_name_list}" == "CHK" ];then
echo -n "FATAL: still no mulipath devices setup,"
echo " check code in Setup_Multipath()"
RETURN_STR=''
return 1
fi
RETURN_STR="${mpath_name_list}"
return 0
fi
#setup scsi_debug
echo "INFO: Loading scsi_debug module for simulation of mpath"
modprobe scsi_debug \
num_tgts=1 vpd_use_hostno=0 \
add_host=4 delay=20 \
max_luns=2 no_lun_0=1 2>&1 1>/dev/null
echo "INFO: Waiting for udev to create /dev/sdX"
sleep 15s #wait for udev to create /dev/sdX
rpm -q device-mapper-multipath 2>/dev/null 1>/dev/null
if [ $? -ne 0 ];then
echo "INFO: Installing device-mapper-multipath via yum"
yum -y install device-mapper-multipath
fi
#enable multipath for scsi_debug.
cat << AA > /etc/multipath.conf
defaults {
#Enable multibus is for mutlbus testing
path_grouping_policy multibus
user_friendly_names yes
}
blacklist {
device {
vendor .*
product .*
}
}
blacklist_exceptions {
device {
vendor Linux
product scsi_debug
}
}
AA
echo "INFO: /etc/multipath.conf updated"
cat /etc/multipath.conf
echo "INFO: Restarting multiapth and reload configuration"
service multipathd restart
sleep 5s #multipathd return premature
multipathd -k'reconfig'
sleep 5s
mpath_name_list=$(dmsetup table | perl -ne 'print "$1 " if /(mpath[a-z0-9]+):[0-9 ]+multipath.*/')
if [ "CHK${mpath_name_list}" != "CHK" ];then
mpath_name_list="$(echo ${mpath_name_list} | sed -e 's/ $//')"
echo "INFO: found mpath: ${mpath_name_list}"
RETURN_STR="${mpath_name_list}"
return 0
fi
return 1
} #end of functoin Setup_Multipath
get_wwid_of_disk()
{
# we should not use scsi_id or /dev/disk/by-id to get the wwid
# since multipath could replace the white spaces of wwid if
# having white spaces. we should use
# multipathd show paths format %w %d
# to get the wwid
for dev in `ls /dev/disk/by-id/*`
do
if readlink $dev | grep -qw "$disk$"
then
wwid=$(basename $dev | sed 's/^[^-]*-//g')
break
fi
done
if test X$wwid = X
then
wwid=$(/lib/udev/scsi_id --page=0x83 --whitelisted --device=/dev/$disk)
fi
echo $wwid
# multipathd_running || texit "multipathd is not running"
# local disk=$1
# local wwid=$(multipathd show paths format %d,%w | grep "^$disk\s*," | \
# awk -F, '{ print $2 }' | sed 's/\s//g')
# echo $wwid
}

124
tests/include/include.sh Executable file
View File

@ -0,0 +1,124 @@
#!/bin/bash
# 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 <http://www.gnu.org/licenses/>.
# Author: Lin Li <lilin@redhat.com>
#----------------------------------------------------------------------------#
# Mp_Conf_Up_Def ()
# Usage:
# Update default section of /etc/multipath.conf, will also reload conf.
# Parameter:
# $config_change #config string want to change, like 'polling_interval 5'
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# Return string:
# NULL
#----------------------------------------------------------------------------#
function Mp_Conf_Up_Def (){
EX_USAGE=64 # Bad arg format
if [ $# -lt 1 ]; then
echo 'Usage: Mp_Conf_Up_Def $config_change'
exit "${EX_USAGE}"
fi
RETURN_STR=''
local multipath_conf_filename="/etc/multipath.conf"
local config_change="$1"
echo ${config_change}
if [ "CHK${config_change}" == "CHK" ];then
echo 'Usage: Mp_Conf_Up_Def $config_change'
exit "${EX_USAGE}"
fi
python2 -c "
import sys
sys.path.append('"${MP_INCLUDE_PATH}"')
from mpconf import *
update_df_section('""${config_change}""')
"
#TODO: we need to check configuration before we return 0
RETURN_STR=""
return 0
} #end of functoin Mp_Conf_Up_Def
# ---------------------------------------------------------#
# Print_multipath_pkginfo()()
# Usage:
# print the multipath pacakge information
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Print_multipath_pkginfo (){
Cmd "rpm -qi device-mapper-multipath"
Cmd "rpm -qi kpartx"
}
# ---------------------------------------------------------#
# Mutipathd_stop()
# Usage:
# check if multipathd stops, if not stop it
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Multipathd_stop (){
# { ! Cmd pidof multipathd ; } || Cmd "service multipathd stop"
{ ! Cmd pidof multipathd ; } || Cmd "kill -9 `pidof multipathd`"
}
# ---------------------------------------------------------#
# Mutipathd_start()
# Usage:
# check if multipathd is installed, if not start it
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Multipathd_start (){
# { Cmd pidof multipathd ; } || Cmd "service multipathd start"
{ Cmd pidof multipathd ; } || Cmd "multipathd"
}
# ---------------------------------------------------------#
# Mutipath_installation()
# Usage:
# check if multipath starts, if not install it with yum
# Parameter:
# NULL
# Returns:
# Return code:
# 0 on success
# 1 if something went wrong.
# ---------------------------------------------------------#
function Multipath_installation (){
Cmd "rpm -qi device-mapper-multipath" && return 0
Cmd "yum install -y device-mapper-multipath"
}

Some files were not shown because too many files have changed in this diff Show More