diff --git a/.gitignore b/.gitignore index 703cbe1..befbabe 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ multipath-tools-091027.tar.gz /multipath-tools-0.8.0.tgz /multipath-tools-0.8.2.tgz /multipath-tools-0.8.4.tgz +/multipath-tools-0.8.5.tgz diff --git a/0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch b/0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch new file mode 100644 index 0000000..02b2e18 --- /dev/null +++ b/0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Varoqui +Date: Mon, 14 Dec 2020 11:05:24 +0100 +Subject: [PATCH] Change the multipath.conf manpage uxsock_timeout default + value + +Fixes: 7db0c44 ("multipathd: Set CLI timeout correctly") + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + multipath/multipath.conf.5 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index d2101ed6..7242d39b 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -1153,7 +1153,7 @@ In these cases it is recommended to increase the CLI timeout to avoid + those issues. + .RS + .TP +-The default is: \fB1000\fR ++The default is: \fB4000\fR + .RE + . + . +-- +2.17.2 + diff --git a/0001-libmpathpersist-limit-PRIN-allocation-length-to-8192.patch b/0001-libmpathpersist-limit-PRIN-allocation-length-to-8192.patch deleted file mode 100644 index d40166a..0000000 --- a/0001-libmpathpersist-limit-PRIN-allocation-length-to-8192.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0002-libmpathpersist-format_transportids-avoid-PROUT-over.patch b/0002-libmpathpersist-format_transportids-avoid-PROUT-over.patch deleted file mode 100644 index 6164b26..0000000 --- a/0002-libmpathpersist-format_transportids-avoid-PROUT-over.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - #include -+#include - - #include - #include -@@ -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(¶mp->private_buffer[buff_offset], ¶mp->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(¶mp->private_buffer[buff_offset], ¶mp->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(¶mp->private_buffer[buff_offset], ¶mp->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 - diff --git a/0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch b/0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch new file mode 100644 index 0000000..2d38590 --- /dev/null +++ b/0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 21:59:11 +0200 +Subject: [PATCH] libmultipath: find_mpe(): don't match with empty WWID + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index b9bdbdbc..df0f8f45 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -147,7 +147,7 @@ struct mpentry *find_mpe(vector mptable, char *wwid) + int i; + struct mpentry * mpe; + +- if (!wwid) ++ if (!wwid || !*wwid) + return NULL; + + vector_foreach_slot (mptable, mpe, i) +-- +2.17.2 + diff --git a/0003-libmpathpersist-mpath_format_readfullstatus-use-real.patch b/0003-libmpathpersist-mpath_format_readfullstatus-use-real.patch deleted file mode 100644 index 6d0cf1e..0000000 --- a/0003-libmpathpersist-mpath_format_readfullstatus-use-real.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch b/0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch new file mode 100644 index 0000000..63ff6a5 --- /dev/null +++ b/0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch @@ -0,0 +1,260 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Sep 2020 22:22:36 +0200 +Subject: [PATCH] libmultipath: copy mpp->hwe from pp->hwe + +Since f0462f0 ("libmultipath: use vector for for pp->hwe and mp->hwe"), +we've been trying to fix issues caused by paths getting freed and mpp->hwe +dangling. This approach couldn't work because we need mpp->hwe to persist, +even if all paths are removed from the map. Before f0462f0, a simple +assignment worked, because the lifetime of the hwe wasn't bound to the +path. But now, we need to copy the vector. It turns out that we need to set +mpp->hwe only in two places, add_map_with_path() and setup_map(), and +that the code is simplified overall. + +Even now, it can happen that a map is added with add_map_without_paths(), +and has no paths. In that case, calling do_set_from_hwe() with a NULL +pointer is not a bug, so remove the message. + +Fixes: f0462f0 ("libmultipath: use vector for for pp->hwe and mp->hwe") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 7 +++++ + libmultipath/propsel.c | 4 +-- + libmultipath/structs.c | 15 +++++++++++ + libmultipath/structs.h | 1 + + libmultipath/structs_vec.c | 54 ++++++++++++++++---------------------- + multipathd/main.c | 10 ------- + 6 files changed, 46 insertions(+), 45 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 6fb477fc..d7afc915 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -311,6 +311,13 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + if (mpp->disable_queueing && VECTOR_SIZE(mpp->paths) != 0) + mpp->disable_queueing = 0; + ++ /* ++ * If this map was created with add_map_without_path(), ++ * mpp->hwe might not be set yet. ++ */ ++ if (!mpp->hwe) ++ extract_hwe_from_path(mpp); ++ + /* + * properties selectors + * +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 7e6e0d68..40201344 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -65,9 +65,7 @@ do { \ + __do_set_from_vec(struct hwentry, var, (src)->hwe, dest) + + #define do_set_from_hwe(var, src, dest, msg) \ +- if (!src->hwe) { \ +- condlog(0, "BUG: do_set_from_hwe called with hwe == NULL"); \ +- } else if (__do_set_from_hwe(var, src, dest)) { \ ++ if (src->hwe && __do_set_from_hwe(var, src, dest)) { \ + origin = msg; \ + goto out; \ + } +diff --git a/libmultipath/structs.c b/libmultipath/structs.c +index 464596fc..2efad6f0 100644 +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -234,6 +234,17 @@ alloc_multipath (void) + return mpp; + } + ++void *set_mpp_hwe(struct multipath *mpp, const struct path *pp) ++{ ++ if (!mpp || !pp || !pp->hwe) ++ return NULL; ++ if (mpp->hwe) ++ return mpp->hwe; ++ mpp->hwe = vector_convert(NULL, pp->hwe, ++ struct hwentry, identity); ++ return mpp->hwe; ++} ++ + void free_multipath_attributes(struct multipath *mpp) + { + if (!mpp) +@@ -290,6 +301,10 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths) + + free_pathvec(mpp->paths, free_paths); + free_pgvec(mpp->pg, free_paths); ++ if (mpp->hwe) { ++ vector_free(mpp->hwe); ++ mpp->hwe = NULL; ++ } + FREE_PTR(mpp->mpcontext); + FREE(mpp); + } +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 7de93d6c..4ce30551 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -422,6 +422,7 @@ struct host_group { + struct path * alloc_path (void); + struct pathgroup * alloc_pathgroup (void); + struct multipath * alloc_multipath (void); ++void *set_mpp_hwe(struct multipath *mpp, const struct path *pp); + void uninitialize_path(struct path *pp); + void free_path (struct path *); + void free_pathvec (vector vec, enum free_path_mode free_paths); +diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c +index 8895fa77..f7f45f11 100644 +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -294,11 +294,6 @@ err: + void orphan_path(struct path *pp, const char *reason) + { + condlog(3, "%s: orphan path, %s", pp->dev, reason); +- 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; + uninitialize_path(pp); + } +@@ -308,8 +303,6 @@ 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) { + if (pp->initialized == INIT_REMOVED) { +@@ -397,24 +390,26 @@ extract_hwe_from_path(struct multipath * mpp) + if (mpp->hwe || !mpp->paths) + return; + +- condlog(3, "%s: searching paths for valid hwe", mpp->alias); ++ condlog(4, "%s: searching paths for valid hwe", mpp->alias); + /* doing this in two passes seems like paranoia to me */ + vector_foreach_slot(mpp->paths, pp, i) { +- if (pp->state != PATH_UP) +- continue; +- if (pp->hwe) { +- mpp->hwe = pp->hwe; +- return; +- } ++ if (pp->state == PATH_UP && ++ pp->initialized != INIT_REMOVED && pp->hwe) ++ goto done; + } + vector_foreach_slot(mpp->paths, pp, i) { +- if (pp->state == PATH_UP) +- continue; +- if (pp->hwe) { +- mpp->hwe = pp->hwe; +- return; +- } ++ if (pp->state != PATH_UP && ++ pp->initialized != INIT_REMOVED && pp->hwe) ++ goto done; + } ++done: ++ if (i < VECTOR_SIZE(mpp->paths)) ++ (void)set_mpp_hwe(mpp, pp); ++ ++ if (mpp->hwe) ++ condlog(3, "%s: got hwe from path %s", mpp->alias, pp->dev); ++ else ++ condlog(2, "%s: no hwe found", mpp->alias); + } + + int +@@ -514,8 +509,6 @@ 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"); + } +@@ -524,8 +517,6 @@ 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 +@@ -701,9 +692,15 @@ struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp, + + conf = get_multipath_config(); + mpp->mpe = find_mpe(conf->mptable, pp->wwid); +- mpp->hwe = pp->hwe; + put_multipath_config(conf); + ++ /* ++ * We need to call this before select_alias(), ++ * because that accesses hwe properties. ++ */ ++ if (pp->hwe && !set_mpp_hwe(mpp, pp)) ++ goto out; ++ + strcpy(mpp->wwid, pp->wwid); + find_existing_alias(mpp, vecs); + if (select_alias(conf, mpp)) +@@ -754,12 +751,6 @@ int verify_paths(struct multipath *mpp) + vector_del_slot(mpp->paths, i); + i--; + +- /* Make sure mpp->hwe doesn't point to freed memory. +- * We call extract_hwe_from_path() below to restore +- * mpp->hwe +- */ +- if (mpp->hwe == pp->hwe) +- mpp->hwe = NULL; + /* + * Don't delete path from pathvec yet. We'll do this + * after the path has been removed from the map, in +@@ -771,7 +762,6 @@ int verify_paths(struct multipath *mpp) + mpp->alias, pp->dev, pp->dev_t); + } + } +- extract_hwe_from_path(mpp); + return count; + } + +diff --git a/multipathd/main.c b/multipathd/main.c +index a4abbb27..eedc6c10 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1153,13 +1153,6 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) + if (i != -1) + vector_del_slot(mpp->paths, i); + +- /* +- * Make sure mpp->hwe doesn't point to freed memory +- * We call extract_hwe_from_path() below to restore mpp->hwe +- */ +- if (mpp->hwe == pp->hwe) +- mpp->hwe = NULL; +- + /* + * remove the map IF removing the last path + */ +@@ -1191,9 +1184,6 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) + */ + } + +- if (mpp->hwe == NULL) +- extract_hwe_from_path(mpp); +- + if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + condlog(0, "%s: failed to setup map for" + " removal of path %s", mpp->alias, pp->dev); +-- +2.17.2 + diff --git a/0004-libmultipath-assign-variable-to-make-gcc-happy.patch b/0004-libmultipath-assign-variable-to-make-gcc-happy.patch deleted file mode 100644 index 8db8dd9..0000000 --- a/0004-libmultipath-assign-variable-to-make-gcc-happy.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch b/0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch new file mode 100644 index 0000000..c3a0a18 --- /dev/null +++ b/0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 14:24:41 +0200 +Subject: [PATCH] libmultipath: dm_map_present_by_uuid(): fix dm_task_create() + call + +libmultipath shouldn't call dm_task_create() directly any more. + +Fixes: 90535a3 ("multipath: centralize validation code") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/devmapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 7f093617..0bc1d16e 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -836,7 +836,7 @@ dm_map_present_by_uuid(const char *uuid) + if (safe_sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid)) + goto out; + +- if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO))) + goto out; + + dm_task_no_open_count(dmt); +-- +2.17.2 + diff --git a/0005-libdmmp-tests-fix-compilation.patch b/0005-libdmmp-tests-fix-compilation.patch new file mode 100644 index 0000000..d1d9955 --- /dev/null +++ b/0005-libdmmp-tests-fix-compilation.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 12:10:35 +0200 +Subject: [PATCH] libdmmp tests: fix compilation + +These tests don't compile with -Werror=unused-parameter. Fix it. +Reviewed-by: Benjamin Marzinski + +Signed-off-by: Benjamin Marzinski +--- + libdmmp/test/libdmmp_speed_test.c | 2 +- + libdmmp/test/libdmmp_test.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libdmmp/test/libdmmp_speed_test.c b/libdmmp/test/libdmmp_speed_test.c +index 372cd390..d91ba50a 100644 +--- a/libdmmp/test/libdmmp_speed_test.c ++++ b/libdmmp/test/libdmmp_speed_test.c +@@ -27,7 +27,7 @@ + + #include + +-int main(int argc, char *argv[]) ++int main(void) + { + struct dmmp_context *ctx = NULL; + struct dmmp_mpath **dmmp_mps = NULL; +diff --git a/libdmmp/test/libdmmp_test.c b/libdmmp/test/libdmmp_test.c +index d944e1e3..a940b576 100644 +--- a/libdmmp/test/libdmmp_test.c ++++ b/libdmmp/test/libdmmp_test.c +@@ -102,7 +102,7 @@ out: + return rc; + } + +-int main(int argc, char *argv[]) ++int main(void) + { + struct dmmp_context *ctx = NULL; + struct dmmp_mpath **dmmp_mps = NULL; +-- +2.17.2 + diff --git a/0005-libmutipath-don-t-close-fd-on-dm_lib_release.patch b/0005-libmutipath-don-t-close-fd-on-dm_lib_release.patch deleted file mode 100644 index dd4af7e..0000000 --- a/0005-libmutipath-don-t-close-fd-on-dm_lib_release.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0006-libmultipath-allow-force-reload-with-no-active-paths.patch b/0006-libmultipath-allow-force-reload-with-no-active-paths.patch deleted file mode 100644 index 77d5474..0000000 --- a/0006-libmultipath-allow-force-reload-with-no-active-paths.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0006-libmultipath-prio-constify-some-function-parameters.patch b/0006-libmultipath-prio-constify-some-function-parameters.patch new file mode 100644 index 0000000..80771ea --- /dev/null +++ b/0006-libmultipath-prio-constify-some-function-parameters.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Sep 2020 23:57:22 +0200 +Subject: [PATCH] libmultipath: prio: constify some function parameters + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/prio.c | 4 ++-- + libmultipath/prio.h | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/prio.c b/libmultipath/prio.c +index 194563c4..3a718ba5 100644 +--- a/libmultipath/prio.c ++++ b/libmultipath/prio.c +@@ -18,7 +18,7 @@ unsigned int get_prio_timeout(unsigned int timeout_ms, + return default_timeout; + } + +-int init_prio (char *multipath_dir) ++int init_prio (const char *multipath_dir) + { + if (!add_prio(multipath_dir, DEFAULT_PRIO)) + return 1; +@@ -87,7 +87,7 @@ int prio_set_args (struct prio * p, const char * args) + return snprintf(p->args, PRIO_ARGS_LEN, "%s", args); + } + +-struct prio * add_prio (char *multipath_dir, char * name) ++struct prio * add_prio (const char *multipath_dir, const char * name) + { + char libname[LIB_PRIO_NAMELEN]; + struct stat stbuf; +diff --git a/libmultipath/prio.h b/libmultipath/prio.h +index 599d1d88..26754f78 100644 +--- a/libmultipath/prio.h ++++ b/libmultipath/prio.h +@@ -55,9 +55,9 @@ struct prio { + + unsigned int get_prio_timeout(unsigned int checker_timeout, + unsigned int default_timeout); +-int init_prio (char *); ++int init_prio (const char *); + void cleanup_prio (void); +-struct prio * add_prio (char *, char *); ++struct prio * add_prio (const char *, const char *); + int prio_getprio (struct prio *, struct path *, unsigned int); + void prio_get (char *, struct prio *, char *, char *); + void prio_put (struct prio *); +-- +2.17.2 + diff --git a/0007-kpartx.rules-honor-DM_UDEV_DISABLE_OTHER_RULES_FLAG.patch b/0007-kpartx.rules-honor-DM_UDEV_DISABLE_OTHER_RULES_FLAG.patch deleted file mode 100644 index 6c33439..0000000 --- a/0007-kpartx.rules-honor-DM_UDEV_DISABLE_OTHER_RULES_FLAG.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch b/0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch new file mode 100644 index 0000000..90a2f25 --- /dev/null +++ b/0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Sep 2020 23:58:15 +0200 +Subject: [PATCH] libmultipath: checkers/prio: allow non-lazy .so loading + +If compiled with -DLOAD_ALL_SHARED_LIBS, all known prioritizers +and checkers will be loaded immediately on startup. This is useful +for determining symbol usage (start executables with LD_BIND_NOW=1). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/checkers.c | 17 +++++++++++++++++ + libmultipath/prio.c | 22 ++++++++++++++++++++++ + 2 files changed, 39 insertions(+) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index f7ddd536..18b1f5eb 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -7,6 +7,7 @@ + #include "debug.h" + #include "checkers.h" + #include "vector.h" ++#include "util.h" + + struct checker_class { + struct list_head node; +@@ -375,7 +376,23 @@ void checker_get(const char *multipath_dir, struct checker *dst, + + int init_checkers(const char *multipath_dir) + { ++#ifdef LOAD_ALL_SHARED_LIBS ++ static const char *const all_checkers[] = { ++ DIRECTIO, ++ TUR, ++ HP_SW, ++ RDAC, ++ EMC_CLARIION, ++ READSECTOR0, ++ CCISS_TUR, ++ }; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(all_checkers); i++) ++ add_checker_class(multipath_dir, all_checkers[i]); ++#else + if (!add_checker_class(multipath_dir, DEFAULT_CHECKER)) + return 1; ++#endif + return 0; + } +diff --git a/libmultipath/prio.c b/libmultipath/prio.c +index 3a718ba5..c92bde7f 100644 +--- a/libmultipath/prio.c ++++ b/libmultipath/prio.c +@@ -20,8 +20,30 @@ unsigned int get_prio_timeout(unsigned int timeout_ms, + + int init_prio (const char *multipath_dir) + { ++#ifdef LOAD_ALL_SHARED_LIBS ++ static const char *const all_prios[] = { ++ PRIO_ALUA, ++ PRIO_CONST, ++ PRIO_DATACORE, ++ PRIO_EMC, ++ PRIO_HDS, ++ PRIO_HP_SW, ++ PRIO_ONTAP, ++ PRIO_RANDOM, ++ PRIO_RDAC, ++ PRIO_WEIGHTED_PATH, ++ PRIO_SYSFS, ++ PRIO_PATH_LATENCY, ++ PRIO_ANA, ++ }; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(all_prios); i++) ++ add_prio(multipath_dir, all_prios[i]); ++#else + if (!add_prio(multipath_dir, DEFAULT_PRIO)) + return 1; ++#endif + return 0; + } + +-- +2.17.2 + diff --git a/0008-kpartx.rules-check-for-skip_kpartx-on-synthetic-ueve.patch b/0008-kpartx.rules-check-for-skip_kpartx-on-synthetic-ueve.patch deleted file mode 100644 index 2a18b15..0000000 --- a/0008-kpartx.rules-check-for-skip_kpartx-on-synthetic-ueve.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch b/0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch new file mode 100644 index 0000000..edc3e66 --- /dev/null +++ b/0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 12:52:49 +0200 +Subject: [PATCH] multipath-tools Makefiles: separate rules for .so and man + pages + +Rely more on "make" functionality than on sequential command execution. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathcmd/Makefile | 8 +++++--- + libmpathpersist/Makefile | 10 +++++++--- + libmultipath/Makefile | 8 +++++--- + 3 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/libmpathcmd/Makefile b/libmpathcmd/Makefile +index 0f6b8166..08ccb811 100644 +--- a/libmpathcmd/Makefile ++++ b/libmpathcmd/Makefile +@@ -8,13 +8,15 @@ CFLAGS += $(LIB_CFLAGS) + + OBJS = mpath_cmd.o + +-all: $(LIBS) ++all: $(DEVLIB) + + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) +- $(LN) $@ $(DEVLIB) + +-install: $(LIBS) ++$(DEVLIB): $(LIBS) ++ $(LN) $(LIBS) $@ ++ ++install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) +diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile +index 21fdad80..9e869fdc 100644 +--- a/libmpathpersist/Makefile ++++ b/libmpathpersist/Makefile +@@ -11,15 +11,19 @@ LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ + + OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + +-all: $(LIBS) ++all: $(DEVLIB) man + + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ -o $@ $(OBJS) +- $(LN) $(LIBS) $(DEVLIB) ++ ++$(DEVLIB): $(LIBS) ++ $(LN) $(LIBS) $@ ++ ++man: + $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz + $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz + +-install: $(LIBS) ++install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 62ba16e8..40028556 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -54,7 +54,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \ + io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o \ + libsg.o valid.o + +-all: $(LIBS) ++all: $(DEVLIB) + + nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h + $(CC) $(CFLAGS) -Wno-unused-function -c -o $@ $< +@@ -74,9 +74,11 @@ nvme-ioctl.h: nvme/nvme-ioctl.h + + $(LIBS): $(OBJS) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) +- $(LN) $@ $(DEVLIB) + +-install: ++$(DEVLIB): $(LIBS) ++ $(LN) $(LIBS) $@ ++ ++install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) + $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir) +-- +2.17.2 + diff --git a/0009-libmpathpersist-depend-on-libmultipath.patch b/0009-libmpathpersist-depend-on-libmultipath.patch deleted file mode 100644 index 47aad9b..0000000 --- a/0009-libmpathpersist-depend-on-libmultipath.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Christian Hesse -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0009-libmultipath-create-separate-.so-for-unit-tests.patch b/0009-libmultipath-create-separate-.so-for-unit-tests.patch new file mode 100644 index 0000000..38a01d7 --- /dev/null +++ b/0009-libmultipath-create-separate-.so-for-unit-tests.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 19 Sep 2020 00:29:45 +0200 +Subject: [PATCH] libmultipath: create separate .so for unit tests + +The unit tests use a lot of internal symbols that we don't want +to add to the ABI if we don't have to. As long as we don't +have to make incompatible changes to functions, we can work around +that by simply using a non-versioned library for the unit tests. +Therefore we add a seperate rule here. Do this before actually +adding a version script, to avoid breakage during bisection. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/Makefile | 7 +++++++ + tests/Makefile | 10 ++++++---- + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 40028556..12bf6300 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -78,6 +78,13 @@ $(LIBS): $(OBJS) + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ + ++../tests/$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=`basename $@` \ ++ -o $@ $(OBJS) $(LIBDEPS) ++ $(LN) $@ ${@:.so.0=.so} ++ ++test-lib: ../tests/$(LIBS) ++ + install: all + $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) +diff --git a/tests/Makefile b/tests/Makefile +index d26b3ce7..9658c9fd 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) -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka ++LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka + + TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \ + alias directio valid devt +@@ -68,7 +68,7 @@ lib/libchecktur.so: + + %.out: %-test lib/libchecktur.so + @echo == running $< == +- @LD_LIBRARY_PATH=$(multipathdir):$(mpathcmddir) ./$< >$@ ++ @LD_LIBRARY_PATH=.:$(mpathcmddir) ./$< >$@ + + %.vgr: %-test lib/libchecktur.so + @echo == running valgrind for $< == +@@ -78,7 +78,7 @@ lib/libchecktur.so: + OBJS = $(TESTS:%=%.o) $(HELPERS) + + test_clean: +- $(RM) $(TESTS:%=%.out) $(TESTS:%=%.vgr) ++ $(RM) $(TESTS:%=%.out) $(TESTS:%=%.vgr) *.so* + + valgrind_clean: + $(RM) $(TESTS:%=%.vgr) +@@ -98,12 +98,14 @@ dep_clean: + @sed -n 's/^.*__wrap_\([a-zA-Z0-9_]*\).*$$/-Wl,--wrap=\1/p' $< | \ + sort -u | tr '\n' ' ' >$@ + ++libmultipath.so.0: ++ $(MAKE) -C $(multipathdir) test-lib + + # COLON will get expanded during second expansion below + COLON:=: + .SECONDEXPANSION: + %-test: %.o %.o.wrap $$($$@_OBJDEPS) $$($$@_TESTDEPS) $$($$@_TESTDEPS$$(COLON).o=.o.wrap) \ +- $(multipathdir)/libmultipath.so Makefile ++ libmultipath.so.0 Makefile + $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $< $($@_TESTDEPS) $($@_OBJDEPS) \ + $(LIBDEPS) $($@_LIBDEPS) \ + $(shell cat $<.wrap) $(foreach dep,$($@_TESTDEPS),$(shell cat $(dep).wrap)) +-- +2.17.2 + diff --git a/0010-libmultipath-add-linker-version-script.patch b/0010-libmultipath-add-linker-version-script.patch new file mode 100644 index 0000000..ed6ad7f --- /dev/null +++ b/0010-libmultipath-add-linker-version-script.patch @@ -0,0 +1,303 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 19 Sep 2020 00:00:18 +0200 +Subject: [PATCH] libmultipath: add linker version script + +This version script documents the current ABI of libmultipath, +as used by multipath, multipathd, (lib)mpathpersist, and the +dynamically loaded libraries (prioritizers, checkers, and foreign). +The initial version string is set to "LIBMULTIPATH_1.0.0". + +This reduces the amount of exported symbols of libmultipath.so.0 +by more than a half (199 vs. 434). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/Makefile | 7 +- + libmultipath/libmultipath.version | 248 ++++++++++++++++++++++++++++++ + 2 files changed, 253 insertions(+), 2 deletions(-) + create mode 100644 libmultipath/libmultipath.version + +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 12bf6300..e7254f39 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -6,6 +6,7 @@ include ../Makefile.inc + SONAME = 0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmultipath.version + + CFLAGS += $(LIB_CFLAGS) -I$(mpathcmddir) -I$(mpathpersistdir) -I$(nvmedir) + +@@ -72,8 +73,10 @@ nvme-ioctl.c: nvme/nvme-ioctl.c + nvme-ioctl.h: nvme/nvme-ioctl.h + $(call make_static,$<,$@) + +-$(LIBS): $(OBJS) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) ++ ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +new file mode 100644 +index 00000000..a6bf8218 +--- /dev/null ++++ b/libmultipath/libmultipath.version +@@ -0,0 +1,248 @@ ++/* ++ * Copyright (c) 2020 SUSE LLC ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * libmultipath ABI ++ * ++ * libmultipath doesn't have a stable ABI in the usual sense. In particular, ++ * the library does not attempt to ship different versions of the same symbol ++ * for backward compatibility. ++ * ++ * The ABI versioning only serves to avoid linking with a non-matching ABI, to ++ * cut down the set of exported symbols, and to describe it. ++ * The version string is LIBMULTIPATH_$MAJOR.$MINOR.$REL. ++ * ++ * Policy: ++ * ++ * * Bump $MAJOR for incompatible changes, like: ++ * - symbols removed ++ * - parameter list or return values changed for existing functions ++ * - externally visible data structures changed in incompatible ways ++ * (like offsets of previously existing struct members) ++ * In this case, the new version doesn't inherit the previous versions, ++ * because the new library doesn't provide the full previous ABI any more. ++ * All predecessors are merged into the new version. ++ * ++ * * Bump $MINOR for compatible changes, like adding symbols. ++ * The new version inherits the previous ones. ++ * ++ * * Bump $REL to describe deviations from upstream, e.g. in ++ * multipath-tools packages shipped by distributions. ++ * The new version inherits the previous ones. ++ */ ++ ++LIBMULTIPATH_1.0.0 { ++global: ++ /* symbols referenced by multipath and multipathd */ ++ add_foreign; ++ add_map_with_path; ++ adopt_paths; ++ alloc_multipath; ++ alloc_path; ++ alloc_path_with_pathinfo; ++ alloc_strvec; ++ change_foreign; ++ check_alias_settings; ++ checker_clear_message; ++ checker_disable; ++ checker_enable; ++ checker_is_sync; ++ checker_message; ++ checker_name; ++ checker_state_name; ++ check_foreign; ++ cleanup_checkers; ++ cleanup_foreign; ++ cleanup_lock; ++ cleanup_prio; ++ close_fd; ++ coalesce_paths; ++ convert_dev; ++ count_active_paths; ++ delete_all_foreign; ++ delete_foreign; ++ disassemble_map; ++ disassemble_status; ++ dlog; ++ dm_cancel_deferred_remove; ++ dm_drv_version; ++ dm_enablegroup; ++ dm_fail_path; ++ _dm_flush_map; ++ dm_flush_map_nopaths; ++ dm_flush_maps; ++ dm_geteventnr; ++ dm_get_info; ++ dm_get_major_minor; ++ dm_get_map; ++ dm_get_maps; ++ dm_get_multipath; ++ dm_get_status; ++ dm_get_uuid; ++ dm_is_mpath; ++ dm_mapname; ++ dm_map_present; ++ dm_queue_if_no_path; ++ dm_reassign; ++ dm_reinstate_path; ++ dm_simplecmd_noflush; ++ dm_switchgroup; ++ dm_tgt_version; ++ domap; ++ ensure_directories_exist; ++ extract_hwe_from_path; ++ filter_devnode; ++ filter_path; ++ filter_wwid; ++ find_mp_by_alias; ++ find_mp_by_minor; ++ find_mp_by_str; ++ find_mp_by_wwid; ++ find_mpe; ++ find_path_by_dev; ++ find_path_by_devt; ++ find_slot; ++ foreign_multipath_layout; ++ foreign_path_layout; ++ free_config; ++ free_multipath; ++ free_multipathvec; ++ free_path; ++ free_pathvec; ++ free_strvec; ++ get_monotonic_time; ++ get_multipath_layout; ++ get_path_layout; ++ get_pgpolicy_id; ++ get_refwwid; ++ get_state; ++ get_udev_device; ++ get_uid; ++ get_used_hwes; ++ group_by_prio; ++ init_checkers; ++ init_foreign; ++ init_prio; ++ io_err_stat_attr; ++ io_err_stat_handle_pathfail; ++ is_path_valid; ++ is_quote; ++ libmp_dm_task_create; ++ libmp_udev_set_sync_support; ++ load_config; ++ log_thread_reset; ++ log_thread_start; ++ log_thread_stop; ++ need_io_err_check; ++ normalize_timespec; ++ orphan_path; ++ orphan_paths; ++ parse_prkey_flags; ++ pathcount; ++ path_discovery; ++ path_get_tpgs; ++ pathinfo; ++ path_offline; ++ print_all_paths; ++ print_foreign_topology; ++ _print_multipath_topology; ++ pthread_cond_init_mono; ++ recv_packet; ++ recv_packet_from_client; ++ reinstate_paths; ++ remember_wwid; ++ remove_map; ++ remove_map_by_alias; ++ remove_maps; ++ remove_wwid; ++ replace_wwids; ++ reset_checker_classes; ++ select_all_tg_pt; ++ select_action; ++ select_find_multipaths_timeout; ++ select_no_path_retry; ++ select_path_group; ++ select_reservation_key; ++ send_packet; ++ set_max_fds; ++ __set_no_path_retry; ++ set_path_removed; ++ set_prkey; ++ setup_map; ++ setup_thread_attr; ++ should_multipath; ++ snprint_blacklist_report; ++ snprint_config; ++ snprint_devices; ++ snprint_foreign_multipaths; ++ snprint_foreign_paths; ++ snprint_foreign_topology; ++ _snprint_multipath; ++ snprint_multipath_header; ++ snprint_multipath_map_json; ++ _snprint_multipath_topology; ++ snprint_multipath_topology_json; ++ _snprint_path; ++ snprint_path_header; ++ snprint_status; ++ snprint_wildcards; ++ stop_io_err_stat_thread; ++ store_path; ++ store_pathinfo; ++ strchop; ++ strlcpy; ++ sync_map_state; ++ sysfs_attr_set_value; ++ sysfs_get_size; ++ sysfs_is_multipathed; ++ timespecsub; ++ trigger_paths_udev_change; ++ uevent_dispatch; ++ uevent_get_dm_str; ++ uevent_get_env_positive_int; ++ uevent_is_mpath; ++ uevent_listen; ++ update_mpp_paths; ++ update_multipath_status; ++ update_multipath_strings; ++ update_multipath_table; ++ update_pathvec_from_dm; ++ update_queue_mode_add_path; ++ update_queue_mode_del_path; ++ ux_socket_listen; ++ valid_alias; ++ vector_alloc; ++ vector_alloc_slot; ++ vector_del_slot; ++ vector_free; ++ vector_reset; ++ vector_set_slot; ++ verify_paths; ++ ++ /* checkers */ ++ sg_read; ++ ++ /* prioritizers */ ++ get_asymmetric_access_state; ++ get_prio_timeout; ++ get_target_port_group; ++ get_target_port_group_support; ++ libmp_nvme_ana_log; ++ libmp_nvme_get_nsid; ++ libmp_nvme_identify_ns; ++ log_nvme_errcode; ++ nvme_id_ctrl_ana; ++ snprint_host_wwnn; ++ snprint_host_wwpn; ++ snprint_path_serial; ++ snprint_tgt_wwnn; ++ snprint_tgt_wwpn; ++ sysfs_get_asymmetric_access_state; ++ ++ /* foreign */ ++ free_scandir_result; ++ sysfs_attr_get_value; ++ ++local: ++ *; ++}; +-- +2.17.2 + diff --git a/0010-multipath-tools-Makefile-more-dependency-fixes-for-p.patch b/0010-multipath-tools-Makefile-more-dependency-fixes-for-p.patch deleted file mode 100644 index c4f0b3e..0000000 --- a/0010-multipath-tools-Makefile-more-dependency-fixes-for-p.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0011-libmpathpersist-add-linker-version-script.patch b/0011-libmpathpersist-add-linker-version-script.patch new file mode 100644 index 0000000..916c4f3 --- /dev/null +++ b/0011-libmpathpersist-add-linker-version-script.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 19 Sep 2020 00:02:16 +0200 +Subject: [PATCH] libmpathpersist: add linker version script + +This defines the ABI of libmpathpersist in the current state. +The initial version is set to "LIBMPATHPERSIST_1.0.0". + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/Makefile | 6 +++-- + libmpathpersist/libmpathpersist.version | 32 +++++++++++++++++++++++++ + 2 files changed, 36 insertions(+), 2 deletions(-) + create mode 100644 libmpathpersist/libmpathpersist.version + +diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile +index 9e869fdc..456ce4cf 100644 +--- a/libmpathpersist/Makefile ++++ b/libmpathpersist/Makefile +@@ -3,6 +3,7 @@ include ../Makefile.inc + SONAME = 0 + DEVLIB = libmpathpersist.so + LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmpathpersist.version + + CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) + +@@ -13,8 +14,9 @@ OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + + all: $(DEVLIB) man + +-$(LIBS): $(OBJS) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ -o $@ $(OBJS) ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version +new file mode 100644 +index 00000000..dc648ce6 +--- /dev/null ++++ b/libmpathpersist/libmpathpersist.version +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2020 SUSE LLC ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * libmpathpersist ABI ++ * ++ * The ABI of libmpathpersist is supposed to remain stable. Removing symbols ++ * or altering existing symbols' semantics is not allowed. When changing a ++ * a symbol, either use a new name, or explicit symver directives. ++ * ++ * See libmultipath.version for general policy about version numbers. ++ */ ++LIBMPATHPERSIST_1.0.0 { ++global: ++ ++ __mpath_persistent_reserve_in; ++ __mpath_persistent_reserve_out; ++ dumpHex; ++ mpath_alloc_prin_response; ++ mpath_lib_exit; ++ mpath_lib_init; ++ mpath_mx_alloc_len; ++ mpath_persistent_reserve_in; ++ mpath_persistent_reserve_init_vecs; ++ mpath_persistent_reserve_out; ++ mpath_persistent_reserve_free_vecs; ++ prin_do_scsi_ioctl; ++ prout_do_scsi_ioctl; ++ update_map_pr; ++ ++local: *; ++}; +-- +2.17.2 + diff --git a/0011-multipath-tools-Makefile.inc-separate-out-OPTFLAGS.patch b/0011-multipath-tools-Makefile.inc-separate-out-OPTFLAGS.patch deleted file mode 100644 index 2082970..0000000 --- a/0011-multipath-tools-Makefile.inc-separate-out-OPTFLAGS.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0012-libmpathcmd-add-linker-version-script.patch b/0012-libmpathcmd-add-linker-version-script.patch new file mode 100644 index 0000000..454c3b7 --- /dev/null +++ b/0012-libmpathcmd-add-linker-version-script.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 12:54:20 +0200 +Subject: [PATCH] libmpathcmd: add linker version script + +For completeness, this isn't really necessary. +The version string is set to "LIBMPATHCMD_1.0.0". + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathcmd/Makefile | 6 ++++-- + libmpathcmd/libmpathcmd.version | 25 +++++++++++++++++++++++++ + 2 files changed, 29 insertions(+), 2 deletions(-) + create mode 100644 libmpathcmd/libmpathcmd.version + +diff --git a/libmpathcmd/Makefile b/libmpathcmd/Makefile +index 08ccb811..25910194 100644 +--- a/libmpathcmd/Makefile ++++ b/libmpathcmd/Makefile +@@ -3,6 +3,7 @@ include ../Makefile.inc + SONAME = 0 + DEVLIB = libmpathcmd.so + LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmpathcmd.version + + CFLAGS += $(LIB_CFLAGS) + +@@ -10,8 +11,9 @@ OBJS = mpath_cmd.o + + all: $(DEVLIB) + +-$(LIBS): $(OBJS) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmpathcmd/libmpathcmd.version b/libmpathcmd/libmpathcmd.version +new file mode 100644 +index 00000000..f1006280 +--- /dev/null ++++ b/libmpathcmd/libmpathcmd.version +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2020 SUSE LLC ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * libmpathcmd ABI ++ * ++ * The ABI of libmpathcmd is supposed to remain stable. Removing symbols ++ * or altering existing symbols' semantics is not allowed. When changing a ++ * a symbol, either use a new name, or explicit symver directives. ++ * ++ * See libmultipath.version for general policy about version numbers. ++ */ ++LIBMPATHCMD_1.0.0 { ++global: ++ __mpath_connect; ++ mpath_connect; ++ mpath_disconnect; ++ mpath_process_cmd; ++ mpath_recv_reply; ++ mpath_recv_reply_len; ++ mpath_recv_reply_data; ++ mpath_send_cmd; ++local: ++ *; ++}; +-- +2.17.2 + diff --git a/0012-multipath-tools-Makefile.inc-allow-user-settings-for.patch b/0012-multipath-tools-Makefile.inc-allow-user-settings-for.patch deleted file mode 100644 index ba2ec42..0000000 --- a/0012-multipath-tools-Makefile.inc-allow-user-settings-for.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch b/0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch new file mode 100644 index 0000000..a04673d --- /dev/null +++ b/0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 25 Sep 2020 21:37:16 +0200 +Subject: [PATCH] libmpathpersist: initialize mpp->hwe in get_mpvec() + +In __mpath_persistent_reserve_out, we call select_all_tg_pt(), +which requires mpp->hwe to be set. Initialize it in get_mpvec(). + +Fixes: 5b54e77 ("mpathpersist: add all_tg_pt option") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 1f9817ed..4b3f3e0d 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -341,11 +341,13 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid) + continue; + + if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK || +- update_multipath_status(mpp) != DMP_OK) { ++ update_multipath_status(mpp) != DMP_OK || ++ update_mpp_paths(mpp, pathvec)) { + condlog(1, "error parsing map %s", mpp->wwid); + remove_map(mpp, pathvec, curmp, PURGE_VEC); + i--; +- } ++ } else ++ extract_hwe_from_path(mpp); + } + return MPATH_PR_SUCCESS ; + } +-- +2.17.2 + diff --git a/0013-multipath-tools-Makefile.inc-set-Wno-error-clobbered.patch b/0013-multipath-tools-Makefile.inc-set-Wno-error-clobbered.patch deleted file mode 100644 index 3de6cb6..0000000 --- a/0013-multipath-tools-Makefile.inc-set-Wno-error-clobbered.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0014-libmultipath-discovery.c-use-z-qualifier-for-size_t.patch b/0014-libmultipath-discovery.c-use-z-qualifier-for-size_t.patch deleted file mode 100644 index 749bef2..0000000 --- a/0014-libmultipath-discovery.c-use-z-qualifier-for-size_t.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0014-multipathd-allow-shutdown-during-configure.patch b/0014-multipathd-allow-shutdown-during-configure.patch new file mode 100644 index 0000000..2cbfecf --- /dev/null +++ b/0014-multipathd-allow-shutdown-during-configure.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 4 Jan 2019 16:59:49 +0100 +Subject: [PATCH] multipathd: allow shutdown during configure() + +reconfigure() can be a long-running operation; both initial path +discovery and initial map setup can take a long time. Allow +the main program to indicate that the process should be +interrupted if a shutdown signal was received. + +We take advantage of the dynamic linker's symbol lookup ordering +here. The default implementation of should_exit never returns +true, but callers (like multipathd) can override it. + +Cc: Chongyun Wu +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 6 ++++++ + libmultipath/discovery.c | 3 +++ + libmultipath/util.c | 5 +++++ + libmultipath/util.h | 1 + + multipathd/main.c | 17 +++++++++++++++++ + 5 files changed, 32 insertions(+) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index d7afc915..1c8aac08 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1173,6 +1173,12 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + + vector_foreach_slot (pathvec, pp1, k) { + int invalid; ++ ++ if (should_exit()) { ++ ret = CP_FAIL; ++ goto out; ++ } ++ + /* skip this path for some reason */ + + /* 1. if path has no unique id or wwid blacklisted */ +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index c2e1754c..e7084664 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -200,6 +200,9 @@ path_discovery (vector pathvec, int flag) + const char *devtype; + const char *devpath; + ++ if (should_exit()) ++ break; ++ + devpath = udev_list_entry_get_name(entry); + condlog(4, "Discover device %s", devpath); + udevice = udev_device_new_from_syspath(udev, devpath); +diff --git a/libmultipath/util.c b/libmultipath/util.c +index 1748eafe..1f977792 100644 +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -445,3 +445,8 @@ void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len) + { + condlog(0, "%s: bitfield overflow: %u >= %u", f, bit, len); + } ++ ++int should_exit(void) ++{ ++ return 0; ++} +diff --git a/libmultipath/util.h b/libmultipath/util.h +index 2b9703ac..ac19473e 100644 +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -27,6 +27,7 @@ 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); ++int should_exit(void); + + #define KERNEL_VERSION(maj, min, ptc) ((((maj) * 256) + (min)) * 256 + (ptc)) + #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +diff --git a/multipathd/main.c b/multipathd/main.c +index eedc6c10..fa53e963 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -141,6 +141,11 @@ static inline enum daemon_status get_running_state(void) + return st; + } + ++int should_exit(void) ++{ ++ return get_running_state() == DAEMON_SHUTDOWN; ++} ++ + /* + * global copy of vecs for use in sig handlers + */ +@@ -2570,6 +2575,9 @@ configure (struct vectors * vecs) + goto fail; + } + ++ if (should_exit()) ++ goto fail; ++ + conf = get_multipath_config(); + pthread_cleanup_push(put_multipath_config, conf); + vector_foreach_slot (vecs->pathvec, pp, i){ +@@ -2586,6 +2594,9 @@ configure (struct vectors * vecs) + goto fail; + } + ++ if (should_exit()) ++ goto fail; ++ + /* + * create new set of maps & push changed ones into dm + * In the first call, use FORCE_RELOAD_WEAK to avoid making +@@ -2600,6 +2611,9 @@ configure (struct vectors * vecs) + goto fail; + } + ++ if (should_exit()) ++ goto fail; ++ + /* + * may need to remove some maps which are no longer relevant + * e.g., due to blacklist changes in conf file +@@ -2611,6 +2625,9 @@ configure (struct vectors * vecs) + + dm_lib_release(); + ++ if (should_exit()) ++ goto fail; ++ + sync_maps_state(mpvec); + vector_foreach_slot(mpvec, mpp, i){ + if (remember_wwid(mpp->wwid) == 1) +-- +2.17.2 + diff --git a/0015-libmultipath-eliminate-more-signed-unsigned-comparis.patch b/0015-libmultipath-eliminate-more-signed-unsigned-comparis.patch deleted file mode 100644 index a97c202..0000000 --- a/0015-libmultipath-eliminate-more-signed-unsigned-comparis.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch b/0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch new file mode 100644 index 0000000..c2d1475 --- /dev/null +++ b/0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 10:23:05 +0200 +Subject: [PATCH] multipathd: avoid sending "READY=1" to systemd on early + shutdown + +If multipathd gets a shutdown request during initial reconfigure(), +it shouldn't send "READY=1" to systemd. Ensure this by sending +"READY=1" via post_config_state(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index fa53e963..53a22a43 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -189,6 +189,8 @@ static void do_sd_notify(enum daemon_status old_state, + { + char notify_msg[MSG_SIZE]; + const char *msg; ++ static bool startup_done = false; ++ + /* + * Checkerloop switches back and forth between idle and running state. + * No need to tell systemd each time. +@@ -205,6 +207,11 @@ static void do_sd_notify(enum daemon_status old_state, + + if (msg && !safe_sprintf(notify_msg, "STATUS=%s", msg)) + sd_notify(0, notify_msg); ++ ++ if (new_state == DAEMON_IDLE && !startup_done) { ++ sd_notify(0, "READY=1"); ++ startup_done = true; ++ } + } + #endif + +@@ -2903,9 +2910,6 @@ child (__attribute__((unused)) void *param) + struct vectors * vecs; + struct multipath * mpp; + int i; +-#ifdef USE_SYSTEMD +- int startup_done = 0; +-#endif + int rc; + int pid_fd = -1; + struct config *conf; +@@ -3065,12 +3069,6 @@ child (__attribute__((unused)) void *param) + } + lock_cleanup_pop(vecs->lock); + post_config_state(DAEMON_IDLE); +-#ifdef USE_SYSTEMD +- if (!startup_done) { +- sd_notify(0, "READY=1"); +- startup_done = 1; +- } +-#endif + } + } + +-- +2.17.2 + diff --git a/0016-libmultipath-set_uint-fix-parsing-for-32bit.patch b/0016-libmultipath-set_uint-fix-parsing-for-32bit.patch deleted file mode 100644 index c621937..0000000 --- a/0016-libmultipath-set_uint-fix-parsing-for-32bit.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch b/0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch new file mode 100644 index 0000000..b38cf2f --- /dev/null +++ b/0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 10:47:52 +0200 +Subject: [PATCH] multipathd: send "STOPPING=1" to systemd on shutdown + +Inform systemd that the daemon is shutting down. See sd_notify(3). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 53a22a43..c264351c 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -208,7 +208,9 @@ static void do_sd_notify(enum daemon_status old_state, + if (msg && !safe_sprintf(notify_msg, "STATUS=%s", msg)) + sd_notify(0, notify_msg); + +- if (new_state == DAEMON_IDLE && !startup_done) { ++ if (new_state == DAEMON_SHUTDOWN) ++ sd_notify(0, "STOPPING=1"); ++ else if (new_state == DAEMON_IDLE && !startup_done) { + sd_notify(0, "READY=1"); + startup_done = true; + } +-- +2.17.2 + diff --git a/0017-multipath-tools-tests-Makefile-add-lmpathcmd-to-LIBD.patch b/0017-multipath-tools-tests-Makefile-add-lmpathcmd-to-LIBD.patch deleted file mode 100644 index 282aa38..0000000 --- a/0017-multipath-tools-tests-Makefile-add-lmpathcmd-to-LIBD.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch b/0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch new file mode 100644 index 0000000..76894d0 --- /dev/null +++ b/0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 10:57:22 +0200 +Subject: [PATCH] multipathd: send "RELOADING=1" to systemd on DAEMON_CONFIGURE + state + +The logic is as follows: child() sets DAEMON_IDLE status after +DAEMON_CONFIGURE when reconfigure() has finished. The only other state change +that can race with that is DAEMON_SHUTDOWN. Other state changes will wait for +DAEMON_IDLE first (see set_config_state()). When DAEMON_CONFIGURE is entered, +and we are not just starting up, send a "RELOADING=1" message to +systemd. After that, we must send "READY=1" when we're done reloading. Also +do that on startup, when DAEMON_IDLE is set for the first time. +See sd_notify(3). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index c264351c..e3f2328d 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -210,10 +210,11 @@ static void do_sd_notify(enum daemon_status old_state, + + if (new_state == DAEMON_SHUTDOWN) + sd_notify(0, "STOPPING=1"); +- else if (new_state == DAEMON_IDLE && !startup_done) { ++ else if (new_state == DAEMON_IDLE && old_state == DAEMON_CONFIGURE) { + sd_notify(0, "READY=1"); + startup_done = true; +- } ++ } else if (new_state == DAEMON_CONFIGURE && startup_done) ++ sd_notify(0, "RELOADING=1"); + } + #endif + +-- +2.17.2 + diff --git a/0018-multipath-tools-tests-Makefile-Fix-OBJDEPS-for-hwtab.patch b/0018-multipath-tools-tests-Makefile-Fix-OBJDEPS-for-hwtab.patch deleted file mode 100644 index 5835089..0000000 --- a/0018-multipath-tools-tests-Makefile-Fix-OBJDEPS-for-hwtab.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0018-multipathd-use-volatile-qualifier-for-running_state.patch b/0018-multipathd-use-volatile-qualifier-for-running_state.patch new file mode 100644 index 0000000..400298e --- /dev/null +++ b/0018-multipathd-use-volatile-qualifier-for-running_state.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 12:44:59 +0200 +Subject: [PATCH] multipathd: use volatile qualifier for running_state + +While we access running_state only under the config_lock, +we sometimes do in a loop. Use the volatile qualifier to make +sure compilers can't optimize away the loads. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index e3f2328d..d081b3e9 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -126,7 +126,7 @@ int poll_dmevents = 0; + int poll_dmevents = 1; + #endif + /* Don't access this variable without holding config_lock */ +-enum daemon_status running_state = DAEMON_INIT; ++volatile enum daemon_status running_state = DAEMON_INIT; + pid_t daemon_pid; + pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t config_cond; +-- +2.17.2 + diff --git a/0019-multipath-tools-tests-test-lib.c-drop-__wrap_is_clai.patch b/0019-multipath-tools-tests-test-lib.c-drop-__wrap_is_clai.patch deleted file mode 100644 index e5882f6..0000000 --- a/0019-multipath-tools-tests-test-lib.c-drop-__wrap_is_clai.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0019-multipathd-generalize-and-fix-wait_for_state_change_.patch b/0019-multipathd-generalize-and-fix-wait_for_state_change_.patch new file mode 100644 index 0000000..73f99ec --- /dev/null +++ b/0019-multipathd-generalize-and-fix-wait_for_state_change_.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 12:46:36 +0200 +Subject: [PATCH] multipathd: generalize and fix wait_for_state_change_if() + +It's unlikely but not impossible that other threads change the state +while we're waiting, and if we grab the lock again, it's still not +what we wanted. We need to continue waiting until either the condition +is met, or time timeout expired. + +Moreover, generalize this code so that it can also be used in +set_config_state(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index d081b3e9..1fb0ee62 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -223,6 +223,23 @@ static void config_cleanup(__attribute__((unused)) void *arg) + pthread_mutex_unlock(&config_lock); + } + ++#define __wait_for_state_change(condition, ms) \ ++ ({ \ ++ struct timespec tmo; \ ++ int rc = 0; \ ++ \ ++ if (condition) { \ ++ get_monotonic_time(&tmo); \ ++ tmo.tv_nsec += (ms) * 1000 * 1000; \ ++ normalize_timespec(&tmo); \ ++ do \ ++ rc = pthread_cond_timedwait( \ ++ &config_cond, &config_lock, &tmo); \ ++ while (rc == 0 && (condition)); \ ++ } \ ++ rc; \ ++ }) ++ + /* + * If the current status is @oldstate, wait for at most @ms milliseconds + * for the state to change, and return the new state, which may still be +@@ -232,20 +249,14 @@ enum daemon_status wait_for_state_change_if(enum daemon_status oldstate, + unsigned long ms) + { + enum daemon_status st; +- struct timespec tmo; + + if (oldstate == DAEMON_SHUTDOWN) + return DAEMON_SHUTDOWN; + + pthread_mutex_lock(&config_lock); + pthread_cleanup_push(config_cleanup, NULL); ++ __wait_for_state_change(running_state == oldstate, ms); + st = running_state; +- if (st == oldstate && clock_gettime(CLOCK_MONOTONIC, &tmo) == 0) { +- tmo.tv_nsec += ms * 1000 * 1000; +- normalize_timespec(&tmo); +- (void)pthread_cond_timedwait(&config_cond, &config_lock, &tmo); +- st = running_state; +- } + pthread_cleanup_pop(1); + return st; + } +-- +2.17.2 + diff --git a/0020-multipath-tools-tests-directio-fix-Wmaybe-uninitaliz.patch b/0020-multipath-tools-tests-directio-fix-Wmaybe-uninitaliz.patch deleted file mode 100644 index 3bf6f75..0000000 --- a/0020-multipath-tools-tests-directio-fix-Wmaybe-uninitaliz.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0020-multipathd-set_config_state-avoid-code-duplication.patch b/0020-multipathd-set_config_state-avoid-code-duplication.patch new file mode 100644 index 0000000..a5310f3 --- /dev/null +++ b/0020-multipathd-set_config_state-avoid-code-duplication.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 12:48:55 +0200 +Subject: [PATCH] multipathd: set_config_state(): avoid code duplication + +Use __post_config_state() and __wait_for_state_change(). This +way __post_config_state() is the only place where running_state +is ever changed, and we avoid code duplication. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 23 +++++------------------ + 1 file changed, 5 insertions(+), 18 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 1fb0ee62..39aea4ad 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -292,27 +292,14 @@ 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; +- else if (running_state != DAEMON_IDLE) { +- struct timespec ts; +- +- get_monotonic_time(&ts); +- ts.tv_sec += 1; +- rc = pthread_cond_timedwait(&config_cond, +- &config_lock, &ts); +- } +- if (!rc && (running_state != DAEMON_SHUTDOWN)) { +- running_state = state; +- pthread_cond_broadcast(&config_cond); +-#ifdef USE_SYSTEMD +- do_sd_notify(old_state, state); +-#endif +- } ++ else ++ rc = __wait_for_state_change( ++ running_state != DAEMON_IDLE, 1000); ++ if (!rc) ++ __post_config_state(state); + } + pthread_cleanup_pop(1); + return rc; +-- +2.17.2 + diff --git a/0021-libmultipath-move-libsg-into-libmultipath.patch b/0021-libmultipath-move-libsg-into-libmultipath.patch deleted file mode 100644 index e7cf278..0000000 --- a/0021-libmultipath-move-libsg-into-libmultipath.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0021-multipathd-cancel-threads-early-during-shutdown.patch b/0021-multipathd-cancel-threads-early-during-shutdown.patch new file mode 100644 index 0000000..cc51513 --- /dev/null +++ b/0021-multipathd-cancel-threads-early-during-shutdown.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 4 Jan 2019 17:10:25 +0100 +Subject: [PATCH] multipathd: cancel threads early during shutdown + +Cancel the other threads before taking vecs->lock. This avoids +delays during shutdown caused e.g. by the checker thread holding +the vecs lock. + +Note: this makes it possible that cancelled threads leak memory, +because they can now be cancelled before having released the vecs +lock. I believe this is acceptable, as only threads are affected +that are cancelled during multipathd shutdown. + +Cc: Chongyun Wu +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 39aea4ad..d1f8cc1b 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3073,23 +3073,24 @@ child (__attribute__((unused)) void *param) + } + } + +- lock(&vecs->lock); ++ pthread_cancel(check_thr); ++ pthread_cancel(uevent_thr); ++ pthread_cancel(uxlsnr_thr); ++ pthread_cancel(uevq_thr); ++ if (poll_dmevents) ++ pthread_cancel(dmevent_thr); ++ + conf = get_multipath_config(); + queue_without_daemon = conf->queue_without_daemon; + put_multipath_config(conf); ++ ++ lock(&vecs->lock); + if (queue_without_daemon == QUE_NO_DAEMON_OFF) + vector_foreach_slot(vecs->mpvec, mpp, i) + dm_queue_if_no_path(mpp->alias, 0); + remove_maps_and_stop_waiters(vecs); + unlock(&vecs->lock); + +- pthread_cancel(check_thr); +- pthread_cancel(uevent_thr); +- pthread_cancel(uxlsnr_thr); +- pthread_cancel(uevq_thr); +- if (poll_dmevents) +- pthread_cancel(dmevent_thr); +- + pthread_join(check_thr, NULL); + pthread_join(uevent_thr, NULL); + pthread_join(uxlsnr_thr, NULL); +-- +2.17.2 + diff --git a/0022-multipath-tools-Makefile-add-install-dependency.patch b/0022-multipath-tools-Makefile-add-install-dependency.patch deleted file mode 100644 index 95c80fd..0000000 --- a/0022-multipath-tools-Makefile-add-install-dependency.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch b/0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch new file mode 100644 index 0000000..fe32b1a --- /dev/null +++ b/0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch @@ -0,0 +1,165 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 17:57:16 +0200 +Subject: [PATCH] multipath-tools: don't call dm_lib_release() any more + +The purpose of dm_lib_release() is to release stacked device node +operations in libdevmapper. This is functionality we don't need and +use any more, as we rely on udev to set up device nodes and symlinks. + +We always set DM_UDEV_DISABLE_LIBRARY_FALLBACK when we run dm tasks. +In the standard CREATE and REMOVE cases, libdevmapper doesn't +stack any operations if this flag is set. The only exceptions are + + a) RESUME operations with DM_ADD_NODE_ON_RESUME set. This happens +implicity when we create new maps + b) RENAME operations + +In both cases, we call dm_udev_wait() after the libdm operation, which +calls update_devs() and thus has the same effect as dm_lib_release(), +cleaning out stacked operations. + +OTOH, dm_lib_releases() accesses static variables in libdevmapper, so +calling it might be racy. + +Drop the calls to dm_lib_release(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + kpartx/kpartx.c | 1 - + libmpathpersist/mpath_persist.c | 1 - + multipath/main.c | 1 - + multipathd/cli_handlers.c | 2 -- + multipathd/main.c | 15 ++------------- + 5 files changed, 2 insertions(+), 18 deletions(-) + +diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c +index 4a0aae93..6a7933fa 100644 +--- a/kpartx/kpartx.c ++++ b/kpartx/kpartx.c +@@ -681,7 +681,6 @@ main(int argc, char **argv){ + } + + end: +- dm_lib_release(); + dm_lib_exit(); + + return r; +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 4b3f3e0d..cc4a088d 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -56,7 +56,6 @@ mpath_lib_init (void) + int + mpath_lib_exit (struct config *conf) + { +- dm_lib_release(); + dm_lib_exit(); + cleanup_prio(); + cleanup_checkers(); +diff --git a/multipath/main.c b/multipath/main.c +index 9e920d89..dc4974b9 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -1063,7 +1063,6 @@ main (int argc, char *argv[]) + condlog(3, "restart multipath configuration process"); + + out: +- dm_lib_release(); + dm_lib_exit(); + + cleanup_foreign(); +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 235e2a2e..54635738 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -860,7 +860,6 @@ cli_add_map (void * v, char ** reply, int * len, void * data) + != CP_OK) + condlog(2, "%s: coalesce_paths failed", + param); +- dm_lib_release(); + FREE(refwwid); + } + } /*we attempt to create device only once*/ +@@ -1032,7 +1031,6 @@ cli_resize(void *v, char **reply, int *len, void *data) + if (resize_map(mpp, size, vecs) != 0) + return 1; + +- dm_lib_release(); + if (setup_multipath(vecs, mpp) != 0) + return 1; + sync_map_state(mpp); +diff --git a/multipathd/main.c b/multipathd/main.c +index d1f8cc1b..5cc34357 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -510,7 +510,6 @@ retry: + sleep(1); + goto retry; + } +- dm_lib_release(); + + fail: + if (new_map && (retries < 0 || wait_for_events(mpp, vecs))) { +@@ -611,10 +610,8 @@ coalesce_maps(struct vectors *vecs, vector nmpv) + vector_del_slot(ompv, i); + i--; + } +- else { +- dm_lib_release(); ++ else + condlog(2, "%s devmap removed", ompp->alias); +- } + } else if (reassign_maps) { + condlog(3, "%s: Reassign existing device-mapper" + " devices", ompp->alias); +@@ -660,10 +657,8 @@ flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths) + } + return r; + } +- else { +- dm_lib_release(); ++ else + condlog(2, "%s: map flushed", mpp->alias); +- } + + orphan_paths(vecs->pathvec, mpp, "map flushed"); + remove_map_and_stop_waiter(mpp, vecs); +@@ -1080,7 +1075,6 @@ rescan: + else + goto fail_map; + } +- dm_lib_release(); + + if ((mpp->action == ACT_CREATE || + (mpp->action == ACT_NOTHING && start_waiter && !mpp->waiter)) && +@@ -1947,8 +1941,6 @@ int reload_and_sync_map(struct multipath *mpp, + { + if (reload_map(vecs, mpp, refresh, 1)) + return 1; +- +- dm_lib_release(); + if (setup_multipath(vecs, mpp) != 0) + return 2; + sync_map_state(mpp); +@@ -2631,8 +2623,6 @@ configure (struct vectors * vecs) + goto fail; + } + +- dm_lib_release(); +- + if (should_exit()) + goto fail; + +@@ -3115,7 +3105,6 @@ child (__attribute__((unused)) void *param) + if (poll_dmevents) + cleanup_dmevent_waiter(); + +- dm_lib_release(); + dm_lib_exit(); + + /* We're done here */ +-- +2.17.2 + diff --git a/0023-libmultipath-devmapper-refactor-libdm-version-determ.patch b/0023-libmultipath-devmapper-refactor-libdm-version-determ.patch new file mode 100644 index 0000000..b5e96b2 --- /dev/null +++ b/0023-libmultipath-devmapper-refactor-libdm-version-determ.patch @@ -0,0 +1,506 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 23:12:15 +0200 +Subject: [PATCH] libmultipath: devmapper: refactor libdm version determination + +As one step towards bundling all possibly racy libdm init calls into a single +function, split the code for determining and checking versions of +libdm and kernel components. Provide a generic helper +libmp_get_version() that makes sure the versions are "lazily" initialized. + +External callers may use dm_prereq(), like before. +Minor API change: dm_prereq() does not nullify the argument any more +if an error is encountered. + +Remove the conf->version field, which isn't needed any more after this +change. This makes it necessary to fixup the hwtable test. Also, it +represents an incompatible ABI change as offsets in "struct config" are +changed, and two symbols removed. Bump the ABI major version to 2. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.h | 1 - + libmultipath/devmapper.c | 162 ++++++++++++++++++++---------- + libmultipath/devmapper.h | 10 +- + libmultipath/libmultipath.version | 5 +- + libmultipath/propsel.c | 10 +- + multipathd/dmevents.c | 2 +- + multipathd/main.c | 1 - + tests/Makefile | 2 +- + tests/hwtable.c | 3 - + tests/test-lib.c | 13 +++ + 10 files changed, 141 insertions(+), 68 deletions(-) + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 290aea58..7af19844 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; +- unsigned int version[3]; + unsigned int sequence_nr; + + char * multipath_dir; +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 0bc1d16e..3e36129b 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -26,6 +26,7 @@ + #include "sysfs.h" + #include "config.h" + #include "wwids.h" ++#include "version.h" + + #include "log_pthread.h" + #include +@@ -34,7 +35,13 @@ + #define MAX_WAIT 5 + #define LOOPS_PER_SEC 5 + ++#define INVALID_VERSION ~0U ++static unsigned int dm_library_version[3] = { INVALID_VERSION, }; ++static unsigned int dm_kernel_version[3] = { INVALID_VERSION, }; ++static unsigned int dm_mpath_target_version[3] = { INVALID_VERSION, }; ++ + static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT; ++static pthread_once_t versions_initialized = PTHREAD_ONCE_INIT; + + static int dm_conf_verbosity; + +@@ -102,7 +109,7 @@ dm_write_log (int level, const char *file, int line, const char *f, ...) + return; + } + +-void dm_init(int v) ++static void dm_init(int v) + { + /* + * This maps libdm's standard loglevel _LOG_WARN (= 4), which is rather +@@ -112,61 +119,68 @@ void dm_init(int v) + dm_log_init(&dm_write_log); + } + ++static void init_dm_library_version(void) ++{ ++ char version[64]; ++ unsigned int v[3]; ++ ++ dm_get_library_version(version, sizeof(version)); ++ if (sscanf(version, "%u.%u.%u ", &v[0], &v[1], &v[2]) != 3) { ++ condlog(0, "invalid libdevmapper version %s", version); ++ return; ++ } ++ memcpy(dm_library_version, v, sizeof(dm_library_version)); ++ condlog(3, "libdevmapper version %u.%.2u.%.2u", ++ dm_library_version[0], dm_library_version[1], ++ dm_library_version[2]); ++} ++ + static int + dm_lib_prereq (void) + { +- char version[64]; +- int v[3]; ++ + #if defined(LIBDM_API_HOLD_CONTROL) +- int minv[3] = {1, 2, 111}; ++ unsigned int minv[3] = {1, 2, 111}; + #elif defined(LIBDM_API_GET_ERRNO) +- int minv[3] = {1, 2, 99}; ++ unsigned int minv[3] = {1, 2, 99}; + #elif defined(LIBDM_API_DEFERRED) +- int minv[3] = {1, 2, 89}; ++ unsigned int minv[3] = {1, 2, 89}; + #elif defined(DM_SUBSYSTEM_UDEV_FLAG0) +- int minv[3] = {1, 2, 82}; ++ unsigned int minv[3] = {1, 2, 82}; + #elif defined(LIBDM_API_COOKIE) +- int minv[3] = {1, 2, 38}; ++ unsigned int minv[3] = {1, 2, 38}; + #else +- int minv[3] = {1, 2, 8}; ++ unsigned int minv[3] = {1, 2, 8}; + #endif + +- dm_get_library_version(version, sizeof(version)); +- condlog(3, "libdevmapper version %s", version); +- if (sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]) != 3) { +- condlog(0, "invalid libdevmapper version %s", version); +- return 1; +- } +- +- if VERSION_GE(v, minv) ++ if (VERSION_GE(dm_library_version, minv)) + return 0; +- condlog(0, "libdevmapper version must be >= %d.%.2d.%.2d", ++ condlog(0, "libdevmapper version must be >= %u.%.2u.%.2u", + minv[0], minv[1], minv[2]); + return 1; + } + +-int +-dm_drv_version(unsigned int *v) ++static void init_dm_drv_version(void) + { + char buff[64]; +- +- v[0] = 0; +- v[1] = 0; +- v[2] = 0; ++ unsigned int v[3]; + + if (!dm_driver_version(buff, sizeof(buff))) { + condlog(0, "cannot get kernel dm version"); +- return 1; ++ return; + } + if (sscanf(buff, "%u.%u.%u ", &v[0], &v[1], &v[2]) != 3) { + condlog(0, "invalid kernel dm version '%s'", buff); +- return 1; ++ return; + } +- return 0; ++ memcpy(dm_kernel_version, v, sizeof(dm_library_version)); ++ condlog(3, "kernel device mapper v%u.%u.%u", ++ dm_kernel_version[0], ++ dm_kernel_version[1], ++ dm_kernel_version[2]); + } + +-int +-dm_tgt_version (unsigned int * version, char * str) ++static int dm_tgt_version (unsigned int *version, char *str) + { + int r = 2; + struct dm_task *dmt; +@@ -174,10 +188,11 @@ dm_tgt_version (unsigned int * version, char * str) + struct dm_versions *last_target; + unsigned int *v; + +- version[0] = 0; +- version[1] = 0; +- version[2] = 0; +- ++ /* ++ * We have to call dm_task_create() and not libmp_dm_task_create() ++ * here to avoid a recursive invocation of ++ * pthread_once(&dm_initialized), which would cause a deadlock. ++ */ + if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) + return 1; + +@@ -213,26 +228,25 @@ out: + return r; + } + +-static int +-dm_tgt_prereq (unsigned int *ver) ++static void init_dm_mpath_version(void) + { +- unsigned int minv[3] = {1, 0, 3}; +- unsigned int version[3] = {0, 0, 0}; +- unsigned int * v = version; +- +- if (dm_tgt_version(v, TGT_MPATH)) { +- /* in doubt return not capable */ +- return 1; +- } ++ if (!dm_tgt_version(dm_mpath_target_version, TGT_MPATH)) ++ condlog(3, "DM multipath kernel driver v%u.%u.%u", ++ dm_mpath_target_version[0], ++ dm_mpath_target_version[1], ++ dm_mpath_target_version[2]); ++} + +- /* test request based multipath capability */ +- condlog(3, "DM multipath kernel driver v%u.%u.%u", +- v[0], v[1], v[2]); ++static int dm_tgt_prereq (unsigned int *ver) ++{ ++ unsigned int minv[3] = {1, 0, 3}; + +- if (VERSION_GE(v, minv)) { +- ver[0] = v[0]; +- ver[1] = v[1]; +- ver[2] = v[2]; ++ if (VERSION_GE(dm_mpath_target_version, minv)) { ++ if (ver) { ++ ver[0] = dm_mpath_target_version[0]; ++ ver[1] = dm_mpath_target_version[1]; ++ ver[2] = dm_mpath_target_version[2]; ++ } + return 0; + } + +@@ -241,13 +255,60 @@ dm_tgt_prereq (unsigned int *ver) + return 1; + } + ++static void _init_versions(void) ++{ ++ dlog(logsink, 3, VERSION_STRING); ++ init_dm_library_version(); ++ init_dm_drv_version(); ++ init_dm_mpath_version(); ++} ++ ++static int init_versions(void) { ++ pthread_once(&versions_initialized, _init_versions); ++ return (dm_library_version[0] == INVALID_VERSION || ++ dm_kernel_version[0] == INVALID_VERSION || ++ dm_mpath_target_version[0] == INVALID_VERSION); ++} ++ + int dm_prereq(unsigned int *v) + { ++ if (init_versions()) ++ return 1; + if (dm_lib_prereq()) + return 1; + return dm_tgt_prereq(v); + } + ++int libmp_get_version(int which, unsigned int version[3]) ++{ ++ unsigned int *src_version; ++ ++ init_versions(); ++ switch (which) { ++ case DM_LIBRARY_VERSION: ++ src_version = dm_library_version; ++ break; ++ case DM_KERNEL_VERSION: ++ src_version = dm_kernel_version; ++ break; ++ case DM_MPATH_TARGET_VERSION: ++ src_version = dm_mpath_target_version; ++ break; ++ case MULTIPATH_VERSION: ++ version[0] = (VERSION_CODE >> 16) & 0xff; ++ version[1] = (VERSION_CODE >> 8) & 0xff; ++ version[2] = VERSION_CODE & 0xff; ++ return 0; ++ default: ++ condlog(0, "%s: invalid value for 'which'", __func__); ++ return 1; ++ } ++ if (src_version[0] == INVALID_VERSION) ++ return 1; ++ memcpy(version, src_version, 3 * sizeof(*version)); ++ return 0; ++} ++ + static int libmp_dm_udev_sync = 0; + + void libmp_udev_set_sync_support(int on) +@@ -265,7 +326,6 @@ static void libmp_dm_init(void) + exit(1); + conf = get_multipath_config(); + verbosity = conf->verbosity; +- memcpy(conf->version, version, sizeof(version)); + put_multipath_config(conf); + dm_init(verbosity); + #ifdef LIBDM_API_HOLD_CONTROL +diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h +index f469c98a..a0bcd137 100644 +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -33,13 +33,10 @@ enum { + DMP_NOT_FOUND, + }; + +-void dm_init(int verbosity); + 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); +-int dm_tgt_version (unsigned int * version, char * str); + int dm_simplecmd_flush (int, const char *, uint16_t); + int dm_simplecmd_noflush (int, const char *, uint16_t); + int dm_addmap_create (struct multipath *mpp, char *params); +@@ -89,6 +86,13 @@ struct multipath *dm_get_multipath(const char *name); + #include + #define dm_task_get_errno(x) errno + #endif ++enum { ++ DM_LIBRARY_VERSION, ++ DM_KERNEL_VERSION, ++ DM_MPATH_TARGET_VERSION, ++ MULTIPATH_VERSION ++}; ++int libmp_get_version(int which, unsigned int version[3]); + + #define dm_log_error(lvl, cmd, dmt) \ + condlog(lvl, "%s: libdm task=%d error: %s", __func__, \ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index a6bf8218..ab5bb0ad 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -31,7 +31,7 @@ + * The new version inherits the previous ones. + */ + +-LIBMULTIPATH_1.0.0 { ++LIBMULTIPATH_2.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -65,7 +65,6 @@ global: + disassemble_status; + dlog; + dm_cancel_deferred_remove; +- dm_drv_version; + dm_enablegroup; + dm_fail_path; + _dm_flush_map; +@@ -87,7 +86,6 @@ global: + dm_reinstate_path; + dm_simplecmd_noflush; + dm_switchgroup; +- dm_tgt_version; + domap; + ensure_directories_exist; + extract_hwe_from_path; +@@ -128,6 +126,7 @@ global: + is_path_valid; + is_quote; + libmp_dm_task_create; ++ libmp_get_version; + libmp_udev_set_sync_support; + load_config; + log_thread_reset; +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 40201344..3f2c2cfa 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -735,9 +735,10 @@ out: + + int select_minio(struct config *conf, struct multipath *mp) + { +- unsigned int minv_dmrq[3] = {1, 1, 0}; ++ unsigned int minv_dmrq[3] = {1, 1, 0}, version[3]; + +- if (VERSION_GE(conf->version, minv_dmrq)) ++ if (!libmp_get_version(DM_MPATH_TARGET_VERSION, version) ++ && VERSION_GE(version, minv_dmrq)) + return select_minio_rq(conf, mp); + else + return select_minio_bio(conf, mp); +@@ -820,9 +821,10 @@ out: + int select_retain_hwhandler(struct config *conf, struct multipath *mp) + { + const char *origin; +- unsigned int minv_dm_retain[3] = {1, 5, 0}; ++ unsigned int minv_dm_retain[3] = {1, 5, 0}, version[3]; + +- if (!VERSION_GE(conf->version, minv_dm_retain)) { ++ if (!libmp_get_version(DM_MPATH_TARGET_VERSION, version) && ++ !VERSION_GE(version, minv_dm_retain)) { + mp->retain_hwhandler = RETAIN_HWHANDLER_OFF; + origin = "(setting: WARNING, requires kernel dm-mpath version >= 1.5.0)"; + goto out; +diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c +index 5f2d210d..fc97c8a2 100644 +--- a/multipathd/dmevents.c ++++ b/multipathd/dmevents.c +@@ -60,7 +60,7 @@ int dmevent_poll_supported(void) + { + unsigned int v[3]; + +- if (dm_drv_version(v)) ++ if (libmp_get_version(DM_KERNEL_VERSION, v)) + return 0; + + if (VERSION_GE(v, DM_VERSION_FOR_ARM_POLL)) +diff --git a/multipathd/main.c b/multipathd/main.c +index 5cc34357..00b66ba4 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2709,7 +2709,6 @@ reconfigure (struct vectors * vecs) + /* Re-read any timezone changes */ + tzset(); + +- dm_tgt_version(conf->version, TGT_MPATH); + if (verbosity) + conf->verbosity = verbosity; + if (bindings_read_only) +diff --git a/tests/Makefile b/tests/Makefile +index 9658c9fd..78777bec 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -43,7 +43,7 @@ endif + dmevents-test_LIBDEPS = -lpthread -ldevmapper -lurcu + hwtable-test_TESTDEPS := test-lib.o + hwtable-test_OBJDEPS := ../libmultipath/discovery.o ../libmultipath/blacklist.o \ +- ../libmultipath/structs.o ++ ../libmultipath/structs.o ../libmultipath/propsel.o + hwtable-test_LIBDEPS := -ludev -lpthread -ldl + blacklist-test_TESTDEPS := test-log.o + blacklist-test_OBJDEPS := ../libmultipath/blacklist.o +diff --git a/tests/hwtable.c b/tests/hwtable.c +index 12660da2..57f832b7 100644 +--- a/tests/hwtable.c ++++ b/tests/hwtable.c +@@ -30,8 +30,6 @@ + #define N_CONF_FILES 2 + + static const char tmplate[] = "/tmp/hwtable-XXXXXX"; +-/* pretend new dm, use minio_rq */ +-static const unsigned int dm_tgt_version[3] = { 1, 1, 1 }; + + struct key_value { + const char *key; +@@ -360,7 +358,6 @@ static void write_device(FILE *ff, int nkv, const struct key_value *kv) + assert_ptr_not_equal(__cf, NULL); \ + assert_ptr_not_equal(__cf->hwtable, NULL); \ + __cf->verbosity = VERBOSITY; \ +- memcpy(&__cf->version, dm_tgt_version, sizeof(__cf->version)); \ + __cf; }) + + #define FREE_CONFIG(conf) do { \ +diff --git a/tests/test-lib.c b/tests/test-lib.c +index b7c09cc2..e7663f9a 100644 +--- a/tests/test-lib.c ++++ b/tests/test-lib.c +@@ -56,6 +56,15 @@ int __wrap_execute_program(char *path, char *value, int len) + return 0; + } + ++int __wrap_libmp_get_version(int which, unsigned int version[3]) ++{ ++ unsigned int *vers = mock_ptr_type(unsigned int *); ++ ++ condlog(4, "%s: %d", __func__, which); ++ memcpy(version, vers, 3 * sizeof(unsigned int)); ++ return 0; ++} ++ + struct udev_list_entry + *__wrap_udev_device_get_properties_list_entry(struct udev_device *ud) + { +@@ -339,6 +348,8 @@ struct multipath *__mock_multipath(struct vectors *vecs, struct path *pp) + struct multipath *mp; + struct config *conf; + struct mocked_path mop; ++ /* pretend new dm, use minio_rq, */ ++ static const unsigned int fake_dm_tgt_version[3] = { 1, 1, 1 }; + + mocked_path_from_path(&mop, pp); + /* pathinfo() call in adopt_paths */ +@@ -351,7 +362,9 @@ struct multipath *__mock_multipath(struct vectors *vecs, struct path *pp) + conf = get_multipath_config(); + select_pgpolicy(conf, mp); + select_no_path_retry(conf, mp); ++ will_return(__wrap_libmp_get_version, fake_dm_tgt_version); + select_retain_hwhandler(conf, mp); ++ will_return(__wrap_libmp_get_version, fake_dm_tgt_version); + select_minio(conf, mp); + put_multipath_config(conf); + +-- +2.17.2 + diff --git a/0023-libmultipath-make-libmp_dm_init-optional.patch b/0023-libmultipath-make-libmp_dm_init-optional.patch deleted file mode 100644 index 588fd87..0000000 --- a/0023-libmultipath-make-libmp_dm_init-optional.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0024-libmultipath-make-sysfs_is_multipathed-able-to-retur.patch b/0024-libmultipath-make-sysfs_is_multipathed-able-to-retur.patch deleted file mode 100644 index 47c7a80..0000000 --- a/0024-libmultipath-make-sysfs_is_multipathed-able-to-retur.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch b/0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch new file mode 100644 index 0000000..026dd7c --- /dev/null +++ b/0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch @@ -0,0 +1,437 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Sep 2020 23:38:48 +0200 +Subject: [PATCH] libmultipath: protect racy libdevmapper calls with a mutex + +dm_udev_wait() and dm_task_run() may access global / static state +in libdevmapper. They need to be protected by a lock in in our +multithreaded library. + +The modified call sequence requires fixing the dmevents test: +devmapper.c must be added to dmevents-test_OBJDEPS to catch calls +to dm_task_run(). Also, the call to dmevent_poll_supported() in +setup() will cause init_versions() to be called, which requires +bypassing the wrappers in the test setup phase. + +Cc: lixiaokeng@huawei.com + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/devmapper.c | 73 +++++++++++++++++++------------ + libmultipath/devmapper.h | 2 + + libmultipath/libmultipath.version | 6 +++ + libmultipath/util.c | 5 +++ + libmultipath/util.h | 1 + + multipathd/dmevents.c | 2 +- + multipathd/waiter.c | 2 +- + tests/Makefile | 1 + + tests/dmevents.c | 12 +++++ + 9 files changed, 75 insertions(+), 29 deletions(-) + +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 3e36129b..4eb6f539 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -42,6 +42,7 @@ static unsigned int dm_mpath_target_version[3] = { INVALID_VERSION, }; + + static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT; + static pthread_once_t versions_initialized = PTHREAD_ONCE_INIT; ++static pthread_mutex_t libmp_dm_lock = PTHREAD_MUTEX_INITIALIZER; + + static int dm_conf_verbosity; + +@@ -59,16 +60,34 @@ static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a) + return 1; + } + +-void dm_udev_wait(unsigned int c) ++static void libmp_udev_wait(unsigned int c) + { + } + +-void dm_udev_set_sync_support(int c) ++static void dm_udev_set_sync_support(int c) + { + } +- ++#else ++static void libmp_udev_wait(unsigned int c) ++{ ++ pthread_mutex_lock(&libmp_dm_lock); ++ pthread_cleanup_push(cleanup_mutex, &libmp_dm_lock); ++ dm_udev_wait(c); ++ pthread_cleanup_pop(1); ++} + #endif + ++int libmp_dm_task_run(struct dm_task *dmt) ++{ ++ int r; ++ ++ pthread_mutex_lock(&libmp_dm_lock); ++ pthread_cleanup_push(cleanup_mutex, &libmp_dm_lock); ++ r = dm_task_run(dmt); ++ pthread_cleanup_pop(1); ++ return r; ++} ++ + __attribute__((format(printf, 4, 5))) static void + dm_write_log (int level, const char *file, int line, const char *f, ...) + { +@@ -198,7 +217,7 @@ static int dm_tgt_version (unsigned int *version, char *str) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(2, DM_DEVICE_LIST_VERSIONS, dmt); + condlog(0, "Can not communicate with kernel DM"); + goto out; +@@ -382,12 +401,12 @@ dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t + DM_UDEV_DISABLE_LIBRARY_FALLBACK | udev_flags)) + goto out; + +- r = dm_task_run (dmt); ++ r = libmp_dm_task_run (dmt); + if (!r) + dm_log_error(2, task, dmt); + + if (udev_wait_flag) +- dm_udev_wait(cookie); ++ libmp_udev_wait(cookie); + out: + dm_task_destroy (dmt); + return r; +@@ -474,12 +493,12 @@ dm_addmap (int task, const char *target, struct multipath *mpp, + !dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto freeout; + +- r = dm_task_run (dmt); ++ r = libmp_dm_task_run (dmt); + if (!r) + dm_log_error(2, task, dmt); + + if (task == DM_DEVICE_CREATE) +- dm_udev_wait(cookie); ++ libmp_udev_wait(cookie); + freeout: + if (prefixed_uuid) + FREE(prefixed_uuid); +@@ -589,7 +608,7 @@ do_get_info(const char *name, struct dm_info *info) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto out; + } +@@ -630,7 +649,7 @@ int dm_get_map(const char *name, unsigned long long *size, char *outparams) + dm_task_no_open_count(dmt); + + errno = 0; +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + if (dm_task_get_errno(dmt) == ENXIO) + r = DMP_NOT_FOUND; +@@ -672,7 +691,7 @@ dm_get_prefixed_uuid(const char *name, char *uuid, int uuid_len) + if (!dm_task_set_name (dmt, name)) + goto uuidout; + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto uuidout; + } +@@ -743,7 +762,7 @@ int dm_get_status(const char *name, char *outstatus) + dm_task_no_open_count(dmt); + + errno = 0; +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_STATUS, dmt); + if (dm_task_get_errno(dmt) == ENXIO) + r = DMP_NOT_FOUND; +@@ -796,7 +815,7 @@ int dm_type(const char *name, char *type) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + goto out; + } +@@ -840,7 +859,7 @@ int dm_is_mpath(const char *name) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + goto out_task; + } +@@ -904,7 +923,7 @@ dm_map_present_by_uuid(const char *uuid) + if (!dm_task_set_uuid(dmt, prefixed_uuid)) + goto out_task; + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto out_task; + } +@@ -950,7 +969,7 @@ dm_get_opencount (const char * mapname) + if (!dm_task_set_name(dmt, mapname)) + goto out; + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_INFO, dmt); + goto out; + } +@@ -1110,7 +1129,7 @@ int dm_flush_maps (int need_suspend, int retries) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run (dmt)) { ++ if (!libmp_dm_task_run (dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto out; + } +@@ -1156,7 +1175,7 @@ dm_message(const char * mapname, char * message) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(2, DM_DEVICE_TARGET_MSG, dmt); + goto out; + } +@@ -1276,7 +1295,7 @@ dm_get_maps (vector mp) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto out; + } +@@ -1361,7 +1380,7 @@ dm_mapname(int major, int minor) + * daemon uev_trigger -> uev_add_map + */ + while (--loop) { +- r = dm_task_run(dmt); ++ r = libmp_dm_task_run(dmt); + + if (r) + break; +@@ -1406,7 +1425,7 @@ do_foreach_partmaps (const char * mapname, + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto out; + } +@@ -1641,11 +1660,11 @@ dm_rename (const char * old, char * new, char *delim, int skip_kpartx) + + if (!dm_task_set_cookie(dmt, &cookie, udev_flags)) + goto out; +- r = dm_task_run(dmt); ++ r = libmp_dm_task_run(dmt); + if (!r) + dm_log_error(2, DM_DEVICE_RENAME, dmt); + +- dm_udev_wait(cookie); ++ libmp_udev_wait(cookie); + + out: + dm_task_destroy(dmt); +@@ -1687,7 +1706,7 @@ int dm_reassign_table(const char *name, char *old, char *new) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_TABLE, dmt); + goto out; + } +@@ -1720,7 +1739,7 @@ int dm_reassign_table(const char *name, char *old, char *new) + if (modified) { + dm_task_no_open_count(reload_dmt); + +- if (!dm_task_run(reload_dmt)) { ++ if (!libmp_dm_task_run(reload_dmt)) { + dm_log_error(3, DM_DEVICE_RELOAD, reload_dmt); + condlog(3, "%s: failed to reassign targets", name); + goto out_reload; +@@ -1767,7 +1786,7 @@ int dm_reassign(const char *mapname) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_DEPS, dmt); + goto out; + } +@@ -1835,7 +1854,7 @@ int dm_setgeometry(struct multipath *mpp) + goto out; + } + +- r = dm_task_run(dmt); ++ r = libmp_dm_task_run(dmt); + if (!r) + dm_log_error(3, DM_DEVICE_SET_GEOMETRY, dmt); + out: +diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h +index a0bcd137..fa6b3c53 100644 +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -93,6 +93,8 @@ enum { + MULTIPATH_VERSION + }; + int libmp_get_version(int which, unsigned int version[3]); ++struct dm_task; ++int libmp_dm_task_run(struct dm_task *dmt); + + #define dm_log_error(lvl, cmd, dmt) \ + condlog(lvl, "%s: libdm task=%d error: %s", __func__, \ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index ab5bb0ad..97acdbb2 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -245,3 +245,9 @@ global: + local: + *; + }; ++ ++LIBMULTIPATH_2.1.0 { ++global: ++ libmp_dm_task_run; ++ cleanup_mutex; ++} LIBMULTIPATH_2.0.0; +diff --git a/libmultipath/util.c b/libmultipath/util.c +index 1f977792..0e37f3ff 100644 +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -424,6 +424,11 @@ void cleanup_free_ptr(void *arg) + free(*p); + } + ++void cleanup_mutex(void *arg) ++{ ++ pthread_mutex_unlock(arg); ++} ++ + struct bitfield *alloc_bitfield(unsigned int maxbit) + { + unsigned int n; +diff --git a/libmultipath/util.h b/libmultipath/util.h +index ac19473e..e9b48f9f 100644 +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -49,6 +49,7 @@ int should_exit(void); + + void close_fd(void *arg); + void cleanup_free_ptr(void *arg); ++void cleanup_mutex(void *arg); + + struct scandir_result { + struct dirent **di; +diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c +index fc97c8a2..b561cbfd 100644 +--- a/multipathd/dmevents.c ++++ b/multipathd/dmevents.c +@@ -156,7 +156,7 @@ static int dm_get_events(void) + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) { ++ if (!libmp_dm_task_run(dmt)) { + dm_log_error(3, DM_DEVICE_LIST, dmt); + goto fail; + } +diff --git a/multipathd/waiter.c b/multipathd/waiter.c +index 3bc69807..bbe6c2a1 100644 +--- a/multipathd/waiter.c ++++ b/multipathd/waiter.c +@@ -118,7 +118,7 @@ static int waiteventloop (struct event_thread *waiter) + pthread_sigmask(SIG_UNBLOCK, &set, &oldset); + + pthread_testcancel(); +- r = dm_task_run(waiter->dmt); ++ r = libmp_dm_task_run(waiter->dmt); + if (!r) + dm_log_error(2, DM_DEVICE_WAITEVENT, waiter->dmt); + pthread_testcancel(); +diff --git a/tests/Makefile b/tests/Makefile +index 78777bec..908407ea 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -40,6 +40,7 @@ endif + # linker input file). + # XYZ-test_LIBDEPS: Additional libs to link for this test + ++dmevents-test_OBJDEPS = ../libmultipath/devmapper.o + dmevents-test_LIBDEPS = -lpthread -ldevmapper -lurcu + hwtable-test_TESTDEPS := test-lib.o + hwtable-test_OBJDEPS := ../libmultipath/discovery.o ../libmultipath/blacklist.o \ +diff --git a/tests/dmevents.c b/tests/dmevents.c +index bee117ac..b7c5122b 100644 +--- a/tests/dmevents.c ++++ b/tests/dmevents.c +@@ -179,6 +179,8 @@ struct dm_names *build_dm_names(void) + return names; + } + ++static bool setup_done; ++ + static int setup(void **state) + { + if (dmevent_poll_supported()) { +@@ -186,6 +188,7 @@ static int setup(void **state) + *state = &data; + } else + *state = NULL; ++ setup_done = true; + return 0; + } + +@@ -262,14 +265,20 @@ struct dm_task *__wrap_libmp_dm_task_create(int task) + return mock_type(struct dm_task *); + } + ++int __real_dm_task_no_open_count(struct dm_task *dmt); + int __wrap_dm_task_no_open_count(struct dm_task *dmt) + { ++ if (!setup_done) ++ return __real_dm_task_no_open_count(dmt); + assert_ptr_equal((struct test_data *)dmt, &data); + return mock_type(int); + } + ++int __real_dm_task_run(struct dm_task *dmt); + int __wrap_dm_task_run(struct dm_task *dmt) + { ++ if (!setup_done) ++ return __real_dm_task_run(dmt); + assert_ptr_equal((struct test_data *)dmt, &data); + return mock_type(int); + } +@@ -291,8 +300,11 @@ struct dm_names * __wrap_dm_task_get_names(struct dm_task *dmt) + return data.names; + } + ++void __real_dm_task_destroy(struct dm_task *dmt); + void __wrap_dm_task_destroy(struct dm_task *dmt) + { ++ if (!setup_done) ++ return __real_dm_task_destroy(dmt); + assert_ptr_equal((struct test_data *)dmt, &data); + + if (data.names) { +-- +2.17.2 + diff --git a/0074-libmultipath-constify-file-argument-in-config-parser.patch b/0025-libmultipath-constify-file-argument-in-config-parser.patch similarity index 79% rename from 0074-libmultipath-constify-file-argument-in-config-parser.patch rename to 0025-libmultipath-constify-file-argument-in-config-parser.patch index ffef052..9470cf4 100644 --- a/0074-libmultipath-constify-file-argument-in-config-parser.patch +++ b/0025-libmultipath-constify-file-argument-in-config-parser.patch @@ -1,10 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:07 +0200 +Date: Wed, 16 Sep 2020 12:02:01 +0200 Subject: [PATCH] libmultipath: constify file argument in config parser Reviewed-by: Benjamin Marzinski -Signed-off-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- libmultipath/config.c | 3 +-- @@ -14,10 +13,10 @@ Signed-off-by: Benjamin Marzinski 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libmultipath/config.c b/libmultipath/config.c -index a253a936..1818f8b9 100644 +index df0f8f45..5c91a09d 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -718,8 +718,7 @@ static void set_max_checkint_from_watchdog(struct config *conf) +@@ -719,8 +719,7 @@ static void set_max_checkint_from_watchdog(struct config *conf) } #endif @@ -28,10 +27,10 @@ index a253a936..1818f8b9 100644 struct config *conf = alloc_config(); diff --git a/libmultipath/config.h b/libmultipath/config.h -index c7a73fba..78375f2f 100644 +index 7af19844..ace403b8 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h -@@ -253,7 +253,7 @@ void free_mptable (vector mptable); +@@ -251,7 +251,7 @@ void free_mptable (vector mptable); int store_hwe (vector hwtable, struct hwentry *); @@ -41,10 +40,10 @@ index c7a73fba..78375f2f 100644 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 +index ed6d5d6d..163ffbc9 100644 --- a/libmultipath/parser.c +++ b/libmultipath/parser.c -@@ -400,7 +400,7 @@ set_regex_value(vector strvec) +@@ -390,7 +390,7 @@ oom: /* non-recursive configuration stream handler */ static int kw_level = 0; @@ -53,16 +52,16 @@ index a7285a35..d150e7b2 100644 { char *tmp; int i; -@@ -444,7 +444,7 @@ is_sublevel_keyword(char *str) +@@ -434,7 +434,7 @@ is_sublevel_keyword(char *str) } int -validate_config_strvec(vector strvec, char *file) +validate_config_strvec(vector strvec, const char *file) { - char *str; + char *str = NULL; int i; -@@ -507,7 +507,8 @@ validate_config_strvec(vector strvec, char *file) +@@ -499,7 +499,8 @@ validate_config_strvec(vector strvec, char *file) } static int @@ -72,7 +71,7 @@ index a7285a35..d150e7b2 100644 { int i; int r = 0, t; -@@ -592,7 +593,7 @@ out: +@@ -584,7 +585,7 @@ out: /* Data initialization */ int @@ -82,13 +81,13 @@ index a7285a35..d150e7b2 100644 int r; FILE *stream; diff --git a/libmultipath/parser.h b/libmultipath/parser.h -index b7917052..b385fb9e 100644 +index 62906e98..06666ccf 100644 --- a/libmultipath/parser.h +++ b/libmultipath/parser.h -@@ -78,7 +78,7 @@ extern void free_keywords(vector keywords); +@@ -77,7 +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 int process_file(struct config *conf, const char *conf_file); extern struct keyword * find_keyword(vector keywords, vector v, char * name); diff --git a/0025-multipath-centralize-validation-code.patch b/0025-multipath-centralize-validation-code.patch deleted file mode 100644 index c8f862c..0000000 --- a/0025-multipath-centralize-validation-code.patch +++ /dev/null @@ -1,777 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 . -+ */ -+#include -+#include -+#include -+ -+#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 . -+ */ -+#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 - diff --git a/0026-Unit-tests-for-is_path_valid.patch b/0026-Unit-tests-for-is_path_valid.patch deleted file mode 100644 index 9ada368..0000000 --- a/0026-Unit-tests-for-is_path_valid.patch +++ /dev/null @@ -1,530 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Tue, 19 May 2020 12:08:43 -0500 -Subject: [PATCH] Unit tests for is_path_valid() - -Reviewed-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - 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 . -+ * -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#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 - diff --git a/0075-libmultipath-provide-defaults-for-get-put-_multipath.patch b/0026-libmultipath-provide-defaults-for-get-put-_multipath.patch similarity index 78% rename from 0075-libmultipath-provide-defaults-for-get-put-_multipath.patch rename to 0026-libmultipath-provide-defaults-for-get-put-_multipath.patch index 9fe50d0..e3375f0 100644 --- a/0075-libmultipath-provide-defaults-for-get-put-_multipath.patch +++ b/0026-libmultipath-provide-defaults-for-get-put-_multipath.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:08 +0200 +Date: Wed, 16 Sep 2020 12:06:56 +0200 Subject: [PATCH] libmultipath: provide defaults for {get,put}_multipath_config Add an implementation of get_multipath_config() and put_multipath_config() @@ -14,24 +14,28 @@ 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 +Reviewed-by: Benjamin Marzinski Signed-off-by: Benjamin Marzinski --- - libmultipath/config.c | 72 +++++++++++++++++++++++++++++++++++++------ - libmultipath/config.h | 21 +++++++++++-- - 2 files changed, 80 insertions(+), 13 deletions(-) + libmultipath/config.c | 75 ++++++++++++++++++++++++++----- + libmultipath/config.h | 21 +++++++-- + libmultipath/libmultipath.version | 10 +++++ + 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/libmultipath/config.c b/libmultipath/config.c -index 1818f8b9..422e923d 100644 +index 5c91a09d..01b77dfe 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -28,6 +28,23 @@ +@@ -27,6 +27,26 @@ + #include "mpath_cmd.h" #include "propsel.h" - #include "version.h" +static struct config __internal_config; +struct config *libmp_get_multipath_config(void) +{ ++ if (!__internal_config.hwtable) ++ /* not initialized */ ++ return NULL; + return &__internal_config; +} + @@ -49,7 +53,7 @@ index 1818f8b9..422e923d 100644 static int hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2) { -@@ -575,17 +592,15 @@ restart: +@@ -574,17 +594,15 @@ restart: return; } @@ -70,7 +74,7 @@ index 1818f8b9..422e923d 100644 if (conf->multipath_dir) FREE(conf->multipath_dir); -@@ -649,7 +664,27 @@ free_config (struct config * conf) +@@ -650,7 +668,27 @@ free_config (struct config * conf) free_hwtable(conf->hwtable); free_hwe(conf->overrides); free_keywords(conf->keywords); @@ -99,7 +103,7 @@ index 1818f8b9..422e923d 100644 } /* 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) +@@ -719,12 +757,29 @@ static void set_max_checkint_from_watchdog(struct config *conf) } #endif @@ -130,7 +134,7 @@ index 1818f8b9..422e923d 100644 /* * internal defaults -@@ -911,10 +963,10 @@ struct config *load_config(const char *file) +@@ -896,10 +951,10 @@ struct config *load_config(const char *file) !conf->wwids_file || !conf->prkeys_file) goto out; @@ -145,10 +149,10 @@ index 1818f8b9..422e923d 100644 char *get_uid_attribute_by_attrs(struct config *conf, diff --git a/libmultipath/config.h b/libmultipath/config.h -index 78375f2f..83d179ac 100644 +index ace403b8..0329de29 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h -@@ -254,10 +254,25 @@ void free_mptable (vector mptable); +@@ -252,10 +252,25 @@ void free_mptable (vector mptable); int store_hwe (vector hwtable, struct hwentry *); struct config *load_config (const char *file); @@ -177,6 +181,24 @@ index 78375f2f..83d179ac 100644 int parse_uid_attrs(char *uid_attrs, struct config *conf); char *get_uid_attribute_by_attrs(struct config *conf, +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 97acdbb2..3e780fce 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -251,3 +251,13 @@ global: + libmp_dm_task_run; + cleanup_mutex; + } LIBMULTIPATH_2.0.0; ++ ++LIBMULTIPATH_2.2.0 { ++global: ++ libmp_get_multipath_config; ++ get_multipath_config; ++ libmp_put_multipath_config; ++ put_multipath_config; ++ init_config; ++ uninit_config; ++} LIBMULTIPATH_2.1.0; -- 2.17.2 diff --git a/0076-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch b/0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch similarity index 81% rename from 0076-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch rename to 0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch index c36aa90..def8896 100644 --- a/0076-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch +++ b/0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch @@ -1,23 +1,38 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:09 +0200 +Date: Wed, 16 Sep 2020 12:11:46 +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. +internal implementation. This causes a minor version bump for +libmpathpersist. Reviewed-by: Benjamin Marzinski -Signed-off-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- - libmpathpersist/mpath_persist.c | 42 ++++++++++++++++++++++++++++----- - libmpathpersist/mpath_persist.h | 28 ++++++++++++++++++++++ - 2 files changed, 64 insertions(+), 6 deletions(-) + libmpathpersist/libmpathpersist.version | 6 ++++ + libmpathpersist/mpath_persist.c | 42 +++++++++++++++++++++---- + libmpathpersist/mpath_persist.h | 28 +++++++++++++++++ + 3 files changed, 70 insertions(+), 6 deletions(-) +diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version +index dc648ce6..e0748138 100644 +--- a/libmpathpersist/libmpathpersist.version ++++ b/libmpathpersist/libmpathpersist.version +@@ -30,3 +30,9 @@ global: + + local: *; + }; ++ ++LIBMPATHPERSIST_1.1.0 { ++global: ++ libmpathpersist_init; ++ libmpathpersist_exit; ++} LIBMPATHPERSIST_1.0.0; diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c -index a132f4e9..9dfc98cd 100644 +index cc4a088d..febf4758 100644 --- a/libmpathpersist/mpath_persist.c +++ b/libmpathpersist/mpath_persist.c @@ -37,6 +37,27 @@ @@ -48,7 +63,7 @@ index a132f4e9..9dfc98cd 100644 struct config * mpath_lib_init (void) { -@@ -47,21 +68,30 @@ mpath_lib_init (void) +@@ -47,20 +68,29 @@ mpath_lib_init (void) condlog(0, "Failed to initialize multipath config."); return NULL; } @@ -63,7 +78,6 @@ index a132f4e9..9dfc98cd 100644 -mpath_lib_exit (struct config *conf) +static void libmpathpersist_cleanup(void) { - dm_lib_release(); dm_lib_exit(); cleanup_prio(); cleanup_checkers(); diff --git a/0027-libmultipath-simplify-failed-wwid-code.patch b/0027-libmultipath-simplify-failed-wwid-code.patch deleted file mode 100644 index bb60d21..0000000 --- a/0027-libmultipath-simplify-failed-wwid-code.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - #include - #include -+#include - - #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 - diff --git a/0028-libmultipath-use-atomic-linkat-in-mark_failed_wwid.patch b/0028-libmultipath-use-atomic-linkat-in-mark_failed_wwid.patch deleted file mode 100644 index 6b9941a..0000000 --- a/0028-libmultipath-use-atomic-linkat-in-mark_failed_wwid.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0077-multipath-use-get_put-_multipath_config-from-libmult.patch b/0028-multipath-use-get_put-_multipath_config-from-libmult.patch similarity index 81% rename from 0077-multipath-use-get_put-_multipath_config-from-libmult.patch rename to 0028-multipath-use-get_put-_multipath_config-from-libmult.patch index 8f0f443..762daea 100644 --- a/0077-multipath-use-get_put-_multipath_config-from-libmult.patch +++ b/0028-multipath-use-get_put-_multipath_config-from-libmult.patch @@ -1,20 +1,19 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:10 +0200 +Date: Wed, 16 Sep 2020 12:27:09 +0200 Subject: [PATCH] multipath: use {get_put}_multipath_config from libmultipath Reviewed-by: Benjamin Marzinski -Signed-off-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- 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 +index dc4974b9..4bbfce9a 100644 --- a/multipath/main.c +++ b/multipath/main.c -@@ -67,7 +67,6 @@ +@@ -68,7 +68,6 @@ int logsink; struct udev *udev; @@ -22,7 +21,7 @@ index ce48a932..879d7ac9 100644 /* * Return values of configure(), check_path_valid(), and main(). -@@ -78,16 +77,6 @@ enum { +@@ -79,16 +78,6 @@ enum { RTVL_RETRY, /* returned by configure(), not by main() */ }; @@ -39,7 +38,7 @@ index ce48a932..879d7ac9 100644 static int dump_config (struct config *conf, vector hwes, vector mpvec) { -@@ -892,10 +881,9 @@ main (int argc, char *argv[]) +@@ -823,10 +812,9 @@ main (int argc, char *argv[]) udev = udev_new(); logsink = 0; @@ -51,8 +50,8 @@ index ce48a932..879d7ac9 100644 + 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: + while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) { +@@ -1078,8 +1066,8 @@ out_free_config: * the logging function (dm_write_log()), which is called there, * references the config. */ diff --git a/0029-fix-boolean-value-with-json-c-0.14.patch b/0029-fix-boolean-value-with-json-c-0.14.patch deleted file mode 100644 index 29bb90b..0000000 --- a/0029-fix-boolean-value-with-json-c-0.14.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "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 -Signed-off-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - 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 - #include - #include -+#include - #include - - #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 - diff --git a/0078-mpathpersist-use-get-put-_multipath_config-from-libm.patch b/0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch similarity index 88% rename from 0078-mpathpersist-use-get-put-_multipath_config-from-libm.patch rename to 0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch index cc601bb..6ab3c10 100644 --- a/0078-mpathpersist-use-get-put-_multipath_config-from-libm.patch +++ b/0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch @@ -1,18 +1,17 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:11 +0200 +Date: Wed, 16 Sep 2020 12:39:01 +0200 Subject: [PATCH] mpathpersist: use {get,put}_multipath_config() from libmultipath Reviewed-by: Benjamin Marzinski -Signed-off-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- 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 +index a6a3bcf6..278e48f7 100644 --- a/mpathpersist/main.c +++ b/mpathpersist/main.c @@ -43,17 +43,6 @@ void mpath_print_transport_id(struct prin_fulldescr *fdesc); @@ -33,7 +32,7 @@ index 28bfe410..0f0db4b8 100644 void rcu_register_thread_memb(void) {} -@@ -620,15 +609,14 @@ int main(int argc, char *argv[]) +@@ -653,15 +642,14 @@ int main(int argc, char *argv[]) } udev = udev_new(); diff --git a/0079-libmultipath-add-udev-and-logsink-symbols.patch b/0030-libmultipath-add-udev-and-logsink-symbols.patch similarity index 81% rename from 0079-libmultipath-add-udev-and-logsink-symbols.patch rename to 0030-libmultipath-add-udev-and-logsink-symbols.patch index 1b17a12..3bd9de0 100644 --- a/0079-libmultipath-add-udev-and-logsink-symbols.patch +++ b/0030-libmultipath-add-udev-and-logsink-symbols.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:12 +0200 +Date: Wed, 16 Sep 2020 15:06:12 +0200 Subject: [PATCH] libmultipath: add udev and logsink symbols With these symbols added, applications using libmultipath don't @@ -16,21 +16,22 @@ 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 +Reviewed-by: Benjamin Marzinski Signed-off-by: Benjamin Marzinski --- - libmultipath/config.c | 46 +++++++++++++++++++++++++++++++++++++++++++ - libmultipath/config.h | 46 ++++++++++++++++++++++++++++++++++++++++++- - libmultipath/debug.c | 2 ++ - 3 files changed, 93 insertions(+), 1 deletion(-) + libmultipath/config.c | 41 +++++++++++++++++++++++++++ + libmultipath/config.h | 46 ++++++++++++++++++++++++++++++- + libmultipath/debug.c | 2 ++ + libmultipath/libmultipath.version | 8 ++++++ + 4 files changed, 96 insertions(+), 1 deletion(-) diff --git a/libmultipath/config.c b/libmultipath/config.c -index 422e923d..b3809433 100644 +index 01b77dfe..f74417c6 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -28,6 +28,52 @@ +@@ -27,6 +27,47 @@ + #include "mpath_cmd.h" #include "propsel.h" - #include "version.h" +/* + * We don't support re-initialization after @@ -51,11 +52,6 @@ index 422e923d..b3809433 100644 + 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; @@ -63,7 +59,7 @@ index 422e923d..b3809433 100644 + +int libmultipath_init(void) +{ -+ pthread_once(&_init_once, _libmultipath_init); ++ pthread_once(&_init_once, _udev_init); + return !_is_libmultipath_initialized(); +} + @@ -82,10 +78,10 @@ index 422e923d..b3809433 100644 struct config *libmp_get_multipath_config(void) { diff --git a/libmultipath/config.h b/libmultipath/config.h -index 83d179ac..089b2ac2 100644 +index 0329de29..f478df71 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h -@@ -235,7 +235,51 @@ struct config { +@@ -233,7 +233,51 @@ struct config { char *enable_foreign; }; @@ -151,6 +147,22 @@ index 4128cb90..b3a1de9e 100644 void dlog (int sink, int prio, const char * fmt, ...) { va_list ap; +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 3e780fce..0c300c81 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -261,3 +261,11 @@ global: + init_config; + uninit_config; + } LIBMULTIPATH_2.1.0; ++ ++LIBMULTIPATH_2.3.0 { ++global: ++ udev; ++ logsink; ++ libmultipath_init; ++ libmultipath_exit; ++} LIBMULTIPATH_2.2.0; -- 2.17.2 diff --git a/0030-libmultipath-fix-condlog-NULL-argument-in-uevent_get.patch b/0030-libmultipath-fix-condlog-NULL-argument-in-uevent_get.patch deleted file mode 100644 index d8ae27d..0000000 --- a/0030-libmultipath-fix-condlog-NULL-argument-in-uevent_get.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0031-libmultipath-set-enable_foreign-to-NONE-by-default.patch b/0031-libmultipath-set-enable_foreign-to-NONE-by-default.patch deleted file mode 100644 index 7d2b886..0000000 --- a/0031-libmultipath-set-enable_foreign-to-NONE-by-default.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 ---- - 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 - diff --git a/0080-multipath-remove-logsink-and-udev.patch b/0031-multipath-remove-logsink-and-udev.patch similarity index 79% rename from 0080-multipath-remove-logsink-and-udev.patch rename to 0031-multipath-remove-logsink-and-udev.patch index 9c4b728..7ba8272 100644 --- a/0080-multipath-remove-logsink-and-udev.patch +++ b/0031-multipath-remove-logsink-and-udev.patch @@ -1,24 +1,23 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:13 +0200 +Date: Wed, 16 Sep 2020 16:06:17 +0200 Subject: [PATCH] multipath: remove logsink and udev We can use libmultipath's symbols now. Reviewed-by: Benjamin Marzinski -Signed-off-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- 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 +index 4bbfce9a..9ae46ed5 100644 --- a/multipath/main.c +++ b/multipath/main.c -@@ -65,9 +65,6 @@ - #include "file.h" +@@ -66,9 +66,6 @@ #include "valid.h" + #include "alias.h" -int logsink; -struct udev *udev; @@ -26,7 +25,7 @@ index 879d7ac9..322b30e0 100644 /* * Return values of configure(), check_path_valid(), and main(). */ -@@ -879,7 +876,7 @@ main (int argc, char *argv[]) +@@ -810,7 +807,7 @@ main (int argc, char *argv[]) int retries = -1; bool enable_foreign = false; @@ -35,7 +34,7 @@ index 879d7ac9..322b30e0 100644 logsink = 0; if (init_config(DEFAULT_CONFIGFILE)) exit(RTVL_FAIL); -@@ -1138,7 +1135,7 @@ out_free_config: +@@ -1068,7 +1065,7 @@ out_free_config: */ put_multipath_config(conf); uninit_config(); diff --git a/0081-libmpathpersist-call-libmultipath_-init-exit.patch b/0032-libmpathpersist-call-libmultipath_-init-exit.patch similarity index 91% rename from 0081-libmpathpersist-call-libmultipath_-init-exit.patch rename to 0032-libmpathpersist-call-libmultipath_-init-exit.patch index 2163f02..9c52f9f 100644 --- a/0081-libmpathpersist-call-libmultipath_-init-exit.patch +++ b/0032-libmpathpersist-call-libmultipath_-init-exit.patch @@ -1,19 +1,19 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:14 +0200 +Date: Tue, 22 Sep 2020 14:23:14 +0200 Subject: [PATCH] libmpathpersist: call libmultipath_{init,exit}() Have libmpathpersist_{init,exit} do the udev initialization, too. -Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski Signed-off-by: Benjamin Marzinski --- - libmpathpersist/mpath_persist.c | 13 +++++++++---- + libmpathpersist/mpath_persist.c | 11 ++++++++--- libmpathpersist/mpath_persist.h | 9 ++++++--- - 2 files changed, 15 insertions(+), 7 deletions(-) + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c -index 9dfc98cd..d1538195 100644 +index febf4758..e1d1cb76 100644 --- a/libmpathpersist/mpath_persist.c +++ b/libmpathpersist/mpath_persist.c @@ -48,6 +48,10 @@ int libmpathpersist_init(void) @@ -27,16 +27,14 @@ index 9dfc98cd..d1538195 100644 if (init_config(DEFAULT_CONFIGFILE)) { condlog(0, "Failed to initialize multipath config."); return 1; -@@ -74,24 +78,25 @@ mpath_lib_init (void) +@@ -74,23 +78,24 @@ 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(); } diff --git a/0032-multipath-add-e-option-to-enable-foreign-libraries.patch b/0032-multipath-add-e-option-to-enable-foreign-libraries.patch deleted file mode 100644 index 6e07152..0000000 --- a/0032-multipath-add-e-option-to-enable-foreign-libraries.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0033-libmultipath-remove-_blacklist_exceptions-functions.patch b/0033-libmultipath-remove-_blacklist_exceptions-functions.patch deleted file mode 100644 index 5fa6539..0000000 --- a/0033-libmultipath-remove-_blacklist_exceptions-functions.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0082-mpathpersist-remove-logsink-and-udev.patch b/0033-mpathpersist-remove-logsink-and-udev.patch similarity index 86% rename from 0082-mpathpersist-remove-logsink-and-udev.patch rename to 0033-mpathpersist-remove-logsink-and-udev.patch index 8dde360..501f32f 100644 --- a/0082-mpathpersist-remove-logsink-and-udev.patch +++ b/0033-mpathpersist-remove-logsink-and-udev.patch @@ -1,19 +1,19 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:15 +0200 +Date: Wed, 16 Sep 2020 16:08:43 +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 +Reviewed-by: Benjamin Marzinski Signed-off-by: Benjamin Marzinski --- mpathpersist/main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mpathpersist/main.c b/mpathpersist/main.c -index 0f0db4b8..a25b08f0 100644 +index 278e48f7..3c2e6576 100644 --- a/mpathpersist/main.c +++ b/mpathpersist/main.c @@ -42,13 +42,10 @@ void * mpath_alloc_prin_response(int prin_sa); @@ -30,7 +30,7 @@ index 0f0db4b8..a25b08f0 100644 static int verbose, loglevel, noisy; -@@ -608,16 +605,13 @@ int main(int argc, char *argv[]) +@@ -641,16 +638,13 @@ int main(int argc, char *argv[]) exit (1); } diff --git a/0034-libmultipath-fix-parser-issue-with-comments-in-strin.patch b/0034-libmultipath-fix-parser-issue-with-comments-in-strin.patch deleted file mode 100644 index 22cc22c..0000000 --- a/0034-libmultipath-fix-parser-issue-with-comments-in-strin.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0083-multipathd-remove-logsink-and-udev.patch b/0034-multipathd-remove-logsink-and-udev.patch similarity index 77% rename from 0083-multipathd-remove-logsink-and-udev.patch rename to 0034-multipathd-remove-logsink-and-udev.patch index a2b656b..25e929a 100644 --- a/0083-multipathd-remove-logsink-and-udev.patch +++ b/0034-multipathd-remove-logsink-and-udev.patch @@ -1,21 +1,21 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck -Date: Thu, 24 Sep 2020 15:37:16 +0200 +Date: Wed, 23 Sep 2020 11:28:22 +0200 Subject: [PATCH] multipathd: remove logsink and udev We can use the symbols from libmultipath now. -Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski Signed-off-by: Benjamin Marzinski --- 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 +index 00b66ba4..c5c374b7 100644 --- a/multipathd/main.c +++ b/multipathd/main.c -@@ -113,7 +113,6 @@ struct mpath_event_param +@@ -115,7 +115,6 @@ struct mpath_event_param struct multipath *mpp; }; @@ -23,7 +23,7 @@ index 48b62937..6a4b8b83 100644 int uxsock_timeout; int verbosity; int bindings_read_only; -@@ -144,8 +143,6 @@ static inline enum daemon_status get_running_state(void) +@@ -151,8 +150,6 @@ int should_exit(void) */ struct vectors * gvecs; @@ -32,7 +32,7 @@ index 48b62937..6a4b8b83 100644 struct config *multipath_conf; /* Local variables */ -@@ -3009,8 +3006,6 @@ child (__attribute__((unused)) void *param) +@@ -3123,8 +3120,6 @@ child (__attribute__((unused)) void *param) conf = rcu_dereference(multipath_conf); rcu_assign_pointer(multipath_conf, NULL); call_rcu(&conf->rcu, rcu_free_config); @@ -41,7 +41,7 @@ index 48b62937..6a4b8b83 100644 pthread_attr_destroy(&waiter_attr); pthread_attr_destroy(&io_err_stat_attr); #ifdef _DEBUG_ -@@ -3114,7 +3109,9 @@ main (int argc, char *argv[]) +@@ -3228,7 +3223,9 @@ main (int argc, char *argv[]) pthread_cond_init_mono(&config_cond); diff --git a/0035-libmultipath-invert-regexes-that-start-with-exclamat.patch b/0035-libmultipath-invert-regexes-that-start-with-exclamat.patch deleted file mode 100644 index ff1331d..0000000 --- a/0035-libmultipath-invert-regexes-that-start-with-exclamat.patch +++ /dev/null @@ -1,435 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch b/0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch new file mode 100644 index 0000000..c8fa5bb --- /dev/null +++ b/0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Wed, 16 Dec 2020 23:17:39 +0100 +Subject: [PATCH] multipath-tools: add Vexata(by StorCentric) VX arrays + +https://support.sas.com/resources/papers/performance-tuning-sas-vexata-systems.pdf + +Reviewed-by: Martin Wilck +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index cd65afcc..c1d6f7ae 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -1191,6 +1191,14 @@ static struct hwentry default_hw[] = { + .product = "Magnitude", + .pgpolicy = MULTIBUS, + .no_path_retry = 30, ++ }, ++ /* Vexata */ ++ { ++ /* VX */ ++ .vendor = "Vexata", ++ .product = "VX", ++ .pgpolicy = MULTIBUS, ++ .no_path_retry = 30, + }, + /* + * Promise Technology +-- +2.17.2 + diff --git a/0036-multipath-Fix-compiler-warnings-when-built-without-s.patch b/0036-multipath-Fix-compiler-warnings-when-built-without-s.patch deleted file mode 100644 index f631fdb..0000000 --- a/0036-multipath-Fix-compiler-warnings-when-built-without-s.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Marius Bakke -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 ---- - 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 - diff --git a/0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch b/0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch new file mode 100644 index 0000000..006d74e --- /dev/null +++ b/0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Wed, 16 Dec 2020 23:17:40 +0100 +Subject: [PATCH] multipath-tools: Violin and Nexsan were bought by StorCentric + +Reviewed-by: Martin Wilck +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index c1d6f7ae..a54cc0a3 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -1113,8 +1113,9 @@ static struct hwentry default_hw[] = { + .pgpolicy = MULTIBUS, + }, + /* +- * Imation/Nexsan ++ * StorCentric + */ ++ /* Nexsan */ + { + /* E-Series */ + .vendor = "NEXSAN", +@@ -1143,9 +1144,7 @@ static struct hwentry default_hw[] = { + .prio_name = PRIO_ALUA, + .no_path_retry = 30, + }, +- /* +- * Violin Systems +- */ ++ /* Violin Systems */ + { + /* 3000 / 6000 Series */ + .vendor = "VIOLIN", +-- +2.17.2 + diff --git a/0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch b/0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch new file mode 100644 index 0000000..0f67ead --- /dev/null +++ b/0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Mon, 9 Nov 2020 12:32:05 +0800 +Subject: [PATCH] libmultipath: fix memory leaks in coalesce_paths + +When multipath -F are executed first and multipath -v2 or +-d are executed later, asan will warn memory leaks. The +reason is that the mpp allocated in coalesce_paths isn't +freed. Here we use newmp to store mpp. If newmp need not +be copied to mpvec, we free newmp at the end of the func. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Lixiaokeng +Signed-off-by: Zhiqiang Liu +Signed-off-by: Linfeilong +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 40 +++++++++++++++++++++++++++++----------- + 1 file changed, 29 insertions(+), 11 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 1c8aac08..d36f0d0d 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1139,7 +1139,7 @@ out: + * FORCE_RELOAD_WEAK: existing maps are compared to the current conf and only + * reloaded in DM if there's a difference. This is useful during startup. + */ +-int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, ++int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + int force_reload, enum mpath_cmds cmd) + { + int ret = CP_FAIL; +@@ -1151,6 +1151,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + struct path * pp2; + vector curmp = vecs->mpvec; + vector pathvec = vecs->pathvec; ++ vector newmp; + struct config *conf; + int allow_queueing; + struct bitfield *size_mismatch_seen; +@@ -1171,6 +1172,15 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + if (size_mismatch_seen == NULL) + return CP_FAIL; + ++ if (mpvec) ++ newmp = mpvec; ++ else ++ newmp = vector_alloc(); ++ if (!newmp) { ++ condlog(0, "can not allocate newmp"); ++ goto out; ++ } ++ + vector_foreach_slot (pathvec, pp1, k) { + int invalid; + +@@ -1283,8 +1293,14 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + goto out; + } + } +- if (r == DOMAP_DRY) ++ if (r == DOMAP_DRY) { ++ if (!vector_alloc_slot(newmp)) { ++ remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC); ++ goto out; ++ } ++ vector_set_slot(newmp, mpp); + continue; ++ } + + if (r == DOMAP_EXIST && mpp->action == ACT_NOTHING && + force_reload == FORCE_RELOAD_WEAK) +@@ -1320,22 +1336,22 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + print_multipath_topology(mpp, verbosity); + } + +- if (newmp) { +- if (mpp->action != ACT_REJECT) { +- if (!vector_alloc_slot(newmp)) +- goto out; +- vector_set_slot(newmp, mpp); ++ if (mpp->action != ACT_REJECT) { ++ if (!vector_alloc_slot(newmp)) { ++ remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC); ++ goto out; + } +- else +- remove_map(mpp, vecs->pathvec, vecs->mpvec, +- KEEP_VEC); ++ vector_set_slot(newmp, mpp); + } ++ else ++ remove_map(mpp, vecs->pathvec, vecs->mpvec, ++ KEEP_VEC); + } + /* + * Flush maps with only dead paths (ie not in sysfs) + * Keep maps with only failed paths + */ +- if (newmp) { ++ if (mpvec) { + vector_foreach_slot (newmp, mpp, i) { + char alias[WWID_SIZE]; + +@@ -1358,6 +1374,8 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, + ret = CP_OK; + out: + free(size_mismatch_seen); ++ if (!mpvec) ++ free_multipathvec(newmp, KEEP_PATHS); + return ret; + } + +-- +2.17.2 + diff --git a/0037-libmultipath-fix-sysfs-dev_loss_tmo-parsing.patch b/0037-libmultipath-fix-sysfs-dev_loss_tmo-parsing.patch deleted file mode 100644 index 0888750..0000000 --- a/0037-libmultipath-fix-sysfs-dev_loss_tmo-parsing.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Martin Wilck ---- - 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 - diff --git a/0038-kpartx-read-devices-with-direct-IO.patch b/0038-kpartx-read-devices-with-direct-IO.patch deleted file mode 100644 index eaa91c3..0000000 --- a/0038-kpartx-read-devices-with-direct-IO.patch +++ /dev/null @@ -1,267 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 . - */ - -+#define _GNU_SOURCE - #include - #include - #include -@@ -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 - #include - #include -@@ -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 - #include - #include - -@@ -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 - diff --git a/0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch b/0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch new file mode 100644 index 0000000..d51c502 --- /dev/null +++ b/0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Thu, 17 Dec 2020 16:49:38 +0100 +Subject: [PATCH] multipath-tools: replace hidden tab by space in hwtable + +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index a54cc0a3..921aadc5 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -819,7 +819,7 @@ static struct hwentry default_hw[] = { + * + * The hwtable is searched backwards, so place this after "Generic NVMe" + */ +- .vendor = "NVME", ++ .vendor = "NVME", + .product = "^NetApp ONTAP Controller", + .pgpolicy = MULTIBUS, + .no_path_retry = NO_PATH_RETRY_QUEUE, +-- +2.17.2 + diff --git a/0039-kpartx-handle-alternate-bsd-disklabel-location.patch b/0039-kpartx-handle-alternate-bsd-disklabel-location.patch deleted file mode 100644 index 4b6e7e5..0000000 --- a/0039-kpartx-handle-alternate-bsd-disklabel-location.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - -+#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 - diff --git a/0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch b/0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch new file mode 100644 index 0000000..6f4fc00 --- /dev/null +++ b/0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Sep 2020 20:59:25 +0200 +Subject: [PATCH] multipathd: uxlsnr: avoid deadlock on exit + +The uxlsnr wouldn't always release the client lock when cancelled, +causing a deadlock in uxsock_cleanup(). While this hasn't been +caused by commit 3d611a2, the deadlock seems to have become much +more likely after that patch. Solving this means that we have to +treat reallocation failure of the pollfd array differently. +We will now just ignore any clients above the last valid pfd index. +That's a minor problem, as we're in an OOM situation anyway. + +Moreover, client_lock is not a "struct lock", but a plain +pthread_mutex_t. + +Fixes: 3d611a2 ("multipathd: cancel threads early during shutdown") +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/uxlsnr.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c +index 1c5ce9d2..ce2b6800 100644 +--- a/multipathd/uxlsnr.c ++++ b/multipathd/uxlsnr.c +@@ -35,6 +35,7 @@ + #include "config.h" + #include "mpath_cmd.h" + #include "time-util.h" ++#include "util.h" + + #include "main.h" + #include "cli.h" +@@ -116,7 +117,7 @@ static void _dead_client(struct client *c) + + static void dead_client(struct client *c) + { +- pthread_cleanup_push(cleanup_lock, &client_lock); ++ pthread_cleanup_push(cleanup_mutex, &client_lock); + pthread_mutex_lock(&client_lock); + _dead_client(c); + pthread_cleanup_pop(1); +@@ -302,10 +303,11 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + sigdelset(&mask, SIGUSR1); + while (1) { + struct client *c, *tmp; +- int i, poll_count, num_clients; ++ int i, n_pfds, poll_count, num_clients; + + /* setup for a poll */ + pthread_mutex_lock(&client_lock); ++ pthread_cleanup_push(cleanup_mutex, &client_lock); + num_clients = 0; + list_for_each_entry(c, &clients, node) { + num_clients++; +@@ -322,14 +324,13 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + sizeof(struct pollfd)); + } + if (!new) { +- pthread_mutex_unlock(&client_lock); + condlog(0, "%s: failed to realloc %d poll fds", + "uxsock", 2 + num_clients); +- sched_yield(); +- continue; ++ num_clients = old_clients; ++ } else { ++ old_clients = num_clients; ++ polls = new; + } +- old_clients = num_clients; +- polls = new; + } + polls[0].fd = ux_sock; + polls[0].events = POLLIN; +@@ -347,11 +348,14 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + polls[i].fd = c->fd; + polls[i].events = POLLIN; + i++; ++ if (i >= 2 + num_clients) ++ break; + } +- pthread_mutex_unlock(&client_lock); ++ n_pfds = i; ++ pthread_cleanup_pop(1); + + /* most of our life is spent in this call */ +- poll_count = ppoll(polls, i, &sleep_time, &mask); ++ poll_count = ppoll(polls, n_pfds, &sleep_time, &mask); + + handle_signals(false); + if (poll_count == -1) { +@@ -384,7 +388,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + } + + /* see if a client wants to speak to us */ +- for (i = 2; i < num_clients + 2; i++) { ++ for (i = 2; i < n_pfds; i++) { + if (polls[i].revents & POLLIN) { + struct timespec start_time; + +-- +2.17.2 + diff --git a/0040-libmultipath-fix-checker-detection-for-nvme-devices.patch b/0040-libmultipath-fix-checker-detection-for-nvme-devices.patch deleted file mode 100644 index 1054e30..0000000 --- a/0040-libmultipath-fix-checker-detection-for-nvme-devices.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0040-multipathd-Fix-liburcu-memory-leak.patch b/0040-multipathd-Fix-liburcu-memory-leak.patch new file mode 100644 index 0000000..8f04a66 --- /dev/null +++ b/0040-multipathd-Fix-liburcu-memory-leak.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:02:39 +0200 +Subject: [PATCH] multipathd: Fix liburcu memory leak + +Fix this leak in multipathd, reported by valgrind, that messes up +multipathd's otherwise clean leak report: + +==23823== 336 bytes in 1 blocks are possibly lost in loss record 3 of 3 +==23823== at 0x483AB65: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) +==23823== by 0x4012F16: _dl_allocate_tls (in /lib64/ld-2.31.so) +==23823== by 0x493BB8E: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.31.so) +==23823== by 0x492A9A9: call_rcu_data_init (urcu-call-rcu-impl.h:437) +==23823== by 0x492AD2F: UnknownInlinedFun (urcu-call-rcu-impl.h:492) +==23823== by 0x492AD2F: create_call_rcu_data_memb (urcu-call-rcu-impl.h:504) +==23823== by 0x1164E3: child.constprop.0.isra.0 (main.c:2915) +==23823== by 0x10F50C: main (main.c:3335) +==23823== +==23823== LEAK SUMMARY: +==23823== definitely lost: 0 bytes in 0 blocks +==23823== indirectly lost: 0 bytes in 0 blocks +==23823== possibly lost: 336 bytes in 1 blocks + +The problem is caused by using liburcu's default RCU call handler, +which liburcu refuses to stop/join. See comments in the code. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 44 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index c5c374b7..ce14bb66 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2889,6 +2889,48 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++/* ++ * Use a non-default call_rcu_data for child(). ++ * ++ * We do this to avoid a memory leak from liburcu. ++ * liburcu never frees the default rcu handler (see comments on ++ * call_rcu_data_free() in urcu-call-rcu-impl.h), its thread ++ * can't be joined with pthread_join(), leaving a memory leak. ++ * ++ * Therefore we create our own, which can be destroyed and joined. ++ */ ++static struct call_rcu_data *setup_rcu(void) ++{ ++ struct call_rcu_data *crdp; ++ ++ rcu_init(); ++ rcu_register_thread(); ++ crdp = create_call_rcu_data(0UL, -1); ++ if (crdp != NULL) ++ set_thread_call_rcu_data(crdp); ++ return crdp; ++} ++ ++static struct call_rcu_data *mp_rcu_data; ++ ++static void cleanup_rcu(void) ++{ ++ pthread_t rcu_thread; ++ ++ /* Wait for any pending RCU calls */ ++ rcu_barrier(); ++ if (mp_rcu_data != NULL) { ++ rcu_thread = get_call_rcu_thread(mp_rcu_data); ++ /* detach this thread from the RCU thread */ ++ set_thread_call_rcu_data(NULL); ++ synchronize_rcu(); ++ /* tell RCU thread to exit */ ++ call_rcu_data_free(mp_rcu_data); ++ pthread_join(rcu_thread, NULL); ++ } ++ rcu_unregister_thread(); ++} ++ + static int + child (__attribute__((unused)) void *param) + { +@@ -2906,7 +2948,8 @@ child (__attribute__((unused)) void *param) + + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); +- rcu_init(); ++ mp_rcu_data = setup_rcu(); ++ atexit(cleanup_rcu); + + setup_thread_attr(&misc_attr, 64 * 1024, 0); + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); +-- +2.17.2 + diff --git a/0041-libmultipath-make-dm_get_map-status-return-codes-sym.patch b/0041-libmultipath-make-dm_get_map-status-return-codes-sym.patch deleted file mode 100644 index 91c9a8b..0000000 --- a/0041-libmultipath-make-dm_get_map-status-return-codes-sym.patch +++ /dev/null @@ -1,322 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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, ¶ms); -+ if (dm_get_next_target(dmt, NULL, &start, &length, -+ &target_type, ¶ms) != 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, ¶ms[0]) && -+ dm_get_map(names->name, &size, ¶ms[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 - diff --git a/0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch b/0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch new file mode 100644 index 0000000..329876d --- /dev/null +++ b/0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 10:33:12 +0200 +Subject: [PATCH] multipathd: move handling of io_err_stat_attr into + libmultipath + +This thread attribute can be dynamically initialized and destroyed. +No need to carry it along in multipathd. Removal of the symbol +requires to bump the ABI version to 3. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/io_err_stat.c | 7 +++++-- + libmultipath/libmultipath.version | 23 ++++++++--------------- + multipathd/main.c | 2 -- + 3 files changed, 13 insertions(+), 19 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 58bc1dd2..5363049d 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -34,6 +34,7 @@ + #include "lock.h" + #include "time-util.h" + #include "io_err_stat.h" ++#include "util.h" + + #define TIMEOUT_NO_IO_NSEC 10000000 /*10ms = 10000000ns*/ + #define FLAKY_PATHFAIL_THRESHOLD 2 +@@ -70,8 +71,7 @@ struct io_err_stat_path { + int err_rate_threshold; + }; + +-pthread_t io_err_stat_thr; +-pthread_attr_t io_err_stat_attr; ++static pthread_t io_err_stat_thr; + + static pthread_mutex_t io_err_thread_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t io_err_thread_cond = PTHREAD_COND_INITIALIZER; +@@ -727,6 +727,7 @@ static void *io_err_stat_loop(void *data) + int start_io_err_stat_thread(void *data) + { + int ret; ++ pthread_attr_t io_err_stat_attr; + + if (uatomic_read(&io_err_thread_running) == 1) + return 0; +@@ -739,6 +740,7 @@ int start_io_err_stat_thread(void *data) + if (!paths) + goto destroy_ctx; + ++ setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + pthread_mutex_lock(&io_err_thread_lock); + pthread_cleanup_push(cleanup_unlock, &io_err_thread_lock); + +@@ -750,6 +752,7 @@ int start_io_err_stat_thread(void *data) + &io_err_thread_lock) == 0); + + pthread_cleanup_pop(1); ++ pthread_attr_destroy(&io_err_stat_attr); + + if (ret) { + io_err_stat_log(0, "cannot create io_error statistic thread"); +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 0c300c81..84beb7f0 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -31,7 +31,7 @@ + * The new version inherits the previous ones. + */ + +-LIBMULTIPATH_2.0.0 { ++LIBMULTIPATH_3.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -121,7 +121,6 @@ global: + init_checkers; + init_foreign; + init_prio; +- io_err_stat_attr; + io_err_stat_handle_pathfail; + is_path_valid; + is_quote; +@@ -242,30 +241,24 @@ global: + free_scandir_result; + sysfs_attr_get_value; + +-local: +- *; +-}; +- +-LIBMULTIPATH_2.1.0 { +-global: ++ /* added in 2.1.0 */ + libmp_dm_task_run; + cleanup_mutex; +-} LIBMULTIPATH_2.0.0; + +-LIBMULTIPATH_2.2.0 { +-global: ++ /* added in 2.2.0 */ + libmp_get_multipath_config; + get_multipath_config; + libmp_put_multipath_config; + put_multipath_config; + init_config; + uninit_config; +-} LIBMULTIPATH_2.1.0; + +-LIBMULTIPATH_2.3.0 { +-global: ++ /* added in 2.3.0 */ + udev; + logsink; + libmultipath_init; + libmultipath_exit; +-} LIBMULTIPATH_2.2.0; ++ ++local: ++ *; ++}; +diff --git a/multipathd/main.c b/multipathd/main.c +index ce14bb66..abc6a9f7 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2954,7 +2954,6 @@ child (__attribute__((unused)) void *param) + setup_thread_attr(&misc_attr, 64 * 1024, 0); + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); +- setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + + if (logsink == 1) { + setup_thread_attr(&log_attr, 64 * 1024, 0); +@@ -3164,7 +3163,6 @@ child (__attribute__((unused)) void *param) + rcu_assign_pointer(multipath_conf, NULL); + call_rcu(&conf->rcu, rcu_free_config); + pthread_attr_destroy(&waiter_attr); +- pthread_attr_destroy(&io_err_stat_attr); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0042-multipathd-fix-check_path-errors-with-removed-map.patch b/0042-multipathd-fix-check_path-errors-with-removed-map.patch deleted file mode 100644 index 155e93a..0000000 --- a/0042-multipathd-fix-check_path-errors-with-removed-map.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch b/0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch new file mode 100644 index 0000000..f65e6eb --- /dev/null +++ b/0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:05:40 +0200 +Subject: [PATCH] multipathd: move vecs desctruction into cleanup function + +This will make it easer to move the stuff around later. +The only functional change is that map destuction now happens after +joining all threads, which should actually improve robustness. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 64 +++++++++++++++++++++++++++++------------------ + 1 file changed, 40 insertions(+), 24 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index abc6a9f7..3da0d7cc 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -148,7 +148,7 @@ int should_exit(void) + /* + * global copy of vecs for use in sig handlers + */ +-struct vectors * gvecs; ++static struct vectors * gvecs; + + struct config *multipath_conf; + +@@ -2889,6 +2889,44 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++static void cleanup_maps(struct vectors *vecs) ++{ ++ int queue_without_daemon, i; ++ struct multipath *mpp; ++ struct config *conf; ++ ++ conf = get_multipath_config(); ++ queue_without_daemon = conf->queue_without_daemon; ++ put_multipath_config(conf); ++ if (queue_without_daemon == QUE_NO_DAEMON_OFF) ++ vector_foreach_slot(vecs->mpvec, mpp, i) ++ dm_queue_if_no_path(mpp->alias, 0); ++ remove_maps_and_stop_waiters(vecs); ++ vecs->mpvec = NULL; ++} ++ ++static void cleanup_paths(struct vectors *vecs) ++{ ++ free_pathvec(vecs->pathvec, FREE_PATHS); ++ vecs->pathvec = NULL; ++} ++ ++static void cleanup_vecs(void) ++{ ++ if (!gvecs) ++ return; ++ /* ++ * We can't take the vecs lock here, because exit() may ++ * have been called from the child() thread, holding the lock already. ++ * Anyway, by the time we get here, all threads that might access ++ * vecs should have been joined already (in cleanup_threads). ++ */ ++ cleanup_maps(gvecs); ++ cleanup_paths(gvecs); ++ pthread_mutex_destroy(&gvecs->lock.mutex); ++ FREE(gvecs); ++} ++ + /* + * Use a non-default call_rcu_data for child(). + * +@@ -2937,13 +2975,10 @@ child (__attribute__((unused)) void *param) + pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; + pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; +- struct multipath * mpp; +- int i; + int rc; + int pid_fd = -1; + struct config *conf; + char *envp; +- int queue_without_daemon; + enum daemon_status state; + + mlockall(MCL_CURRENT | MCL_FUTURE); +@@ -3108,17 +3143,6 @@ child (__attribute__((unused)) void *param) + if (poll_dmevents) + pthread_cancel(dmevent_thr); + +- conf = get_multipath_config(); +- queue_without_daemon = conf->queue_without_daemon; +- put_multipath_config(conf); +- +- lock(&vecs->lock); +- if (queue_without_daemon == QUE_NO_DAEMON_OFF) +- vector_foreach_slot(vecs->mpvec, mpp, i) +- dm_queue_if_no_path(mpp->alias, 0); +- remove_maps_and_stop_waiters(vecs); +- unlock(&vecs->lock); +- + pthread_join(check_thr, NULL); + pthread_join(uevent_thr, NULL); + pthread_join(uxlsnr_thr, NULL); +@@ -3128,15 +3152,7 @@ child (__attribute__((unused)) void *param) + + stop_io_err_stat_thread(); + +- lock(&vecs->lock); +- free_pathvec(vecs->pathvec, FREE_PATHS); +- vecs->pathvec = NULL; +- unlock(&vecs->lock); +- +- pthread_mutex_destroy(&vecs->lock.mutex); +- FREE(vecs); +- vecs = NULL; +- ++ cleanup_vecs(); + cleanup_foreign(); + cleanup_checkers(); + cleanup_prio(); +-- +2.17.2 + diff --git a/0043-libmultipath-make-dm_flush_maps-only-return-0-on-suc.patch b/0043-libmultipath-make-dm_flush_maps-only-return-0-on-suc.patch deleted file mode 100644 index 4dce980..0000000 --- a/0043-libmultipath-make-dm_flush_maps-only-return-0-on-suc.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0043-multipathd-make-some-globals-static.patch b/0043-multipathd-make-some-globals-static.patch new file mode 100644 index 0000000..6ae5835 --- /dev/null +++ b/0043-multipathd-make-some-globals-static.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 11:18:02 +0200 +Subject: [PATCH] multipathd: make some globals static + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 3da0d7cc..eb760a71 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -116,19 +116,19 @@ struct mpath_event_param + }; + + int uxsock_timeout; +-int verbosity; +-int bindings_read_only; ++static int verbosity; ++static int bindings_read_only; + int ignore_new_devs; + #ifdef NO_DMEVENTS_POLL +-int poll_dmevents = 0; ++static int poll_dmevents = 0; + #else +-int poll_dmevents = 1; ++static int poll_dmevents = 1; + #endif + /* Don't access this variable without holding config_lock */ +-volatile enum daemon_status running_state = DAEMON_INIT; ++static volatile enum daemon_status running_state = DAEMON_INIT; + pid_t daemon_pid; +-pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; +-pthread_cond_t config_cond; ++static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t config_cond; + + static inline enum daemon_status get_running_state(void) + { +-- +2.17.2 + diff --git a/0044-multipathd-add-del-maps-multipathd-command.patch b/0044-multipathd-add-del-maps-multipathd-command.patch deleted file mode 100644 index 9f32eb2..0000000 --- a/0044-multipathd-add-del-maps-multipathd-command.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0044-multipathd-move-threads-destruction-into-separate-fu.patch b/0044-multipathd-move-threads-destruction-into-separate-fu.patch new file mode 100644 index 0000000..6c2251e --- /dev/null +++ b/0044-multipathd-move-threads-destruction-into-separate-fu.patch @@ -0,0 +1,164 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 11:18:44 +0200 +Subject: [PATCH] multipathd: move threads destruction into separate function + +Also, introduce booleans that indicate a certain thread has +been started successfully. Using these booleans, we can avoid +crashing by cancelling threads that have never been started. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 76 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 51 insertions(+), 25 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index eb760a71..9eb658d4 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -129,6 +129,9 @@ static volatile enum daemon_status running_state = DAEMON_INIT; + pid_t daemon_pid; + static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t config_cond; ++static pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; ++static bool check_thr_started, uevent_thr_started, uxlsnr_thr_started, ++ uevq_thr_started, dmevent_thr_started; + + static inline enum daemon_status get_running_state(void) + { +@@ -2927,6 +2930,39 @@ static void cleanup_vecs(void) + FREE(gvecs); + } + ++static void cleanup_threads(void) ++{ ++ stop_io_err_stat_thread(); ++ ++ if (check_thr_started) ++ pthread_cancel(check_thr); ++ if (uevent_thr_started) ++ pthread_cancel(uevent_thr); ++ if (uxlsnr_thr_started) ++ pthread_cancel(uxlsnr_thr); ++ if (uevq_thr_started) ++ pthread_cancel(uevq_thr); ++ if (dmevent_thr_started) ++ pthread_cancel(dmevent_thr); ++ ++ if (check_thr_started) ++ pthread_join(check_thr, NULL); ++ if (uevent_thr_started) ++ pthread_join(uevent_thr, NULL); ++ if (uxlsnr_thr_started) ++ pthread_join(uxlsnr_thr, NULL); ++ if (uevq_thr_started) ++ pthread_join(uevq_thr, NULL); ++ if (dmevent_thr_started) ++ pthread_join(dmevent_thr, NULL); ++ ++ /* ++ * As all threads are joined now, and we're in DAEMON_SHUTDOWN ++ * state, no new waiter threads will be created any more. ++ */ ++ pthread_attr_destroy(&waiter_attr); ++} ++ + /* + * Use a non-default call_rcu_data for child(). + * +@@ -2972,7 +3008,6 @@ static void cleanup_rcu(void) + static int + child (__attribute__((unused)) void *param) + { +- pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; + pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; + int rc; +@@ -3070,9 +3105,12 @@ child (__attribute__((unused)) void *param) + condlog(0, "failed to create cli listener: %d", rc); + goto failed; + } +- else if (state != DAEMON_CONFIGURE) { +- condlog(0, "cli listener failed to start"); +- goto failed; ++ else { ++ uxlsnr_thr_started = true; ++ if (state != DAEMON_CONFIGURE) { ++ condlog(0, "cli listener failed to start"); ++ goto failed; ++ } + } + + if (poll_dmevents) { +@@ -3085,7 +3123,8 @@ child (__attribute__((unused)) void *param) + condlog(0, "failed to create dmevent waiter thread: %d", + rc); + goto failed; +- } ++ } else ++ dmevent_thr_started = true; + } + + /* +@@ -3094,7 +3133,8 @@ child (__attribute__((unused)) void *param) + if ((rc = pthread_create(&uevent_thr, &uevent_attr, ueventloop, udev))) { + condlog(0, "failed to create uevent thread: %d", rc); + goto failed; +- } ++ } else ++ uevent_thr_started = true; + pthread_attr_destroy(&uevent_attr); + + /* +@@ -3103,11 +3143,13 @@ child (__attribute__((unused)) void *param) + if ((rc = pthread_create(&check_thr, &misc_attr, checkerloop, vecs))) { + condlog(0,"failed to create checker loop thread: %d", rc); + goto failed; +- } ++ } else ++ check_thr_started = true; + if ((rc = pthread_create(&uevq_thr, &misc_attr, uevqloop, vecs))) { + condlog(0, "failed to create uevent dispatcher: %d", rc); + goto failed; +- } ++ } else ++ uevq_thr_started = true; + pthread_attr_destroy(&misc_attr); + + while (1) { +@@ -3136,22 +3178,7 @@ child (__attribute__((unused)) void *param) + } + } + +- pthread_cancel(check_thr); +- pthread_cancel(uevent_thr); +- pthread_cancel(uxlsnr_thr); +- pthread_cancel(uevq_thr); +- if (poll_dmevents) +- pthread_cancel(dmevent_thr); +- +- pthread_join(check_thr, NULL); +- pthread_join(uevent_thr, NULL); +- pthread_join(uxlsnr_thr, NULL); +- pthread_join(uevq_thr, NULL); +- if (poll_dmevents) +- pthread_join(dmevent_thr, NULL); +- +- stop_io_err_stat_thread(); +- ++ cleanup_threads(); + cleanup_vecs(); + cleanup_foreign(); + cleanup_checkers(); +@@ -3178,7 +3205,6 @@ child (__attribute__((unused)) void *param) + conf = rcu_dereference(multipath_conf); + rcu_assign_pointer(multipath_conf, NULL); + call_rcu(&conf->rcu, rcu_free_config); +- pthread_attr_destroy(&waiter_attr); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0045-multipath-make-flushing-maps-work-like-other-command.patch b/0045-multipath-make-flushing-maps-work-like-other-command.patch deleted file mode 100644 index b7450ee..0000000 --- a/0045-multipath-make-flushing-maps-work-like-other-command.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0045-multipathd-move-conf-destruction-into-separate-funct.patch b/0045-multipathd-move-conf-destruction-into-separate-funct.patch new file mode 100644 index 0000000..97125dc --- /dev/null +++ b/0045-multipathd-move-conf-destruction-into-separate-funct.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 12:38:50 +0200 +Subject: [PATCH] multipathd: move conf destruction into separate function + +Also removing the comment about dlog() and dm_write_log(). +dlog() can cope with get_multipath_config() returning NULL, +and dm_write_log() hasn't accessed the configuration for a while. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 9eb658d4..07973e85 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2892,6 +2892,16 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++static void cleanup_conf(void) { ++ struct config *conf; ++ ++ conf = rcu_dereference(multipath_conf); ++ if (!conf) ++ return; ++ rcu_assign_pointer(multipath_conf, NULL); ++ call_rcu(&conf->rcu, rcu_free_config); ++} ++ + static void cleanup_maps(struct vectors *vecs) + { + int queue_without_daemon, i; +@@ -3196,15 +3206,7 @@ child (__attribute__((unused)) void *param) + + if (logsink == 1) + log_thread_stop(); +- +- /* +- * Freeing config must be done after condlog() and dm_lib_exit(), +- * because logging functions like dlog() and dm_write_log() +- * reference the config. +- */ +- conf = rcu_dereference(multipath_conf); +- rcu_assign_pointer(multipath_conf, NULL); +- call_rcu(&conf->rcu, rcu_free_config); ++ cleanup_conf(); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0046-multipath-delegate-flushing-maps-to-multipathd.patch b/0046-multipath-delegate-flushing-maps-to-multipathd.patch deleted file mode 100644 index 1a4a771..0000000 --- a/0046-multipath-delegate-flushing-maps-to-multipathd.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0046-multipathd-move-pid-destruction-into-separate-functi.patch b/0046-multipathd-move-pid-destruction-into-separate-functi.patch new file mode 100644 index 0000000..bbff859 --- /dev/null +++ b/0046-multipathd-move-pid-destruction-into-separate-functi.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 16:10:19 +0200 +Subject: [PATCH] multipathd: move pid destruction into separate function + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 07973e85..fc1f8d7f 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2892,6 +2892,12 @@ set_oom_adj (void) + condlog(0, "couldn't adjust oom score"); + } + ++static void cleanup_pidfile(void) ++{ ++ condlog(3, "unlink pidfile"); ++ unlink(DEFAULT_PIDFILE); ++} ++ + static void cleanup_conf(void) { + struct config *conf; + +@@ -3199,9 +3205,7 @@ child (__attribute__((unused)) void *param) + dm_lib_exit(); + + /* We're done here */ +- condlog(3, "unlink pidfile"); +- unlink(DEFAULT_PIDFILE); +- ++ cleanup_pidfile(); + condlog(2, "--------shut down-------"); + + if (logsink == 1) +-- +2.17.2 + diff --git a/0047-multipath-add-option-to-skip-multipathd-delegation.patch b/0047-multipath-add-option-to-skip-multipathd-delegation.patch deleted file mode 100644 index 51284aa..0000000 --- a/0047-multipath-add-option-to-skip-multipathd-delegation.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0047-multipathd-close-pidfile-on-exit.patch b/0047-multipathd-close-pidfile-on-exit.patch new file mode 100644 index 0000000..6c9c1b1 --- /dev/null +++ b/0047-multipathd-close-pidfile-on-exit.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 16:27:33 +0200 +Subject: [PATCH] multipathd: close pidfile on exit + +It seems we've been doing this only in the failure case, for ages. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index fc1f8d7f..f6b80668 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -132,6 +132,7 @@ static pthread_cond_t config_cond; + static pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr, dmevent_thr; + static bool check_thr_started, uevent_thr_started, uxlsnr_thr_started, + uevq_thr_started, dmevent_thr_started; ++static int pid_fd = -1; + + static inline enum daemon_status get_running_state(void) + { +@@ -2894,6 +2895,8 @@ set_oom_adj (void) + + static void cleanup_pidfile(void) + { ++ if (pid_fd >= 0) ++ close(pid_fd); + condlog(3, "unlink pidfile"); + unlink(DEFAULT_PIDFILE); + } +@@ -3027,7 +3030,6 @@ child (__attribute__((unused)) void *param) + pthread_attr_t log_attr, misc_attr, uevent_attr; + struct vectors * vecs; + int rc; +- int pid_fd = -1; + struct config *conf; + char *envp; + enum daemon_status state; +-- +2.17.2 + diff --git a/0048-libmultipath-add-device-to-hwtable.c.patch b/0048-libmultipath-add-device-to-hwtable.c.patch deleted file mode 100644 index 9d5e780..0000000 --- a/0048-libmultipath-add-device-to-hwtable.c.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Steve Schremmer -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 -Reviewed-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - 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 -+ */ -+ .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 - diff --git a/0048-multipathd-add-helper-for-systemd-notification-at-ex.patch b/0048-multipathd-add-helper-for-systemd-notification-at-ex.patch new file mode 100644 index 0000000..bf3c462 --- /dev/null +++ b/0048-multipathd-add-helper-for-systemd-notification-at-ex.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 17:49:02 +0200 +Subject: [PATCH] multipathd: add helper for systemd notification at exit + +Add sd_notify_exit(). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index f6b80668..07068e4a 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3024,6 +3024,17 @@ static void cleanup_rcu(void) + rcu_unregister_thread(); + } + ++static int sd_notify_exit(int err) ++{ ++#ifdef USE_SYSTEMD ++ char msg[24]; ++ ++ snprintf(msg, sizeof(msg), "ERRNO=%d", err); ++ sd_notify(0, msg); ++#endif ++ return err; ++} ++ + static int + child (__attribute__((unused)) void *param) + { +@@ -3216,19 +3227,12 @@ child (__attribute__((unused)) void *param) + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +- +-#ifdef USE_SYSTEMD +- sd_notify(0, "ERRNO=0"); +-#endif +- exit(0); ++ exit(sd_notify_exit(0)); + + failed: +-#ifdef USE_SYSTEMD +- sd_notify(0, "ERRNO=1"); +-#endif + if (pid_fd >= 0) + close(pid_fd); +- exit(1); ++ exit(sd_notify_exit(1)); + } + + static int +-- +2.17.2 + diff --git a/0049-master-libmultipath-fix-use-after-free-when-iscsi-lo.patch b/0049-master-libmultipath-fix-use-after-free-when-iscsi-lo.patch deleted file mode 100644 index bfb9f8f..0000000 --- a/0049-master-libmultipath-fix-use-after-free-when-iscsi-lo.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: lixiaokeng -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 -Signed-off-by: lixiaokeng -Signed-off-by: Zhiqiang Liu -Signed-off-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0049-multipathd-child-call-cleanups-in-failure-case-too.patch b/0049-multipathd-child-call-cleanups-in-failure-case-too.patch new file mode 100644 index 0000000..fba8169 --- /dev/null +++ b/0049-multipathd-child-call-cleanups-in-failure-case-too.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 17:57:16 +0200 +Subject: [PATCH] multipathd: child(): call cleanups in failure case, too + +So far we haven't called any cleanup code if child() failed. +Fix it. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 07068e4a..6b9e323e 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3044,6 +3044,7 @@ child (__attribute__((unused)) void *param) + struct config *conf; + char *envp; + enum daemon_status state; ++ int exit_code = 1; + + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); +@@ -3207,6 +3208,8 @@ child (__attribute__((unused)) void *param) + } + } + ++ exit_code = 0; ++failed: + cleanup_threads(); + cleanup_vecs(); + cleanup_foreign(); +@@ -3227,12 +3230,7 @@ child (__attribute__((unused)) void *param) + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +- exit(sd_notify_exit(0)); +- +-failed: +- if (pid_fd >= 0) +- close(pid_fd); +- exit(sd_notify_exit(1)); ++ return sd_notify_exit(exit_code); + } + + static int +-- +2.17.2 + diff --git a/0050-libmultipath-warn-if-freeing-path-that-holds-mpp-hwe.patch b/0050-libmultipath-warn-if-freeing-path-that-holds-mpp-hwe.patch deleted file mode 100644 index 3c286fa..0000000 --- a/0050-libmultipath-warn-if-freeing-path-that-holds-mpp-hwe.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch b/0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch new file mode 100644 index 0000000..279109c --- /dev/null +++ b/0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:45:30 +0200 +Subject: [PATCH] multipathd: unwatch_all_dmevents: check if waiter is + initialized + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/dmevents.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c +index b561cbfd..f52f5970 100644 +--- a/multipathd/dmevents.c ++++ b/multipathd/dmevents.c +@@ -257,6 +257,8 @@ void unwatch_all_dmevents(void) + struct dev_event *dev_evt; + int i; + ++ if (!waiter) ++ return; + pthread_mutex_lock(&waiter->events_lock); + vector_foreach_slot(waiter->events, dev_evt, i) + free(dev_evt); +-- +2.17.2 + diff --git a/0051-libmultipath-warn-about-NULL-value-of-mpp-hwe.patch b/0051-libmultipath-warn-about-NULL-value-of-mpp-hwe.patch deleted file mode 100644 index a50b9b2..0000000 --- a/0051-libmultipath-warn-about-NULL-value-of-mpp-hwe.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0051-multipathd-print-error-message-if-config-can-t-be-lo.patch b/0051-multipathd-print-error-message-if-config-can-t-be-lo.patch new file mode 100644 index 0000000..9cf6182 --- /dev/null +++ b/0051-multipathd-print-error-message-if-config-can-t-be-lo.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 18:45:51 +0200 +Subject: [PATCH] multipathd: print error message if config can't be loaded + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 6b9e323e..7ab3eab8 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3074,8 +3074,10 @@ child (__attribute__((unused)) void *param) + condlog(2, "read " DEFAULT_CONFIGFILE); + + conf = load_config(DEFAULT_CONFIGFILE); +- if (!conf) ++ if (!conf) { ++ condlog(0, "failed to load configuration"); + goto failed; ++ } + + if (verbosity) + conf->verbosity = verbosity; +-- +2.17.2 + diff --git a/0052-libmultipath-add-libmp_dm_exit.patch b/0052-libmultipath-add-libmp_dm_exit.patch new file mode 100644 index 0000000..db24711 --- /dev/null +++ b/0052-libmultipath-add-libmp_dm_exit.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:02:45 +0200 +Subject: [PATCH] libmultipath: add libmp_dm_exit() + +This function prepares for calling dm_lib_exit() on program exit. +It undoes changes to libdm internals done by libmultipath. +It doesn't call dm_lib_exit(), as the caller may want to keep +libdm active. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 2 ++ + libmultipath/devmapper.c | 15 +++++++++++++++ + libmultipath/devmapper.h | 1 + + 4 files changed, 19 insertions(+) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index f74417c6..b9cb4131 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -60,6 +60,7 @@ int libmultipath_init(void) + static void _libmultipath_exit(void) + { + libmultipath_exit_called = true; ++ libmp_dm_exit(); + udev_unref(udev); + } + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index f478df71..5d460359 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -271,6 +271,8 @@ int libmultipath_init(void); + * + * This function un-initializes libmultipath data structures. + * It is recommended to call this function at program exit. ++ * If the application also calls dm_lib_exit(), it should do so ++ * after libmultipath_exit(). + * + * Calls to libmultipath_init() after libmultipath_exit() will fail + * (in other words, libmultipath can't be re-initialized). +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 4eb6f539..e60ab493 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -335,6 +335,20 @@ void libmp_udev_set_sync_support(int on) + libmp_dm_udev_sync = !!on; + } + ++static bool libmp_dm_init_called; ++void libmp_dm_exit(void) ++{ ++ if (!libmp_dm_init_called) ++ return; ++ ++ /* switch back to default libdm logging */ ++ dm_log_init(NULL); ++#ifdef LIBDM_API_HOLD_CONTROL ++ /* make sure control fd is closed in dm_lib_release() */ ++ dm_hold_control_dev(0); ++#endif ++} ++ + static void libmp_dm_init(void) + { + struct config *conf; +@@ -351,6 +365,7 @@ static void libmp_dm_init(void) + dm_hold_control_dev(1); + #endif + dm_udev_set_sync_support(libmp_dm_udev_sync); ++ libmp_dm_init_called = true; + } + + static void _do_skip_libmp_dm_init(void) +diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h +index fa6b3c53..e29b4d41 100644 +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -35,6 +35,7 @@ enum { + + int dm_prereq(unsigned int *v); + void skip_libmp_dm_init(void); ++void libmp_dm_exit(void); + void libmp_udev_set_sync_support(int on); + struct dm_task *libmp_dm_task_create(int task); + int dm_simplecmd_flush (int, const char *, uint16_t); +-- +2.17.2 + diff --git a/0052-libmultipath-fix-mpp-hwe-handling-in-sync_paths.patch b/0052-libmultipath-fix-mpp-hwe-handling-in-sync_paths.patch deleted file mode 100644 index b9caf46..0000000 --- a/0052-libmultipath-fix-mpp-hwe-handling-in-sync_paths.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0053-Makefile.inc-trim-extra-information-from-systemd-ver.patch b/0053-Makefile.inc-trim-extra-information-from-systemd-ver.patch deleted file mode 100644 index 5c3f614..0000000 --- a/0053-Makefile.inc-trim-extra-information-from-systemd-ver.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0053-multipathd-fixup-libdm-deinitialization.patch b/0053-multipathd-fixup-libdm-deinitialization.patch new file mode 100644 index 0000000..b57a8cd --- /dev/null +++ b/0053-multipathd-fixup-libdm-deinitialization.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:06:13 +0200 +Subject: [PATCH] multipathd: fixup libdm deinitialization + +With libmp_dm_exit() in place, we can make sure that the +calls are made in the right order. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 7ab3eab8..4c4e2eab 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3220,8 +3220,6 @@ failed: + if (poll_dmevents) + cleanup_dmevent_waiter(); + +- dm_lib_exit(); +- + /* We're done here */ + cleanup_pidfile(); + condlog(2, "--------shut down-------"); +@@ -3318,6 +3316,9 @@ main (int argc, char *argv[]) + + pthread_cond_init_mono(&config_cond); + ++ if (atexit(dm_lib_exit)) ++ condlog(3, "failed to register exit handler for libdm"); ++ + libmultipath_init(); + if (atexit(libmultipath_exit)) + condlog(3, "failed to register exit handler for libmultipath"); +-- +2.17.2 + diff --git a/0054-kpartx-fix-Wsign-compare-error.patch b/0054-kpartx-fix-Wsign-compare-error.patch deleted file mode 100644 index ffaa477..0000000 --- a/0054-kpartx-fix-Wsign-compare-error.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Mon, 6 Jul 2020 17:28:46 -0500 -Subject: [PATCH] kpartx: fix -Wsign-compare error - -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch b/0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch new file mode 100644 index 0000000..004016c --- /dev/null +++ b/0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:04:04 +0200 +Subject: [PATCH] libmultipath: log_thread_stop(): check if logarea is + initialized + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log_pthread.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 15baef88..0c327ffc 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -112,6 +112,9 @@ void log_thread_reset (void) + + void log_thread_stop (void) + { ++ if (!la) ++ return; ++ + logdbg(stderr,"enter log_thread_stop\n"); + + pthread_mutex_lock(&logev_lock); +-- +2.17.2 + diff --git a/0055-libmultipath-remove-code-duplication-in-path-countin.patch b/0055-libmultipath-remove-code-duplication-in-path-countin.patch deleted file mode 100644 index 699049a..0000000 --- a/0055-libmultipath-remove-code-duplication-in-path-countin.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0055-multipathd-add-cleanup_child-exit-handler.patch b/0055-multipathd-add-cleanup_child-exit-handler.patch new file mode 100644 index 0000000..8455a96 --- /dev/null +++ b/0055-multipathd-add-cleanup_child-exit-handler.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:08:19 +0200 +Subject: [PATCH] multipathd: add cleanup_child() exit handler + +cleanup_child() calls all cleanups in the right order, in an +exit handler. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 45 +++++++++++++++++++++++++-------------------- + 1 file changed, 25 insertions(+), 20 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 4c4e2eab..50cc3356 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3024,6 +3024,27 @@ static void cleanup_rcu(void) + rcu_unregister_thread(); + } + ++static void cleanup_child(void) ++{ ++ cleanup_threads(); ++ cleanup_vecs(); ++ cleanup_foreign(); ++ cleanup_checkers(); ++ cleanup_prio(); ++ if (poll_dmevents) ++ cleanup_dmevent_waiter(); ++ ++ cleanup_pidfile(); ++ if (logsink == 1) ++ log_thread_stop(); ++ ++ cleanup_conf(); ++ ++#ifdef _DEBUG_ ++ dbg_free_final(NULL); ++#endif ++} ++ + static int sd_notify_exit(int err) + { + #ifdef USE_SYSTEMD +@@ -3049,7 +3070,9 @@ child (__attribute__((unused)) void *param) + mlockall(MCL_CURRENT | MCL_FUTURE); + signal_init(); + mp_rcu_data = setup_rcu(); +- atexit(cleanup_rcu); ++ ++ if (atexit(cleanup_rcu) || atexit(cleanup_child)) ++ fprintf(stderr, "failed to register cleanup handlers\n"); + + setup_thread_attr(&misc_attr, 64 * 1024, 0); + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); +@@ -3063,8 +3086,6 @@ child (__attribute__((unused)) void *param) + pid_fd = pidfile_create(DEFAULT_PIDFILE, daemon_pid); + if (pid_fd < 0) { + condlog(1, "failed to create pidfile"); +- if (logsink == 1) +- log_thread_stop(); + exit(1); + } + +@@ -3212,24 +3233,8 @@ child (__attribute__((unused)) void *param) + + exit_code = 0; + failed: +- cleanup_threads(); +- cleanup_vecs(); +- cleanup_foreign(); +- cleanup_checkers(); +- cleanup_prio(); +- if (poll_dmevents) +- cleanup_dmevent_waiter(); +- +- /* We're done here */ +- cleanup_pidfile(); + condlog(2, "--------shut down-------"); +- +- if (logsink == 1) +- log_thread_stop(); +- cleanup_conf(); +-#ifdef _DEBUG_ +- dbg_free_final(NULL); +-#endif ++ /* All cleanup is done in the cleanup_child() exit handler */ + return sd_notify_exit(exit_code); + } + +-- +2.17.2 + diff --git a/0056-libmultipath-count-pending-paths-as-active-on-loads.patch b/0056-libmultipath-count-pending-paths-as-active-on-loads.patch deleted file mode 100644 index 5320297..0000000 --- a/0056-libmultipath-count-pending-paths-as-active-on-loads.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0056-libmultipath-fix-log_thread-startup-and-teardown.patch b/0056-libmultipath-fix-log_thread-startup-and-teardown.patch new file mode 100644 index 0000000..106f19a --- /dev/null +++ b/0056-libmultipath-fix-log_thread-startup-and-teardown.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 26 Oct 2020 16:44:32 +0100 +Subject: [PATCH] libmultipath: fix log_thread startup and teardown + +This fixes several issues with the log_thread. First, the running flag +logq_running should be set by the thread itself, not by +log_thread_start()/_stop(). Second, the thread was both cancelled and +terminated via a flag (again, logq_running). It's sufficient to just cancel +and join it. Third, the locking wasn't cancel-safe in some places. Forth, +log_thread_start() didn't wait for startup properly. Fifth, using (pthread_t)0 +is wrong (pthread_t is opaque; there's no guarantee that 0 is not a valid +pthread_t value). Sixth, pthread_cancel() was called under logq_lock, which +doesn't make sense to me. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log_pthread.c | 62 +++++++++++++++++++++++++++----------- + 1 file changed, 45 insertions(+), 17 deletions(-) + +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 0c327ffc..3a2566ae 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -13,6 +13,7 @@ + #include "log_pthread.h" + #include "log.h" + #include "lock.h" ++#include "util.h" + + static pthread_t log_thr; + +@@ -56,35 +57,52 @@ static void flush_logqueue (void) + } while (empty == 0); + } + ++static void cleanup_log_thread(__attribute((unused)) void *arg) ++{ ++ logdbg(stderr, "log thread exiting"); ++ pthread_mutex_lock(&logev_lock); ++ logq_running = 0; ++ pthread_mutex_unlock(&logev_lock); ++} ++ + static void * log_thread (__attribute__((unused)) void * et) + { + int running; + + pthread_mutex_lock(&logev_lock); +- logq_running = 1; ++ running = logq_running; ++ if (!running) ++ logq_running = 1; ++ pthread_cond_signal(&logev_cond); + pthread_mutex_unlock(&logev_lock); ++ if (running) ++ /* already started */ ++ return NULL; ++ pthread_cleanup_push(cleanup_log_thread, NULL); + + mlockall(MCL_CURRENT | MCL_FUTURE); + logdbg(stderr,"enter log_thread\n"); + + while (1) { + pthread_mutex_lock(&logev_lock); +- if (logq_running && !log_messages_pending) ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ while (!log_messages_pending) ++ /* this is a cancellation point */ + pthread_cond_wait(&logev_cond, &logev_lock); + log_messages_pending = 0; +- running = logq_running; +- pthread_mutex_unlock(&logev_lock); +- if (!running) +- break; ++ pthread_cleanup_pop(1); ++ + flush_logqueue(); + } ++ pthread_cleanup_pop(1); + return NULL; + } + + void log_thread_start (pthread_attr_t *attr) + { +- logdbg(stderr,"enter log_thread_start\n"); ++ int running = 0; + ++ logdbg(stderr,"enter log_thread_start\n"); + pthread_mutex_init(&logq_lock, NULL); + pthread_mutex_init(&logev_lock, NULL); + pthread_cond_init(&logev_cond, NULL); +@@ -93,7 +111,15 @@ void log_thread_start (pthread_attr_t *attr) + fprintf(stderr,"can't initialize log buffer\n"); + exit(1); + } +- if (pthread_create(&log_thr, attr, log_thread, NULL)) { ++ ++ pthread_mutex_lock(&logev_lock); ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ if (!pthread_create(&log_thr, attr, log_thread, NULL)) ++ while (!(running = logq_running)) ++ pthread_cond_wait(&logev_cond, &logev_lock); ++ pthread_cleanup_pop(1); ++ ++ if (!running) { + fprintf(stderr,"can't start log thread\n"); + exit(1); + } +@@ -112,23 +138,25 @@ void log_thread_reset (void) + + void log_thread_stop (void) + { ++ int running; ++ + if (!la) + return; + + logdbg(stderr,"enter log_thread_stop\n"); + + pthread_mutex_lock(&logev_lock); +- logq_running = 0; +- pthread_cond_signal(&logev_cond); +- pthread_mutex_unlock(&logev_lock); +- +- pthread_mutex_lock(&logq_lock); +- pthread_cancel(log_thr); +- pthread_mutex_unlock(&logq_lock); +- pthread_join(log_thr, NULL); +- log_thr = (pthread_t)0; ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ running = logq_running; ++ if (running) { ++ pthread_cancel(log_thr); ++ pthread_cond_signal(&logev_cond); ++ } ++ pthread_cleanup_pop(1); + + flush_logqueue(); ++ if (running) ++ pthread_join(log_thr, NULL); + + pthread_mutex_destroy(&logq_lock); + pthread_mutex_destroy(&logev_lock); +-- +2.17.2 + diff --git a/0057-libmultipath-deal-with-flushing-no-maps.patch b/0057-libmultipath-deal-with-flushing-no-maps.patch deleted file mode 100644 index 0aee761..0000000 --- a/0057-libmultipath-deal-with-flushing-no-maps.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch b/0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch new file mode 100644 index 0000000..017034e --- /dev/null +++ b/0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 21:57:22 +0200 +Subject: [PATCH] multipathd: move cleanup_{prio,checkers,foreign} to + libmultipath_exit + +This requires another major ABI bump. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 2 -- + libmultipath/config.c | 4 ++++ + libmultipath/libmultipath.version | 5 +---- + multipathd/main.c | 3 --- + 4 files changed, 5 insertions(+), 9 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index e1d1cb76..9ebf91dd 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -78,8 +78,6 @@ mpath_lib_init (void) + + static void libmpathpersist_cleanup(void) + { +- cleanup_prio(); +- cleanup_checkers(); + libmultipath_exit(); + dm_lib_exit(); + } +diff --git a/libmultipath/config.c b/libmultipath/config.c +index b9cb4131..52b1447b 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -26,6 +26,7 @@ + #include "devmapper.h" + #include "mpath_cmd.h" + #include "propsel.h" ++#include "foreign.h" + + /* + * We don't support re-initialization after +@@ -60,6 +61,9 @@ int libmultipath_init(void) + static void _libmultipath_exit(void) + { + libmultipath_exit_called = true; ++ cleanup_foreign(); ++ cleanup_checkers(); ++ cleanup_prio(); + libmp_dm_exit(); + udev_unref(udev); + } +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 84beb7f0..800cff22 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -31,7 +31,7 @@ + * The new version inherits the previous ones. + */ + +-LIBMULTIPATH_3.0.0 { ++LIBMULTIPATH_4.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -51,10 +51,7 @@ global: + checker_name; + checker_state_name; + check_foreign; +- cleanup_checkers; +- cleanup_foreign; + cleanup_lock; +- cleanup_prio; + close_fd; + coalesce_paths; + convert_dev; +diff --git a/multipathd/main.c b/multipathd/main.c +index 50cc3356..4de0978e 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3028,9 +3028,6 @@ static void cleanup_child(void) + { + cleanup_threads(); + cleanup_vecs(); +- cleanup_foreign(); +- cleanup_checkers(); +- cleanup_prio(); + if (poll_dmevents) + cleanup_dmevent_waiter(); + +-- +2.17.2 + diff --git a/0058-multipath-deal-with-delegation-failures-correctly.patch b/0058-multipath-deal-with-delegation-failures-correctly.patch deleted file mode 100644 index e8d0050..0000000 --- a/0058-multipath-deal-with-delegation-failures-correctly.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0058-multipath-use-atexit-for-cleanup-handlers.patch b/0058-multipath-use-atexit-for-cleanup-handlers.patch new file mode 100644 index 0000000..444a39d --- /dev/null +++ b/0058-multipath-use-atexit-for-cleanup-handlers.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 00:30:02 +0200 +Subject: [PATCH] multipath: use atexit() for cleanup handlers + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 37 ++++++++++++++++--------------------- + 1 file changed, 16 insertions(+), 21 deletions(-) + +diff --git a/multipath/main.c b/multipath/main.c +index 9ae46ed5..1949a1cd 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -452,13 +452,19 @@ static bool released_to_systemd(void) + return ret; + } + ++static struct vectors vecs; ++static void cleanup_vecs(void) ++{ ++ free_multipathvec(vecs.mpvec, KEEP_PATHS); ++ free_pathvec(vecs.pathvec, FREE_PATHS); ++} ++ + static int + configure (struct config *conf, enum mpath_cmds cmd, + enum devtypes dev_type, char *devpath) + { + vector curmp = NULL; + vector pathvec = NULL; +- struct vectors vecs; + int r = RTVL_FAIL, rc; + int di_flag = 0; + char * refwwid = NULL; +@@ -469,6 +475,7 @@ configure (struct config *conf, enum mpath_cmds cmd, + */ + curmp = vector_alloc(); + pathvec = vector_alloc(); ++ atexit(cleanup_vecs); + + if (!curmp || !pathvec) { + condlog(0, "can not allocate memory"); +@@ -580,9 +587,6 @@ out: + if (refwwid) + FREE(refwwid); + +- free_multipathvec(curmp, KEEP_PATHS); +- free_pathvec(pathvec, FREE_PATHS); +- + return r; + } + +@@ -808,9 +812,13 @@ main (int argc, char *argv[]) + bool enable_foreign = false; + + libmultipath_init(); ++ if (atexit(dm_lib_exit) || atexit(libmultipath_exit)) ++ condlog(1, "failed to register cleanup handler for libmultipath: %m"); + logsink = 0; + if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); ++ if (atexit(uninit_config)) ++ condlog(1, "failed to register cleanup handler for config: %m"); + conf = get_multipath_config(); + conf->retrigger_tries = 0; + conf->force_sync = 1; +@@ -887,7 +895,7 @@ main (int argc, char *argv[]) + break; + case 't': + r = dump_config(conf, NULL, NULL) ? RTVL_FAIL : RTVL_OK; +- goto out_free_config; ++ goto out; + case 'T': + cmd = CMD_DUMP_CONFIG; + break; +@@ -1048,26 +1056,13 @@ main (int argc, char *argv[]) + condlog(3, "restart multipath configuration process"); + + out: +- dm_lib_exit(); +- +- cleanup_foreign(); +- cleanup_prio(); +- cleanup_checkers(); ++ put_multipath_config(conf); ++ if (dev) ++ FREE(dev); + + if (dev_type == DEV_UEVENT) + closelog(); + +-out_free_config: +- /* +- * Freeing config must be done after dm_lib_exit(), because +- * the logging function (dm_write_log()), which is called there, +- * references the config. +- */ +- put_multipath_config(conf); +- uninit_config(); +- libmultipath_exit(); +- if (dev) +- FREE(dev); + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +-- +2.17.2 + diff --git a/0059-mpathpersist-use-atexit-for-cleanup-handlers.patch b/0059-mpathpersist-use-atexit-for-cleanup-handlers.patch new file mode 100644 index 0000000..7494b34 --- /dev/null +++ b/0059-mpathpersist-use-atexit-for-cleanup-handlers.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 00:32:48 +0200 +Subject: [PATCH] mpathpersist: use atexit() for cleanup handlers + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + mpathpersist/main.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/mpathpersist/main.c b/mpathpersist/main.c +index 3c2e6576..14245cc3 100644 +--- a/mpathpersist/main.c ++++ b/mpathpersist/main.c +@@ -641,11 +641,10 @@ int main(int argc, char *argv[]) + if (libmpathpersist_init()) { + exit(1); + } ++ if (atexit((void(*)(void))libmpathpersist_exit)) ++ fprintf(stderr, "failed to register cleanup handler for libmpathpersist: %m"); + + ret = handle_args(argc, argv, 0); +- +- libmpathpersist_exit(); +- + return (ret >= 0) ? ret : MPATH_PR_OTHER; + } + +-- +2.17.2 + diff --git a/0060-multipath-fix-leak-in-check_path_valid.patch b/0060-multipath-fix-leak-in-check_path_valid.patch new file mode 100644 index 0000000..c96f4cb --- /dev/null +++ b/0060-multipath-fix-leak-in-check_path_valid.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Sep 2020 23:30:50 +0200 +Subject: [PATCH] multipath: fix leak in check_path_valid() + +If path status was successfully determined before calling store_pathvec(), +free_path() wasn't called. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 30 ++++++++++++++++++++---------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +diff --git a/multipath/main.c b/multipath/main.c +index 1949a1cd..043d8fa7 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -93,7 +93,7 @@ void rcu_register_thread_memb(void) {} + void rcu_unregister_thread_memb(void) {} + + static int +-filter_pathvec (vector pathvec, char * refwwid) ++filter_pathvec (vector pathvec, const char *refwwid) + { + int i; + struct path * pp; +@@ -594,8 +594,9 @@ static int + check_path_valid(const char *name, struct config *conf, bool is_uevent) + { + int fd, r = PATH_IS_ERROR; +- struct path *pp = NULL; ++ struct path *pp; + vector pathvec = NULL; ++ const char *wwid; + + pp = alloc_path(); + if (!pp) +@@ -664,14 +665,19 @@ check_path_valid(const char *name, struct config *conf, bool is_uevent) + + if (store_path(pathvec, pp) != 0) { + free_path(pp); ++ pp = NULL; + goto fail; ++ } else { ++ /* make sure path isn't freed twice */ ++ wwid = pp->wwid; ++ pp = NULL; + } + + /* 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); ++ filter_pathvec(pathvec, wwid); + if (VECTOR_SIZE(pathvec) > 1) + r = PATH_IS_VALID; + else +@@ -679,21 +685,25 @@ check_path_valid(const char *name, struct config *conf, bool is_uevent) + + 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; ++ r = RTVL_FAIL; ++ else ++ r = RTVL_OK; ++ goto cleanup; + + fail: +- if (pathvec) +- free_pathvec(pathvec, FREE_PATHS); +- else ++ r = RTVL_FAIL; ++ ++cleanup: ++ if (pp != NULL) + free_path(pp); +- return RTVL_FAIL; ++ if (pathvec != NULL) ++ free_pathvec(pathvec, FREE_PATHS); ++ return r; + } + + static int +-- +2.17.2 + diff --git a/0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch b/0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch new file mode 100644 index 0000000..4228be6 --- /dev/null +++ b/0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Sep 2020 15:13:06 +0200 +Subject: [PATCH] multipath-tools: mpath-tools.supp: file with valgrind + suppressions + +These leaks are caused by other libraries (libsystemd, glibc, +libgcrypt) and should be ignored when debugging with valgrind + +Usage example: + +valgrind --suppressions=mpath-tools.supp \ + --leak-check=full --show-leak-kinds=all $COMMAND + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + third-party/valgrind/mpath-tools.supp | 32 +++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + create mode 100644 third-party/valgrind/mpath-tools.supp + +diff --git a/third-party/valgrind/mpath-tools.supp b/third-party/valgrind/mpath-tools.supp +new file mode 100644 +index 00000000..0537fd56 +--- /dev/null ++++ b/third-party/valgrind/mpath-tools.supp +@@ -0,0 +1,32 @@ ++{ ++ glibc _dlerror_run leak: https://stackoverflow.com/questions/1542457/memory-leak-reported-by-valgrind-in-dlopen ++ Memcheck:Leak ++ match-leak-kinds: reachable ++ fun:calloc ++ fun:_dlerror_run ++ fun:dlopen* ++} ++ ++{ ++ systemd mempools are never freed: https://bugzilla.redhat.com/show_bug.cgi?id=1215670 ++ Memcheck:Leak ++ match-leak-kinds: reachable ++ fun:malloc ++ fun:mempool_alloc_tile ++ fun:mempool_alloc0_tile ++ fun:hashmap_base_new ++ fun:hashmap_base_ensure_allocated ++} ++ ++{ ++ libgcrypt library initialization ++ Memcheck:Leak ++ match-leak-kinds: reachable ++ fun:malloc ++ ... ++ fun:_gcry_xmalloc ++ ... ++ fun:global_init.* ++ ... ++ fun:_dl_init ++} +-- +2.17.2 + diff --git a/0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch b/0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch new file mode 100644 index 0000000..042929d --- /dev/null +++ b/0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch @@ -0,0 +1,441 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:04:53 +0200 +Subject: [PATCH] libmultipath: use libmp_verbosity to track verbosity + +Introduce a new global variable to set the verbosity of libmultipath. +This avoids accessing the configuration in every dlog() call. +When libmultipath reads its configuration in init_config() or +load_config(), it will use the current value of libmp_verbosity +for logging. Immediately before returning, libmp_verbosity will be +overwritten with the verbosity value from the configuration file, +if it was set there. An application is free to set libmp_verbosity +back to the previous value or not after that, depending on whether +command line options or configuration file settings should take +precedence. + +Replace internal access to conf->verbosity with the new variable. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 5 +--- + libmultipath/config.c | 9 +++++-- + libmultipath/configure.c | 16 +++---------- + libmultipath/debug.c | 10 ++------ + libmultipath/debug.h | 1 + + libmultipath/devmapper.c | 7 +----- + libmultipath/libmultipath.version | 5 ++++ + multipath/main.c | 21 ++++++---------- + multipathd/main.c | 40 ++++++++++++++++++------------- + tests/alias.c | 1 + + tests/blacklist.c | 2 ++ + 11 files changed, 53 insertions(+), 64 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 9ebf91dd..79322e86 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -170,10 +170,7 @@ void mpath_persistent_reserve_free_vecs(void) + + int mpath_persistent_reserve_init_vecs(int verbose) + { +- struct config *conf = get_multipath_config(); +- +- conf->verbosity = verbose; +- put_multipath_config(conf); ++ libmp_verbosity = verbose; + + if (curmp) + return MPATH_PR_SUCCESS; +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 52b1447b..49e7fb81 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -828,10 +828,14 @@ int _init_config (const char *file, struct config *conf) + conf = &__internal_config; + + /* +- * internal defaults ++ * Processing the config file will overwrite conf->verbosity if set ++ * When we return, we'll copy the config value back + */ +- conf->verbosity = DEFAULT_VERBOSITY; ++ conf->verbosity = libmp_verbosity; + ++ /* ++ * internal defaults ++ */ + get_sys_max_fds(&conf->max_fds); + conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE); + conf->wwids_file = set_default(DEFAULT_WWIDS_FILE); +@@ -997,6 +1001,7 @@ int _init_config (const char *file, struct config *conf) + !conf->wwids_file || !conf->prkeys_file) + goto out; + ++ libmp_verbosity = conf->verbosity; + return 0; + out: + _uninit_config(conf); +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index d36f0d0d..20536e60 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -934,16 +934,12 @@ int domap(struct multipath *mpp, char *params, int is_daemon) + { + int r = DOMAP_FAIL; + struct config *conf; +- int verbosity; + + /* + * last chance to quit before touching the devmaps + */ + if (mpp->action == ACT_DRY_RUN) { +- conf = get_multipath_config(); +- verbosity = conf->verbosity; +- put_multipath_config(conf); +- print_multipath_topology(mpp, verbosity); ++ print_multipath_topology(mpp, libmp_verbosity); + return DOMAP_DRY; + } + +@@ -1327,14 +1323,8 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + "queue_if_no_path"); + } + +- if (!is_daemon && mpp->action != ACT_NOTHING) { +- int verbosity; +- +- conf = get_multipath_config(); +- verbosity = conf->verbosity; +- put_multipath_config(conf); +- print_multipath_topology(mpp, verbosity); +- } ++ if (!is_daemon && mpp->action != ACT_NOTHING) ++ print_multipath_topology(mpp, libmp_verbosity); + + if (mpp->action != ACT_REJECT) { + if (!vector_alloc_slot(newmp)) { +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index b3a1de9e..a1713b95 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -16,21 +16,15 @@ + #include "debug.h" + + int logsink; ++int libmp_verbosity = DEFAULT_VERBOSITY; + + void dlog (int sink, int prio, const char * fmt, ...) + { + va_list ap; +- int thres; +- struct config *conf; + + va_start(ap, fmt); +- conf = get_multipath_config(); +- ANNOTATE_IGNORE_READS_BEGIN(); +- thres = (conf) ? conf->verbosity : DEFAULT_VERBOSITY; +- ANNOTATE_IGNORE_READS_END(); +- put_multipath_config(conf); + +- if (prio <= thres) { ++ if (prio <= libmp_verbosity) { + if (sink < 1) { + if (sink == 0) { + time_t t = time(NULL); +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index c6120c1d..1f3bc8be 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -8,6 +8,7 @@ void dlog (int sink, int prio, const char * fmt, ...) + #include "log_pthread.h" + + extern int logsink; ++extern int libmp_verbosity; + + #define condlog(prio, fmt, args...) \ + dlog(logsink, prio, fmt "\n", ##args) +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index e60ab493..dfe95d2f 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -351,16 +351,11 @@ void libmp_dm_exit(void) + + static void libmp_dm_init(void) + { +- struct config *conf; +- int verbosity; + unsigned int version[3]; + + if (dm_prereq(version)) + exit(1); +- conf = get_multipath_config(); +- verbosity = conf->verbosity; +- put_multipath_config(conf); +- dm_init(verbosity); ++ dm_init(libmp_verbosity); + #ifdef LIBDM_API_HOLD_CONTROL + dm_hold_control_dev(1); + #endif +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 800cff22..67a7379f 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -259,3 +259,8 @@ global: + local: + *; + }; ++ ++LIBMULTIPATH_4.1.0 { ++global: ++ libmp_verbosity; ++} LIBMULTIPATH_4.0.0; +diff --git a/multipath/main.c b/multipath/main.c +index 043d8fa7..98d93c58 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -208,22 +208,15 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid) + mpp->bestpg = select_path_group(mpp); + + if (cmd == CMD_LIST_SHORT || +- cmd == CMD_LIST_LONG) { +- struct config *conf = get_multipath_config(); +- print_multipath_topology(mpp, conf->verbosity); +- put_multipath_config(conf); +- } ++ cmd == CMD_LIST_LONG) ++ print_multipath_topology(mpp, libmp_verbosity); + + if (cmd == CMD_CREATE) + reinstate_paths(mpp); + } + +- if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) { +- struct config *conf = get_multipath_config(); +- +- print_foreign_topology(conf->verbosity); +- put_multipath_config(conf); +- } ++ if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) ++ print_foreign_topology(libmp_verbosity); + + return 0; + } +@@ -552,7 +545,7 @@ configure (struct config *conf, enum mpath_cmds cmd, + if (path_discovery(pathvec, di_flag) < 0) + goto out; + +- if (conf->verbosity > 2) ++ if (libmp_verbosity > 2) + print_all_paths(pathvec, 1); + + get_path_layout(pathvec, 0); +@@ -843,7 +836,7 @@ main (int argc, char *argv[]) + exit(RTVL_FAIL); + } + +- conf->verbosity = atoi(optarg); ++ libmp_verbosity = atoi(optarg); + break; + case 'b': + conf->bindings_file = strdup(optarg); +@@ -974,7 +967,7 @@ main (int argc, char *argv[]) + } + if (dev_type == DEV_UEVENT) { + openlog("multipath", 0, LOG_DAEMON); +- setlogmask(LOG_UPTO(conf->verbosity + 3)); ++ setlogmask(LOG_UPTO(libmp_verbosity + 3)); + logsink = 1; + } + +diff --git a/multipathd/main.c b/multipathd/main.c +index 4de0978e..ba257515 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -88,10 +88,10 @@ + #define CMDSIZE 160 + #define MSG_SIZE 32 + +-#define LOG_MSG(lvl, verb, pp) \ ++#define LOG_MSG(lvl, pp) \ + do { \ + if (pp->mpp && checker_selected(&pp->checker) && \ +- lvl <= verb) { \ ++ lvl <= libmp_verbosity) { \ + if (pp->offline) \ + condlog(lvl, "%s: %s - path offline", \ + pp->mpp->alias, pp->dev); \ +@@ -2070,7 +2070,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + int chkr_new_path_up = 0; + int disable_reinstate = 0; + int oldchkrstate = pp->chkrstate; +- int retrigger_tries, verbosity; ++ int retrigger_tries; + unsigned int checkint, max_checkint; + struct config *conf; + int marginal_pathgroups, marginal_changed = 0; +@@ -2090,7 +2090,6 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + retrigger_tries = conf->retrigger_tries; + checkint = conf->checkint; + max_checkint = conf->max_checkint; +- verbosity = conf->verbosity; + marginal_pathgroups = conf->marginal_pathgroups; + put_multipath_config(conf); + +@@ -2152,7 +2151,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { + condlog(2, "%s: unusable path (%s) - checker failed", + pp->dev, checker_state_name(newstate)); +- LOG_MSG(2, verbosity, pp); ++ LOG_MSG(2, pp); + conf = get_multipath_config(); + pthread_cleanup_push(put_multipath_config, conf); + pathinfo(pp, conf, 0); +@@ -2257,7 +2256,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + int oldstate = pp->state; + pp->state = newstate; + +- LOG_MSG(1, verbosity, pp); ++ LOG_MSG(1, pp); + + /* + * upon state change, reset the checkint +@@ -2321,7 +2320,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + /* Clear IO errors */ + reinstate_path(pp); + else { +- LOG_MSG(4, verbosity, pp); ++ LOG_MSG(4, pp); + if (pp->checkint != max_checkint) { + /* + * double the next check delay. +@@ -2349,9 +2348,9 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + log_checker_err = conf->log_checker_err; + put_multipath_config(conf); + if (log_checker_err == LOG_CHKR_ERR_ONCE) +- LOG_MSG(3, verbosity, pp); ++ LOG_MSG(3, pp); + else +- LOG_MSG(2, verbosity, pp); ++ LOG_MSG(2, pp); + } + } + +@@ -2696,6 +2695,10 @@ reconfigure (struct vectors * vecs) + if (!conf) + return 1; + ++ if (verbosity) ++ libmp_verbosity = verbosity; ++ setlogmask(LOG_UPTO(libmp_verbosity + 3)); ++ + /* + * free old map and path vectors ... they use old conf state + */ +@@ -2710,8 +2713,6 @@ reconfigure (struct vectors * vecs) + /* Re-read any timezone changes */ + tzset(); + +- if (verbosity) +- conf->verbosity = verbosity; + if (bindings_read_only) + conf->bindings_read_only = bindings_read_only; + check_alias_settings(conf); +@@ -3091,14 +3092,18 @@ child (__attribute__((unused)) void *param) + condlog(2, "--------start up--------"); + condlog(2, "read " DEFAULT_CONFIGFILE); + ++ if (verbosity) ++ libmp_verbosity = verbosity; + conf = load_config(DEFAULT_CONFIGFILE); ++ if (verbosity) ++ libmp_verbosity = verbosity; ++ setlogmask(LOG_UPTO(libmp_verbosity + 3)); ++ + if (!conf) { + condlog(0, "failed to load configuration"); + goto failed; + } + +- if (verbosity) +- conf->verbosity = verbosity; + if (bindings_read_only) + conf->bindings_read_only = bindings_read_only; + uxsock_timeout = conf->uxsock_timeout; +@@ -3117,7 +3122,6 @@ child (__attribute__((unused)) void *param) + + if (poll_dmevents) + poll_dmevents = dmevent_poll_supported(); +- setlogmask(LOG_UPTO(conf->verbosity + 3)); + + envp = getenv("LimitNOFILE"); + +@@ -3339,7 +3343,7 @@ main (int argc, char *argv[]) + !isdigit(optarg[0])) + exit(1); + +- verbosity = atoi(optarg); ++ libmp_verbosity = verbosity = atoi(optarg); + break; + case 's': + logsink = -1; +@@ -3350,7 +3354,7 @@ main (int argc, char *argv[]) + if (!conf) + exit(1); + if (verbosity) +- conf->verbosity = verbosity; ++ libmp_verbosity = verbosity; + uxsock_timeout = conf->uxsock_timeout; + err = uxclnt(optarg, uxsock_timeout + 100); + free_config(conf); +@@ -3376,11 +3380,13 @@ main (int argc, char *argv[]) + char * c = s; + + logsink = 0; ++ if (verbosity) ++ libmp_verbosity = verbosity; + conf = load_config(DEFAULT_CONFIGFILE); + if (!conf) + exit(1); + if (verbosity) +- conf->verbosity = verbosity; ++ libmp_verbosity = verbosity; + uxsock_timeout = conf->uxsock_timeout; + memset(cmd, 0x0, CMDSIZE); + while (optind < argc) { +diff --git a/tests/alias.c b/tests/alias.c +index 7fda679d..0311faa6 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -735,6 +735,7 @@ static int test_allocate_binding(void) + int main(void) + { + int ret = 0; ++ libmp_verbosity = conf.verbosity; + + ret += test_format_devname(); + ret += test_scan_devname(); +diff --git a/tests/blacklist.c b/tests/blacklist.c +index 84a3ba2f..0b42e255 100644 +--- a/tests/blacklist.c ++++ b/tests/blacklist.c +@@ -22,6 +22,7 @@ + #include "globals.c" + #include "blacklist.h" + #include "test-log.h" ++#include "debug.h" + + struct udev_device { + const char *sysname; +@@ -152,6 +153,7 @@ static int setup(void **state) + store_ble(blist_property_wwn_inv, "!ID_WWN", ORIGIN_CONFIG)) + return -1; + ++ libmp_verbosity = conf.verbosity = 4; + return 0; + } + +-- +2.17.2 + diff --git a/0063-libmultipath-introduce-symbolic-values-for-logsink.patch b/0063-libmultipath-introduce-symbolic-values-for-logsink.patch new file mode 100644 index 0000000..24cf615 --- /dev/null +++ b/0063-libmultipath-introduce-symbolic-values-for-logsink.patch @@ -0,0 +1,185 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:32:05 +0200 +Subject: [PATCH] libmultipath: introduce symbolic values for logsink + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/debug.c | 4 ++-- + libmultipath/debug.h | 6 ++++++ + libmultipath/devmapper.c | 4 ++-- + multipath/main.c | 4 ++-- + multipathd/main.c | 17 ++++++++--------- + tests/globals.c | 3 ++- + tests/hwtable.c | 2 +- + 7 files changed, 23 insertions(+), 17 deletions(-) + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index a1713b95..f9b77552 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -25,8 +25,8 @@ void dlog (int sink, int prio, const char * fmt, ...) + va_start(ap, fmt); + + if (prio <= libmp_verbosity) { +- if (sink < 1) { +- if (sink == 0) { ++ if (sink != LOGSINK_SYSLOG) { ++ if (sink == LOGSINK_STDERR_WITH_TIME) { + time_t t = time(NULL); + struct tm *tb = localtime(&t); + char buff[16]; +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index 1f3bc8be..b6ce70a7 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -12,3 +12,9 @@ extern int libmp_verbosity; + + #define condlog(prio, fmt, args...) \ + dlog(logsink, prio, fmt "\n", ##args) ++ ++enum { ++ LOGSINK_STDERR_WITH_TIME = 0, ++ LOGSINK_STDERR_WITHOUT_TIME = -1, ++ LOGSINK_SYSLOG = 1, ++}; +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index dfe95d2f..f8b180e1 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -104,8 +104,8 @@ dm_write_log (int level, const char *file, int line, const char *f, ...) + return; + + va_start(ap, f); +- if (logsink < 1) { +- if (logsink == 0) { ++ if (logsink != LOGSINK_SYSLOG) { ++ if (logsink == LOGSINK_STDERR_WITH_TIME) { + time_t t = time(NULL); + struct tm *tb = localtime(&t); + char buff[16]; +diff --git a/multipath/main.c b/multipath/main.c +index 98d93c58..9ac42869 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -817,7 +817,7 @@ main (int argc, char *argv[]) + libmultipath_init(); + if (atexit(dm_lib_exit) || atexit(libmultipath_exit)) + condlog(1, "failed to register cleanup handler for libmultipath: %m"); +- logsink = 0; ++ logsink = LOGSINK_STDERR_WITH_TIME; + if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); + if (atexit(uninit_config)) +@@ -968,7 +968,7 @@ main (int argc, char *argv[]) + if (dev_type == DEV_UEVENT) { + openlog("multipath", 0, LOG_DAEMON); + setlogmask(LOG_UPTO(libmp_verbosity + 3)); +- logsink = 1; ++ logsink = LOGSINK_SYSLOG; + } + + set_max_fds(conf->max_fds); +diff --git a/multipathd/main.c b/multipathd/main.c +index ba257515..867f0f84 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2780,7 +2780,7 @@ handle_signals(bool nonfatal) + } + if (log_reset_sig) { + condlog(2, "reset log (signal)"); +- if (logsink == 1) ++ if (logsink == LOGSINK_SYSLOG) + log_thread_reset(); + } + reconfig_sig = 0; +@@ -3033,7 +3033,7 @@ static void cleanup_child(void) + cleanup_dmevent_waiter(); + + cleanup_pidfile(); +- if (logsink == 1) ++ if (logsink == LOGSINK_SYSLOG) + log_thread_stop(); + + cleanup_conf(); +@@ -3076,7 +3076,7 @@ child (__attribute__((unused)) void *param) + setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 0); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); + +- if (logsink == 1) { ++ if (logsink == LOGSINK_SYSLOG) { + setup_thread_attr(&log_attr, 64 * 1024, 0); + log_thread_start(&log_attr); + pthread_attr_destroy(&log_attr); +@@ -3307,7 +3307,7 @@ main (int argc, char *argv[]) + ANNOTATE_BENIGN_RACE_SIZED(&uxsock_timeout, sizeof(uxsock_timeout), + "Suppress complaints about this scalar variable"); + +- logsink = 1; ++ logsink = LOGSINK_SYSLOG; + + if (getuid() != 0) { + fprintf(stderr, "need to be root\n"); +@@ -3334,9 +3334,8 @@ main (int argc, char *argv[]) + switch(arg) { + case 'd': + foreground = 1; +- if (logsink > 0) +- logsink = 0; +- //debug=1; /* ### comment me out ### */ ++ if (logsink == LOGSINK_SYSLOG) ++ logsink = LOGSINK_STDERR_WITH_TIME; + break; + case 'v': + if (sizeof(optarg) > sizeof(char *) || +@@ -3346,7 +3345,7 @@ main (int argc, char *argv[]) + libmp_verbosity = verbosity = atoi(optarg); + break; + case 's': +- logsink = -1; ++ logsink = LOGSINK_STDERR_WITHOUT_TIME; + break; + case 'k': + logsink = 0; +@@ -3379,7 +3378,7 @@ main (int argc, char *argv[]) + char * s = cmd; + char * c = s; + +- logsink = 0; ++ logsink = LOGSINK_STDERR_WITH_TIME; + if (verbosity) + libmp_verbosity = verbosity; + conf = load_config(DEFAULT_CONFIGFILE); +diff --git a/tests/globals.c b/tests/globals.c +index 8add5eb7..fc0c07ad 100644 +--- a/tests/globals.c ++++ b/tests/globals.c +@@ -1,9 +1,10 @@ + #include "structs.h" + #include "config.h" ++#include "debug.h" + + /* Required globals */ + struct udev *udev; +-int logsink = -1; ++int logsink = LOGSINK_STDERR_WITHOUT_TIME; + struct config conf = { + .verbosity = 4, + }; +diff --git a/tests/hwtable.c b/tests/hwtable.c +index 57f832b7..4dd0873b 100644 +--- a/tests/hwtable.c ++++ b/tests/hwtable.c +@@ -53,7 +53,7 @@ struct hwt_state { + + static struct config *_conf; + struct udev *udev; +-int logsink = -1; ++int logsink = LOGSINK_STDERR_WITHOUT_TIME; + + struct config *get_multipath_config(void) + { +-- +2.17.2 + diff --git a/0064-libmultipath-simplify-dlog.patch b/0064-libmultipath-simplify-dlog.patch new file mode 100644 index 0000000..af47833 --- /dev/null +++ b/0064-libmultipath-simplify-dlog.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:39:22 +0200 +Subject: [PATCH] libmultipath: simplify dlog() + +By checking the log level in condlog() directly, we can simplify +dlog(). Also, it's now possible to limit the log level at compile +time by setting MAX_VERBOSITY, enabling the compiler to optimize +away log messages with higher loglevel. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/debug.c | 30 +++++++++++++----------------- + libmultipath/debug.h | 20 ++++++++++++++++---- + libmultipath/devmapper.c | 4 +++- + tests/test-log.c | 4 ++-- + tests/test-log.h | 3 ++- + 5 files changed, 36 insertions(+), 25 deletions(-) + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index f9b77552..429f2699 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -18,29 +18,25 @@ + int logsink; + int libmp_verbosity = DEFAULT_VERBOSITY; + +-void dlog (int sink, int prio, const char * fmt, ...) ++void dlog(int prio, const char * fmt, ...) + { + va_list ap; + + va_start(ap, fmt); ++ if (logsink != LOGSINK_SYSLOG) { ++ if (logsink == LOGSINK_STDERR_WITH_TIME) { ++ time_t t = time(NULL); ++ struct tm *tb = localtime(&t); ++ char buff[16]; + +- if (prio <= libmp_verbosity) { +- if (sink != LOGSINK_SYSLOG) { +- if (sink == LOGSINK_STDERR_WITH_TIME) { +- time_t t = time(NULL); +- struct tm *tb = localtime(&t); +- char buff[16]; +- +- strftime(buff, sizeof(buff), +- "%b %d %H:%M:%S", tb); +- buff[sizeof(buff)-1] = '\0'; +- +- fprintf(stderr, "%s | ", buff); +- } +- vfprintf(stderr, fmt, ap); ++ strftime(buff, sizeof(buff), ++ "%b %d %H:%M:%S", tb); ++ buff[sizeof(buff)-1] = '\0'; ++ fprintf(stderr, "%s | ", buff); + } +- else +- log_safe(prio + 3, fmt, ap); ++ vfprintf(stderr, fmt, ap); + } ++ else ++ log_safe(prio + 3, fmt, ap); + va_end(ap); + } +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index b6ce70a7..705a5d73 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -1,5 +1,7 @@ +-void dlog (int sink, int prio, const char * fmt, ...) +- __attribute__((format(printf, 3, 4))); ++#ifndef _DEBUG_H ++#define _DEBUG_H ++void dlog (int prio, const char *fmt, ...) ++ __attribute__((format(printf, 2, 3))); + + + #include +@@ -10,11 +12,21 @@ void dlog (int sink, int prio, const char * fmt, ...) + extern int logsink; + extern int libmp_verbosity; + +-#define condlog(prio, fmt, args...) \ +- dlog(logsink, prio, fmt "\n", ##args) ++#ifndef MAX_VERBOSITY ++#define MAX_VERBOSITY 4 ++#endif + + enum { + LOGSINK_STDERR_WITH_TIME = 0, + LOGSINK_STDERR_WITHOUT_TIME = -1, + LOGSINK_SYSLOG = 1, + }; ++ ++#define condlog(prio, fmt, args...) \ ++ do { \ ++ int __p = (prio); \ ++ \ ++ if (__p <= MAX_VERBOSITY && __p <= libmp_verbosity) \ ++ dlog(__p, fmt "\n", ##args); \ ++ } while (0) ++#endif /* _DEBUG_H */ +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index f8b180e1..4977b311 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -276,7 +276,9 @@ static int dm_tgt_prereq (unsigned int *ver) + + static void _init_versions(void) + { +- dlog(logsink, 3, VERSION_STRING); ++ /* Can't use condlog here because of how VERSION_STRING is defined */ ++ if (3 <= libmp_verbosity) ++ dlog(3, VERSION_STRING); + init_dm_library_version(); + init_dm_drv_version(); + init_dm_mpath_version(); +diff --git a/tests/test-log.c b/tests/test-log.c +index 1c901cba..14f25b9b 100644 +--- a/tests/test-log.c ++++ b/tests/test-log.c +@@ -7,8 +7,8 @@ + #include "log.h" + #include "test-log.h" + +-__attribute__((format(printf, 3, 0))) +-void __wrap_dlog (int sink, int prio, const char * fmt, ...) ++__attribute__((format(printf, 2, 0))) ++void __wrap_dlog (int prio, const char * fmt, ...) + { + char buff[MAX_MSG_SIZE]; + va_list ap; +diff --git a/tests/test-log.h b/tests/test-log.h +index 2c878c63..6d22cd23 100644 +--- a/tests/test-log.h ++++ b/tests/test-log.h +@@ -1,7 +1,8 @@ + #ifndef _TEST_LOG_H + #define _TEST_LOG_H + +-void __wrap_dlog (int sink, int prio, const char * fmt, ...); ++__attribute__((format(printf, 2, 0))) ++void __wrap_dlog (int prio, const char * fmt, ...); + void expect_condlog(int prio, char *string); + + #endif +-- +2.17.2 + diff --git a/0065-RH-warn-on-invalid-regex-instead-of-failing.patch b/0065-RH-warn-on-invalid-regex-instead-of-failing.patch deleted file mode 100644 index 4bdd97e..0000000 --- a/0065-RH-warn-on-invalid-regex-instead-of-failing.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0065-multipathd-common-code-for-k-and-command-args.patch b/0065-multipathd-common-code-for-k-and-command-args.patch new file mode 100644 index 0000000..1fc5a75 --- /dev/null +++ b/0065-multipathd-common-code-for-k-and-command-args.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 00:43:12 +0200 +Subject: [PATCH] multipathd: common code for "-k" and command args + +'multipathd -k"cmd"' and 'multipath cmd' are the same thing. +Treat it with common code. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 867f0f84..b6a5f5b7 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3301,6 +3301,8 @@ main (int argc, char *argv[]) + int err; + int foreground = 0; + struct config *conf; ++ char *opt_k_arg = NULL; ++ bool opt_k = false; + + ANNOTATE_BENIGN_RACE_SIZED(&multipath_conf, sizeof(multipath_conf), + "Manipulated through RCU"); +@@ -3348,16 +3350,9 @@ main (int argc, char *argv[]) + logsink = LOGSINK_STDERR_WITHOUT_TIME; + break; + case 'k': +- logsink = 0; +- conf = load_config(DEFAULT_CONFIGFILE); +- if (!conf) +- exit(1); +- if (verbosity) +- libmp_verbosity = verbosity; +- uxsock_timeout = conf->uxsock_timeout; +- err = uxclnt(optarg, uxsock_timeout + 100); +- free_config(conf); +- return err; ++ opt_k = true; ++ opt_k_arg = optarg; ++ break; + case 'B': + bindings_read_only = 1; + break; +@@ -3373,7 +3368,7 @@ main (int argc, char *argv[]) + exit(1); + } + } +- if (optind < argc) { ++ if (opt_k || optind < argc) { + char cmd[CMDSIZE]; + char * s = cmd; + char * c = s; +@@ -3388,14 +3383,20 @@ main (int argc, char *argv[]) + libmp_verbosity = verbosity; + uxsock_timeout = conf->uxsock_timeout; + memset(cmd, 0x0, CMDSIZE); +- while (optind < argc) { +- if (strchr(argv[optind], ' ')) +- c += snprintf(c, s + CMDSIZE - c, "\"%s\" ", argv[optind]); +- else +- c += snprintf(c, s + CMDSIZE - c, "%s ", argv[optind]); +- optind++; ++ if (opt_k) ++ s = opt_k_arg; ++ else { ++ while (optind < argc) { ++ if (strchr(argv[optind], ' ')) ++ c += snprintf(c, s + CMDSIZE - c, ++ "\"%s\" ", argv[optind]); ++ else ++ c += snprintf(c, s + CMDSIZE - c, ++ "%s ", argv[optind]); ++ optind++; ++ } ++ c += snprintf(c, s + CMDSIZE - c, "\n"); + } +- c += snprintf(c, s + CMDSIZE - c, "\n"); + err = uxclnt(s, uxsock_timeout + 100); + free_config(conf); + return err; +-- +2.17.2 + diff --git a/0066-multipathd-sanitize-uxsock_listen.patch b/0066-multipathd-sanitize-uxsock_listen.patch new file mode 100644 index 0000000..d7efc72 --- /dev/null +++ b/0066-multipathd-sanitize-uxsock_listen.patch @@ -0,0 +1,157 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Sat, 26 Sep 2020 15:22:34 +0200 +Subject: [PATCH] multipathd: sanitize uxsock_listen() + +We were allocating 1025 poll fds, which is weird. Change it to a power of two, +and make this more easily customizable in general. Use POLLFDS_BASE rather +than the hard-coded "2" for the number of fds we poll besides client +connections. Introduce a maximum number of clients that can connect. When +this number is reached, we simply stop polling the accept socket, so that new +connections aren't accepted any more. Don't attempt to realloc() the pollfd +array if the number of clients decreases. It's unlikely to ever be more than +one or two pages. Finally, there's no need to wake up every 5s. Our signal +handling is robust. Just sleep forever in ppoll() if nothing happens. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/uxlsnr.c | 70 ++++++++++++++++++++++++++++----------------- + 1 file changed, 43 insertions(+), 27 deletions(-) + +diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c +index ce2b6800..cd462b6d 100644 +--- a/multipathd/uxlsnr.c ++++ b/multipathd/uxlsnr.c +@@ -41,14 +41,25 @@ + #include "cli.h" + #include "uxlsnr.h" + +-static struct timespec sleep_time = {5, 0}; +- + struct client { + struct list_head node; + int fd; + }; + +-#define MIN_POLLS 1023 ++/* The number of fds we poll on, other than individual client connections */ ++#define POLLFDS_BASE 2 ++#define POLLFD_CHUNK (4096 / sizeof(struct pollfd)) ++/* Minimum mumber of pollfds to reserve for clients */ ++#define MIN_POLLS (POLLFD_CHUNK - POLLFDS_BASE) ++/* ++ * Max number of client connections allowed ++ * During coldplug, there may be a large number of "multipath -u" ++ * processes connecting. ++ */ ++#define MAX_CLIENTS (16384 - POLLFDS_BASE) ++ ++/* Compile-time error if POLLFD_CHUNK is too small */ ++static __attribute__((unused)) char ___a[-(MIN_POLLS <= 0)]; + + static LIST_HEAD(clients); + static pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER; +@@ -282,13 +293,13 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + char *inbuf; + char *reply; + sigset_t mask; +- int old_clients = MIN_POLLS; ++ int max_pfds = MIN_POLLS + POLLFDS_BASE; + /* conf->sequence_nr will be 1 when uxsock_listen is first called */ + unsigned int sequence_nr = 0; + struct watch_descriptors wds = { .conf_wd = -1, .dir_wd = -1 }; + + condlog(3, "uxsock: startup listener"); +- polls = (struct pollfd *)MALLOC((MIN_POLLS + 2) * sizeof(struct pollfd)); ++ polls = MALLOC(max_pfds * sizeof(*polls)); + if (!polls) { + condlog(0, "uxsock: failed to allocate poll fds"); + exit_daemon(); +@@ -312,28 +323,33 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + list_for_each_entry(c, &clients, node) { + num_clients++; + } +- if (num_clients != old_clients) { ++ if (num_clients + POLLFDS_BASE > max_pfds) { + struct pollfd *new; +- if (num_clients <= MIN_POLLS && old_clients > MIN_POLLS) { +- new = REALLOC(polls, (2 + MIN_POLLS) * +- sizeof(struct pollfd)); +- } else if (num_clients <= MIN_POLLS && old_clients <= MIN_POLLS) { +- new = polls; +- } else { +- new = REALLOC(polls, (2 + num_clients) * +- sizeof(struct pollfd)); +- } +- if (!new) { +- condlog(0, "%s: failed to realloc %d poll fds", +- "uxsock", 2 + num_clients); +- num_clients = old_clients; +- } else { +- old_clients = num_clients; ++ int n_new = max_pfds + POLLFD_CHUNK; ++ ++ new = REALLOC(polls, n_new * sizeof(*polls)); ++ if (new) { ++ max_pfds = n_new; + polls = new; ++ } else { ++ condlog(1, "%s: realloc failure, %d clients not served", ++ __func__, ++ num_clients + POLLFDS_BASE - max_pfds); ++ num_clients = max_pfds - POLLFDS_BASE; + } + } +- polls[0].fd = ux_sock; +- polls[0].events = POLLIN; ++ if (num_clients < MAX_CLIENTS) { ++ polls[0].fd = ux_sock; ++ polls[0].events = POLLIN; ++ } else { ++ /* ++ * New clients can't connect, num_clients won't grow ++ * to MAX_CLIENTS or higher ++ */ ++ condlog(1, "%s: max client connections reached, pausing polling", ++ __func__); ++ polls[0].fd = -1; ++ } + + reset_watch(notify_fd, &wds, &sequence_nr); + if (notify_fd == -1 || (wds.conf_wd == -1 && wds.dir_wd == -1)) +@@ -343,19 +359,19 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + polls[1].events = POLLIN; + + /* setup the clients */ +- i = 2; ++ i = POLLFDS_BASE; + list_for_each_entry(c, &clients, node) { + polls[i].fd = c->fd; + polls[i].events = POLLIN; + i++; +- if (i >= 2 + num_clients) ++ if (i >= max_pfds) + break; + } + n_pfds = i; + pthread_cleanup_pop(1); + + /* most of our life is spent in this call */ +- poll_count = ppoll(polls, n_pfds, &sleep_time, &mask); ++ poll_count = ppoll(polls, n_pfds, NULL, &mask); + + handle_signals(false); + if (poll_count == -1) { +@@ -388,7 +404,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, + } + + /* see if a client wants to speak to us */ +- for (i = 2; i < n_pfds; i++) { ++ for (i = POLLFDS_BASE; i < n_pfds; i++) { + if (polls[i].revents & POLLIN) { + struct timespec start_time; + +-- +2.17.2 + diff --git a/0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch b/0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch new file mode 100644 index 0000000..29f5ce7 --- /dev/null +++ b/0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 15 Oct 2020 16:13:14 +0200 +Subject: [PATCH] libmultipath: fix race between log_safe and log_thread_stop() + +log_safe() could race with log_thread_stop(); simply +checking the value of log_thr has never been safe. By converting the +mutexes to static initializers, we avoid having to destroy them, and thus +possibly accessing a destroyed mutex in log_safe(). Furthermore, taking +both the logev_lock and the logq_lock makes sure the logarea isn't freed +while we are writing to it. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log_pthread.c | 48 +++++++++++++++++++++----------------- + 1 file changed, 26 insertions(+), 22 deletions(-) + +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 3a2566ae..0d48c52c 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -17,31 +17,42 @@ + + static pthread_t log_thr; + +-static pthread_mutex_t logq_lock; +-static pthread_mutex_t logev_lock; +-static pthread_cond_t logev_cond; ++/* logev_lock must not be taken with logq_lock held */ ++static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_mutex_t logev_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t logev_cond = PTHREAD_COND_INITIALIZER; + + static int logq_running; + static int log_messages_pending; + + void log_safe (int prio, const char * fmt, va_list ap) + { ++ bool running; ++ + if (prio > LOG_DEBUG) + prio = LOG_DEBUG; + +- if (log_thr == (pthread_t)0) { +- vsyslog(prio, fmt, ap); +- return; +- } ++ /* ++ * logev_lock protects logq_running. By holding it, we avoid a race ++ * with log_thread_stop() -> log_close(), which would free the logarea. ++ */ ++ pthread_mutex_lock(&logev_lock); ++ pthread_cleanup_push(cleanup_mutex, &logev_lock); ++ running = logq_running; + +- pthread_mutex_lock(&logq_lock); +- log_enqueue(prio, fmt, ap); +- pthread_mutex_unlock(&logq_lock); ++ if (running) { ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ log_enqueue(prio, fmt, ap); ++ pthread_cleanup_pop(1); + +- pthread_mutex_lock(&logev_lock); +- log_messages_pending = 1; +- pthread_cond_signal(&logev_cond); +- pthread_mutex_unlock(&logev_lock); ++ log_messages_pending = 1; ++ pthread_cond_signal(&logev_cond); ++ } ++ pthread_cleanup_pop(1); ++ ++ if (!running) ++ vsyslog(prio, fmt, ap); + } + + static void flush_logqueue (void) +@@ -103,9 +114,6 @@ void log_thread_start (pthread_attr_t *attr) + int running = 0; + + logdbg(stderr,"enter log_thread_start\n"); +- pthread_mutex_init(&logq_lock, NULL); +- pthread_mutex_init(&logev_lock, NULL); +- pthread_cond_init(&logev_cond, NULL); + + if (log_init("multipathd", 0)) { + fprintf(stderr,"can't initialize log buffer\n"); +@@ -154,13 +162,9 @@ void log_thread_stop (void) + } + pthread_cleanup_pop(1); + +- flush_logqueue(); + if (running) + pthread_join(log_thr, NULL); + +- pthread_mutex_destroy(&logq_lock); +- pthread_mutex_destroy(&logev_lock); +- pthread_cond_destroy(&logev_cond); +- ++ flush_logqueue(); + log_close(); + } +-- +2.17.2 + diff --git a/0070-multipath-add-libmpathvalid-library.patch b/0068-multipath-add-libmpathvalid-library.patch similarity index 52% rename from 0070-multipath-add-libmpathvalid-library.patch rename to 0068-multipath-add-libmpathvalid-library.patch index b3863cd..24ba4ac 100644 --- a/0070-multipath-add-libmpathvalid-library.patch +++ b/0068-multipath-add-libmpathvalid-library.patch @@ -1,13 +1,13 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski -Date: Wed, 13 May 2020 17:04:24 -0500 +Date: Wed, 21 Oct 2020 16:39:23 -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. +by multipath. It exports an init function, that needs to be called +before and after all other library calls, an exit function, that needs +to be called after all library calls, a function to reread the multipath +configuration files, 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 @@ -17,25 +17,26 @@ 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. +The library also doesn't set up the device-mapper library. It leaves +this up to the caller. Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck --- Makefile | 3 +- - Makefile.inc | 1 + - libmpathvalid/Makefile | 38 +++++++ + libmpathvalid/Makefile | 39 ++++++ libmpathvalid/libmpathvalid.version | 10 ++ - libmpathvalid/mpath_valid.c | 168 ++++++++++++++++++++++++++++ - libmpathvalid/mpath_valid.h | 57 ++++++++++ - 6 files changed, 276 insertions(+), 1 deletion(-) + libmpathvalid/mpath_valid.c | 202 ++++++++++++++++++++++++++++ + libmpathvalid/mpath_valid.h | 155 +++++++++++++++++++++ + libmultipath/libmultipath.version | 6 + + 6 files changed, 414 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 +index 4a3491da..f127ff91 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ BUILDDIRS := \ @@ -55,29 +56,18 @@ index 8bcaba66..f157a549 100644 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 +index 00000000..6bea4bcd --- /dev/null +++ b/libmpathvalid/Makefile -@@ -0,0 +1,38 @@ +@@ -0,0 +1,39 @@ +include ../Makefile.inc + +SONAME = 0 +DEVLIB = libmpathvalid.so +LIBS = $(DEVLIB).$(SONAME) ++VERSION_SCRIPT := libmpathvalid.version + +CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) + @@ -88,7 +78,7 @@ index 00000000..70b97eca + +all: $(LIBS) + -+$(LIBS): $(OBJS) ++$(LIBS): $(OBJS) $(VERSION_SCRIPT) + $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) -Wl,--version-script=libmpathvalid.version + $(LN) $(LIBS) $(DEVLIB) + @@ -113,14 +103,14 @@ index 00000000..70b97eca + $(RM) $(OBJS:.o=.d) diff --git a/libmpathvalid/libmpathvalid.version b/libmpathvalid/libmpathvalid.version new file mode 100644 -index 00000000..4d8a8ba4 +index 00000000..3bd0d3c5 --- /dev/null +++ b/libmpathvalid/libmpathvalid.version @@ -0,0 +1,10 @@ +MPATH_1.0 { + global: -+ mpathvalid_conf; + mpathvalid_init; ++ mpathvalid_reload_config; + mpathvalid_exit; + mpathvalid_is_path; + mpathvalid_get_mode; @@ -129,10 +119,10 @@ index 00000000..4d8a8ba4 +}; diff --git a/libmpathvalid/mpath_valid.c b/libmpathvalid/mpath_valid.c new file mode 100644 -index 00000000..6153e8b7 +index 00000000..7073d17d --- /dev/null +++ b/libmpathvalid/mpath_valid.c -@@ -0,0 +1,168 @@ +@@ -0,0 +1,202 @@ +#include +#include +#include @@ -150,11 +140,10 @@ index 00000000..6153e8b7 +#include "mpath_cmd.h" +#include "valid.h" +#include "mpath_valid.h" ++#include "debug.h" + -+static struct config default_config = { .verbosity = -1 }; -+struct config *mpathvalid_conf = &default_config; -+ -+static unsigned int get_conf_mode(struct config *conf) ++static unsigned int ++get_conf_mode(struct config *conf) +{ + if (conf->find_multipaths == FIND_MULTIPATHS_SMART) + return MPATH_SMART; @@ -163,7 +152,8 @@ index 00000000..6153e8b7 + return MPATH_STRICT; +} + -+static void set_conf_mode(struct config *conf, unsigned int mode) ++static void ++set_conf_mode(struct config *conf, unsigned int mode) +{ + if (mode == MPATH_SMART) + conf->find_multipaths = FIND_MULTIPATHS_SMART; @@ -173,20 +163,23 @@ index 00000000..6153e8b7 + conf->find_multipaths = FIND_MULTIPATHS_STRICT; +} + -+unsigned int mpathvalid_get_mode(void) ++unsigned int ++mpathvalid_get_mode(void) +{ + int mode; + struct config *conf; + + conf = get_multipath_config(); + if (!conf) -+ return -1; -+ mode = get_conf_mode(conf); ++ mode = MPATH_MODE_ERROR; ++ else ++ mode = get_conf_mode(conf); + put_multipath_config(conf); + return mode; +} + -+static int convert_result(int result) { ++static int ++convert_result(int result) { + switch (result) { + case PATH_IS_ERROR: + return MPATH_IS_ERROR; @@ -202,39 +195,66 @@ index 00000000..6153e8b7 + return MPATH_IS_ERROR; +} + ++static void ++set_log_style(int log_style) ++{ ++ /* ++ * convert MPATH_LOG_* to LOGSINK_* ++ * currently there is no work to do here. ++ */ ++ logsink = log_style; ++} ++ ++static int ++load_default_config(int verbosity) ++{ ++ /* need to set verbosity here to control logging during init_config() */ ++ libmp_verbosity = verbosity; ++ if (init_config(DEFAULT_CONFIGFILE)) ++ return -1; ++ /* Need to override verbosity from init_config() */ ++ libmp_verbosity = verbosity; ++ ++ return 0; ++} ++ +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) ++ set_log_style(log_style); ++ if (libmultipath_init()) + return -1; -+ conf->verbosity = verbosity; -+ if (dm_prereq(version)) -+ goto fail; -+ memcpy(conf->version, version, sizeof(version)); + -+ mpathvalid_conf = conf; ++ skip_libmp_dm_init(); ++ if (load_default_config(verbosity)) ++ goto fail; ++ ++ if (dm_prereq(version)) ++ goto fail_config; ++ + return 0; ++ ++fail_config: ++ uninit_config(); +fail: -+ free_config(conf); ++ libmultipath_exit(); + return -1; +} + +int ++mpathvalid_reload_config(void) ++{ ++ uninit_config(); ++ return load_default_config(libmp_verbosity); ++} ++ ++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); ++ uninit_config(); ++ libmultipath_exit(); + return 0; +} + @@ -250,15 +270,16 @@ index 00000000..6153e8b7 + const char **path_wwids, unsigned int nr_paths) +{ + struct config *conf; -+ int r = MPATH_IS_ERROR; ++ int find_multipaths_saved, r = MPATH_IS_ERROR; + unsigned int i; + struct path *pp; + -+ if (!name || mode >= MPATH_MAX_MODE) ++ if (!name || mode >= MPATH_MODE_ERROR) + return r; -+ + if (nr_paths > 0 && !path_wwids) + return r; ++ if (!udev) ++ return r; + + pp = alloc_path(); + if (!pp) @@ -271,16 +292,19 @@ index 00000000..6153e8b7 + } + + conf = get_multipath_config(); -+ if (!conf || conf == &default_config) ++ if (!conf) + goto out_wwid; ++ find_multipaths_saved = conf->find_multipaths; + if (mode != MPATH_DEFAULT) + set_conf_mode(conf, mode); + r = convert_result(is_path_valid(name, conf, pp, true)); ++ conf->find_multipaths = find_multipaths_saved; + 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) { ++ if (path_wwids[i] && ++ strncmp(path_wwids[i], pp->wwid, WWID_SIZE) == 0) { + r = MPATH_IS_VALID; + break; + } @@ -303,10 +327,10 @@ index 00000000..6153e8b7 +} diff --git a/libmpathvalid/mpath_valid.h b/libmpathvalid/mpath_valid.h new file mode 100644 -index 00000000..7fd8aa47 +index 00000000..63de4e1c --- /dev/null +++ b/libmpathvalid/mpath_valid.h -@@ -0,0 +1,57 @@ +@@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * @@ -338,11 +362,16 @@ index 00000000..7fd8aa47 + MPATH_STRICT, + MPATH_SMART, + MPATH_GREEDY, -+ MPATH_MAX_MODE, /* used only for bounds checking */ ++ MPATH_MODE_ERROR, +}; + -+/* MPATH_IS_VALID_NO_CHECK is used to skip checks to see if the device -+ * has already been unclaimed by multipath in the past */ ++/* ++ * MPATH_IS_VALID_NO_CHECK is used to indicate that it is safe to skip ++ * checks to see if the device has already been released to the system ++ * for use by things other that multipath. ++ * MPATH_IS_MAYBE_VALID is used to indicate that this device would ++ * be a valid multipath path device if another device with the same ++ * wwid existed */ +enum mpath_valid_result { + MPATH_IS_ERROR = -1, + MPATH_IS_NOT_VALID, @@ -351,19 +380,126 @@ index 00000000..7fd8aa47 + MPATH_IS_MAYBE_VALID, +}; + -+struct config; -+extern struct config *mpathvalid_conf; -+int mpathvalid_init(int verbosity); ++enum mpath_valid_log_style { ++ MPATH_LOG_STDERR = -1, /* log to STDERR */ ++ MPATH_LOG_STDERR_TIMESTAMP, /* log to STDERR, with timestamps */ ++ MPATH_LOG_SYSLOG, /* log to system log */ ++}; ++ ++enum mpath_valid_verbosity { ++ MPATH_LOG_PRIO_NOLOG = -1, /* log nothing */ ++ MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_PRIO_WARN, ++ MPATH_LOG_PRIO_NOTICE, ++ MPATH_LOG_PRIO_INFO, ++ MPATH_LOG_PRIO_DEBUG, ++}; ++ ++/* Function declarations */ ++ ++/* ++ * DESCRIPTION: ++ * Initialize the device mapper multipath configuration. This ++ * function must be invoked before calling any other ++ * libmpathvalid functions. Call mpathvalid_exit() to cleanup. ++ * @verbosity: the logging level (mpath_valid_verbosity) ++ * @log_style: the logging style (mpath_valid_log_style) ++ * ++ * RESTRICTIONS: ++ * Calling mpathvalid_init() after calling mpathvalid_exit() has no ++ * effect. ++ * ++ * RETURNS: 0 = Success, -1 = Failure ++ */ ++int mpathvalid_init(int verbosity, int log_style); ++ ++ ++/* ++ * DESCRIPTION: ++ * Reread the multipath configuration files and reinitalize ++ * the device mapper multipath configuration. This function can ++ * be called as many times as necessary. ++ * ++ * RETURNS: 0 = Success, -1 = Failure ++ */ ++int mpathvalid_reload_config(void); ++ ++ ++/* ++ * DESCRIPTION: ++ * Release the device mapper multipath configuration. This ++ * function must be called to cleanup resoures allocated by ++ * mpathvalid_init(). After calling this function, no futher ++ * libmpathvalid functions may be called. ++ * ++ * RETURNS: 0 = Success, -1 = Failure ++ */ +int mpathvalid_exit(void); ++ ++/* ++ * DESCRIPTION: ++ * Return the configured find_multipaths claim mode, using the ++ * configuration from either mpathvalid_init() or ++ * mpathvalid_reload_config() ++ * ++ * RETURNS: ++ * MPATH_STRICT, MPATH_SMART, MPATH_GREEDY, or MPATH_MODE_ERROR ++ * ++ * MPATH_STRICT = find_multiapths (yes|on|no|off) ++ * MPATH_SMART = find_multipaths smart ++ * MPATH_GREEDY = find_multipaths greedy ++ * MPATH_MODE_ERROR = multipath configuration not initialized ++ */ +unsigned int mpathvalid_get_mode(void); ++/* ++ * DESCRIPTION: ++ * Return whether device-mapper multipath claims a path device, ++ * using the configuration read from either mpathvalid_init() or ++ * mpathvalid_reload_config(). If the device is either claimed or ++ * potentially claimed (MPATH_IS_VALID, MPATH_IS_VALID_NO_CHECK, ++ * or MPATH_IS_MAYBE_VALID) and wwid is not NULL, then *wiid will ++ * be set to point to the wwid of device. If set, *wwid must be ++ * freed by the caller. path_wwids is an obptional parameter that ++ * points to an array of wwids, that were returned from previous ++ * calls to mpathvalid_is_path(). These are wwids of existing ++ * devices that are or potentially are claimed by device-mapper ++ * multipath. path_wwids is used with the MPATH_SMART claim mode, ++ * to claim devices when another device with the same wwid exists. ++ * nr_paths must either be set to the number of elements of ++ * path_wwids, or 0, if path_wwids is NULL. ++ * @name: The kernel name of the device. input argument ++ * @mode: the find_multipaths claim mode (mpath_valid_mode). input argument ++ * @wwid: address of a pointer to the path wwid, or NULL. Output argument. ++ * Set if path is/may be claimed. If set, must be freed by caller ++ * @path_wwids: Array of pointers to path wwids, or NULL. input argument ++ * @nr_paths: number of elements in path_wwids array. input argument. ++ * ++ * RETURNS: device claim result (mpath_valid_result) ++ * Also sets *wwid if wwid is not NULL, and the claim result is ++ * MPATH_IS_VALID, MPATH_IS_VALID_NO_CHECK, or ++ * MPATH_IS_MAYBE_VALID ++ */ +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 */ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 67a7379f..2e3583f5 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -264,3 +264,9 @@ LIBMULTIPATH_4.1.0 { + global: + libmp_verbosity; + } LIBMULTIPATH_4.0.0; ++ ++LIBMULTIPATH_4.2.0 { ++global: ++ dm_prereq; ++ skip_libmp_dm_init; ++} LIBMULTIPATH_4.1.0; -- 2.17.2 diff --git a/0069-RH-work-around-gcc-10-format-truncation-issue.patch b/0069-RH-work-around-gcc-10-format-truncation-issue.patch deleted file mode 100644 index c501ce9..0000000 --- a/0069-RH-work-around-gcc-10-format-truncation-issue.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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 - diff --git a/0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch b/0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch new file mode 100644 index 0000000..cd24d4e --- /dev/null +++ b/0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch @@ -0,0 +1,532 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 21 Oct 2020 16:39:24 -0500 +Subject: [PATCH] multipath-tools tests: and unit tests for libmpathvalid + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + Makefile.inc | 1 + + tests/Makefile | 5 +- + tests/mpathvalid.c | 467 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 472 insertions(+), 1 deletion(-) + create mode 100644 tests/mpathvalid.c + +diff --git a/Makefile.inc b/Makefile.inc +index e05f3a91..13587a9f 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/tests/Makefile b/tests/Makefile +index 908407ea..54da774e 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \ + LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka + + TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \ +- alias directio valid devt ++ alias directio valid devt mpathvalid + HELPERS := test-lib.o test-log.o + + .SILENT: $(TESTS:%=%.o) +@@ -31,6 +31,7 @@ endif + ifneq ($(DIO_TEST_DEV),) + directio-test_FLAGS := -DDIO_TEST_DEV=\"$(DIO_TEST_DEV)\" + endif ++mpathvalid-test_FLAGS := -I$(mpathvaliddir) + + # test-specific linker flags + # XYZ-test_TESTDEPS: test libraries containing __wrap_xyz functions +@@ -56,6 +57,8 @@ alias-test_LIBDEPS := -lpthread -ldl + valid-test_OBJDEPS := ../libmultipath/valid.o + valid-test_LIBDEPS := -ludev -lpthread -ldl + devt-test_LIBDEPS := -ludev ++mpathvalid-test_LIBDEPS := -ludev -lpthread -ldl ++mpathvalid-test_OBJDEPS := ../libmpathvalid/mpath_valid.o + ifneq ($(DIO_TEST_DEV),) + directio-test_LIBDEPS := -laio + endif +diff --git a/tests/mpathvalid.c b/tests/mpathvalid.c +new file mode 100644 +index 00000000..5ffabb9d +--- /dev/null ++++ b/tests/mpathvalid.c +@@ -0,0 +1,467 @@ ++/* ++ * Copyright (c) 2020 Benjamin Marzinski, Red Hat ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "structs.h" ++#include "config.h" ++#include "mpath_valid.h" ++#include "util.h" ++#include "debug.h" ++ ++const char *test_dev = "test_name"; ++#define TEST_WWID "WWID_123" ++#define CONF_TEMPLATE "mpathvalid-testconf-XXXXXXXX" ++char conf_name[] = CONF_TEMPLATE; ++bool initialized; ++ ++#if 0 ++static int mode_to_findmp(unsigned int mode) ++{ ++ switch (mode) { ++ case MPATH_SMART: ++ return FIND_MULTIPATHS_SMART; ++ case MPATH_GREEDY: ++ return FIND_MULTIPATHS_GREEDY; ++ case MPATH_STRICT: ++ return FIND_MULTIPATHS_STRICT; ++ } ++ fail_msg("invalid mode: %u", mode); ++ return FIND_MULTIPATHS_UNDEF; ++} ++#endif ++ ++static unsigned int findmp_to_mode(int findmp) ++{ ++ switch (findmp) { ++ case FIND_MULTIPATHS_SMART: ++ return MPATH_SMART; ++ case FIND_MULTIPATHS_GREEDY: ++ return MPATH_GREEDY; ++ case FIND_MULTIPATHS_STRICT: ++ case FIND_MULTIPATHS_OFF: ++ case FIND_MULTIPATHS_ON: ++ return MPATH_STRICT; ++ } ++ fail_msg("invalid find_multipaths value: %d", findmp); ++ return MPATH_DEFAULT; ++} ++ ++int __wrap_is_path_valid(const char *name, struct config *conf, struct path *pp, ++ bool check_multipathd) ++{ ++ int r = mock_type(int); ++ int findmp = mock_type(int); ++ ++ assert_ptr_equal(name, test_dev); ++ assert_ptr_not_equal(conf, NULL); ++ assert_ptr_not_equal(pp, NULL); ++ assert_true(check_multipathd); ++ ++ assert_int_equal(findmp, conf->find_multipaths); ++ if (r == MPATH_IS_ERROR || r == MPATH_IS_NOT_VALID) ++ return r; ++ ++ strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE); ++ return r; ++} ++ ++int __wrap_libmultipath_init(void) ++{ ++ int r = mock_type(int); ++ ++ assert_false(initialized); ++ if (r != 0) ++ return r; ++ initialized = true; ++ return 0; ++} ++ ++void __wrap_libmultipath_exit(void) ++{ ++ assert_true(initialized); ++ initialized = false; ++} ++ ++int __wrap_dm_prereq(unsigned int *v) ++{ ++ assert_ptr_not_equal(v, NULL); ++ return mock_type(int); ++} ++ ++int __real_init_config(const char *file); ++ ++int __wrap_init_config(const char *file) ++{ ++ int r = mock_type(int); ++ struct config *conf; ++ ++ assert_ptr_equal(file, DEFAULT_CONFIGFILE); ++ if (r != 0) ++ return r; ++ ++ assert_string_not_equal(conf_name, CONF_TEMPLATE); ++ r = __real_init_config(conf_name); ++ conf = get_multipath_config(); ++ assert_ptr_not_equal(conf, NULL); ++ assert_int_equal(conf->find_multipaths, mock_type(int)); ++ return 0; ++} ++ ++static const char * const find_multipaths_optvals[] = { ++ [FIND_MULTIPATHS_OFF] = "off", ++ [FIND_MULTIPATHS_ON] = "on", ++ [FIND_MULTIPATHS_STRICT] = "strict", ++ [FIND_MULTIPATHS_GREEDY] = "greedy", ++ [FIND_MULTIPATHS_SMART] = "smart", ++}; ++ ++void make_config_file(int findmp) ++{ ++ int r, fd; ++ char buf[64]; ++ ++ assert_true(findmp > FIND_MULTIPATHS_UNDEF && ++ findmp < __FIND_MULTIPATHS_LAST); ++ ++ r = snprintf(buf, sizeof(buf), "defaults {\nfind_multipaths %s\n}\n", ++ find_multipaths_optvals[findmp]); ++ assert_true(r > 0 && (long unsigned int)r < sizeof(buf)); ++ ++ memcpy(conf_name, CONF_TEMPLATE, sizeof(conf_name)); ++ fd = mkstemp(conf_name); ++ assert_true(fd >= 0); ++ assert_int_equal(safe_write(fd, buf, r), 0); ++ assert_int_equal(close(fd), 0); ++} ++ ++int setup(void **state) ++{ ++ initialized = false; ++ udev = udev_new(); ++ if (udev == NULL) ++ return -1; ++ return 0; ++} ++ ++int teardown(void **state) ++{ ++ struct config *conf; ++ conf = get_multipath_config(); ++ put_multipath_config(conf); ++ if (conf) ++ uninit_config(); ++ if (strcmp(conf_name, CONF_TEMPLATE) != 0) ++ unlink(conf_name); ++ udev_unref(udev); ++ udev = NULL; ++ return 0; ++} ++ ++static void check_config(bool valid_config) ++{ ++ struct config *conf; ++ ++ conf = get_multipath_config(); ++ put_multipath_config(conf); ++ if (valid_config) ++ assert_ptr_not_equal(conf, NULL); ++} ++ ++/* libmultipath_init fails */ ++static void test_mpathvalid_init_bad1(void **state) ++{ ++ will_return(__wrap_libmultipath_init, 1); ++ assert_int_equal(mpathvalid_init(MPATH_LOG_PRIO_DEBUG, ++ MPATH_LOG_STDERR), -1); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++/* init_config fails */ ++static void test_mpathvalid_init_bad2(void **state) ++{ ++ will_return(__wrap_libmultipath_init, 0); ++ will_return(__wrap_init_config, 1); ++ assert_int_equal(mpathvalid_init(MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR_TIMESTAMP), -1); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++/* dm_prereq fails */ ++static void test_mpathvalid_init_bad3(void **state) ++{ ++ make_config_file(FIND_MULTIPATHS_STRICT); ++ will_return(__wrap_libmultipath_init, 0); ++ will_return(__wrap_init_config, 0); ++ will_return(__wrap_init_config, FIND_MULTIPATHS_STRICT); ++ will_return(__wrap_dm_prereq, 1); ++ assert_int_equal(mpathvalid_init(MPATH_LOG_STDERR, MPATH_LOG_PRIO_ERR), ++ -1); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++static void check_mpathvalid_init(int findmp, int prio, int log_style) ++{ ++ make_config_file(findmp); ++ will_return(__wrap_libmultipath_init, 0); ++ will_return(__wrap_init_config, 0); ++ will_return(__wrap_init_config, findmp); ++ will_return(__wrap_dm_prereq, 0); ++ assert_int_equal(mpathvalid_init(prio, log_style), 0); ++ assert_true(initialized); ++ check_config(true); ++ assert_int_equal(logsink, log_style); ++ assert_int_equal(libmp_verbosity, prio); ++ assert_int_equal(findmp_to_mode(findmp), mpathvalid_get_mode()); ++} ++ ++static void check_mpathvalid_exit(void) ++{ ++ assert_int_equal(mpathvalid_exit(), 0); ++ assert_false(initialized); ++ check_config(false); ++} ++ ++static void test_mpathvalid_init_good1(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR_TIMESTAMP); ++} ++ ++static void test_mpathvalid_init_good2(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_STRICT, MPATH_LOG_PRIO_DEBUG, ++ MPATH_LOG_STDERR); ++} ++ ++static void test_mpathvalid_init_good3(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_NOLOG, ++ MPATH_LOG_SYSLOG); ++} ++ ++static void test_mpathvalid_exit(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ check_mpathvalid_exit(); ++} ++ ++/* fails if config hasn't been set */ ++static void test_mpathvalid_get_mode_bad(void **state) ++{ ++#if 1 ++ assert_int_equal(mpathvalid_get_mode(), MPATH_MODE_ERROR); ++#else ++ assert_int_equal(mpathvalid_get_mode(), 1); ++#endif ++} ++ ++/*fails if config hasn't been set */ ++static void test_mpathvalid_reload_config_bad1(void **state) ++{ ++#if 1 ++ will_return(__wrap_init_config, 1); ++#endif ++ assert_int_equal(mpathvalid_reload_config(), -1); ++ check_config(false); ++} ++ ++/* init_config fails */ ++static void test_mpathvalid_reload_config_bad2(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_init_config, 1); ++ assert_int_equal(mpathvalid_reload_config(), -1); ++ check_config(false); ++ check_mpathvalid_exit(); ++} ++ ++static void check_mpathvalid_reload_config(int findmp) ++{ ++ assert_string_not_equal(conf_name, CONF_TEMPLATE); ++ unlink(conf_name); ++ make_config_file(findmp); ++ will_return(__wrap_init_config, 0); ++ will_return(__wrap_init_config, findmp); ++ assert_int_equal(mpathvalid_reload_config(), 0); ++ check_config(true); ++ assert_int_equal(findmp_to_mode(findmp), mpathvalid_get_mode()); ++} ++ ++static void test_mpathvalid_reload_config_good(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_ON); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_GREEDY); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_SMART); ++ check_mpathvalid_reload_config(FIND_MULTIPATHS_STRICT); ++ check_mpathvalid_exit(); ++} ++ ++/* NULL name */ ++static void test_mpathvalid_is_path_bad1(void **state) ++{ ++ assert_int_equal(mpathvalid_is_path(NULL, MPATH_STRICT, NULL, NULL, 0), ++ MPATH_IS_ERROR); ++} ++ ++/* bad mode */ ++static void test_mpathvalid_is_path_bad2(void **state) ++{ ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_MODE_ERROR, NULL, ++ NULL, 0), MPATH_IS_ERROR); ++} ++ ++/* NULL path_wwids and non-zero nr_paths */ ++static void test_mpathvalid_is_path_bad3(void **state) ++{ ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_MODE_ERROR, NULL, ++ NULL, 1), MPATH_IS_ERROR); ++} ++ ++/*fails if config hasn't been set */ ++static void test_mpathvalid_is_path_bad4(void **state) ++{ ++#if 0 ++ will_return(__wrap_is_path_valid, MPATH_IS_ERROR); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_STRICT); ++#endif ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_STRICT, NULL, ++ NULL, 0), MPATH_IS_ERROR); ++} ++ ++/* is_path_valid fails */ ++static void test_mpathvalid_is_path_bad5(void **state) ++{ ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_ERROR); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_GREEDY); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_GREEDY, NULL, ++ NULL, 0), MPATH_IS_ERROR); ++ check_mpathvalid_exit(); ++} ++ ++static void test_mpathvalid_is_path_good1(void **state) ++{ ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_STRICT, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_NOT_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_STRICT); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ NULL, 0), MPATH_IS_NOT_VALID); ++ assert_ptr_equal(wwid, NULL); ++ check_mpathvalid_exit(); ++} ++ ++static void test_mpathvalid_is_path_good2(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_ON); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ wwids, 4), MPATH_IS_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++static void test_mpathvalid_is_path_good3(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_SMART, &wwid, ++ wwids, 4), MPATH_IS_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++/* mabybe valid with no matching paths */ ++static void test_mpathvalid_is_path_good4(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_SMART, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_MAYBE_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ wwids, 4), MPATH_IS_MAYBE_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++/* maybe valid with matching paths */ ++static void test_mpathvalid_is_path_good5(void **state) ++{ ++ const char *wwids[] = { "WWID_A", "WWID_B", TEST_WWID, "WWID_D" }; ++ char *wwid; ++ check_mpathvalid_init(FIND_MULTIPATHS_SMART, MPATH_LOG_PRIO_ERR, ++ MPATH_LOG_STDERR); ++ will_return(__wrap_is_path_valid, MPATH_IS_MAYBE_VALID); ++ will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART); ++ will_return(__wrap_is_path_valid, TEST_WWID); ++ assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, ++ wwids, 4), MPATH_IS_VALID); ++ assert_string_equal(wwid, TEST_WWID); ++} ++ ++#define setup_test(name) \ ++ cmocka_unit_test_setup_teardown(name, setup, teardown) ++ ++int test_mpathvalid(void) ++{ ++ const struct CMUnitTest tests[] = { ++ setup_test(test_mpathvalid_init_bad1), ++ setup_test(test_mpathvalid_init_bad2), ++ setup_test(test_mpathvalid_init_bad3), ++ setup_test(test_mpathvalid_init_good1), ++ setup_test(test_mpathvalid_init_good2), ++ setup_test(test_mpathvalid_init_good3), ++ setup_test(test_mpathvalid_exit), ++ setup_test(test_mpathvalid_get_mode_bad), ++ setup_test(test_mpathvalid_reload_config_bad1), ++ setup_test(test_mpathvalid_reload_config_bad2), ++ setup_test(test_mpathvalid_reload_config_good), ++ setup_test(test_mpathvalid_is_path_bad1), ++ setup_test(test_mpathvalid_is_path_bad2), ++ setup_test(test_mpathvalid_is_path_bad3), ++ setup_test(test_mpathvalid_is_path_bad4), ++ setup_test(test_mpathvalid_is_path_bad5), ++ setup_test(test_mpathvalid_is_path_good1), ++ setup_test(test_mpathvalid_is_path_good2), ++ setup_test(test_mpathvalid_is_path_good3), ++ setup_test(test_mpathvalid_is_path_good4), ++ setup_test(test_mpathvalid_is_path_good5), ++ }; ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} ++ ++int main(void) ++{ ++ int r = 0; ++ ++ r += test_mpathvalid(); ++ return r; ++} +-- +2.17.2 + diff --git a/0071-libmultipath-add-uid-failback-for-dasd-devices.patch b/0070-libmultipath-add-uid-failback-for-dasd-devices.patch similarity index 90% rename from 0071-libmultipath-add-uid-failback-for-dasd-devices.patch rename to 0070-libmultipath-add-uid-failback-for-dasd-devices.patch index 2515095..c052217 100644 --- a/0071-libmultipath-add-uid-failback-for-dasd-devices.patch +++ b/0070-libmultipath-add-uid-failback-for-dasd-devices.patch @@ -1,11 +1,12 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski -Date: Tue, 19 May 2020 15:55:15 -0500 +Date: Wed, 21 Oct 2020 16:39:25 -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 +Reviewed-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- libmultipath/defaults.h | 1 + @@ -13,7 +14,7 @@ Signed-off-by: Benjamin Marzinski 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h -index 984d8dd8..6a678a83 100644 +index 39a5e415..947ba467 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h @@ -8,6 +8,7 @@ @@ -25,10 +26,10 @@ index 984d8dd8..6a678a83 100644 #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 +index e7084664..877e8f2b 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c -@@ -1920,12 +1920,44 @@ get_vpd_uid(struct path * pp) +@@ -1959,12 +1959,44 @@ get_vpd_uid(struct path * pp) return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE); } @@ -74,7 +75,7 @@ index aa5942c3..002d3d18 100644 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) +@@ -2012,6 +2044,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) || diff --git a/0086-libmultipath-change-log-level-for-null-uid_attribute.patch b/0071-libmultipath-change-log-level-for-null-uid_attribute.patch similarity index 50% rename from 0086-libmultipath-change-log-level-for-null-uid_attribute.patch rename to 0071-libmultipath-change-log-level-for-null-uid_attribute.patch index 8567bc3..3fa6b93 100644 --- a/0086-libmultipath-change-log-level-for-null-uid_attribute.patch +++ b/0071-libmultipath-change-log-level-for-null-uid_attribute.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski -Date: Tue, 22 Sep 2020 16:03:31 -0500 +Date: Wed, 21 Oct 2020 16:39:26 -0500 Subject: [PATCH] libmultipath: change log level for null uid_attribute If uid_attribute is explicitly set to an empty string, multipath should @@ -8,20 +8,34 @@ log the uid at the default log level, since using the fallback code is the expected behavior. Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck --- - libmultipath/discovery.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) + libmultipath/discovery.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index 002d3d18..77468524 100644 +index 877e8f2b..c74f13bf 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, +@@ -2086,8 +2086,11 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev, + len = strlen(pp->wwid); + origin = "callout"; + } else { +- bool udev_available = udev && pp->uid_attribute ++ bool valid_uid_attr = pp->uid_attribute + && *pp->uid_attribute; ++ bool empty_uid_attr = pp->uid_attribute ++ && !*pp->uid_attribute; ++ bool udev_available = udev && valid_uid_attr; + + if (udev_available) { + len = get_udev_uid(pp, pp->uid_attribute, udev); +@@ -2097,7 +2100,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)) ++ if (!udev || !empty_uid_attr) + used_fallback = 1; len = uid_fallback(pp, path_state, &origin); } diff --git a/0072-libmultipath-add-ignore_udev_uid-option.patch b/0072-libmultipath-add-ignore_udev_uid-option.patch deleted file mode 100644 index d9cf8a7..0000000 --- a/0072-libmultipath-add-ignore_udev_uid-option.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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\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 - diff --git a/0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch b/0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch new file mode 100644 index 0000000..8346fa2 --- /dev/null +++ b/0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:50:59 -0600 +Subject: [PATCH] libmultipath: move fast_io_fail defines to structs.h + +Since fast_io_fail is part of the multipath struct, its symbolic values +belong in structs.h. Also, make it an instance of a general enum, which +will be used again in future patches, and change the set/print functions +which use it to use the general enum instead. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/config.h | 8 -------- + libmultipath/dict.c | 30 +++++++++++++++--------------- + libmultipath/dict.h | 2 +- + libmultipath/propsel.c | 2 +- + libmultipath/structs.h | 17 +++++++++++++++++ + 5 files changed, 34 insertions(+), 25 deletions(-) + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 5d460359..661dd586 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -10,14 +10,6 @@ + #define ORIGIN_DEFAULT 0 + #define ORIGIN_CONFIG 1 + +-/* +- * In kernel, fast_io_fail == 0 means immediate failure on rport delete. +- * OTOH '0' means not-configured in various places in multipath-tools. +- */ +-#define MP_FAST_IO_FAIL_UNSET (0) +-#define MP_FAST_IO_FAIL_OFF (-1) +-#define MP_FAST_IO_FAIL_ZERO (-2) +- + enum devtypes { + DEV_NONE, + DEV_DEVT, +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index f12c2e5c..f4357da1 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -822,7 +822,7 @@ declare_mp_attr_handler(gid, set_gid) + declare_mp_attr_snprint(gid, print_gid) + + static int +-set_fast_io_fail(vector strvec, void *ptr) ++set_undef_off_zero(vector strvec, void *ptr) + { + char * buff; + int *int_ptr = (int *)ptr; +@@ -832,36 +832,36 @@ set_fast_io_fail(vector strvec, void *ptr) + return 1; + + if (strcmp(buff, "off") == 0) +- *int_ptr = MP_FAST_IO_FAIL_OFF; ++ *int_ptr = UOZ_OFF; + else if (sscanf(buff, "%d", int_ptr) != 1 || +- *int_ptr < MP_FAST_IO_FAIL_ZERO) +- *int_ptr = MP_FAST_IO_FAIL_UNSET; ++ *int_ptr < UOZ_ZERO) ++ *int_ptr = UOZ_UNDEF; + else if (*int_ptr == 0) +- *int_ptr = MP_FAST_IO_FAIL_ZERO; ++ *int_ptr = UOZ_ZERO; + + FREE(buff); + return 0; + } + + int +-print_fast_io_fail(char * buff, int len, long v) ++print_undef_off_zero(char * buff, int len, long v) + { +- if (v == MP_FAST_IO_FAIL_UNSET) ++ if (v == UOZ_UNDEF) + return 0; +- if (v == MP_FAST_IO_FAIL_OFF) ++ if (v == UOZ_OFF) + return snprintf(buff, len, "\"off\""); +- if (v == MP_FAST_IO_FAIL_ZERO) ++ if (v == UOZ_ZERO) + return snprintf(buff, len, "0"); + return snprintf(buff, len, "%ld", v); + } + +-declare_def_handler(fast_io_fail, set_fast_io_fail) +-declare_def_snprint_defint(fast_io_fail, print_fast_io_fail, ++declare_def_handler(fast_io_fail, set_undef_off_zero) ++declare_def_snprint_defint(fast_io_fail, print_undef_off_zero, + DEFAULT_FAST_IO_FAIL) +-declare_ovr_handler(fast_io_fail, set_fast_io_fail) +-declare_ovr_snprint(fast_io_fail, print_fast_io_fail) +-declare_hw_handler(fast_io_fail, set_fast_io_fail) +-declare_hw_snprint(fast_io_fail, print_fast_io_fail) ++declare_ovr_handler(fast_io_fail, set_undef_off_zero) ++declare_ovr_snprint(fast_io_fail, print_undef_off_zero) ++declare_hw_handler(fast_io_fail, set_undef_off_zero) ++declare_hw_snprint(fast_io_fail, print_undef_off_zero) + + static int + set_dev_loss(vector strvec, void *ptr) +diff --git a/libmultipath/dict.h b/libmultipath/dict.h +index a40ac66f..a917e1ca 100644 +--- a/libmultipath/dict.h ++++ b/libmultipath/dict.h +@@ -13,7 +13,7 @@ int print_rr_weight(char *buff, int len, long v); + int print_pgfailback(char *buff, int len, long v); + int print_pgpolicy(char *buff, int len, long v); + int print_no_path_retry(char *buff, int len, long v); +-int print_fast_io_fail(char *buff, int len, long v); ++int print_undef_off_zero(char *buff, int len, long v); + int print_dev_loss(char *buff, int len, unsigned long v); + int print_reservation_key(char * buff, int len, struct be64 key, uint8_t + flags, int source); +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 3f2c2cfa..67d025cf 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -754,7 +754,7 @@ int select_fast_io_fail(struct config *conf, struct multipath *mp) + mp_set_conf(fast_io_fail); + mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL); + out: +- print_fast_io_fail(buff, 12, mp->fast_io_fail); ++ print_undef_off_zero(buff, 12, mp->fast_io_fail); + condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin); + return 0; + } +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 4ce30551..cfa7b649 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -219,6 +219,23 @@ enum vpd_vendor_ids { + VPD_VP_ARRAY_SIZE, /* This must remain the last entry */ + }; + ++/* ++ * Multipath treats 0 as undefined for optional config parameters. ++ * Use this for cases where 0 is a valid option for systems multipath ++ * is communicating with ++ */ ++enum undefined_off_zero { ++ UOZ_UNDEF = 0, ++ UOZ_OFF = -1, ++ UOZ_ZERO = -2, ++}; ++ ++enum fast_io_fail_states { ++ MP_FAST_IO_FAIL_UNSET = UOZ_UNDEF, ++ MP_FAST_IO_FAIL_OFF = UOZ_OFF, ++ MP_FAST_IO_FAIL_ZERO = UOZ_ZERO, ++}; ++ + struct vpd_vendor_page { + int pg; + const char *name; +-- +2.17.2 + diff --git a/0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch b/0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch new file mode 100644 index 0000000..f5b1d8a --- /dev/null +++ b/0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch @@ -0,0 +1,338 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:00 -0600 +Subject: [PATCH] libmultipath: add eh_deadline multipath.conf parameter + +There are times a fc rport is never lost, meaning that fast_io_fail_tmo +and dev_loss_tmo never trigger, but scsi commands still hang. This can +cause problems in cases where users have strict timing requirements, and +the easiest way to solve these issues is to set eh_deadline. Since it's +already possible to set fast_io_fail_tmo and dev_loss_tmo from +multipath.conf, and have multipath take care of setting it correctly for +the scsi devices in sysfs, it makes sense to allow users to set +eh_deadline here as well. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/config.c | 2 ++ + libmultipath/config.h | 2 ++ + libmultipath/configure.c | 1 + + libmultipath/dict.c | 10 +++++++ + libmultipath/discovery.c | 60 +++++++++++++++++++++++++++++++++----- + libmultipath/propsel.c | 17 +++++++++++ + libmultipath/propsel.h | 1 + + libmultipath/structs.h | 7 +++++ + multipath/multipath.conf.5 | 16 ++++++++++ + 9 files changed, 109 insertions(+), 7 deletions(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 49e7fb81..9f3cb38d 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -424,6 +424,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src) + merge_num(flush_on_last_del); + merge_num(fast_io_fail); + merge_num(dev_loss); ++ merge_num(eh_deadline); + merge_num(user_friendly_names); + merge_num(retain_hwhandler); + merge_num(detect_prio); +@@ -579,6 +580,7 @@ store_hwe (vector hwtable, struct hwentry * dhwe) + hwe->flush_on_last_del = dhwe->flush_on_last_del; + hwe->fast_io_fail = dhwe->fast_io_fail; + hwe->dev_loss = dhwe->dev_loss; ++ hwe->eh_deadline = dhwe->eh_deadline; + hwe->user_friendly_names = dhwe->user_friendly_names; + hwe->retain_hwhandler = dhwe->retain_hwhandler; + hwe->detect_prio = dhwe->detect_prio; +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 661dd586..9ce37f16 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -63,6 +63,7 @@ struct hwentry { + int flush_on_last_del; + int fast_io_fail; + unsigned int dev_loss; ++ int eh_deadline; + int user_friendly_names; + int retain_hwhandler; + int detect_prio; +@@ -148,6 +149,7 @@ struct config { + int attribute_flags; + int fast_io_fail; + unsigned int dev_loss; ++ int eh_deadline; + int log_checker_err; + int allow_queueing; + int allow_usb_devices; +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 20536e60..c076be72 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -368,6 +368,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + select_gid(conf, mpp); + select_fast_io_fail(conf, mpp); + select_dev_loss(conf, mpp); ++ select_eh_deadline(conf, mpp); + select_reservation_key(conf, mpp); + select_deferred_remove(conf, mpp); + select_marginal_path_err_sample_time(conf, mpp); +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index f4357da1..bab96146 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -899,6 +899,13 @@ declare_ovr_snprint(dev_loss, print_dev_loss) + declare_hw_handler(dev_loss, set_dev_loss) + declare_hw_snprint(dev_loss, print_dev_loss) + ++declare_def_handler(eh_deadline, set_undef_off_zero) ++declare_def_snprint(eh_deadline, print_undef_off_zero) ++declare_ovr_handler(eh_deadline, set_undef_off_zero) ++declare_ovr_snprint(eh_deadline, print_undef_off_zero) ++declare_hw_handler(eh_deadline, set_undef_off_zero) ++declare_hw_snprint(eh_deadline, print_undef_off_zero) ++ + static int + set_pgpolicy(vector strvec, void *ptr) + { +@@ -1771,6 +1778,7 @@ init_keywords(vector keywords) + install_keyword("gid", &def_gid_handler, &snprint_def_gid); + install_keyword("fast_io_fail_tmo", &def_fast_io_fail_handler, &snprint_def_fast_io_fail); + install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss); ++ install_keyword("eh_deadline", &def_eh_deadline_handler, &snprint_def_eh_deadline); + install_keyword("bindings_file", &def_bindings_file_handler, &snprint_def_bindings_file); + install_keyword("wwids_file", &def_wwids_file_handler, &snprint_def_wwids_file); + install_keyword("prkeys_file", &def_prkeys_file_handler, &snprint_def_prkeys_file); +@@ -1880,6 +1888,7 @@ init_keywords(vector keywords) + install_keyword("flush_on_last_del", &hw_flush_on_last_del_handler, &snprint_hw_flush_on_last_del); + install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_handler, &snprint_hw_fast_io_fail); + install_keyword("dev_loss_tmo", &hw_dev_loss_handler, &snprint_hw_dev_loss); ++ install_keyword("eh_deadline", &hw_eh_deadline_handler, &snprint_hw_eh_deadline); + install_keyword("user_friendly_names", &hw_user_friendly_names_handler, &snprint_hw_user_friendly_names); + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler); + install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_hw_detect_prio); +@@ -1920,6 +1929,7 @@ init_keywords(vector keywords) + install_keyword("flush_on_last_del", &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del); + install_keyword("fast_io_fail_tmo", &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail); + install_keyword("dev_loss_tmo", &ovr_dev_loss_handler, &snprint_ovr_dev_loss); ++ install_keyword("eh_deadline", &ovr_eh_deadline_handler, &snprint_ovr_eh_deadline); + install_keyword("user_friendly_names", &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names); + install_keyword("retain_attached_hw_handler", &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler); + install_keyword("detect_prio", &ovr_detect_prio_handler, &snprint_ovr_detect_prio); +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index c74f13bf..add7bb97 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -587,6 +587,42 @@ sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen) + return !!preferred; + } + ++static int ++sysfs_set_eh_deadline(struct multipath *mpp, struct path *pp) ++{ ++ struct udev_device *hostdev; ++ char host_name[HOST_NAME_LEN], value[16]; ++ int ret, len; ++ ++ if (mpp->eh_deadline == EH_DEADLINE_UNSET) ++ return 0; ++ ++ sprintf(host_name, "host%d", pp->sg_id.host_no); ++ hostdev = udev_device_new_from_subsystem_sysname(udev, ++ "scsi_host", host_name); ++ if (!hostdev) ++ return 1; ++ ++ if (mpp->eh_deadline == EH_DEADLINE_OFF) ++ len = sprintf(value, "off"); ++ else if (mpp->eh_deadline == EH_DEADLINE_ZERO) ++ len = sprintf(value, "0"); ++ else ++ len = sprintf(value, "%d", mpp->eh_deadline); ++ ++ ret = sysfs_attr_set_value(hostdev, "eh_deadline", ++ value, len + 1); ++ /* ++ * not all scsi drivers support setting eh_deadline, so failing ++ * is totally reasonable ++ */ ++ if (ret <= 0) ++ condlog(3, "%s: failed to set eh_deadline to %s, error %d", udev_device_get_sysname(hostdev), value, -ret); ++ ++ udev_device_unref(hostdev); ++ return (ret <= 0); ++} ++ + static void + sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + { +@@ -596,6 +632,10 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + unsigned int tmo; + int ret; + ++ if (mpp->dev_loss == DEV_LOSS_TMO_UNSET && ++ mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ return; ++ + sprintf(rport_id, "rport-%d:%d-%d", + pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id); + rport_dev = udev_device_new_from_subsystem_sysname(udev, +@@ -703,6 +743,11 @@ sysfs_set_session_tmo(struct multipath *mpp, struct path *pp) + char session_id[64]; + char value[11]; + ++ if (mpp->dev_loss != DEV_LOSS_TMO_UNSET) ++ condlog(3, "%s: ignoring dev_loss_tmo on iSCSI", pp->dev); ++ if (mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ return; ++ + sprintf(session_id, "session%d", pp->sg_id.transport_id); + session_dev = udev_device_new_from_subsystem_sysname(udev, + "iscsi_session", session_id); +@@ -714,9 +759,6 @@ sysfs_set_session_tmo(struct multipath *mpp, struct path *pp) + condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no, + pp->sg_id.channel, pp->sg_id.scsi_id, session_id); + +- if (mpp->dev_loss != DEV_LOSS_TMO_UNSET) { +- condlog(3, "%s: ignoring dev_loss_tmo on iSCSI", pp->dev); +- } + if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) { + if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) { + condlog(3, "%s: can't switch off fast_io_fail_tmo " +@@ -744,6 +786,8 @@ sysfs_set_nexus_loss_tmo(struct multipath *mpp, struct path *pp) + char end_dev_id[64]; + char value[11]; + ++ if (mpp->dev_loss == DEV_LOSS_TMO_UNSET) ++ return; + sprintf(end_dev_id, "end_device-%d:%d", + pp->sg_id.host_no, pp->sg_id.transport_id); + sas_dev = udev_device_new_from_subsystem_sysname(udev, +@@ -801,7 +845,8 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint) + mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF; + } + if (mpp->dev_loss == DEV_LOSS_TMO_UNSET && +- mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET) ++ mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET && ++ mpp->eh_deadline == EH_DEADLINE_UNSET) + return 0; + + vector_foreach_slot(mpp->paths, pp, i) { +@@ -814,17 +859,18 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint) + switch (pp->sg_id.proto_id) { + case SCSI_PROTOCOL_FCP: + sysfs_set_rport_tmo(mpp, pp); +- continue; ++ break; + case SCSI_PROTOCOL_ISCSI: + sysfs_set_session_tmo(mpp, pp); +- continue; ++ break; + case SCSI_PROTOCOL_SAS: + sysfs_set_nexus_loss_tmo(mpp, pp); +- continue; ++ break; + default: + if (!err_path) + err_path = pp; + } ++ sysfs_set_eh_deadline(mpp, pp); + } + + if (err_path) { +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 67d025cf..fa4ac5d9 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -775,6 +775,23 @@ out: + return 0; + } + ++int select_eh_deadline(struct config *conf, struct multipath *mp) ++{ ++ const char *origin; ++ char buff[12]; ++ ++ mp_set_ovr(eh_deadline); ++ mp_set_hwe(eh_deadline); ++ mp_set_conf(eh_deadline); ++ mp->eh_deadline = EH_DEADLINE_UNSET; ++ /* not changing sysfs in default cause, so don't print anything */ ++ return 0; ++out: ++ print_undef_off_zero(buff, 12, mp->eh_deadline); ++ condlog(3, "%s: eh_deadline = %s %s", mp->alias, buff, origin); ++ return 0; ++} ++ + int select_flush_on_last_del(struct config *conf, struct multipath *mp) + { + const char *origin; +diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h +index 3d6edd8a..a68bacf0 100644 +--- a/libmultipath/propsel.h ++++ b/libmultipath/propsel.h +@@ -17,6 +17,7 @@ int select_uid(struct config *conf, struct multipath *mp); + int select_gid(struct config *conf, struct multipath *mp); + int select_fast_io_fail(struct config *conf, struct multipath *mp); + int select_dev_loss(struct config *conf, struct multipath *mp); ++int select_eh_deadline(struct config *conf, struct multipath *mp); + int select_reservation_key(struct config *conf, struct multipath *mp); + int select_retain_hwhandler (struct config *conf, struct multipath * mp); + int select_detect_prio(struct config *conf, struct path * pp); +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index cfa7b649..d6ff6762 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -236,6 +236,12 @@ enum fast_io_fail_states { + MP_FAST_IO_FAIL_ZERO = UOZ_ZERO, + }; + ++enum eh_deadline_states { ++ EH_DEADLINE_UNSET = UOZ_UNDEF, ++ EH_DEADLINE_OFF = UOZ_OFF, ++ EH_DEADLINE_ZERO = UOZ_ZERO, ++}; ++ + struct vpd_vendor_page { + int pg; + const char *name; +@@ -356,6 +362,7 @@ struct multipath { + int ghost_delay; + int ghost_delay_tick; + unsigned int dev_loss; ++ int eh_deadline; + uid_t uid; + gid_t gid; + mode_t mode; +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index 7242d39b..ea66a01e 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -717,6 +717,22 @@ The default is: \fB600\fR + . + . + .TP ++.B eh_deadline ++Specify the maximum number of seconds the SCSI layer will spend doing error ++handling when scsi devices fail. After this timeout the scsi layer will perform ++a full HBA reset. Setting this may be necessary in cases where the rport is ++never lost, so \fIfast_io_fail_tmo\fR and \fIdev_loss_tmo\fR will never ++trigger, but (frequently do to load) scsi commands still hang. \fBNote:\fR when ++the scsi error handler performs the HBA reset, all target paths on that HBA ++will be affected. eh_deadline should only be set in cases where all targets on ++the affected HBAs are multipathed. ++.RS ++.TP ++The default is: \fB\fR ++.RE ++. ++. ++.TP + .B bindings_file + The full pathname of the binding file to be used when the user_friendly_names + option is set. +-- +2.17.2 + diff --git a/0073-libmultipath-util-constify-function-arguments.patch b/0073-libmultipath-util-constify-function-arguments.patch deleted file mode 100644 index d1a0763..0000000 --- a/0073-libmultipath-util-constify-function-arguments.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0074-multipathd-remove-redundant-vector_free-int-configur.patch b/0074-multipathd-remove-redundant-vector_free-int-configur.patch new file mode 100644 index 0000000..c9947f5 --- /dev/null +++ b/0074-multipathd-remove-redundant-vector_free-int-configur.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:01 -0600 +Subject: [PATCH] multipathd: remove redundant vector_free() int configure + +remove_maps(vecs) already calls vector_free(vecs->mpvec) + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + multipathd/main.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index b6a5f5b7..2eab4854 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2634,14 +2634,10 @@ configure (struct vectors * vecs) + } + + /* +- * purge dm of old maps ++ * purge dm of old maps and save new set of maps formed by ++ * considering current path state + */ + remove_maps(vecs); +- +- /* +- * save new set of maps formed by considering current path state +- */ +- vector_free(vecs->mpvec); + vecs->mpvec = mpvec; + + /* +-- +2.17.2 + diff --git a/0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch b/0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch new file mode 100644 index 0000000..fe2ea50 --- /dev/null +++ b/0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:02 -0600 +Subject: [PATCH] libmultipath: factor out code to get vpd page data + +A future patch will reuse the code to get the vpd page data, so factor +it out from get_vpd_sgio(). + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/discovery.c | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index add7bb97..f901e9ff 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1321,14 +1321,13 @@ get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen) + return len; + } + +-int +-get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) ++static int ++fetch_vpd_page(int fd, int pg, unsigned char *buff, int maxlen) + { +- int len, buff_len; +- unsigned char buff[4096]; ++ int buff_len; + +- memset(buff, 0x0, 4096); +- if (sgio_get_vpd(buff, 4096, fd, pg) < 0) { ++ memset(buff, 0x0, maxlen); ++ if (sgio_get_vpd(buff, maxlen, fd, pg) < 0) { + int lvl = pg == 0x80 || pg == 0x83 ? 3 : 4; + + condlog(lvl, "failed to issue vpd inquiry for pg%02x", +@@ -1342,10 +1341,22 @@ get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) + return -ENODATA; + } + buff_len = get_unaligned_be16(&buff[2]) + 4; +- if (buff_len > 4096) { ++ if (buff_len > maxlen) { + condlog(3, "vpd pg%02x page truncated", pg); +- buff_len = 4096; ++ buff_len = maxlen; + } ++ return buff_len; ++} ++ ++int ++get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) ++{ ++ int len, buff_len; ++ unsigned char buff[4096]; ++ ++ buff_len = fetch_vpd_page(fd, pg, buff, sizeof(buff)); ++ if (buff_len < 0) ++ return buff_len; + if (pg == 0x80) + len = parse_vpd_pg80(buff, str, maxlen); + else if (pg == 0x83) +-- +2.17.2 + diff --git a/0076-libmultipath-limit-reading-0xc9-vpd-page.patch b/0076-libmultipath-limit-reading-0xc9-vpd-page.patch new file mode 100644 index 0000000..6208fe5 --- /dev/null +++ b/0076-libmultipath-limit-reading-0xc9-vpd-page.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 17 Dec 2020 16:51:03 -0600 +Subject: [PATCH] libmultipath: limit reading 0xc9 vpd page + +Only rdac arrays support 0xC9 vpd page inquiries. All other arrays will +return a failure. Only do the rdac inquiry when detecting array +capabilities if the array's path checker is explicitly set to rdac, or +the path checker is not set, and the array reports that it supports vpd +page 0xC9 in the Supported VPD Pages (0x00) vpd page. + +Multipath was doing the check if either the path checker was set to +rdac, or no path checker was set. This means that for almost all +non-rdac arrays, multipath was issuing a bad inquiry. This was annoying +users. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/discovery.c | 17 +++++++++++++++++ + libmultipath/discovery.h | 1 + + libmultipath/propsel.c | 10 ++++++---- + 3 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index f901e9ff..e818585a 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1348,6 +1348,23 @@ fetch_vpd_page(int fd, int pg, unsigned char *buff, int maxlen) + return buff_len; + } + ++/* based on sg_inq.c from sg3_utils */ ++bool ++is_vpd_page_supported(int fd, int pg) ++{ ++ int i, len; ++ unsigned char buff[4096]; ++ ++ len = fetch_vpd_page(fd, 0x00, buff, sizeof(buff)); ++ if (len < 0) ++ return false; ++ ++ for (i = 4; i < len; ++i) ++ if (buff[i] == pg) ++ return true; ++ return false; ++} ++ + int + get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen) + { +diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h +index 6444887d..d3193daf 100644 +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -56,6 +56,7 @@ int sysfs_get_asymmetric_access_state(struct path *pp, + char *buff, int buflen); + int get_uid(struct path * pp, int path_state, struct udev_device *udev, + int allow_fallback); ++bool is_vpd_page_supported(int fd, int pg); + + /* + * discovery bitmask +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index fa4ac5d9..f771a830 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -496,13 +496,15 @@ check_rdac(struct path * pp) + { + int len; + char buff[44]; +- const char *checker_name; ++ const char *checker_name = NULL; + + if (pp->bus != SYSFS_BUS_SCSI) + return 0; +- /* Avoid ioctl if this is likely not an RDAC array */ +- if (__do_set_from_hwe(checker_name, pp, checker_name) && +- strcmp(checker_name, RDAC)) ++ /* Avoid checking 0xc9 if this is likely not an RDAC array */ ++ if (!__do_set_from_hwe(checker_name, pp, checker_name) && ++ !is_vpd_page_supported(pp->fd, 0xC9)) ++ return 0; ++ if (checker_name && strcmp(checker_name, RDAC)) + return 0; + len = get_vpd_sgio(pp->fd, 0xC9, 0, buff, 44); + if (len <= 0) +-- +2.17.2 + diff --git a/0077-libmultipath-move-logq_lock-handling-to-log.c.patch b/0077-libmultipath-move-logq_lock-handling-to-log.c.patch new file mode 100644 index 0000000..ae9385f --- /dev/null +++ b/0077-libmultipath-move-logq_lock-handling-to-log.c.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 26 Oct 2020 22:01:18 +0100 +Subject: [PATCH] libmultipath: move logq_lock handling to log.c + +logq_lock protects internal data structures of log.c, and should +be handled there. This patch doesn't change functionality, except +improving cancel-safety somewhat. +Reviewed-by: Benjamin Marzinski + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log.c | 34 ++++++++++++++++++++++++++++++++-- + libmultipath/log_pthread.c | 9 --------- + 2 files changed, 32 insertions(+), 11 deletions(-) + +diff --git a/libmultipath/log.c b/libmultipath/log.c +index debd36de..7f337879 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -9,13 +9,16 @@ + #include + #include + #include ++#include + + #include "memory.h" + #include "log.h" ++#include "util.h" + + #define ALIGN(len, s) (((len)+(s)-1)/(s)*(s)) + + struct logarea* la; ++static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER; + + #if LOGDBG + static void dump_logarea (void) +@@ -101,12 +104,17 @@ void log_close (void) + + void log_reset (char *program_name) + { ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ + closelog(); + tzset(); + openlog(program_name, 0, LOG_DAEMON); ++ ++ pthread_cleanup_pop(1); + } + +-int log_enqueue (int prio, const char * fmt, va_list ap) ++static int _log_enqueue(int prio, const char * fmt, va_list ap) + { + int len, fwd; + char buff[MAX_MSG_SIZE]; +@@ -165,7 +173,18 @@ int log_enqueue (int prio, const char * fmt, va_list ap) + return 0; + } + +-int log_dequeue (void * buff) ++int log_enqueue(int prio, const char *fmt, va_list ap) ++{ ++ int ret; ++ ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ ret = _log_enqueue(prio, fmt, ap); ++ pthread_cleanup_pop(1); ++ return ret; ++} ++ ++static int _log_dequeue(void *buff) + { + struct logmsg * src = (struct logmsg *)la->head; + struct logmsg * dst = (struct logmsg *)buff; +@@ -194,6 +213,17 @@ int log_dequeue (void * buff) + return 0; + } + ++int log_dequeue(void *buff) ++{ ++ int ret; ++ ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ ret = _log_dequeue(buff); ++ pthread_cleanup_pop(1); ++ return ret; ++} ++ + /* + * this one can block under memory pressure + */ +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index 0d48c52c..65992101 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -18,7 +18,6 @@ + static pthread_t log_thr; + + /* logev_lock must not be taken with logq_lock held */ +-static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t logev_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t logev_cond = PTHREAD_COND_INITIALIZER; + +@@ -41,10 +40,7 @@ void log_safe (int prio, const char * fmt, va_list ap) + running = logq_running; + + if (running) { +- pthread_mutex_lock(&logq_lock); +- pthread_cleanup_push(cleanup_mutex, &logq_lock); + log_enqueue(prio, fmt, ap); +- pthread_cleanup_pop(1); + + log_messages_pending = 1; + pthread_cond_signal(&logev_cond); +@@ -60,9 +56,7 @@ static void flush_logqueue (void) + int empty; + + do { +- pthread_mutex_lock(&logq_lock); + empty = log_dequeue(la->buff); +- pthread_mutex_unlock(&logq_lock); + if (!empty) + log_syslog(la->buff); + } while (empty == 0); +@@ -138,10 +132,7 @@ void log_thread_start (pthread_attr_t *attr) + void log_thread_reset (void) + { + logdbg(stderr,"resetting log\n"); +- +- pthread_mutex_lock(&logq_lock); + log_reset("multipathd"); +- pthread_mutex_unlock(&logq_lock); + } + + void log_thread_stop (void) +-- +2.17.2 + diff --git a/0078-libmultipath-protect-logarea-with-logq_lock.patch b/0078-libmultipath-protect-logarea-with-logq_lock.patch new file mode 100644 index 0000000..e27aa64 --- /dev/null +++ b/0078-libmultipath-protect-logarea-with-logq_lock.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 26 Oct 2020 22:13:40 +0100 +Subject: [PATCH] libmultipath: protect logarea with logq_lock + +Make sure the global logarea (la) is only allocated and freed +hile holding logq_lock. This avoids invalid memory access. + +This patch makes free_logarea() static. libmultipath.version +is unchanged, as free_logarea() wasn't exported anyway. +Reviewed-by: Benjamin Marzinski + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log.c | 32 +++++++++++++++++++++++--------- + libmultipath/log.h | 1 - + 2 files changed, 23 insertions(+), 10 deletions(-) + +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 7f337879..95c8f01a 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -77,16 +77,23 @@ static int logarea_init (int size) + + int log_init(char *program_name, int size) + { ++ int ret = 1; ++ + logdbg(stderr,"enter log_init\n"); ++ ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ + openlog(program_name, 0, LOG_DAEMON); ++ if (!la) ++ ret = logarea_init(size); + +- if (logarea_init(size)) +- return 1; ++ pthread_cleanup_pop(1); + +- return 0; ++ return ret; + } + +-void free_logarea (void) ++static void free_logarea (void) + { + FREE(la->start); + FREE(la->buff); +@@ -96,9 +103,14 @@ void free_logarea (void) + + void log_close (void) + { +- free_logarea(); ++ pthread_mutex_lock(&logq_lock); ++ pthread_cleanup_push(cleanup_mutex, &logq_lock); ++ ++ if (la) ++ free_logarea(); + closelog(); + ++ pthread_cleanup_pop(1); + return; + } + +@@ -175,11 +187,12 @@ static int _log_enqueue(int prio, const char * fmt, va_list ap) + + int log_enqueue(int prio, const char *fmt, va_list ap) + { +- int ret; ++ int ret = 1; + + pthread_mutex_lock(&logq_lock); + pthread_cleanup_push(cleanup_mutex, &logq_lock); +- ret = _log_enqueue(prio, fmt, ap); ++ if (la) ++ ret = _log_enqueue(prio, fmt, ap); + pthread_cleanup_pop(1); + return ret; + } +@@ -215,11 +228,12 @@ static int _log_dequeue(void *buff) + + int log_dequeue(void *buff) + { +- int ret; ++ int ret = 1; + + pthread_mutex_lock(&logq_lock); + pthread_cleanup_push(cleanup_mutex, &logq_lock); +- ret = _log_dequeue(buff); ++ if (la) ++ ret = _log_dequeue(buff); + pthread_cleanup_pop(1); + return ret; + } +diff --git a/libmultipath/log.h b/libmultipath/log.h +index d2448f6a..fa224e4d 100644 +--- a/libmultipath/log.h ++++ b/libmultipath/log.h +@@ -39,6 +39,5 @@ int log_enqueue (int prio, const char * fmt, va_list ap) + int log_dequeue (void *); + void log_syslog (void *); + void dump_logmsg (void *); +-void free_logarea (void); + + #endif /* LOG_H */ +-- +2.17.2 + diff --git a/0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch b/0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch new file mode 100644 index 0000000..31fd8b4 --- /dev/null +++ b/0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch @@ -0,0 +1,284 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 5 Nov 2020 12:43:25 +0100 +Subject: [PATCH] libmultipath: prevent DSO unloading with astray checker + threads + +The multipathd tur checker thread is designed to be able to finish at +any time, even after the tur checker itself has been freed. The +multipathd shutdown code makes sure all the checkers have been freed +before freeing the checker_class and calling dlclose() to unload the +DSO, but this doesn't guarantee that the checker threads have finished. +If one hasn't, the DSO will get unloaded while the thread still running +code from it, causing a segfault. + +This patch fixes the issue by further incrementing the DSO's refcount +for every running thread. To avoid race conditions leading to segfaults, +the thread's entrypoint must be in libmultipath, not in the DSO itself. +Therefore we add a new optional checker method, libcheck_thread(). +Checkers defining this method may create a detached thread with +entrypoint checker_thread_entry(), which will call the DSO's +libcheck_thread and take care of the refcount handling. + +Reported-by: Benjamin Marzinski +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/checkers.c | 68 +++++++++++++++++++++++++++---- + libmultipath/checkers.h | 25 ++++++++++++ + libmultipath/checkers/tur.c | 12 +++--- + libmultipath/libmultipath.version | 5 +++ + 4 files changed, 97 insertions(+), 13 deletions(-) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index 18b1f5eb..2dd9915d 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -3,6 +3,8 @@ + #include + #include + #include ++#include ++#include + + #include "debug.h" + #include "checkers.h" +@@ -20,6 +22,7 @@ struct checker_class { + int (*mp_init)(struct checker *); /* to allocate the mpcontext */ + void (*free)(struct checker *); /* to free the context */ + void (*reset)(void); /* to reset the global variables */ ++ void *(*thread)(void *); /* async thread entry point */ + const char **msgtable; + short msgtable_size; + }; +@@ -55,19 +58,32 @@ static struct checker_class *alloc_checker_class(void) + c = MALLOC(sizeof(struct checker_class)); + if (c) { + INIT_LIST_HEAD(&c->node); +- c->refcount = 1; ++ uatomic_set(&c->refcount, 1); + } + return c; + } + ++/* Use uatomic_{sub,add}_return() to ensure proper memory barriers */ ++static int checker_class_ref(struct checker_class *cls) ++{ ++ return uatomic_add_return(&cls->refcount, 1); ++} ++ ++static int checker_class_unref(struct checker_class *cls) ++{ ++ return uatomic_sub_return(&cls->refcount, 1); ++} ++ + void free_checker_class(struct checker_class *c) + { ++ int cnt; ++ + if (!c) + return; +- c->refcount--; +- if (c->refcount) { +- condlog(4, "%s checker refcount %d", +- c->name, c->refcount); ++ cnt = checker_class_unref(c); ++ if (cnt != 0) { ++ condlog(cnt < 0 ? 1 : 4, "%s checker refcount %d", ++ c->name, cnt); + return; + } + condlog(3, "unloading %s checker", c->name); +@@ -161,7 +177,8 @@ static struct checker_class *add_checker_class(const char *multipath_dir, + + c->mp_init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_mp_init"); + c->reset = (void (*)(void)) dlsym(c->handle, "libcheck_reset"); +- /* These 2 functions can be NULL. call dlerror() to clear out any ++ c->thread = (void *(*)(void*)) dlsym(c->handle, "libcheck_thread"); ++ /* These 3 functions can be NULL. call dlerror() to clear out any + * error string */ + dlerror(); + +@@ -347,6 +364,43 @@ bad_id: + return generic_msg[CHECKER_MSGID_NONE]; + } + ++static void checker_cleanup_thread(void *arg) ++{ ++ struct checker_class *cls = arg; ++ ++ (void)checker_class_unref(cls); ++ rcu_unregister_thread(); ++} ++ ++static void *checker_thread_entry(void *arg) ++{ ++ struct checker_context *ctx = arg; ++ void *rv; ++ ++ rcu_register_thread(); ++ pthread_cleanup_push(checker_cleanup_thread, ctx->cls); ++ rv = ctx->cls->thread(ctx); ++ pthread_cleanup_pop(1); ++ return rv; ++} ++ ++int start_checker_thread(pthread_t *thread, const pthread_attr_t *attr, ++ struct checker_context *ctx) ++{ ++ int rv; ++ ++ assert(ctx && ctx->cls && ctx->cls->thread); ++ /* Take a ref here, lest the class be freed before the thread starts */ ++ (void)checker_class_ref(ctx->cls); ++ rv = pthread_create(thread, attr, checker_thread_entry, ctx); ++ if (rv != 0) { ++ condlog(1, "failed to start checker thread for %s: %m", ++ ctx->cls->name); ++ checker_class_unref(ctx->cls); ++ } ++ return rv; ++} ++ + void checker_clear_message (struct checker *c) + { + if (!c) +@@ -371,7 +425,7 @@ void checker_get(const char *multipath_dir, struct checker *dst, + if (!src) + return; + +- src->refcount++; ++ (void)checker_class_ref(dst->cls); + } + + int init_checkers(const char *multipath_dir) +diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h +index 9d5f90b9..2fd1d1c6 100644 +--- a/libmultipath/checkers.h ++++ b/libmultipath/checkers.h +@@ -1,6 +1,7 @@ + #ifndef _CHECKERS_H + #define _CHECKERS_H + ++#include + #include "list.h" + #include "memory.h" + #include "defaults.h" +@@ -148,6 +149,28 @@ void checker_set_async (struct checker *); + void checker_set_fd (struct checker *, int); + void checker_enable (struct checker *); + void checker_disable (struct checker *); ++/* ++ * start_checker_thread(): start async path checker thread ++ * ++ * This function provides a wrapper around pthread_create(). ++ * The created thread will call the DSO's "libcheck_thread" function with the ++ * checker context as argument. ++ * ++ * Rationale: ++ * Path checkers that do I/O may hang forever. To avoid blocking, some ++ * checkers therefore use asyncronous, detached threads for checking ++ * the paths. These threads may continue hanging if multipathd is stopped. ++ * In this case, we can't unload the checker DSO at exit. In order to ++ * avoid race conditions and crashes, the entry point of the thread ++ * needs to be in libmultipath, not in the DSO itself. ++ * ++ * @param arg: pointer to struct checker_context. ++ */ ++struct checker_context { ++ struct checker_class *cls; ++}; ++int start_checker_thread (pthread_t *thread, const pthread_attr_t *attr, ++ struct checker_context *ctx); + int checker_check (struct checker *, int); + int checker_is_sync(const struct checker *); + const char *checker_name (const struct checker *); +@@ -164,6 +187,8 @@ void checker_get(const char *, struct checker *, const char *); + int libcheck_check(struct checker *); + int libcheck_init(struct checker *); + void libcheck_free(struct checker *); ++void *libcheck_thread(struct checker_context *ctx); ++ + /* + * msgid => message map. + * +diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c +index e886fcf8..a4b4a213 100644 +--- a/libmultipath/checkers/tur.c ++++ b/libmultipath/checkers/tur.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + + #include "checkers.h" +@@ -55,6 +54,7 @@ struct tur_checker_context { + pthread_cond_t active; + int holders; /* uatomic access only */ + int msgid; ++ struct checker_context ctx; + }; + + int libcheck_init (struct checker * c) +@@ -74,6 +74,7 @@ int libcheck_init (struct checker * c) + pthread_mutex_init(&ct->lock, NULL); + if (fstat(c->fd, &sb) == 0) + ct->devt = sb.st_rdev; ++ ct->ctx.cls = c->cls; + c->context = ct; + + return 0; +@@ -204,7 +205,6 @@ static void cleanup_func(void *data) + holders = uatomic_sub_return(&ct->holders, 1); + if (!holders) + cleanup_context(ct); +- rcu_unregister_thread(); + } + + /* +@@ -251,15 +251,15 @@ static void tur_deep_sleep(const struct tur_checker_context *ct) + #define tur_deep_sleep(x) do {} while (0) + #endif /* TUR_TEST_MAJOR */ + +-static void *tur_thread(void *ctx) ++void *libcheck_thread(struct checker_context *ctx) + { +- struct tur_checker_context *ct = ctx; ++ struct tur_checker_context *ct = ++ container_of(ctx, struct tur_checker_context, ctx); + int state, running; + short msgid; + + /* This thread can be canceled, so setup clean up */ + tur_thread_cleanup_push(ct); +- rcu_register_thread(); + + condlog(4, "%d:%d : tur checker starting up", major(ct->devt), + minor(ct->devt)); +@@ -394,7 +394,7 @@ int libcheck_check(struct checker * c) + uatomic_set(&ct->running, 1); + tur_set_async_timeout(c); + setup_thread_attr(&attr, 32 * 1024, 1); +- r = pthread_create(&ct->thread, &attr, tur_thread, ct); ++ r = start_checker_thread(&ct->thread, &attr, &ct->ctx); + pthread_attr_destroy(&attr); + if (r) { + uatomic_sub(&ct->holders, 1); +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 2e3583f5..751099dc 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -270,3 +270,8 @@ global: + dm_prereq; + skip_libmp_dm_init; + } LIBMULTIPATH_4.1.0; ++ ++LIBMULTIPATH_4.3.0 { ++global: ++ start_checker_thread; ++} LIBMULTIPATH_4.2.0; +-- +2.17.2 + diff --git a/0080-libmultipath-force-map-reload-if-udev-incomplete.patch b/0080-libmultipath-force-map-reload-if-udev-incomplete.patch new file mode 100644 index 0000000..913c438 --- /dev/null +++ b/0080-libmultipath-force-map-reload-if-udev-incomplete.patch @@ -0,0 +1,151 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 14 Dec 2020 18:22:55 +0100 +Subject: [PATCH] libmultipath: force map reload if udev incomplete + +We've recently observed various cases of incompletely processed uevents +during initrd processing. Typically, this would leave a dm device in +the state it had after the initial "add" uevent, which is basically unusable, +because udevd had been killed by systemd before processing the subsequent +"change" event. After switching root, the coldplug event would re-read +the db file, which would be in unusable state, and would not do anything. +In such cases, a RELOAD action with force_udev_reload=1 is in order to +make udev re-process the device completely (DM_UDEV_PRIMARY_SOURCE_FLAG=1 and +DM_SUBSYSTEM_UDEV_FLAG0=0). + +The previous commits + +2b25a9e libmultipath: select_action(): force udev reload for uninitialized maps +cb10d38 multipathd: uev_trigger(): handle incomplete ADD events + +addressed the same issue, but incompletely. They would miss cases where the +map was configured correctly but none of the RELOAD criteria were met. +This patch partially reverts 2b25a9e by converting select_reload_action() into +a trivial helper. Instead, we now check for incompletely initialized udev now +before checking any of the other reload criteria. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 45 ++++++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 16 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index c076be72..d9fd9cb8 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -696,12 +696,11 @@ sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload) + return err; + } + +-static void +-select_reload_action(struct multipath *mpp, const struct multipath *cmpp, +- const char *reason) ++static bool is_udev_ready(struct multipath *cmpp) + { + struct udev_device *mpp_ud; + const char *env; ++ bool rc; + + /* + * MPATH_DEVICE_READY != 1 can mean two things: +@@ -713,14 +712,20 @@ select_reload_action(struct multipath *mpp, const struct multipath *cmpp, + */ + + mpp_ud = get_udev_for_mpp(cmpp); ++ if (!mpp_ud) ++ return true; + env = udev_device_get_property_value(mpp_ud, "MPATH_DEVICE_READY"); +- if ((!env || strcmp(env, "1")) && count_active_paths(mpp) > 0) +- mpp->force_udev_reload = 1; ++ rc = (env != NULL && !strcmp(env, "1")); + udev_device_unref(mpp_ud); ++ condlog(4, "%s: %s: \"%s\" -> %d\n", __func__, cmpp->alias, env, rc); ++ return rc; ++} ++ ++static void ++select_reload_action(struct multipath *mpp, const char *reason) ++{ + mpp->action = ACT_RELOAD; +- condlog(3, "%s: set ACT_RELOAD (%s%s)", mpp->alias, +- mpp->force_udev_reload ? "forced, " : "", +- reason); ++ condlog(3, "%s: set ACT_RELOAD (%s)", mpp->alias, reason); + } + + void select_action (struct multipath *mpp, const struct _vector *curmp, +@@ -789,10 +794,18 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + return; + } + ++ if (!is_udev_ready(cmpp) && count_active_paths(mpp) > 0) { ++ mpp->force_udev_reload = 1; ++ mpp->action = ACT_RELOAD; ++ condlog(3, "%s: set ACT_RELOAD (udev incomplete)", ++ mpp->alias); ++ return; ++ } ++ + if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF && + !!strstr(mpp->features, "queue_if_no_path") != + !!strstr(cmpp->features, "queue_if_no_path")) { +- select_reload_action(mpp, cmpp, "no_path_retry change"); ++ select_reload_action(mpp, "no_path_retry change"); + return; + } + if ((mpp->retain_hwhandler != RETAIN_HWHANDLER_ON || +@@ -800,7 +813,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + (strlen(cmpp->hwhandler) != strlen(mpp->hwhandler) || + strncmp(cmpp->hwhandler, mpp->hwhandler, + strlen(mpp->hwhandler)))) { +- select_reload_action(mpp, cmpp, "hwhandler change"); ++ select_reload_action(mpp, "hwhandler change"); + return; + } + +@@ -808,7 +821,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + !!strstr(mpp->features, "retain_attached_hw_handler") != + !!strstr(cmpp->features, "retain_attached_hw_handler") && + get_linux_version_code() < KERNEL_VERSION(4, 3, 0)) { +- select_reload_action(mpp, cmpp, "retain_hwhandler change"); ++ select_reload_action(mpp, "retain_hwhandler change"); + return; + } + +@@ -820,7 +833,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + remove_feature(&cmpp_feat, "queue_if_no_path"); + remove_feature(&cmpp_feat, "retain_attached_hw_handler"); + if (strncmp(mpp_feat, cmpp_feat, PARAMS_SIZE)) { +- select_reload_action(mpp, cmpp, "features change"); ++ select_reload_action(mpp, "features change"); + FREE(cmpp_feat); + FREE(mpp_feat); + return; +@@ -831,19 +844,19 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + + if (!cmpp->selector || strncmp(cmpp->selector, mpp->selector, + strlen(mpp->selector))) { +- select_reload_action(mpp, cmpp, "selector change"); ++ select_reload_action(mpp, "selector change"); + return; + } + if (cmpp->minio != mpp->minio) { +- select_reload_action(mpp, cmpp, "minio change"); ++ select_reload_action(mpp, "minio change"); + return; + } + if (!cmpp->pg || VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) { +- select_reload_action(mpp, cmpp, "path group number change"); ++ select_reload_action(mpp, "path group number change"); + return; + } + if (pgcmp(mpp, cmpp)) { +- select_reload_action(mpp, cmpp, "path group topology change"); ++ select_reload_action(mpp, "path group topology change"); + return; + } + if (cmpp->nextpg != mpp->bestpg) { +-- +2.17.2 + diff --git a/0081-multipath-tools-avoid-access-to-etc-localtime.patch b/0081-multipath-tools-avoid-access-to-etc-localtime.patch new file mode 100644 index 0000000..1e67613 --- /dev/null +++ b/0081-multipath-tools-avoid-access-to-etc-localtime.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 15 Dec 2020 17:09:49 +0100 +Subject: [PATCH] multipath-tools: avoid access to /etc/localtime + +If the root file system is multipathed, and IO is queued because all paths +are failed, multipathd may block trying to access the root FS, and thus be +unable to reinstate paths. One file that is frequently accessed is +/etc/localtime. Avoid that by printing monotonic timestamps instead. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/debug.c | 14 ++++++++------ + libmultipath/devmapper.c | 12 ++++++------ + libmultipath/log.c | 1 - + multipathd/main.c | 3 --- + 4 files changed, 14 insertions(+), 16 deletions(-) + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index 429f2699..510e15e5 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -14,6 +14,8 @@ + #include "config.h" + #include "defaults.h" + #include "debug.h" ++#include "time-util.h" ++#include "util.h" + + int logsink; + int libmp_verbosity = DEFAULT_VERBOSITY; +@@ -25,13 +27,13 @@ void dlog(int prio, const char * fmt, ...) + va_start(ap, fmt); + if (logsink != LOGSINK_SYSLOG) { + if (logsink == LOGSINK_STDERR_WITH_TIME) { +- time_t t = time(NULL); +- struct tm *tb = localtime(&t); +- char buff[16]; ++ struct timespec ts; ++ char buff[32]; + +- strftime(buff, sizeof(buff), +- "%b %d %H:%M:%S", tb); +- buff[sizeof(buff)-1] = '\0'; ++ get_monotonic_time(&ts); ++ safe_sprintf(buff, "%ld.%06ld", ++ (long)ts.tv_sec, ++ ts.tv_nsec/1000); + fprintf(stderr, "%s | ", buff); + } + vfprintf(stderr, fmt, ap); +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 4977b311..095cbc0c 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -27,6 +27,7 @@ + #include "config.h" + #include "wwids.h" + #include "version.h" ++#include "time-util.h" + + #include "log_pthread.h" + #include +@@ -106,13 +107,12 @@ dm_write_log (int level, const char *file, int line, const char *f, ...) + va_start(ap, f); + if (logsink != LOGSINK_SYSLOG) { + if (logsink == LOGSINK_STDERR_WITH_TIME) { +- time_t t = time(NULL); +- struct tm *tb = localtime(&t); +- char buff[16]; +- +- strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb); +- buff[sizeof(buff)-1] = '\0'; ++ struct timespec ts; ++ char buff[32]; + ++ get_monotonic_time(&ts); ++ safe_sprintf(buff, "%ld.%06ld", ++ (long)ts.tv_sec, ts.tv_nsec/1000); + fprintf(stderr, "%s | ", buff); + } + fprintf(stderr, "libdevmapper: %s(%i): ", file, line); +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 95c8f01a..6498c88c 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -120,7 +120,6 @@ void log_reset (char *program_name) + pthread_cleanup_push(cleanup_mutex, &logq_lock); + + closelog(); +- tzset(); + openlog(program_name, 0, LOG_DAEMON); + + pthread_cleanup_pop(1); +diff --git a/multipathd/main.c b/multipathd/main.c +index 2eab4854..4417860b 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2706,9 +2706,6 @@ reconfigure (struct vectors * vecs) + delete_all_foreign(); + + reset_checker_classes(); +- /* Re-read any timezone changes */ +- tzset(); +- + if (bindings_read_only) + conf->bindings_read_only = bindings_read_only; + check_alias_settings(conf); +-- +2.17.2 + diff --git a/0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch b/0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch new file mode 100644 index 0000000..cc3a633 --- /dev/null +++ b/0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 16 Dec 2020 23:14:59 +0100 +Subject: [PATCH] multipath-tools: make sure plugin DSOs use symbol versions + +By adding -Wl,-z,defs, we'll get warnings about unresolved symbols +at the linking stage. This way we make sure our plugins (checkers etc.) +will use versioned symbols from libmultipath, and incompatible plugins +can't be loaded any more. Doing this requires explicitly linking +the plugins with all libraries they use, in particular libmultipath. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + Makefile | 1 + + Makefile.inc | 2 +- + libmpathpersist/Makefile | 8 ++++---- + libmultipath/checkers/Makefile | 7 +++---- + libmultipath/foreign/Makefile | 4 +++- + libmultipath/prioritizers/Makefile | 7 +++---- + 6 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/Makefile b/Makefile +index f127ff91..bddb2bf7 100644 +--- a/Makefile ++++ b/Makefile +@@ -31,6 +31,7 @@ $(BUILDDIRS): + + libmultipath libdmmp: libmpathcmd + libmpathpersist libmpathvalid multipath multipathd: libmultipath ++libmultipath/prioritizers libmultipath/checkers libmultipath/foreign: libmultipath + mpathpersist multipathd: libmpathpersist + + libmultipath/checkers.install \ +diff --git a/Makefile.inc b/Makefile.inc +index 13587a9f..05429307 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -105,7 +105,7 @@ CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ + BIN_CFLAGS = -fPIE -DPIE + LIB_CFLAGS = -fPIC + SHARED_FLAGS = -shared +-LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now ++LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now -Wl,-z,defs + BIN_LDFLAGS = -pie + + # Check whether a function with name $1 has been declared in header file $2. +diff --git a/libmpathpersist/Makefile b/libmpathpersist/Makefile +index 456ce4cf..57103e58 100644 +--- a/libmpathpersist/Makefile ++++ b/libmpathpersist/Makefile +@@ -6,17 +6,17 @@ LIBS = $(DEVLIB).$(SONAME) + VERSION_SCRIPT := libmpathpersist.version + + CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) ++LDFLAGS += -L$(multipathdir) -L$(mpathcmddir) + +-LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ +- -L$(mpathcmddir) -lmpathcmd ++LIBDEPS += -lmultipath -lmpathcmd -ldevmapper -lpthread -ldl + + OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o + + all: $(DEVLIB) man + + $(LIBS): $(OBJS) $(VERSION_SCRIPT) +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ \ +- -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ \ ++ -Wl,--version-script=$(VERSION_SCRIPT) -o $@ $(OBJS) $(LIBDEPS) + + $(DEVLIB): $(LIBS) + $(LN) $(LIBS) $@ +diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile +index 01c04510..8e0ed5e9 100644 +--- a/libmultipath/checkers/Makefile ++++ b/libmultipath/checkers/Makefile +@@ -4,6 +4,8 @@ + include ../../Makefile.inc + + CFLAGS += $(LIB_CFLAGS) -I.. ++LDFLAGS += -L.. -lmultipath ++LIBDEPS = -lmultipath -laio -lpthread -lrt + + # If you add or remove a checker also update multipath/multipath.conf.5 + LIBS= \ +@@ -17,11 +19,8 @@ LIBS= \ + + all: $(LIBS) + +-libcheckdirectio.so: directio.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio +- + libcheck%.so: %.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) + + install: + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) +diff --git a/libmultipath/foreign/Makefile b/libmultipath/foreign/Makefile +index fae58a0d..f447a1c4 100644 +--- a/libmultipath/foreign/Makefile ++++ b/libmultipath/foreign/Makefile +@@ -5,13 +5,15 @@ TOPDIR=../.. + include ../../Makefile.inc + + CFLAGS += $(LIB_CFLAGS) -I.. -I$(nvmedir) ++LDFLAGS += -L.. ++LIBDEPS = -lmultipath -ludev -lpthread -lrt + + LIBS = libforeign-nvme.so + + all: $(LIBS) + + libforeign-%.so: %.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) + + install: + $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) +diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile +index fc6e0e0c..8d34ae32 100644 +--- a/libmultipath/prioritizers/Makefile ++++ b/libmultipath/prioritizers/Makefile +@@ -4,6 +4,8 @@ + include ../../Makefile.inc + + CFLAGS += $(LIB_CFLAGS) -I.. ++LDFLAGS += -L.. ++LIBDEPS = -lmultipath -lm -lpthread -lrt + + # If you add or remove a prioritizer also update multipath/multipath.conf.5 + LIBS = \ +@@ -28,11 +30,8 @@ endif + + all: $(LIBS) + +-libpriopath_latency.so: path_latency.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lm +- + libprio%.so: %.o +- $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ ++ $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ $(LIBDEPS) + + install: $(LIBS) + $(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(libdir) +-- +2.17.2 + diff --git a/0083-libmultipath.version-add-missing-symbol.patch b/0083-libmultipath.version-add-missing-symbol.patch new file mode 100644 index 0000000..55e4396 --- /dev/null +++ b/0083-libmultipath.version-add-missing-symbol.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 17 Dec 2020 01:30:30 +0100 +Subject: [PATCH] libmultipath.version: add missing symbol + +The weightedpath prioritizer uses get_next_string(). I'd overlooked +this before. This was found with the help of the previous patch. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/libmultipath.version | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 751099dc..2228f4ec 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -275,3 +275,8 @@ LIBMULTIPATH_4.3.0 { + global: + start_checker_thread; + } LIBMULTIPATH_4.2.0; ++ ++LIBMULTIPATH_4.4.0 { ++global: ++ get_next_string; ++} LIBMULTIPATH_4.3.0; +-- +2.17.2 + diff --git a/0084-libmpathvalid-use-default-_multipath_config-udev-and.patch b/0084-libmpathvalid-use-default-_multipath_config-udev-and.patch deleted file mode 100644 index 114d0f4..0000000 --- a/0084-libmpathvalid-use-default-_multipath_config-udev-and.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Sat, 26 Sep 2020 23:25:46 -0500 -Subject: [PATCH] libmpathvalid: use default *_multipath_config, udev, and - logsink - -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch b/0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch new file mode 100644 index 0000000..6be89d6 --- /dev/null +++ b/0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:11:47 +0100 +Subject: [PATCH] multipath-tools tests: unversioned .so for valgrind tests + +We need to the same thing for valgrind tests as we did in +448752f ("libmultipath: create separate .so for unit tests"). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/Makefile b/tests/Makefile +index 54da774e..50673fae 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -76,7 +76,7 @@ lib/libchecktur.so: + + %.vgr: %-test lib/libchecktur.so + @echo == running valgrind for $< == +- @LD_LIBRARY_PATH=$(multipathdir):$(mpathcmddir) \ ++ @LD_LIBRARY_PATH=.:$(mpathcmddir) \ + valgrind --leak-check=full --error-exitcode=128 ./$< >$@ 2>&1 + + OBJS = $(TESTS:%=%.o) $(HELPERS) +-- +2.17.2 + diff --git a/0085-Revert-libmultipath-add-ignore_udev_uid-option.patch b/0085-Revert-libmultipath-add-ignore_udev_uid-option.patch deleted file mode 100644 index 57ff199..0000000 --- a/0085-Revert-libmultipath-add-ignore_udev_uid-option.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -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 ---- - 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\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 - diff --git a/0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch b/0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch new file mode 100644 index 0000000..3a3bbbf --- /dev/null +++ b/0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:17:48 +0100 +Subject: [PATCH] multipath-tools unit tests: fix memory leaks in mpathvalid + tests + +They break "make valgrind-test". + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/mpathvalid.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/mpathvalid.c b/tests/mpathvalid.c +index 5ffabb9d..cfe4bae1 100644 +--- a/tests/mpathvalid.c ++++ b/tests/mpathvalid.c +@@ -381,6 +381,7 @@ static void test_mpathvalid_is_path_good2(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, + wwids, 4), MPATH_IS_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + static void test_mpathvalid_is_path_good3(void **state) +@@ -395,6 +396,7 @@ static void test_mpathvalid_is_path_good3(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_SMART, &wwid, + wwids, 4), MPATH_IS_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + /* mabybe valid with no matching paths */ +@@ -410,6 +412,7 @@ static void test_mpathvalid_is_path_good4(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, + wwids, 4), MPATH_IS_MAYBE_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + /* maybe valid with matching paths */ +@@ -425,6 +428,7 @@ static void test_mpathvalid_is_path_good5(void **state) + assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid, + wwids, 4), MPATH_IS_VALID); + assert_string_equal(wwid, TEST_WWID); ++ free(wwid); + } + + #define setup_test(name) \ +-- +2.17.2 + diff --git a/0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch b/0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch new file mode 100644 index 0000000..3e152fc --- /dev/null +++ b/0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:37 -0600 +Subject: [PATCH] mpathpersist: Fix Register and Ignore with 0x00 SARK + +When the Register and Ignore command is run with sg_persist, if a 0x00 +Service Action Reservation Key is given or the --param-sark option is +not used at all, sg_persist will clear the registration. mpathpersist +will fail with an error. This patch fixes mpathpersist to work like +sg_persist in this case. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 79322e86..41789c46 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -304,7 +304,8 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + } + + if (memcmp(paramp->key, &mpp->reservation_key, 8) && +- memcmp(paramp->sa_key, &mpp->reservation_key, 8)) { ++ memcmp(paramp->sa_key, &mpp->reservation_key, 8) && ++ (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) { + condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key)); + ret = MPATH_PR_SYNTAX_ERROR; + goto out1; +-- +2.17.2 + diff --git a/0087-libmultipath-orphan_paths-avoid-BUG-message.patch b/0087-libmultipath-orphan_paths-avoid-BUG-message.patch deleted file mode 100644 index 3dcc3a4..0000000 --- a/0087-libmultipath-orphan_paths-avoid-BUG-message.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -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 -Signed-off-by: Benjamin Marzinski ---- - 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 - diff --git a/0087-mpathpersist-update-prkeys-file-on-changing-registra.patch b/0087-mpathpersist-update-prkeys-file-on-changing-registra.patch new file mode 100644 index 0000000..79bee15 --- /dev/null +++ b/0087-mpathpersist-update-prkeys-file-on-changing-registra.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:38 -0600 +Subject: [PATCH] mpathpersist: update prkeys file on changing registrations + +When the "reservation_key" option is set to "file" and Register command +is run with both the current Reservation Key and a new Service Action +Reservation Key, mpathpersist will change the registration, but will not +update the prkeys file. This means that future paths that come online +will not be able to register, since multipathd is still using the old +reservation key. Fix this. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 41789c46..08077936 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -290,9 +290,10 @@ int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, + + memcpy(&prkey, paramp->sa_key, 8); + if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey && +- ((!get_be64(mpp->reservation_key) && +- rq_servact == MPATH_PROUT_REG_SA) || +- rq_servact == MPATH_PROUT_REG_IGN_SA)) { ++ (rq_servact == MPATH_PROUT_REG_IGN_SA || ++ (rq_servact == MPATH_PROUT_REG_SA && ++ (!get_be64(mpp->reservation_key) || ++ memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) { + memcpy(&mpp->reservation_key, paramp->sa_key, 8); + if (update_prkey_flags(alias, get_be64(mpp->reservation_key), + paramp->sa_flags)) { +-- +2.17.2 + diff --git a/0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch b/0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch new file mode 100644 index 0000000..bbb9f13 --- /dev/null +++ b/0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:39 -0600 +Subject: [PATCH] libmultipath: warn about missing braces at end of + multipath.conf + +Multipath doesn't warn when multipath.conf is missing closing braces at +the end of the file. This has confused people about the correct config +file syntax, so add a warning. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/parser.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/parser.c b/libmultipath/parser.c +index 163ffbc9..c70243c3 100644 +--- a/libmultipath/parser.c ++++ b/libmultipath/parser.c +@@ -537,7 +537,7 @@ process_stream(struct config *conf, FILE *stream, vector keywords, + if (!strcmp(str, EOB)) { + if (kw_level > 0) { + free_strvec(strvec); +- break; ++ goto out; + } + condlog(0, "unmatched '%s' at line %d of %s", + EOB, line_nr, file); +@@ -576,7 +576,8 @@ process_stream(struct config *conf, FILE *stream, vector keywords, + + free_strvec(strvec); + } +- ++ if (kw_level == 1) ++ condlog(1, "missing '%s' at end of %s", EOB, file); + out: + FREE(buf); + free_uniques(uniques); +-- +2.17.2 + diff --git a/0089-libmultipath-ignore-multipaths-sections-without-wwid.patch b/0089-libmultipath-ignore-multipaths-sections-without-wwid.patch new file mode 100644 index 0000000..25aa7ea --- /dev/null +++ b/0089-libmultipath-ignore-multipaths-sections-without-wwid.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 18 Dec 2020 17:06:40 -0600 +Subject: [PATCH] libmultipath: ignore multipaths sections without wwid option + +"multipathd show config local" was crashing in find_mp_by_wwid() if +the multipath configuration included a multipaths section that did +not set a wwid option. There is no reason to keep a mpentry that +didn't set its wwid. Remove it in merge_mptable(). + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/config.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 9f3cb38d..a643703e 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -509,6 +509,13 @@ void merge_mptable(vector mptable) + int i, j; + + vector_foreach_slot(mptable, mp1, i) { ++ /* drop invalid multipath configs */ ++ if (!mp1->wwid) { ++ condlog(0, "multipaths config section missing wwid"); ++ vector_del_slot(mptable, i--); ++ free_mpe(mp1); ++ continue; ++ } + j = i + 1; + vector_foreach_slot_after(mptable, mp2, j) { + if (strcmp(mp1->wwid, mp2->wwid)) +-- +2.17.2 + diff --git a/0090-libmultipath-fix-format-warning-with-clang.patch b/0090-libmultipath-fix-format-warning-with-clang.patch new file mode 100644 index 0000000..931e81c --- /dev/null +++ b/0090-libmultipath-fix-format-warning-with-clang.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 18 Dec 2020 23:34:35 +0100 +Subject: [PATCH] libmultipath: fix format warning with clang + +Reported-by: Xose Vazquez Perez +Tested-by: Xose Vazquez Perez +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/log.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 6498c88c..10fa32cd 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -125,6 +125,7 @@ void log_reset (char *program_name) + pthread_cleanup_pop(1); + } + ++__attribute__((format(printf, 2, 0))) + static int _log_enqueue(int prio, const char * fmt, va_list ap) + { + int len, fwd; +-- +2.17.2 + diff --git a/0091-libmultipath-check-for-null-wwid-before-strcmp.patch b/0091-libmultipath-check-for-null-wwid-before-strcmp.patch new file mode 100644 index 0000000..1f6894d --- /dev/null +++ b/0091-libmultipath-check-for-null-wwid-before-strcmp.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 4 Jan 2021 21:59:54 -0600 +Subject: [PATCH] libmultipath: check for null wwid before strcmp + +Commit 749aabd0 (libmultipath: ignore multipaths sections without wwid +option) removed all mpentries with a NULL wwid, but didn't stop strcmp() +from being run on them in merge_mptable(). The result of strcmp() with +a NULL parameter is undefined, so fix that. + +Signed-off-by: Benjamin Marzinski + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/config.c b/libmultipath/config.c +index a643703e..be310159 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -518,7 +518,7 @@ void merge_mptable(vector mptable) + } + j = i + 1; + vector_foreach_slot_after(mptable, mp2, j) { +- if (strcmp(mp1->wwid, mp2->wwid)) ++ if (!mp2->wwid || strcmp(mp1->wwid, mp2->wwid)) + continue; + condlog(1, "%s: duplicate multipath config section for %s", + __func__, mp1->wwid); +-- +2.17.2 + diff --git a/0092-multipath.conf.5-Improve-checker_timeout-description.patch b/0092-multipath.conf.5-Improve-checker_timeout-description.patch new file mode 100644 index 0000000..120c637 --- /dev/null +++ b/0092-multipath.conf.5-Improve-checker_timeout-description.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 4 Jan 2021 21:59:55 -0600 +Subject: [PATCH] multipath.conf.5: Improve checker_timeout description + +I was asked to explain how checker_timeout works for checkers like +directio, that don't issue scsi commands with an explicit timeout. +Also, undeprecate the directio checker. + +Signed-off-by: Benjamin Marzinski + +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + multipath/multipath.conf.5 | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index ea66a01e..8ef3a747 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -472,8 +472,12 @@ The default is: \fB\fR + . + .TP + .B path_checker +-The default method used to determine the paths state. Possible values +-are: ++The default method used to determine the path's state. The synchronous ++checkers (all except \fItur\fR and \fIdirectio\fR) will cause multipathd to ++pause most activity, waiting up to \fIchecker_timeout\fR seconds for the path ++to respond. The asynchronous checkers (\fItur\fR and \fIdirectio\fR) will not ++pause multipathd. Instead, multipathd will check for a response once per ++second, until \fIchecker_timeout\fR seconds have elapsed. Possible values are: + .RS + .TP 12 + .I readsector0 +@@ -499,10 +503,8 @@ Check the path state for LSI/Engenio/NetApp RDAC class as NetApp SANtricity E/EF + Series, and OEM arrays from IBM DELL SGI STK and SUN. + .TP + .I directio +-(Deprecated) Read the first sector with direct I/O. If you have a large number +-of paths, or many AIO users on a system, you may need to use sysctl to +-increase fs.aio-max-nr. This checker is being deprecated, it could cause +-spurious path failures under high load. Please use \fItur\fR instead. ++Read the first sector with direct I/O. This checker could cause spurious path ++failures under high load. Increasing \fIchecker_timeout\fR can help with this. + .TP + .I cciss_tur + (Hardware-dependent) +@@ -639,8 +641,10 @@ The default is: \fBno\fR + . + .TP + .B checker_timeout +-Specify the timeout to use for path checkers and prioritizers that issue SCSI +-commands with an explicit timeout, in seconds. ++Specify the timeout to use for path checkers and prioritizers, in seconds. ++Only prioritizers that issue scsi commands use checker_timeout. If a path ++does not respond to the checker command after \fIchecker_timeout\fR ++seconds have elapsed, it is considered down. + .RS + .TP + The default is: in \fB/sys/block/sd/device/timeout\fR +-- +2.17.2 + diff --git a/0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch b/0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch new file mode 100644 index 0000000..868fa18 --- /dev/null +++ b/0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chongyun Wu +Date: Wed, 6 Jan 2021 09:39:12 +0800 +Subject: [PATCH] multipathd: fix path checkint not changed when path state + changed from delay to failed + +Check_path: when path state change back to failed from delay state, +should change this path's check interval time to the shortest delay +to faster path state check. + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Chongyun Wu +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 4417860b..7612430a 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2161,6 +2161,11 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + (pp->state == PATH_DELAYED)) { + /* If path state become failed again cancel path delay state */ + pp->state = newstate; ++ /* ++ * path state bad again should change the check interval time ++ * to the shortest delay ++ */ ++ pp->checkint = checkint; + return 1; + } + if (!pp->mpp) { +-- +2.17.2 + diff --git a/0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch b/0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch new file mode 100644 index 0000000..e37e4da --- /dev/null +++ b/0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Jan 2021 17:22:09 +0100 +Subject: [PATCH] libmultipath: select_action(): skip is_mpp_known_to_udev() + test + +This test is now superseded by the check introduced in +0d66e03 ("libmultipath: force map reload if udev incomplete"). + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 15 --------------- + 1 file changed, 15 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index d9fd9cb8..999f3106 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -635,15 +635,6 @@ trigger_paths_udev_change(struct multipath *mpp, bool is_mpath) + mpp->needs_paths_uevent = 0; + } + +-static int +-is_mpp_known_to_udev(const struct multipath *mpp) +-{ +- struct udev_device *udd = get_udev_for_mpp(mpp); +- int ret = (udd != NULL); +- udev_device_unref(udd); +- return ret; +-} +- + static int + sysfs_set_max_sectors_kb(struct multipath *mpp, int is_reload) + { +@@ -865,12 +856,6 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, + mpp->alias); + return; + } +- if (!is_mpp_known_to_udev(cmpp)) { +- mpp->action = ACT_RELOAD; +- condlog(3, "%s: set ACT_RELOAD (udev device not initialized)", +- mpp->alias); +- return; +- } + mpp->action = ACT_NOTHING; + condlog(3, "%s: set ACT_NOTHING (map unchanged)", + mpp->alias); +-- +2.17.2 + diff --git a/0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch b/0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch new file mode 100644 index 0000000..033525b --- /dev/null +++ b/0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Jan 2021 17:36:40 +0100 +Subject: [PATCH] libmultipath: coalesce_paths(): stop triggering spurious + uevents + +Since 0d66e03 ("libmultipath: force map reload if udev incomplete"), we +force-reload maps that we find incompletely initialized by udev. If +select_action returns ACT_NOTHING nonetheless, the map must be initialized +in udev, and thus and "add" uevent must have been seen already. Triggering +this event once more is unlikely to fix anything for real. + +Reverts: b516118 ("libmultipath: coalesce_paths: trigger uevent if nothing done") + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 999f3106..3263bb01 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -527,18 +527,6 @@ get_udev_for_mpp(const struct multipath *mpp) + return udd; + } + +-static void +-trigger_udev_change(const struct multipath *mpp) +-{ +- static const char change[] = "change"; +- struct udev_device *udd = get_udev_for_mpp(mpp); +- if (!udd) +- return; +- condlog(3, "triggering %s uevent for %s", change, mpp->alias); +- sysfs_attr_set_value(udd, "uevent", change, sizeof(change)-1); +- udev_device_unref(udd); +-} +- + static void trigger_partitions_udev_change(struct udev_device *dev, + const char *action, int len) + { +@@ -1297,18 +1285,6 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + continue; + } + +- if (r == DOMAP_EXIST && mpp->action == ACT_NOTHING && +- force_reload == FORCE_RELOAD_WEAK) +- /* +- * First time we're called, and no changes applied. +- * domap() was a noop. But we can't be sure that +- * udev has already finished setting up this device +- * (udev in initrd may have been shut down while +- * processing this device or its children). +- * Trigger a change event, just in case. +- */ +- trigger_udev_change(find_mp_by_wwid(curmp, mpp->wwid)); +- + conf = get_multipath_config(); + allow_queueing = conf->allow_queueing; + put_multipath_config(conf); +-- +2.17.2 + diff --git a/0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch b/0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch new file mode 100644 index 0000000..79912f0 --- /dev/null +++ b/0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Jan 2021 17:27:10 +0100 +Subject: [PATCH] Revert "multipathd: uev_trigger(): handle incomplete ADD + events" + +cb10d38 ("multipathd: uev_trigger(): handle incomplete ADD events") was an +attempt to fix issues with incompletely initialized multipath maps observed +in various scenarious. However, that patch was wrong. Spurious "change" events +as this patch would generate have no effect, because they are ignored by +the device-mapper udev rules. The correct fix for the problem we were +facing is 0d66e03 ("libmultipath: force map reload if udev incomplete"), +which forces a full map reload. + +Reverts: cb10d38 ("multipathd: uev_trigger(): handle incomplete ADD events") + +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 25 ------------------------- + 1 file changed, 25 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 7612430a..92c45d44 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1499,31 +1499,6 @@ uev_trigger (struct uevent * uev, void * trigger_data) + uev_pathfail_check(uev, vecs); + } else if (!strncmp(uev->action, "remove", 6)) { + r = uev_remove_map(uev, vecs); +- } else if (!strncmp(uev->action, "add", 3)) { +- const char *ev_name; +- char *dm_name; +- int major = -1, minor = -1; +- +- /* +- * If DM_NAME is not set for a valid map, trigger a +- * change event. This can happen during coldplug +- * if udev was killed between handling the 'add' and +- * 'change' events before. +- */ +- ev_name = uevent_get_dm_name(uev); +- if (!ev_name) { +- major = uevent_get_major(uev); +- minor = uevent_get_minor(uev); +- dm_name = dm_mapname(major, minor); +- if (dm_name && *dm_name) { +- condlog(2, "%s: received incomplete 'add' uevent, triggering change", +- dm_name); +- udev_device_set_sysattr_value(uev->udev, +- "uevent", +- "change"); +- free(dm_name); +- } +- } + } + goto out; + } +-- +2.17.2 + diff --git a/0097-libmultipath-make-find_err_path_by_dev-static.patch b/0097-libmultipath-make-find_err_path_by_dev-static.patch new file mode 100644 index 0000000..a19afc4 --- /dev/null +++ b/0097-libmultipath-make-find_err_path_by_dev-static.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:22 -0600 +Subject: [PATCH] libmultipath: make find_err_path_by_dev() static + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 5363049d..2e48ee81 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -88,7 +88,7 @@ static void rcu_unregister(__attribute__((unused)) void *param) + rcu_unregister_thread(); + } + +-struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev) ++static struct io_err_stat_path *find_err_path_by_dev(vector pathvec, char *dev) + { + int i; + struct io_err_stat_path *pp; +-- +2.17.2 + diff --git a/0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch b/0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch new file mode 100644 index 0000000..4c21465 --- /dev/null +++ b/0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch @@ -0,0 +1,257 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:23 -0600 +Subject: [PATCH] multipathd: avoid io_err_stat crash during shutdown + +The checker thread is reponsible for enqueueing paths for the +io_err_stat thread to check. During shutdown, the io_err_stat thread is +shut down and cleaned up before the checker thread. There is no code +to make sure that the checker thread isn't accessing the io_err_stat +pathvec or its mutex while they are being freed, which can lead to +memory corruption crashes. + +To solve this, get rid of the io_err_stat_pathvec structure, and +statically define the mutex. This means that the mutex is always valid +to access, and the io_err_stat pathvec can only be accessed while +holding it. If the io_err_stat thread has already been cleaned up +when the checker tries to access the pathvec, it will be NULL, and the +checker will simply fail to enqueue the path. + +This change also fixes a bug in free_io_err_pathvec(), which previously +only attempted to free the pathvec if it was not set, instead of when it +was set. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 111 ++++++++++++++----------------------- + 1 file changed, 43 insertions(+), 68 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 2e48ee81..feb66469 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -46,12 +46,6 @@ + #define io_err_stat_log(prio, fmt, args...) \ + condlog(prio, "io error statistic: " fmt, ##args) + +- +-struct io_err_stat_pathvec { +- pthread_mutex_t mutex; +- vector pathvec; +-}; +- + struct dio_ctx { + struct timespec io_starttime; + unsigned int blksize; +@@ -75,9 +69,10 @@ static pthread_t io_err_stat_thr; + + static pthread_mutex_t io_err_thread_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t io_err_thread_cond = PTHREAD_COND_INITIALIZER; ++static pthread_mutex_t io_err_pathvec_lock = PTHREAD_MUTEX_INITIALIZER; + static int io_err_thread_running = 0; + +-static struct io_err_stat_pathvec *paths; ++static vector io_err_pathvec; + struct vectors *vecs; + io_context_t ioctx; + +@@ -207,46 +202,23 @@ static void free_io_err_stat_path(struct io_err_stat_path *p) + FREE(p); + } + +-static struct io_err_stat_pathvec *alloc_pathvec(void) +-{ +- struct io_err_stat_pathvec *p; +- int r; +- +- p = (struct io_err_stat_pathvec *)MALLOC(sizeof(*p)); +- if (!p) +- return NULL; +- p->pathvec = vector_alloc(); +- if (!p->pathvec) +- goto out_free_struct_pathvec; +- r = pthread_mutex_init(&p->mutex, NULL); +- if (r) +- goto out_free_member_pathvec; +- +- return p; +- +-out_free_member_pathvec: +- vector_free(p->pathvec); +-out_free_struct_pathvec: +- FREE(p); +- return NULL; +-} +- +-static void free_io_err_pathvec(struct io_err_stat_pathvec *p) ++static void free_io_err_pathvec(void) + { + struct io_err_stat_path *path; + int i; + +- if (!p) +- return; +- pthread_mutex_destroy(&p->mutex); +- if (!p->pathvec) { +- vector_foreach_slot(p->pathvec, path, i) { +- destroy_directio_ctx(path); +- free_io_err_stat_path(path); +- } +- vector_free(p->pathvec); ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock); ++ if (!io_err_pathvec) ++ goto out; ++ vector_foreach_slot(io_err_pathvec, path, i) { ++ destroy_directio_ctx(path); ++ free_io_err_stat_path(path); + } +- FREE(p); ++ vector_free(io_err_pathvec); ++ io_err_pathvec = NULL; ++out: ++ pthread_cleanup_pop(1); + } + + /* +@@ -258,13 +230,13 @@ static int enqueue_io_err_stat_by_path(struct path *path) + { + struct io_err_stat_path *p; + +- pthread_mutex_lock(&paths->mutex); +- p = find_err_path_by_dev(paths->pathvec, path->dev); ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ p = find_err_path_by_dev(io_err_pathvec, path->dev); + if (p) { +- pthread_mutex_unlock(&paths->mutex); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + return 0; + } +- pthread_mutex_unlock(&paths->mutex); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + + p = alloc_io_err_stat_path(); + if (!p) +@@ -276,18 +248,18 @@ static int enqueue_io_err_stat_by_path(struct path *path) + + if (setup_directio_ctx(p)) + goto free_ioerr_path; +- pthread_mutex_lock(&paths->mutex); +- if (!vector_alloc_slot(paths->pathvec)) ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ if (!vector_alloc_slot(io_err_pathvec)) + goto unlock_destroy; +- vector_set_slot(paths->pathvec, p); +- pthread_mutex_unlock(&paths->mutex); ++ vector_set_slot(io_err_pathvec, p); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + + io_err_stat_log(2, "%s: enqueue path %s to check", + path->mpp->alias, path->dev); + return 0; + + unlock_destroy: +- pthread_mutex_unlock(&paths->mutex); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + destroy_directio_ctx(p); + free_ioerr_path: + free_io_err_stat_path(p); +@@ -412,9 +384,9 @@ static int delete_io_err_stat_by_addr(struct io_err_stat_path *p) + { + int i; + +- i = find_slot(paths->pathvec, p); ++ i = find_slot(io_err_pathvec, p); + if (i != -1) +- vector_del_slot(paths->pathvec, i); ++ vector_del_slot(io_err_pathvec, i); + + destroy_directio_ctx(p); + free_io_err_stat_path(p); +@@ -585,7 +557,7 @@ static void poll_async_io_timeout(void) + + if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) + return; +- vector_foreach_slot(paths->pathvec, pp, i) { ++ vector_foreach_slot(io_err_pathvec, pp, i) { + for (j = 0; j < CONCUR_NR_EVENT; j++) { + rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j, + &curr_time, pp->devname); +@@ -631,7 +603,7 @@ static void handle_async_io_done_event(struct io_event *io_evt) + int rc = PATH_UNCHECKED; + int i, j; + +- vector_foreach_slot(paths->pathvec, pp, i) { ++ vector_foreach_slot(io_err_pathvec, pp, i) { + for (j = 0; j < CONCUR_NR_EVENT; j++) { + ct = pp->dio_ctx_array + j; + if (&ct->io == io_evt->obj) { +@@ -665,19 +637,14 @@ static void service_paths(void) + struct io_err_stat_path *pp; + int i; + +- pthread_mutex_lock(&paths->mutex); +- vector_foreach_slot(paths->pathvec, pp, i) { ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ vector_foreach_slot(io_err_pathvec, pp, i) { + send_batch_async_ios(pp); + process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname); + poll_async_io_timeout(); + poll_io_err_stat(vecs, pp); + } +- pthread_mutex_unlock(&paths->mutex); +-} +- +-static void cleanup_unlock(void *arg) +-{ +- pthread_mutex_unlock((pthread_mutex_t*) arg); ++ pthread_mutex_unlock(&io_err_pathvec_lock); + } + + static void cleanup_exited(__attribute__((unused)) void *arg) +@@ -736,13 +703,18 @@ int start_io_err_stat_thread(void *data) + io_err_stat_log(4, "io_setup failed"); + return 1; + } +- paths = alloc_pathvec(); +- if (!paths) ++ ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ io_err_pathvec = vector_alloc(); ++ if (!io_err_pathvec) { ++ pthread_mutex_unlock(&io_err_pathvec_lock); + goto destroy_ctx; ++ } ++ pthread_mutex_unlock(&io_err_pathvec_lock); + + setup_thread_attr(&io_err_stat_attr, 32 * 1024, 0); + pthread_mutex_lock(&io_err_thread_lock); +- pthread_cleanup_push(cleanup_unlock, &io_err_thread_lock); ++ pthread_cleanup_push(cleanup_mutex, &io_err_thread_lock); + + ret = pthread_create(&io_err_stat_thr, &io_err_stat_attr, + io_err_stat_loop, data); +@@ -763,7 +735,10 @@ int start_io_err_stat_thread(void *data) + return 0; + + out_free: +- free_io_err_pathvec(paths); ++ pthread_mutex_lock(&io_err_pathvec_lock); ++ vector_free(io_err_pathvec); ++ io_err_pathvec = NULL; ++ pthread_mutex_unlock(&io_err_pathvec_lock); + destroy_ctx: + io_destroy(ioctx); + io_err_stat_log(0, "failed to start io_error statistic thread"); +@@ -779,6 +754,6 @@ void stop_io_err_stat_thread(void) + pthread_cancel(io_err_stat_thr); + + pthread_join(io_err_stat_thr, NULL); +- free_io_err_pathvec(paths); ++ free_io_err_pathvec(); + io_destroy(ioctx); + } +-- +2.17.2 + diff --git a/0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch b/0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch new file mode 100644 index 0000000..30584f6 --- /dev/null +++ b/0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:24 -0600 +Subject: [PATCH] multipathd: avoid io_err_stat ABBA deadlock + +When the checker thread enqueues paths for the io_err_stat thread to +check, it calls enqueue_io_err_stat_by_path() with the vecs lock held. +start_io_err_stat_thread() is also called with the vecs lock held. +These two functions both lock io_err_pathvec_lock. When the io_err_stat +thread updates the paths in vecs->pathvec in poll_io_err_stat(), it has +the io_err_pathvec_lock held, and then locks the vecs lock. This can +cause an ABBA deadlock. + +To solve this, service_paths() no longer updates the paths in +vecs->pathvec with the io_err_pathvec_lock held. It does this by moving +the io_err_stat_path from io_err_pathvec to a local vector when it needs +to update the path. After releasing the io_err_pathvec_lock, it goes +through this temporary vector, updates the paths with the vecs lock +held, and then frees everything. + +This change fixes a bug in service_paths() where elements were being +deleted from io_err_pathvec, without the index being decremented, +causing the loop to skip elements. Also, service_paths() could be +cancelled while holding the io_err_pathvec_lock, so it should have a +cleanup handler. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 56 ++++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 24 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index feb66469..775e7259 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -380,20 +380,6 @@ recover: + return 0; + } + +-static int delete_io_err_stat_by_addr(struct io_err_stat_path *p) +-{ +- int i; +- +- i = find_slot(io_err_pathvec, p); +- if (i != -1) +- vector_del_slot(io_err_pathvec, i); +- +- destroy_directio_ctx(p); +- free_io_err_stat_path(p); +- +- return 0; +-} +- + static void account_async_io_state(struct io_err_stat_path *pp, int rc) + { + switch (rc) { +@@ -410,17 +396,26 @@ static void account_async_io_state(struct io_err_stat_path *pp, int rc) + } + } + +-static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) ++static int io_err_stat_time_up(struct io_err_stat_path *pp) + { + struct timespec currtime, difftime; +- struct path *path; +- double err_rate; + + if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- return 1; ++ return 0; + timespecsub(&currtime, &pp->start_time, &difftime); + if (difftime.tv_sec < pp->total_time) + return 0; ++ return 1; ++} ++ ++static void end_io_err_stat(struct io_err_stat_path *pp) ++{ ++ struct timespec currtime; ++ struct path *path; ++ double err_rate; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) ++ currtime = pp->start_time; + + io_err_stat_log(4, "%s: check end", pp->devname); + +@@ -459,10 +454,6 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) + pp->devname); + } + lock_cleanup_pop(vecs->lock); +- +- delete_io_err_stat_by_addr(pp); +- +- return 0; + } + + static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev) +@@ -622,6 +613,7 @@ static void process_async_ios_event(int timeout_nsecs, char *dev) + struct timespec timeout = { .tv_nsec = timeout_nsecs }; + + errno = 0; ++ pthread_testcancel(); + n = io_getevents(ioctx, 1L, CONCUR_NR_EVENT, events, &timeout); + if (n < 0) { + io_err_stat_log(3, "%s: async io events returned %d (errno=%s)", +@@ -634,17 +626,33 @@ static void process_async_ios_event(int timeout_nsecs, char *dev) + + static void service_paths(void) + { ++ struct _vector _pathvec = {0}; ++ /* avoid gcc warnings that &_pathvec will never be NULL in vector ops */ ++ struct _vector * const tmp_pathvec = &_pathvec; + struct io_err_stat_path *pp; + int i; + + pthread_mutex_lock(&io_err_pathvec_lock); ++ pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock); + vector_foreach_slot(io_err_pathvec, pp, i) { + send_batch_async_ios(pp); + process_async_ios_event(TIMEOUT_NO_IO_NSEC, pp->devname); + poll_async_io_timeout(); +- poll_io_err_stat(vecs, pp); ++ if (io_err_stat_time_up(pp)) { ++ if (!vector_alloc_slot(tmp_pathvec)) ++ continue; ++ vector_del_slot(io_err_pathvec, i--); ++ vector_set_slot(tmp_pathvec, pp); ++ } + } +- pthread_mutex_unlock(&io_err_pathvec_lock); ++ pthread_cleanup_pop(1); ++ vector_foreach_slot_backwards(tmp_pathvec, pp, i) { ++ end_io_err_stat(pp); ++ vector_del_slot(tmp_pathvec, i); ++ destroy_directio_ctx(pp); ++ free_io_err_stat_path(pp); ++ } ++ vector_reset(tmp_pathvec); + } + + static void cleanup_exited(__attribute__((unused)) void *arg) +-- +2.17.2 + diff --git a/0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch b/0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch new file mode 100644 index 0000000..89d9f73 --- /dev/null +++ b/0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:25 -0600 +Subject: [PATCH] multipathd: use get_monotonic_time() in io_err_stat code + +Instead of calling clock_gettime(), and dealing with failure +conditions, just call get_monotonic_time(). + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 34 +++++++++++----------------------- + 1 file changed, 11 insertions(+), 23 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 775e7259..92871f40 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -295,8 +295,7 @@ int io_err_stat_handle_pathfail(struct path *path) + * the repeated count threshold and time frame, we assume a path + * which fails at least twice within 60 seconds is flaky. + */ +- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) +- return 1; ++ get_monotonic_time(&curr_time); + if (path->io_err_pathfail_cnt == 0) { + path->io_err_pathfail_cnt++; + path->io_err_pathfail_starttime = curr_time.tv_sec; +@@ -352,9 +351,9 @@ int need_io_err_check(struct path *pp) + } + if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) + return 1; +- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 || +- (curr_time.tv_sec - pp->io_err_dis_reinstate_time) > +- pp->mpp->marginal_path_err_recheck_gap_time) { ++ get_monotonic_time(&curr_time); ++ if ((curr_time.tv_sec - pp->io_err_dis_reinstate_time) > ++ pp->mpp->marginal_path_err_recheck_gap_time) { + io_err_stat_log(4, "%s: reschedule checking after %d seconds", + pp->dev, + pp->mpp->marginal_path_err_recheck_gap_time); +@@ -400,8 +399,7 @@ static int io_err_stat_time_up(struct io_err_stat_path *pp) + { + struct timespec currtime, difftime; + +- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- return 0; ++ get_monotonic_time(&currtime); + timespecsub(&currtime, &pp->start_time, &difftime); + if (difftime.tv_sec < pp->total_time) + return 0; +@@ -414,8 +412,7 @@ static void end_io_err_stat(struct io_err_stat_path *pp) + struct path *path; + double err_rate; + +- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- currtime = pp->start_time; ++ get_monotonic_time(&currtime); + + io_err_stat_log(4, "%s: check end", pp->devname); + +@@ -464,11 +461,7 @@ static int send_each_async_io(struct dio_ctx *ct, int fd, char *dev) + ct->io_starttime.tv_sec == 0) { + struct iocb *ios[1] = { &ct->io }; + +- if (clock_gettime(CLOCK_MONOTONIC, &ct->io_starttime) != 0) { +- ct->io_starttime.tv_sec = 0; +- ct->io_starttime.tv_nsec = 0; +- return rc; +- } ++ get_monotonic_time(&ct->io_starttime); + io_prep_pread(&ct->io, fd, ct->buf, ct->blksize, 0); + if (io_submit(ioctx, 1, ios) != 1) { + io_err_stat_log(5, "%s: io_submit error %i", +@@ -487,8 +480,7 @@ static void send_batch_async_ios(struct io_err_stat_path *pp) + struct dio_ctx *ct; + struct timespec currtime, difftime; + +- if (clock_gettime(CLOCK_MONOTONIC, &currtime) != 0) +- return; ++ get_monotonic_time(&currtime); + /* + * Give a free time for all IO to complete or timeout + */ +@@ -503,11 +495,8 @@ static void send_batch_async_ios(struct io_err_stat_path *pp) + if (!send_each_async_io(ct, pp->fd, pp->devname)) + pp->io_nr++; + } +- if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0 && +- clock_gettime(CLOCK_MONOTONIC, &pp->start_time)) { +- pp->start_time.tv_sec = 0; +- pp->start_time.tv_nsec = 0; +- } ++ if (pp->start_time.tv_sec == 0 && pp->start_time.tv_nsec == 0) ++ get_monotonic_time(&pp->start_time); + } + + static int try_to_cancel_timeout_io(struct dio_ctx *ct, struct timespec *t, +@@ -546,8 +535,7 @@ static void poll_async_io_timeout(void) + int rc = PATH_UNCHECKED; + int i, j; + +- if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0) +- return; ++ get_monotonic_time(&curr_time); + vector_foreach_slot(io_err_pathvec, pp, i) { + for (j = 0; j < CONCUR_NR_EVENT; j++) { + rc = try_to_cancel_timeout_io(pp->dio_ctx_array + j, +-- +2.17.2 + diff --git a/0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch b/0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch new file mode 100644 index 0000000..90fd516 --- /dev/null +++ b/0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 14 Jan 2021 20:20:26 -0600 +Subject: [PATCH] multipathd: combine free_io_err_stat_path and + destroy_directio_ctx + +destroy_directio_ctx() is only called from free_io_err_stat_path(), and +free_io_err_stat_path() is very short, so combine them. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 24 ++++++++++-------------- + 1 file changed, 10 insertions(+), 14 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index 92871f40..bf78a236 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -161,12 +161,15 @@ fail_close: + return 1; + } + +-static void destroy_directio_ctx(struct io_err_stat_path *p) ++static void free_io_err_stat_path(struct io_err_stat_path *p) + { + int i; + +- if (!p || !p->dio_ctx_array) ++ if (!p) + return; ++ if (!p->dio_ctx_array) ++ goto free_path; ++ + cancel_inflight_io(p); + + for (i = 0; i < CONCUR_NR_EVENT; i++) +@@ -175,6 +178,8 @@ static void destroy_directio_ctx(struct io_err_stat_path *p) + + if (p->fd > 0) + close(p->fd); ++free_path: ++ FREE(p); + } + + static struct io_err_stat_path *alloc_io_err_stat_path(void) +@@ -197,11 +202,6 @@ static struct io_err_stat_path *alloc_io_err_stat_path(void) + return p; + } + +-static void free_io_err_stat_path(struct io_err_stat_path *p) +-{ +- FREE(p); +-} +- + static void free_io_err_pathvec(void) + { + struct io_err_stat_path *path; +@@ -211,10 +211,8 @@ static void free_io_err_pathvec(void) + pthread_cleanup_push(cleanup_mutex, &io_err_pathvec_lock); + if (!io_err_pathvec) + goto out; +- vector_foreach_slot(io_err_pathvec, path, i) { +- destroy_directio_ctx(path); ++ vector_foreach_slot(io_err_pathvec, path, i) + free_io_err_stat_path(path); +- } + vector_free(io_err_pathvec); + io_err_pathvec = NULL; + out: +@@ -250,7 +248,7 @@ static int enqueue_io_err_stat_by_path(struct path *path) + goto free_ioerr_path; + pthread_mutex_lock(&io_err_pathvec_lock); + if (!vector_alloc_slot(io_err_pathvec)) +- goto unlock_destroy; ++ goto unlock_pathvec; + vector_set_slot(io_err_pathvec, p); + pthread_mutex_unlock(&io_err_pathvec_lock); + +@@ -258,9 +256,8 @@ static int enqueue_io_err_stat_by_path(struct path *path) + path->mpp->alias, path->dev); + return 0; + +-unlock_destroy: ++unlock_pathvec: + pthread_mutex_unlock(&io_err_pathvec_lock); +- destroy_directio_ctx(p); + free_ioerr_path: + free_io_err_stat_path(p); + +@@ -637,7 +634,6 @@ static void service_paths(void) + vector_foreach_slot_backwards(tmp_pathvec, pp, i) { + end_io_err_stat(pp); + vector_del_slot(tmp_pathvec, i); +- destroy_directio_ctx(pp); + free_io_err_stat_path(pp); + } + vector_reset(tmp_pathvec); +-- +2.17.2 + diff --git a/0102-multipathd-cleanup-logging-for-marginal-paths.patch b/0102-multipathd-cleanup-logging-for-marginal-paths.patch new file mode 100644 index 0000000..79ad137 --- /dev/null +++ b/0102-multipathd-cleanup-logging-for-marginal-paths.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 18 Jan 2021 22:46:04 -0600 +Subject: [PATCH] multipathd: cleanup logging for marginal paths + +io_err_stat logged at level 2 whenever it enqueued a path to check, +which could happen multiple times while a path was marginal. On the +other hand if marginal_pathgroups wasn't set, multipathd didn't log when +paths were set to marginal. Now io_err_stat only logs at level 2 when +something unexpected happens, but multipathd will always log when a +path switches its marginal state. + +This patch also fixes an issue where paths in the delayed state could +get set to the pending state if they could not be checked in time. +Aside from going against the idea the paths should not be set to pending +if they already have a valid state, this caused multipathd to log a +message whenever the path state switched to from delayed to pending and +then back. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/io_err_stat.c | 7 +++---- + multipathd/main.c | 25 ++++++++++++++----------- + 2 files changed, 17 insertions(+), 15 deletions(-) + +diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c +index bf78a236..abdd0b4f 100644 +--- a/libmultipath/io_err_stat.c ++++ b/libmultipath/io_err_stat.c +@@ -252,7 +252,7 @@ static int enqueue_io_err_stat_by_path(struct path *path) + vector_set_slot(io_err_pathvec, p); + pthread_mutex_unlock(&io_err_pathvec_lock); + +- io_err_stat_log(2, "%s: enqueue path %s to check", ++ io_err_stat_log(3, "%s: enqueue path %s to check", + path->mpp->alias, path->dev); + return 0; + +@@ -343,7 +343,7 @@ int need_io_err_check(struct path *pp) + if (uatomic_read(&io_err_thread_running) == 0) + return 0; + if (count_active_paths(pp->mpp) <= 0) { +- io_err_stat_log(2, "%s: recover path early", pp->dev); ++ io_err_stat_log(2, "%s: no paths. recovering early", pp->dev); + goto recover; + } + if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) +@@ -361,8 +361,7 @@ int need_io_err_check(struct path *pp) + * Or else, return 1 to set path state to PATH_SHAKY + */ + if (r == 1) { +- io_err_stat_log(3, "%s: enqueue fails, to recover", +- pp->dev); ++ io_err_stat_log(2, "%s: enqueue failed. recovering early", pp->dev); + goto recover; + } else + pp->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; +diff --git a/multipathd/main.c b/multipathd/main.c +index 92c45d44..99a89a69 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2132,8 +2132,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + pathinfo(pp, conf, 0); + pthread_cleanup_pop(1); + return 1; +- } else if ((newstate != PATH_UP && newstate != PATH_GHOST) && +- (pp->state == PATH_DELAYED)) { ++ } else if ((newstate != PATH_UP && newstate != PATH_GHOST && ++ newstate != PATH_PENDING) && (pp->state == PATH_DELAYED)) { + /* If path state become failed again cancel path delay state */ + pp->state = newstate; + /* +@@ -2200,8 +2200,9 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + if ((newstate == PATH_UP || newstate == PATH_GHOST) && + (san_path_check_enabled(pp->mpp) || + marginal_path_check_enabled(pp->mpp))) { +- int was_marginal = pp->marginal; + if (should_skip_path(pp)) { ++ if (!pp->marginal && pp->state != PATH_DELAYED) ++ condlog(2, "%s: path is now marginal", pp->dev); + if (!marginal_pathgroups) { + if (marginal_path_check_enabled(pp->mpp)) + /* to reschedule as soon as possible, +@@ -2211,13 +2212,18 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + pp->state = PATH_DELAYED; + return 1; + } +- if (!was_marginal) { ++ if (!pp->marginal) { + pp->marginal = 1; + marginal_changed = 1; + } +- } else if (marginal_pathgroups && was_marginal) { +- pp->marginal = 0; +- marginal_changed = 1; ++ } else { ++ if (pp->marginal || pp->state == PATH_DELAYED) ++ condlog(2, "%s: path is no longer marginal", ++ pp->dev); ++ if (marginal_pathgroups && pp->marginal) { ++ pp->marginal = 0; ++ marginal_changed = 1; ++ } + } + } + +@@ -2343,11 +2349,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + */ + condlog(4, "path prio refresh"); + +- if (marginal_changed) { +- condlog(2, "%s: path is %s marginal", pp->dev, +- (pp->marginal)? "now" : "no longer"); ++ if (marginal_changed) + reload_and_sync_map(pp->mpp, vecs, 1); +- } + else if (update_prio(pp, new_path_up) && + (pp->mpp->pgpolicyfn == (pgpolicyfn *)group_by_prio) && + pp->mpp->pgfailback == -FAILBACK_IMMEDIATE) { +-- +2.17.2 + diff --git a/0059-RH-fixup-udev-rules-for-redhat.patch b/0103-RH-fixup-udev-rules-for-redhat.patch similarity index 98% rename from 0059-RH-fixup-udev-rules-for-redhat.patch rename to 0103-RH-fixup-udev-rules-for-redhat.patch index b1f5beb..d5bbd5b 100644 --- a/0059-RH-fixup-udev-rules-for-redhat.patch +++ b/0103-RH-fixup-udev-rules-for-redhat.patch @@ -15,7 +15,7 @@ Signed-off-by: Benjamin Marzinski 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.inc b/Makefile.inc -index 8ea3352d..873fb62f 100644 +index 05429307..24e943d5 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -53,7 +53,7 @@ endif diff --git a/0060-RH-Remove-the-property-blacklist-exception-builtin.patch b/0104-RH-Remove-the-property-blacklist-exception-builtin.patch similarity index 78% rename from 0060-RH-Remove-the-property-blacklist-exception-builtin.patch rename to 0104-RH-Remove-the-property-blacklist-exception-builtin.patch index f760f87..9c44867 100644 --- a/0060-RH-Remove-the-property-blacklist-exception-builtin.patch +++ b/0104-RH-Remove-the-property-blacklist-exception-builtin.patch @@ -13,29 +13,26 @@ it. Signed-off-by: Benjamin Marzinski --- - libmultipath/blacklist.c | 9 ++------- + libmultipath/blacklist.c | 6 ++---- multipath/multipath.conf.5 | 11 ++++++----- - tests/blacklist.c | 6 ++---- - 3 files changed, 10 insertions(+), 16 deletions(-) + tests/blacklist.c | 7 ++----- + 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c -index db58ccca..0c58aa32 100644 +index 6c6a5979..785f5ee9 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)) +@@ -201,9 +201,6 @@ setup_default_blist (struct config * conf) + if (store_ble(conf->blist_devnode, "!^(sd[a-z]|dasd[a-z]|nvme[0-9])", ORIGIN_DEFAULT)) return 1; -- str = STRDUP("(SCSI_IDENT_|ID_WWN)"); -- if (!str) -- return 1; -- if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT)) +- if (store_ble(conf->elist_property, "(SCSI_IDENT_|ID_WWN)", 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, +@@ -407,7 +404,8 @@ filter_property(const struct config *conf, struct udev_device *udev, *uid_attribute != '\0'; bool uid_attr_seen = false; @@ -46,10 +43,10 @@ index db58ccca..0c58aa32 100644 udev_device_get_properties_list_entry(udev)) { diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 -index 5adaced6..42a192f6 100644 +index 8ef3a747..1e95a854 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 +@@ -1333,9 +1333,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, @@ -65,7 +62,7 @@ index 5adaced6..42a192f6 100644 . .RS .PP -@@ -1309,10 +1314,6 @@ Blacklisting by missing properties is only applied to devices which do have the +@@ -1346,10 +1351,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. @@ -77,19 +74,21 @@ index 5adaced6..42a192f6 100644 .TP .B protocol diff --git a/tests/blacklist.c b/tests/blacklist.c -index d5c40898..d20e97af 100644 +index 0b42e255..4d595eda 100644 --- a/tests/blacklist.c +++ b/tests/blacklist.c -@@ -380,7 +380,7 @@ static void test_property_missing(void **state) +@@ -375,9 +375,8 @@ static void test_property_missing(void **state) + { + static struct udev_device udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", "ID_SERIAL", NULL } }; conf.blist_property = blist_property_wwn; - expect_condlog(3, "sdb: blacklisted, udev property missing\n"); +- 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) +@@ -469,9 +468,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; diff --git a/0061-RH-don-t-start-without-a-config-file.patch b/0105-RH-don-t-start-without-a-config-file.patch similarity index 85% rename from 0061-RH-don-t-start-without-a-config-file.patch rename to 0105-RH-don-t-start-without-a-config-file.patch index 4712300..2f8d791 100644 --- a/0061-RH-don-t-start-without-a-config-file.patch +++ b/0105-RH-don-t-start-without-a-config-file.patch @@ -12,26 +12,18 @@ simple way to disable multipath. Simply removing or renaming Signed-off-by: Benjamin Marzinski --- - libmultipath/config.c | 15 +++++++++++++++ + libmultipath/config.c | 13 +++++++++++++ libmultipath/config.h | 1 + multipath/multipath.rules | 1 + multipathd/multipathd.8 | 2 ++ multipathd/multipathd.service | 1 + - 5 files changed, 20 insertions(+) + 5 files changed, 18 insertions(+) diff --git a/libmultipath/config.c b/libmultipath/config.c -index 658bec8b..1c02e230 100644 +index be310159..8d291491 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) +@@ -893,6 +893,19 @@ int _init_config (const char *file, struct config *conf) goto out; } factorize_hwtable(conf->hwtable, builtin_hwtable_size, file); @@ -44,8 +36,7 @@ index 658bec8b..1c02e230 100644 + goto out; + } + } -+ if (store_ble(conf->blist_devnode, strdup(".*"), -+ ORIGIN_NO_CONFIG)) { ++ if (store_ble(conf->blist_devnode, ".*", ORIGIN_NO_CONFIG)) { + condlog(0, "cannot store default no-config blacklist\n"); + goto out; + } @@ -53,7 +44,7 @@ index 658bec8b..1c02e230 100644 conf->processed_main_config = 1; diff --git a/libmultipath/config.h b/libmultipath/config.h -index 92c61a0d..160867cd 100644 +index 9ce37f16..7f8d9cd0 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -9,6 +9,7 @@ @@ -62,8 +53,8 @@ index 92c61a0d..160867cd 100644 #define ORIGIN_CONFIG 1 +#define ORIGIN_NO_CONFIG 2 - /* - * In kernel, fast_io_fail == 0 means immediate failure on rport delete. + enum devtypes { + DEV_NONE, diff --git a/multipath/multipath.rules b/multipath/multipath.rules index 9df11a95..0486bf70 100644 --- a/multipath/multipath.rules diff --git a/0067-RH-Fix-nvme-compilation-warning.patch b/0106-RH-Fix-nvme-function-missing-argument.patch similarity index 82% rename from 0067-RH-Fix-nvme-compilation-warning.patch rename to 0106-RH-Fix-nvme-function-missing-argument.patch index fc6ccd7..b5c63c0 100644 --- a/0067-RH-Fix-nvme-compilation-warning.patch +++ b/0106-RH-Fix-nvme-function-missing-argument.patch @@ -1,7 +1,10 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 25 Jan 2019 14:54:56 -0600 -Subject: [PATCH] RH: Fix nvme compilation warning +Subject: [PATCH] RH: Fix nvme function missing argument + +A future patch will change the compilation options to error when +function declarations have unspecified arguments. Signed-off-by: Benjamin Marzinski --- diff --git a/0062-RH-use-rpm-optflags-if-present.patch b/0107-RH-use-rpm-optflags-if-present.patch similarity index 92% rename from 0062-RH-use-rpm-optflags-if-present.patch rename to 0107-RH-use-rpm-optflags-if-present.patch index d6c97c1..f765f47 100644 --- a/0062-RH-use-rpm-optflags-if-present.patch +++ b/0107-RH-use-rpm-optflags-if-present.patch @@ -13,10 +13,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Makefile.inc b/Makefile.inc -index 873fb62f..479523bc 100644 +index 24e943d5..e978d306 100644 --- a/Makefile.inc +++ b/Makefile.inc -@@ -89,15 +89,27 @@ TEST_CC_OPTION = $(shell \ +@@ -90,15 +90,27 @@ TEST_CC_OPTION = $(shell \ echo "$(2)"; \ fi) @@ -46,10 +46,10 @@ index 873fb62f..479523bc 100644 -CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2 + $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) \ + -Wstrict-prototypes - CFLAGS := $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ + CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \ -MMD -MP -@@ -135,4 +147,4 @@ check_file = $(shell \ +@@ -136,4 +148,4 @@ check_file = $(shell \ %.o: %.c @echo building $@ because of $? diff --git a/0063-RH-add-mpathconf.patch b/0108-RH-add-mpathconf.patch similarity index 94% rename from 0063-RH-add-mpathconf.patch rename to 0108-RH-add-mpathconf.patch index 6480711..503fef2 100644 --- a/0063-RH-add-mpathconf.patch +++ b/0108-RH-add-mpathconf.patch @@ -14,17 +14,17 @@ Signed-off-by: Benjamin Marzinski --- libmultipath/config.c | 2 + multipath/Makefile | 5 + - multipath/mpathconf | 565 ++++++++++++++++++++++++++++++++++++++++++ + multipath/mpathconf | 555 ++++++++++++++++++++++++++++++++++++++++++ multipath/mpathconf.8 | 135 ++++++++++ - 4 files changed, 707 insertions(+) + 4 files changed, 697 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 +index 8d291491..bbdd1617 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -781,6 +781,8 @@ load_config (char * file) +@@ -895,6 +895,8 @@ int _init_config (const char *file, struct config *conf) factorize_hwtable(conf->hwtable, builtin_hwtable_size, file); } else { condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); @@ -69,10 +69,10 @@ index b9bbb3cf..e720c7f6 100644 $(RM) core *.o $(EXEC) *.gz diff --git a/multipath/mpathconf b/multipath/mpathconf new file mode 100644 -index 00000000..f0d09cbb +index 00000000..f34003c9 --- /dev/null +++ b/multipath/mpathconf -@@ -0,0 +1,565 @@ +@@ -0,0 +1,555 @@ +#!/bin/bash +# +# Copyright (C) 2010 Red Hat, Inc. All rights reserved. @@ -107,6 +107,11 @@ index 00000000..f0d09cbb +defaults { + user_friendly_names yes + find_multipaths yes ++ enable_foreign \"^$\" ++} ++ ++blacklist_exceptions { ++ property \"(SCSI_IDENT_|ID_WWN)\" +}" + +CONFIGFILE="/etc/multipath.conf" @@ -125,7 +130,7 @@ index 00000000..f0d09cbb + echo "Only allow certain wwids (instead of enable): --allow " + echo "Set user_friendly_names (Default y): --user_friendly_names " + echo "Set find_multipaths (Default y): --find_multipaths " -+ echo "Set default property blacklist (Default n): --property_blacklist " ++ echo "Set default property blacklist (Default y): --property_blacklist " + echo "Set enable_foreign to show foreign devices (Default n): --enable_foreign " + echo "Load the dm-multipath modules on enable (Default y): --with_module " + echo "start/stop/reload multipathd (Default n): --with_multipathd " @@ -283,13 +288,12 @@ index 00000000..f0d09cbb + +function validate_args +{ -+ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$PROPERTY" -o -n "$MODULE" -o -n "$FOREIGN" ]; then ++ if [ "$ENABLE" = "0" ] && [ -n "$FRIENDLY" -o -n "$FIND" -o -n "$PROPERTY" -o -n "$MODULE" ]; 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'" @@ -307,7 +311,7 @@ index 00000000..f0d09cbb + 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 ++ if [ -z "$ENABLE" -a -z "$FIND" -a -z "$FRIENDLY" -a -z "$PROPERTY" ]; then + SHOW_STATUS=1 + fi + if [ -n "$MODULE" ] && [ "$MODULE" != "y" -a "$MODULE" != "n" ]; then @@ -412,12 +416,8 @@ index 00000000..f0d09cbb + 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 ++ HAVE_FOREIGN=2 + fi +fi + @@ -451,11 +451,9 @@ index 00000000..f0d09cbb + 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)" ++ echo "enable_foreign is not set (all 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 @@ -572,15 +570,7 @@ index 00000000..f0d09cbb + 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 ++ if [ -z "$HAVE_PROPERTY" ]; then + sed -i '/^blacklist_exceptions[[:space:]]*{/ a\ + property "(SCSI_IDENT_|ID_WWN)" +' $TMPFILE @@ -592,18 +582,18 @@ index 00000000..f0d09cbb +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 ++ if [ "$HAVE_FOREIGN" = 1 -o "$HAVE_FOREIGN" = 2 ]; then ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[: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 ++ if [ -z "$HAVE_FOREIGN" ]; then ++ sed -i '/^defaults[[:space:]]*{/ a\ ++ enable_foreign "^$" ++' $TMPFILE ++ CHANGED_CONFIG=1 ++ elif [ "$HAVE_FOREIGN" = 0 -o "$HAVE_FOREIGN" = 2 ]; then ++ sed -i '/^defaults[[:space:]]*{/,/^}/ s/^[[:space:]]*#\?[[:space:]]*enable_foreign.*$/ enable_foreign "^$"/' $TMPFILE + CHANGED_CONFIG=1 + fi +fi diff --git a/0064-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch b/0109-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch similarity index 78% rename from 0064-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch rename to 0109-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch index 0b95ee6..cdce408 100644 --- a/0064-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +++ b/0109-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch @@ -14,23 +14,38 @@ multipathd.service Signed-off-by: Benjamin Marzinski --- - libmultipath/wwids.c | 44 +++++++++++++++++++++++++++++++++++ - libmultipath/wwids.h | 1 + - multipath/main.c | 10 ++++++-- - multipath/multipath.8 | 7 +++++- + multipath/main.c | 54 +++++++++++++++++++++++++++++++++-- + multipath/multipath.8 | 7 ++++- multipathd/multipathd.service | 1 + - 5 files changed, 60 insertions(+), 3 deletions(-) + 3 files changed, 59 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; +diff --git a/multipath/main.c b/multipath/main.c +index 9ac42869..beaac3ca 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -122,7 +122,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); +@@ -136,6 +136,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" +@@ -452,6 +454,50 @@ static void cleanup_vecs(void) + free_pathvec(vecs.pathvec, FREE_PATHS); } -+ -+int remember_cmdline_wwid(void) + ++static int remember_cmdline_wwid(void) +{ + FILE *f = NULL; + char buf[LINE_MAX], *next, *ptr; @@ -73,42 +88,12 @@ index 61d9c39e..c7a16636 100644 + } + 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; ++ + static int + configure (struct config *conf, enum mpath_cmds cmd, + enum devtypes dev_type, char *devpath) +@@ -825,7 +871,7 @@ main (int argc, char *argv[]) + conf = get_multipath_config(); conf->retrigger_tries = 0; conf->force_sync = 1; - while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) { @@ -116,7 +101,7 @@ index 3da692dc..ce48a932 100644 switch(arg) { case 1: printf("optarg : %s\n",optarg); break; -@@ -973,6 +975,10 @@ main (int argc, char *argv[]) +@@ -902,6 +948,10 @@ main (int argc, char *argv[]) case 'T': cmd = CMD_DUMP_CONFIG; break; diff --git a/0066-RH-reset-default-find_mutipaths-value-to-off.patch b/0110-RH-reset-default-find_mutipaths-value-to-off.patch similarity index 95% rename from 0066-RH-reset-default-find_mutipaths-value-to-off.patch rename to 0110-RH-reset-default-find_mutipaths-value-to-off.patch index 2dfb52e..304db61 100644 --- a/0066-RH-reset-default-find_mutipaths-value-to-off.patch +++ b/0110-RH-reset-default-find_mutipaths-value-to-off.patch @@ -12,10 +12,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h -index 01a501bd..984d8dd8 100644 +index 947ba467..518d0b16 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h -@@ -22,7 +22,7 @@ +@@ -23,7 +23,7 @@ #define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF #define DEFAULT_VERBOSITY 2 #define DEFAULT_REASSIGN_MAPS 0 diff --git a/0068-RH-attempt-to-get-ANA-info-via-sysfs-first.patch b/0111-RH-attempt-to-get-ANA-info-via-sysfs-first.patch similarity index 100% rename from 0068-RH-attempt-to-get-ANA-info-via-sysfs-first.patch rename to 0111-RH-attempt-to-get-ANA-info-via-sysfs-first.patch diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index 7b4fb7a..bf64277 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,102 +1,126 @@ Name: device-mapper-multipath -Version: 0.8.4 -Release: 7%{?dist} +Version: 0.8.5 +Release: 2%{?dist} Summary: Tools to manage multipath devices using device-mapper License: GPLv2 URL: http://christophe.varoqui.free.fr/ # The source for this package was pulled from upstream's git repo. Use the # following command to generate the tarball -# curl "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;h=refs/tags/0.8.4;sf=tgz" -o multipath-tools-0.8.4.tgz -Source0: multipath-tools-0.8.4.tgz +# curl -L https://github.com/opensvc/multipath-tools/archive/0.8.5.tar.gz -o multipath-tools-0.8.5.tgz +Source0: multipath-tools-0.8.5.tgz Source1: multipath.conf -Patch0001: 0001-libmpathpersist-limit-PRIN-allocation-length-to-8192.patch -Patch0002: 0002-libmpathpersist-format_transportids-avoid-PROUT-over.patch -Patch0003: 0003-libmpathpersist-mpath_format_readfullstatus-use-real.patch -Patch0004: 0004-libmultipath-assign-variable-to-make-gcc-happy.patch -Patch0005: 0005-libmutipath-don-t-close-fd-on-dm_lib_release.patch -Patch0006: 0006-libmultipath-allow-force-reload-with-no-active-paths.patch -Patch0007: 0007-kpartx.rules-honor-DM_UDEV_DISABLE_OTHER_RULES_FLAG.patch -Patch0008: 0008-kpartx.rules-check-for-skip_kpartx-on-synthetic-ueve.patch -Patch0009: 0009-libmpathpersist-depend-on-libmultipath.patch -Patch0010: 0010-multipath-tools-Makefile-more-dependency-fixes-for-p.patch -Patch0011: 0011-multipath-tools-Makefile.inc-separate-out-OPTFLAGS.patch -Patch0012: 0012-multipath-tools-Makefile.inc-allow-user-settings-for.patch -Patch0013: 0013-multipath-tools-Makefile.inc-set-Wno-error-clobbered.patch -Patch0014: 0014-libmultipath-discovery.c-use-z-qualifier-for-size_t.patch -Patch0015: 0015-libmultipath-eliminate-more-signed-unsigned-comparis.patch -Patch0016: 0016-libmultipath-set_uint-fix-parsing-for-32bit.patch -Patch0017: 0017-multipath-tools-tests-Makefile-add-lmpathcmd-to-LIBD.patch -Patch0018: 0018-multipath-tools-tests-Makefile-Fix-OBJDEPS-for-hwtab.patch -Patch0019: 0019-multipath-tools-tests-test-lib.c-drop-__wrap_is_clai.patch -Patch0020: 0020-multipath-tools-tests-directio-fix-Wmaybe-uninitaliz.patch -Patch0021: 0021-libmultipath-move-libsg-into-libmultipath.patch -Patch0022: 0022-multipath-tools-Makefile-add-install-dependency.patch -Patch0023: 0023-libmultipath-make-libmp_dm_init-optional.patch -Patch0024: 0024-libmultipath-make-sysfs_is_multipathed-able-to-retur.patch -Patch0025: 0025-multipath-centralize-validation-code.patch -Patch0026: 0026-Unit-tests-for-is_path_valid.patch -Patch0027: 0027-libmultipath-simplify-failed-wwid-code.patch -Patch0028: 0028-libmultipath-use-atomic-linkat-in-mark_failed_wwid.patch -Patch0029: 0029-fix-boolean-value-with-json-c-0.14.patch -Patch0030: 0030-libmultipath-fix-condlog-NULL-argument-in-uevent_get.patch -Patch0031: 0031-libmultipath-set-enable_foreign-to-NONE-by-default.patch -Patch0032: 0032-multipath-add-e-option-to-enable-foreign-libraries.patch -Patch0033: 0033-libmultipath-remove-_blacklist_exceptions-functions.patch -Patch0034: 0034-libmultipath-fix-parser-issue-with-comments-in-strin.patch -Patch0035: 0035-libmultipath-invert-regexes-that-start-with-exclamat.patch -Patch0036: 0036-multipath-Fix-compiler-warnings-when-built-without-s.patch -Patch0037: 0037-libmultipath-fix-sysfs-dev_loss_tmo-parsing.patch -Patch0038: 0038-kpartx-read-devices-with-direct-IO.patch -Patch0039: 0039-kpartx-handle-alternate-bsd-disklabel-location.patch -Patch0040: 0040-libmultipath-fix-checker-detection-for-nvme-devices.patch -Patch0041: 0041-libmultipath-make-dm_get_map-status-return-codes-sym.patch -Patch0042: 0042-multipathd-fix-check_path-errors-with-removed-map.patch -Patch0043: 0043-libmultipath-make-dm_flush_maps-only-return-0-on-suc.patch -Patch0044: 0044-multipathd-add-del-maps-multipathd-command.patch -Patch0045: 0045-multipath-make-flushing-maps-work-like-other-command.patch -Patch0046: 0046-multipath-delegate-flushing-maps-to-multipathd.patch -Patch0047: 0047-multipath-add-option-to-skip-multipathd-delegation.patch -Patch0048: 0048-libmultipath-add-device-to-hwtable.c.patch -Patch0049: 0049-master-libmultipath-fix-use-after-free-when-iscsi-lo.patch -Patch0050: 0050-libmultipath-warn-if-freeing-path-that-holds-mpp-hwe.patch -Patch0051: 0051-libmultipath-warn-about-NULL-value-of-mpp-hwe.patch -Patch0052: 0052-libmultipath-fix-mpp-hwe-handling-in-sync_paths.patch -Patch0053: 0053-Makefile.inc-trim-extra-information-from-systemd-ver.patch -Patch0054: 0054-kpartx-fix-Wsign-compare-error.patch -Patch0055: 0055-libmultipath-remove-code-duplication-in-path-countin.patch -Patch0056: 0056-libmultipath-count-pending-paths-as-active-on-loads.patch -Patch0057: 0057-libmultipath-deal-with-flushing-no-maps.patch -Patch0058: 0058-multipath-deal-with-delegation-failures-correctly.patch -Patch0059: 0059-RH-fixup-udev-rules-for-redhat.patch -Patch0060: 0060-RH-Remove-the-property-blacklist-exception-builtin.patch -Patch0061: 0061-RH-don-t-start-without-a-config-file.patch -Patch0062: 0062-RH-use-rpm-optflags-if-present.patch -Patch0063: 0063-RH-add-mpathconf.patch -Patch0064: 0064-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch -Patch0065: 0065-RH-warn-on-invalid-regex-instead-of-failing.patch -Patch0066: 0066-RH-reset-default-find_mutipaths-value-to-off.patch -Patch0067: 0067-RH-Fix-nvme-compilation-warning.patch -Patch0068: 0068-RH-attempt-to-get-ANA-info-via-sysfs-first.patch -Patch0069: 0069-RH-work-around-gcc-10-format-truncation-issue.patch -Patch0070: 0070-multipath-add-libmpathvalid-library.patch -Patch0071: 0071-libmultipath-add-uid-failback-for-dasd-devices.patch -Patch0072: 0072-libmultipath-add-ignore_udev_uid-option.patch -Patch0073: 0073-libmultipath-util-constify-function-arguments.patch -Patch0074: 0074-libmultipath-constify-file-argument-in-config-parser.patch -Patch0075: 0075-libmultipath-provide-defaults-for-get-put-_multipath.patch -Patch0076: 0076-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch -Patch0077: 0077-multipath-use-get_put-_multipath_config-from-libmult.patch -Patch0078: 0078-mpathpersist-use-get-put-_multipath_config-from-libm.patch -Patch0079: 0079-libmultipath-add-udev-and-logsink-symbols.patch -Patch0080: 0080-multipath-remove-logsink-and-udev.patch -Patch0081: 0081-libmpathpersist-call-libmultipath_-init-exit.patch -Patch0082: 0082-mpathpersist-remove-logsink-and-udev.patch -Patch0083: 0083-multipathd-remove-logsink-and-udev.patch -Patch0084: 0084-libmpathvalid-use-default-_multipath_config-udev-and.patch -Patch0085: 0085-Revert-libmultipath-add-ignore_udev_uid-option.patch -Patch0086: 0086-libmultipath-change-log-level-for-null-uid_attribute.patch -Patch0087: 0087-libmultipath-orphan_paths-avoid-BUG-message.patch +Patch0001: 0001-Change-the-multipath.conf-manpage-uxsock_timeout-def.patch +Patch0002: 0002-libmultipath-find_mpe-don-t-match-with-empty-WWID.patch +Patch0003: 0003-libmultipath-copy-mpp-hwe-from-pp-hwe.patch +Patch0004: 0004-libmultipath-dm_map_present_by_uuid-fix-dm_task_crea.patch +Patch0005: 0005-libdmmp-tests-fix-compilation.patch +Patch0006: 0006-libmultipath-prio-constify-some-function-parameters.patch +Patch0007: 0007-libmultipath-checkers-prio-allow-non-lazy-.so-loadin.patch +Patch0008: 0008-multipath-tools-Makefiles-separate-rules-for-.so-and.patch +Patch0009: 0009-libmultipath-create-separate-.so-for-unit-tests.patch +Patch0010: 0010-libmultipath-add-linker-version-script.patch +Patch0011: 0011-libmpathpersist-add-linker-version-script.patch +Patch0012: 0012-libmpathcmd-add-linker-version-script.patch +Patch0013: 0013-libmpathpersist-initialize-mpp-hwe-in-get_mpvec.patch +Patch0014: 0014-multipathd-allow-shutdown-during-configure.patch +Patch0015: 0015-multipathd-avoid-sending-READY-1-to-systemd-on-early.patch +Patch0016: 0016-multipathd-send-STOPPING-1-to-systemd-on-shutdown.patch +Patch0017: 0017-multipathd-send-RELOADING-1-to-systemd-on-DAEMON_CON.patch +Patch0018: 0018-multipathd-use-volatile-qualifier-for-running_state.patch +Patch0019: 0019-multipathd-generalize-and-fix-wait_for_state_change_.patch +Patch0020: 0020-multipathd-set_config_state-avoid-code-duplication.patch +Patch0021: 0021-multipathd-cancel-threads-early-during-shutdown.patch +Patch0022: 0022-multipath-tools-don-t-call-dm_lib_release-any-more.patch +Patch0023: 0023-libmultipath-devmapper-refactor-libdm-version-determ.patch +Patch0024: 0024-libmultipath-protect-racy-libdevmapper-calls-with-a-.patch +Patch0025: 0025-libmultipath-constify-file-argument-in-config-parser.patch +Patch0026: 0026-libmultipath-provide-defaults-for-get-put-_multipath.patch +Patch0027: 0027-libmpathpersist-allow-using-libmultipath-get-put-_mu.patch +Patch0028: 0028-multipath-use-get_put-_multipath_config-from-libmult.patch +Patch0029: 0029-mpathpersist-use-get-put-_multipath_config-from-libm.patch +Patch0030: 0030-libmultipath-add-udev-and-logsink-symbols.patch +Patch0031: 0031-multipath-remove-logsink-and-udev.patch +Patch0032: 0032-libmpathpersist-call-libmultipath_-init-exit.patch +Patch0033: 0033-mpathpersist-remove-logsink-and-udev.patch +Patch0034: 0034-multipathd-remove-logsink-and-udev.patch +Patch0035: 0035-multipath-tools-add-Vexata-by-StorCentric-VX-arrays.patch +Patch0036: 0036-multipath-tools-Violin-and-Nexsan-were-bought-by-Sto.patch +Patch0037: 0037-libmultipath-fix-memory-leaks-in-coalesce_paths.patch +Patch0038: 0038-multipath-tools-replace-hidden-tab-by-space-in-hwtab.patch +Patch0039: 0039-multipathd-uxlsnr-avoid-deadlock-on-exit.patch +Patch0040: 0040-multipathd-Fix-liburcu-memory-leak.patch +Patch0041: 0041-multipathd-move-handling-of-io_err_stat_attr-into-li.patch +Patch0042: 0042-multipathd-move-vecs-desctruction-into-cleanup-funct.patch +Patch0043: 0043-multipathd-make-some-globals-static.patch +Patch0044: 0044-multipathd-move-threads-destruction-into-separate-fu.patch +Patch0045: 0045-multipathd-move-conf-destruction-into-separate-funct.patch +Patch0046: 0046-multipathd-move-pid-destruction-into-separate-functi.patch +Patch0047: 0047-multipathd-close-pidfile-on-exit.patch +Patch0048: 0048-multipathd-add-helper-for-systemd-notification-at-ex.patch +Patch0049: 0049-multipathd-child-call-cleanups-in-failure-case-too.patch +Patch0050: 0050-multipathd-unwatch_all_dmevents-check-if-waiter-is-i.patch +Patch0051: 0051-multipathd-print-error-message-if-config-can-t-be-lo.patch +Patch0052: 0052-libmultipath-add-libmp_dm_exit.patch +Patch0053: 0053-multipathd-fixup-libdm-deinitialization.patch +Patch0054: 0054-libmultipath-log_thread_stop-check-if-logarea-is-ini.patch +Patch0055: 0055-multipathd-add-cleanup_child-exit-handler.patch +Patch0056: 0056-libmultipath-fix-log_thread-startup-and-teardown.patch +Patch0057: 0057-multipathd-move-cleanup_-prio-checkers-foreign-to-li.patch +Patch0058: 0058-multipath-use-atexit-for-cleanup-handlers.patch +Patch0059: 0059-mpathpersist-use-atexit-for-cleanup-handlers.patch +Patch0060: 0060-multipath-fix-leak-in-check_path_valid.patch +Patch0061: 0061-multipath-tools-mpath-tools.supp-file-with-valgrind-.patch +Patch0062: 0062-libmultipath-use-libmp_verbosity-to-track-verbosity.patch +Patch0063: 0063-libmultipath-introduce-symbolic-values-for-logsink.patch +Patch0064: 0064-libmultipath-simplify-dlog.patch +Patch0065: 0065-multipathd-common-code-for-k-and-command-args.patch +Patch0066: 0066-multipathd-sanitize-uxsock_listen.patch +Patch0067: 0067-libmultipath-fix-race-between-log_safe-and-log_threa.patch +Patch0068: 0068-multipath-add-libmpathvalid-library.patch +Patch0069: 0069-multipath-tools-tests-and-unit-tests-for-libmpathval.patch +Patch0070: 0070-libmultipath-add-uid-failback-for-dasd-devices.patch +Patch0071: 0071-libmultipath-change-log-level-for-null-uid_attribute.patch +Patch0072: 0072-libmultipath-move-fast_io_fail-defines-to-structs.h.patch +Patch0073: 0073-libmultipath-add-eh_deadline-multipath.conf-paramete.patch +Patch0074: 0074-multipathd-remove-redundant-vector_free-int-configur.patch +Patch0075: 0075-libmultipath-factor-out-code-to-get-vpd-page-data.patch +Patch0076: 0076-libmultipath-limit-reading-0xc9-vpd-page.patch +Patch0077: 0077-libmultipath-move-logq_lock-handling-to-log.c.patch +Patch0078: 0078-libmultipath-protect-logarea-with-logq_lock.patch +Patch0079: 0079-libmultipath-prevent-DSO-unloading-with-astray-check.patch +Patch0080: 0080-libmultipath-force-map-reload-if-udev-incomplete.patch +Patch0081: 0081-multipath-tools-avoid-access-to-etc-localtime.patch +Patch0082: 0082-multipath-tools-make-sure-plugin-DSOs-use-symbol-ver.patch +Patch0083: 0083-libmultipath.version-add-missing-symbol.patch +Patch0084: 0084-multipath-tools-tests-unversioned-.so-for-valgrind-t.patch +Patch0085: 0085-multipath-tools-unit-tests-fix-memory-leaks-in-mpath.patch +Patch0086: 0086-mpathpersist-Fix-Register-and-Ignore-with-0x00-SARK.patch +Patch0087: 0087-mpathpersist-update-prkeys-file-on-changing-registra.patch +Patch0088: 0088-libmultipath-warn-about-missing-braces-at-end-of-mul.patch +Patch0089: 0089-libmultipath-ignore-multipaths-sections-without-wwid.patch +Patch0090: 0090-libmultipath-fix-format-warning-with-clang.patch +Patch0091: 0091-libmultipath-check-for-null-wwid-before-strcmp.patch +Patch0092: 0092-multipath.conf.5-Improve-checker_timeout-description.patch +Patch0093: 0093-multipathd-fix-path-checkint-not-changed-when-path-s.patch +Patch0094: 0094-libmultipath-select_action-skip-is_mpp_known_to_udev.patch +Patch0095: 0095-libmultipath-coalesce_paths-stop-triggering-spurious.patch +Patch0096: 0096-Revert-multipathd-uev_trigger-handle-incomplete-ADD-.patch +Patch0097: 0097-libmultipath-make-find_err_path_by_dev-static.patch +Patch0098: 0098-multipathd-avoid-io_err_stat-crash-during-shutdown.patch +Patch0099: 0099-multipathd-avoid-io_err_stat-ABBA-deadlock.patch +Patch0100: 0100-multipathd-use-get_monotonic_time-in-io_err_stat-cod.patch +Patch0101: 0101-multipathd-combine-free_io_err_stat_path-and-destroy.patch +Patch0102: 0102-multipathd-cleanup-logging-for-marginal-paths.patch +Patch0103: 0103-RH-fixup-udev-rules-for-redhat.patch +Patch0104: 0104-RH-Remove-the-property-blacklist-exception-builtin.patch +Patch0105: 0105-RH-don-t-start-without-a-config-file.patch +Patch0106: 0106-RH-Fix-nvme-function-missing-argument.patch +Patch0107: 0107-RH-use-rpm-optflags-if-present.patch +Patch0108: 0108-RH-add-mpathconf.patch +Patch0109: 0109-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +Patch0110: 0110-RH-reset-default-find_mutipaths-value-to-off.patch +Patch0111: 0111-RH-attempt-to-get-ANA-info-via-sysfs-first.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -124,6 +148,7 @@ BuildRequires: readline-devel, ncurses-devel BuildRequires: systemd-units, systemd-devel BuildRequires: json-c-devel, perl-interpreter, pkgconfig, gcc BuildRequires: userspace-rcu-devel +BuildRequires: make %description %{name} provides tools to manage multipath devices by @@ -179,7 +204,7 @@ This package contains the files needed to develop applications that use device-mapper-multipath's libdmmp C API library %prep -%autosetup -n multipath-tools-0.8.4 -p1 +%autosetup -n multipath-tools-0.8.5 -p1 cp %{SOURCE1} . %build @@ -237,14 +262,14 @@ fi %{_mandir}/man8/mpathpersist.8.gz %config /usr/lib/udev/rules.d/62-multipath.rules %config /usr/lib/udev/rules.d/11-dm-mpath.rules -%doc README +%doc README.md %doc README.alua %doc multipath.conf %dir /etc/multipath %files libs %license LICENSES/GPL-2.0 LICENSES/LGPL-2.0 -%doc README +%doc README.md %{_libdir}/libmultipath.so %{_libdir}/libmultipath.so.* %{_libdir}/libmpathpersist.so.* @@ -256,7 +281,7 @@ fi %ldconfig_scriptlets libs %files devel -%doc README +%doc README.md %{_libdir}/libmpathpersist.so %{_libdir}/libmpathcmd.so %{_libdir}/libmpathvalid.so @@ -268,7 +293,7 @@ fi %files -n kpartx %license LICENSES/GPL-2.0 -%doc README +%doc README.md %{_sbindir}/kpartx /usr/lib/udev/kpartx_id %{_mandir}/man8/kpartx.8.gz @@ -278,13 +303,13 @@ fi %files -n libdmmp %license LICENSES/GPL-3.0 -%doc README +%doc README.md %{_libdir}/libdmmp.so.* %ldconfig_scriptlets -n libdmmp %files -n libdmmp-devel -%doc README +%doc README.md %{_libdir}/libdmmp.so %dir %{_includedir}/libdmmp %{_includedir}/libdmmp/* @@ -293,6 +318,18 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Tue Jan 19 2021 Benjamin Marzinski - 0.8.5-2 +- Fix build issues + +* Tue Jan 19 2021 Benjamin Marzinski - 0.8.5-1 +- Update Source to upstream version 0.8.5 plus post tag commits + * Patches 0001-0102 are from + https://github.com/openSUSE/multipath-tools/tree/queue and are + already queued for upstream. +- Rename files + * Previous patches 0059-0068 are now patches 0103-0111 + + * Sun Sep 27 2020 Benjamin Marzinski - 0.8.4-7 - Add 0073-libmultipath-util-constify-function-arguments.patch - Add 0074-libmultipath-constify-file-argument-in-config-parser.patch diff --git a/sources b/sources index 1e028ad..cf508e4 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (multipath-tools-0.8.4.tgz) = 130308e61d6dce31085fc2763219f4df0f3ad9153e0e6e7a5a1c3c948a2305cff9413699025c28f9b81dd24d2a9263f9fa825253060e44232c3bb6600cd1f07f +SHA512 (multipath-tools-0.8.5.tgz) = 3b65f89621203304cdc0d074124627132f0a600c347f2eec03372463737493e3a7da38813d375c1f7d6fe2e55a7d4f7494574f74412534832f217954ba34c293 SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942