diff --git a/SOURCES/0062-libmultipath-select_action-don-t-drop-map-if-alias-c.patch b/SOURCES/0062-libmultipath-select_action-don-t-drop-map-if-alias-c.patch new file mode 100644 index 0000000..d34e9e3 --- /dev/null +++ b/SOURCES/0062-libmultipath-select_action-don-t-drop-map-if-alias-c.patch @@ -0,0 +1,45 @@ +From 7a7b96246b84ccf533a6f4dc0424830792fdb96a Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 3 Jul 2020 15:17:09 +0200 +Subject: [PATCH] libmultipath: select_action(): don't drop map if alias + clashes + +If for a given map, if we find that the requested alias is already +used by a map with different WWID, while the map's own WWID is +not used yet, give up the alias and use the WWID instead. This +is safer than trying to destroy the existing map, which is likely +to fail. + +This allows us to make use const for the "curmp" parameter. + +Reviewed-by: Benjamin Marzinski +--- + libmultipath/configure.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index b7113291..2e8f34f9 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -690,12 +690,13 @@ select_action (struct multipath * mpp, vector curmp, int force_reload) + } + + if (!cmpp) { +- condlog(2, "%s: remove (wwid changed)", mpp->alias); +- dm_flush_map(mpp->alias); +- strlcpy(cmpp_by_name->wwid, mpp->wwid, WWID_SIZE); +- drop_multipath(curmp, cmpp_by_name->wwid, KEEP_PATHS); ++ condlog(1, "%s: can't use alias \"%s\" used by %s, falling back to WWID", ++ mpp->wwid, mpp->alias, cmpp_by_name->wwid); ++ /* We can do this because wwid wasn't found */ ++ free(mpp->alias); ++ mpp->alias = strdup(mpp->wwid); + mpp->action = ACT_CREATE; +- condlog(3, "%s: set ACT_CREATE (map wwid change)", ++ condlog(3, "%s: set ACT_CREATE (map does not exist, name changed)", + mpp->alias); + return; + } +-- +2.17.2 + diff --git a/SOURCES/0063-libmultipath-check-if-user_friendly_name-is-in-use.patch b/SOURCES/0063-libmultipath-check-if-user_friendly_name-is-in-use.patch new file mode 100644 index 0000000..81947be --- /dev/null +++ b/SOURCES/0063-libmultipath-check-if-user_friendly_name-is-in-use.patch @@ -0,0 +1,231 @@ +From e714eb26fddc8768a8de279d1de3ffedab35929e Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 5 Mar 2021 21:40:57 -0600 +Subject: [PATCH] libmultipath: check if user_friendly_name is in use + +If there are multipath devices that have user_friendly_names but do not +have their bindings in the bindings_file, get_user_friendly_alias() can +currently give out those names again. This can result in an incorrect +entry in the bindings file, and a device that gets created with a WWID +alias instead of a user_friendly_name. This situation can happen after +the pivot root, if a multipath device is created in the initramfs. If +this device doesn't have a binding in the regular filesystem +bindings_file and a new multipath device is created before it can add +its binding, the new device can steal that user_friendly_name during +multipathd's initial configure. + +To solve this, get_user_friendly_alias() now calls lookup_binding() with +a new paramter, telling it to check if the id it found is already in use +by a diffent device. If so, lookup_binding() will continue to check open +ids, until it finds one that it not currently in use by a dm device. +--- + libmultipath/alias.c | 48 +++++++++++++++++++++++++++++++++++++++++--- + tests/alias.c | 22 ++++++++++---------- + 2 files changed, 56 insertions(+), 14 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 14401cae..01f737f4 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -17,6 +17,7 @@ + #include "vector.h" + #include "checkers.h" + #include "structs.h" ++#include "devmapper.h" + + + /* +@@ -104,6 +105,28 @@ scan_devname(const char *alias, const char *prefix) + return n; + } + ++static int ++id_already_taken(int id, const char *prefix, const char *map_wwid) ++{ ++ char alias[LINE_MAX]; ++ ++ if (format_devname(alias, id, LINE_MAX, prefix) < 0) ++ return 0; ++ ++ if (dm_map_present(alias)) { ++ char wwid[WWID_SIZE]; ++ ++ /* If both the name and the wwid match, then it's fine.*/ ++ if (dm_get_uuid(alias, wwid, sizeof(wwid)) == 0 && ++ strncmp(map_wwid, wwid, sizeof(wwid)) == 0) ++ return 0; ++ condlog(3, "%s: alias '%s' already taken, but not in bindings file. reselecting alias", map_wwid, alias); ++ return 1; ++ } ++ return 0; ++} ++ ++ + /* + * Returns: 0 if matching entry in WWIDs file found + * -1 if an error occurs +@@ -113,7 +136,7 @@ scan_devname(const char *alias, const char *prefix) + */ + static int + lookup_binding(FILE *f, const char *map_wwid, char **map_alias, +- const char *prefix) ++ const char *prefix, int check_if_taken) + { + char buf[LINE_MAX]; + unsigned int line_nr = 0; +@@ -168,12 +191,31 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias, + return 0; + } + } ++ if (!prefix && check_if_taken) ++ id = -1; + if (id >= smallest_bigger_id) { + if (biggest_id < INT_MAX) + id = biggest_id + 1; + else + id = -1; + } ++ if (id > 0 && check_if_taken) { ++ while(id_already_taken(id, prefix, map_wwid)) { ++ if (id == INT_MAX) { ++ id = -1; ++ break; ++ } ++ id++; ++ if (id == smallest_bigger_id) { ++ if (biggest_id == INT_MAX) { ++ id = -1; ++ break; ++ } ++ if (biggest_id >= smallest_bigger_id) ++ id = biggest_id + 1; ++ } ++ } ++ } + if (id < 0) { + condlog(0, "no more available user_friendly_names"); + return -1; +@@ -316,7 +358,7 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old, + goto out; + } + +- id = lookup_binding(f, wwid, &alias, NULL); ++ id = lookup_binding(f, wwid, &alias, NULL, 0); + if (alias) { + condlog(3, "Use existing binding [%s] for WWID [%s]", + alias, wwid); +@@ -373,7 +415,7 @@ get_user_friendly_alias(const char *wwid, const char *file, const char *prefix, + return NULL; + } + +- id = lookup_binding(f, wwid, &alias, prefix); ++ id = lookup_binding(f, wwid, &alias, prefix, 1); + if (id < 0) { + fclose(f); + return NULL; +diff --git a/tests/alias.c b/tests/alias.c +index 30414db0..ab1a9325 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -356,7 +356,7 @@ static void lb_empty(void **state) + + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID0", &alias, NULL); ++ rc = lookup_binding(NULL, "WWID0", &alias, NULL, 0); + assert_int_equal(rc, 1); + assert_ptr_equal(alias, NULL); + } +@@ -369,7 +369,7 @@ static void lb_match_a(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + expect_condlog(3, "Found matching wwid [WWID0] in bindings file." + " Setting alias to MPATHa\n"); +- rc = lookup_binding(NULL, "WWID0", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 0); + assert_int_equal(rc, 0); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHa"); +@@ -384,7 +384,7 @@ static void lb_nomatch_a(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID1] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID1", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } +@@ -398,7 +398,7 @@ static void lb_match_c(void **state) + will_return(__wrap_fgets, "MPATHc WWID1\n"); + expect_condlog(3, "Found matching wwid [WWID1] in bindings file." + " Setting alias to MPATHc\n"); +- rc = lookup_binding(NULL, "WWID1", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0); + assert_int_equal(rc, 0); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHc"); +@@ -414,7 +414,7 @@ static void lb_nomatch_a_c(void **state) + will_return(__wrap_fgets, "MPATHc WWID1\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } +@@ -428,7 +428,7 @@ static void lb_nomatch_c_a(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } +@@ -443,7 +443,7 @@ static void lb_nomatch_a_b(void **state) + will_return(__wrap_fgets, "MPATHb WWID1\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); + } +@@ -459,7 +459,7 @@ static void lb_nomatch_a_b_bad(void **state) + will_return(__wrap_fgets, NULL); + expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); + expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); + } +@@ -474,7 +474,7 @@ static void lb_nomatch_b_a(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 27); + assert_ptr_equal(alias, NULL); + } +@@ -490,7 +490,7 @@ static void lb_nomatch_int_max(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(0, "no more available user_friendly_names\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); + } +@@ -505,7 +505,7 @@ static void lb_nomatch_int_max_m1(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, INT_MAX); + assert_ptr_equal(alias, NULL); + } +-- +2.17.2 + diff --git a/SPECS/device-mapper-multipath.spec b/SPECS/device-mapper-multipath.spec index 0876147..5104f8f 100644 --- a/SPECS/device-mapper-multipath.spec +++ b/SPECS/device-mapper-multipath.spec @@ -1,7 +1,7 @@ Summary: Tools to manage multipath devices using device-mapper Name: device-mapper-multipath Version: 0.8.4 -Release: 9%{?dist} +Release: 10%{?dist} License: GPLv2 Group: System Environment/Base URL: http://christophe.varoqui.free.fr/ @@ -72,6 +72,8 @@ Patch00058: 0058-multipathd-cleanup-logging-for-marginal-paths.patch Patch00059: 0059-libmpathpersist-fix-thread-safety-of-default-functio.patch Patch00060: 0060-kpartx-free-loop-device-after-listing-partitions.patch Patch00061: 0061-RH-fix-find_multipaths-in-mpathconf.patch +Patch00062: 0062-libmultipath-select_action-don-t-drop-map-if-alias-c.patch +Patch00063: 0063-libmultipath-check-if-user_friendly_name-is-in-use.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -273,6 +275,15 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Sun Mar 7 2021 Benjamin Marzinski 0.8.4-10 +- Add 0062-libmultipath-select_action-don-t-drop-map-if-alias-c.patch + * Fall back to WWID names instead of removing existing device +- Add 0063-libmultipath-check-if-user_friendly_name-is-in-use.patch + * make sure to choose a user_friendly_name that isn't in use + * Fixes bz #1923777 +- Add alias_clash CI test +- Resolves: bz #1923777 + * Wed Feb 10 2021 Benjamin Marzinski 0.8.4-9 - Add 0060-kpartx-free-loop-device-after-listing-partitions.patch * Fixes bz #1925490