diff --git a/.gitignore b/.gitignore index 18226b9..75c4abc 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ multipath-tools-091027.tar.gz /multipath-tools-0.9.3.tgz /multipath-tools-0.9.4.tgz /multipath-tools-0.9.5.tgz +/multipath-tools-0.9.6.tgz diff --git a/0001-libmultipath-sysfs_set_scsi_tmo-do-nothing-for-ACT_D.patch b/0001-libmultipath-sysfs_set_scsi_tmo-do-nothing-for-ACT_D.patch new file mode 100644 index 0000000..9b8a486 --- /dev/null +++ b/0001-libmultipath-sysfs_set_scsi_tmo-do-nothing-for-ACT_D.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 16:21:43 +0200 +Subject: [PATCH] libmultipath: sysfs_set_scsi_tmo: do nothing for ACT_DRY_RUN + +"multipath -d" might change sysfs timeouts of SCSI devices. +Make sure it doesn't. + +Signed-off-by: Martin Wilck +Cc: Jehan Singh +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 4 ++-- + libmultipath/discovery.c | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 9513baae..029fbbd2 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1193,13 +1193,13 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, + + if (cmpp) + mpp->queue_mode = cmpp->queue_mode; ++ if (cmd == CMD_DRY_RUN && mpp->action == ACT_UNDEF) ++ mpp->action = ACT_DRY_RUN; + if (setup_map(mpp, ¶ms, vecs)) { + remove_map(mpp, vecs->pathvec, NULL); + continue; + } + +- if (cmd == CMD_DRY_RUN) +- mpp->action = ACT_DRY_RUN; + if (mpp->action == ACT_UNDEF) + select_action(mpp, curmp, + force_reload == FORCE_RELOAD_YES ? 1 : 0); +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index e4de48e7..84ce5fe7 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -857,6 +857,9 @@ sysfs_set_scsi_tmo (struct config *conf, struct multipath *mpp) + bool warn_dev_loss = false; + bool warn_fast_io_fail = false; + ++ if (mpp->action == ACT_DRY_RUN || mpp->action == ACT_REJECT) ++ return 0; ++ + if (mpp->no_path_retry > 0) { + uint64_t no_path_retry_tmo = + (uint64_t)mpp->no_path_retry * conf->checkint; diff --git a/0002-libmultipath-add-alias_already_taken.patch b/0002-libmultipath-add-alias_already_taken.patch new file mode 100644 index 0000000..8ed3c7b --- /dev/null +++ b/0002-libmultipath-add-alias_already_taken.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 21:36:11 +0200 +Subject: [PATCH] libmultipath: add alias_already_taken() + +Factor out a trivial helper function. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 32 +++++++++++++++++++------------- + 1 file changed, 19 insertions(+), 13 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index c0139a2e..83ded886 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "debug.h" + #include "util.h" +@@ -109,30 +110,35 @@ scan_devname(const char *alias, const char *prefix) + return n; + } + +-static int +-id_already_taken(int id, const char *prefix, const char *map_wwid) ++static bool alias_already_taken(const char *alias, const char *map_wwid) + { +- STRBUF_ON_STACK(buf); +- const char *alias; +- +- if (append_strbuf_str(&buf, prefix) < 0 || +- format_devname(&buf, id) < 0) +- return 0; + +- alias = get_strbuf_str(&buf); + 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 false; ++ condlog(3, "%s: alias '%s' already taken, but not in bindings file. reselecting alias", ++ map_wwid, alias); ++ return true; + } +- return 0; ++ return false; + } + ++static bool id_already_taken(int id, const char *prefix, const char *map_wwid) ++{ ++ STRBUF_ON_STACK(buf); ++ const char *alias; ++ ++ if (append_strbuf_str(&buf, prefix) < 0 || ++ format_devname(&buf, id) < 0) ++ return false; ++ ++ alias = get_strbuf_str(&buf); ++ return alias_already_taken(alias, map_wwid); ++} + + /* + * Returns: 0 if matching entry in WWIDs file found diff --git a/0003-libmultipath-unify-use_existing_alias-and-get_user_f.patch b/0003-libmultipath-unify-use_existing_alias-and-get_user_f.patch new file mode 100644 index 0000000..5beb1fe --- /dev/null +++ b/0003-libmultipath-unify-use_existing_alias-and-get_user_f.patch @@ -0,0 +1,207 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 22:00:58 +0200 +Subject: [PATCH] libmultipath: unify use_existing_alias() and + get_user_friendly_alias() + +These functions are only called from select_alias(). The logic +is more obvious when unified in a single function. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 82 ++++++++++++------------------------------ + libmultipath/alias.h | 9 ++--- + libmultipath/propsel.c | 19 +++++----- + 3 files changed, 34 insertions(+), 76 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 83ded886..68f5d848 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -329,13 +329,13 @@ allocate_binding(int fd, const char *wwid, int id, const char *prefix) + return alias; + } + +-char * +-use_existing_alias (const char *wwid, const char *file, const char *alias_old, +- const char *prefix, int bindings_read_only) ++char *get_user_friendly_alias(const char *wwid, const char *file, const char *alias_old, ++ const char *prefix, bool bindings_read_only) + { + char *alias = NULL; + int id = 0; + int fd, can_write; ++ bool new_binding = false; + char buff[WWID_SIZE]; + FILE *f; + +@@ -349,6 +349,10 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old, + close(fd); + return NULL; + } ++ ++ if (!strlen(alias_old)) ++ goto new_alias; ++ + /* lookup the binding. if it exists, the wwid will be in buff + * either way, id contains the id for the alias + */ +@@ -358,14 +362,14 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old, + /* if buff is our wwid, it's already + * allocated correctly + */ +- if (strcmp(buff, wwid) == 0) ++ if (strcmp(buff, wwid) == 0) { + alias = strdup(alias_old); +- else { +- alias = NULL; ++ goto out; ++ } else { + condlog(0, "alias %s already bound to wwid %s, cannot reuse", + alias_old, buff); ++ goto new_alias; + } +- goto out; + } + + id = lookup_binding(f, wwid, &alias, NULL, 0); +@@ -377,8 +381,15 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old, + + /* allocate the existing alias in the bindings file */ + id = scan_devname(alias_old, prefix); +- if (id <= 0) +- goto out; ++ ++new_alias: ++ if (id <= 0) { ++ id = lookup_binding(f, wwid, &alias, prefix, 1); ++ if (id <= 0) ++ goto out; ++ else ++ new_binding = true; ++ } + + if (fflush(f) != 0) { + condlog(0, "cannot fflush bindings file stream : %s", +@@ -388,8 +399,9 @@ use_existing_alias (const char *wwid, const char *file, const char *alias_old, + + if (can_write && !bindings_read_only) { + alias = allocate_binding(fd, wwid, id, prefix); +- condlog(0, "Allocated existing binding [%s] for WWID [%s]", +- alias, wwid); ++ if (alias && !new_binding) ++ condlog(2, "Allocated existing binding [%s] for WWID [%s]", ++ alias, wwid); + } + + out: +@@ -399,54 +411,6 @@ out: + return alias; + } + +-char * +-get_user_friendly_alias(const char *wwid, const char *file, const char *prefix, +- int bindings_read_only) +-{ +- char *alias; +- int fd, id; +- FILE *f; +- int can_write; +- +- if (!wwid || *wwid == '\0') { +- condlog(3, "Cannot find binding for empty WWID"); +- return NULL; +- } +- +- fd = open_file(file, &can_write, bindings_file_header); +- if (fd < 0) +- return NULL; +- +- f = fdopen(fd, "r"); +- if (!f) { +- condlog(0, "cannot fdopen on bindings file descriptor : %s", +- strerror(errno)); +- close(fd); +- return NULL; +- } +- +- id = lookup_binding(f, wwid, &alias, prefix, 1); +- if (id < 0) { +- fclose(f); +- return NULL; +- } +- +- pthread_cleanup_push(free, alias); +- +- if (fflush(f) != 0) { +- condlog(0, "cannot fflush bindings file stream : %s", +- strerror(errno)); +- free(alias); +- alias = NULL; +- } else if (can_write && !bindings_read_only && !alias) +- alias = allocate_binding(fd, wwid, id, prefix); +- +- fclose(f); +- +- pthread_cleanup_pop(0); +- return alias; +-} +- + int + get_user_friendly_wwid(const char *alias, char *buff, const char *file) + { +diff --git a/libmultipath/alias.h b/libmultipath/alias.h +index dbc950c4..fa332233 100644 +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -2,13 +2,10 @@ + #define _ALIAS_H + + int valid_alias(const char *alias); +-char *get_user_friendly_alias(const char *wwid, const char *file, +- const char *prefix, +- int bindings_readonly); + int get_user_friendly_wwid(const char *alias, char *buff, const char *file); +-char *use_existing_alias (const char *wwid, const char *file, +- const char *alias_old, +- const char *prefix, int bindings_read_only); ++char *get_user_friendly_alias(const char *wwid, const char *file, ++ const char *alias_old, ++ const char *prefix, bool bindings_read_only); + + struct config; + int check_alias_settings(const struct config *); +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index d6bce129..354e883f 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -401,19 +401,16 @@ int select_alias(struct config *conf, struct multipath * mp) + + select_alias_prefix(conf, mp); + +- if (strlen(mp->alias_old) > 0) { +- mp->alias = use_existing_alias(mp->wwid, conf->bindings_file, +- mp->alias_old, mp->alias_prefix, +- conf->bindings_read_only); +- memset (mp->alias_old, 0, WWID_SIZE); +- origin = "(setting: using existing alias)"; +- } ++ mp->alias = get_user_friendly_alias(mp->wwid, conf->bindings_file, ++ mp->alias_old, mp->alias_prefix, ++ conf->bindings_read_only); + +- if (mp->alias == NULL) { +- mp->alias = get_user_friendly_alias(mp->wwid, +- conf->bindings_file, mp->alias_prefix, conf->bindings_read_only); ++ if (mp->alias && !strncmp(mp->alias, mp->alias_old, WWID_SIZE)) ++ origin = "(setting: using existing alias)"; ++ else if (mp->alias) + origin = "(setting: user_friendly_name)"; +- } ++ memset (mp->alias_old, 0, WWID_SIZE); ++ + out: + if (mp->alias == NULL) { + mp->alias = strdup(mp->wwid); diff --git a/0004-libmultipath-never-allocate-an-alias-that-s-already-.patch b/0004-libmultipath-never-allocate-an-alias-that-s-already-.patch new file mode 100644 index 0000000..3d05b85 --- /dev/null +++ b/0004-libmultipath-never-allocate-an-alias-that-s-already-.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 22:23:29 +0200 +Subject: [PATCH] libmultipath: never allocate an alias that's already taken + +If the bindings file is changed in a way that multipathd can't handle +(e.g. by swapping the aliases of two maps), multipathd must not try +to re-use an alias that is already used by another map. Creating +or renaming a map with such an alias will fail. We already avoid +this for some cases, but not for all. Fix it. + +Signed-off-by: Martin Wilck +Cc: David Bond +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 31 +++++++++++++++++++++++-------- + tests/alias.c | 2 +- + 2 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 68f5d848..3e3dfe98 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -120,7 +120,7 @@ static bool alias_already_taken(const char *alias, const char *map_wwid) + if (dm_get_uuid(alias, wwid, sizeof(wwid)) == 0 && + strncmp(map_wwid, wwid, sizeof(wwid)) == 0) + return false; +- condlog(3, "%s: alias '%s' already taken, but not in bindings file. reselecting alias", ++ condlog(3, "%s: alias '%s' already taken, reselecting alias", + map_wwid, alias); + return true; + } +@@ -359,12 +359,11 @@ char *get_user_friendly_alias(const char *wwid, const char *file, const char *al + rlookup_binding(f, buff, alias_old); + + if (strlen(buff) > 0) { +- /* if buff is our wwid, it's already +- * allocated correctly +- */ ++ /* If buff is our wwid, it's already allocated correctly. */ + if (strcmp(buff, wwid) == 0) { + alias = strdup(alias_old); + goto out; ++ + } else { + condlog(0, "alias %s already bound to wwid %s, cannot reuse", + alias_old, buff); +@@ -372,19 +371,35 @@ char *get_user_friendly_alias(const char *wwid, const char *file, const char *al + } + } + +- id = lookup_binding(f, wwid, &alias, NULL, 0); ++ /* ++ * Look for an existing alias in the bindings file. ++ * Pass prefix = NULL, so lookup_binding() won't try to allocate a new id. ++ */ ++ lookup_binding(f, wwid, &alias, NULL, 0); + if (alias) { +- condlog(3, "Use existing binding [%s] for WWID [%s]", +- alias, wwid); ++ if (alias_already_taken(alias, wwid)) { ++ free(alias); ++ alias = NULL; ++ } else ++ condlog(3, "Use existing binding [%s] for WWID [%s]", ++ alias, wwid); + goto out; + } + +- /* allocate the existing alias in the bindings file */ ++ /* alias_old is already taken by our WWID, update bindings file. */ + id = scan_devname(alias_old, prefix); + + new_alias: + if (id <= 0) { ++ /* ++ * no existing alias was provided, or allocating it ++ * failed. Try a new one. ++ */ + id = lookup_binding(f, wwid, &alias, prefix, 1); ++ if (id == 0 && alias_already_taken(alias, wwid)) { ++ free(alias); ++ alias = NULL; ++ } + if (id <= 0) + goto out; + else +diff --git a/tests/alias.c b/tests/alias.c +index 3ca6c28b..11f209e0 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -398,7 +398,7 @@ static void mock_self_alias(const char *alias, const char *wwid) + will_return(__wrap_dm_get_uuid, wwid); + } + +-#define USED_STR(alias_str, wwid_str) wwid_str ": alias '" alias_str "' already taken, but not in bindings file. reselecting alias\n" ++#define USED_STR(alias_str, wwid_str) wwid_str ": alias '" alias_str "' already taken, reselecting alias\n" + + static void mock_failed_alias(const char *alias, char *msg) + { diff --git a/0005-libmultipath-lookup_binding-add-comment-about-the-al.patch b/0005-libmultipath-lookup_binding-add-comment-about-the-al.patch new file mode 100644 index 0000000..71d077a --- /dev/null +++ b/0005-libmultipath-lookup_binding-add-comment-about-the-al.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 22:30:16 +0200 +Subject: [PATCH] libmultipath: lookup_binding: add comment about the algorithm + +When I read this code, I always get confused. Adding comments to +explain the algorithm. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 3e3dfe98..9e9ac563 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -172,6 +172,41 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias, + alias = strtok_r(buf, " \t", &saveptr); + if (!alias) /* blank line */ + continue; ++ ++ /* ++ * Find an unused index - explanation of the algorithm ++ * ++ * ID: 1 = mpatha, 2 = mpathb, ... ++ * ++ * We assume the bindings are unsorted. The only constraint ++ * is that no ID occurs more than once. IDs that occur in the ++ * bindings are called "used". ++ * ++ * We call the list 1,2,3,..., exactly in this order, the list ++ * of "expected" IDs. The variable "id" always holds the next ++ * "expected" ID, IOW the last "expected" ID encountered plus 1. ++ * Thus all IDs below "id" are known to be used. However, at the ++ * end of the loop, the value of "id" isn't necessarily unused. ++ * ++ * "smallest_bigger_id" is the smallest used ID that was ++ * encountered while it was larger than the next "expected" ID ++ * at that iteration. Let X be some used ID. If all IDs below X ++ * are used and encountered in the right sequence before X, "id" ++ * will be > X when the loop ends. Otherwise, X was encountered ++ * "out of order", the condition (X > id) holds when X is ++ * encountered, and "smallest_bigger_id" will be set to X; i.e. ++ * it will be less or equal than X when the loop ends. ++ * ++ * At the end of the loop, (id < smallest_bigger_id) means that ++ * the value of "id" had been encountered neither in order nor ++ * out of order, and is thus unused. (id >= smallest_bigger_id) ++ * means that "id"'s value is in use. In this case, we play safe ++ * and use "biggest_id + 1" as the next value to try. ++ * ++ * biggest_id is always > smallest_bigger_id, except in the ++ * "perfectly ordered" case. ++ */ ++ + curr_id = scan_devname(alias, prefix); + if (curr_id == id) { + if (id < INT_MAX) diff --git a/0006-multipath-tools-test-simplify-debugging-for-condlog-.patch b/0006-multipath-tools-test-simplify-debugging-for-condlog-.patch new file mode 100644 index 0000000..a206358 --- /dev/null +++ b/0006-multipath-tools-test-simplify-debugging-for-condlog-.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Aug 2023 22:56:41 +0200 +Subject: [PATCH] multipath-tools test: simplify debugging for condlog mismatch + +If there's a mismatch between expected and actual log message, +print both messages. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/test-log.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tests/test-log.c b/tests/test-log.c +index c1745872..63516999 100644 +--- a/tests/test-log.c ++++ b/tests/test-log.c +@@ -16,12 +16,14 @@ void __wrap_dlog (int prio, const char * fmt, ...) + va_list ap; + char *expected; + +- check_expected(prio); + va_start(ap, fmt); + vsnprintf(buff, MAX_MSG_SIZE, fmt, ap); + va_end(ap); + fprintf(stderr, "%s(%d): %s", __func__, prio, buff); + expected = mock_ptr_type(char *); ++ if (memcmp(expected, buff, strlen(expected))) ++ fprintf(stderr, "%s(expected): %s", __func__, expected); ++ check_expected(prio); + assert_memory_equal(buff, expected, strlen(expected)); + } + diff --git a/0007-multipath-tools-tests-add-tests-for-get_user_friendl.patch b/0007-multipath-tools-tests-add-tests-for-get_user_friendl.patch new file mode 100644 index 0000000..f829db4 --- /dev/null +++ b/0007-multipath-tools-tests-add-tests-for-get_user_friendl.patch @@ -0,0 +1,493 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Wed, 23 Aug 2023 22:57:29 +0200 +Subject: [PATCH] multipath-tools tests: add tests for + get_user_friendly_alias() + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 441 insertions(+) + +diff --git a/tests/alias.c b/tests/alias.c +index 11f209e0..7e443b06 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -81,6 +81,35 @@ int __wrap_dm_get_uuid(const char *name, char *uuid, int uuid_len) + return ret; + } + ++#define TEST_FDNO 1234 ++#define TEST_FPTR ((FILE *) 0xaffe) ++ ++int __wrap_open_file(const char *file, int *can_write, const char *header) ++{ ++ int cw = mock_type(int); ++ ++ *can_write = cw; ++ return TEST_FDNO; ++} ++ ++FILE *__wrap_fdopen(int fd, const char *mode) ++{ ++ assert_int_equal(fd, TEST_FDNO); ++ return TEST_FPTR; ++} ++ ++int __wrap_fflush(FILE *f) ++{ ++ assert_ptr_equal(f, TEST_FPTR); ++ return 0; ++} ++ ++int __wrap_fclose(FILE *f) ++{ ++ assert_ptr_equal(f, TEST_FPTR); ++ return 0; ++} ++ + /* strbuf wrapper for the old format_devname() */ + static int __format_devname(char *name, int id, size_t len, const char *prefix) + { +@@ -399,6 +428,22 @@ static void mock_self_alias(const char *alias, const char *wwid) + } + + #define USED_STR(alias_str, wwid_str) wwid_str ": alias '" alias_str "' already taken, reselecting alias\n" ++#define NOMATCH_STR(alias_str) ("No matching alias [" alias_str "] in bindings file.\n") ++#define FOUND_STR(alias_str, wwid_str) \ ++ "Found matching wwid [" wwid_str "] in bindings file." \ ++ " Setting alias to " alias_str "\n" ++#define FOUND_ALIAS_STR(alias_str, wwid_str) \ ++ "Found matching alias [" alias_str "] in bindings file." \ ++ " Setting wwid to " wwid_str "\n" ++#define NOMATCH_WWID_STR(wwid_str) ("No matching wwid [" wwid_str "] in bindings file.\n") ++#define NEW_STR(alias_str, wwid_str) ("Created new binding [" alias_str "] for WWID [" wwid_str "]\n") ++#define EXISTING_STR(alias_str, wwid_str) ("Use existing binding [" alias_str "] for WWID [" wwid_str "]\n") ++#define ALLOC_STR(alias_str, wwid_str) ("Allocated existing binding [" alias_str "] for WWID [" wwid_str "]\n") ++#define BINDING_STR(alias_str, wwid_str) (alias_str " " wwid_str "\n") ++#define BOUND_STR(alias_str, wwid_str) ("alias "alias_str " already bound to wwid " wwid_str ", cannot reuse") ++#define ERR_STR(alias_str, wwid_str) ("ERROR: old alias [" alias_str "] for wwid [" wwid_str "] is used by other map\n") ++#define REUSE_STR(alias_str, wwid_str) ("alias " alias_str " already bound to wwid " wwid_str ", cannot reuse\n") ++#define NOMORE_STR "no more available user_friendly_names\n" + + static void mock_failed_alias(const char *alias, char *msg) + { +@@ -421,6 +466,24 @@ static void mock_used_alias(const char *alias, char *msg) + expect_condlog(3, msg); + } + ++static void mock_bindings_file(const char *content, int match_line) ++{ ++ static char cnt[1024]; ++ char *token; ++ int i; ++ ++ assert_in_range(strlcpy(cnt, content, sizeof(cnt)), 0, sizeof(cnt) - 1); ++ ++ for (token = strtok(cnt, "\n"), i = 0; ++ token && *token; ++ token = strtok(NULL, "\n"), i++) { ++ will_return(__wrap_fgets, token); ++ if (match_line == i) ++ return; ++ } ++ will_return(__wrap_fgets, NULL); ++} ++ + static void lb_empty(void **state) + { + int rc; +@@ -1147,6 +1210,382 @@ static int test_allocate_binding(void) + return cmocka_run_group_tests(tests, NULL, NULL); + } + ++#define mock_allocate_binding(alias, wwid) \ ++ do { \ ++ static const char ln[] = BINDING_STR(alias, wwid); \ ++ \ ++ will_return(__wrap_lseek, 0); \ ++ expect_value(__wrap_write, count, strlen(ln)); \ ++ expect_string(__wrap_write, buf, ln); \ ++ will_return(__wrap_write, strlen(ln)); \ ++ expect_condlog(3, NEW_STR(alias, wwid)); \ ++ } while (0) ++ ++static void gufa_empty_new_rw(void **state) { ++ char *alias; ++ ++ will_return(__wrap_open_file, true); ++ ++ will_return(__wrap_fgets, NULL); ++ mock_unused_alias("MPATHa"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ ++ mock_allocate_binding("MPATHa", "WWID0"); ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHa"); ++ free(alias); ++} ++ ++static void gufa_empty_new_ro_1(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, false); ++ will_return(__wrap_fgets, NULL); ++ mock_unused_alias("MPATHa"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void gufa_empty_new_ro_2(void **state) { ++ char *alias; ++ ++ will_return(__wrap_open_file, true); ++ ++ will_return(__wrap_fgets, NULL); ++ mock_unused_alias("MPATHa"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void gufa_match_a_unused(void **state) { ++ char *alias; ++ ++ will_return(__wrap_open_file, true); ++ ++ will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); ++ expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); ++ mock_unused_alias("MPATHa"); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ assert_string_equal(alias, "MPATHa"); ++ free(alias); ++} ++ ++static void gufa_match_a_self(void **state) { ++ char *alias; ++ ++ will_return(__wrap_open_file, true); ++ ++ will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); ++ expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); ++ mock_self_alias("MPATHa", "WWID0"); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ assert_string_equal(alias, "MPATHa"); ++ free(alias); ++} ++ ++static void gufa_match_a_used(void **state) { ++ char *alias; ++ ++ will_return(__wrap_open_file, true); ++ ++ will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); ++ expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void gufa_nomatch_a_c(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHc WWID2", ++ -1); ++ mock_unused_alias("MPATHb"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); ++ ++ mock_allocate_binding("MPATHb", "WWID1"); ++ ++ alias = get_user_friendly_alias("WWID1", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHb"); ++ free(alias); ++} ++ ++static void gufa_nomatch_c_a(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file("MPATHc WWID2\n" ++ "MPATHa WWID0", ++ -1); ++ mock_unused_alias("MPATHb"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); ++ ++ mock_allocate_binding("MPATHb", "WWID1"); ++ ++ alias = get_user_friendly_alias("WWID1", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHb"); ++ free(alias); ++} ++ ++static void gufa_nomatch_c_b(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file("MPATHc WWID2\n" ++ "MPATHb WWID1\n", ++ -1); ++ mock_unused_alias("MPATHa"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ ++ mock_allocate_binding("MPATHa", "WWID0"); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHa"); ++ free(alias); ++} ++ ++static void gufa_nomatch_c_b_used(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file("MPATHc WWID2\n" ++ "MPATHb WWID1", ++ -1); ++ mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID4")); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID4")); ++ mock_unused_alias("MPATHd"); ++ ++ mock_allocate_binding("MPATHd", "WWID4"); ++ ++ alias = get_user_friendly_alias("WWID4", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHd"); ++ free(alias); ++} ++ ++static void gufa_nomatch_b_f_a(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATHf WWID6\n" ++ "MPATHa WWID0\n", ++ -1); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID7")); ++ mock_unused_alias("MPATHg"); ++ ++ mock_allocate_binding("MPATHg", "WWID7"); ++ ++ alias = get_user_friendly_alias("WWID7", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHg"); ++ free(alias); ++} ++ ++static void gufa_old_empty(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ /* rlookup_binding for ALIAS */ ++ will_return(__wrap_fgets, NULL); ++ expect_condlog(3, NOMATCH_STR("MPATHz")); ++ ++ /* lookup_binding */ ++ will_return(__wrap_fgets, NULL); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ ++ mock_allocate_binding("MPATHz", "WWID0"); ++ expect_condlog(2, ALLOC_STR("MPATHz", "WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHz"); ++ free(alias); ++} ++ ++static void gufa_old_match(void **state) { ++ char *alias; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATHz WWID0", ++ 1); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHz"); ++ free(alias); ++} ++ ++static void gufa_old_match_other(void **state) { ++ char *alias; ++ static const char bindings[] = "MPATHz WWID9"; ++ ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, 0); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); ++ expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); ++ ++ mock_bindings_file(bindings, -1); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ mock_unused_alias("MPATHa"); ++ ++ mock_allocate_binding("MPATHa", "WWID0"); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHa"); ++ free(alias); ++} ++ ++static void gufa_old_match_other_used(void **state) { ++ char *alias; ++ static const char bindings[] = "MPATHz WWID9"; ++ ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, 0); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); ++ expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); ++ ++ mock_bindings_file(bindings, -1); ++ mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ mock_unused_alias("MPATHb"); ++ ++ mock_allocate_binding("MPATHb", "WWID0"); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHb"); ++ free(alias); ++} ++ ++static void gufa_old_match_other_wwidmatch(void **state) { ++ char *alias; ++ static const char bindings[] = ("MPATHz WWID9\n" ++ "MPATHc WWID2"); ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, 0); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); ++ expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); ++ ++ mock_bindings_file(bindings, 1); ++ expect_condlog(3, FOUND_STR("MPATHc", "WWID2")); ++ mock_unused_alias("MPATHc"); ++ ++ alias = get_user_friendly_alias("WWID2", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHc"); ++ free(alias); ++} ++ ++static void gufa_old_match_other_wwidmatch_used(void **state) { ++ char *alias; ++ static const char bindings[] = ("MPATHz WWID9\n" ++ "MPATHc WWID2"); ++ ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, 0); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); ++ expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); ++ ++ mock_bindings_file(bindings, 1); ++ expect_condlog(3, FOUND_STR("MPATHc", "WWID2")); ++ mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID2")); ++ ++ alias = get_user_friendly_alias("WWID2", "x", "MPATHz", "MPATH", false); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void gufa_old_nomatch_wwidmatch(void **state) { ++ char *alias; ++ static const char bindings[] = "MPATHa WWID0"; ++ ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, -1); ++ expect_condlog(3, NOMATCH_STR("MPATHz")); ++ ++ mock_bindings_file(bindings, 0); ++ expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); ++ mock_unused_alias("MPATHa"); ++ expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHa"); ++ free(alias); ++} ++ ++static void gufa_old_nomatch_wwidmatch_used(void **state) { ++ char *alias; ++ static const char bindings[] = "MPATHa WWID0"; ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, -1); ++ expect_condlog(3, NOMATCH_STR("MPATHz")); ++ ++ mock_bindings_file(bindings, 0); ++ expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void gufa_old_nomatch_nowwidmatch(void **state) { ++ char *alias; ++ static const char bindings[] = "MPATHb WWID1"; ++ ++ will_return(__wrap_open_file, true); ++ ++ mock_bindings_file(bindings, -1); ++ expect_condlog(3, NOMATCH_STR("MPATHz")); ++ ++ mock_bindings_file(bindings, -1); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ ++ mock_allocate_binding("MPATHz", "WWID0"); ++ expect_condlog(2, ALLOC_STR("MPATHz", "WWID0")); ++ ++ alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ assert_string_equal(alias, "MPATHz"); ++ free(alias); ++} ++ ++static int test_get_user_friendly_alias() ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(gufa_empty_new_rw), ++ cmocka_unit_test(gufa_empty_new_ro_1), ++ cmocka_unit_test(gufa_empty_new_ro_2), ++ cmocka_unit_test(gufa_match_a_unused), ++ cmocka_unit_test(gufa_match_a_self), ++ cmocka_unit_test(gufa_match_a_used), ++ cmocka_unit_test(gufa_nomatch_a_c), ++ cmocka_unit_test(gufa_nomatch_c_a), ++ cmocka_unit_test(gufa_nomatch_c_b), ++ cmocka_unit_test(gufa_nomatch_c_b_used), ++ cmocka_unit_test(gufa_nomatch_b_f_a), ++ cmocka_unit_test(gufa_old_empty), ++ cmocka_unit_test(gufa_old_match), ++ cmocka_unit_test(gufa_old_match_other), ++ cmocka_unit_test(gufa_old_match_other_used), ++ cmocka_unit_test(gufa_old_match_other_wwidmatch), ++ cmocka_unit_test(gufa_old_match_other_wwidmatch_used), ++ cmocka_unit_test(gufa_old_nomatch_wwidmatch), ++ cmocka_unit_test(gufa_old_nomatch_wwidmatch_used), ++ cmocka_unit_test(gufa_old_nomatch_nowwidmatch), ++ }; ++ ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} ++ + int main(void) + { + int ret = 0; +@@ -1157,6 +1596,8 @@ int main(void) + ret += test_lookup_binding(); + ret += test_rlookup_binding(); + ret += test_allocate_binding(); ++ ret += test_allocate_binding(); ++ ret += test_get_user_friendly_alias(); + + return ret; + } diff --git a/0008-multipath-tools-test-consistent-use-of-macros-in-ali.patch b/0008-multipath-tools-test-consistent-use-of-macros-in-ali.patch new file mode 100644 index 0000000..430ceaf --- /dev/null +++ b/0008-multipath-tools-test-consistent-use-of-macros-in-ali.patch @@ -0,0 +1,365 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 10:40:32 +0200 +Subject: [PATCH] multipath-tools test: consistent use of macros in alias test + +Use the macros introduced with the tests for get_user_friendly_alias() +also in the previously existing tests. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 80 ++++++++++++++++++++++++--------------------------- + 1 file changed, 38 insertions(+), 42 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index 7e443b06..427b2814 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -490,7 +490,7 @@ static void lb_empty(void **state) + char *alias; + + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, NULL, 0); + assert_int_equal(rc, 1); + assert_ptr_equal(alias, NULL); +@@ -503,7 +503,7 @@ static void lb_empty_unused(void **state) + + will_return(__wrap_fgets, NULL); + mock_unused_alias("MPATHa"); +- expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 1); + assert_ptr_equal(alias, NULL); +@@ -518,7 +518,7 @@ static void lb_empty_failed(void **state) + will_return(__wrap_fgets, NULL); + mock_failed_alias("MPATHa", USED_STR("MPATHa", "WWID0")); + mock_unused_alias("MPATHb"); +- expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -533,7 +533,7 @@ static void lb_empty_1_used(void **state) + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); + mock_unused_alias("MPATHb"); +- expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -548,7 +548,7 @@ static void lb_empty_1_used_self(void **state) + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); + mock_self_alias("MPATHb", "WWID0"); +- expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -561,8 +561,7 @@ static void lb_match_a(void **state) + char *alias; + + will_return(__wrap_fgets, "MPATHa WWID0\n"); +- expect_condlog(3, "Found matching wwid [WWID0] in bindings file." +- " Setting alias to MPATHa\n"); ++ expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 0); + assert_int_equal(rc, 0); + assert_ptr_not_equal(alias, NULL); +@@ -577,7 +576,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"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -590,7 +589,7 @@ static void lb_nomatch_a_bad_check(void **state) + + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(0, "no more available user_friendly_names\n"); ++ expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID1", &alias, NULL, 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); +@@ -604,7 +603,7 @@ static void lb_nomatch_a_unused(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + mock_unused_alias("MPATHb"); +- expect_condlog(3, "No matching wwid [WWID1] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -622,7 +621,7 @@ static void lb_nomatch_a_3_used_failed_self(void **state) + mock_used_alias("MPATHd", USED_STR("MPATHd", "WWID1")); + mock_failed_alias("MPATHe", USED_STR("MPATHe", "WWID1")); + mock_self_alias("MPATHf", "WWID1"); +- expect_condlog(3, "No matching wwid [WWID1] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); + assert_int_equal(rc, 6); + assert_ptr_equal(alias, NULL); +@@ -635,8 +634,7 @@ static void do_lb_match_c(void **state, int check_if_taken) + + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHc WWID1\n"); +- expect_condlog(3, "Found matching wwid [WWID1] in bindings file." +- " Setting alias to MPATHc\n"); ++ expect_condlog(3, FOUND_STR("MPATHc", "WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", check_if_taken); + assert_int_equal(rc, 0); + assert_ptr_not_equal(alias, NULL); +@@ -662,7 +660,7 @@ static void lb_nomatch_a_c(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHc WWID1\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -677,7 +675,7 @@ static void lb_nomatch_a_d_unused(void **state) + will_return(__wrap_fgets, "MPATHd WWID1\n"); + will_return(__wrap_fgets, NULL); + mock_unused_alias("MPATHb"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -693,7 +691,7 @@ static void lb_nomatch_a_d_1_used(void **state) + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); + mock_unused_alias("MPATHc"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); +@@ -710,7 +708,7 @@ static void lb_nomatch_a_d_2_used(void **state) + mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); + mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID2")); + mock_unused_alias("MPATHe"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 5); + assert_ptr_equal(alias, NULL); +@@ -728,7 +726,7 @@ static void lb_nomatch_a_d_3_used(void **state) + mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID2")); + mock_used_alias("MPATHe", USED_STR("MPATHe", "WWID2")); + mock_unused_alias("MPATHf"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 6); + assert_ptr_equal(alias, NULL); +@@ -742,7 +740,7 @@ static void lb_nomatch_c_a(void **state) + will_return(__wrap_fgets, "MPATHc WWID1\n"); + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -758,7 +756,7 @@ static void lb_nomatch_d_a_unused(void **state) + will_return(__wrap_fgets, "MPATHd WWID0\n"); + will_return(__wrap_fgets, NULL); + mock_unused_alias("MPATHb"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -775,7 +773,7 @@ static void lb_nomatch_d_a_1_used(void **state) + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); + mock_unused_alias("MPATHe"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 5); + assert_ptr_equal(alias, NULL); +@@ -790,7 +788,7 @@ static void lb_nomatch_a_b(void **state) + will_return(__wrap_fgets, "MPATHz WWID26\n"); + will_return(__wrap_fgets, "MPATHb WWID1\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); +@@ -806,7 +804,7 @@ static void lb_nomatch_a_b_bad(void **state) + will_return(__wrap_fgets, "MPATHb\n"); + 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"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); +@@ -823,7 +821,7 @@ static void lb_nomatch_a_b_bad_self(void **state) + will_return(__wrap_fgets, NULL); + expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); + mock_self_alias("MPATHc", "WWID2"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); +@@ -838,7 +836,7 @@ static void lb_nomatch_b_a(void **state) + will_return(__wrap_fgets, "MPATHz WWID26\n"); + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 27); + assert_ptr_equal(alias, NULL); +@@ -857,7 +855,7 @@ static void lb_nomatch_b_a_3_used(void **state) + mock_used_alias("MPATHab", USED_STR("MPATHab", "WWID2")); + mock_used_alias("MPATHac", USED_STR("MPATHac", "WWID2")); + mock_unused_alias("MPATHad"); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 30); + assert_ptr_equal(alias, NULL); +@@ -873,7 +871,7 @@ static void do_lb_nomatch_int_max(void **state, int check_if_taken) + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n"); + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(0, "no more available user_friendly_names\n"); ++ expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", check_if_taken); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); +@@ -898,7 +896,7 @@ static void lb_nomatch_int_max_used(void **state) + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n"); + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID2")); +- expect_condlog(0, "no more available user_friendly_names\n"); ++ expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); +@@ -913,7 +911,7 @@ static void lb_nomatch_int_max_m1(void **state) + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, INT_MAX); + assert_ptr_equal(alias, NULL); +@@ -929,7 +927,7 @@ static void lb_nomatch_int_max_m1_used(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATH" MPATH_ID_INT_MAX, USED_STR("MPATH" MPATH_ID_INT_MAX, "WWID2")); +- expect_condlog(0, "no more available user_friendly_names\n"); ++ expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); +@@ -945,7 +943,7 @@ static void lb_nomatch_int_max_m1_1_used(void **state) + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID2")); + mock_unused_alias("MPATH" MPATH_ID_INT_MAX); +- expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, INT_MAX); + assert_ptr_equal(alias, NULL); +@@ -961,7 +959,7 @@ static void lb_nomatch_int_max_m1_2_used(void **state) + will_return(__wrap_fgets, NULL); + mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID2")); + mock_used_alias("MPATH" MPATH_ID_INT_MAX, USED_STR("MPATH" MPATH_ID_INT_MAX, "WWID2")); +- expect_condlog(0, "no more available user_friendly_names\n"); ++ expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); +@@ -1017,7 +1015,7 @@ static void rl_empty(void **state) + + buf[0] = '\0'; + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); + assert_string_equal(buf, ""); +@@ -1030,8 +1028,7 @@ static void rl_match_a(void **state) + + buf[0] = '\0'; + will_return(__wrap_fgets, "MPATHa WWID0\n"); +- expect_condlog(3, "Found matching alias [MPATHa] in bindings file. " +- "Setting wwid to WWID0\n"); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHa", "WWID0")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, 0); + assert_string_equal(buf, "WWID0"); +@@ -1045,7 +1042,7 @@ static void rl_nomatch_a(void **state) + buf[0] = '\0'; + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- expect_condlog(3, "No matching alias [MPATHb] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_STR("MPATHb")); + rc = rlookup_binding(NULL, buf, "MPATHb"); + assert_int_equal(rc, -1); + assert_string_equal(buf, ""); +@@ -1060,7 +1057,7 @@ static void rl_malformed_a(void **state) + will_return(__wrap_fgets, "MPATHa \n"); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "Ignoring malformed line 1 in bindings file\n"); +- expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); + assert_string_equal(buf, ""); +@@ -1080,7 +1077,7 @@ static void rl_overlong_a(void **state) + will_return(__wrap_fgets, line); + will_return(__wrap_fgets, NULL); + expect_condlog(3, "Ignoring too large wwid at 1 in bindings file\n"); +- expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n"); ++ expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); + assert_string_equal(buf, ""); +@@ -1095,8 +1092,7 @@ static void rl_match_b(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHz WWID26\n"); + will_return(__wrap_fgets, "MPATHb WWID2\n"); +- expect_condlog(3, "Found matching alias [MPATHb] in bindings file. " +- "Setting wwid to WWID2\n"); ++ expect_condlog(3, FOUND_ALIAS_STR("MPATHb", "WWID2")); + rc = rlookup_binding(NULL, buf, "MPATHb"); + assert_int_equal(rc, 0); + assert_string_equal(buf, "WWID2"); +@@ -1125,7 +1121,7 @@ static void al_a(void **state) + expect_value(__wrap_write, count, strlen(ln)); + expect_string(__wrap_write, buf, ln); + will_return(__wrap_write, strlen(ln)); +- expect_condlog(3, "Created new binding [MPATHa] for WWID [WWIDa]\n"); ++ expect_condlog(3, NEW_STR("MPATHa", "WWIDa")); + + alias = allocate_binding(0, "WWIDa", 1, "MPATH"); + assert_ptr_not_equal(alias, NULL); +@@ -1142,7 +1138,7 @@ static void al_zz(void **state) + expect_value(__wrap_write, count, strlen(ln)); + expect_string(__wrap_write, buf, ln); + will_return(__wrap_write, strlen(ln)); +- expect_condlog(3, "Created new binding [MPATHzz] for WWID [WWIDzz]\n"); ++ expect_condlog(3, NEW_STR("MPATHzz", "WWIDzz")); + + alias = allocate_binding(0, "WWIDzz", 26*26 + 26, "MPATH"); + assert_ptr_not_equal(alias, NULL); diff --git a/0009-multipath-tools-tests-convert-mock_-failed-used-_ali.patch b/0009-multipath-tools-tests-convert-mock_-failed-used-_ali.patch new file mode 100644 index 0000000..9d71adf --- /dev/null +++ b/0009-multipath-tools-tests-convert-mock_-failed-used-_ali.patch @@ -0,0 +1,246 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 10:49:32 +0200 +Subject: [PATCH] multipath-tools tests: convert mock_{failed,used}_alias to + macros + +This way we can further improve readability of the individual test +cases. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 92 +++++++++++++++++++++++++-------------------------- + 1 file changed, 46 insertions(+), 46 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index 427b2814..a32b43e8 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -445,26 +445,26 @@ static void mock_self_alias(const char *alias, const char *wwid) + #define REUSE_STR(alias_str, wwid_str) ("alias " alias_str " already bound to wwid " wwid_str ", cannot reuse\n") + #define NOMORE_STR "no more available user_friendly_names\n" + +-static void mock_failed_alias(const char *alias, char *msg) +-{ +- expect_string(__wrap_dm_map_present, str, alias); +- will_return(__wrap_dm_map_present, 1); +- expect_string(__wrap_dm_get_uuid, name, alias); +- expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); +- will_return(__wrap_dm_get_uuid, 1); +- expect_condlog(3, msg); +-} ++#define mock_failed_alias(alias, wwid) \ ++ do { \ ++ expect_string(__wrap_dm_map_present, str, alias); \ ++ will_return(__wrap_dm_map_present, 1); \ ++ expect_string(__wrap_dm_get_uuid, name, alias); \ ++ expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); \ ++ will_return(__wrap_dm_get_uuid, 1); \ ++ expect_condlog(3, USED_STR(alias, wwid)); \ ++ } while (0) + +-static void mock_used_alias(const char *alias, char *msg) +-{ +- expect_string(__wrap_dm_map_present, str, alias); +- will_return(__wrap_dm_map_present, 1); +- expect_string(__wrap_dm_get_uuid, name, alias); +- expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); +- will_return(__wrap_dm_get_uuid, 0); +- will_return(__wrap_dm_get_uuid, "WWID_USED"); +- expect_condlog(3, msg); +-} ++#define mock_used_alias(alias, wwid) \ ++ do { \ ++ expect_string(__wrap_dm_map_present, str, alias); \ ++ will_return(__wrap_dm_map_present, 1); \ ++ expect_string(__wrap_dm_get_uuid, name, alias); \ ++ expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); \ ++ will_return(__wrap_dm_get_uuid, 0); \ ++ will_return(__wrap_dm_get_uuid, "WWID_USED"); \ ++ expect_condlog(3, USED_STR(alias, wwid)); \ ++ } while(0) + + static void mock_bindings_file(const char *content, int match_line) + { +@@ -516,7 +516,7 @@ static void lb_empty_failed(void **state) + char *alias; + + will_return(__wrap_fgets, NULL); +- mock_failed_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ mock_failed_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); +@@ -531,7 +531,7 @@ static void lb_empty_1_used(void **state) + char *alias; + + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); +@@ -546,7 +546,7 @@ static void lb_empty_1_used_self(void **state) + char *alias; + + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", "WWID0"); + mock_self_alias("MPATHb", "WWID0"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); +@@ -616,10 +616,10 @@ static void lb_nomatch_a_3_used_failed_self(void **state) + + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID1")); +- mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID1")); +- mock_used_alias("MPATHd", USED_STR("MPATHd", "WWID1")); +- mock_failed_alias("MPATHe", USED_STR("MPATHe", "WWID1")); ++ mock_used_alias("MPATHb", "WWID1"); ++ mock_used_alias("MPATHc", "WWID1"); ++ mock_used_alias("MPATHd", "WWID1"); ++ mock_failed_alias("MPATHe", "WWID1"); + mock_self_alias("MPATHf", "WWID1"); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); +@@ -689,7 +689,7 @@ static void lb_nomatch_a_d_1_used(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHd WWID1\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); ++ mock_used_alias("MPATHb", "WWID2"); + mock_unused_alias("MPATHc"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -705,8 +705,8 @@ static void lb_nomatch_a_d_2_used(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHd WWID1\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); +- mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID2")); ++ mock_used_alias("MPATHb", "WWID2"); ++ mock_used_alias("MPATHc", "WWID2"); + mock_unused_alias("MPATHe"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -722,9 +722,9 @@ static void lb_nomatch_a_d_3_used(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHd WWID1\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); +- mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID2")); +- mock_used_alias("MPATHe", USED_STR("MPATHe", "WWID2")); ++ mock_used_alias("MPATHb", "WWID2"); ++ mock_used_alias("MPATHc", "WWID2"); ++ mock_used_alias("MPATHe", "WWID2"); + mock_unused_alias("MPATHf"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -771,7 +771,7 @@ static void lb_nomatch_d_a_1_used(void **state) + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, "MPATHd WWID0\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHb", USED_STR("MPATHb", "WWID2")); ++ mock_used_alias("MPATHb", "WWID2"); + mock_unused_alias("MPATHe"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -851,9 +851,9 @@ static void lb_nomatch_b_a_3_used(void **state) + will_return(__wrap_fgets, "MPATHz WWID26\n"); + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHaa", USED_STR("MPATHaa", "WWID2")); +- mock_used_alias("MPATHab", USED_STR("MPATHab", "WWID2")); +- mock_used_alias("MPATHac", USED_STR("MPATHac", "WWID2")); ++ mock_used_alias("MPATHaa", "WWID2"); ++ mock_used_alias("MPATHab", "WWID2"); ++ mock_used_alias("MPATHac", "WWID2"); + mock_unused_alias("MPATHad"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -895,7 +895,7 @@ static void lb_nomatch_int_max_used(void **state) + will_return(__wrap_fgets, "MPATHb WWID1\n"); + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID2")); ++ mock_used_alias("MPATHa", "WWID2"); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, -1); +@@ -926,7 +926,7 @@ static void lb_nomatch_int_max_m1_used(void **state) + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); + will_return(__wrap_fgets, "MPATHa WWID0\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATH" MPATH_ID_INT_MAX, USED_STR("MPATH" MPATH_ID_INT_MAX, "WWID2")); ++ mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWID2"); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, -1); +@@ -941,7 +941,7 @@ static void lb_nomatch_int_max_m1_1_used(void **state) + will_return(__wrap_fgets, "MPATHb WWID1\n"); + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID2")); ++ mock_used_alias("MPATHa", "WWID2"); + mock_unused_alias("MPATH" MPATH_ID_INT_MAX); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -957,8 +957,8 @@ static void lb_nomatch_int_max_m1_2_used(void **state) + will_return(__wrap_fgets, "MPATHb WWID1\n"); + will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); + will_return(__wrap_fgets, NULL); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID2")); +- mock_used_alias("MPATH" MPATH_ID_INT_MAX, USED_STR("MPATH" MPATH_ID_INT_MAX, "WWID2")); ++ mock_used_alias("MPATHa", "WWID2"); ++ mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWID2"); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, -1); +@@ -1291,7 +1291,7 @@ static void gufa_match_a_used(void **state) { + + will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", "WWID0"); + + alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); + assert_ptr_equal(alias, NULL); +@@ -1355,7 +1355,7 @@ static void gufa_nomatch_c_b_used(void **state) { + mock_bindings_file("MPATHc WWID2\n" + "MPATHb WWID1", + -1); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID4")); ++ mock_used_alias("MPATHa", "WWID4"); + expect_condlog(3, NOMATCH_WWID_STR("WWID4")); + mock_unused_alias("MPATHd"); + +@@ -1450,7 +1450,7 @@ static void gufa_old_match_other_used(void **state) { + expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); + + mock_bindings_file(bindings, -1); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", "WWID0"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_unused_alias("MPATHb"); + +@@ -1493,7 +1493,7 @@ static void gufa_old_match_other_wwidmatch_used(void **state) { + + mock_bindings_file(bindings, 1); + expect_condlog(3, FOUND_STR("MPATHc", "WWID2")); +- mock_used_alias("MPATHc", USED_STR("MPATHc", "WWID2")); ++ mock_used_alias("MPATHc", "WWID2"); + + alias = get_user_friendly_alias("WWID2", "x", "MPATHz", "MPATH", false); + assert_ptr_equal(alias, NULL); +@@ -1528,7 +1528,7 @@ static void gufa_old_nomatch_wwidmatch_used(void **state) { + + mock_bindings_file(bindings, 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); +- mock_used_alias("MPATHa", USED_STR("MPATHa", "WWID0")); ++ mock_used_alias("MPATHa", "WWID0"); + + alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); + assert_ptr_equal(alias, NULL); diff --git a/0010-multipath-tools-test-use-mock_bindings_file-consiste.patch b/0010-multipath-tools-test-use-mock_bindings_file-consiste.patch new file mode 100644 index 0000000..2105f5a --- /dev/null +++ b/0010-multipath-tools-test-use-mock_bindings_file-consiste.patch @@ -0,0 +1,500 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 11:13:44 +0200 +Subject: [PATCH] multipath-tools test: use mock_bindings_file() consistently + +Further improve test readablity. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 178 +++++++++++++++++++++----------------------------- + 1 file changed, 76 insertions(+), 102 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index a32b43e8..f334f928 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -489,7 +489,7 @@ static void lb_empty(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, NULL, 0); + assert_int_equal(rc, 1); +@@ -501,7 +501,7 @@ static void lb_empty_unused(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); +@@ -515,7 +515,7 @@ static void lb_empty_failed(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_failed_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); +@@ -530,7 +530,7 @@ static void lb_empty_1_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_used_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); +@@ -545,7 +545,7 @@ static void lb_empty_1_used_self(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_used_alias("MPATHa", "WWID0"); + mock_self_alias("MPATHb", "WWID0"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); +@@ -560,7 +560,7 @@ static void lb_match_a(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); ++ mock_bindings_file("MPATHa WWID0\n", 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 0); + assert_int_equal(rc, 0); +@@ -574,8 +574,7 @@ static void lb_nomatch_a(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0); + assert_int_equal(rc, 2); +@@ -587,8 +586,7 @@ static void lb_nomatch_a_bad_check(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n", -1); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID1", &alias, NULL, 1); + assert_int_equal(rc, -1); +@@ -600,8 +598,7 @@ static void lb_nomatch_a_unused(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n", -1); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); +@@ -614,8 +611,7 @@ static void lb_nomatch_a_3_used_failed_self(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n", -1); + mock_used_alias("MPATHb", "WWID1"); + mock_used_alias("MPATHc", "WWID1"); + mock_used_alias("MPATHd", "WWID1"); +@@ -632,8 +628,8 @@ static void do_lb_match_c(void **state, int check_if_taken) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHc WWID1\n"); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHc WWID1", 1); + expect_condlog(3, FOUND_STR("MPATHc", "WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", check_if_taken); + assert_int_equal(rc, 0); +@@ -657,9 +653,8 @@ static void lb_nomatch_a_c(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHc WWID1\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHc WWID1", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 2); +@@ -671,9 +666,8 @@ static void lb_nomatch_a_d_unused(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHd WWID1\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHd WWID1", -1); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -686,9 +680,8 @@ static void lb_nomatch_a_d_1_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHd WWID1\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHd WWID1", -1); + mock_used_alias("MPATHb", "WWID2"); + mock_unused_alias("MPATHc"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +@@ -702,9 +695,8 @@ static void lb_nomatch_a_d_2_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHd WWID1\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHd WWID1", -1); + mock_used_alias("MPATHb", "WWID2"); + mock_used_alias("MPATHc", "WWID2"); + mock_unused_alias("MPATHe"); +@@ -719,9 +711,8 @@ static void lb_nomatch_a_d_3_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHd WWID1\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHd WWID1", -1); + mock_used_alias("MPATHb", "WWID2"); + mock_used_alias("MPATHc", "WWID2"); + mock_used_alias("MPATHe", "WWID2"); +@@ -737,9 +728,8 @@ static void lb_nomatch_c_a(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHc WWID1\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHc WWID1\n" ++ "MPATHa WWID0\n", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 2); +@@ -751,10 +741,9 @@ static void lb_nomatch_d_a_unused(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHc WWID1\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHd WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHc WWID1\n" ++ "MPATHa WWID0\n" ++ "MPATHd WWID0\n", -1); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -767,10 +756,9 @@ static void lb_nomatch_d_a_1_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHc WWID1\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHd WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHc WWID1\n" ++ "MPATHa WWID0\n" ++ "MPATHd WWID0\n", -1); + mock_used_alias("MPATHb", "WWID2"); + mock_unused_alias("MPATHe"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +@@ -784,10 +772,9 @@ static void lb_nomatch_a_b(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHz WWID26\n"); +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHz WWID26\n" ++ "MPATHb WWID1\n", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 3); +@@ -799,10 +786,9 @@ static void lb_nomatch_a_b_bad(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHz WWID26\n"); +- will_return(__wrap_fgets, "MPATHb\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHz WWID26\n" ++ "MPATHb\n", -1); + expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); +@@ -815,10 +801,9 @@ static void lb_nomatch_a_b_bad_self(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHz WWID26\n"); +- will_return(__wrap_fgets, "MPATHb\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHz WWID26\n" ++ "MPATHb\n", -1); + expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); + mock_self_alias("MPATHc", "WWID2"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +@@ -832,10 +817,9 @@ static void lb_nomatch_b_a(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATHz WWID26\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATHz WWID26\n" ++ "MPATHa WWID0\n", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, 27); +@@ -847,10 +831,9 @@ static void lb_nomatch_b_a_3_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATHz WWID26\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATHz WWID26\n" ++ "MPATHa WWID0\n", -1); + mock_used_alias("MPATHaa", "WWID2"); + mock_used_alias("MPATHab", "WWID2"); + mock_used_alias("MPATHac", "WWID2"); +@@ -867,10 +850,9 @@ static void do_lb_nomatch_int_max(void **state, int check_if_taken) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n" ++ "MPATHa WWID0\n", -1); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", check_if_taken); + assert_int_equal(rc, -1); +@@ -892,9 +874,8 @@ static void lb_nomatch_int_max_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n", -1); + mock_used_alias("MPATHa", "WWID2"); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -907,10 +888,9 @@ static void lb_nomatch_int_max_m1(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n" ++ "MPATHa WWID0\n", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); + assert_int_equal(rc, INT_MAX); +@@ -922,10 +902,9 @@ static void lb_nomatch_int_max_m1_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n" ++ "MPATHa WWID0\n", -1); + mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWID2"); + expect_condlog(0, NOMORE_STR); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -938,9 +917,8 @@ static void lb_nomatch_int_max_m1_1_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n", -1); + mock_used_alias("MPATHa", "WWID2"); + mock_unused_alias("MPATH" MPATH_ID_INT_MAX); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +@@ -954,9 +932,8 @@ static void lb_nomatch_int_max_m1_2_used(void **state) + int rc; + char *alias; + +- will_return(__wrap_fgets, "MPATHb WWID1\n"); +- will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHb WWID1\n" ++ "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n", -1); + mock_used_alias("MPATHa", "WWID2"); + mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWID2"); + expect_condlog(0, NOMORE_STR); +@@ -1014,7 +991,7 @@ static void rl_empty(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); +@@ -1027,7 +1004,7 @@ static void rl_match_a(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- will_return(__wrap_fgets, "MPATHa WWID0\n"); ++ mock_bindings_file("MPATHa WWID0\n", 0); + expect_condlog(3, FOUND_ALIAS_STR("MPATHa", "WWID0")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, 0); +@@ -1040,8 +1017,7 @@ static void rl_nomatch_a(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa WWID0\n", -1); + expect_condlog(3, NOMATCH_STR("MPATHb")); + rc = rlookup_binding(NULL, buf, "MPATHb"); + assert_int_equal(rc, -1); +@@ -1054,8 +1030,7 @@ static void rl_malformed_a(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- will_return(__wrap_fgets, "MPATHa \n"); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("MPATHa \n", -1); + expect_condlog(3, "Ignoring malformed line 1 in bindings file\n"); + expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); +@@ -1074,8 +1049,7 @@ static void rl_overlong_a(void **state) + snprintf(line + sizeof(line) - 2, 2, "\n"); + + buf[0] = '\0'; +- will_return(__wrap_fgets, line); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file(line, -1); + expect_condlog(3, "Ignoring too large wwid at 1 in bindings file\n"); + expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); +@@ -1089,9 +1063,9 @@ static void rl_match_b(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- will_return(__wrap_fgets, "MPATHa WWID0\n"); +- will_return(__wrap_fgets, "MPATHz WWID26\n"); +- will_return(__wrap_fgets, "MPATHb WWID2\n"); ++ mock_bindings_file("MPATHa WWID0\n" ++ "MPATHz WWID26\n" ++ "MPATHb WWID2\n", 2); + expect_condlog(3, FOUND_ALIAS_STR("MPATHb", "WWID2")); + rc = rlookup_binding(NULL, buf, "MPATHb"); + assert_int_equal(rc, 0); +@@ -1222,7 +1196,7 @@ static void gufa_empty_new_rw(void **state) { + + will_return(__wrap_open_file, true); + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + +@@ -1235,7 +1209,7 @@ static void gufa_empty_new_rw(void **state) { + static void gufa_empty_new_ro_1(void **state) { + char *alias; + will_return(__wrap_open_file, false); +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + +@@ -1248,7 +1222,7 @@ static void gufa_empty_new_ro_2(void **state) { + + will_return(__wrap_open_file, true); + +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + +@@ -1261,7 +1235,7 @@ static void gufa_match_a_unused(void **state) { + + will_return(__wrap_open_file, true); + +- will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); ++ mock_bindings_file("MPATHa WWID0", 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_unused_alias("MPATHa"); + +@@ -1275,7 +1249,7 @@ static void gufa_match_a_self(void **state) { + + will_return(__wrap_open_file, true); + +- will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); ++ mock_bindings_file("MPATHa WWID0", 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_self_alias("MPATHa", "WWID0"); + +@@ -1289,7 +1263,7 @@ static void gufa_match_a_used(void **state) { + + will_return(__wrap_open_file, true); + +- will_return(__wrap_fgets, BINDING_STR("MPATHa", "WWID0")); ++ mock_bindings_file("MPATHa WWID0", 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_used_alias("MPATHa", "WWID0"); + +@@ -1389,11 +1363,11 @@ static void gufa_old_empty(void **state) { + will_return(__wrap_open_file, true); + + /* rlookup_binding for ALIAS */ +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + expect_condlog(3, NOMATCH_STR("MPATHz")); + + /* lookup_binding */ +- will_return(__wrap_fgets, NULL); ++ mock_bindings_file("", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + + mock_allocate_binding("MPATHz", "WWID0"); diff --git a/0011-libmultipath-add-global-variable-for-current-binding.patch b/0011-libmultipath-add-global-variable-for-current-binding.patch new file mode 100644 index 0000000..c91259d --- /dev/null +++ b/0011-libmultipath-add-global-variable-for-current-binding.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 15:32:17 +0200 +Subject: [PATCH] libmultipath: add global variable for current bindings + +Add a variable global_bindings that holds the currently active vector of +bindings. This variable is freed at program exit. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 11 +++++++++-- + libmultipath/alias.h | 1 + + libmultipath/libmultipath.version | 1 + + multipath/main.c | 2 ++ + multipathd/main.c | 1 + + 5 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 9e9ac563..dd363fd8 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -511,6 +511,7 @@ static void _free_binding(struct binding *bdg) + * an abstract type. + */ + typedef struct _vector Bindings; ++static Bindings global_bindings = { .allocated = 0 }; + + static void free_bindings(Bindings *bindings) + { +@@ -522,6 +523,11 @@ static void free_bindings(Bindings *bindings) + vector_reset(bindings); + } + ++void cleanup_bindings(void) ++{ ++ free_bindings(&global_bindings); ++} ++ + enum { + BINDING_EXISTS, + BINDING_CONFLICT, +@@ -751,7 +757,6 @@ int check_alias_settings(const struct config *conf) + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + +- pthread_cleanup_push_cast(free_bindings, &bindings); + fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER); + if (fd != -1) { + FILE *file = fdopen(fd, "r"); +@@ -771,6 +776,8 @@ int check_alias_settings(const struct config *conf) + close(fd); + } + } +- pthread_cleanup_pop(1); ++ ++ cleanup_bindings(); ++ global_bindings = bindings; + return rc; + } +diff --git a/libmultipath/alias.h b/libmultipath/alias.h +index fa332233..37b49d9c 100644 +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -9,5 +9,6 @@ char *get_user_friendly_alias(const char *wwid, const char *file, + + struct config; + int check_alias_settings(const struct config *); ++void cleanup_bindings(void); + + #endif /* _ALIAS_H */ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index a7b8c337..ddd302f5 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -64,6 +64,7 @@ global: + checker_name; + checker_state_name; + check_foreign; ++ cleanup_bindings; + cleanup_lock; + coalesce_paths; + count_active_paths; +diff --git a/multipath/main.c b/multipath/main.c +index b78f3162..45e9745f 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -843,6 +843,8 @@ main (int argc, char *argv[]) + conf->force_sync = 1; + if (atexit(cleanup_vecs)) + condlog(1, "failed to register cleanup handler for vecs: %m"); ++ if (atexit(cleanup_bindings)) ++ condlog(1, "failed to register cleanup handler for bindings: %m"); + while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) { + switch(arg) { + case 'v': +diff --git a/multipathd/main.c b/multipathd/main.c +index 2e02a548..214ed4ae 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3325,6 +3325,7 @@ static void cleanup_child(void) + { + cleanup_threads(); + cleanup_vecs(); ++ cleanup_bindings(); + if (poll_dmevents) + cleanup_dmevent_waiter(); + diff --git a/0012-libmultipath-rename-fix_bindings_file-to-update_bind.patch b/0012-libmultipath-rename-fix_bindings_file-to-update_bind.patch new file mode 100644 index 0000000..e0f8673 --- /dev/null +++ b/0012-libmultipath-rename-fix_bindings_file-to-update_bind.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 15:37:15 +0200 +Subject: [PATCH] libmultipath: rename fix_bindings_file() to + update_bindings_file() + +We will use this function in a more generic way, give it a more +generic name. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index dd363fd8..0aac2393 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -595,8 +595,8 @@ static int write_bindings_file(const Bindings *bindings, int fd) + return 0; + } + +-static int fix_bindings_file(const struct config *conf, +- const Bindings *bindings) ++static int update_bindings_file(const struct config *conf, ++ const Bindings *bindings) + { + int rc; + int fd = -1; +@@ -766,7 +766,7 @@ int check_alias_settings(const struct config *conf) + rc = _check_bindings_file(conf, file, &bindings); + pthread_cleanup_pop(1); + if (rc == -1 && can_write && !conf->bindings_read_only) +- rc = fix_bindings_file(conf, &bindings); ++ rc = update_bindings_file(conf, &bindings); + else if (rc == -1) + condlog(0, "ERROR: bad settings in read-only bindings file %s", + conf->bindings_file); diff --git a/0013-libmultipath-alias.c-move-bindings-related-code-up.patch b/0013-libmultipath-alias.c-move-bindings-related-code-up.patch new file mode 100644 index 0000000..1ad7b9e --- /dev/null +++ b/0013-libmultipath-alias.c-move-bindings-related-code-up.patch @@ -0,0 +1,285 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 16:54:54 +0200 +Subject: [PATCH] libmultipath: alias.c: move bindings related code up + +No code changes, just moving code. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 239 ++++++++++++++++++++++--------------------- + 1 file changed, 120 insertions(+), 119 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 0aac2393..7af403da 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + #include "debug.h" + #include "util.h" +@@ -51,6 +52,125 @@ + + static const char bindings_file_header[] = BINDINGS_FILE_HEADER; + ++struct binding { ++ char *alias; ++ char *wwid; ++}; ++ ++/* ++ * Perhaps one day we'll implement this more efficiently, thus use ++ * an abstract type. ++ */ ++typedef struct _vector Bindings; ++static Bindings global_bindings = { .allocated = 0 }; ++ ++enum { ++ BINDING_EXISTS, ++ BINDING_CONFLICT, ++ BINDING_ADDED, ++ BINDING_DELETED, ++ BINDING_NOTFOUND, ++ BINDING_ERROR, ++}; ++ ++static void _free_binding(struct binding *bdg) ++{ ++ free(bdg->wwid); ++ free(bdg->alias); ++ free(bdg); ++} ++ ++static int add_binding(Bindings *bindings, const char *alias, const char *wwid) ++{ ++ struct binding *bdg; ++ int i, cmp = 0; ++ ++ /* ++ * Keep the bindings array sorted by alias. ++ * Optimization: Search backwards, assuming that the bindings file is ++ * sorted already. ++ */ ++ vector_foreach_slot_backwards(bindings, bdg, i) { ++ if ((cmp = strcmp(bdg->alias, alias)) <= 0) ++ break; ++ } ++ ++ /* Check for exact match */ ++ if (i >= 0 && cmp == 0) ++ return strcmp(bdg->wwid, wwid) ? ++ BINDING_CONFLICT : BINDING_EXISTS; ++ ++ i++; ++ bdg = calloc(1, sizeof(*bdg)); ++ if (bdg) { ++ bdg->wwid = strdup(wwid); ++ bdg->alias = strdup(alias); ++ if (bdg->wwid && bdg->alias && ++ vector_insert_slot(bindings, i, bdg)) ++ return BINDING_ADDED; ++ else ++ _free_binding(bdg); ++ } ++ ++ return BINDING_ERROR; ++} ++ ++static int write_bindings_file(const Bindings *bindings, int fd) ++{ ++ struct binding *bnd; ++ STRBUF_ON_STACK(line); ++ int i; ++ ++ if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1) ++ != sizeof(BINDINGS_FILE_HEADER) - 1) ++ return -1; ++ ++ vector_foreach_slot(bindings, bnd, i) { ++ int len; ++ ++ if ((len = print_strbuf(&line, "%s %s\n", ++ bnd->alias, bnd->wwid)) < 0) ++ return -1; ++ if (write(fd, get_strbuf_str(&line), len) != len) ++ return -1; ++ truncate_strbuf(&line, 0); ++ } ++ return 0; ++} ++ ++static int update_bindings_file(const struct config *conf, ++ const Bindings *bindings) ++{ ++ int rc; ++ int fd = -1; ++ char tempname[PATH_MAX]; ++ mode_t old_umask; ++ ++ if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file)) ++ return -1; ++ /* coverity: SECURE_TEMP */ ++ old_umask = umask(0077); ++ if ((fd = mkstemp(tempname)) == -1) { ++ condlog(1, "%s: mkstemp: %m", __func__); ++ return -1; ++ } ++ umask(old_umask); ++ pthread_cleanup_push(cleanup_fd_ptr, &fd); ++ rc = write_bindings_file(bindings, fd); ++ pthread_cleanup_pop(1); ++ if (rc == -1) { ++ condlog(1, "failed to write new bindings file %s", ++ tempname); ++ unlink(tempname); ++ return rc; ++ } ++ if ((rc = rename(tempname, conf->bindings_file)) == -1) ++ condlog(0, "%s: rename: %m", __func__); ++ else ++ condlog(1, "updated bindings file %s", conf->bindings_file); ++ return rc; ++} ++ + int + valid_alias(const char *alias) + { +@@ -494,25 +614,6 @@ get_user_friendly_wwid(const char *alias, char *buff, const char *file) + return 0; + } + +-struct binding { +- char *alias; +- char *wwid; +-}; +- +-static void _free_binding(struct binding *bdg) +-{ +- free(bdg->wwid); +- free(bdg->alias); +- free(bdg); +-} +- +-/* +- * Perhaps one day we'll implement this more efficiently, thus use +- * an abstract type. +- */ +-typedef struct _vector Bindings; +-static Bindings global_bindings = { .allocated = 0 }; +- + static void free_bindings(Bindings *bindings) + { + struct binding *bdg; +@@ -528,106 +629,6 @@ void cleanup_bindings(void) + free_bindings(&global_bindings); + } + +-enum { +- BINDING_EXISTS, +- BINDING_CONFLICT, +- BINDING_ADDED, +- BINDING_DELETED, +- BINDING_NOTFOUND, +- BINDING_ERROR, +-}; +- +-static int add_binding(Bindings *bindings, const char *alias, const char *wwid) +-{ +- struct binding *bdg; +- int i, cmp = 0; +- +- /* +- * Keep the bindings array sorted by alias. +- * Optimization: Search backwards, assuming that the bindings file is +- * sorted already. +- */ +- vector_foreach_slot_backwards(bindings, bdg, i) { +- if ((cmp = strcmp(bdg->alias, alias)) <= 0) +- break; +- } +- +- /* Check for exact match */ +- if (i >= 0 && cmp == 0) +- return strcmp(bdg->wwid, wwid) ? +- BINDING_CONFLICT : BINDING_EXISTS; +- +- i++; +- bdg = calloc(1, sizeof(*bdg)); +- if (bdg) { +- bdg->wwid = strdup(wwid); +- bdg->alias = strdup(alias); +- if (bdg->wwid && bdg->alias && +- vector_insert_slot(bindings, i, bdg)) +- return BINDING_ADDED; +- else +- _free_binding(bdg); +- } +- +- return BINDING_ERROR; +-} +- +-static int write_bindings_file(const Bindings *bindings, int fd) +-{ +- struct binding *bnd; +- STRBUF_ON_STACK(line); +- int i; +- +- if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1) +- != sizeof(BINDINGS_FILE_HEADER) - 1) +- return -1; +- +- vector_foreach_slot(bindings, bnd, i) { +- int len; +- +- if ((len = print_strbuf(&line, "%s %s\n", +- bnd->alias, bnd->wwid)) < 0) +- return -1; +- if (write(fd, get_strbuf_str(&line), len) != len) +- return -1; +- truncate_strbuf(&line, 0); +- } +- return 0; +-} +- +-static int update_bindings_file(const struct config *conf, +- const Bindings *bindings) +-{ +- int rc; +- int fd = -1; +- char tempname[PATH_MAX]; +- mode_t old_umask; +- +- if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file)) +- return -1; +- /* coverity: SECURE_TEMP */ +- old_umask = umask(0077); +- if ((fd = mkstemp(tempname)) == -1) { +- condlog(1, "%s: mkstemp: %m", __func__); +- return -1; +- } +- umask(old_umask); +- pthread_cleanup_push(cleanup_fd_ptr, &fd); +- rc = write_bindings_file(bindings, fd); +- pthread_cleanup_pop(1); +- if (rc == -1) { +- condlog(1, "failed to write new bindings file %s", +- tempname); +- unlink(tempname); +- return rc; +- } +- if ((rc = rename(tempname, conf->bindings_file)) == -1) +- condlog(0, "%s: rename: %m", __func__); +- else +- condlog(1, "updated bindings file %s", conf->bindings_file); +- return rc; +-} +- + static int _check_bindings_file(const struct config *conf, FILE *file, + Bindings *bindings) + { diff --git a/0014-libmultipath-update_bindings_file-take-filename-argu.patch b/0014-libmultipath-update_bindings_file-take-filename-argu.patch new file mode 100644 index 0000000..6b9d2e8 --- /dev/null +++ b/0014-libmultipath-update_bindings_file-take-filename-argu.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 15:53:49 +0200 +Subject: [PATCH] libmultipath: update_bindings_file: take filename argument + +This function just uses the file name, no other configuration +parameters. Also, pass the Bindings argument first to use the +same convention as the other functions in this file. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 7af403da..9bd3875e 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -138,15 +138,15 @@ static int write_bindings_file(const Bindings *bindings, int fd) + return 0; + } + +-static int update_bindings_file(const struct config *conf, +- const Bindings *bindings) ++static int update_bindings_file(const Bindings *bindings, ++ const char *bindings_file) + { + int rc; + int fd = -1; + char tempname[PATH_MAX]; + mode_t old_umask; + +- if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file)) ++ if (safe_sprintf(tempname, "%s.XXXXXX", bindings_file)) + return -1; + /* coverity: SECURE_TEMP */ + old_umask = umask(0077); +@@ -164,10 +164,10 @@ static int update_bindings_file(const struct config *conf, + unlink(tempname); + return rc; + } +- if ((rc = rename(tempname, conf->bindings_file)) == -1) ++ if ((rc = rename(tempname, bindings_file)) == -1) + condlog(0, "%s: rename: %m", __func__); + else +- condlog(1, "updated bindings file %s", conf->bindings_file); ++ condlog(1, "updated bindings file %s", bindings_file); + return rc; + } + +@@ -767,7 +767,7 @@ int check_alias_settings(const struct config *conf) + rc = _check_bindings_file(conf, file, &bindings); + pthread_cleanup_pop(1); + if (rc == -1 && can_write && !conf->bindings_read_only) +- rc = update_bindings_file(conf, &bindings); ++ rc = update_bindings_file(&bindings, conf->bindings_file); + else if (rc == -1) + condlog(0, "ERROR: bad settings in read-only bindings file %s", + conf->bindings_file); diff --git a/0015-libmultipath-update_bindings_file-use-a-single-write.patch b/0015-libmultipath-update_bindings_file-use-a-single-write.patch new file mode 100644 index 0000000..1e1fd15 --- /dev/null +++ b/0015-libmultipath-update_bindings_file-use-a-single-write.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 15:54:45 +0200 +Subject: [PATCH] libmultipath: update_bindings_file: use a single write() + +Save code and syscalls by assembling the content in memory first. +write() may return less bytes written than expected. Deal with it. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 9bd3875e..92f90f05 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -118,22 +118,30 @@ static int add_binding(Bindings *bindings, const char *alias, const char *wwid) + static int write_bindings_file(const Bindings *bindings, int fd) + { + struct binding *bnd; +- STRBUF_ON_STACK(line); ++ STRBUF_ON_STACK(content); + int i; ++ size_t len; + +- if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1) +- != sizeof(BINDINGS_FILE_HEADER) - 1) ++ if (__append_strbuf_str(&content, BINDINGS_FILE_HEADER, ++ sizeof(BINDINGS_FILE_HEADER) - 1) == -1) + return -1; + + vector_foreach_slot(bindings, bnd, i) { +- int len; +- +- if ((len = print_strbuf(&line, "%s %s\n", +- bnd->alias, bnd->wwid)) < 0) ++ if (print_strbuf(&content, "%s %s\n", ++ bnd->alias, bnd->wwid) < 0) + return -1; +- if (write(fd, get_strbuf_str(&line), len) != len) ++ } ++ len = get_strbuf_len(&content); ++ while (len > 0) { ++ ssize_t n = write(fd, get_strbuf_str(&content), len); ++ ++ if (n < 0) ++ return n; ++ else if (n == 0) { ++ condlog(2, "%s: short write", __func__); + return -1; +- truncate_strbuf(&line, 0); ++ } ++ len -= n; + } + return 0; + } diff --git a/0016-libmultipath-update_bindings_file-don-t-log-temp-fil.patch b/0016-libmultipath-update_bindings_file-don-t-log-temp-fil.patch new file mode 100644 index 0000000..1126b95 --- /dev/null +++ b/0016-libmultipath-update_bindings_file-don-t-log-temp-fil.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 22:33:39 +0200 +Subject: [PATCH] libmultipath: update_bindings_file: don't log temp file name + +The name of the temp file is unlikely to be helpful for users, +and hard to predict in the unit test. Omit it. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 92f90f05..afa5879e 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -167,8 +167,7 @@ static int update_bindings_file(const Bindings *bindings, + rc = write_bindings_file(bindings, fd); + pthread_cleanup_pop(1); + if (rc == -1) { +- condlog(1, "failed to write new bindings file %s", +- tempname); ++ condlog(1, "failed to write new bindings file"); + unlink(tempname); + return rc; + } diff --git a/0017-libmultipath-alias.c-factor-out-read_binding.patch b/0017-libmultipath-alias.c-factor-out-read_binding.patch new file mode 100644 index 0000000..8c9cb08 --- /dev/null +++ b/0017-libmultipath-alias.c-factor-out-read_binding.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 24 Aug 2023 21:17:25 +0200 +Subject: [PATCH] libmultipath: alias.c: factor out read_binding() + +This way we can test the parsing of input lines from the bindings +file more easily. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 58 ++++++++++++++++++++++++++++++-------------- + 1 file changed, 40 insertions(+), 18 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index afa5879e..ecf4a2ac 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -636,6 +636,43 @@ void cleanup_bindings(void) + free_bindings(&global_bindings); + } + ++enum { ++ READ_BINDING_OK, ++ READ_BINDING_SKIP, ++}; ++ ++static int read_binding(char *line, unsigned int linenr, char **alias, ++ char **wwid) { ++ char *c, *saveptr; ++ ++ c = strpbrk(line, "#\n\r"); ++ if (c) ++ *c = '\0'; ++ ++ *alias = strtok_r(line, " \t", &saveptr); ++ if (!*alias) /* blank line */ ++ return READ_BINDING_SKIP; ++ ++ *wwid = strtok_r(NULL, " \t", &saveptr); ++ if (!*wwid) { ++ condlog(1, "invalid line %u in bindings file, missing WWID", ++ linenr); ++ return READ_BINDING_SKIP; ++ } ++ if (strlen(*wwid) > WWID_SIZE - 1) { ++ condlog(3, ++ "Ignoring too large wwid at %u in bindings file", ++ linenr); ++ return READ_BINDING_SKIP; ++ } ++ c = strtok_r(NULL, " \t", &saveptr); ++ if (c) ++ /* This is non-fatal */ ++ condlog(1, "invalid line %d in bindings file, extra args \"%s\"", ++ linenr, c); ++ return READ_BINDING_OK; ++} ++ + static int _check_bindings_file(const struct config *conf, FILE *file, + Bindings *bindings) + { +@@ -647,27 +684,12 @@ static int _check_bindings_file(const struct config *conf, FILE *file, + + pthread_cleanup_push(cleanup_free_ptr, &line); + while ((n = getline(&line, &line_len, file)) >= 0) { +- char *c, *alias, *wwid, *saveptr; ++ char *alias, *wwid; + const char *mpe_wwid; + +- linenr++; +- c = strpbrk(line, "#\n\r"); +- if (c) +- *c = '\0'; +- alias = strtok_r(line, " \t", &saveptr); +- if (!alias) /* blank line */ +- continue; +- wwid = strtok_r(NULL, " \t", &saveptr); +- if (!wwid) { +- condlog(1, "invalid line %d in bindings file, missing WWID", +- linenr); ++ if (read_binding(line, ++linenr, &alias, &wwid) ++ == READ_BINDING_SKIP) + continue; +- } +- c = strtok_r(NULL, " \t", &saveptr); +- if (c) +- /* This is non-fatal */ +- condlog(1, "invalid line %d in bindings file, extra args \"%s\"", +- linenr, c); + + mpe_wwid = get_mpe_wwid(conf->mptable, alias); + if (mpe_wwid && strcmp(mpe_wwid, wwid)) { diff --git a/0018-libmultipath-keep-bindings-in-memory.patch b/0018-libmultipath-keep-bindings-in-memory.patch new file mode 100644 index 0000000..bb26ea2 --- /dev/null +++ b/0018-libmultipath-keep-bindings-in-memory.patch @@ -0,0 +1,545 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 22 Aug 2023 21:14:51 +0200 +Subject: [PATCH] libmultipath: keep bindings in memory + +Rather than opening the bindings file every time we must retrieve +a binding, keep the contents in memory and write the file only +if additions have been made. This simplifies the code, and should speed up +alias lookups significantly. As a side effect, the aliases will be stored +sorted by alias, which changes the way aliases are allocated if there are +unused "holes" in the sequence of aliases. For example, if the bindings file +contains mpathb, mpathy, and mpatha, in this order, the next new alias used to +be mpathz and is now mpathc. + +Another side effect is that multipathd will not automatically pick up changes +to the bindings file at runtime without a reconfigure operation. It is +questionable whether these on-the-fly changes were a good idea in the first +place, as inconsistent configurations may easily come to pass. It desired, +it would be feasible to implement automatic update of the bindings using the +existing inotify approach. + +The new implementation of get_user_friendly_alias() is slightly different +than before. The logic is summarized in a comment in the code. Unit tests +will be provided that illustrate the changes. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 351 ++++++++++++++++----------------------- + libmultipath/alias.h | 2 +- + libmultipath/configure.c | 3 +- + 3 files changed, 144 insertions(+), 212 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index ecf4a2ac..d6563749 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -50,8 +50,6 @@ + "# alias wwid\n" \ + "#\n" + +-static const char bindings_file_header[] = BINDINGS_FILE_HEADER; +- + struct binding { + char *alias; + char *wwid; +@@ -80,6 +78,45 @@ static void _free_binding(struct binding *bdg) + free(bdg); + } + ++static const struct binding *get_binding_for_alias(const Bindings *bindings, ++ const char *alias) ++{ ++ const struct binding *bdg; ++ int i; ++ ++ if (!alias) ++ return NULL; ++ vector_foreach_slot(bindings, bdg, i) { ++ if (!strncmp(bdg->alias, alias, WWID_SIZE)) { ++ condlog(3, "Found matching alias [%s] in bindings file." ++ " Setting wwid to %s", alias, bdg->wwid); ++ return bdg; ++ } ++ } ++ ++ condlog(3, "No matching alias [%s] in bindings file.", alias); ++ return NULL; ++} ++ ++static const struct binding *get_binding_for_wwid(const Bindings *bindings, ++ const char *wwid) ++{ ++ const struct binding *bdg; ++ int i; ++ ++ if (!wwid) ++ return NULL; ++ vector_foreach_slot(bindings, bdg, i) { ++ if (!strncmp(bdg->wwid, wwid, WWID_SIZE)) { ++ condlog(3, "Found matching wwid [%s] in bindings file." ++ " Setting alias to %s", wwid, bdg->alias); ++ return bdg; ++ } ++ } ++ condlog(3, "No matching wwid [%s] in bindings file.", wwid); ++ return NULL; ++} ++ + static int add_binding(Bindings *bindings, const char *alias, const char *wwid) + { + struct binding *bdg; +@@ -115,6 +152,24 @@ static int add_binding(Bindings *bindings, const char *alias, const char *wwid) + return BINDING_ERROR; + } + ++static int delete_binding(Bindings *bindings, const char *wwid) ++{ ++ struct binding *bdg; ++ int i; ++ ++ vector_foreach_slot(bindings, bdg, i) { ++ if (!strncmp(bdg->wwid, wwid, WWID_SIZE)) { ++ _free_binding(bdg); ++ break; ++ } ++ } ++ if (i >= VECTOR_SIZE(bindings)) ++ return BINDING_NOTFOUND; ++ ++ vector_del_slot(bindings, i); ++ return BINDING_DELETED; ++} ++ + static int write_bindings_file(const Bindings *bindings, int fd) + { + struct binding *bnd; +@@ -267,38 +322,15 @@ static bool id_already_taken(int id, const char *prefix, const char *map_wwid) + return alias_already_taken(alias, map_wwid); + } + +-/* +- * Returns: 0 if matching entry in WWIDs file found +- * -1 if an error occurs +- * >0 a free ID that could be used for the WWID at hand +- * *map_alias is set to a freshly allocated string with the matching alias if +- * the function returns 0, or to NULL otherwise. +- */ +-static int +-lookup_binding(FILE *f, const char *map_wwid, char **map_alias, +- const char *prefix, int check_if_taken) ++int get_free_id(const Bindings *bindings, const char *prefix, const char *map_wwid) + { +- char buf[LINE_MAX]; +- unsigned int line_nr = 0; +- int id = 1; ++ const struct binding *bdg; ++ int i, id = 1; + int biggest_id = 1; + int smallest_bigger_id = INT_MAX; + +- *map_alias = NULL; +- +- rewind(f); +- while (fgets(buf, LINE_MAX, f)) { +- const char *alias, *wwid; +- char *c, *saveptr; +- int curr_id; +- +- line_nr++; +- c = strpbrk(buf, "#\n\r"); +- if (c) +- *c = '\0'; +- alias = strtok_r(buf, " \t", &saveptr); +- if (!alias) /* blank line */ +- continue; ++ vector_foreach_slot(bindings, bdg, i) { ++ int curr_id = scan_devname(bdg->alias, prefix); + + /* + * Find an unused index - explanation of the algorithm +@@ -333,8 +365,6 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias, + * biggest_id is always > smallest_bigger_id, except in the + * "perfectly ordered" case. + */ +- +- curr_id = scan_devname(alias, prefix); + if (curr_id == id) { + if (id < INT_MAX) + id++; +@@ -345,36 +375,15 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias, + } + if (curr_id > biggest_id) + biggest_id = curr_id; ++ + if (curr_id > id && curr_id < smallest_bigger_id) + smallest_bigger_id = curr_id; +- wwid = strtok_r(NULL, " \t", &saveptr); +- if (!wwid){ +- condlog(3, +- "Ignoring malformed line %u in bindings file", +- line_nr); +- continue; +- } +- if (strcmp(wwid, map_wwid) == 0){ +- condlog(3, "Found matching wwid [%s] in bindings file." +- " Setting alias to %s", wwid, alias); +- *map_alias = strdup(alias); +- if (*map_alias == NULL) { +- condlog(0, "Cannot copy alias from bindings " +- "file: out of memory"); +- return -1; +- } +- 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) { ++ ++ if (id >= smallest_bigger_id) ++ id = biggest_id < INT_MAX ? biggest_id + 1 : -1; ++ ++ if (id > 0) { + while(id_already_taken(id, prefix, map_wwid)) { + if (id == INT_MAX) { + id = -1; +@@ -391,64 +400,17 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias, + } + } + } +- if (id < 0) { ++ ++ if (id < 0) + condlog(0, "no more available user_friendly_names"); +- return -1; +- } else +- condlog(3, "No matching wwid [%s] in bindings file.", map_wwid); + return id; + } + +-static int +-rlookup_binding(FILE *f, char *buff, const char *map_alias) +-{ +- char line[LINE_MAX]; +- unsigned int line_nr = 0; +- +- buff[0] = '\0'; +- +- while (fgets(line, LINE_MAX, f)) { +- char *c, *saveptr; +- const char *alias, *wwid; +- +- line_nr++; +- c = strpbrk(line, "#\n\r"); +- if (c) +- *c = '\0'; +- alias = strtok_r(line, " \t", &saveptr); +- if (!alias) /* blank line */ +- continue; +- wwid = strtok_r(NULL, " \t", &saveptr); +- if (!wwid){ +- condlog(3, +- "Ignoring malformed line %u in bindings file", +- line_nr); +- continue; +- } +- if (strlen(wwid) > WWID_SIZE - 1) { +- condlog(3, +- "Ignoring too large wwid at %u in bindings file", line_nr); +- continue; +- } +- if (strcmp(alias, map_alias) == 0){ +- condlog(3, "Found matching alias [%s] in bindings file." +- " Setting wwid to %s", alias, wwid); +- strlcpy(buff, wwid, WWID_SIZE); +- return 0; +- } +- } +- condlog(3, "No matching alias [%s] in bindings file.", map_alias); +- +- return -1; +-} +- + static char * +-allocate_binding(int fd, const char *wwid, int id, const char *prefix) ++allocate_binding(const char *filename, const char *wwid, int id, const char *prefix) + { + STRBUF_ON_STACK(buf); +- off_t offset; +- ssize_t len; +- char *alias, *c; ++ char *alias; + + if (id <= 0) { + condlog(0, "%s: cannot allocate new binding for id %d", +@@ -460,164 +422,135 @@ allocate_binding(int fd, const char *wwid, int id, const char *prefix) + format_devname(&buf, id) == -1) + return NULL; + +- if (print_strbuf(&buf, " %s\n", wwid) < 0) +- return NULL; ++ alias = steal_strbuf_str(&buf); + +- offset = lseek(fd, 0, SEEK_END); +- if (offset < 0){ +- condlog(0, "Cannot seek to end of bindings file : %s", +- strerror(errno)); ++ if (add_binding(&global_bindings, alias, wwid) != BINDING_ADDED) { ++ condlog(0, "%s: cannot allocate new binding %s for %s", ++ __func__, alias, wwid); ++ free(alias); + return NULL; + } + +- len = get_strbuf_len(&buf); +- alias = steal_strbuf_str(&buf); +- +- if (write(fd, alias, len) != len) { +- condlog(0, "Cannot write binding to bindings file : %s", +- strerror(errno)); +- /* clear partial write */ +- if (ftruncate(fd, offset)) +- condlog(0, "Cannot truncate the header : %s", +- strerror(errno)); ++ if (update_bindings_file(&global_bindings, filename) == -1) { ++ condlog(1, "%s: deleting binding %s for %s", __func__, alias, wwid); ++ delete_binding(&global_bindings, wwid); + free(alias); + return NULL; + } +- c = strchr(alias, ' '); +- if (c) +- *c = '\0'; + + condlog(3, "Created new binding [%s] for WWID [%s]", alias, wwid); + return alias; + } + ++/* ++ * get_user_friendly_alias() action table ++ * ++ * The table shows the various cases, the actions taken, and the CI ++ * functions from tests/alias.c that represent them. ++ * ++ * - O: old alias given ++ * - A: old alias in table (y: yes, correct WWID; X: yes, wrong WWID) ++ * - W: wwid in table ++ * ++ * | No | O | A | W | action | function gufa_X | ++ * |----+---+---+---+--------------------------------------------+------------------------------| ++ * | 1 | n | - | n | get new alias | nomatch_Y | ++ * | 2 | n | - | y | use alias from bindings | match_a_Y | ++ * | 3 | y | n | n | add binding for old alias | old_nomatch_nowwidmatch | ++ * | 4 | y | n | y | use alias from bindings (avoid duplicates) | old_nomatch_wwidmatch | ++ * | 5 | y | y | n | [ impossible ] | - | ++ * | 6 | y | y | y | use old alias == alias from bindings | old_match | ++ * | 7 | y | X | n | get new alias | old_match_other | ++ * | 8 | y | X | y | use alias from bindings | old_match_other_wwidmatch | ++ * ++ * Notes: ++ * - "use alias from bindings" means that the alias from the bindings file will ++ * be tried; if it is in use, the alias selection will fail. No other ++ * bindings will be attempted. ++ * - "get new alias" fails if all aliases are used up, or if writing the ++ * bindings file fails. ++ * - if "alias_old" is set, it can't be bound to a different map. alias_old is ++ * initialized in find_existing_alias() by scanning the mpvec. We trust ++ * that the mpvec corrcectly represents kernel state. ++ */ ++ + char *get_user_friendly_alias(const char *wwid, const char *file, const char *alias_old, + const char *prefix, bool bindings_read_only) + { + char *alias = NULL; + int id = 0; +- int fd, can_write; + bool new_binding = false; +- char buff[WWID_SIZE]; +- FILE *f; +- +- fd = open_file(file, &can_write, bindings_file_header); +- if (fd < 0) +- return NULL; +- +- f = fdopen(fd, "r"); +- if (!f) { +- condlog(0, "cannot fdopen on bindings file descriptor"); +- close(fd); +- return NULL; +- } ++ const struct binding *bdg; + +- if (!strlen(alias_old)) ++ if (!*alias_old) + goto new_alias; + +- /* lookup the binding. if it exists, the wwid will be in buff +- * either way, id contains the id for the alias +- */ +- rlookup_binding(f, buff, alias_old); +- +- if (strlen(buff) > 0) { +- /* If buff is our wwid, it's already allocated correctly. */ +- if (strcmp(buff, wwid) == 0) { ++ /* See if there's a binding matching both alias_old and wwid */ ++ bdg = get_binding_for_alias(&global_bindings, alias_old); ++ if (bdg) { ++ if (!strcmp(bdg->wwid, wwid)) { + alias = strdup(alias_old); + goto out; +- + } else { + condlog(0, "alias %s already bound to wwid %s, cannot reuse", +- alias_old, buff); ++ alias_old, bdg->wwid); + goto new_alias; + } + } + +- /* +- * Look for an existing alias in the bindings file. +- * Pass prefix = NULL, so lookup_binding() won't try to allocate a new id. +- */ +- lookup_binding(f, wwid, &alias, NULL, 0); +- if (alias) { +- if (alias_already_taken(alias, wwid)) { +- free(alias); +- alias = NULL; +- } else ++ /* allocate the existing alias in the bindings file */ ++ id = scan_devname(alias_old, prefix); ++ ++new_alias: ++ /* Check for existing binding of WWID */ ++ bdg = get_binding_for_wwid(&global_bindings, wwid); ++ if (bdg) { ++ if (!alias_already_taken(bdg->alias, wwid)) { + condlog(3, "Use existing binding [%s] for WWID [%s]", +- alias, wwid); ++ bdg->alias, wwid); ++ alias = strdup(bdg->alias); ++ } + goto out; + } + +- /* alias_old is already taken by our WWID, update bindings file. */ +- id = scan_devname(alias_old, prefix); +- +-new_alias: + if (id <= 0) { + /* + * no existing alias was provided, or allocating it + * failed. Try a new one. + */ +- id = lookup_binding(f, wwid, &alias, prefix, 1); +- if (id == 0 && alias_already_taken(alias, wwid)) { +- free(alias); +- alias = NULL; +- } ++ id = get_free_id(&global_bindings, prefix, wwid); + if (id <= 0) + goto out; + else + new_binding = true; + } + +- if (fflush(f) != 0) { +- condlog(0, "cannot fflush bindings file stream : %s", +- strerror(errno)); +- goto out; +- } ++ if (!bindings_read_only && id > 0) ++ alias = allocate_binding(file, wwid, id, prefix); + +- if (can_write && !bindings_read_only) { +- alias = allocate_binding(fd, wwid, id, prefix); +- if (alias && !new_binding) +- condlog(2, "Allocated existing binding [%s] for WWID [%s]", +- alias, wwid); +- } ++ if (alias && !new_binding) ++ condlog(2, "Allocated existing binding [%s] for WWID [%s]", ++ alias, wwid); + + out: +- pthread_cleanup_push(free, alias); +- fclose(f); +- pthread_cleanup_pop(0); + return alias; + } + +-int +-get_user_friendly_wwid(const char *alias, char *buff, const char *file) ++int get_user_friendly_wwid(const char *alias, char *buff) + { +- int fd, unused; +- FILE *f; ++ const struct binding *bdg; + + if (!alias || *alias == '\0') { + condlog(3, "Cannot find binding for empty alias"); + return -1; + } + +- fd = open_file(file, &unused, bindings_file_header); +- if (fd < 0) +- return -1; +- +- f = fdopen(fd, "r"); +- if (!f) { +- condlog(0, "cannot fdopen on bindings file descriptor : %s", +- strerror(errno)); +- close(fd); ++ bdg = get_binding_for_alias(&global_bindings, alias); ++ if (!bdg) { ++ *buff = '\0'; + return -1; + } +- +- rlookup_binding(f, buff, alias); +- if (!strlen(buff)) { +- fclose(f); +- return -1; +- } +- +- fclose(f); ++ strlcpy(buff, bdg->wwid, WWID_SIZE); + return 0; + } + +diff --git a/libmultipath/alias.h b/libmultipath/alias.h +index 37b49d9c..5ef6720b 100644 +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -2,7 +2,7 @@ + #define _ALIAS_H + + int valid_alias(const char *alias); +-int get_user_friendly_wwid(const char *alias, char *buff, const char *file); ++int get_user_friendly_wwid(const char *alias, char *buff); + char *get_user_friendly_alias(const char *wwid, const char *file, + const char *alias_old, + const char *prefix, bool bindings_read_only); +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 029fbbd2..d8094903 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -1378,8 +1378,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev, + refwwid = tmpwwid; + + /* or may be a binding */ +- else if (get_user_friendly_wwid(dev, tmpwwid, +- conf->bindings_file) == 0) ++ else if (get_user_friendly_wwid(dev, tmpwwid) == 0) + refwwid = tmpwwid; + + /* or may be an alias */ diff --git a/0019-multipath-tools-tests-fix-alias-tests.patch b/0019-multipath-tools-tests-fix-alias-tests.patch new file mode 100644 index 0000000..da618f6 --- /dev/null +++ b/0019-multipath-tools-tests-fix-alias-tests.patch @@ -0,0 +1,1698 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 25 Aug 2023 17:55:55 +0200 +Subject: [PATCH] multipath-tools tests: fix alias tests + +The different implementation of get_user_friendly_alias() and its helpers +necessitates changes in the unit tests. It would be nice if it didn't, but the +unit tests are too closely bound to the implementation to make this possible. + +- The bindings table is held in memory in alphabetically sorted order, which + may change the result of looking for free alias IDs if the entries in the + bindings file were unordered initially. In particular, if only a small + number of bindings exists, "holes" in the file will be detected more easily. + But because the sort order of the aliases differs from simple alphabetic + sorting ("mpathz" precedes "mpathaa"), a bindings file that contains all + bindings from "a" to "aa" (or more) will appear unsorted. + As an extra check, some of the unit tests deliberately use a different + implementation of add_binding() that does not order the bindings + table. + +- Broken lines in the bindings file never make it to the in-memory + representation. An alias that appeard "used" because it occurred in a broken + line will not appear used any more. Warnings about malformed lines will only + be printed while the bindings file is read, not from get_user_friendly_alias(). + +- The match_line argument of mock_bindings_file() is obsolete. + +- lookup_binding() and rlookup_binding() have been removed from + libmultipath. They are now emulated in the unit test code. + +- lookup_binding() didn't check for used alias in all cases previously, but it does now. + +- prefix != NULL and check_if_taken == false is not supported any more + in lookup_binding(). + +- allocate_binding() uses a very different sequence of systems calls now, as + it's implemented using update_bindings_file(). In particular, it's now more + difficult to predict the content of the write() call that creates the + bindings file. See comments for __wrap_write(). + +- some unit tests for get_user_friendly_alias() had to call + mock_bindings_file() twice, because the old implementation would read the + file twice (first rlookup_binding() and then lookup_binding()). This is not + necessary any more. + +- The unit tests need a teardown function to clear the bindings table in memory. + +- Minor changes are necessary because of changed ordering of the log messages. + Previously, lookup_binding() combined check for an existing entry and the + search for a new ID. The new algorithm does this in two separate steps and + tests for used aliases in between, which causes a change in the order in which + log messages are emitted. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 957 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 614 insertions(+), 343 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index f334f928..50a21ecf 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -3,10 +3,12 @@ + #include + #include + #include ++#include "strbuf.h" + #include "util.h" + #include "alias.h" + #include "test-log.h" + #include ++#include + + #include "globals.c" + #include "../libmultipath/alias.c" +@@ -20,18 +22,6 @@ + #define MPATH_ID_INT_MAX_p1 "fxshrxx" + #endif + +-void __wrap_rewind(FILE *stream) +-{} +- +-char *__wrap_fgets(char *buf, int n, FILE *stream) +-{ +- char *val = mock_ptr_type(char *); +- if (!val) +- return NULL; +- strlcpy(buf, val, n); +- return buf; +-} +- + static int __set_errno(int err) + { + if (err >= 0) { +@@ -43,23 +33,44 @@ static int __set_errno(int err) + } + } + +-off_t __wrap_lseek(int fd, off_t offset, int whence) ++/* ++ * allocate_binding -> write_bindings_file() writes the entire file, i.e. the ++ * header, any pre-existing bindings, and the new binding. The complete content ++ * depends on history and is different to predict here. Therefore we check only ++ * the newly added binding. Because add_binding() sorts entries, this new ++ * binding isn't necessarily the last one; receive it from will_return() and ++ * search for it with strstr(). ++ * If the string to be written doesn't start with the bindings file ++ * header, it's a test of a partial write. ++ */ ++ssize_t __wrap_write(int fd, const void *buf, size_t count) + { +- return __set_errno(mock_type(int)); ++ const char *binding, *start; + ++#if DEBUG_WRITE ++ fprintf(stderr, "%s: %zx exp %zx\n===\n%s\n===\n", __func__, strlen(buf), ++ count, (const char *)buf); ++#endif ++ if (!strncmp((const char *)buf, BINDINGS_FILE_HEADER, ++ sizeof(BINDINGS_FILE_HEADER) - 1)) ++ start = (const char *)buf + sizeof(BINDINGS_FILE_HEADER) - 1; ++ else ++ start = buf; ++ binding = mock_ptr_type(char *); ++ start = strstr(start, binding); ++ check_expected(count); ++ assert_ptr_not_equal(start, NULL); ++ return __set_errno(mock_type(int)); + } + +-ssize_t __wrap_write(int fd, const void *buf, size_t count) ++int __wrap_rename(const char *old, const char *new) + { +- check_expected(count); +- check_expected(buf); + return __set_errno(mock_type(int)); + } + +-int __wrap_ftruncate(int fd, off_t length) ++int __wrap_mkstemp(char *template) + { +- check_expected(length); +- return __set_errno(mock_type(int)); ++ return 10; + } + + int __wrap_dm_map_present(const char * str) +@@ -84,32 +95,6 @@ int __wrap_dm_get_uuid(const char *name, char *uuid, int uuid_len) + #define TEST_FDNO 1234 + #define TEST_FPTR ((FILE *) 0xaffe) + +-int __wrap_open_file(const char *file, int *can_write, const char *header) +-{ +- int cw = mock_type(int); +- +- *can_write = cw; +- return TEST_FDNO; +-} +- +-FILE *__wrap_fdopen(int fd, const char *mode) +-{ +- assert_int_equal(fd, TEST_FDNO); +- return TEST_FPTR; +-} +- +-int __wrap_fflush(FILE *f) +-{ +- assert_ptr_equal(f, TEST_FPTR); +- return 0; +-} +- +-int __wrap_fclose(FILE *f) +-{ +- assert_ptr_equal(f, TEST_FPTR); +- return 0; +-} +- + /* strbuf wrapper for the old format_devname() */ + static int __format_devname(char *name, int id, size_t len, const char *prefix) + { +@@ -466,22 +451,85 @@ static void mock_self_alias(const char *alias, const char *wwid) + expect_condlog(3, USED_STR(alias, wwid)); \ + } while(0) + +-static void mock_bindings_file(const char *content, int match_line) ++static int add_binding_unsorted(Bindings *bindings, ++ const char *alias, const char *wwid) ++{ ++ struct binding *bdg = calloc(1, sizeof(*bdg)); ++ ++ if (!bdg) ++ return -1; ++ bdg->wwid = strdup(wwid); ++ bdg->alias = strdup(alias); ++ if (!bdg->wwid || !bdg->alias || !vector_alloc_slot(bindings)) { ++ free(bdg->alias); ++ free(bdg->wwid); ++ free(bdg); ++ return BINDING_ERROR; ++ } ++ vector_set_slot(bindings, bdg); ++ return BINDING_ADDED; ++} ++ ++static void __mock_bindings_file(const char *content, ++ int (*add)(Bindings *, const char *, const char *)) + { +- static char cnt[1024]; +- char *token; ++ char *cnt __attribute__((cleanup(cleanup_charp))) = NULL; ++ char *token, *savep = NULL; + int i; + +- assert_in_range(strlcpy(cnt, content, sizeof(cnt)), 0, sizeof(cnt) - 1); ++ cnt = strdup(content); ++ assert_ptr_not_equal(cnt, NULL); + +- for (token = strtok(cnt, "\n"), i = 0; ++ for (token = strtok_r(cnt, "\n", &savep), i = 0; + token && *token; +- token = strtok(NULL, "\n"), i++) { +- will_return(__wrap_fgets, token); +- if (match_line == i) +- return; ++ token = strtok_r(NULL, "\n", &savep), i++) { ++ char *alias, *wwid; ++ int rc; ++ ++ if (read_binding(token, i + 1, &alias, &wwid) ++ == READ_BINDING_SKIP) ++ continue; ++ ++ rc = add(&global_bindings, alias, wwid); ++ assert_int_equal(rc, BINDING_ADDED); + } +- will_return(__wrap_fgets, NULL); ++} ++ ++static void mock_bindings_file(const char *content) { ++ return __mock_bindings_file(content, add_binding); ++} ++ ++static void mock_bindings_file_unsorted(const char *content) { ++ return __mock_bindings_file(content, add_binding_unsorted); ++} ++ ++static int teardown_bindings(void **state) ++{ ++ cleanup_bindings(); ++ return 0; ++} ++ ++static int lookup_binding(FILE *dummy, const char *wwid, char **alias, ++ const char *prefix, int check_if_taken) ++{ ++ const struct binding *bdg; ++ int id; ++ ++ /* ++ * get_free_id() always checks if aliases are taken. ++ * Therefore if prefix is non-null, check_if_taken must be true. ++ */ ++ assert_true(!prefix || check_if_taken); ++ *alias = NULL; ++ bdg = get_binding_for_wwid(&global_bindings, wwid); ++ if (bdg) { ++ *alias = strdup(bdg->alias); ++ return 0; ++ } else if (!prefix && check_if_taken) ++ return -1; ++ ++ id = get_free_id(&global_bindings, prefix, wwid); ++ return id; + } + + static void lb_empty(void **state) +@@ -489,7 +537,7 @@ static void lb_empty(void **state) + int rc; + char *alias; + +- mock_bindings_file("", -1); ++ mock_bindings_file(""); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, NULL, 0); + assert_int_equal(rc, 1); +@@ -501,7 +549,7 @@ static void lb_empty_unused(void **state) + int rc; + char *alias; + +- mock_bindings_file("", -1); ++ mock_bindings_file(""); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); +@@ -515,10 +563,10 @@ static void lb_empty_failed(void **state) + int rc; + char *alias; + +- mock_bindings_file("", -1); ++ mock_bindings_file(""); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_failed_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -530,10 +578,10 @@ static void lb_empty_1_used(void **state) + int rc; + char *alias; + +- mock_bindings_file("", -1); ++ mock_bindings_file(""); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_used_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -545,10 +593,10 @@ static void lb_empty_1_used_self(void **state) + int rc; + char *alias; + +- mock_bindings_file("", -1); ++ mock_bindings_file(""); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_used_alias("MPATHa", "WWID0"); + mock_self_alias("MPATHb", "WWID0"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); +@@ -560,9 +608,9 @@ static void lb_match_a(void **state) + int rc; + char *alias; + +- mock_bindings_file("MPATHa WWID0\n", 0); ++ mock_bindings_file("MPATHa WWID0\n"); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); +- rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 0); ++ rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); + assert_int_equal(rc, 0); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHa"); +@@ -574,9 +622,10 @@ static void lb_nomatch_a(void **state) + int rc; + char *alias; + +- mock_bindings_file("MPATHa WWID0\n", -1); ++ mock_bindings_file("MPATHa WWID0\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); +- rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 0); ++ mock_unused_alias("MPATHb"); ++ rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } +@@ -586,8 +635,8 @@ static void lb_nomatch_a_bad_check(void **state) + int rc; + char *alias; + +- mock_bindings_file("MPATHa WWID0\n", -1); +- expect_condlog(0, NOMORE_STR); ++ mock_bindings_file("MPATHa WWID0\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, NULL, 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); +@@ -598,7 +647,7 @@ static void lb_nomatch_a_unused(void **state) + int rc; + char *alias; + +- mock_bindings_file("MPATHa WWID0\n", -1); ++ mock_bindings_file("MPATHa WWID0\n"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); +@@ -611,27 +660,27 @@ static void lb_nomatch_a_3_used_failed_self(void **state) + int rc; + char *alias; + +- mock_bindings_file("MPATHa WWID0\n", -1); ++ mock_bindings_file("MPATHa WWID0\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + mock_used_alias("MPATHb", "WWID1"); + mock_used_alias("MPATHc", "WWID1"); + mock_used_alias("MPATHd", "WWID1"); + mock_failed_alias("MPATHe", "WWID1"); + mock_self_alias("MPATHf", "WWID1"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); + assert_int_equal(rc, 6); + assert_ptr_equal(alias, NULL); + } + +-static void do_lb_match_c(void **state, int check_if_taken) ++static void do_lb_match_c(void **state) + { + int rc; + char *alias; + + mock_bindings_file("MPATHa WWID0\n" +- "MPATHc WWID1", 1); ++ "MPATHc WWID1"); + expect_condlog(3, FOUND_STR("MPATHc", "WWID1")); +- rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", check_if_taken); ++ rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); + assert_int_equal(rc, 0); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHc"); +@@ -640,12 +689,12 @@ static void do_lb_match_c(void **state, int check_if_taken) + + static void lb_match_c(void **state) + { +- do_lb_match_c(state, 0); ++ do_lb_match_c(state); + } + + static void lb_match_c_check(void **state) + { +- do_lb_match_c(state, 1); ++ do_lb_match_c(state); + } + + static void lb_nomatch_a_c(void **state) +@@ -654,9 +703,10 @@ static void lb_nomatch_a_c(void **state) + char *alias; + + mock_bindings_file("MPATHa WWID0\n" +- "MPATHc WWID1", -1); ++ "MPATHc WWID1"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); ++ mock_unused_alias("MPATHb"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } +@@ -667,7 +717,7 @@ static void lb_nomatch_a_d_unused(void **state) + char *alias; + + mock_bindings_file("MPATHa WWID0\n" +- "MPATHd WWID1", -1); ++ "MPATHd WWID1"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -681,10 +731,10 @@ static void lb_nomatch_a_d_1_used(void **state) + char *alias; + + mock_bindings_file("MPATHa WWID0\n" +- "MPATHd WWID1", -1); ++ "MPATHd WWID1"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + mock_used_alias("MPATHb", "WWID2"); + mock_unused_alias("MPATHc"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); +@@ -696,11 +746,11 @@ static void lb_nomatch_a_d_2_used(void **state) + char *alias; + + mock_bindings_file("MPATHa WWID0\n" +- "MPATHd WWID1", -1); ++ "MPATHd WWID1"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + mock_used_alias("MPATHb", "WWID2"); + mock_used_alias("MPATHc", "WWID2"); + mock_unused_alias("MPATHe"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 5); + assert_ptr_equal(alias, NULL); +@@ -712,12 +762,12 @@ static void lb_nomatch_a_d_3_used(void **state) + char *alias; + + mock_bindings_file("MPATHa WWID0\n" +- "MPATHd WWID1", -1); ++ "MPATHd WWID1"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + mock_used_alias("MPATHb", "WWID2"); + mock_used_alias("MPATHc", "WWID2"); + mock_used_alias("MPATHe", "WWID2"); + mock_unused_alias("MPATHf"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 6); + assert_ptr_equal(alias, NULL); +@@ -729,9 +779,10 @@ static void lb_nomatch_c_a(void **state) + char *alias; + + mock_bindings_file("MPATHc WWID1\n" +- "MPATHa WWID0\n", -1); ++ "MPATHa WWID0\n"); ++ mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } +@@ -743,7 +794,7 @@ static void lb_nomatch_d_a_unused(void **state) + + mock_bindings_file("MPATHc WWID1\n" + "MPATHa WWID0\n" +- "MPATHd WWID0\n", -1); ++ "MPATHd WWID0\n"); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +@@ -758,10 +809,10 @@ static void lb_nomatch_d_a_1_used(void **state) + + mock_bindings_file("MPATHc WWID1\n" + "MPATHa WWID0\n" +- "MPATHd WWID0\n", -1); ++ "MPATHd WWID0\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + mock_used_alias("MPATHb", "WWID2"); + mock_unused_alias("MPATHe"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 5); + assert_ptr_equal(alias, NULL); +@@ -774,9 +825,10 @@ static void lb_nomatch_a_b(void **state) + + mock_bindings_file("MPATHa WWID0\n" + "MPATHz WWID26\n" +- "MPATHb WWID1\n", -1); ++ "MPATHb WWID1\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); ++ mock_unused_alias("MPATHc"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); + assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); + } +@@ -786,13 +838,19 @@ static void lb_nomatch_a_b_bad(void **state) + int rc; + char *alias; + ++ expect_condlog(1, "invalid line 3 in bindings file, missing WWID\n"); ++ /* ++ * The broken line will be ignored when constructing the bindings vector. ++ * Thus in lookup_binding() MPATHb is never encountered, ++ * and MPATHb appears usable. ++ */ + mock_bindings_file("MPATHa WWID0\n" + "MPATHz WWID26\n" +- "MPATHb\n", -1); +- expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); ++ "MPATHb\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); +- assert_int_equal(rc, 3); ++ mock_unused_alias("MPATHb"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } + +@@ -801,84 +859,200 @@ static void lb_nomatch_a_b_bad_self(void **state) + int rc; + char *alias; + ++ expect_condlog(1, "invalid line 3 in bindings file, missing WWID\n"); + mock_bindings_file("MPATHa WWID0\n" + "MPATHz WWID26\n" +- "MPATHb\n", -1); +- expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); +- mock_self_alias("MPATHc", "WWID2"); ++ "MPATHb\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); ++ mock_self_alias("MPATHb", "WWID2"); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +- assert_int_equal(rc, 3); ++ assert_int_equal(rc, 2); + assert_ptr_equal(alias, NULL); + } + +-static void lb_nomatch_b_a(void **state) ++static void lb_nomatch_b_z_a(void **state) + { + int rc; + char *alias; + ++ /* ++ * add_bindings() sorts alphabetically. Therefore get_free_id() ++ * finds MPATHc as a free entry. ++ */ + mock_bindings_file("MPATHb WWID1\n" + "MPATHz WWID26\n" +- "MPATHa WWID0\n", -1); ++ "MPATHa WWID0\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); +- assert_int_equal(rc, 27); ++ mock_unused_alias("MPATHc"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); + } + +-static void lb_nomatch_b_a_3_used(void **state) ++static void lb_nomatch_b_aa_a(void **state) + { + int rc; + char *alias; + ++ /* ++ * add_bindings() sorts alphabetically. ("a", "aa", b"). ++ * The get_free_id() algorithm finds the "hole" after "b". ++ */ + mock_bindings_file("MPATHb WWID1\n" + "MPATHz WWID26\n" +- "MPATHa WWID0\n", -1); +- mock_used_alias("MPATHaa", "WWID2"); +- mock_used_alias("MPATHab", "WWID2"); +- mock_used_alias("MPATHac", "WWID2"); +- mock_unused_alias("MPATHad"); ++ "MPATHa WWID0\n"); + expect_condlog(3, NOMATCH_WWID_STR("WWID2")); ++ mock_unused_alias("MPATHc"); + rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +- assert_int_equal(rc, 30); ++ assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); + } + +-#ifdef MPATH_ID_INT_MAX +-static void do_lb_nomatch_int_max(void **state, int check_if_taken) ++static void fill_bindings(struct strbuf *buf, int start, int end) ++{ ++ int i; ++ ++ for (i = start; i <= end; i++) { ++ print_strbuf(buf, "MPATH"); ++ format_devname(buf, i + 1); ++ print_strbuf(buf, " WWID%d\n", i); ++ } ++} ++ ++static void lb_nomatch_b_a_aa(void **state) ++{ ++ int rc; ++ char *alias; ++ STRBUF_ON_STACK(buf); ++ ++ /* ++ * add_bindings() sorts alphabetically. ("a", "aa", "ab", "b", "c", ...) ++ * lookup_binding finds MPATHac as next free entry. ++ */ ++ fill_bindings(&buf, 0, 26); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID28")); ++ mock_unused_alias("MPATHab"); ++ rc = lookup_binding(NULL, "WWID28", &alias, "MPATH", 1); ++ assert_int_equal(rc, 28); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void lb_nomatch_b_a_aa_zz(void **state) ++{ ++ int rc, i; ++ char *alias; ++ STRBUF_ON_STACK(buf); ++ ++ /* ++ * add_bindings() sorts alphabetically. ("a", "aa", "ab", "b", "c", ...) ++ * lookup_binding finds MPATHaaa as next free entry, because MPATHaa is ++ * found before MPATHb, and MPATHzz was in the bindings, too. ++ */ ++ for (i = 0; i <= 26; i++) { ++ print_strbuf(&buf, "MPATH"); ++ format_devname(&buf, i + 1); ++ print_strbuf(&buf, " WWID%d\n", i); ++ } ++ print_strbuf(&buf, "MPATHzz WWID676\n"); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID703")); ++ mock_unused_alias("MPATHaaa"); ++ rc = lookup_binding(NULL, "WWID703", &alias, "MPATH", 1); ++ assert_int_equal(rc, 703); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void lb_nomatch_b_z_a_unsorted(void **state) ++{ ++ int rc; ++ char *alias; ++ ++ /* ++ * With unsorted bindings (shouldn't happen normally), get_free_id() ++ * plays safe and returns MPATHaa as first free entry. ++ */ ++ mock_bindings_file_unsorted("MPATHb WWID1\n" ++ "MPATHz WWID26\n" ++ "MPATHa WWID0\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); ++ mock_unused_alias("MPATHaa"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ assert_int_equal(rc, 27); ++ assert_ptr_equal(alias, NULL); ++} ++ ++static void lb_nomatch_b_a(void **state) + { + int rc; + char *alias; + + mock_bindings_file("MPATHb WWID1\n" +- "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n" +- "MPATHa WWID0\n", -1); +- expect_condlog(0, NOMORE_STR); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", check_if_taken); +- assert_int_equal(rc, -1); ++ "MPATHa WWID0\n"); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID2")); ++ mock_unused_alias("MPATHc"); ++ rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ assert_int_equal(rc, 3); + assert_ptr_equal(alias, NULL); + } + +-static void lb_nomatch_int_max(void **state) ++static void lb_nomatch_b_a_3_used(void **state) + { +- do_lb_nomatch_int_max(state, 0); ++ int rc; ++ char *alias; ++ STRBUF_ON_STACK(buf); ++ ++ fill_bindings(&buf, 0, 26); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID31")); ++ mock_used_alias("MPATHab", "WWID31"); ++ mock_used_alias("MPATHac", "WWID31"); ++ mock_used_alias("MPATHad", "WWID31"); ++ mock_unused_alias("MPATHae"); ++ rc = lookup_binding(NULL, "WWID31", &alias, "MPATH", 1); ++ assert_int_equal(rc, 31); ++ assert_ptr_equal(alias, NULL); + } + +-static void lb_nomatch_int_max_check(void **state) ++#ifdef MPATH_ID_INT_MAX ++/* ++ * The bindings will be sorted by alias, alphabetically, which is not ++ * the same as the "numeric" sort order for user-friendly aliases. ++ * get_free_id() selects the highest used ID + 1 if an unsorted entry ++ * is encountered in the bindings table and it's id is equal to the ++ * next "expected" id. This happens if all IDs from "a" to "aa" are ++ * in the table. If the INT_MAX entry is in the table, too, it will ++ * overflow. ++ */ ++static void lb_nomatch_int_max(void **state) + { +- do_lb_nomatch_int_max(state, 1); ++ int rc; ++ char *alias; ++ STRBUF_ON_STACK(buf); ++ ++ fill_bindings(&buf, 0, 26); ++ print_strbuf(&buf, "MPATH%s WWIDMAX\n", MPATH_ID_INT_MAX); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWIDNOMORE")); ++ expect_condlog(0, NOMORE_STR); ++ rc = lookup_binding(NULL, "WWIDNOMORE", &alias, "MPATH", 1); ++ assert_int_equal(rc, -1); ++ assert_ptr_equal(alias, NULL); + } + + static void lb_nomatch_int_max_used(void **state) + { + int rc; + char *alias; ++ STRBUF_ON_STACK(buf); + +- mock_bindings_file("MPATHb WWID1\n" +- "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n", -1); +- mock_used_alias("MPATHa", "WWID2"); ++ fill_bindings(&buf, 1, 26); ++ print_strbuf(&buf, "MPATH%s WWIDMAX\n", MPATH_ID_INT_MAX); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWIDNOMORE")); ++ mock_used_alias("MPATHa", "WWIDNOMORE"); + expect_condlog(0, NOMORE_STR); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ rc = lookup_binding(NULL, "WWIDNOMORE", &alias, "MPATH", 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); + } +@@ -887,12 +1061,14 @@ static void lb_nomatch_int_max_m1(void **state) + { + int rc; + char *alias; ++ STRBUF_ON_STACK(buf); + +- mock_bindings_file("MPATHb WWID1\n" +- "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n" +- "MPATHa WWID0\n", -1); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 0); ++ fill_bindings(&buf, 0, 26); ++ print_strbuf(&buf, "MPATH%s WWIDMAXM1\n", MPATH_ID_INT_MAX_m1); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); ++ mock_unused_alias("MPATH" MPATH_ID_INT_MAX); ++ rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); + assert_int_equal(rc, INT_MAX); + assert_ptr_equal(alias, NULL); + } +@@ -901,13 +1077,15 @@ static void lb_nomatch_int_max_m1_used(void **state) + { + int rc; + char *alias; ++ STRBUF_ON_STACK(buf); + +- mock_bindings_file("MPATHb WWID1\n" +- "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n" +- "MPATHa WWID0\n", -1); +- mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWID2"); ++ fill_bindings(&buf, 0, 26); ++ print_strbuf(&buf, "MPATH%s WWIDMAXM1\n", MPATH_ID_INT_MAX_m1); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); ++ mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWIDMAX"); + expect_condlog(0, NOMORE_STR); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); + } +@@ -916,13 +1094,15 @@ static void lb_nomatch_int_max_m1_1_used(void **state) + { + int rc; + char *alias; ++ STRBUF_ON_STACK(buf); + +- mock_bindings_file("MPATHb WWID1\n" +- "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n", -1); +- mock_used_alias("MPATHa", "WWID2"); ++ fill_bindings(&buf, 1, 26); ++ print_strbuf(&buf, "MPATH%s WWIDMAXM1\n", MPATH_ID_INT_MAX_m1); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); ++ mock_used_alias("MPATHa", "WWIDMAX"); + mock_unused_alias("MPATH" MPATH_ID_INT_MAX); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); + assert_int_equal(rc, INT_MAX); + assert_ptr_equal(alias, NULL); + } +@@ -931,13 +1111,17 @@ static void lb_nomatch_int_max_m1_2_used(void **state) + { + int rc; + char *alias; ++ STRBUF_ON_STACK(buf); + +- mock_bindings_file("MPATHb WWID1\n" +- "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n", -1); +- mock_used_alias("MPATHa", "WWID2"); +- mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWID2"); ++ fill_bindings(&buf, 1, 26); ++ print_strbuf(&buf, "MPATH%s WWIDMAXM1\n", MPATH_ID_INT_MAX_m1); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ ++ expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); ++ mock_used_alias("MPATHa", "WWIDMAX"); ++ mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWIDMAX"); + expect_condlog(0, NOMORE_STR); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); ++ rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); + assert_int_equal(rc, -1); + assert_ptr_equal(alias, NULL); + } +@@ -946,52 +1130,68 @@ static void lb_nomatch_int_max_m1_2_used(void **state) + static int test_lookup_binding(void) + { + const struct CMUnitTest tests[] = { +- cmocka_unit_test(lb_empty), +- cmocka_unit_test(lb_empty_unused), +- cmocka_unit_test(lb_empty_failed), +- cmocka_unit_test(lb_empty_1_used), +- cmocka_unit_test(lb_empty_1_used_self), +- cmocka_unit_test(lb_match_a), +- cmocka_unit_test(lb_nomatch_a), +- cmocka_unit_test(lb_nomatch_a_bad_check), +- cmocka_unit_test(lb_nomatch_a_unused), +- cmocka_unit_test(lb_nomatch_a_3_used_failed_self), +- cmocka_unit_test(lb_match_c), +- cmocka_unit_test(lb_match_c_check), +- cmocka_unit_test(lb_nomatch_a_c), +- cmocka_unit_test(lb_nomatch_a_d_unused), +- cmocka_unit_test(lb_nomatch_a_d_1_used), +- cmocka_unit_test(lb_nomatch_a_d_2_used), +- cmocka_unit_test(lb_nomatch_a_d_3_used), +- cmocka_unit_test(lb_nomatch_c_a), +- cmocka_unit_test(lb_nomatch_d_a_unused), +- cmocka_unit_test(lb_nomatch_d_a_1_used), +- cmocka_unit_test(lb_nomatch_a_b), +- cmocka_unit_test(lb_nomatch_a_b_bad), +- cmocka_unit_test(lb_nomatch_a_b_bad_self), +- cmocka_unit_test(lb_nomatch_b_a), +- cmocka_unit_test(lb_nomatch_b_a_3_used), ++ cmocka_unit_test_teardown(lb_empty, teardown_bindings), ++ cmocka_unit_test_teardown(lb_empty_unused, teardown_bindings), ++ cmocka_unit_test_teardown(lb_empty_failed, teardown_bindings), ++ cmocka_unit_test_teardown(lb_empty_1_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_empty_1_used_self, teardown_bindings), ++ cmocka_unit_test_teardown(lb_match_a, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_bad_check, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_unused, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_3_used_failed_self, teardown_bindings), ++ cmocka_unit_test_teardown(lb_match_c, teardown_bindings), ++ cmocka_unit_test_teardown(lb_match_c_check, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_c, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_d_unused, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_d_1_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_d_2_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_d_3_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_c_a, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_d_a_unused, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_d_a_1_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_b, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_b_bad, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_a_b_bad_self, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_z_a, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_aa_a, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_a_aa, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_a_aa_zz, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_z_a_unsorted, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_a, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_b_a_3_used, teardown_bindings), + #ifdef MPATH_ID_INT_MAX +- cmocka_unit_test(lb_nomatch_int_max), +- cmocka_unit_test(lb_nomatch_int_max_check), +- cmocka_unit_test(lb_nomatch_int_max_used), +- cmocka_unit_test(lb_nomatch_int_max_m1), +- cmocka_unit_test(lb_nomatch_int_max_m1_used), +- cmocka_unit_test(lb_nomatch_int_max_m1_1_used), +- cmocka_unit_test(lb_nomatch_int_max_m1_2_used), ++ cmocka_unit_test_teardown(lb_nomatch_int_max, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_int_max_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_int_max_m1, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_int_max_m1_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_int_max_m1_1_used, teardown_bindings), ++ cmocka_unit_test_teardown(lb_nomatch_int_max_m1_2_used, teardown_bindings), + #endif + }; + + return cmocka_run_group_tests(tests, NULL, NULL); + } + ++static int rlookup_binding(FILE *dummy, char *buf, const char *alias) { ++ ++ const struct binding *bdg; ++ ++ bdg = get_binding_for_alias(&global_bindings, alias); ++ if (!bdg) { ++ return -1; ++ } ++ strlcpy(buf, bdg->wwid, WWID_SIZE); ++ return 0; ++} ++ + static void rl_empty(void **state) + { + int rc; + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- mock_bindings_file("", -1); ++ mock_bindings_file(""); + expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); +@@ -1004,7 +1204,7 @@ static void rl_match_a(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- mock_bindings_file("MPATHa WWID0\n", 0); ++ mock_bindings_file("MPATHa WWID0\n"); + expect_condlog(3, FOUND_ALIAS_STR("MPATHa", "WWID0")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, 0); +@@ -1017,7 +1217,7 @@ static void rl_nomatch_a(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- mock_bindings_file("MPATHa WWID0\n", -1); ++ mock_bindings_file("MPATHa WWID0\n"); + expect_condlog(3, NOMATCH_STR("MPATHb")); + rc = rlookup_binding(NULL, buf, "MPATHb"); + assert_int_equal(rc, -1); +@@ -1030,8 +1230,8 @@ static void rl_malformed_a(void **state) + char buf[WWID_SIZE]; + + buf[0] = '\0'; +- mock_bindings_file("MPATHa \n", -1); +- expect_condlog(3, "Ignoring malformed line 1 in bindings file\n"); ++ expect_condlog(1, "invalid line 1 in bindings file, missing WWID\n"); ++ mock_bindings_file("MPATHa \n"); + expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); +@@ -1049,8 +1249,8 @@ static void rl_overlong_a(void **state) + snprintf(line + sizeof(line) - 2, 2, "\n"); + + buf[0] = '\0'; +- mock_bindings_file(line, -1); + expect_condlog(3, "Ignoring too large wwid at 1 in bindings file\n"); ++ mock_bindings_file(line); + expect_condlog(3, NOMATCH_STR("MPATHa")); + rc = rlookup_binding(NULL, buf, "MPATHa"); + assert_int_equal(rc, -1); +@@ -1065,7 +1265,7 @@ static void rl_match_b(void **state) + buf[0] = '\0'; + mock_bindings_file("MPATHa WWID0\n" + "MPATHz WWID26\n" +- "MPATHb WWID2\n", 2); ++ "MPATHb WWID2\n"); + expect_condlog(3, FOUND_ALIAS_STR("MPATHb", "WWID2")); + rc = rlookup_binding(NULL, buf, "MPATHb"); + assert_int_equal(rc, 0); +@@ -1075,31 +1275,41 @@ static void rl_match_b(void **state) + static int test_rlookup_binding(void) + { + const struct CMUnitTest tests[] = { +- cmocka_unit_test(rl_empty), +- cmocka_unit_test(rl_match_a), +- cmocka_unit_test(rl_nomatch_a), +- cmocka_unit_test(rl_malformed_a), +- cmocka_unit_test(rl_overlong_a), +- cmocka_unit_test(rl_match_b), ++ cmocka_unit_test_teardown(rl_empty, teardown_bindings), ++ cmocka_unit_test_teardown(rl_match_a, teardown_bindings), ++ cmocka_unit_test_teardown(rl_nomatch_a, teardown_bindings), ++ cmocka_unit_test_teardown(rl_malformed_a, teardown_bindings), ++ cmocka_unit_test_teardown(rl_overlong_a, teardown_bindings), ++ cmocka_unit_test_teardown(rl_match_b, teardown_bindings), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); + } + ++void check_bindings_size(int n) ++{ ++ /* avoid -Waddress problem */ ++ Bindings *bindings = &global_bindings; ++ ++ assert_int_equal(VECTOR_SIZE(bindings), n); ++} ++ + static void al_a(void **state) + { + static const char ln[] = "MPATHa WWIDa\n"; + char *alias; + +- will_return(__wrap_lseek, 0); +- expect_value(__wrap_write, count, strlen(ln)); +- expect_string(__wrap_write, buf, ln); +- will_return(__wrap_write, strlen(ln)); ++ expect_value(__wrap_write, count, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_write, ln); ++ will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_rename, 0); ++ expect_condlog(1, "updated bindings file foo"); + expect_condlog(3, NEW_STR("MPATHa", "WWIDa")); + +- alias = allocate_binding(0, "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHa"); ++ check_bindings_size(1); + free(alias); + } + +@@ -1108,15 +1318,17 @@ static void al_zz(void **state) + static const char ln[] = "MPATHzz WWIDzz\n"; + char *alias; + +- will_return(__wrap_lseek, 0); +- expect_value(__wrap_write, count, strlen(ln)); +- expect_string(__wrap_write, buf, ln); +- will_return(__wrap_write, strlen(ln)); ++ expect_value(__wrap_write, count, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_write, ln); ++ will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_rename, 0); ++ expect_condlog(1, "updated bindings file foo"); + expect_condlog(3, NEW_STR("MPATHzz", "WWIDzz")); + +- alias = allocate_binding(0, "WWIDzz", 26*26 + 26, "MPATH"); ++ alias = allocate_binding("foo", "WWIDzz", 26*26 + 26, "MPATH"); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHzz"); ++ check_bindings_size(1); + free(alias); + } + +@@ -1127,6 +1339,7 @@ static void al_0(void **state) + expect_condlog(0, "allocate_binding: cannot allocate new binding for id 0\n"); + alias = allocate_binding(0, "WWIDa", 0, "MPATH"); + assert_ptr_equal(alias, NULL); ++ check_bindings_size(0); + } + + static void al_m2(void **state) +@@ -1136,67 +1349,133 @@ static void al_m2(void **state) + expect_condlog(0, "allocate_binding: cannot allocate new binding for id -2\n"); + alias = allocate_binding(0, "WWIDa", -2, "MPATH"); + assert_ptr_equal(alias, NULL); ++ check_bindings_size(0); ++} ++ ++static void al_write_partial(void **state) ++{ ++ static const char ln[] = "MPATHa WWIDa\n"; ++ char *alias; ++ ++ expect_value(__wrap_write, count, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_write, ln); ++ will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln) - 1); ++ expect_value(__wrap_write, count, 1); ++ will_return(__wrap_write, ln + sizeof(ln) - 2); ++ will_return(__wrap_write, 1); ++ will_return(__wrap_rename, 0); ++ expect_condlog(1, "updated bindings file foo"); ++ expect_condlog(3, "Created new binding [MPATHa] for WWID [WWIDa]\n"); ++ ++ alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ assert_ptr_not_equal(alias, NULL); ++ assert_string_equal(alias, "MPATHa"); ++ check_bindings_size(1); ++ free(alias); + } + +-static void al_lseek_err(void **state) ++static void al_write_short(void **state) + { ++ static const char ln[] = "MPATHa WWIDa\n"; + char *alias; + +- will_return(__wrap_lseek, -ENODEV); +- expect_condlog(0, "Cannot seek to end of bindings file : No such device\n"); +- alias = allocate_binding(0, "WWIDa", 1, "MPATH"); ++ expect_value(__wrap_write, count, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_write, ln); ++ will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln) - 1); ++ expect_value(__wrap_write, count, 1); ++ will_return(__wrap_write, ln + sizeof(ln) - 2); ++ will_return(__wrap_write, 0); ++ expect_condlog(2, "write_bindings_file: short write"); ++ expect_condlog(1, "failed to write new bindings file"); ++ expect_condlog(1, "allocate_binding: deleting binding MPATHa for WWIDa"); ++ ++ alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); + assert_ptr_equal(alias, NULL); ++ check_bindings_size(0); + } + + static void al_write_err(void **state) + { + static const char ln[] = "MPATHa WWIDa\n"; +- const int offset = 20; + char *alias; + +- will_return(__wrap_lseek, offset); +- expect_value(__wrap_write, count, strlen(ln)); +- expect_string(__wrap_write, buf, ln); +- will_return(__wrap_write, strlen(ln) - 1); +- expect_value(__wrap_ftruncate, length, offset); +- will_return(__wrap_ftruncate, 0); +- expect_condlog(0, "Cannot write binding to bindings file :"); ++ expect_value(__wrap_write, count, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_write, ln); ++ will_return(__wrap_write, -EPERM); ++ expect_condlog(1, "failed to write new bindings file"); ++ expect_condlog(1, "allocate_binding: deleting binding MPATHa for WWIDa"); + +- alias = allocate_binding(0, "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); + assert_ptr_equal(alias, NULL); ++ check_bindings_size(0); ++} ++ ++static void al_rename_err(void **state) ++{ ++ static const char ln[] = "MPATHa WWIDa\n"; ++ char *alias; ++ ++ expect_value(__wrap_write, count, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_write, ln); ++ will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); ++ will_return(__wrap_rename, -EROFS); ++ ++ expect_condlog(0, "update_bindings_file: rename: Read-only file system"); ++ expect_condlog(1, "allocate_binding: deleting binding MPATHa for WWIDa"); ++ alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ assert_ptr_equal(alias, NULL); ++ check_bindings_size(0); + } + + static int test_allocate_binding(void) + { + const struct CMUnitTest tests[] = { +- cmocka_unit_test(al_a), +- cmocka_unit_test(al_zz), +- cmocka_unit_test(al_0), +- cmocka_unit_test(al_m2), +- cmocka_unit_test(al_lseek_err), +- cmocka_unit_test(al_write_err), ++ cmocka_unit_test_teardown(al_a, teardown_bindings), ++ cmocka_unit_test_teardown(al_zz, teardown_bindings), ++ cmocka_unit_test_teardown(al_0, teardown_bindings), ++ cmocka_unit_test_teardown(al_m2, teardown_bindings), ++ cmocka_unit_test_teardown(al_write_partial, teardown_bindings), ++ cmocka_unit_test_teardown(al_write_short, teardown_bindings), ++ cmocka_unit_test_teardown(al_write_err, teardown_bindings), ++ cmocka_unit_test_teardown(al_rename_err, teardown_bindings), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); + } + +-#define mock_allocate_binding(alias, wwid) \ ++#define mock_allocate_binding_err_len(alias, wwid, len, err, msg) \ + do { \ + static const char ln[] = BINDING_STR(alias, wwid); \ + \ +- will_return(__wrap_lseek, 0); \ +- expect_value(__wrap_write, count, strlen(ln)); \ +- expect_string(__wrap_write, buf, ln); \ +- will_return(__wrap_write, strlen(ln)); \ +- expect_condlog(3, NEW_STR(alias, wwid)); \ ++ expect_value(__wrap_write, count, \ ++ strlen(BINDINGS_FILE_HEADER) + (len) + strlen(ln)); \ ++ will_return(__wrap_write, ln); \ ++ will_return(__wrap_write, \ ++ strlen(BINDINGS_FILE_HEADER) + (len) + strlen(ln)); \ ++ will_return(__wrap_rename, err); \ ++ if (err == 0) { \ ++ expect_condlog(1, "updated bindings file x\n"); \ ++ expect_condlog(3, NEW_STR(alias, wwid)); \ ++ } else { \ ++ expect_condlog(0, "update_bindings_file: rename: " msg "\n"); \ ++ expect_condlog(1, "allocate_binding: deleting binding " \ ++ alias " for " wwid "\n"); \ ++ } \ + } while (0) + ++#define mock_allocate_binding_err(alias, wwid, err, msg) \ ++ mock_allocate_binding_err_len(alias, wwid, 0, err, msg) ++ ++#define mock_allocate_binding(alias, wwid) \ ++ mock_allocate_binding_err(alias, wwid, 0, "") ++ ++#define mock_allocate_binding_len(alias, wwid, len) \ ++ mock_allocate_binding_err_len(alias, wwid, len, 0, "") ++ + static void gufa_empty_new_rw(void **state) { + char *alias; + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file("", -1); ++ mock_bindings_file(""); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + +@@ -1208,10 +1487,11 @@ static void gufa_empty_new_rw(void **state) { + + static void gufa_empty_new_ro_1(void **state) { + char *alias; +- will_return(__wrap_open_file, false); +- mock_bindings_file("", -1); ++ ++ mock_bindings_file(""); + mock_unused_alias("MPATHa"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ mock_allocate_binding_err("MPATHa", "WWID0", -EROFS, "Read-only file system"); + + alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); + assert_ptr_equal(alias, NULL); +@@ -1220,11 +1500,9 @@ static void gufa_empty_new_ro_1(void **state) { + static void gufa_empty_new_ro_2(void **state) { + char *alias; + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file("", -1); +- mock_unused_alias("MPATHa"); ++ mock_bindings_file(""); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ mock_unused_alias("MPATHa"); + + alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); + assert_ptr_equal(alias, NULL); +@@ -1233,11 +1511,10 @@ static void gufa_empty_new_ro_2(void **state) { + static void gufa_match_a_unused(void **state) { + char *alias; + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file("MPATHa WWID0", 0); ++ mock_bindings_file("MPATHa WWID0"); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_unused_alias("MPATHa"); ++ expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); + + alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); + assert_string_equal(alias, "MPATHa"); +@@ -1247,11 +1524,10 @@ static void gufa_match_a_unused(void **state) { + static void gufa_match_a_self(void **state) { + char *alias; + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file("MPATHa WWID0", 0); ++ mock_bindings_file("MPATHa WWID0"); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_self_alias("MPATHa", "WWID0"); ++ expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); + + alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); + assert_string_equal(alias, "MPATHa"); +@@ -1261,9 +1537,8 @@ static void gufa_match_a_self(void **state) { + static void gufa_match_a_used(void **state) { + char *alias; + +- will_return(__wrap_open_file, true); + +- mock_bindings_file("MPATHa WWID0", 0); ++ mock_bindings_file("MPATHa WWID0"); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_used_alias("MPATHa", "WWID0"); + +@@ -1273,15 +1548,14 @@ static void gufa_match_a_used(void **state) { + + static void gufa_nomatch_a_c(void **state) { + char *alias; +- will_return(__wrap_open_file, true); ++ static const char bindings[] = ("MPATHa WWID0\n" ++ "MPATHc WWID2\n"); + +- mock_bindings_file("MPATHa WWID0\n" +- "MPATHc WWID2", +- -1); ++ mock_bindings_file(bindings); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + +- mock_allocate_binding("MPATHb", "WWID1"); ++ mock_allocate_binding_len("MPATHb", "WWID1", strlen(bindings)); + + alias = get_user_friendly_alias("WWID1", "x", "", "MPATH", false); + assert_string_equal(alias, "MPATHb"); +@@ -1290,15 +1564,14 @@ static void gufa_nomatch_a_c(void **state) { + + static void gufa_nomatch_c_a(void **state) { + char *alias; +- will_return(__wrap_open_file, true); ++ const char bindings[] = ("MPATHc WWID2\n" ++ "MPATHa WWID0\n"); + +- mock_bindings_file("MPATHc WWID2\n" +- "MPATHa WWID0", +- -1); ++ mock_bindings_file(bindings); + mock_unused_alias("MPATHb"); + expect_condlog(3, NOMATCH_WWID_STR("WWID1")); + +- mock_allocate_binding("MPATHb", "WWID1"); ++ mock_allocate_binding_len("MPATHb", "WWID1", sizeof(bindings) - 1); + + alias = get_user_friendly_alias("WWID1", "x", "", "MPATH", false); + assert_string_equal(alias, "MPATHb"); +@@ -1307,15 +1580,14 @@ static void gufa_nomatch_c_a(void **state) { + + static void gufa_nomatch_c_b(void **state) { + char *alias; +- will_return(__wrap_open_file, true); ++ const char bindings[] = ("MPATHc WWID2\n" ++ "MPATHb WWID1\n"); + +- mock_bindings_file("MPATHc WWID2\n" +- "MPATHb WWID1\n", +- -1); +- mock_unused_alias("MPATHa"); ++ mock_bindings_file(bindings); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ mock_unused_alias("MPATHa"); + +- mock_allocate_binding("MPATHa", "WWID0"); ++ mock_allocate_binding_len("MPATHa", "WWID0", sizeof(bindings) - 1); + + alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); + assert_string_equal(alias, "MPATHa"); +@@ -1324,16 +1596,15 @@ static void gufa_nomatch_c_b(void **state) { + + static void gufa_nomatch_c_b_used(void **state) { + char *alias; +- will_return(__wrap_open_file, true); ++ const char bindings[] = ("MPATHc WWID2\n" ++ "MPATHb WWID1\n"); + +- mock_bindings_file("MPATHc WWID2\n" +- "MPATHb WWID1", +- -1); +- mock_used_alias("MPATHa", "WWID4"); ++ mock_bindings_file(bindings); + expect_condlog(3, NOMATCH_WWID_STR("WWID4")); ++ mock_used_alias("MPATHa", "WWID4"); + mock_unused_alias("MPATHd"); + +- mock_allocate_binding("MPATHd", "WWID4"); ++ mock_allocate_binding_len("MPATHd", "WWID4", sizeof(bindings) - 1); + + alias = get_user_friendly_alias("WWID4", "x", "", "MPATH", false); + assert_string_equal(alias, "MPATHd"); +@@ -1342,32 +1613,59 @@ static void gufa_nomatch_c_b_used(void **state) { + + static void gufa_nomatch_b_f_a(void **state) { + char *alias; +- will_return(__wrap_open_file, true); ++ const char bindings[] = ("MPATHb WWID1\n" ++ "MPATHf WWID6\n" ++ "MPATHa WWID0\n"); + +- mock_bindings_file("MPATHb WWID1\n" +- "MPATHf WWID6\n" +- "MPATHa WWID0\n", +- -1); ++ mock_bindings_file_unsorted(bindings); + expect_condlog(3, NOMATCH_WWID_STR("WWID7")); + mock_unused_alias("MPATHg"); + +- mock_allocate_binding("MPATHg", "WWID7"); ++ mock_allocate_binding_len("MPATHg", "WWID7", sizeof(bindings) - 1); + + alias = get_user_friendly_alias("WWID7", "x", "", "MPATH", false); + assert_string_equal(alias, "MPATHg"); + free(alias); + } + ++static void gufa_nomatch_b_aa_a(void **state) { ++ char *alias; ++ STRBUF_ON_STACK(buf); ++ ++ fill_bindings(&buf, 0, 26); ++ mock_bindings_file(get_strbuf_str(&buf)); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID28")); ++ mock_unused_alias("MPATHab"); ++ mock_allocate_binding_len("MPATHab", "WWID28", get_strbuf_len(&buf)); ++ ++ alias = get_user_friendly_alias("WWID28", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHab"); ++ free(alias); ++} ++ ++static void gufa_nomatch_b_f_a_sorted(void **state) { ++ char *alias; ++ const char bindings[] = ("MPATHb WWID1\n" ++ "MPATHf WWID6\n" ++ "MPATHa WWID0\n"); ++ ++ mock_bindings_file(bindings); ++ expect_condlog(3, NOMATCH_WWID_STR("WWID7")); ++ mock_unused_alias("MPATHc"); ++ ++ mock_allocate_binding_len("MPATHc", "WWID7", sizeof(bindings) - 1); ++ ++ alias = get_user_friendly_alias("WWID7", "x", "", "MPATH", false); ++ assert_string_equal(alias, "MPATHc"); ++ free(alias); ++} ++ + static void gufa_old_empty(void **state) { + char *alias; +- will_return(__wrap_open_file, true); + + /* rlookup_binding for ALIAS */ +- mock_bindings_file("", -1); ++ mock_bindings_file(""); + expect_condlog(3, NOMATCH_STR("MPATHz")); +- +- /* lookup_binding */ +- mock_bindings_file("", -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + + mock_allocate_binding("MPATHz", "WWID0"); +@@ -1380,11 +1678,9 @@ static void gufa_old_empty(void **state) { + + static void gufa_old_match(void **state) { + char *alias; +- will_return(__wrap_open_file, true); + + mock_bindings_file("MPATHb WWID1\n" +- "MPATHz WWID0", +- 1); ++ "MPATHz WWID0"); + expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID0")); + + alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); +@@ -1394,19 +1690,15 @@ static void gufa_old_match(void **state) { + + static void gufa_old_match_other(void **state) { + char *alias; +- static const char bindings[] = "MPATHz WWID9"; +- +- will_return(__wrap_open_file, true); ++ static const char bindings[] = "MPATHz WWID9\n"; + +- mock_bindings_file(bindings, 0); ++ mock_bindings_file(bindings); + expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); + expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); +- +- mock_bindings_file(bindings, -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_unused_alias("MPATHa"); + +- mock_allocate_binding("MPATHa", "WWID0"); ++ mock_allocate_binding_len("MPATHa", "WWID0", sizeof(bindings) - 1); + + alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHa"); +@@ -1415,21 +1707,16 @@ static void gufa_old_match_other(void **state) { + + static void gufa_old_match_other_used(void **state) { + char *alias; +- static const char bindings[] = "MPATHz WWID9"; ++ static const char bindings[] = "MPATHz WWID9\n"; + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file(bindings, 0); ++ mock_bindings_file(bindings); + expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); + expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); +- +- mock_bindings_file(bindings, -1); +- mock_used_alias("MPATHa", "WWID0"); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); ++ mock_used_alias("MPATHa", "WWID0"); + mock_unused_alias("MPATHb"); + +- mock_allocate_binding("MPATHb", "WWID0"); +- ++ mock_allocate_binding_len("MPATHb", "WWID0", sizeof(bindings) - 1); + alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHb"); + free(alias); +@@ -1439,15 +1726,13 @@ static void gufa_old_match_other_wwidmatch(void **state) { + char *alias; + static const char bindings[] = ("MPATHz WWID9\n" + "MPATHc WWID2"); +- will_return(__wrap_open_file, true); + +- mock_bindings_file(bindings, 0); ++ mock_bindings_file(bindings); + expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); + expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); +- +- mock_bindings_file(bindings, 1); + expect_condlog(3, FOUND_STR("MPATHc", "WWID2")); + mock_unused_alias("MPATHc"); ++ expect_condlog(3, EXISTING_STR("MPATHc", "WWID2")); + + alias = get_user_friendly_alias("WWID2", "x", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHc"); +@@ -1459,13 +1744,9 @@ static void gufa_old_match_other_wwidmatch_used(void **state) { + static const char bindings[] = ("MPATHz WWID9\n" + "MPATHc WWID2"); + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file(bindings, 0); ++ mock_bindings_file(bindings); + expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID9")); + expect_condlog(0, REUSE_STR("MPATHz", "WWID9")); +- +- mock_bindings_file(bindings, 1); + expect_condlog(3, FOUND_STR("MPATHc", "WWID2")); + mock_used_alias("MPATHc", "WWID2"); + +@@ -1477,12 +1758,8 @@ static void gufa_old_nomatch_wwidmatch(void **state) { + char *alias; + static const char bindings[] = "MPATHa WWID0"; + +- will_return(__wrap_open_file, true); +- +- mock_bindings_file(bindings, -1); ++ mock_bindings_file(bindings); + expect_condlog(3, NOMATCH_STR("MPATHz")); +- +- mock_bindings_file(bindings, 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_unused_alias("MPATHa"); + expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); +@@ -1495,12 +1772,9 @@ static void gufa_old_nomatch_wwidmatch(void **state) { + static void gufa_old_nomatch_wwidmatch_used(void **state) { + char *alias; + static const char bindings[] = "MPATHa WWID0"; +- will_return(__wrap_open_file, true); + +- mock_bindings_file(bindings, -1); ++ mock_bindings_file(bindings); + expect_condlog(3, NOMATCH_STR("MPATHz")); +- +- mock_bindings_file(bindings, 0); + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_used_alias("MPATHa", "WWID0"); + +@@ -1510,17 +1784,13 @@ static void gufa_old_nomatch_wwidmatch_used(void **state) { + + static void gufa_old_nomatch_nowwidmatch(void **state) { + char *alias; +- static const char bindings[] = "MPATHb WWID1"; +- +- will_return(__wrap_open_file, true); ++ static const char bindings[] = "MPATHb WWID1\n"; + +- mock_bindings_file(bindings, -1); ++ mock_bindings_file(bindings); + expect_condlog(3, NOMATCH_STR("MPATHz")); +- +- mock_bindings_file(bindings, -1); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + +- mock_allocate_binding("MPATHz", "WWID0"); ++ mock_allocate_binding_len("MPATHz", "WWID0", sizeof(bindings) - 1); + expect_condlog(2, ALLOC_STR("MPATHz", "WWID0")); + + alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); +@@ -1531,26 +1801,28 @@ static void gufa_old_nomatch_nowwidmatch(void **state) { + static int test_get_user_friendly_alias() + { + const struct CMUnitTest tests[] = { +- cmocka_unit_test(gufa_empty_new_rw), +- cmocka_unit_test(gufa_empty_new_ro_1), +- cmocka_unit_test(gufa_empty_new_ro_2), +- cmocka_unit_test(gufa_match_a_unused), +- cmocka_unit_test(gufa_match_a_self), +- cmocka_unit_test(gufa_match_a_used), +- cmocka_unit_test(gufa_nomatch_a_c), +- cmocka_unit_test(gufa_nomatch_c_a), +- cmocka_unit_test(gufa_nomatch_c_b), +- cmocka_unit_test(gufa_nomatch_c_b_used), +- cmocka_unit_test(gufa_nomatch_b_f_a), +- cmocka_unit_test(gufa_old_empty), +- cmocka_unit_test(gufa_old_match), +- cmocka_unit_test(gufa_old_match_other), +- cmocka_unit_test(gufa_old_match_other_used), +- cmocka_unit_test(gufa_old_match_other_wwidmatch), +- cmocka_unit_test(gufa_old_match_other_wwidmatch_used), +- cmocka_unit_test(gufa_old_nomatch_wwidmatch), +- cmocka_unit_test(gufa_old_nomatch_wwidmatch_used), +- cmocka_unit_test(gufa_old_nomatch_nowwidmatch), ++ cmocka_unit_test_teardown(gufa_empty_new_rw, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_empty_new_ro_1, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_empty_new_ro_2, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_match_a_unused, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_match_a_self, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_match_a_used, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_a_c, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_c_a, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_c_b, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_c_b_used, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_b_f_a, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_b_aa_a, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_nomatch_b_f_a_sorted, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_empty, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_match, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_match_other, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_match_other_used, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_match_other_wwidmatch, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_match_other_wwidmatch_used, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_nomatch_wwidmatch, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_nomatch_wwidmatch_used, teardown_bindings), ++ cmocka_unit_test_teardown(gufa_old_nomatch_nowwidmatch, teardown_bindings), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +@@ -1566,7 +1838,6 @@ int main(void) + ret += test_lookup_binding(); + ret += test_rlookup_binding(); + ret += test_allocate_binding(); +- ret += test_allocate_binding(); + ret += test_get_user_friendly_alias(); + + return ret; diff --git a/0020-libmultipath-dm_get_uuid-return-emtpy-UUID-for-non-e.patch b/0020-libmultipath-dm_get_uuid-return-emtpy-UUID-for-non-e.patch new file mode 100644 index 0000000..c105b01 --- /dev/null +++ b/0020-libmultipath-dm_get_uuid-return-emtpy-UUID-for-non-e.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 25 Aug 2023 20:35:19 +0200 +Subject: [PATCH] libmultipath: dm_get_uuid(): return emtpy UUID for + non-existing maps + +libdevmapper will most probably not return a UUID for non-existing +maps anyway. But it's cheap to double-check here. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/devmapper.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 248c3734..9be82f4e 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -706,12 +706,16 @@ dm_get_prefixed_uuid(const char *name, char *uuid, int uuid_len) + { + struct dm_task *dmt; + const char *uuidtmp; ++ struct dm_info info; + int r = 1; + + dmt = libmp_dm_task_create(DM_DEVICE_INFO); + if (!dmt) + return 1; + ++ if (uuid_len > 0) ++ uuid[0] = '\0'; ++ + if (!dm_task_set_name (dmt, name)) + goto uuidout; + +@@ -720,11 +724,13 @@ dm_get_prefixed_uuid(const char *name, char *uuid, int uuid_len) + goto uuidout; + } + ++ if (!dm_task_get_info(dmt, &info) || ++ !info.exists) ++ goto uuidout; ++ + uuidtmp = dm_task_get_uuid(dmt); + if (uuidtmp) + strlcpy(uuid, uuidtmp, uuid_len); +- else +- uuid[0] = '\0'; + + r = 0; + uuidout: diff --git a/0021-libmultipath-adapt-to-new-semantics-of-dm_get_uuid.patch b/0021-libmultipath-adapt-to-new-semantics-of-dm_get_uuid.patch new file mode 100644 index 0000000..4d15554 --- /dev/null +++ b/0021-libmultipath-adapt-to-new-semantics-of-dm_get_uuid.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 28 Aug 2023 12:26:37 +0200 +Subject: [PATCH] libmultipath: adapt to new semantics of dm_get_uuid() + +dm_get_uuid() will return 1 for non-existing maps. Thus we don't need +to call dm_map_present() any more in alias_already_taken(). This changes +our semantics: previously we'd avoid using an alias for which dm_get_uuid() +had failed. Now we treat failure in dm_get_uuid() as indication that the +map doesn't exist. This is not dangerous because dm_task_get_uuid() cannot +fail, and thus the modified dm_get_uuid() will fail if and only if +dm_map_present() would return false. + +This makes the "failed alias" test mostly obsolete, as "failed" is now +treated as "unused". + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 25 +++++++++++++------------ + tests/alias.c | 32 +++++++------------------------- + 2 files changed, 20 insertions(+), 37 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index d6563749..58436ec0 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -295,18 +295,19 @@ scan_devname(const char *alias, const char *prefix) + static bool alias_already_taken(const char *alias, const char *map_wwid) + { + +- 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 false; +- condlog(3, "%s: alias '%s' already taken, reselecting alias", +- map_wwid, alias); +- return true; +- } +- return false; ++ char wwid[WWID_SIZE]; ++ ++ /* If the map doesn't exist, it's fine */ ++ if (dm_get_uuid(alias, wwid, sizeof(wwid)) != 0) ++ return false; ++ ++ /* If both the name and the wwid match, it's fine.*/ ++ if (strncmp(map_wwid, wwid, sizeof(wwid)) == 0) ++ return false; ++ ++ condlog(3, "%s: alias '%s' already taken, reselecting alias", ++ map_wwid, alias); ++ return true; + } + + static bool id_already_taken(int id, const char *prefix, const char *map_wwid) +diff --git a/tests/alias.c b/tests/alias.c +index 50a21ecf..d1cc487b 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -73,12 +73,6 @@ int __wrap_mkstemp(char *template) + return 10; + } + +-int __wrap_dm_map_present(const char * str) +-{ +- check_expected(str); +- return mock_type(int); +-} +- + int __wrap_dm_get_uuid(const char *name, char *uuid, int uuid_len) + { + int ret; +@@ -398,14 +392,13 @@ static int test_scan_devname(void) + + static void mock_unused_alias(const char *alias) + { +- expect_string(__wrap_dm_map_present, str, alias); +- will_return(__wrap_dm_map_present, 0); ++ expect_string(__wrap_dm_get_uuid, name, alias); ++ expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); ++ will_return(__wrap_dm_get_uuid, 1); + } + + static void mock_self_alias(const char *alias, const char *wwid) + { +- expect_string(__wrap_dm_map_present, str, alias); +- will_return(__wrap_dm_map_present, 1); + expect_string(__wrap_dm_get_uuid, name, alias); + expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); + will_return(__wrap_dm_get_uuid, 0); +@@ -432,18 +425,13 @@ static void mock_self_alias(const char *alias, const char *wwid) + + #define mock_failed_alias(alias, wwid) \ + do { \ +- expect_string(__wrap_dm_map_present, str, alias); \ +- will_return(__wrap_dm_map_present, 1); \ + expect_string(__wrap_dm_get_uuid, name, alias); \ + expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); \ + will_return(__wrap_dm_get_uuid, 1); \ +- expect_condlog(3, USED_STR(alias, wwid)); \ + } while (0) + + #define mock_used_alias(alias, wwid) \ + do { \ +- expect_string(__wrap_dm_map_present, str, alias); \ +- will_return(__wrap_dm_map_present, 1); \ + expect_string(__wrap_dm_get_uuid, name, alias); \ + expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE); \ + will_return(__wrap_dm_get_uuid, 0); \ +@@ -566,9 +554,8 @@ static void lb_empty_failed(void **state) + mock_bindings_file(""); + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_failed_alias("MPATHa", "WWID0"); +- mock_unused_alias("MPATHb"); + rc = lookup_binding(NULL, "WWID0", &alias, "MPATH", 1); +- assert_int_equal(rc, 2); ++ assert_int_equal(rc, 1); + assert_ptr_equal(alias, NULL); + free(alias); + } +@@ -666,9 +653,8 @@ static void lb_nomatch_a_3_used_failed_self(void **state) + mock_used_alias("MPATHc", "WWID1"); + mock_used_alias("MPATHd", "WWID1"); + mock_failed_alias("MPATHe", "WWID1"); +- mock_self_alias("MPATHf", "WWID1"); + rc = lookup_binding(NULL, "WWID1", &alias, "MPATH", 1); +- assert_int_equal(rc, 6); ++ assert_int_equal(rc, 5); + assert_ptr_equal(alias, NULL); + } + +@@ -940,7 +926,7 @@ static void lb_nomatch_b_a_aa(void **state) + + static void lb_nomatch_b_a_aa_zz(void **state) + { +- int rc, i; ++ int rc; + char *alias; + STRBUF_ON_STACK(buf); + +@@ -949,11 +935,7 @@ static void lb_nomatch_b_a_aa_zz(void **state) + * lookup_binding finds MPATHaaa as next free entry, because MPATHaa is + * found before MPATHb, and MPATHzz was in the bindings, too. + */ +- for (i = 0; i <= 26; i++) { +- print_strbuf(&buf, "MPATH"); +- format_devname(&buf, i + 1); +- print_strbuf(&buf, " WWID%d\n", i); +- } ++ fill_bindings(&buf, 0, 26); + print_strbuf(&buf, "MPATHzz WWID676\n"); + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWID703")); diff --git a/0022-libmultipath-sort-aliases-by-length-and-strcmp.patch b/0022-libmultipath-sort-aliases-by-length-and-strcmp.patch new file mode 100644 index 0000000..1504bec --- /dev/null +++ b/0022-libmultipath-sort-aliases-by-length-and-strcmp.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 15:19:54 +0200 +Subject: [PATCH] libmultipath: sort aliases by length and strcmp + +The current sort order of aliases is alphabetical, which is does not match +the actual order of aliases, where "mpathaa" > "mpathz". Change the ordering as +follows: first sort by string length, then alphabetically. This will make +sure that for aliases with the same prefix, alias order is correct ("mpathaaa" +will be sorted after "mpathzz", etc). Even for mixed prefixes, the alias +order will be correct for every individual prefix, even though aliases with +different prefixes may alternate in the file. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 45 +++++++++++++++++++++++++++++++++----------- + 1 file changed, 34 insertions(+), 11 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 58436ec0..af6565b1 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -117,6 +117,35 @@ static const struct binding *get_binding_for_wwid(const Bindings *bindings, + return NULL; + } + ++/* ++ * Sort order for aliases. ++ * ++ * The "numeric" ordering of aliases for a given prefix P is ++ * Pa, ..., Pz, Paa, ..., Paz, Pba, ... , Pzz, Paaa, ..., Pzzz, Paaaa, ... ++ * We use the fact that for equal prefix, longer strings are always ++ * higher than shorter ones. Strings of equal length are sorted alphabetically. ++ * This is achieved by sorting be length first, then using strcmp(). ++ * If multiple prefixes are in use, the aliases with a given prefix will ++ * not necessarily be in a contiguous range of the vector, but they will ++ * be ordered such that for a given prefix, numercally higher aliases will ++ * always be sorted after lower ones. ++ */ ++static int alias_compar(const void *p1, const void *p2) ++{ ++ const char *alias1 = *((char * const *)p1); ++ const char *alias2 = *((char * const *)p2); ++ ++ if (alias1 && alias2) { ++ ssize_t ldif = strlen(alias1) - strlen(alias2); ++ ++ if (ldif) ++ return ldif; ++ return strcmp(alias1, alias2); ++ } else ++ /* Move NULL alias to the end */ ++ return alias1 ? -1 : alias2 ? 1 : 0; ++} ++ + static int add_binding(Bindings *bindings, const char *alias, const char *wwid) + { + struct binding *bdg; +@@ -128,7 +157,7 @@ static int add_binding(Bindings *bindings, const char *alias, const char *wwid) + * sorted already. + */ + vector_foreach_slot_backwards(bindings, bdg, i) { +- if ((cmp = strcmp(bdg->alias, alias)) <= 0) ++ if ((cmp = alias_compar(&bdg->alias, &alias)) <= 0) + break; + } + +@@ -657,16 +686,10 @@ static int _check_bindings_file(const struct config *conf, FILE *file, + return rc; + } + +-static int alias_compar(const void *p1, const void *p2) ++static int mp_alias_compar(const void *p1, const void *p2) + { +- const char *alias1 = (*(struct mpentry * const *)p1)->alias; +- const char *alias2 = (*(struct mpentry * const *)p2)->alias; +- +- if (alias1 && alias2) +- return strcmp(alias1, alias2); +- else +- /* Move NULL alias to the end */ +- return alias1 ? -1 : alias2 ? 1 : 0; ++ return alias_compar(&((*(struct mpentry * const *)p1)->alias), ++ &((*(struct mpentry * const *)p2)->alias)); + } + + /* +@@ -700,7 +723,7 @@ int check_alias_settings(const struct config *conf) + pthread_cleanup_push_cast(free_bindings, &bindings); + pthread_cleanup_push(cleanup_vector_free, mptable); + +- vector_sort(mptable, alias_compar); ++ vector_sort(mptable, mp_alias_compar); + vector_foreach_slot(mptable, mpe, i) { + if (!mpe->alias) + /* diff --git a/0023-multipath-tools-tests-fix-alias-test-after-sort-orde.patch b/0023-multipath-tools-tests-fix-alias-test-after-sort-orde.patch new file mode 100644 index 0000000..dd0f29d --- /dev/null +++ b/0023-multipath-tools-tests-fix-alias-test-after-sort-orde.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 15:46:02 +0200 +Subject: [PATCH] multipath-tools tests: fix alias test after sort order change + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 30 ++++++++++++------------------ + 1 file changed, 12 insertions(+), 18 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index d1cc487b..8ed95d7a 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -932,16 +932,15 @@ static void lb_nomatch_b_a_aa_zz(void **state) + + /* + * add_bindings() sorts alphabetically. ("a", "aa", "ab", "b", "c", ...) +- * lookup_binding finds MPATHaaa as next free entry, because MPATHaa is +- * found before MPATHb, and MPATHzz was in the bindings, too. ++ * lookup_binding finds MPATHab as next free entry. + */ + fill_bindings(&buf, 0, 26); + print_strbuf(&buf, "MPATHzz WWID676\n"); + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWID703")); +- mock_unused_alias("MPATHaaa"); ++ mock_unused_alias("MPATHab"); + rc = lookup_binding(NULL, "WWID703", &alias, "MPATH", 1); +- assert_int_equal(rc, 703); ++ assert_int_equal(rc, 28); + assert_ptr_equal(alias, NULL); + } + +@@ -998,13 +997,8 @@ static void lb_nomatch_b_a_3_used(void **state) + + #ifdef MPATH_ID_INT_MAX + /* +- * The bindings will be sorted by alias, alphabetically, which is not +- * the same as the "numeric" sort order for user-friendly aliases. +- * get_free_id() selects the highest used ID + 1 if an unsorted entry +- * is encountered in the bindings table and it's id is equal to the +- * next "expected" id. This happens if all IDs from "a" to "aa" are +- * in the table. If the INT_MAX entry is in the table, too, it will +- * overflow. ++ * The bindings will be sorted by alias. Therefore we have no chance to ++ * simulate a "full" table. + */ + static void lb_nomatch_int_max(void **state) + { +@@ -1016,9 +1010,9 @@ static void lb_nomatch_int_max(void **state) + print_strbuf(&buf, "MPATH%s WWIDMAX\n", MPATH_ID_INT_MAX); + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWIDNOMORE")); +- expect_condlog(0, NOMORE_STR); ++ mock_unused_alias("MPATHab"); + rc = lookup_binding(NULL, "WWIDNOMORE", &alias, "MPATH", 1); +- assert_int_equal(rc, -1); ++ assert_int_equal(rc, 28); + assert_ptr_equal(alias, NULL); + } + +@@ -1049,9 +1043,9 @@ static void lb_nomatch_int_max_m1(void **state) + print_strbuf(&buf, "MPATH%s WWIDMAXM1\n", MPATH_ID_INT_MAX_m1); + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); +- mock_unused_alias("MPATH" MPATH_ID_INT_MAX); ++ mock_unused_alias("MPATHab"); + rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); +- assert_int_equal(rc, INT_MAX); ++ assert_int_equal(rc, 28); + assert_ptr_equal(alias, NULL); + } + +@@ -1065,10 +1059,10 @@ static void lb_nomatch_int_max_m1_used(void **state) + print_strbuf(&buf, "MPATH%s WWIDMAXM1\n", MPATH_ID_INT_MAX_m1); + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); +- mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWIDMAX"); +- expect_condlog(0, NOMORE_STR); ++ mock_used_alias("MPATHab", "WWIDMAX"); ++ mock_unused_alias("MPATHac"); + rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); +- assert_int_equal(rc, -1); ++ assert_int_equal(rc, 29); + assert_ptr_equal(alias, NULL); + } + diff --git a/0024-libmultipath-simplify-get_free_id-assuming-total-ord.patch b/0024-libmultipath-simplify-get_free_id-assuming-total-ord.patch new file mode 100644 index 0000000..b16b3da --- /dev/null +++ b/0024-libmultipath-simplify-get_free_id-assuming-total-ord.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 19:50:51 +0200 +Subject: [PATCH] libmultipath: simplify get_free_id() assuming total ordering + +If we can assume that the bindings array is totally ordered for every +prefix, which the previous patch guarantees, the search for a free ID can be +simplified. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 85 ++++++++++---------------------------------- + 1 file changed, 18 insertions(+), 67 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index af6565b1..66e34e31 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -356,83 +356,34 @@ int get_free_id(const Bindings *bindings, const char *prefix, const char *map_ww + { + const struct binding *bdg; + int i, id = 1; +- int biggest_id = 1; +- int smallest_bigger_id = INT_MAX; + + vector_foreach_slot(bindings, bdg, i) { + int curr_id = scan_devname(bdg->alias, prefix); + +- /* +- * Find an unused index - explanation of the algorithm +- * +- * ID: 1 = mpatha, 2 = mpathb, ... +- * +- * We assume the bindings are unsorted. The only constraint +- * is that no ID occurs more than once. IDs that occur in the +- * bindings are called "used". +- * +- * We call the list 1,2,3,..., exactly in this order, the list +- * of "expected" IDs. The variable "id" always holds the next +- * "expected" ID, IOW the last "expected" ID encountered plus 1. +- * Thus all IDs below "id" are known to be used. However, at the +- * end of the loop, the value of "id" isn't necessarily unused. +- * +- * "smallest_bigger_id" is the smallest used ID that was +- * encountered while it was larger than the next "expected" ID +- * at that iteration. Let X be some used ID. If all IDs below X +- * are used and encountered in the right sequence before X, "id" +- * will be > X when the loop ends. Otherwise, X was encountered +- * "out of order", the condition (X > id) holds when X is +- * encountered, and "smallest_bigger_id" will be set to X; i.e. +- * it will be less or equal than X when the loop ends. +- * +- * At the end of the loop, (id < smallest_bigger_id) means that +- * the value of "id" had been encountered neither in order nor +- * out of order, and is thus unused. (id >= smallest_bigger_id) +- * means that "id"'s value is in use. In this case, we play safe +- * and use "biggest_id + 1" as the next value to try. +- * +- * biggest_id is always > smallest_bigger_id, except in the +- * "perfectly ordered" case. +- */ +- if (curr_id == id) { +- if (id < INT_MAX) +- id++; +- else { +- id = -1; +- break; +- } ++ if (curr_id == -1) ++ continue; ++ if (id > curr_id) { ++ condlog(0, "%s: ERROR: bindings are not sorted", __func__); ++ return -1; + } +- if (curr_id > biggest_id) +- biggest_id = curr_id; +- +- if (curr_id > id && curr_id < smallest_bigger_id) +- smallest_bigger_id = curr_id; ++ while (id < curr_id && id_already_taken(id, prefix, map_wwid)) ++ id++; ++ if (id < curr_id) ++ return id; ++ id++; ++ if (id <= 0) ++ break; + } + +- if (id >= smallest_bigger_id) +- id = biggest_id < INT_MAX ? biggest_id + 1 : -1; +- +- if (id > 0) { +- 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; +- } +- } ++ for (; id > 0; id++) { ++ if (!id_already_taken(id, prefix, map_wwid)) ++ break; + } + +- if (id < 0) ++ if (id <= 0) { ++ id = -1; + condlog(0, "no more available user_friendly_names"); ++ } + return id; + } + diff --git a/0025-multipath-tools-tests-adapt-alias-tests-for-total-or.patch b/0025-multipath-tools-tests-adapt-alias-tests-for-total-or.patch new file mode 100644 index 0000000..b1d6b15 --- /dev/null +++ b/0025-multipath-tools-tests-adapt-alias-tests-for-total-or.patch @@ -0,0 +1,203 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 19:58:03 +0200 +Subject: [PATCH] multipath-tools tests: adapt alias tests for total ordering + +The "unsorted" test fail now, and are removed. The algorithm is now +better at finding "gaps". + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 88 ++++++++------------------------------------------- + 1 file changed, 14 insertions(+), 74 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index 8ed95d7a..dff5f93b 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -439,27 +439,7 @@ static void mock_self_alias(const char *alias, const char *wwid) + expect_condlog(3, USED_STR(alias, wwid)); \ + } while(0) + +-static int add_binding_unsorted(Bindings *bindings, +- const char *alias, const char *wwid) +-{ +- struct binding *bdg = calloc(1, sizeof(*bdg)); +- +- if (!bdg) +- return -1; +- bdg->wwid = strdup(wwid); +- bdg->alias = strdup(alias); +- if (!bdg->wwid || !bdg->alias || !vector_alloc_slot(bindings)) { +- free(bdg->alias); +- free(bdg->wwid); +- free(bdg); +- return BINDING_ERROR; +- } +- vector_set_slot(bindings, bdg); +- return BINDING_ADDED; +-} +- +-static void __mock_bindings_file(const char *content, +- int (*add)(Bindings *, const char *, const char *)) ++static void __mock_bindings_file(const char *content) + { + char *cnt __attribute__((cleanup(cleanup_charp))) = NULL; + char *token, *savep = NULL; +@@ -478,17 +458,13 @@ static void __mock_bindings_file(const char *content, + == READ_BINDING_SKIP) + continue; + +- rc = add(&global_bindings, alias, wwid); ++ rc = add_binding(&global_bindings, alias, wwid); + assert_int_equal(rc, BINDING_ADDED); + } + } + + static void mock_bindings_file(const char *content) { +- return __mock_bindings_file(content, add_binding); +-} +- +-static void mock_bindings_file_unsorted(const char *content) { +- return __mock_bindings_file(content, add_binding_unsorted); ++ return __mock_bindings_file(content); + } + + static int teardown_bindings(void **state) +@@ -861,10 +837,6 @@ static void lb_nomatch_b_z_a(void **state) + int rc; + char *alias; + +- /* +- * add_bindings() sorts alphabetically. Therefore get_free_id() +- * finds MPATHc as a free entry. +- */ + mock_bindings_file("MPATHb WWID1\n" + "MPATHz WWID26\n" + "MPATHa WWID0\n"); +@@ -880,10 +852,6 @@ static void lb_nomatch_b_aa_a(void **state) + int rc; + char *alias; + +- /* +- * add_bindings() sorts alphabetically. ("a", "aa", b"). +- * The get_free_id() algorithm finds the "hole" after "b". +- */ + mock_bindings_file("MPATHb WWID1\n" + "MPATHz WWID26\n" + "MPATHa WWID0\n"); +@@ -911,10 +879,6 @@ static void lb_nomatch_b_a_aa(void **state) + char *alias; + STRBUF_ON_STACK(buf); + +- /* +- * add_bindings() sorts alphabetically. ("a", "aa", "ab", "b", "c", ...) +- * lookup_binding finds MPATHac as next free entry. +- */ + fill_bindings(&buf, 0, 26); + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWID28")); +@@ -930,10 +894,6 @@ static void lb_nomatch_b_a_aa_zz(void **state) + char *alias; + STRBUF_ON_STACK(buf); + +- /* +- * add_bindings() sorts alphabetically. ("a", "aa", "ab", "b", "c", ...) +- * lookup_binding finds MPATHab as next free entry. +- */ + fill_bindings(&buf, 0, 26); + print_strbuf(&buf, "MPATHzz WWID676\n"); + mock_bindings_file(get_strbuf_str(&buf)); +@@ -944,25 +904,6 @@ static void lb_nomatch_b_a_aa_zz(void **state) + assert_ptr_equal(alias, NULL); + } + +-static void lb_nomatch_b_z_a_unsorted(void **state) +-{ +- int rc; +- char *alias; +- +- /* +- * With unsorted bindings (shouldn't happen normally), get_free_id() +- * plays safe and returns MPATHaa as first free entry. +- */ +- mock_bindings_file_unsorted("MPATHb WWID1\n" +- "MPATHz WWID26\n" +- "MPATHa WWID0\n"); +- expect_condlog(3, NOMATCH_WWID_STR("WWID2")); +- mock_unused_alias("MPATHaa"); +- rc = lookup_binding(NULL, "WWID2", &alias, "MPATH", 1); +- assert_int_equal(rc, 27); +- assert_ptr_equal(alias, NULL); +-} +- + static void lb_nomatch_b_a(void **state) + { + int rc; +@@ -1027,9 +968,9 @@ static void lb_nomatch_int_max_used(void **state) + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWIDNOMORE")); + mock_used_alias("MPATHa", "WWIDNOMORE"); +- expect_condlog(0, NOMORE_STR); ++ mock_unused_alias("MPATHab"); + rc = lookup_binding(NULL, "WWIDNOMORE", &alias, "MPATH", 1); +- assert_int_equal(rc, -1); ++ assert_int_equal(rc, 28); + assert_ptr_equal(alias, NULL); + } + +@@ -1077,9 +1018,9 @@ static void lb_nomatch_int_max_m1_1_used(void **state) + mock_bindings_file(get_strbuf_str(&buf)); + expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); + mock_used_alias("MPATHa", "WWIDMAX"); +- mock_unused_alias("MPATH" MPATH_ID_INT_MAX); ++ mock_unused_alias("MPATHab"); + rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); +- assert_int_equal(rc, INT_MAX); ++ assert_int_equal(rc, 28); + assert_ptr_equal(alias, NULL); + } + +@@ -1095,10 +1036,10 @@ static void lb_nomatch_int_max_m1_2_used(void **state) + + expect_condlog(3, NOMATCH_WWID_STR("WWIDMAX")); + mock_used_alias("MPATHa", "WWIDMAX"); +- mock_used_alias("MPATH" MPATH_ID_INT_MAX, "WWIDMAX"); +- expect_condlog(0, NOMORE_STR); ++ mock_used_alias("MPATHab", "WWIDMAX"); ++ mock_unused_alias("MPATHac"); + rc = lookup_binding(NULL, "WWIDMAX", &alias, "MPATH", 1); +- assert_int_equal(rc, -1); ++ assert_int_equal(rc, 29); + assert_ptr_equal(alias, NULL); + } + #endif +@@ -1133,7 +1074,6 @@ static int test_lookup_binding(void) + cmocka_unit_test_teardown(lb_nomatch_b_aa_a, teardown_bindings), + cmocka_unit_test_teardown(lb_nomatch_b_a_aa, teardown_bindings), + cmocka_unit_test_teardown(lb_nomatch_b_a_aa_zz, teardown_bindings), +- cmocka_unit_test_teardown(lb_nomatch_b_z_a_unsorted, teardown_bindings), + cmocka_unit_test_teardown(lb_nomatch_b_a, teardown_bindings), + cmocka_unit_test_teardown(lb_nomatch_b_a_3_used, teardown_bindings), + #ifdef MPATH_ID_INT_MAX +@@ -1593,14 +1533,14 @@ static void gufa_nomatch_b_f_a(void **state) { + "MPATHf WWID6\n" + "MPATHa WWID0\n"); + +- mock_bindings_file_unsorted(bindings); ++ mock_bindings_file(bindings); + expect_condlog(3, NOMATCH_WWID_STR("WWID7")); +- mock_unused_alias("MPATHg"); ++ mock_unused_alias("MPATHc"); + +- mock_allocate_binding_len("MPATHg", "WWID7", sizeof(bindings) - 1); ++ mock_allocate_binding_len("MPATHc", "WWID7", sizeof(bindings) - 1); + + alias = get_user_friendly_alias("WWID7", "x", "", "MPATH", false); +- assert_string_equal(alias, "MPATHg"); ++ assert_string_equal(alias, "MPATHc"); + free(alias); + } + diff --git a/0026-multipath-tools-tests-add-test-for-ordering-of-bindi.patch b/0026-multipath-tools-tests-add-test-for-ordering-of-bindi.patch new file mode 100644 index 0000000..5317ef9 --- /dev/null +++ b/0026-multipath-tools-tests-add-test-for-ordering-of-bindi.patch @@ -0,0 +1,275 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 21:39:44 +0200 +Subject: [PATCH] multipath-tools tests: add test for ordering of bindings + +As the assignment of free aliases now relies on the bindings being +properly sorted, add some unit tests to make sure the sorting algorithm +works. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/alias.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 209 insertions(+), 3 deletions(-) + +diff --git a/tests/alias.c b/tests/alias.c +index dff5f93b..7f3ff38a 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -13,6 +13,9 @@ + #include "globals.c" + #include "../libmultipath/alias.c" + ++/* For verbose printing of all aliases in the ordering tests */ ++#define ALIAS_DEBUG 0 ++ + #if INT_MAX == 0x7fffffff + /* user_friendly_name for map #INT_MAX */ + #define MPATH_ID_INT_MAX "fxshrxw" +@@ -439,11 +442,12 @@ static void mock_self_alias(const char *alias, const char *wwid) + expect_condlog(3, USED_STR(alias, wwid)); \ + } while(0) + +-static void __mock_bindings_file(const char *content) ++static void __mock_bindings_file(const char *content, bool conflict_ok) + { + char *cnt __attribute__((cleanup(cleanup_charp))) = NULL; + char *token, *savep = NULL; + int i; ++ uintmax_t values[] = { BINDING_ADDED, BINDING_CONFLICT }; + + cnt = strdup(content); + assert_ptr_not_equal(cnt, NULL); +@@ -459,12 +463,12 @@ static void __mock_bindings_file(const char *content) + continue; + + rc = add_binding(&global_bindings, alias, wwid); +- assert_int_equal(rc, BINDING_ADDED); ++ assert_in_set(rc, values, conflict_ok ? 2 : 1); + } + } + + static void mock_bindings_file(const char *content) { +- return __mock_bindings_file(content); ++ return __mock_bindings_file(content, false); + } + + static int teardown_bindings(void **state) +@@ -1744,6 +1748,207 @@ static int test_get_user_friendly_alias() + return cmocka_run_group_tests(tests, NULL, NULL); + } + ++/* Numbers 1-1000, randomly shuffled */ ++static const int random_numbers[1000] = { ++ 694, 977, 224, 178, 841, 818, 914, 549, 831, 942, 263, 834, 919, 800, ++ 111, 517, 719, 297, 988, 98, 332, 516, 754, 772, 495, 488, 331, 529, ++ 142, 747, 848, 618, 375, 624, 74, 753, 782, 944, 623, 468, 862, 997, ++ 417, 258, 298, 774, 673, 904, 883, 766, 867, 400, 11, 950, 14, 784, ++ 655, 155, 396, 9, 743, 93, 651, 245, 968, 306, 785, 581, 880, 486, ++ 168, 631, 203, 4, 663, 294, 702, 762, 619, 684, 48, 181, 21, 443, 643, ++ 863, 1000, 327, 26, 126, 382, 765, 586, 76, 49, 925, 319, 865, 797, ++ 876, 693, 334, 433, 243, 419, 901, 854, 326, 985, 347, 874, 527, 282, ++ 290, 380, 167, 95, 3, 257, 936, 60, 426, 227, 345, 577, 492, 467, 580, ++ 967, 422, 823, 718, 610, 64, 700, 412, 163, 288, 506, 828, 432, 51, ++ 356, 348, 539, 478, 17, 945, 602, 123, 450, 660, 429, 113, 310, 358, ++ 512, 758, 508, 19, 542, 304, 286, 446, 918, 723, 333, 603, 731, 978, ++ 230, 697, 109, 872, 175, 853, 947, 965, 121, 222, 101, 811, 117, 601, ++ 191, 752, 384, 415, 938, 278, 915, 715, 240, 552, 912, 838, 150, 840, ++ 627, 29, 636, 464, 861, 481, 992, 249, 934, 82, 368, 724, 807, 593, ++ 157, 147, 199, 637, 41, 62, 902, 505, 621, 342, 174, 260, 729, 961, ++ 219, 311, 629, 789, 81, 739, 860, 712, 223, 165, 741, 981, 485, 363, ++ 346, 709, 125, 369, 279, 634, 399, 162, 193, 769, 149, 314, 868, 612, ++ 524, 675, 341, 343, 476, 606, 388, 613, 850, 264, 903, 451, 908, 779, ++ 453, 148, 497, 46, 132, 43, 885, 955, 269, 395, 72, 128, 767, 989, ++ 929, 423, 742, 55, 13, 79, 924, 182, 295, 563, 668, 169, 974, 154, ++ 970, 54, 674, 52, 437, 570, 550, 531, 554, 793, 678, 218, 367, 105, ++ 197, 315, 958, 892, 86, 47, 284, 37, 561, 522, 198, 689, 817, 573, ++ 877, 201, 803, 501, 881, 546, 530, 523, 780, 579, 953, 135, 23, 620, ++ 84, 698, 303, 656, 357, 323, 494, 58, 131, 913, 995, 120, 70, 1, 195, ++ 365, 210, 25, 898, 173, 307, 239, 77, 418, 952, 963, 92, 455, 425, 12, ++ 536, 161, 328, 933, 401, 251, 735, 725, 362, 322, 557, 681, 302, 53, ++ 786, 801, 391, 946, 748, 133, 717, 851, 7, 372, 993, 387, 906, 373, ++ 667, 33, 670, 389, 209, 611, 896, 652, 69, 999, 344, 845, 633, 36, ++ 487, 192, 180, 45, 640, 427, 707, 805, 188, 152, 905, 217, 30, 252, ++ 386, 665, 299, 541, 410, 787, 5, 857, 751, 392, 44, 595, 146, 745, ++ 641, 957, 866, 773, 806, 815, 659, 102, 704, 430, 106, 296, 129, 847, ++ 130, 990, 669, 236, 225, 680, 159, 213, 438, 189, 447, 600, 232, 594, ++ 32, 56, 390, 647, 855, 428, 330, 714, 738, 706, 666, 461, 469, 482, ++ 558, 814, 559, 177, 575, 538, 309, 383, 261, 156, 420, 761, 630, 893, ++ 10, 116, 940, 844, 71, 377, 662, 312, 520, 244, 143, 759, 119, 186, ++ 592, 909, 864, 376, 768, 254, 265, 394, 511, 760, 574, 6, 436, 514, ++ 59, 226, 644, 956, 578, 825, 548, 145, 736, 597, 378, 821, 987, 897, ++ 354, 144, 722, 895, 589, 503, 826, 498, 543, 617, 763, 231, 808, 528, ++ 89, 479, 607, 737, 170, 404, 371, 65, 103, 340, 283, 141, 313, 858, ++ 289, 124, 971, 687, 954, 732, 39, 926, 176, 100, 267, 519, 890, 535, ++ 276, 448, 27, 457, 899, 385, 184, 275, 770, 544, 614, 449, 160, 658, ++ 259, 973, 108, 604, 24, 207, 562, 757, 744, 324, 444, 962, 591, 480, ++ 398, 409, 998, 253, 325, 445, 979, 8, 35, 118, 73, 683, 208, 85, 190, ++ 791, 408, 871, 657, 179, 18, 556, 496, 475, 20, 894, 484, 775, 889, ++ 463, 241, 730, 57, 907, 551, 859, 943, 185, 416, 870, 590, 435, 471, ++ 932, 268, 381, 626, 502, 565, 273, 534, 672, 778, 292, 473, 566, 104, ++ 172, 285, 832, 411, 329, 628, 397, 472, 271, 910, 711, 690, 969, 585, ++ 809, 941, 923, 555, 228, 685, 242, 94, 96, 211, 140, 61, 922, 795, ++ 869, 34, 255, 38, 984, 676, 15, 560, 632, 434, 921, 355, 582, 351, ++ 212, 200, 819, 960, 649, 852, 75, 771, 361, 996, 238, 316, 720, 671, ++ 462, 112, 569, 171, 664, 625, 588, 405, 553, 270, 533, 353, 842, 114, ++ 972, 83, 937, 63, 194, 237, 537, 980, 802, 916, 959, 688, 839, 350, ++ 917, 650, 545, 615, 151, 352, 686, 726, 266, 509, 439, 491, 935, 608, ++ 518, 653, 339, 609, 277, 635, 836, 88, 407, 440, 642, 927, 229, 727, ++ 360, 477, 846, 413, 454, 616, 28, 598, 567, 540, 790, 424, 247, 317, ++ 746, 911, 798, 321, 547, 248, 734, 829, 220, 138, 756, 500, 691, 196, ++ 740, 930, 843, 733, 221, 827, 50, 813, 949, 525, 349, 474, 134, 875, ++ 695, 513, 414, 515, 638, 99, 366, 490, 975, 246, 465, 206, 281, 583, ++ 256, 587, 749, 2, 951, 679, 215, 364, 458, 402, 646, 991, 335, 982, ++ 835, 300, 900, 703, 994, 983, 234, 888, 532, 804, 584, 305, 792, 442, ++ 291, 964, 158, 370, 452, 250, 521, 166, 948, 812, 794, 272, 699, 205, ++ 183, 507, 301, 920, 781, 233, 824, 137, 489, 833, 887, 966, 856, 78, ++ 830, 153, 359, 696, 526, 216, 66, 701, 403, 891, 849, 571, 308, 483, ++ 164, 293, 928, 677, 320, 837, 441, 639, 564, 510, 648, 274, 336, 661, ++ 878, 777, 816, 976, 493, 810, 67, 87, 91, 187, 882, 986, 80, 22, 499, ++ 90, 705, 139, 136, 122, 708, 716, 886, 572, 127, 40, 721, 764, 16, ++ 379, 692, 645, 456, 710, 460, 783, 97, 776, 713, 884, 115, 466, 596, ++ 374, 406, 110, 568, 68, 214, 622, 470, 107, 504, 682, 31, 421, 576, ++ 654, 605, 788, 799, 280, 338, 931, 873, 204, 287, 459, 755, 939, 599, ++ 431, 796, 235, 42, 750, 262, 318, 393, 202, 822, 879, 820, 728, 337, ++}; ++ ++static void fill_bindings_random(struct strbuf *buf, int start, int end, ++ const char *prefix) ++{ ++ int i; ++ ++ for (i = start; i < end; i++) { ++ print_strbuf(buf, "%s", prefix); ++ format_devname(buf, random_numbers[i]); ++ print_strbuf(buf, " WWID%d\n", random_numbers[i]); ++ } ++} ++ ++struct random_aliases { ++ int start; ++ int end; ++ const char *prefix; ++}; ++ ++static void order_test(int n, const struct random_aliases ra[], bool conflict_ok) ++{ ++ STRBUF_ON_STACK(buf); ++ int i, j, prev, curr, tmp; ++ struct binding *bdg; ++ Bindings *bindings = &global_bindings; ++ ++ for (j = 0; j < n; j++) ++ fill_bindings_random(&buf, ra[j].start, ra[j].end, ra[j].prefix); ++ __mock_bindings_file(get_strbuf_str(&buf), conflict_ok); ++ ++ for (j = 0; j < n; j++) { ++ bdg = VECTOR_SLOT(bindings, 0); ++ if (ALIAS_DEBUG && j == 0) ++ printf("%d: %s\n", 0, bdg->alias); ++ prev = scan_devname(bdg->alias, ra[j].prefix); ++ i = 1; ++ vector_foreach_slot_after(bindings, bdg, i) { ++ if (ALIAS_DEBUG && j == 0) ++ printf("%d: %s\n", i, bdg->alias); ++ tmp = scan_devname(bdg->alias, ra[j].prefix); ++ if (tmp == -1) ++ continue; ++ curr = tmp; ++ if (prev > 0) { ++ if (curr <= prev) ++ printf("ERROR: %d (%s) %d >= %d\n", ++ i, bdg->alias, prev, curr); ++ assert_true(curr > prev); ++ } ++ prev = curr; ++ } ++ } ++} ++ ++static void order_01(void **state) ++{ ++ const struct random_aliases ra[] = { ++ { 0, 1000, "MPATH" }, ++ }; ++ ++ order_test(ARRAY_SIZE(ra), ra, false); ++} ++ ++static void order_02(void **state) ++{ ++ const struct random_aliases ra[] = { ++ { 0, 500, "MPATH" }, ++ { 200, 700, "mpath" }, ++ }; ++ order_test(ARRAY_SIZE(ra), ra, false); ++} ++ ++static void order_03(void **state) ++{ ++ const struct random_aliases ra[] = { ++ { 500, 1000, "MPTH" }, ++ { 0, 500, "MPATH" }, ++ }; ++ order_test(ARRAY_SIZE(ra), ra, false); ++} ++ ++static void order_04(void **state) ++{ ++ const struct random_aliases ra[] = { ++ { 0, 500, "mpa" }, ++ { 250, 750, "mp" }, ++ }; ++ order_test(ARRAY_SIZE(ra), ra, true); ++} ++ ++static void order_05(void **state) ++{ ++ const struct random_aliases ra[] = { ++ { 0, 100, "A" }, ++ { 0, 100, "B" }, ++ { 0, 100, "C" }, ++ { 0, 100, "D" }, ++ }; ++ order_test(ARRAY_SIZE(ra), ra, false); ++} ++ ++static void order_06(void **state) ++{ ++ const struct random_aliases ra[] = { ++ { 0, 100, "" }, ++ { 0, 100, "a" }, ++ { 0, 100, "aa" }, ++ { 0, 100, "ab" }, ++ { 0, 100, "aaa" }, ++ }; ++ order_test(ARRAY_SIZE(ra), ra, true); ++} ++ ++static int test_bindings_order() ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_teardown(order_01, teardown_bindings), ++ cmocka_unit_test_teardown(order_02, teardown_bindings), ++ cmocka_unit_test_teardown(order_03, teardown_bindings), ++ cmocka_unit_test_teardown(order_04, teardown_bindings), ++ cmocka_unit_test_teardown(order_05, teardown_bindings), ++ cmocka_unit_test_teardown(order_06, teardown_bindings), ++ }; ++ ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} ++ + int main(void) + { + int ret = 0; +@@ -1755,6 +1960,7 @@ int main(void) + ret += test_rlookup_binding(); + ret += test_allocate_binding(); + ret += test_get_user_friendly_alias(); ++ ret += test_bindings_order(); + + return ret; + } diff --git a/0027-multipathd-watch-bindings-file-with-inotify-timestam.patch b/0027-multipathd-watch-bindings-file-with-inotify-timestam.patch new file mode 100644 index 0000000..af21b74 --- /dev/null +++ b/0027-multipathd-watch-bindings-file-with-inotify-timestam.patch @@ -0,0 +1,597 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 7 Sep 2023 22:22:43 +0200 +Subject: [PATCH] multipathd: watch bindings file with inotify + timestamp + +Since "libmultipath: keep bindings in memory", we don't re-read the +bindings file after every modification. Add a notification mechanism +that makes multipathd aware of changes to the bindings file. Because +multipathd itself will change the bindings file, it must compare +timestamps in order to avoid reading the file repeatedly. + +Because select_alias() can be called from multiple thread contexts (uxlsnr, +uevent handler), we need to add locking for the bindings file. The +timestamp must also be protected by a lock, because it can't be read +or written atomically. + +Note: The notification mechanism expects the bindings file to be +atomically replaced by rename(2). Changes must be made in a temporary file and +applied using rename(2), as in update_bindings_file(). The inotify +mechanism deliberately does not listen to close-after-write events +that would be generated by editing the bindings file directly. This + +Note also: new bindings will only be read from add_map_with_path(), +i.e. either during reconfigure(), or when a new map is created during +runtime. Existing maps will not be renamed if the binding file changes, +unless the user runs "multipathd reconfigure". This is not a change +wrt the previous code, but it should be mentioned anyway. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 256 +++++++++++++++++++++++++----- + libmultipath/alias.h | 3 +- + libmultipath/libmultipath.version | 5 + + multipathd/uxlsnr.c | 36 ++++- + tests/alias.c | 3 + + 5 files changed, 256 insertions(+), 47 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 66e34e31..964b8a7b 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "debug.h" + #include "util.h" +@@ -22,6 +23,7 @@ + #include "config.h" + #include "devmapper.h" + #include "strbuf.h" ++#include "time-util.h" + + /* + * significant parts of this file were taken from iscsi-bindings.c of the +@@ -50,6 +52,12 @@ + "# alias wwid\n" \ + "#\n" + ++/* uatomic access only */ ++static int bindings_file_changed = 1; ++ ++static pthread_mutex_t timestamp_mutex = PTHREAD_MUTEX_INITIALIZER; ++static struct timespec bindings_last_updated; ++ + struct binding { + char *alias; + char *wwid; +@@ -60,6 +68,9 @@ struct binding { + * an abstract type. + */ + typedef struct _vector Bindings; ++ ++/* Protect global_bindings */ ++static pthread_mutex_t bindings_mutex = PTHREAD_MUTEX_INITIALIZER; + static Bindings global_bindings = { .allocated = 0 }; + + enum { +@@ -78,6 +89,27 @@ static void _free_binding(struct binding *bdg) + free(bdg); + } + ++static void free_bindings(Bindings *bindings) ++{ ++ struct binding *bdg; ++ int i; ++ ++ vector_foreach_slot(bindings, bdg, i) ++ _free_binding(bdg); ++ vector_reset(bindings); ++} ++ ++static void set_global_bindings(Bindings *bindings) ++{ ++ Bindings old_bindings; ++ ++ pthread_mutex_lock(&bindings_mutex); ++ old_bindings = global_bindings; ++ global_bindings = *bindings; ++ pthread_mutex_unlock(&bindings_mutex); ++ free_bindings(&old_bindings); ++} ++ + static const struct binding *get_binding_for_alias(const Bindings *bindings, + const char *alias) + { +@@ -199,7 +231,8 @@ static int delete_binding(Bindings *bindings, const char *wwid) + return BINDING_DELETED; + } + +-static int write_bindings_file(const Bindings *bindings, int fd) ++static int write_bindings_file(const Bindings *bindings, int fd, ++ struct timespec *ts) + { + struct binding *bnd; + STRBUF_ON_STACK(content); +@@ -227,9 +260,56 @@ static int write_bindings_file(const Bindings *bindings, int fd) + } + len -= n; + } ++ fsync(fd); ++ if (ts) { ++ struct stat st; ++ ++ if (fstat(fd, &st) == 0) ++ *ts = st.st_mtim; ++ else ++ clock_gettime(CLOCK_REALTIME_COARSE, ts); ++ } + return 0; + } + ++void handle_bindings_file_inotify(const struct inotify_event *event) ++{ ++ struct config *conf; ++ const char *base; ++ bool changed = false; ++ struct stat st; ++ struct timespec ts = { 0, 0 }; ++ int ret; ++ ++ if (!(event->mask & IN_MOVED_TO)) ++ return; ++ ++ conf = get_multipath_config(); ++ base = strrchr(conf->bindings_file, '/'); ++ changed = base && base > conf->bindings_file && ++ !strcmp(base + 1, event->name); ++ ret = stat(conf->bindings_file, &st); ++ put_multipath_config(conf); ++ ++ if (!changed) ++ return; ++ ++ pthread_mutex_lock(×tamp_mutex); ++ if (ret == 0) { ++ ts = st.st_mtim; ++ changed = timespeccmp(&ts, &bindings_last_updated) > 0; ++ } ++ pthread_mutex_unlock(×tamp_mutex); ++ ++ if (changed) { ++ uatomic_xchg(&bindings_file_changed, 1); ++ condlog(3, "%s: bindings file must be re-read, new timestamp: %ld.%06ld", ++ __func__, (long)ts.tv_sec, (long)ts.tv_nsec / 1000); ++ } else ++ condlog(3, "%s: bindings file is up-to-date, timestamp: %ld.%06ld", ++ __func__, (long)ts.tv_sec, (long)ts.tv_nsec / 1000); ++} ++ + static int update_bindings_file(const Bindings *bindings, + const char *bindings_file) + { +@@ -237,6 +317,7 @@ static int update_bindings_file(const Bindings *bindings, + int fd = -1; + char tempname[PATH_MAX]; + mode_t old_umask; ++ struct timespec ts; + + if (safe_sprintf(tempname, "%s.XXXXXX", bindings_file)) + return -1; +@@ -248,7 +329,7 @@ static int update_bindings_file(const Bindings *bindings, + } + umask(old_umask); + pthread_cleanup_push(cleanup_fd_ptr, &fd); +- rc = write_bindings_file(bindings, fd); ++ rc = write_bindings_file(bindings, fd, &ts); + pthread_cleanup_pop(1); + if (rc == -1) { + condlog(1, "failed to write new bindings file"); +@@ -257,8 +338,12 @@ static int update_bindings_file(const Bindings *bindings, + } + if ((rc = rename(tempname, bindings_file)) == -1) + condlog(0, "%s: rename: %m", __func__); +- else ++ else { ++ pthread_mutex_lock(×tamp_mutex); ++ bindings_last_updated = ts; ++ pthread_mutex_unlock(×tamp_mutex); + condlog(1, "updated bindings file %s", bindings_file); ++ } + return rc; + } + +@@ -387,6 +472,7 @@ int get_free_id(const Bindings *bindings, const char *prefix, const char *map_ww + return id; + } + ++/* Called with binding_mutex held */ + static char * + allocate_binding(const char *filename, const char *wwid, int id, const char *prefix) + { +@@ -423,6 +509,30 @@ allocate_binding(const char *filename, const char *wwid, int id, const char *pre + return alias; + } + ++enum { ++ BINDINGS_FILE_UP2DATE, ++ BINDINGS_FILE_READ, ++ BINDINGS_FILE_ERROR, ++ BINDINGS_FILE_BAD, ++}; ++ ++static int _read_bindings_file(const struct config *conf, Bindings *bindings, ++ bool force); ++ ++static void read_bindings_file(void) ++{ ++ struct config *conf; ++ Bindings bindings = {.allocated = 0, }; ++ int rc; ++ ++ conf = get_multipath_config(); ++ pthread_cleanup_push(put_multipath_config, conf); ++ rc = _read_bindings_file(conf, &bindings, false); ++ pthread_cleanup_pop(1); ++ if (rc == BINDINGS_FILE_READ) ++ set_global_bindings(&bindings); ++} ++ + /* + * get_user_friendly_alias() action table + * +@@ -463,6 +573,11 @@ char *get_user_friendly_alias(const char *wwid, const char *file, const char *al + bool new_binding = false; + const struct binding *bdg; + ++ read_bindings_file(); ++ ++ pthread_mutex_lock(&bindings_mutex); ++ pthread_cleanup_push(cleanup_mutex, &bindings_mutex); ++ + if (!*alias_old) + goto new_alias; + +@@ -514,40 +629,40 @@ new_alias: + alias, wwid); + + out: ++ /* unlock bindings_mutex */ ++ pthread_cleanup_pop(1); + return alias; + } + + int get_user_friendly_wwid(const char *alias, char *buff) + { + const struct binding *bdg; ++ int rc = -1; + + if (!alias || *alias == '\0') { + condlog(3, "Cannot find binding for empty alias"); + return -1; + } + ++ read_bindings_file(); ++ ++ pthread_mutex_lock(&bindings_mutex); ++ pthread_cleanup_push(cleanup_mutex, &bindings_mutex); + bdg = get_binding_for_alias(&global_bindings, alias); +- if (!bdg) { ++ if (bdg) { ++ strlcpy(buff, bdg->wwid, WWID_SIZE); ++ rc = 0; ++ } else + *buff = '\0'; +- return -1; +- } +- strlcpy(buff, bdg->wwid, WWID_SIZE); +- return 0; +-} +- +-static void free_bindings(Bindings *bindings) +-{ +- struct binding *bdg; +- int i; +- +- vector_foreach_slot(bindings, bdg, i) +- _free_binding(bdg); +- vector_reset(bindings); ++ pthread_cleanup_pop(1); ++ return rc; + } + + void cleanup_bindings(void) + { ++ pthread_mutex_lock(&bindings_mutex); + free_bindings(&global_bindings); ++ pthread_mutex_unlock(&bindings_mutex); + } + + enum { +@@ -595,7 +710,20 @@ static int _check_bindings_file(const struct config *conf, FILE *file, + char *line = NULL; + size_t line_len = 0; + ssize_t n; +- ++ char header[sizeof(BINDINGS_FILE_HEADER)]; ++ ++ header[sizeof(BINDINGS_FILE_HEADER) - 1] = '\0'; ++ if (fread(header, sizeof(BINDINGS_FILE_HEADER) - 1, 1, file) < 1) { ++ condlog(2, "%s: failed to read header from %s", __func__, ++ conf->bindings_file); ++ fseek(file, 0, SEEK_SET); ++ rc = -1; ++ } else if (strcmp(header, BINDINGS_FILE_HEADER)) { ++ condlog(2, "%s: invalid header in %s", __func__, ++ conf->bindings_file); ++ fseek(file, 0, SEEK_SET); ++ rc = -1; ++ } + pthread_cleanup_push(cleanup_free_ptr, &line); + while ((n = getline(&line, &line_len, file)) >= 0) { + char *alias, *wwid; +@@ -643,6 +771,68 @@ static int mp_alias_compar(const void *p1, const void *p2) + &((*(struct mpentry * const *)p2)->alias)); + } + ++static int _read_bindings_file(const struct config *conf, Bindings *bindings, ++ bool force) ++{ ++ int can_write; ++ int rc = 0, ret, fd; ++ FILE *file; ++ struct stat st; ++ int has_changed = uatomic_xchg(&bindings_file_changed, 0); ++ ++ if (!force) { ++ if (!has_changed) { ++ condlog(4, "%s: bindings are unchanged", __func__); ++ return BINDINGS_FILE_UP2DATE; ++ } ++ } ++ ++ fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER); ++ if (fd == -1) ++ return BINDINGS_FILE_ERROR; ++ ++ file = fdopen(fd, "r"); ++ if (file != NULL) { ++ condlog(3, "%s: reading %s", __func__, conf->bindings_file); ++ ++ pthread_cleanup_push(cleanup_fclose, file); ++ ret = _check_bindings_file(conf, file, bindings); ++ if (ret == 0) { ++ struct timespec ts; ++ ++ rc = BINDINGS_FILE_READ; ++ ret = fstat(fd, &st); ++ if (ret == 0) ++ ts = st.st_mtim; ++ else { ++ condlog(1, "%s: fstat failed (%m), using current time", __func__); ++ clock_gettime(CLOCK_REALTIME_COARSE, &ts); ++ } ++ pthread_mutex_lock(×tamp_mutex); ++ bindings_last_updated = ts; ++ pthread_mutex_unlock(×tamp_mutex); ++ } else if (ret == -1 && can_write && !conf->bindings_read_only) { ++ ret = update_bindings_file(bindings, conf->bindings_file); ++ if (ret == 0) ++ rc = BINDINGS_FILE_READ; ++ else ++ rc = BINDINGS_FILE_BAD; ++ } else { ++ condlog(0, "ERROR: bad settings in read-only bindings file %s", ++ conf->bindings_file); ++ rc = BINDINGS_FILE_BAD; ++ } ++ pthread_cleanup_pop(1); ++ } else { ++ condlog(1, "failed to fdopen %s: %m", ++ conf->bindings_file); ++ close(fd); ++ rc = BINDINGS_FILE_ERROR; ++ } ++ ++ return rc; ++} ++ + /* + * check_alias_settings(): test for inconsistent alias configuration + * +@@ -661,8 +851,7 @@ static int mp_alias_compar(const void *p1, const void *p2) + */ + int check_alias_settings(const struct config *conf) + { +- int can_write; +- int rc = 0, i, fd; ++ int i, rc; + Bindings bindings = {.allocated = 0, }; + vector mptable = NULL; + struct mpentry *mpe; +@@ -695,27 +884,12 @@ int check_alias_settings(const struct config *conf) + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + +- fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER); +- if (fd != -1) { +- FILE *file = fdopen(fd, "r"); +- +- if (file != NULL) { +- pthread_cleanup_push(cleanup_fclose, file); +- rc = _check_bindings_file(conf, file, &bindings); +- pthread_cleanup_pop(1); +- if (rc == -1 && can_write && !conf->bindings_read_only) +- rc = update_bindings_file(&bindings, conf->bindings_file); +- else if (rc == -1) +- condlog(0, "ERROR: bad settings in read-only bindings file %s", +- conf->bindings_file); +- } else { +- condlog(1, "failed to fdopen %s: %m", +- conf->bindings_file); +- close(fd); +- } ++ rc = _read_bindings_file(conf, &bindings, true); ++ ++ if (rc == BINDINGS_FILE_READ) { ++ set_global_bindings(&bindings); ++ rc = 0; + } + +- cleanup_bindings(); +- global_bindings = bindings; + return rc; + } +diff --git a/libmultipath/alias.h b/libmultipath/alias.h +index 5ef6720b..ca8911f4 100644 +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -10,5 +10,6 @@ char *get_user_friendly_alias(const char *wwid, const char *file, + struct config; + int check_alias_settings(const struct config *); + void cleanup_bindings(void); +- ++struct inotify_event; ++void handle_bindings_file_inotify(const struct inotify_event *event); + #endif /* _ALIAS_H */ +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index ddd302f5..57e50c12 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -238,3 +238,8 @@ global: + local: + *; + }; ++ ++LIBMULTIPATH_20.1.0 { ++global: ++ handle_bindings_file_inotify; ++}; +diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c +index 02e89fb4..d1f8f234 100644 +--- a/multipathd/uxlsnr.c ++++ b/multipathd/uxlsnr.c +@@ -41,6 +41,7 @@ + #include "cli.h" + #include "uxlsnr.h" + #include "strbuf.h" ++#include "alias.h" + + /* state of client connection */ + enum { +@@ -190,6 +191,7 @@ void wakeup_cleanup(void *arg) + struct watch_descriptors { + int conf_wd; + int dir_wd; ++ int mp_wd; /* /etc/multipath; for bindings file */ + }; + + /* failing to set the watch descriptor is o.k. we just miss a warning +@@ -200,6 +202,8 @@ static void reset_watch(int notify_fd, struct watch_descriptors *wds, + struct config *conf; + int dir_reset = 0; + int conf_reset = 0; ++ int mp_reset = 0; ++ char *bindings_file __attribute__((cleanup(cleanup_charp))) = NULL; + + if (notify_fd == -1) + return; +@@ -214,7 +218,10 @@ static void reset_watch(int notify_fd, struct watch_descriptors *wds, + conf_reset = 1; + if (wds->dir_wd == -1) + dir_reset = 1; ++ if (wds->mp_wd == -1) ++ mp_reset = 1; + } ++ bindings_file = strdup(conf->bindings_file); + put_multipath_config(conf); + + if (dir_reset) { +@@ -235,7 +242,18 @@ static void reset_watch(int notify_fd, struct watch_descriptors *wds, + if (wds->conf_wd == -1) + condlog(3, "didn't set up notifications on /etc/multipath.conf: %m"); + } +- return; ++ if (mp_reset && bindings_file) { ++ char *slash = strrchr(bindings_file, '/'); ++ ++ if (slash && slash > bindings_file) { ++ *slash = '\0'; ++ wds->mp_wd = inotify_add_watch(notify_fd, bindings_file, ++ IN_MOVED_TO|IN_ONLYDIR); ++ if (wds->mp_wd == -1) ++ condlog(3, "didn't set up notifications on %s: %m", ++ bindings_file); ++ } ++ } + } + + static void handle_inotify(int fd, struct watch_descriptors *wds) +@@ -256,12 +274,13 @@ static void handle_inotify(int fd, struct watch_descriptors *wds) + inotify_rm_watch(fd, wds->conf_wd); + if (wds->dir_wd != -1) + inotify_rm_watch(fd, wds->dir_wd); +- wds->conf_wd = wds->dir_wd = -1; ++ if (wds->mp_wd != -1) ++ inotify_rm_watch(fd, wds->mp_wd); ++ wds->conf_wd = wds->dir_wd = wds->mp_wd = -1; + } + break; + } + +- got_notify = 1; + for (ptr = buff; ptr < buff + len; + ptr += sizeof(struct inotify_event) + event->len) { + event = (const struct inotify_event *) ptr; +@@ -273,7 +292,13 @@ static void handle_inotify(int fd, struct watch_descriptors *wds) + wds->conf_wd = inotify_add_watch(notify_fd, DEFAULT_CONFIGFILE, IN_CLOSE_WRITE); + else if (wds->dir_wd == event->wd) + wds->dir_wd = -1; ++ else if (wds->mp_wd == event->wd) ++ wds->mp_wd = -1; + } ++ if (wds->mp_wd != -1 && wds->mp_wd == event->wd) ++ handle_bindings_file_inotify(event); ++ else ++ got_notify = 1; + } + } + if (got_notify) +@@ -599,7 +624,7 @@ void *uxsock_listen(long ux_sock, void *trigger_data) + 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 }; ++ struct watch_descriptors wds = { .conf_wd = -1, .dir_wd = -1, .mp_wd = -1, }; + struct vectors *vecs = trigger_data; + + condlog(3, "uxsock: startup listener"); +@@ -666,7 +691,8 @@ void *uxsock_listen(long ux_sock, void *trigger_data) + + reset_watch(notify_fd, &wds, &sequence_nr); + polls[POLLFD_NOTIFY].fd = notify_fd; +- if (notify_fd == -1 || (wds.conf_wd == -1 && wds.dir_wd == -1)) ++ if (notify_fd == -1 || (wds.conf_wd == -1 && wds.dir_wd == -1 ++ && wds.mp_wd == -1)) + polls[POLLFD_NOTIFY].events = 0; + else + polls[POLLFD_NOTIFY].events = POLLIN; +diff --git a/tests/alias.c b/tests/alias.c +index 7f3ff38a..9ae27567 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -1954,6 +1954,9 @@ int main(void) + int ret = 0; + init_test_verbosity(3); + ++ /* avoid open_file() call in _read_bindings_file */ ++ bindings_file_changed = 0; ++ + ret += test_format_devname(); + ret += test_scan_devname(); + ret += test_lookup_binding(); diff --git a/0028-multipath-tools-tests-mock-pthread_mutex_-lock-unloc.patch b/0028-multipath-tools-tests-mock-pthread_mutex_-lock-unloc.patch new file mode 100644 index 0000000..bba92f3 --- /dev/null +++ b/0028-multipath-tools-tests-mock-pthread_mutex_-lock-unloc.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 19:54:07 +0200 +Subject: [PATCH] multipath-tools tests: mock pthread_mutex_{lock,unlock} + +If some test fails with a lock held, cmocka doesn't deal well with +pthread_cleanup_pop(). Such tests can cause deadlock with the locking +primitives in the alias code, because locks don't get properly unlocked. Just +mock the lock/unlock functions and generate an error if they weren't paired at +the end of the test. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + tests/Makefile | 1 + + tests/alias.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 47 insertions(+) + +diff --git a/tests/Makefile b/tests/Makefile +index c777d07a..7dac8a8f 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -52,6 +52,7 @@ blacklist-test_LIBDEPS := -ludev + vpd-test_OBJDEPS := $(multipathdir)/discovery.o + vpd-test_LIBDEPS := -ludev -lpthread -ldl + alias-test_TESTDEPS := test-log.o ++alias-test_OBJDEPS := $(mpathutildir)/util.o + alias-test_LIBDEPS := -lpthread -ldl + valid-test_OBJDEPS := $(multipathdir)/valid.o $(multipathdir)/discovery.o + valid-test_LIBDEPS := -lmount -ludev -lpthread -ldl +diff --git a/tests/alias.c b/tests/alias.c +index 9ae27567..94df36d8 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -89,6 +89,47 @@ int __wrap_dm_get_uuid(const char *name, char *uuid, int uuid_len) + return ret; + } + ++static int lock_errors; ++static int bindings_locked; ++static int timestamp_locked; ++int __wrap_pthread_mutex_lock(pthread_mutex_t *mutex) ++{ ++ if (mutex == &bindings_mutex) { ++ if (bindings_locked) { ++ fprintf(stderr, "%s: bindings_mutex LOCKED\n", __func__); ++ lock_errors++; ++ } ++ bindings_locked = 1; ++ } else if (mutex == ×tamp_mutex) { ++ if (timestamp_locked) { ++ fprintf(stderr, "%s: timestamp_mutex LOCKED\n", __func__); ++ lock_errors++; ++ } ++ timestamp_locked = 1; ++ } else ++ fprintf(stderr, "%s called for unknown mutex %p\n", __func__, mutex); ++ return 0; ++} ++ ++int __wrap_pthread_mutex_unlock(pthread_mutex_t *mutex) ++{ ++ if (mutex == &bindings_mutex) { ++ if (!bindings_locked) { ++ fprintf(stderr, "%s: bindings_mutex UNLOCKED\n", __func__); ++ lock_errors++; ++ } ++ bindings_locked = 0; ++ } else if (mutex == ×tamp_mutex) { ++ if (!timestamp_locked) { ++ fprintf(stderr, "%s: timestamp_mutex UNLOCKED\n", __func__); ++ lock_errors++; ++ } ++ timestamp_locked = 0; ++ } else ++ fprintf(stderr, "%s called for unknown mutex %p\n", __func__, mutex); ++ return 0; ++} ++ + #define TEST_FDNO 1234 + #define TEST_FPTR ((FILE *) 0xaffe) + +@@ -1718,6 +1759,10 @@ static void gufa_old_nomatch_nowwidmatch(void **state) { + free(alias); + } + ++static void gufa_check_locking(void **state) { ++ assert_int_equal(lock_errors, 0); ++} ++ + static int test_get_user_friendly_alias() + { + const struct CMUnitTest tests[] = { +@@ -1743,6 +1788,7 @@ static int test_get_user_friendly_alias() + cmocka_unit_test_teardown(gufa_old_nomatch_wwidmatch, teardown_bindings), + cmocka_unit_test_teardown(gufa_old_nomatch_wwidmatch_used, teardown_bindings), + cmocka_unit_test_teardown(gufa_old_nomatch_nowwidmatch, teardown_bindings), ++ cmocka_unit_test(gufa_check_locking), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/0029-multipath-tools-Makefile-sanitize-paths-for-configur.patch b/0029-multipath-tools-Makefile-sanitize-paths-for-configur.patch new file mode 100644 index 0000000..26b79a8 --- /dev/null +++ b/0029-multipath-tools-Makefile-sanitize-paths-for-configur.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 22:13:51 +0200 +Subject: [PATCH] multipath-tools Makefile: sanitize paths for configuration + files + +Make the path to multipath.conf configurable, and use the same prefix +by default for multipath.conf and multipath/conf.d. For "usr-merged" +distributions with immutable /usr, we'll want to have the configuration +under a different prefix. This can be achieved by using e.g. + + make prefix=/usr etc_prefix="" + +Note that with prefix=/usr, before this patch the code would use +/usr/etc/multipath/conf.d, but /etc/multipath.conf. If this (rather +inconsistent) behavior is desired, use the following command line: + + make prefix=/usr configfile=/etc/multipath.conf + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + Makefile.inc | 9 ++++++--- + libmultipath/defaults.h | 1 - + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/Makefile.inc b/Makefile.inc +index 502cd0f1..39972d93 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -37,6 +37,8 @@ prefix := + exec_prefix := $(prefix) + # Prefix for non-essential libraries (libdmmp) + usr_prefix := $(prefix) ++# Prefix for configfuration files (multipath.conf) ++etc_prefix := $(prefix) + # Where to install systemd-related files. systemd is usually installed under /usr + # Note: some systemd installations use separate "prefix" and "rootprefix". + # In this case, override only unitdir to use systemd's "rootprefix" instead of $(systemd_prefix) +@@ -54,7 +56,8 @@ usrlibdir := $(usr_prefix)/$(LIB) + includedir := $(usr_prefix)/include + pkgconfdir := $(usrlibdir)/pkgconfig + plugindir := $(prefix)/$(LIB)/multipath +-configdir := $(prefix)/etc/multipath/conf.d ++configdir := $(etc_prefix)/etc/multipath/conf.d ++configfile := $(etc_prefix)/etc/multipath.conf + runtimedir := $(if $(shell test -L /var/run -o ! -d /var/run && echo 1),/run,/var/run) + devmapper_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir devmapper),/usr/include) + libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr/include) +@@ -84,8 +87,8 @@ WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implici + $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) + CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) \ + -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(plugindir)\" \ +- -DRUNTIME_DIR=\"$(runtimedir)\" \ +- -DCONFIG_DIR=\"$(configdir)\" -DEXTRAVERSION=\"$(EXTRAVERSION)\" -MMD -MP ++ -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(configdir)\" \ ++ -DDEFAULT_CONFIGFILE=\"$(configfile)\" -DEXTRAVERSION=\"$(EXTRAVERSION)\" -MMD -MP + CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe + BIN_CFLAGS := -fPIE -DPIE + LIB_CFLAGS := -fPIC +diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h +index b3f11d4c..bc2d6388 100644 +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -66,7 +66,6 @@ + #define MAX_DEV_LOSS_TMO UINT_MAX + #define DEFAULT_PIDFILE RUNTIME_DIR "/multipathd.pid" + #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" +-#define DEFAULT_CONFIGFILE "/etc/multipath.conf" + #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" + #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" + #define DEFAULT_PRKEYS_FILE "/etc/multipath/prkeys" diff --git a/0030-multipath-tools-add-compile-time-configuration-for-e.patch b/0030-multipath-tools-add-compile-time-configuration-for-e.patch new file mode 100644 index 0000000..afdf833 --- /dev/null +++ b/0030-multipath-tools-add-compile-time-configuration-for-e.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 22:26:22 +0200 +Subject: [PATCH] multipath-tools: add compile time configuration for + "/etc/multipath" + +Instead of hard-conding "/etc/multipath" as the path for the state +files "bindings", "prkeys", and "wwids", make this path configurable +via the "statedir" compile-time option. The default is currently still +/etc, it might change to /var/lib or similar in the future. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + Makefile.inc | 4 +++- + libmultipath/defaults.h | 6 +++--- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/Makefile.inc b/Makefile.inc +index 39972d93..96206b2f 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -58,6 +58,7 @@ pkgconfdir := $(usrlibdir)/pkgconfig + plugindir := $(prefix)/$(LIB)/multipath + configdir := $(etc_prefix)/etc/multipath/conf.d + configfile := $(etc_prefix)/etc/multipath.conf ++statedir := $(etc_prefix)/etc/multipath + runtimedir := $(if $(shell test -L /var/run -o ! -d /var/run && echo 1),/run,/var/run) + devmapper_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir devmapper),/usr/include) + libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr/include) +@@ -88,7 +89,8 @@ WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implici + CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) \ + -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(plugindir)\" \ + -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(configdir)\" \ +- -DDEFAULT_CONFIGFILE=\"$(configfile)\" -DEXTRAVERSION=\"$(EXTRAVERSION)\" -MMD -MP ++ -DDEFAULT_CONFIGFILE=\"$(configfile)\" -DSTATE_DIR=\"$(statedir)\" \ ++ -DEXTRAVERSION=\"$(EXTRAVERSION)\" -MMD -MP + CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe + BIN_CFLAGS := -fPIE -DPIE + LIB_CFLAGS := -fPIC +diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h +index bc2d6388..d01f9712 100644 +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -66,9 +66,9 @@ + #define MAX_DEV_LOSS_TMO UINT_MAX + #define DEFAULT_PIDFILE RUNTIME_DIR "/multipathd.pid" + #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" +-#define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" +-#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" +-#define DEFAULT_PRKEYS_FILE "/etc/multipath/prkeys" ++#define DEFAULT_BINDINGS_FILE STATE_DIR "/bindings" ++#define DEFAULT_WWIDS_FILE STATE_DIR "/wwids" ++#define DEFAULT_PRKEYS_FILE STATE_DIR "/prkeys" + #define MULTIPATH_SHM_BASE RUNTIME_DIR "/multipath/" + + diff --git a/0031-multipath-tools-man-pages-generate-with-correct-path.patch b/0031-multipath-tools-man-pages-generate-with-correct-path.patch new file mode 100644 index 0000000..65fc077 --- /dev/null +++ b/0031-multipath-tools-man-pages-generate-with-correct-path.patch @@ -0,0 +1,366 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Fri, 8 Sep 2023 22:48:16 +0200 +Subject: [PATCH] multipath-tools man pages: generate with correct paths + +Generate the man pages using the compile-time settings for paths +to multipath.conf etc. + +Add a paragraph about the CONFIGDIR (/etc/multipath/conf.d) +and the drop-in configuration files in the multipath.conf man page. + +Also, make sure all generated man pages and other files are correctly +removed by "make clean". + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + .gitignore | 4 +++ + Makefile.inc | 3 +++ + mpathpersist/Makefile | 5 ++-- + .../{mpathpersist.8 => mpathpersist.8.in} | 2 +- + multipath/Makefile | 13 +++++---- + multipath/{multipath.8 => multipath.8.in} | 10 +++---- + .../{multipath.conf.5 => multipath.conf.5.in} | 27 ++++++++++++------- + multipathd/Makefile | 9 ++++--- + multipathd/{multipathd.8 => multipathd.8.in} | 8 +++--- + 9 files changed, 49 insertions(+), 32 deletions(-) + rename mpathpersist/{mpathpersist.8 => mpathpersist.8.in} (99%) + rename multipath/{multipath.8 => multipath.8.in} (97%) + rename multipath/{multipath.conf.5 => multipath.conf.5.in} (98%) + rename multipathd/{multipathd.8 => multipathd.8.in} (97%) + +diff --git a/.gitignore b/.gitignore +index 535353e5..2986578f 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -13,11 +13,15 @@ cscope.files + cscope.out + kpartx/kpartx + multipath/multipath ++multipath/multipath.8 ++multipath/multipath.conf.5 + multipath/multipath.rules + multipath/tmpfiles.conf + multipathd/multipathd ++multipathd/multipathd.8 + multipathd/multipathc + mpathpersist/mpathpersist ++mpathpersist/mpathpersist.8 + abi.tar.gz + abi + abi-test +diff --git a/Makefile.inc b/Makefile.inc +index 96206b2f..79e521e1 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -133,3 +133,6 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version) + @grep -P '^[ \t]+[a-zA-Z_][a-zA-Z0-9_]*;' $< >>$@ + @printf 'local:\n\t*;\n};\n' >>$@ + ++%: %.in ++ @echo creating $@ ++ $(Q)sed 's:@CONFIGFILE@:'$(configfile)':g;s:@CONFIGDIR@:'$(configdir)':g;s:@STATE_DIR@:'$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g' $< >$@ +diff --git a/mpathpersist/Makefile b/mpathpersist/Makefile +index f57c105c..f3749467 100644 +--- a/mpathpersist/Makefile ++++ b/mpathpersist/Makefile +@@ -8,10 +8,11 @@ LIBDEPS += -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath \ + -L$(mpathutildir) -lmpathutil -L$(mpathcmddir) -lmpathcmd -lpthread -ldevmapper -ludev + + EXEC = mpathpersist ++MANPAGES := mpathpersist.8 + + OBJS = main.o + +-all: $(EXEC) ++all: $(EXEC) $(MANPAGES) + + $(EXEC): $(OBJS) + $(Q)$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) $(CFLAGS) $(LIBDEPS) +@@ -23,7 +24,7 @@ install: + $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/man8 + + clean: dep_clean +- $(Q)$(RM) core *.o $(EXEC) ++ $(Q)$(RM) core *.o $(EXEC) $(MANPAGES) + + include $(wildcard $(OBJS:.o=.d)) + +diff --git a/mpathpersist/mpathpersist.8 b/mpathpersist/mpathpersist.8.in +similarity index 99% +rename from mpathpersist/mpathpersist.8 +rename to mpathpersist/mpathpersist.8.in +index 8d26b37c..fecef0d6 100644 +--- a/mpathpersist/mpathpersist.8 ++++ b/mpathpersist/mpathpersist.8.in +@@ -31,7 +31,7 @@ mpathpersist \- Manages SCSI persistent reservations on dm multipath devices. + . + This utility is used to manage SCSI persistent reservations on Device Mapper + Multipath devices. To be able to use this functionality, the \fIreservation_key\fR +-attribute must be defined in the \fI/etc/multipath.conf\fR file. Otherwise the ++attribute must be defined in the \fI@CONFIGFILE@\fR file. Otherwise the + \fBmultipathd\fR daemon will not check for persistent reservation for newly + discovered paths or reinstated paths. + . +diff --git a/multipath/Makefile b/multipath/Makefile +index 73db991a..68cb5ce7 100644 +--- a/multipath/Makefile ++++ b/multipath/Makefile +@@ -3,7 +3,9 @@ + # + include ../Makefile.inc + +-EXEC := multipath ++EXEC := multipath ++MANPAGES := multipath.8 multipath.conf.5 ++GENERATED := $(MANPAGES) multipath.rules tmpfiles.conf + + CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathcmddir) + CFLAGS += $(BIN_CFLAGS) +@@ -13,7 +15,7 @@ LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathutildir) -lmpathutil \ + + OBJS := main.o + +-all: $(EXEC) multipath.rules tmpfiles.conf ++all: $(EXEC) $(GENERATED) + + $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so + @echo building $@ because of $? +@@ -47,15 +49,12 @@ uninstall: + $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules + $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 + $(Q)$(RM) $(DESTDIR)$(mandir)/man5/$(EXEC).conf.5 ++ $(Q)$(RM) $(DESTDIR)$(tmpfilesdir)/multipath.conf + + clean: dep_clean +- $(Q)$(RM) core *.o $(EXEC) multipath.rules tmpfiles.conf ++ $(Q)$(RM) core *.o $(EXEC) $(GENERATED) + + include $(wildcard $(OBJS:.o=.d)) + + dep_clean: + $(Q)$(RM) $(OBJS:.o=.d) +- +-%: %.in +- @echo creating $@ +- $(Q)sed 's,@RUNTIME_DIR@,$(runtimedir),' $< >$@ +diff --git a/multipath/multipath.8 b/multipath/multipath.8.in +similarity index 97% +rename from multipath/multipath.8 +rename to multipath/multipath.8.in +index 5fed6df7..348eb220 100644 +--- a/multipath/multipath.8 ++++ b/multipath/multipath.8.in +@@ -185,7 +185,7 @@ Display the currently used multipathd configuration. + .B \-T + Display the currently used multipathd configuration, limiting the output to + those devices actually present in the system. This can be used a template for +-creating \fImultipath.conf\fR. ++creating \fI@CONFIGFILE@\fR. + . + .\" ---------------------------------------------------------------------------- + .SH OPTIONS +@@ -233,11 +233,11 @@ option from \fBmultipath.conf(5)\fR. + .B \-i + Ignore WWIDs file when processing devices. If + \fIfind_multipaths strict\fR or \fIfind_multipaths no\fR is set in +-\fImultipath.conf\fR, multipath only considers devices that are ++\fI@CONFIGFILE@\fR, multipath only considers devices that are + listed in the WWIDs file. This option overrides that behavior. For other values + of \fIfind_multipaths\fR, this option has no effect. See the description of + \fIfind_multipaths\fR in +-.BR multipath.conf (5). ++.BR @CONFIGFILE@ (5). + This option should only be used in rare circumstances. + . + .TP +@@ -246,8 +246,8 @@ Treat the bindings file as read only. + . + .TP + .BI \-b " file" +-Set \fIuser_friendly_names\fR bindings file location. The default is +-\fI/etc/multipath/bindings\fR. ++(\fBdeprecated, do not use\fR) Set \fIuser_friendly_names\fR bindings file location. The default is ++\fI@STATE_DIR@/bindings\fR. + . + .TP + .B \-q +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5.in +similarity index 98% +rename from multipath/multipath.conf.5 +rename to multipath/multipath.conf.5.in +index 93af17db..20df2232 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5.in +@@ -13,14 +13,14 @@ + .SH NAME + .\" ---------------------------------------------------------------------------- + . +-multipath.conf \- multipath daemon configuration file. ++@CONFIGFILE@, @CONFIGDIR@/*.conf \- multipath daemon configuration file. + . + . + .\" ---------------------------------------------------------------------------- + .SH DESCRIPTION + .\" ---------------------------------------------------------------------------- + . +-.B "/etc/multipath.conf" ++.B "@CONFIGFILE@" + is the configuration file for the multipath daemon. It is used to + overwrite the built-in configuration table of \fBmultipathd\fP. + Any line whose first non-white-space character is a '#' is considered +@@ -29,6 +29,15 @@ a comment line. Empty lines are ignored. + Currently used multipathd configuration can be displayed with the \fBmultipath -t\fR + or \fBmultipathd show config\fR command. + . ++.PP ++Additional configuration can be made in drop-in files under ++.B @CONFIGDIR@. ++Files ending in \fI.conf\fR in this directory are read ++in alphabetical order, after reading \fI@CONFIGFILE@\fR. ++They use the same syntax as \fI@CONFIGFILE@\fR itself, ++and support all sections and keywords. If a keyword occurs in the same section ++in multiple files, the last occurence will take precedence over all others. ++. + . + .\" ---------------------------------------------------------------------------- + .SH SYNTAX +@@ -85,7 +94,7 @@ not mandatory. + . + .LP + .B Note on regular expressions: +-The \fImultipath.conf\fR syntax allows many attribute values to be specified as POSIX ++The \fI@CONFIGFILE@\fR syntax allows many attribute values to be specified as POSIX + Extended Regular Expressions (see \fBregex\fR(7)). These regular expressions + are \fBcase sensitive\fR and \fBnot anchored\fR, thus the expression "bar" matches "barbie", + "rhabarber", and "wunderbar", but not "Barbie". To avoid unwanted substring +@@ -711,7 +720,7 @@ The default is: \fBno\fR + .B user_friendly_names + If set to + .I yes +-, using the bindings file \fI/etc/multipath/bindings\fR to assign a persistent ++, using the bindings file \fI@STATE_DIR@/bindings\fR to assign a persistent + and unique alias to the multipath, in the form of mpath. If set to + .I no + use the WWID as the alias. In either case this be will +@@ -790,7 +799,7 @@ The full pathname of the binding file to be used when the user_friendly_names + option is set. + .RS + .TP +-The default is: \fB/etc/multipath/bindings\fR ++The default is: \fB@STATE_DIR@/bindings\fR + .RE + . + . +@@ -801,7 +810,7 @@ The full pathname of the WWIDs file, which is used by multipath to keep track + of the WWIDs for LUNs it has created multipath devices on in the past. + .RS + .TP +-The default is: \fB/etc/multipath/wwids\fR ++The default is: \fB@STATE_DIR@/wwids\fR + .RE + . + . +@@ -813,7 +822,7 @@ track of the persistent reservation key used for a specific WWID, when + \fIreservation_key\fR is set to \fBfile\fR. + .RS + .TP +-The default is: \fB/etc/multipath/prkeys\fR ++The default is: \fB@STATE_DIR@/prkeys\fR + .RE + . + . +@@ -872,7 +881,7 @@ The default is: \fBno\fR + .I yes + and the SCSI layer has already attached a hardware_handler to the device, + multipath will not force the device to use the hardware_handler specified by +-multipath.conf. If the SCSI layer has not attached a hardware handler, ++@CONFIGFILE@. If the SCSI layer has not attached a hardware handler, + multipath will continue to use its configured hardware handler. + .RS + .PP +@@ -1559,7 +1568,7 @@ given device, the attributes of all matching entries are applied to it. + If an attribute is specified in several matching device subsections, + later entries take precedence. Thus, entries in files under \fIconfig_dir\fR (in + reverse alphabetical order) have the highest precedence, followed by entries +-in \fImultipath.conf\fR; the built-in hardware table has the lowest ++in \fI@CONFIGFILE@\fR; the built-in hardware table has the lowest + precedence. Inside a configuration file, later entries have higher precedence + than earlier ones. + .LP +diff --git a/multipathd/Makefile b/multipathd/Makefile +index 0d0146c5..cdba3db1 100644 +--- a/multipathd/Makefile ++++ b/multipathd/Makefile +@@ -1,7 +1,8 @@ + include ../Makefile.inc + +-EXEC := multipathd +-CLI := multipathc ++EXEC := multipathd ++CLI := multipathc ++MANPAGES := multipathd.8 + + CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathpersistdir) -I$(mpathcmddir) -I$(thirdpartydir) \ + $(shell $(PKG_CONFIG) --modversion liburcu 2>/dev/null | \ +@@ -42,7 +43,7 @@ ifeq ($(FPIN_SUPPORT),1) + OBJS += fpin_handlers.o + endif + +-all : $(EXEC) $(CLI) ++all : $(EXEC) $(CLI) $(MANPAGES) + + $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so + @echo building $@ because of $? +@@ -79,7 +80,7 @@ uninstall: + $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket + + clean: dep_clean +- $(Q)$(RM) core *.o $(EXEC) $(CLI) ++ $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) + + include $(wildcard $(OBJS:.o=.d) $(CLI_OBJS:.o=.d)) + +diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8.in +similarity index 97% +rename from multipathd/multipathd.8 +rename to multipathd/multipathd.8.in +index cc72b775..e98c27fd 100644 +--- a/multipathd/multipathd.8 ++++ b/multipathd/multipathd.8.in +@@ -155,7 +155,7 @@ Show the format wildcards used in interactive commands taking $format. + .TP + .B list|show config + Show the currently used configuration, derived from default values and values +-specified within the configuration file \fI/etc/multipath.conf\fR. ++specified within the configuration file \fI@CONFIGFILE@\fR. + . + .TP + .B list|show config local +@@ -165,7 +165,7 @@ the devices section to those devices that are actually present in the system. + .TP + .B list|show blacklist + Show the currently used blacklist rules, derived from default values and values +-specified within the configuration file \fI/etc/multipath.conf\fR. ++specified within the configuration file \fI@CONFIGFILE@\fR. + . + .TP + .B list|show devices +@@ -290,13 +290,13 @@ Get the current persistent reservation key associated with $map. + .B map|multipath $map setprkey key $key + Set the persistent reservation key associated with $map to $key in the + \fIprkeys_file\fR. This key will only be used by multipathd if +-\fIreservation_key\fR is set to \fBfile\fR in \fI/etc/multipath.conf\fR. ++\fIreservation_key\fR is set to \fBfile\fR in \fI@CONFIGFILE@\fR. + . + .TP + .B map|multipath $map unsetprkey + Remove the persistent reservation key associated with $map from the + \fIprkeys_file\fR. This will only unset the key used by multipathd if +-\fIreservation_key\fR is set to \fBfile\fR in \fI/etc/multipath.conf\fR. ++\fIreservation_key\fR is set to \fBfile\fR in \fI@CONFIGFILE@\fR. + . + .TP + .B path $path setmarginal diff --git a/0032-libdmmp-Makefile-fix-bug-in-install-section.patch b/0032-libdmmp-Makefile-fix-bug-in-install-section.patch new file mode 100644 index 0000000..a3f2470 --- /dev/null +++ b/0032-libdmmp-Makefile-fix-bug-in-install-section.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 11 Sep 2023 09:30:13 +0200 +Subject: [PATCH] libdmmp/Makefile: fix bug in install section + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libdmmp/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libdmmp/Makefile b/libdmmp/Makefile +index 078eca8f..172ba045 100644 +--- a/libdmmp/Makefile ++++ b/libdmmp/Makefile +@@ -44,7 +44,7 @@ install: + $(DESTDIR)$(pkgconfdir)/$(PKGFILE) + $(Q)sed -i 's|__INCLUDEDIR__|$(includedir)|g' \ + $(DESTDIR)$(pkgconfdir)/$(PKGFILE) +- $(Q)$(INSTALL_PROGRAM) -d 755 $(DESTDIR)$(mandir)/man3 ++ $(Q)$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(mandir)/man3 + $(Q)$(INSTALL_PROGRAM) -m 644 -t $(DESTDIR)$(mandir)/man3 docs/man/*.3 + + uninstall: diff --git a/0033-multipath-tools-README.md-improve-documentation-for-.patch b/0033-multipath-tools-README.md-improve-documentation-for-.patch new file mode 100644 index 0000000..3c7edd0 --- /dev/null +++ b/0033-multipath-tools-README.md-improve-documentation-for-.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 11 Sep 2023 10:22:13 +0200 +Subject: [PATCH] multipath-tools: README.md: improve documentation for + compile-time options + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + README.md | 38 ++++++++++++++++++++++++++------------ + 1 file changed, 26 insertions(+), 12 deletions(-) + +diff --git a/README.md b/README.md +index a7f994ae..679e55bf 100644 +--- a/README.md ++++ b/README.md +@@ -89,9 +89,17 @@ The following variables can be passed to the `make` command line: + * `plugindir="/some/path"`: directory where libmultipath plugins (path + checkers, prioritizers, and foreign multipath support) will be looked up. + This used to be the run-time option `multipath_dir` in earlier versions. +- * `configdir="/some/path"` : directory to search for configuration files. ++ The default is `$(prefix)/$(LIB)/multipath`, where `$(LIB)` is `lib64` on ++ systems that have `/lib64`, and `lib` otherwise. ++ * `configfile="/some/path`": The path to the main configuration file. ++ The defalt is `$(etc_prefix)/etc/multipath.conf`. ++ * `configdir="/some/path"` : directory to search for additional configuration files. + This used to be the run-time option `config_dir` in earlier versions. +- The default is `/etc/multipath/conf.d`. ++ The default is `$(etc_prefix)/etc/multipath/conf.d`. ++ * `statedir="/some/path"`: The path of the directory where multipath-tools ++ stores run-time settings that need persist between reboots, such as known ++ WWIDs, user-friendly names, and persistent reservation keys. ++ The default is `$(etc_prefix)/etc/multipath`. + * `READLINE=libedit` or `READLINE=libreadline`: enable command line history + and TAB completion in the interactive mode *(which is entered with `multipathd -k` or `multipathc`)*. + The respective development package will be required for building. +@@ -119,21 +127,27 @@ The following variables can be passed to the `make` command line: + ### Installation Paths + + * `prefix`: The directory prefix for (almost) all files to be installed. +- Distributions may want to set this to `/usr`. +- **Note**: for multipath-tools, unlike many other packages, `prefix` +- defaults to the empty string, which resolves to the root directory (`/`). ++ "Usr-merged" distributions[^systemd] may want to set this to `/usr`. The ++ default is empty (`""`). + * `usr_prefix`: where to install those parts of the code that aren't necessary +- for booting. You may want to set this to `/usr` if `prefix` is empty. +- * `systemd_prefix`: Prefix for systemd-related files. It defaults to `/usr`. +- Some systemd installations use separate `prefix` and `rootprefix`. On such +- a distribution, set `prefix`, and override `unitdir` to use systemd's +- `rootprefix`. ++ for booting. Non-usr-merged distributions[^systemd] may want to set this to ++ `/usr`. The default is `$(prefix)`. ++ * `systemd_prefix`: Prefix for systemd-related files[^systemd]. The default is `/usr`. ++ * `etc_prefix`: The prefix for configuration files. "Usr-merged" ++ distributions with immutable `/usr`[^systemd] may want to set this to ++ `/etc`. The default is `$(prefix)`. + * `LIB`: the subdirectory under `prefix` where shared libraries will be + installed. By default, the makefile uses `/lib64` if this directory is + found on the build system, and `/lib` otherwise. + +-See also `configdir` and `plugindir` above. See `Makefile.inc` for more +-fine-grained control. ++The options `configdir`, `plugindir`, `configfile`, and `statedir` above can ++be used for setting indvidual paths where the `prefix` variables don't provide ++sufficient control. See `Makefile.inc` for even more fine-grained control. ++ ++[^systemd]: Some systemd installations use separate `prefix` and `rootprefix`. ++ On such a distribution, set `prefix`, and override `unitdir` to use systemd's ++ `rootprefix`. Recent systemd releases generally require everything to be ++ installed under `/usr` (so-called "usr-merged" distribution). On "usr- + + ### Compiler Options + diff --git a/0034-libmultipath-print-built-in-values-for-deprecated-op.patch b/0034-libmultipath-print-built-in-values-for-deprecated-op.patch new file mode 100644 index 0000000..45e7874 --- /dev/null +++ b/0034-libmultipath-print-built-in-values-for-deprecated-op.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 11 Sep 2023 11:36:25 +0200 +Subject: [PATCH] libmultipath: print built-in values for deprecated options + +In the error messages we print when a deprecated option is encountered, +print the compile-time value of the option. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/dict.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index f81c84aa..dace343d 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -314,14 +314,16 @@ def_ ## option ## _handler (struct config *conf, vector strvec, \ + static int deprecated_handler(struct config *conf, vector strvec, const char *file, + int line_nr); + +-#define declare_deprecated_handler(option) \ ++#define declare_deprecated_handler(option, default) \ + static int \ + deprecated_ ## option ## _handler (struct config *conf, vector strvec, \ + const char *file, int line_nr) \ + { \ + static bool warned; \ + if (!warned) { \ +- condlog(1, "%s line %d: ignoring deprecated option \"" #option "\"", file, line_nr); \ ++ condlog(1, "%s line %d: ignoring deprecated option \"" \ ++ #option "\", using built-in value: \"%s\"", \ ++ file, line_nr, default); \ + warned = true; \ + } \ + return deprecated_handler(conf, strvec, file, line_nr); \ +@@ -2057,11 +2059,11 @@ snprint_deprecated (struct config *conf, struct strbuf *buff, const void * data) + } + + // Deprecated keywords +-declare_deprecated_handler(config_dir) +-declare_deprecated_handler(disable_changed_wwids) +-declare_deprecated_handler(getuid_callout) +-declare_deprecated_handler(multipath_dir) +-declare_deprecated_handler(pg_timeout) ++declare_deprecated_handler(config_dir, CONFIG_DIR) ++declare_deprecated_handler(disable_changed_wwids, "yes") ++declare_deprecated_handler(getuid_callout, "(not set)") ++declare_deprecated_handler(multipath_dir, MULTIPATH_DIR) ++declare_deprecated_handler(pg_timeout, "(not set)") + + /* + * If you add or remove a keyword also update multipath/multipath.conf.5 diff --git a/0035-multipath-add-a-missing-newline.patch b/0035-multipath-add-a-missing-newline.patch new file mode 100644 index 0000000..706b7d3 --- /dev/null +++ b/0035-multipath-add-a-missing-newline.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 11 Sep 2023 11:37:37 +0200 +Subject: [PATCH] multipath: add a missing newline + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + multipath/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/multipath/main.c b/multipath/main.c +index 45e9745f..b91289e8 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -1025,7 +1025,7 @@ main (int argc, char *argv[]) + } + + if (check_alias_settings(conf)) { +- fprintf(stderr, "fatal configuration error, aborting"); ++ fprintf(stderr, "fatal configuration error, aborting\n"); + exit(RTVL_FAIL); + } + diff --git a/0036-multipath-tools-allow-prefixes-with-and-w-o-trailing.patch b/0036-multipath-tools-allow-prefixes-with-and-w-o-trailing.patch new file mode 100644 index 0000000..c48240b --- /dev/null +++ b/0036-multipath-tools-allow-prefixes-with-and-w-o-trailing.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 11 Sep 2023 16:03:34 +0200 +Subject: [PATCH] multipath-tools: allow prefixes with and w/o trailing slash + +Add some logic to Makefile.inc that leads to the same result +for "prefix=" and "prefix=/", or "prefix=/usr" and "prefix=/usr/". +The logic does not work for multiple trailing slashes. It applies +to all XYZ_prefix variables in Makefile.inc. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + Makefile.inc | 35 ++++++++++++++++++++++------------- + 1 file changed, 22 insertions(+), 13 deletions(-) + +diff --git a/Makefile.inc b/Makefile.inc +index 79e521e1..6e384e68 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -43,22 +43,31 @@ etc_prefix := $(prefix) + # Note: some systemd installations use separate "prefix" and "rootprefix". + # In this case, override only unitdir to use systemd's "rootprefix" instead of $(systemd_prefix) + systemd_prefix := /usr +-unitdir := $(systemd_prefix)/lib/systemd/system +-tmpfilesdir := $(systemd_prefix)/lib/tmpfiles.d +-modulesloaddir := $(systemd_prefix)/lib/modules-load.d +-libudevdir := $(systemd_prefix)/lib/udev ++ ++# Make sure all prefix variables end in "/" ++append-slash = $(1)$(if $(filter %/,$(1)),,/) ++override prefix := $(call append-slash,$(prefix)) ++override exec_prefix := $(call append-slash,$(exec_prefix)) ++override usr_prefix := $(call append-slash,$(usr_prefix)) ++override etc_prefix := $(call append-slash,$(etc_prefix)) ++override systemd_prefix := $(call append-slash,$(systemd_prefix)) ++ ++unitdir := $(systemd_prefix)lib/systemd/system ++tmpfilesdir := $(systemd_prefix)lib/tmpfiles.d ++modulesloaddir := $(systemd_prefix)lib/modules-load.d ++libudevdir := $(systemd_prefix)lib/udev + udevrulesdir := $(libudevdir)/rules.d +-bindir := $(exec_prefix)/sbin +-mandir := $(usr_prefix)/share/man ++bindir := $(exec_prefix)sbin ++mandir := $(usr_prefix)share/man + LIB := $(if $(shell test -d /lib64 && echo 1),lib64,lib) +-syslibdir := $(prefix)/$(LIB) +-usrlibdir := $(usr_prefix)/$(LIB) +-includedir := $(usr_prefix)/include ++syslibdir := $(prefix)$(LIB) ++usrlibdir := $(usr_prefix)$(LIB) ++includedir := $(usr_prefix)include + pkgconfdir := $(usrlibdir)/pkgconfig +-plugindir := $(prefix)/$(LIB)/multipath +-configdir := $(etc_prefix)/etc/multipath/conf.d +-configfile := $(etc_prefix)/etc/multipath.conf +-statedir := $(etc_prefix)/etc/multipath ++plugindir := $(prefix)$(LIB)/multipath ++configdir := $(etc_prefix)etc/multipath/conf.d ++configfile := $(etc_prefix)etc/multipath.conf ++statedir := $(etc_prefix)etc/multipath + runtimedir := $(if $(shell test -L /var/run -o ! -d /var/run && echo 1),/run,/var/run) + devmapper_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir devmapper),/usr/include) + libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr/include) diff --git a/0037-libmultipath-deprecate-bindings_file-wwids_file-prke.patch b/0037-libmultipath-deprecate-bindings_file-wwids_file-prke.patch new file mode 100644 index 0000000..6e066ee --- /dev/null +++ b/0037-libmultipath-deprecate-bindings_file-wwids_file-prke.patch @@ -0,0 +1,897 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Mon, 11 Sep 2023 17:58:13 +0200 +Subject: [PATCH] libmultipath: deprecate bindings_file, wwids_file, + prkeys_file + +The options bindings_file, wwids_file, and prkeys_file have been +deprecated since cb4d6db ("libmultipath: deprecate file and directory config +options") (multipath-tools 0.8.8). Deprecate and ignore them now. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 43 +++++++++---------- + libmultipath/alias.h | 3 +- + libmultipath/config.c | 18 -------- + libmultipath/config.h | 3 -- + libmultipath/dict.c | 39 +++--------------- + libmultipath/libmultipath.version | 8 +--- + libmultipath/prkey.c | 7 ++-- + libmultipath/prkey.h | 7 ++-- + libmultipath/propsel.c | 5 +-- + libmultipath/wwids.c | 18 ++------ + multipath/main.c | 2 +- + multipath/multipath.conf.5.in | 23 +++++------ + multipathd/uxlsnr.c | 17 +++----- + tests/alias.c | 68 +++++++++++++++---------------- + 14 files changed, 90 insertions(+), 171 deletions(-) + +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index 964b8a7b..e5d3f151 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -55,6 +55,8 @@ + /* uatomic access only */ + static int bindings_file_changed = 1; + ++static const char bindings_file_path[] = DEFAULT_BINDINGS_FILE; ++ + static pthread_mutex_t timestamp_mutex = PTHREAD_MUTEX_INITIALIZER; + static struct timespec bindings_last_updated; + +@@ -274,7 +276,6 @@ static int write_bindings_file(const Bindings *bindings, int fd, + + void handle_bindings_file_inotify(const struct inotify_event *event) + { +- struct config *conf; + const char *base; + bool changed = false; + struct stat st; +@@ -284,12 +285,9 @@ void handle_bindings_file_inotify(const struct inotify_event *event) + if (!(event->mask & IN_MOVED_TO)) + return; + +- conf = get_multipath_config(); +- base = strrchr(conf->bindings_file, '/'); +- changed = base && base > conf->bindings_file && +- !strcmp(base + 1, event->name); +- ret = stat(conf->bindings_file, &st); +- put_multipath_config(conf); ++ base = strrchr(bindings_file_path, '/'); ++ changed = base && !strcmp(base + 1, event->name); ++ ret = stat(bindings_file_path, &st); + + if (!changed) + return; +@@ -310,8 +308,7 @@ void handle_bindings_file_inotify(const struct inotify_event *event) + __func__, (long)ts.tv_sec, (long)ts.tv_nsec / 1000); + } + +-static int update_bindings_file(const Bindings *bindings, +- const char *bindings_file) ++static int update_bindings_file(const Bindings *bindings) + { + int rc; + int fd = -1; +@@ -319,7 +316,7 @@ static int update_bindings_file(const Bindings *bindings, + mode_t old_umask; + struct timespec ts; + +- if (safe_sprintf(tempname, "%s.XXXXXX", bindings_file)) ++ if (safe_sprintf(tempname, "%s.XXXXXX", bindings_file_path)) + return -1; + /* coverity: SECURE_TEMP */ + old_umask = umask(0077); +@@ -336,13 +333,13 @@ static int update_bindings_file(const Bindings *bindings, + unlink(tempname); + return rc; + } +- if ((rc = rename(tempname, bindings_file)) == -1) ++ if ((rc = rename(tempname, bindings_file_path)) == -1) + condlog(0, "%s: rename: %m", __func__); + else { + pthread_mutex_lock(×tamp_mutex); + bindings_last_updated = ts; + pthread_mutex_unlock(×tamp_mutex); +- condlog(1, "updated bindings file %s", bindings_file); ++ condlog(1, "updated bindings file %s", bindings_file_path); + } + return rc; + } +@@ -474,7 +471,7 @@ int get_free_id(const Bindings *bindings, const char *prefix, const char *map_ww + + /* Called with binding_mutex held */ + static char * +-allocate_binding(const char *filename, const char *wwid, int id, const char *prefix) ++allocate_binding(const char *wwid, int id, const char *prefix) + { + STRBUF_ON_STACK(buf); + char *alias; +@@ -498,7 +495,7 @@ allocate_binding(const char *filename, const char *wwid, int id, const char *pre + return NULL; + } + +- if (update_bindings_file(&global_bindings, filename) == -1) { ++ if (update_bindings_file(&global_bindings) == -1) { + condlog(1, "%s: deleting binding %s for %s", __func__, alias, wwid); + delete_binding(&global_bindings, wwid); + free(alias); +@@ -565,7 +562,7 @@ static void read_bindings_file(void) + * that the mpvec corrcectly represents kernel state. + */ + +-char *get_user_friendly_alias(const char *wwid, const char *file, const char *alias_old, ++char *get_user_friendly_alias(const char *wwid, const char *alias_old, + const char *prefix, bool bindings_read_only) + { + char *alias = NULL; +@@ -622,7 +619,7 @@ new_alias: + } + + if (!bindings_read_only && id > 0) +- alias = allocate_binding(file, wwid, id, prefix); ++ alias = allocate_binding(wwid, id, prefix); + + if (alias && !new_binding) + condlog(2, "Allocated existing binding [%s] for WWID [%s]", +@@ -715,12 +712,12 @@ static int _check_bindings_file(const struct config *conf, FILE *file, + header[sizeof(BINDINGS_FILE_HEADER) - 1] = '\0'; + if (fread(header, sizeof(BINDINGS_FILE_HEADER) - 1, 1, file) < 1) { + condlog(2, "%s: failed to read header from %s", __func__, +- conf->bindings_file); ++ bindings_file_path); + fseek(file, 0, SEEK_SET); + rc = -1; + } else if (strcmp(header, BINDINGS_FILE_HEADER)) { + condlog(2, "%s: invalid header in %s", __func__, +- conf->bindings_file); ++ bindings_file_path); + fseek(file, 0, SEEK_SET); + rc = -1; + } +@@ -787,13 +784,13 @@ static int _read_bindings_file(const struct config *conf, Bindings *bindings, + } + } + +- fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER); ++ fd = open_file(bindings_file_path, &can_write, BINDINGS_FILE_HEADER); + if (fd == -1) + return BINDINGS_FILE_ERROR; + + file = fdopen(fd, "r"); + if (file != NULL) { +- condlog(3, "%s: reading %s", __func__, conf->bindings_file); ++ condlog(3, "%s: reading %s", __func__, bindings_file_path); + + pthread_cleanup_push(cleanup_fclose, file); + ret = _check_bindings_file(conf, file, bindings); +@@ -812,20 +809,20 @@ static int _read_bindings_file(const struct config *conf, Bindings *bindings, + bindings_last_updated = ts; + pthread_mutex_unlock(×tamp_mutex); + } else if (ret == -1 && can_write && !conf->bindings_read_only) { +- ret = update_bindings_file(bindings, conf->bindings_file); ++ ret = update_bindings_file(bindings); + if (ret == 0) + rc = BINDINGS_FILE_READ; + else + rc = BINDINGS_FILE_BAD; + } else { + condlog(0, "ERROR: bad settings in read-only bindings file %s", +- conf->bindings_file); ++ bindings_file_path); + rc = BINDINGS_FILE_BAD; + } + pthread_cleanup_pop(1); + } else { + condlog(1, "failed to fdopen %s: %m", +- conf->bindings_file); ++ bindings_file_path); + close(fd); + rc = BINDINGS_FILE_ERROR; + } +diff --git a/libmultipath/alias.h b/libmultipath/alias.h +index ca8911f4..629e8d56 100644 +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -3,8 +3,7 @@ + + int valid_alias(const char *alias); + int get_user_friendly_wwid(const char *alias, char *buff); +-char *get_user_friendly_alias(const char *wwid, const char *file, +- const char *alias_old, ++char *get_user_friendly_alias(const char *wwid, const char *alias_old, + const char *prefix, bool bindings_read_only); + + struct config; +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 7b207590..b7dbc6f5 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -752,15 +752,6 @@ static void _uninit_config(struct config *conf) + if (conf->hwhandler) + free(conf->hwhandler); + +- if (conf->bindings_file) +- free(conf->bindings_file); +- +- if (conf->wwids_file) +- free(conf->wwids_file); +- +- if (conf->prkeys_file) +- free(conf->prkeys_file); +- + if (conf->prio_name) + free(conf->prio_name); + +@@ -922,9 +913,6 @@ int _init_config (const char *file, struct config *conf) + * 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); +- conf->prkeys_file = set_default(DEFAULT_PRKEYS_FILE); + conf->attribute_flags = 0; + conf->reassign_maps = DEFAULT_REASSIGN_MAPS; + conf->checkint = CHECKINT_UNDEF; +@@ -1078,12 +1066,6 @@ int _init_config (const char *file, struct config *conf) + merge_blacklist(conf->elist_wwid); + merge_blacklist_device(conf->elist_device); + +- if (conf->bindings_file == NULL) +- conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE); +- +- if (!conf->bindings_file || !conf->wwids_file || !conf->prkeys_file) +- goto out; +- + libmp_verbosity = conf->verbosity; + return 0; + out: +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 0a2c297b..8c22ce75 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -207,9 +207,6 @@ struct config { + char * uid_attribute; + char * features; + char * hwhandler; +- char * bindings_file; +- char * wwids_file; +- char * prkeys_file; + char * prio_name; + char * prio_args; + char * checker_name; +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index dace343d..044067af 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -168,27 +168,6 @@ fail: + return 0; + } + +-static int +-set_path(vector strvec, void *ptr, const char *file, int line_nr) +-{ +- char **str_ptr = (char **)ptr; +- char *old_str = *str_ptr; +- +- *str_ptr = set_value(strvec); +- if (!*str_ptr) { +- free(old_str); +- return 1; +- } +- if ((*str_ptr)[0] != '/'){ +- condlog(1, "%s line %d, %s is not an absolute path. Ignoring", +- file, line_nr, *str_ptr); +- free(*str_ptr); +- *str_ptr = old_str; +- } else +- free(old_str); +- return 0; +-} +- + static int + set_str_noslash(vector strvec, void *ptr, const char *file, int line_nr) + { +@@ -831,15 +810,6 @@ declare_hw_snprint(user_friendly_names, print_yes_no_undef) + declare_mp_handler(user_friendly_names, set_yes_no_undef) + declare_mp_snprint(user_friendly_names, print_yes_no_undef) + +-declare_def_warn_handler(bindings_file, set_path) +-declare_def_snprint(bindings_file, print_str) +- +-declare_def_warn_handler(wwids_file, set_path) +-declare_def_snprint(wwids_file, print_str) +- +-declare_def_warn_handler(prkeys_file, set_path) +-declare_def_snprint(prkeys_file, print_str) +- + declare_def_handler(retain_hwhandler, set_yes_no_undef) + declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef, + DEFAULT_RETAIN_HWHANDLER) +@@ -2064,6 +2034,9 @@ declare_deprecated_handler(disable_changed_wwids, "yes") + declare_deprecated_handler(getuid_callout, "(not set)") + declare_deprecated_handler(multipath_dir, MULTIPATH_DIR) + declare_deprecated_handler(pg_timeout, "(not set)") ++declare_deprecated_handler(bindings_file, DEFAULT_BINDINGS_FILE) ++declare_deprecated_handler(wwids_file, DEFAULT_WWIDS_FILE) ++declare_deprecated_handler(prkeys_file, DEFAULT_PRKEYS_FILE) + + /* + * If you add or remove a keyword also update multipath/multipath.conf.5 +@@ -2106,9 +2079,9 @@ init_keywords(vector keywords) + 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); ++ install_keyword("bindings_file", &deprecated_bindings_file_handler, &snprint_deprecated); ++ install_keyword("wwids_file", &deprecated_wwids_file_handler, &snprint_deprecated); ++ install_keyword("prkeys_file", &deprecated_prkeys_file_handler, &snprint_deprecated); + install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err); + install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key); + install_keyword("all_tg_pt", &def_all_tg_pt_handler, &snprint_def_all_tg_pt); +diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version +index 57e50c12..8368ef7a 100644 +--- a/libmultipath/libmultipath.version ++++ b/libmultipath/libmultipath.version +@@ -43,7 +43,7 @@ LIBMPATHCOMMON_1.0.0 { + put_multipath_config; + }; + +-LIBMULTIPATH_20.0.0 { ++LIBMULTIPATH_21.0.0 { + global: + /* symbols referenced by multipath and multipathd */ + add_foreign; +@@ -121,6 +121,7 @@ global: + get_used_hwes; + get_vpd_sgio; + group_by_prio; ++ handle_bindings_file_inotify; + has_dm_info; + init_checkers; + init_config; +@@ -238,8 +239,3 @@ global: + local: + *; + }; +- +-LIBMULTIPATH_20.1.0 { +-global: +- handle_bindings_file_inotify; +-}; +diff --git a/libmultipath/prkey.c b/libmultipath/prkey.c +index a215499d..c66d293b 100644 +--- a/libmultipath/prkey.c ++++ b/libmultipath/prkey.c +@@ -157,8 +157,7 @@ static int do_prkey(int fd, char *wwid, char *keystr, int cmd) + return 0; + } + +-int get_prkey(struct config *conf, struct multipath *mpp, uint64_t *prkey, +- uint8_t *sa_flags) ++int get_prkey(struct multipath *mpp, uint64_t *prkey, uint8_t *sa_flags) + { + int fd; + int unused; +@@ -168,7 +167,7 @@ int get_prkey(struct config *conf, struct multipath *mpp, uint64_t *prkey, + if (!strlen(mpp->wwid)) + goto out; + +- fd = open_file(conf->prkeys_file, &unused, PRKEYS_FILE_HEADER); ++ fd = open_file(DEFAULT_PRKEYS_FILE, &unused, PRKEYS_FILE_HEADER); + if (fd < 0) + goto out; + ret = do_prkey(fd, mpp->wwid, keystr, PRKEY_READ); +@@ -201,7 +200,7 @@ int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey, + sa_flags &= MPATH_F_APTPL_MASK; + } + +- fd = open_file(conf->prkeys_file, &can_write, PRKEYS_FILE_HEADER); ++ fd = open_file(DEFAULT_PRKEYS_FILE, &can_write, PRKEYS_FILE_HEADER); + if (fd < 0) + goto out; + if (!can_write) { +diff --git a/libmultipath/prkey.h b/libmultipath/prkey.h +index a16de106..43afd5e4 100644 +--- a/libmultipath/prkey.h ++++ b/libmultipath/prkey.h +@@ -16,9 +16,8 @@ + int print_reservation_key(struct strbuf *buff, + struct be64 key, uint8_t flags, int source); + int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags); +-int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey, +- uint8_t sa_flags); +-int get_prkey(struct config *conf, struct multipath *mpp, uint64_t *prkey, +- uint8_t *sa_flags); ++int set_prkey(struct config *conf, struct multipath *mpp, ++ uint64_t prkey, uint8_t sa_flags); ++int get_prkey(struct multipath *mpp, uint64_t *prkey, uint8_t *sa_flags); + + #endif /* _PRKEY_H */ +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 354e883f..44241e2a 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -401,8 +401,7 @@ int select_alias(struct config *conf, struct multipath * mp) + + select_alias_prefix(conf, mp); + +- mp->alias = get_user_friendly_alias(mp->wwid, conf->bindings_file, +- mp->alias_old, mp->alias_prefix, ++ mp->alias = get_user_friendly_alias(mp->wwid, mp->alias_old, mp->alias_prefix, + conf->bindings_read_only); + + if (mp->alias && !strncmp(mp->alias, mp->alias_old, WWID_SIZE)) +@@ -992,7 +991,7 @@ int select_reservation_key(struct config *conf, struct multipath *mp) + out: + if (mp->prkey_source == PRKEY_SOURCE_FILE) { + from_file = " (from prkeys file)"; +- if (get_prkey(conf, mp, &prkey, &mp->sa_flags) != 0) ++ if (get_prkey(mp, &prkey, &mp->sa_flags) != 0) + put_be64(mp->reservation_key, 0); + else + put_be64(mp->reservation_key, prkey); +diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c +index 89bb60ca..591cd09b 100644 +--- a/libmultipath/wwids.c ++++ b/libmultipath/wwids.c +@@ -94,12 +94,8 @@ replace_wwids(vector mp) + struct multipath * mpp; + size_t len; + int ret = -1; +- struct config *conf; + +- conf = get_multipath_config(); +- pthread_cleanup_push(put_multipath_config, conf); +- fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); +- pthread_cleanup_pop(1); ++ fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER); + if (fd < 0) + goto out; + +@@ -200,7 +196,6 @@ remove_wwid(char *wwid) { + int len, can_write; + char *str; + int ret = -1; +- struct config *conf; + + len = strlen(wwid) + 4; /* two slashes the newline and a zero byte */ + str = malloc(len); +@@ -216,10 +211,7 @@ remove_wwid(char *wwid) { + goto out; + } + condlog(3, "removing line '%s' from wwids file", str); +- conf = get_multipath_config(); +- pthread_cleanup_push(put_multipath_config, conf); +- fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); +- pthread_cleanup_pop(1); ++ fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER); + + if (fd < 0) { + ret = -1; +@@ -244,12 +236,8 @@ check_wwids_file(char *wwid, int write_wwid) + { + int fd, can_write, found, ret; + FILE *f; +- struct config *conf; + +- conf = get_multipath_config(); +- pthread_cleanup_push(put_multipath_config, conf); +- fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); +- pthread_cleanup_pop(1); ++ fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER); + if (fd < 0) + return -1; + +diff --git a/multipath/main.c b/multipath/main.c +index b91289e8..9e1c5052 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -856,7 +856,7 @@ main (int argc, char *argv[]) + libmp_verbosity = atoi(optarg); + break; + case 'b': +- conf->bindings_file = strdup(optarg); ++ condlog(1, "option -b ignored"); + break; + case 'B': + conf->bindings_read_only = 1; +diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in +index 20df2232..d320a88f 100644 +--- a/multipath/multipath.conf.5.in ++++ b/multipath/multipath.conf.5.in +@@ -794,35 +794,28 @@ The default is: \fB\fR + . + .TP + .B bindings_file +-(Deprecated) This option is deprecated, and will be removed in a future release. +-The full pathname of the binding file to be used when the user_friendly_names +-option is set. ++(Deprecated) This option is not supported any more, and will be ignored. + .RS + .TP +-The default is: \fB@STATE_DIR@/bindings\fR ++The compiled-in value is: \fB@STATE_DIR@/bindings\fR + .RE + . + . + .TP + .B wwids_file +-(Deprecated) This option is deprecated, and will be removed in a future release. +-The full pathname of the WWIDs file, which is used by multipath to keep track +-of the WWIDs for LUNs it has created multipath devices on in the past. ++(Deprecated) This option is not supported any more, and will be ignored. + .RS + .TP +-The default is: \fB@STATE_DIR@/wwids\fR ++The compiled-in value is: \fB@STATE_DIR@/wwids\fR + .RE + . + . + .TP + .B prkeys_file +-(Deprecated) This option is deprecated, and will be removed in a future release. +-The full pathname of the prkeys file, which is used by multipathd to keep +-track of the persistent reservation key used for a specific WWID, when +-\fIreservation_key\fR is set to \fBfile\fR. ++(Deprecated) This option is not supported any more, and will be ignored. + .RS + .TP +-The default is: \fB@STATE_DIR@/prkeys\fR ++The compiled-in value is: \fB@STATE_DIR@/prkeys\fR + .RE + . + . +@@ -989,6 +982,10 @@ The default is: \fB\fR + .TP + .B config_dir + (Deprecated) This option is not supported any more, and the value is ignored. ++.RS ++.TP ++The compiled-in value is: \fB@CONFIGDIR@\fR ++.RE + . + . + .TP +diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c +index d1f8f234..4d6f258c 100644 +--- a/multipathd/uxlsnr.c ++++ b/multipathd/uxlsnr.c +@@ -203,7 +203,6 @@ static void reset_watch(int notify_fd, struct watch_descriptors *wds, + int dir_reset = 0; + int conf_reset = 0; + int mp_reset = 0; +- char *bindings_file __attribute__((cleanup(cleanup_charp))) = NULL; + + if (notify_fd == -1) + return; +@@ -221,7 +220,6 @@ static void reset_watch(int notify_fd, struct watch_descriptors *wds, + if (wds->mp_wd == -1) + mp_reset = 1; + } +- bindings_file = strdup(conf->bindings_file); + put_multipath_config(conf); + + if (dir_reset) { +@@ -242,17 +240,12 @@ static void reset_watch(int notify_fd, struct watch_descriptors *wds, + if (wds->conf_wd == -1) + condlog(3, "didn't set up notifications on /etc/multipath.conf: %m"); + } +- if (mp_reset && bindings_file) { +- char *slash = strrchr(bindings_file, '/'); +- +- if (slash && slash > bindings_file) { +- *slash = '\0'; +- wds->mp_wd = inotify_add_watch(notify_fd, bindings_file, +- IN_MOVED_TO|IN_ONLYDIR); +- if (wds->mp_wd == -1) ++ if (mp_reset) { ++ wds->mp_wd = inotify_add_watch(notify_fd, STATE_DIR, ++ IN_MOVED_TO|IN_ONLYDIR); ++ if (wds->mp_wd == -1) + condlog(3, "didn't set up notifications on %s: %m", +- bindings_file); +- } ++ STATE_DIR); + } + } + +diff --git a/tests/alias.c b/tests/alias.c +index 94df36d8..f893d174 100644 +--- a/tests/alias.c ++++ b/tests/alias.c +@@ -1264,10 +1264,10 @@ static void al_a(void **state) + will_return(__wrap_write, ln); + will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); + will_return(__wrap_rename, 0); +- expect_condlog(1, "updated bindings file foo"); ++ expect_condlog(1, "updated bindings file " DEFAULT_BINDINGS_FILE); + expect_condlog(3, NEW_STR("MPATHa", "WWIDa")); + +- alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("WWIDa", 1, "MPATH"); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHa"); + check_bindings_size(1); +@@ -1283,10 +1283,10 @@ static void al_zz(void **state) + will_return(__wrap_write, ln); + will_return(__wrap_write, strlen(BINDINGS_FILE_HEADER) + strlen(ln)); + will_return(__wrap_rename, 0); +- expect_condlog(1, "updated bindings file foo"); ++ expect_condlog(1, "updated bindings file " DEFAULT_BINDINGS_FILE); + expect_condlog(3, NEW_STR("MPATHzz", "WWIDzz")); + +- alias = allocate_binding("foo", "WWIDzz", 26*26 + 26, "MPATH"); ++ alias = allocate_binding("WWIDzz", 26*26 + 26, "MPATH"); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHzz"); + check_bindings_size(1); +@@ -1298,7 +1298,7 @@ static void al_0(void **state) + char *alias; + + expect_condlog(0, "allocate_binding: cannot allocate new binding for id 0\n"); +- alias = allocate_binding(0, "WWIDa", 0, "MPATH"); ++ alias = allocate_binding("WWIDa", 0, "MPATH"); + assert_ptr_equal(alias, NULL); + check_bindings_size(0); + } +@@ -1308,7 +1308,7 @@ static void al_m2(void **state) + char *alias; + + expect_condlog(0, "allocate_binding: cannot allocate new binding for id -2\n"); +- alias = allocate_binding(0, "WWIDa", -2, "MPATH"); ++ alias = allocate_binding("WWIDa", -2, "MPATH"); + assert_ptr_equal(alias, NULL); + check_bindings_size(0); + } +@@ -1325,10 +1325,10 @@ static void al_write_partial(void **state) + will_return(__wrap_write, ln + sizeof(ln) - 2); + will_return(__wrap_write, 1); + will_return(__wrap_rename, 0); +- expect_condlog(1, "updated bindings file foo"); ++ expect_condlog(1, "updated bindings file " DEFAULT_BINDINGS_FILE); + expect_condlog(3, "Created new binding [MPATHa] for WWID [WWIDa]\n"); + +- alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("WWIDa", 1, "MPATH"); + assert_ptr_not_equal(alias, NULL); + assert_string_equal(alias, "MPATHa"); + check_bindings_size(1); +@@ -1350,7 +1350,7 @@ static void al_write_short(void **state) + expect_condlog(1, "failed to write new bindings file"); + expect_condlog(1, "allocate_binding: deleting binding MPATHa for WWIDa"); + +- alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("WWIDa", 1, "MPATH"); + assert_ptr_equal(alias, NULL); + check_bindings_size(0); + } +@@ -1366,7 +1366,7 @@ static void al_write_err(void **state) + expect_condlog(1, "failed to write new bindings file"); + expect_condlog(1, "allocate_binding: deleting binding MPATHa for WWIDa"); + +- alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("WWIDa", 1, "MPATH"); + assert_ptr_equal(alias, NULL); + check_bindings_size(0); + } +@@ -1383,7 +1383,7 @@ static void al_rename_err(void **state) + + expect_condlog(0, "update_bindings_file: rename: Read-only file system"); + expect_condlog(1, "allocate_binding: deleting binding MPATHa for WWIDa"); +- alias = allocate_binding("foo", "WWIDa", 1, "MPATH"); ++ alias = allocate_binding("WWIDa", 1, "MPATH"); + assert_ptr_equal(alias, NULL); + check_bindings_size(0); + } +@@ -1415,7 +1415,7 @@ static int test_allocate_binding(void) + strlen(BINDINGS_FILE_HEADER) + (len) + strlen(ln)); \ + will_return(__wrap_rename, err); \ + if (err == 0) { \ +- expect_condlog(1, "updated bindings file x\n"); \ ++ expect_condlog(1, "updated bindings file " DEFAULT_BINDINGS_FILE); \ + expect_condlog(3, NEW_STR(alias, wwid)); \ + } else { \ + expect_condlog(0, "update_bindings_file: rename: " msg "\n"); \ +@@ -1441,7 +1441,7 @@ static void gufa_empty_new_rw(void **state) { + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + + mock_allocate_binding("MPATHa", "WWID0"); +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", false); + assert_string_equal(alias, "MPATHa"); + free(alias); + } +@@ -1454,7 +1454,7 @@ static void gufa_empty_new_ro_1(void **state) { + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_allocate_binding_err("MPATHa", "WWID0", -EROFS, "Read-only file system"); + +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", false); + assert_ptr_equal(alias, NULL); + } + +@@ -1465,7 +1465,7 @@ static void gufa_empty_new_ro_2(void **state) { + expect_condlog(3, NOMATCH_WWID_STR("WWID0")); + mock_unused_alias("MPATHa"); + +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", true); + assert_ptr_equal(alias, NULL); + } + +@@ -1477,7 +1477,7 @@ static void gufa_match_a_unused(void **state) { + mock_unused_alias("MPATHa"); + expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); + +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", true); + assert_string_equal(alias, "MPATHa"); + free(alias); + } +@@ -1490,7 +1490,7 @@ static void gufa_match_a_self(void **state) { + mock_self_alias("MPATHa", "WWID0"); + expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); + +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", true); + assert_string_equal(alias, "MPATHa"); + free(alias); + } +@@ -1503,7 +1503,7 @@ static void gufa_match_a_used(void **state) { + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_used_alias("MPATHa", "WWID0"); + +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", true); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", true); + assert_ptr_equal(alias, NULL); + } + +@@ -1518,7 +1518,7 @@ static void gufa_nomatch_a_c(void **state) { + + mock_allocate_binding_len("MPATHb", "WWID1", strlen(bindings)); + +- alias = get_user_friendly_alias("WWID1", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID1", "", "MPATH", false); + assert_string_equal(alias, "MPATHb"); + free(alias); + } +@@ -1534,7 +1534,7 @@ static void gufa_nomatch_c_a(void **state) { + + mock_allocate_binding_len("MPATHb", "WWID1", sizeof(bindings) - 1); + +- alias = get_user_friendly_alias("WWID1", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID1", "", "MPATH", false); + assert_string_equal(alias, "MPATHb"); + free(alias); + } +@@ -1550,7 +1550,7 @@ static void gufa_nomatch_c_b(void **state) { + + mock_allocate_binding_len("MPATHa", "WWID0", sizeof(bindings) - 1); + +- alias = get_user_friendly_alias("WWID0", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "", "MPATH", false); + assert_string_equal(alias, "MPATHa"); + free(alias); + } +@@ -1567,7 +1567,7 @@ static void gufa_nomatch_c_b_used(void **state) { + + mock_allocate_binding_len("MPATHd", "WWID4", sizeof(bindings) - 1); + +- alias = get_user_friendly_alias("WWID4", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID4", "", "MPATH", false); + assert_string_equal(alias, "MPATHd"); + free(alias); + } +@@ -1584,7 +1584,7 @@ static void gufa_nomatch_b_f_a(void **state) { + + mock_allocate_binding_len("MPATHc", "WWID7", sizeof(bindings) - 1); + +- alias = get_user_friendly_alias("WWID7", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID7", "", "MPATH", false); + assert_string_equal(alias, "MPATHc"); + free(alias); + } +@@ -1599,7 +1599,7 @@ static void gufa_nomatch_b_aa_a(void **state) { + mock_unused_alias("MPATHab"); + mock_allocate_binding_len("MPATHab", "WWID28", get_strbuf_len(&buf)); + +- alias = get_user_friendly_alias("WWID28", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID28", "", "MPATH", false); + assert_string_equal(alias, "MPATHab"); + free(alias); + } +@@ -1616,7 +1616,7 @@ static void gufa_nomatch_b_f_a_sorted(void **state) { + + mock_allocate_binding_len("MPATHc", "WWID7", sizeof(bindings) - 1); + +- alias = get_user_friendly_alias("WWID7", "x", "", "MPATH", false); ++ alias = get_user_friendly_alias("WWID7", "", "MPATH", false); + assert_string_equal(alias, "MPATHc"); + free(alias); + } +@@ -1632,7 +1632,7 @@ static void gufa_old_empty(void **state) { + mock_allocate_binding("MPATHz", "WWID0"); + expect_condlog(2, ALLOC_STR("MPATHz", "WWID0")); + +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHz"); + free(alias); + } +@@ -1644,7 +1644,7 @@ static void gufa_old_match(void **state) { + "MPATHz WWID0"); + expect_condlog(3, FOUND_ALIAS_STR("MPATHz", "WWID0")); + +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHz"); + free(alias); + } +@@ -1661,7 +1661,7 @@ static void gufa_old_match_other(void **state) { + + mock_allocate_binding_len("MPATHa", "WWID0", sizeof(bindings) - 1); + +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHa"); + free(alias); + } +@@ -1678,7 +1678,7 @@ static void gufa_old_match_other_used(void **state) { + mock_unused_alias("MPATHb"); + + mock_allocate_binding_len("MPATHb", "WWID0", sizeof(bindings) - 1); +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHb"); + free(alias); + } +@@ -1695,7 +1695,7 @@ static void gufa_old_match_other_wwidmatch(void **state) { + mock_unused_alias("MPATHc"); + expect_condlog(3, EXISTING_STR("MPATHc", "WWID2")); + +- alias = get_user_friendly_alias("WWID2", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID2", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHc"); + free(alias); + } +@@ -1711,7 +1711,7 @@ static void gufa_old_match_other_wwidmatch_used(void **state) { + expect_condlog(3, FOUND_STR("MPATHc", "WWID2")); + mock_used_alias("MPATHc", "WWID2"); + +- alias = get_user_friendly_alias("WWID2", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID2", "MPATHz", "MPATH", false); + assert_ptr_equal(alias, NULL); + } + +@@ -1725,7 +1725,7 @@ static void gufa_old_nomatch_wwidmatch(void **state) { + mock_unused_alias("MPATHa"); + expect_condlog(3, EXISTING_STR("MPATHa", "WWID0")); + +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHa"); + free(alias); + } +@@ -1739,7 +1739,7 @@ static void gufa_old_nomatch_wwidmatch_used(void **state) { + expect_condlog(3, FOUND_STR("MPATHa", "WWID0")); + mock_used_alias("MPATHa", "WWID0"); + +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_ptr_equal(alias, NULL); + } + +@@ -1754,7 +1754,7 @@ static void gufa_old_nomatch_nowwidmatch(void **state) { + mock_allocate_binding_len("MPATHz", "WWID0", sizeof(bindings) - 1); + expect_condlog(2, ALLOC_STR("MPATHz", "WWID0")); + +- alias = get_user_friendly_alias("WWID0", "x", "MPATHz", "MPATH", false); ++ alias = get_user_friendly_alias("WWID0", "MPATHz", "MPATH", false); + assert_string_equal(alias, "MPATHz"); + free(alias); + } diff --git a/0038-libmultipath-avoid-Warray-bounds-error-in-uatomic-op.patch b/0038-libmultipath-avoid-Warray-bounds-error-in-uatomic-op.patch new file mode 100644 index 0000000..269efcf --- /dev/null +++ b/0038-libmultipath-avoid-Warray-bounds-error-in-uatomic-op.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Tue, 12 Sep 2023 11:54:47 +0200 +Subject: [PATCH] libmultipath: avoid -Warray-bounds error in uatomic + operations + +The use of uatomic_xchg() in alias.c causes a -Warray-bounds error +on distributions using gcc 12, such as Fedora 37. This is a similar +error to 2534c4f ("libmultipath: avoid -Warray-bounds error with gcc +12 and musl libc"). This happens only with liburcu 0.13 and earlier, +and only with certain gcc versions. See liburcu commit 835b9ab +("Fix: x86 and s390 uatomic: __hp() macro warning with gcc 11"). + +Enhance the fix for 2534c4f by a adding a workaround for uatomic_xchg(), +and introduce the macro URCU_VERSION (originally only used for multipathd) +globally. + +Signed-off-by: Martin Wilck +Reviewed-by: Benjamin Marzinski +Signed-off-by: Benjamin Marzinski +--- + Makefile.inc | 2 +- + create-config.mk | 5 +++++ + libmultipath/alias.c | 5 +++-- + libmultipath/lock.h | 21 +++++++++++++-------- + multipathd/Makefile | 2 -- + 5 files changed, 22 insertions(+), 13 deletions(-) + +diff --git a/Makefile.inc b/Makefile.inc +index 6e384e68..04bfa56e 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -95,7 +95,7 @@ OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4 + WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int \ + -Werror=implicit-function-declaration -Werror=format-security \ + $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) +-CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) \ ++CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ + -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(plugindir)\" \ + -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(configdir)\" \ + -DDEFAULT_CONFIGFILE=\"$(configfile)\" -DSTATE_DIR=\"$(statedir)\" \ +diff --git a/create-config.mk b/create-config.mk +index d1255971..4d318b96 100644 +--- a/create-config.mk ++++ b/create-config.mk +@@ -73,6 +73,10 @@ TEST_URCU_TYPE_LIMITS = $(shell \ + $(CC) -c -Werror=type-limits -o /dev/null -xc - 2>/dev/null \ + || echo -Wno-type-limits ) + ++URCU_VERSION = $(shell \ ++ $(PKG_CONFIG) --modversion liburcu 2>/dev/null | \ ++ awk -F. '{ printf("-DURCU_VERSION=0x%06x", 256 * ( 256 * $$1 + $$2) + $$3); }') ++ + DEFINES := + + ifneq ($(call check_func,dm_task_no_flush,$(devmapper_incdir)/libdevmapper.h),0) +@@ -168,6 +172,7 @@ $(TOPDIR)/config.mk: $(multipathdir)/autoconfig.h + @echo creating $@ + @echo "FPIN_SUPPORT := $(FPIN_SUPPORT)" >$@ + @echo "FORTIFY_OPT := $(FORTIFY_OPT)" >>$@ ++ @echo "D_URCU_VERSION := $(call URCU_VERSION)" >>$@ + @echo "SYSTEMD := $(SYSTEMD)" >>$@ + @echo "ANA_SUPPORT := $(ANA_SUPPORT)" >>$@ + @echo "STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)" >>$@ +diff --git a/libmultipath/alias.c b/libmultipath/alias.c +index e5d3f151..74431f3f 100644 +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -24,6 +24,7 @@ + #include "devmapper.h" + #include "strbuf.h" + #include "time-util.h" ++#include "lock.h" + + /* + * significant parts of this file were taken from iscsi-bindings.c of the +@@ -300,7 +301,7 @@ void handle_bindings_file_inotify(const struct inotify_event *event) + pthread_mutex_unlock(×tamp_mutex); + + if (changed) { +- uatomic_xchg(&bindings_file_changed, 1); ++ uatomic_xchg_int(&bindings_file_changed, 1); + condlog(3, "%s: bindings file must be re-read, new timestamp: %ld.%06ld", + __func__, (long)ts.tv_sec, (long)ts.tv_nsec / 1000); + } else +@@ -775,7 +776,7 @@ static int _read_bindings_file(const struct config *conf, Bindings *bindings, + int rc = 0, ret, fd; + FILE *file; + struct stat st; +- int has_changed = uatomic_xchg(&bindings_file_changed, 0); ++ int has_changed = uatomic_xchg_int(&bindings_file_changed, 0); + + if (!force) { + if (!has_changed) { +diff --git a/libmultipath/lock.h b/libmultipath/lock.h +index 9814be76..ac80d1d8 100644 +--- a/libmultipath/lock.h ++++ b/libmultipath/lock.h +@@ -13,15 +13,20 @@ struct mutex_lock { + int waiters; /* uatomic access only */ + }; + +-#if !defined(__GLIBC__) && defined(__GNUC__) && __GNUC__ == 12 ++static inline void init_lock(struct mutex_lock *a) ++{ ++ pthread_mutex_init(&a->mutex, NULL); ++ uatomic_set(&a->waiters, 0); ++} ++ ++#if defined(__GNUC__) && __GNUC__ == 12 && URCU_VERSION < 0xe00 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Warray-bounds" + #endif + +-static inline void init_lock(struct mutex_lock *a) ++static inline int uatomic_xchg_int(int *ptr, int val) + { +- pthread_mutex_init(&a->mutex, NULL); +- uatomic_set(&a->waiters, 0); ++ return uatomic_xchg(ptr, val); + } + + static inline void lock(struct mutex_lock *a) +@@ -31,6 +36,10 @@ static inline void lock(struct mutex_lock *a) + uatomic_dec(&a->waiters); + } + ++#if defined(__GNUC__) && __GNUC__ == 12 && URCU_VERSION < 0xe00 ++#pragma GCC diagnostic pop ++#endif ++ + static inline int trylock(struct mutex_lock *a) + { + return pthread_mutex_trylock(&a->mutex); +@@ -51,10 +60,6 @@ static inline bool lock_has_waiters(struct mutex_lock *a) + return (uatomic_read(&a->waiters) > 0); + } + +-#if !defined(__GLIBC__) && defined(__GNUC__) && __GNUC__ == 12 +-#pragma GCC diagnostic pop +-#endif +- + #define lock_cleanup_pop(a) pthread_cleanup_pop(1) + + void cleanup_lock (void * data); +diff --git a/multipathd/Makefile b/multipathd/Makefile +index cdba3db1..0ba6ecb7 100644 +--- a/multipathd/Makefile ++++ b/multipathd/Makefile +@@ -5,8 +5,6 @@ CLI := multipathc + MANPAGES := multipathd.8 + + CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathpersistdir) -I$(mpathcmddir) -I$(thirdpartydir) \ +- $(shell $(PKG_CONFIG) --modversion liburcu 2>/dev/null | \ +- awk -F. '{ printf("-DURCU_VERSION=0x%06x", 256 * ( 256 * $$1 + $$2) + $$3); }') \ + -DBINDIR='"$(bindir)"' $(SYSTEMD_CPPFLAGS) + + # diff --git a/0039-multipath-tools-fix-spelling.patch b/0039-multipath-tools-fix-spelling.patch new file mode 100644 index 0000000..c0c86f9 --- /dev/null +++ b/0039-multipath-tools-fix-spelling.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xose Vazquez Perez +Date: Fri, 15 Sep 2023 22:22:06 +0200 +Subject: [PATCH] multipath-tools: fix spelling + +Cc: Martin Wilck +Cc: Benjamin Marzinski +Cc: Christophe Varoqui +Cc: DM-DEVEL ML +Signed-off-by: Xose Vazquez Perez +Reviewed-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + README.md | 4 ++-- + multipath/multipath.conf.5.in | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/README.md b/README.md +index 679e55bf..524c9fb1 100644 +--- a/README.md ++++ b/README.md +@@ -92,7 +92,7 @@ The following variables can be passed to the `make` command line: + The default is `$(prefix)/$(LIB)/multipath`, where `$(LIB)` is `lib64` on + systems that have `/lib64`, and `lib` otherwise. + * `configfile="/some/path`": The path to the main configuration file. +- The defalt is `$(etc_prefix)/etc/multipath.conf`. ++ The default is `$(etc_prefix)/etc/multipath.conf`. + * `configdir="/some/path"` : directory to search for additional configuration files. + This used to be the run-time option `config_dir` in earlier versions. + The default is `$(etc_prefix)/etc/multipath/conf.d`. +@@ -141,7 +141,7 @@ The following variables can be passed to the `make` command line: + found on the build system, and `/lib` otherwise. + + The options `configdir`, `plugindir`, `configfile`, and `statedir` above can +-be used for setting indvidual paths where the `prefix` variables don't provide ++be used for setting individual paths where the `prefix` variables don't provide + sufficient control. See `Makefile.inc` for even more fine-grained control. + + [^systemd]: Some systemd installations use separate `prefix` and `rootprefix`. +diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in +index d320a88f..226d0019 100644 +--- a/multipath/multipath.conf.5.in ++++ b/multipath/multipath.conf.5.in +@@ -36,7 +36,7 @@ Files ending in \fI.conf\fR in this directory are read + in alphabetical order, after reading \fI@CONFIGFILE@\fR. + They use the same syntax as \fI@CONFIGFILE@\fR itself, + and support all sections and keywords. If a keyword occurs in the same section +-in multiple files, the last occurence will take precedence over all others. ++in multiple files, the last occurrence will take precedence over all others. + . + . + .\" ---------------------------------------------------------------------------- diff --git a/0040-multipathd-Added-support-to-handle-FPIN-Li-events-fo.patch b/0040-multipathd-Added-support-to-handle-FPIN-Li-events-fo.patch new file mode 100644 index 0000000..7ed50a3 --- /dev/null +++ b/0040-multipathd-Added-support-to-handle-FPIN-Li-events-fo.patch @@ -0,0 +1,300 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Muneendra +Date: Wed, 20 Sep 2023 20:41:15 -0700 +Subject: [PATCH] multipathd: Added support to handle FPIN-Li events for + FC-NVMe + + This patch adds the support to handle FPIN-Li for FC-NVMe. + On receiving the FPIN-Li events this patch moves the devices paths + which are affected due to link integrity to marginal path groups. + The paths which are set to marginal path group will be unset + on receiving the RSCN events + +(mwilck: minor compile fix for 32-bit architectures) + +Signed-off-by: Muneendra +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + multipathd/fpin_handlers.c | 206 +++++++++++++++++++++++++++---------- + 1 file changed, 151 insertions(+), 55 deletions(-) + +diff --git a/multipathd/fpin_handlers.c b/multipathd/fpin_handlers.c +index aa0f63c9..be087ca0 100644 +--- a/multipathd/fpin_handlers.c ++++ b/multipathd/fpin_handlers.c +@@ -60,18 +60,15 @@ static void _udev_device_unref(void *p) + + + /*set/unset the path state to marginal*/ +-static int fpin_set_pathstate(struct path *pp, bool set) ++static void fpin_set_pathstate(struct path *pp, bool set) + { + const char *action = set ? "set" : "unset"; + +- if (!pp || !pp->mpp || !pp->mpp->alias) +- return -1; +- +- condlog(3, "\n%s: %s marginal path %s (fpin)", +- action, pp->mpp->alias, pp->dev_t); ++ condlog(3, "%s: %s marginal path %s (fpin)", ++ pp->mpp ? pp->mpp->alias : "orphan", action, pp->dev_t); + pp->marginal = set; +- pp->mpp->fpin_must_reload = true; +- return 0; ++ if (pp->mpp) ++ pp->mpp->fpin_must_reload = true; + } + + /* This will unset marginal state of a device*/ +@@ -82,14 +79,14 @@ static void fpin_path_unsetmarginal(char *devname, struct vectors *vecs) + pp = find_path_by_dev(vecs->pathvec, devname); + if (!pp) + pp = find_path_by_devt(vecs->pathvec, devname); +- +- fpin_set_pathstate(pp, false); ++ if (pp) ++ fpin_set_pathstate(pp, false); + } + + /*This will set the marginal state of a device*/ +-static int fpin_path_setmarginal(struct path *pp) ++static void fpin_path_setmarginal(struct path *pp) + { +- return fpin_set_pathstate(pp, true); ++ fpin_set_pathstate(pp, true); + } + + /* Unsets all the devices in the list from marginal state */ +@@ -183,8 +180,8 @@ static void fpin_set_rport_marginal(struct udev_device *rport_dev) + udev_device_get_syspath(rport_dev)); + } + +-/*Add the marginal devices info into the list*/ +-static void ++/*Add the marginal devices info into the list and return 0 on success*/ ++static int + fpin_add_marginal_dev_info(uint32_t host_num, char *devname) + { + struct marginal_dev_list *newdev = NULL; +@@ -199,65 +196,160 @@ fpin_add_marginal_dev_info(uint32_t host_num, char *devname) + list_add_tail(&(newdev->node), + &fpin_li_marginal_dev_list_head); + pthread_mutex_unlock(&fpin_li_marginal_dev_mutex); +- } ++ } else ++ return -ENOMEM; ++ return 0; + } + + /* +- * This function goes through the vecs->pathvec, and for +- * each path, check that the host number, +- * the target WWPN associated with the path matches +- * with the els wwpn and sets the path and port state to ++ * This function compares Transport Address Controller Port pn, ++ * Host Transport Address Controller Port pn with the els wwpn ,attached_wwpn ++ * and return 1 (match) or 0 (no match) or a negative error code ++ */ ++static int extract_nvme_addresses_chk_path_pwwn(const char *address, ++ uint64_t els_wwpn, uint64_t els_attached_wwpn) ++ ++{ ++ uint64_t traddr; ++ uint64_t host_traddr; ++ ++ /* ++ * Find the position of "traddr=" and "host_traddr=" ++ * and the address will be in the below format ++ * "traddr=nn-0x200400110dff9400:pn-0x200400110dff9400, ++ * host_traddr=nn-0x200400110dff9400:pn-0x200400110dff9400" ++ */ ++ const char *traddr_start = strstr(address, "traddr="); ++ const char *host_traddr_start = strstr(address, "host_traddr="); ++ ++ if (!traddr_start || !host_traddr_start) ++ return -EINVAL; ++ ++ /* Extract traddr pn */ ++ if (sscanf(traddr_start, "traddr=nn-%*[^:]:pn-%" SCNx64, &traddr) != 1) ++ return -EINVAL; ++ ++ /* Extract host_traddr pn*/ ++ if (sscanf(host_traddr_start, "host_traddr=nn-%*[^:]:pn-%" SCNx64, ++ &host_traddr) != 1) ++ return -EINVAL; ++ condlog(4, "traddr 0x%" PRIx64 " hosttraddr 0x%" PRIx64 " els_wwpn 0x%" ++ PRIx64" els_host_traddr 0x%" PRIx64, ++ traddr, host_traddr, ++ els_wwpn, els_attached_wwpn); ++ if ((host_traddr == els_attached_wwpn) && (traddr == els_wwpn)) ++ return 1; ++ return 0; ++} ++ ++/* ++ * This function check that the Transport Address Controller Port pn, ++ * Host Transport Address Controller Port pn associated with the path matches ++ * with the els wwpn ,attached_wwpn and sets the path state to + * Marginal + */ +-static int fpin_chk_wwn_setpath_marginal(uint16_t host_num, struct vectors *vecs, ++static void fpin_check_set_nvme_path_marginal(uint16_t host_num, struct path *pp, ++ uint64_t els_wwpn, uint64_t attached_wwpn) ++{ ++ struct udev_device *ctl = NULL; ++ const char *address = NULL; ++ int ret = 0; ++ ++ ctl = udev_device_get_parent_with_subsystem_devtype(pp->udev, "nvme", NULL); ++ if (ctl == NULL) { ++ condlog(2, "%s: No parent device for ", pp->dev); ++ return; ++ } ++ address = udev_device_get_sysattr_value(ctl, "address"); ++ if (!address) { ++ condlog(2, "%s: unable to get the address ", pp->dev); ++ return; ++ } ++ condlog(4, "\n address %s: dev :%s\n", address, pp->dev); ++ ret = extract_nvme_addresses_chk_path_pwwn(address, els_wwpn, attached_wwpn); ++ if (ret <= 0) ++ return; ++ ret = fpin_add_marginal_dev_info(host_num, pp->dev); ++ if (ret < 0) ++ return; ++ fpin_path_setmarginal(pp); ++} ++ ++/* ++ * This function check the host number, the target WWPN ++ * associated with the path matches with the els wwpn and ++ * sets the path and port state to Marginal ++ */ ++static void fpin_check_set_scsi_path_marginal(uint16_t host_num, struct path *pp, + uint64_t els_wwpn) + { +- struct path *pp; +- struct multipath *mpp; +- int i, k; + char rport_id[42]; + const char *value = NULL; + struct udev_device *rport_dev = NULL; + uint64_t wwpn; + int ret = 0; ++ sprintf(rport_id, "rport-%d:%d-%d", ++ pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id); ++ rport_dev = udev_device_new_from_subsystem_sysname(udev, ++ "fc_remote_ports", rport_id); ++ if (!rport_dev) { ++ condlog(2, "%s: No fc_remote_port device for '%s'", pp->dev, ++ rport_id); ++ return; ++ } ++ pthread_cleanup_push(_udev_device_unref, rport_dev); ++ value = udev_device_get_sysattr_value(rport_dev, "port_name"); ++ if (!value) ++ goto unref; ++ ++ wwpn = strtol(value, NULL, 16); ++ /* ++ * If the port wwpn matches sets the path and port state ++ * to marginal ++ */ ++ if (wwpn == els_wwpn) { ++ ret = fpin_add_marginal_dev_info(host_num, pp->dev); ++ if (ret < 0) ++ goto unref; ++ fpin_path_setmarginal(pp); ++ fpin_set_rport_marginal(rport_dev); ++ } ++unref: ++ pthread_cleanup_pop(1); ++ return; ++ ++} ++ ++/* ++ * This function goes through the vecs->pathvec, and for ++ * each path, it checks and sets the path state to marginal ++ * if the path's associated port wwpn ,hostnum matches with ++ * els wwnpn ,attached_wwpn ++ */ ++static int fpin_chk_wwn_setpath_marginal(uint16_t host_num, struct vectors *vecs, ++ uint64_t els_wwpn, uint64_t attached_wwpn) ++{ ++ struct path *pp; ++ struct multipath *mpp; ++ int i, k; ++ int ret = 0; + + pthread_cleanup_push(cleanup_lock, &vecs->lock); + lock(&vecs->lock); + pthread_testcancel(); + + vector_foreach_slot(vecs->pathvec, pp, k) { +- /* Checks the host number and also for the SCSI FCP */ +- if (pp->bus != SYSFS_BUS_SCSI || pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num != pp->sg_id.host_no) ++ if (!pp->mpp) + continue; +- sprintf(rport_id, "rport-%d:%d-%d", +- pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id); +- rport_dev = udev_device_new_from_subsystem_sysname(udev, +- "fc_remote_ports", rport_id); +- if (!rport_dev) { +- condlog(2, "%s: No fc_remote_port device for '%s'", pp->dev, +- rport_id); +- continue; +- } +- pthread_cleanup_push(_udev_device_unref, rport_dev); +- value = udev_device_get_sysattr_value(rport_dev, "port_name"); +- if (!value) +- goto unref; +- +- if (value) +- wwpn = strtol(value, NULL, 16); +- /* +- * If the port wwpn matches sets the path and port state +- * to marginal +- */ +- if (wwpn == els_wwpn) { +- ret = fpin_path_setmarginal(pp); +- if (ret < 0) +- goto unref; +- fpin_set_rport_marginal(rport_dev); +- fpin_add_marginal_dev_info(host_num, pp->dev); ++ /*checks if the bus type is nvme and the protocol is FC-NVMe*/ ++ if ((pp->bus == SYSFS_BUS_NVME) && (pp->sg_id.proto_id == NVME_PROTOCOL_FC)) { ++ fpin_check_set_nvme_path_marginal(host_num, pp, els_wwpn, attached_wwpn); ++ } else if ((pp->bus == SYSFS_BUS_SCSI) && ++ (pp->sg_id.proto_id == SCSI_PROTOCOL_FCP) && ++ (host_num == pp->sg_id.host_no)) { ++ /* Checks the host number and also for the SCSI FCP */ ++ fpin_check_set_scsi_path_marginal(host_num, pp, els_wwpn); + } +-unref: +- pthread_cleanup_pop(1); + } + /* walk backwards because reload_and_sync_map() can remove mpp */ + vector_foreach_slot_backwards(vecs->mpvec, mpp, i) { +@@ -286,14 +378,18 @@ fpin_parse_li_els_setpath_marginal(uint16_t host_num, struct fc_tlv_desc *tlv, + struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv; + int count = 0; + int ret = 0; ++ uint64_t attached_wwpn; + + /* Update the wwn to list */ + wwn_count = be32_to_cpu(li_desc->pname_count); +- condlog(4, "Got wwn count as %d\n", wwn_count); ++ attached_wwpn = be64_to_cpu(li_desc->attached_wwpn); ++ condlog(4, "Got wwn count as %d detecting wwn 0x%" PRIx64 ++ " attached_wwpn 0x%" PRIx64 "\n", ++ wwn_count, be64_to_cpu(li_desc->detecting_wwpn), attached_wwpn); + + for (iter = 0; iter < wwn_count; iter++) { + wwpn = be64_to_cpu(li_desc->pname_list[iter]); +- ret = fpin_chk_wwn_setpath_marginal(host_num, vecs, wwpn); ++ ret = fpin_chk_wwn_setpath_marginal(host_num, vecs, wwpn, attached_wwpn); + if (ret < 0) + condlog(2, "failed to set the path marginal associated with wwpn: 0x%" PRIx64 "\n", wwpn); + diff --git a/0001-RH-fixup-udev-rules-for-redhat.patch b/0041-RH-fixup-udev-rules-for-redhat.patch similarity index 89% rename from 0001-RH-fixup-udev-rules-for-redhat.patch rename to 0041-RH-fixup-udev-rules-for-redhat.patch index 618603c..e96c1e7 100644 --- a/0001-RH-fixup-udev-rules-for-redhat.patch +++ b/0041-RH-fixup-udev-rules-for-redhat.patch @@ -15,7 +15,7 @@ Signed-off-by: Benjamin Marzinski 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.inc b/Makefile.inc -index 2e25d2ea..540e1dfc 100644 +index 04bfa56e..62d3d5cc 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -34,9 +34,9 @@ endif @@ -27,9 +27,9 @@ index 2e25d2ea..540e1dfc 100644 # Prefix for non-essential libraries (libdmmp) -usr_prefix := $(prefix) +usr_prefix := $(prefix)/usr + # Prefix for configfuration files (multipath.conf) + etc_prefix := $(prefix) # Where to install systemd-related files. systemd is usually installed under /usr - # Note: some systemd installations use separate "prefix" and "rootprefix". - # In this case, override only unitdir to use systemd's "rootprefix" instead of $(systemd_prefix) diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules index 1969dee0..d2b28233 100644 --- a/kpartx/kpartx.rules @@ -43,10 +43,10 @@ index 1969dee0..d2b28233 100644 LABEL="kpartx_end" diff --git a/multipath/Makefile b/multipath/Makefile -index 73db991a..b3c2cc81 100644 +index 68cb5ce7..f70e64ec 100644 --- a/multipath/Makefile +++ b/multipath/Makefile -@@ -24,7 +24,7 @@ install: +@@ -26,7 +26,7 @@ install: $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir) $(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir) @@ -55,7 +55,7 @@ index 73db991a..b3c2cc81 100644 $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(modulesloaddir) $(Q)$(INSTALL_PROGRAM) -m 644 modules-load.conf $(DESTDIR)$(modulesloaddir)/multipath.conf $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(tmpfilesdir) -@@ -44,7 +44,7 @@ uninstall: +@@ -46,7 +46,7 @@ uninstall: $(Q)$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf @@ -63,4 +63,4 @@ index 73db991a..b3c2cc81 100644 + $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/62-multipath.rules $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 $(Q)$(RM) $(DESTDIR)$(mandir)/man5/$(EXEC).conf.5 - + $(Q)$(RM) $(DESTDIR)$(tmpfilesdir)/multipath.conf diff --git a/0002-RH-Remove-the-property-blacklist-exception-builtin.patch b/0042-RH-Remove-the-property-blacklist-exception-builtin.patch similarity index 79% rename from 0002-RH-Remove-the-property-blacklist-exception-builtin.patch rename to 0042-RH-Remove-the-property-blacklist-exception-builtin.patch index cbd2480..61e8943 100644 --- a/0002-RH-Remove-the-property-blacklist-exception-builtin.patch +++ b/0042-RH-Remove-the-property-blacklist-exception-builtin.patch @@ -13,26 +13,25 @@ it. Signed-off-by: Benjamin Marzinski --- - libmultipath/blacklist.c | 6 ++---- - multipath/multipath.conf.5 | 11 ++++++----- - tests/blacklist.c | 7 ++----- - 3 files changed, 10 insertions(+), 14 deletions(-) + libmultipath/blacklist.c | 5 ++--- + multipath/multipath.conf.5.in | 11 ++++++----- + tests/blacklist.c | 7 ++----- + 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c -index 8d15d2ea..eff690fd 100644 +index 75100b20..0b212078 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c -@@ -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; - +@@ -230,8 +230,6 @@ setup_default_blist (struct config * conf) + ORIGIN_DEFAULT)) + return 1; + } - 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, -@@ -409,7 +406,8 @@ filter_property(const struct config *conf, struct udev_device *udev, +@@ -438,7 +436,8 @@ filter_property(const struct config *conf, struct udev_device *udev, *uid_attribute != '\0'; bool uid_attr_seen = false; @@ -42,11 +41,11 @@ index 8d15d2ea..eff690fd 100644 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev)) { -diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 -index b4dccd1b..284282c6 100644 ---- a/multipath/multipath.conf.5 -+++ b/multipath/multipath.conf.5 -@@ -1367,9 +1367,14 @@ keywords. Both are regular expressions. For a full description of these keywords +diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in +index 226d0019..bae4168f 100644 +--- a/multipath/multipath.conf.5.in ++++ b/multipath/multipath.conf.5.in +@@ -1402,9 +1402,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, @@ -62,7 +61,7 @@ index b4dccd1b..284282c6 100644 . .RS .PP -@@ -1380,10 +1385,6 @@ Blacklisting by missing properties is only applied to devices which do have the +@@ -1415,10 +1420,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. @@ -74,10 +73,10 @@ index b4dccd1b..284282c6 100644 .TP .B protocol diff --git a/tests/blacklist.c b/tests/blacklist.c -index 882aa3a1..6a22b660 100644 +index ba8dfd07..693db3fa 100644 --- a/tests/blacklist.c +++ b/tests/blacklist.c -@@ -375,9 +375,8 @@ static void test_property_missing(void **state) +@@ -384,9 +384,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; @@ -88,7 +87,7 @@ index 882aa3a1..6a22b660 100644 assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"), MATCH_NOTHING); assert_int_equal(filter_property(&conf, &udev, 3, ""), -@@ -469,9 +468,7 @@ static void test_filter_path_missing1(void **state) +@@ -478,9 +477,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/0003-RH-don-t-start-without-a-config-file.patch b/0043-RH-don-t-start-without-a-config-file.patch similarity index 71% rename from 0003-RH-don-t-start-without-a-config-file.patch rename to 0043-RH-don-t-start-without-a-config-file.patch index e6e03b4..ef9415d 100644 --- a/0003-RH-don-t-start-without-a-config-file.patch +++ b/0043-RH-don-t-start-without-a-config-file.patch @@ -14,17 +14,18 @@ Signed-off-by: Benjamin Marzinski --- libmultipath/config.c | 13 +++++++++++++ libmultipath/config.h | 1 + + multipath/main.c | 6 ++++++ multipath/multipath.rules.in | 1 + - multipathd/multipathd.8 | 2 ++ + multipathd/multipathd.8.in | 2 ++ multipathd/multipathd.service | 1 + multipathd/multipathd.socket | 1 + - 6 files changed, 19 insertions(+) + 7 files changed, 25 insertions(+) diff --git a/libmultipath/config.c b/libmultipath/config.c -index 5c5c0726..183b319d 100644 +index b7dbc6f5..3a374b3d 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -966,6 +966,19 @@ int _init_config (const char *file, struct config *conf) +@@ -958,6 +958,19 @@ int _init_config (const char *file, struct config *conf) } factorize_hwtable(conf->hwtable, builtin_hwtable_size, file); validate_pctable(conf->overrides, 0, file); @@ -45,7 +46,7 @@ index 5c5c0726..183b319d 100644 conf->processed_main_config = 1; diff --git a/libmultipath/config.h b/libmultipath/config.h -index 87947469..0dc89c16 100644 +index 8c22ce75..92f3a0df 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -10,6 +10,7 @@ @@ -56,6 +57,35 @@ index 87947469..0dc89c16 100644 enum devtypes { DEV_NONE, +diff --git a/multipath/main.c b/multipath/main.c +index 9e1c5052..46944589 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -829,11 +829,14 @@ main (int argc, char *argv[]) + struct config *conf; + int retries = -1; + bool enable_foreign = false; ++ bool have_config; ++ struct stat buf; + + libmultipath_init(); + if (atexit(dm_lib_exit) || atexit(libmultipath_exit)) + condlog(1, "failed to register cleanup handler for libmultipath: %m"); + logsink = LOGSINK_STDERR_WITH_TIME; ++ have_config = (stat(DEFAULT_CONFIGFILE, &buf) == 0); + if (init_config(DEFAULT_CONFIGFILE)) + exit(RTVL_FAIL); + if (atexit(uninit_config)) +@@ -1081,6 +1084,9 @@ main (int argc, char *argv[]) + while ((r = configure(conf, cmd, dev_type, dev)) == RTVL_RETRY) + condlog(3, "restart multipath configuration process"); + ++ if (!have_config && r == RTVL_OK && ++ (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG)) ++ r = RTVL_FAIL; + out: + put_multipath_config(conf); + if (dev) diff --git a/multipath/multipath.rules.in b/multipath/multipath.rules.in index 6f123760..70b69a06 100644 --- a/multipath/multipath.rules.in @@ -68,11 +98,11 @@ index 6f123760..70b69a06 100644 ENV{DEVTYPE}!="partition", GOTO="test_dev" IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH" -diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8 -index bdf102eb..a16a0bd5 100644 ---- a/multipathd/multipathd.8 -+++ b/multipathd/multipathd.8 -@@ -48,6 +48,8 @@ map regains its maximum performance and redundancy. +diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in +index e98c27fd..fd2061e5 100644 +--- a/multipathd/multipathd.8.in ++++ b/multipathd/multipathd.8.in +@@ -49,6 +49,8 @@ map regains its maximum performance and redundancy. With the \fB-k\fR option, \fBmultipathd\fR acts as a client utility that sends commands to a running instance of the multipathd daemon (see \fBCOMMANDS\fR below). diff --git a/0004-RH-Fix-nvme-function-missing-argument.patch b/0044-RH-Fix-nvme-function-missing-argument.patch similarity index 100% rename from 0004-RH-Fix-nvme-function-missing-argument.patch rename to 0044-RH-Fix-nvme-function-missing-argument.patch diff --git a/0005-RH-use-rpm-optflags-if-present.patch b/0045-RH-use-rpm-optflags-if-present.patch similarity index 83% rename from 0005-RH-use-rpm-optflags-if-present.patch rename to 0045-RH-use-rpm-optflags-if-present.patch index 6a7fdea..1ad6b40 100644 --- a/0005-RH-use-rpm-optflags-if-present.patch +++ b/0045-RH-use-rpm-optflags-if-present.patch @@ -13,10 +13,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Makefile.inc b/Makefile.inc -index 540e1dfc..748911e2 100644 +index 62d3d5cc..72fd8d57 100644 --- a/Makefile.inc +++ b/Makefile.inc -@@ -78,11 +78,23 @@ ORIG_LDFLAGS := $(LDFLAGS) +@@ -91,11 +91,23 @@ ORIG_LDFLAGS := $(LDFLAGS) SYSTEMD_CPPFLAGS := $(if $(SYSTEMD),-DUSE_SYSTEMD=$(SYSTEMD)) SYSTEMD_LIBDEPS := $(if $(SYSTEMD),$(if $(shell test $(SYSTEMD) -gt 209 && echo 1),-lsystemd,-lsystemd-daemon)) @@ -38,13 +38,13 @@ index 540e1dfc..748911e2 100644 +WARNFLAGS := -Werror -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int \ -Werror=implicit-function-declaration -Werror=format-security \ - $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) --CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) \ +-CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ + $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS) -Wstrict-prototypes -+CPPFLAGS := $(CPPFLAGS) \ ++CPPFLAGS := $(CPPFLAGS) $(D_URCU_VERSION) \ -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(plugindir)\" \ - -DRUNTIME_DIR=\"$(runtimedir)\" \ - -DCONFIG_DIR=\"$(configdir)\" -DEXTRAVERSION=\"$(EXTRAVERSION)\" -MMD -MP -@@ -90,7 +102,7 @@ CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe + -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(configdir)\" \ + -DDEFAULT_CONFIGFILE=\"$(configfile)\" -DSTATE_DIR=\"$(statedir)\" \ +@@ -104,7 +116,7 @@ CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe BIN_CFLAGS := -fPIE -DPIE LIB_CFLAGS := -fPIC SHARED_FLAGS := -shared diff --git a/0006-RH-add-mpathconf.patch b/0046-RH-add-mpathconf.patch similarity index 98% rename from 0006-RH-add-mpathconf.patch rename to 0046-RH-add-mpathconf.patch index e279822..01bc8d2 100644 --- a/0006-RH-add-mpathconf.patch +++ b/0046-RH-add-mpathconf.patch @@ -21,10 +21,10 @@ Signed-off-by: Benjamin Marzinski create mode 100644 multipath/mpathconf.8 diff --git a/libmultipath/config.c b/libmultipath/config.c -index 183b319d..01f36a4f 100644 +index 3a374b3d..4544f484 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -968,6 +968,8 @@ int _init_config (const char *file, struct config *conf) +@@ -960,6 +960,8 @@ int _init_config (const char *file, struct config *conf) validate_pctable(conf->overrides, 0, file); } else { condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); @@ -34,10 +34,10 @@ index 183b319d..01f36a4f 100644 conf->blist_devnode = vector_alloc(); if (!conf->blist_devnode) { diff --git a/multipath/Makefile b/multipath/Makefile -index b3c2cc81..413294ef 100644 +index f70e64ec..9942d1a9 100644 --- a/multipath/Makefile +++ b/multipath/Makefile -@@ -22,6 +22,7 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so +@@ -24,6 +24,7 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so install: $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ @@ -45,7 +45,7 @@ index b3c2cc81..413294ef 100644 $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir) $(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir) $(Q)$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(udevrulesdir)/62-multipath.rules -@@ -31,6 +32,7 @@ install: +@@ -33,6 +34,7 @@ install: $(Q)$(INSTALL_PROGRAM) -m 644 tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/multipath.conf $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man8 $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/man8 @@ -53,7 +53,7 @@ index b3c2cc81..413294ef 100644 $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)/man5 $(Q)$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5 $(DESTDIR)$(mandir)/man5 ifneq ($(SCSI_DH_MODULES_PRELOAD),) -@@ -41,11 +43,13 @@ endif +@@ -43,11 +45,13 @@ endif uninstall: $(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) @@ -65,8 +65,8 @@ index b3c2cc81..413294ef 100644 $(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8 + $(Q)$(RM) $(DESTDIR)$(mandir)/man8/mpathconf.8 $(Q)$(RM) $(DESTDIR)$(mandir)/man5/$(EXEC).conf.5 + $(Q)$(RM) $(DESTDIR)$(tmpfilesdir)/multipath.conf - clean: dep_clean diff --git a/multipath/mpathconf b/multipath/mpathconf new file mode 100644 index 00000000..319664b1 diff --git a/0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch b/0047-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch similarity index 87% rename from 0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch rename to 0047-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch index 714a1bb..7714825 100644 --- a/0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +++ b/0047-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch @@ -15,12 +15,12 @@ multipathd.service Signed-off-by: Benjamin Marzinski --- multipath/main.c | 54 +++++++++++++++++++++++++++++++++-- - multipath/multipath.8 | 7 ++++- + multipath/multipath.8.in | 7 ++++- multipathd/multipathd.service | 1 + 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/multipath/main.c b/multipath/main.c -index 90f940f1..3549740a 100644 +index 46944589..47f89a0a 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -120,7 +120,7 @@ usage (char * progname) @@ -41,7 +41,7 @@ index 90f940f1..3549740a 100644 " -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" -@@ -447,6 +449,50 @@ static void cleanup_vecs(void) +@@ -448,6 +450,50 @@ static void cleanup_vecs(void) free_pathvec(vecs.pathvec, FREE_PATHS); } @@ -92,16 +92,16 @@ index 90f940f1..3549740a 100644 static int configure (struct config *conf, enum mpath_cmds cmd, enum devtypes dev_type, char *devpath) -@@ -842,7 +888,7 @@ main (int argc, char *argv[]) - conf->force_sync = 1; - if (atexit(cleanup_vecs)) +@@ -848,7 +894,7 @@ main (int argc, char *argv[]) condlog(1, "failed to register cleanup handler for vecs: %m"); + if (atexit(cleanup_bindings)) + condlog(1, "failed to register cleanup handler for bindings: %m"); - while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) { + while ((arg = getopt(argc, argv, ":aAdDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) { switch(arg) { case 'v': if (!isdigit(optarg[0])) { -@@ -913,6 +959,10 @@ main (int argc, char *argv[]) +@@ -919,6 +965,10 @@ main (int argc, char *argv[]) case 'T': cmd = CMD_DUMP_CONFIG; break; @@ -112,11 +112,11 @@ index 90f940f1..3549740a 100644 case 'h': usage(argv[0]); exit(RTVL_OK); -diff --git a/multipath/multipath.8 b/multipath/multipath.8 -index 88149d53..072a03ee 100644 ---- a/multipath/multipath.8 -+++ b/multipath/multipath.8 -@@ -63,7 +63,7 @@ multipath \- Device mapper target autoconfig. +diff --git a/multipath/multipath.8.in b/multipath/multipath.8.in +index 348eb220..82a7e68e 100644 +--- a/multipath/multipath.8.in ++++ b/multipath/multipath.8.in +@@ -64,7 +64,7 @@ multipath \- Device mapper target autoconfig. .B multipath .RB [\| \-v\ \c .IR level \|] @@ -125,7 +125,7 @@ index 88149d53..072a03ee 100644 . .LP .B multipath -@@ -145,6 +145,11 @@ device mapper, path checkers ...). +@@ -146,6 +146,11 @@ device mapper, path checkers ...). Add the WWID for the specified device to the WWIDs file. . .TP diff --git a/0008-RH-reset-default-find_mutipaths-value-to-off.patch b/0048-RH-reset-default-find_mutipaths-value-to-off.patch similarity index 96% rename from 0008-RH-reset-default-find_mutipaths-value-to-off.patch rename to 0048-RH-reset-default-find_mutipaths-value-to-off.patch index ea12464..432b070 100644 --- a/0008-RH-reset-default-find_mutipaths-value-to-off.patch +++ b/0048-RH-reset-default-find_mutipaths-value-to-off.patch @@ -12,7 +12,7 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h -index a5e9ea0c..514fd880 100644 +index d01f9712..ee2e13a9 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h @@ -23,7 +23,7 @@ diff --git a/0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch b/0049-RH-attempt-to-get-ANA-info-via-sysfs-first.patch similarity index 95% rename from 0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch rename to 0049-RH-attempt-to-get-ANA-info-via-sysfs-first.patch index 06233ff..1f94eb3 100644 --- a/0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch +++ b/0049-RH-attempt-to-get-ANA-info-via-sysfs-first.patch @@ -13,7 +13,7 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/libmultipath/prioritizers/ana.c b/libmultipath/prioritizers/ana.c -index b5c7873d..e139360c 100644 +index e9827dca..80a32aa3 100644 --- a/libmultipath/prioritizers/ana.c +++ b/libmultipath/prioritizers/ana.c @@ -24,6 +24,7 @@ @@ -68,7 +68,7 @@ index b5c7873d..e139360c 100644 static int get_ana_info(struct path * pp) { int rc; -@@ -210,8 +234,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args, +@@ -209,8 +233,11 @@ int getprio(struct path *pp, __attribute__((unused)) char *args) if (pp->fd < 0) rc = -ANA_ERR_NO_INFORMATION; diff --git a/0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch b/0050-RH-make-parse_vpd_pg83-match-scsi_id-output.patch similarity index 98% rename from 0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch rename to 0050-RH-make-parse_vpd_pg83-match-scsi_id-output.patch index 4e0b116..1906258 100644 --- a/0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch +++ b/0050-RH-make-parse_vpd_pg83-match-scsi_id-output.patch @@ -14,7 +14,7 @@ Signed-off-by: Benjamin Marzinski 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index 6865cd92..72825829 100644 +index 84ce5fe7..104fdd5a 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -1177,13 +1177,9 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len, diff --git a/0011-RH-add-scsi-device-handlers-to-modules-load.d.patch b/0051-RH-add-scsi-device-handlers-to-modules-load.d.patch similarity index 96% rename from 0011-RH-add-scsi-device-handlers-to-modules-load.d.patch rename to 0051-RH-add-scsi-device-handlers-to-modules-load.d.patch index 26b0d06..407b621 100644 --- a/0011-RH-add-scsi-device-handlers-to-modules-load.d.patch +++ b/0051-RH-add-scsi-device-handlers-to-modules-load.d.patch @@ -11,7 +11,7 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc -index 748911e2..c07bcb0c 100644 +index 72fd8d57..a49e9f5a 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -16,7 +16,7 @@ READLINE := diff --git a/0012-RH-compile-with-libreadline-support.patch b/0052-RH-compile-with-libreadline-support.patch similarity index 96% rename from 0012-RH-compile-with-libreadline-support.patch rename to 0052-RH-compile-with-libreadline-support.patch index df99295..c78d5c0 100644 --- a/0012-RH-compile-with-libreadline-support.patch +++ b/0052-RH-compile-with-libreadline-support.patch @@ -12,7 +12,7 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc -index c07bcb0c..e59313c6 100644 +index a49e9f5a..51b55196 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -12,7 +12,7 @@ diff --git a/0053-RH-Add-mpathcleanup.patch b/0053-RH-Add-mpathcleanup.patch new file mode 100644 index 0000000..9278829 --- /dev/null +++ b/0053-RH-Add-mpathcleanup.patch @@ -0,0 +1,186 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 7 Jul 2023 15:25:59 -0500 +Subject: [PATCH] RH: Add mpathcleanup + +mpathcleanup is a program that will remove a multipath device as well as +all of the scsi path devices that make it up. + +Signed-off-by: Benjamin Marzinski +--- + multipath/Makefile | 2 + + multipath/mpathcleanup | 145 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 147 insertions(+) + create mode 100755 multipath/mpathcleanup + +diff --git a/multipath/Makefile b/multipath/Makefile +index 9942d1a9..d281b501 100644 +--- a/multipath/Makefile ++++ b/multipath/Makefile +@@ -25,6 +25,7 @@ install: + $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) + $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + $(Q)$(INSTALL_PROGRAM) -m 755 mpathconf $(DESTDIR)$(bindir)/ ++ $(Q)$(INSTALL_PROGRAM) -m 755 mpathcleanup $(DESTDIR)$(bindir)/ + $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir) + $(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir) + $(Q)$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(udevrulesdir)/62-multipath.rules +@@ -46,6 +47,7 @@ endif + uninstall: + $(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) + $(Q)$(RM) $(DESTDIR)$(bindir)/mpathconf ++ $(Q)$(RM) $(DESTDIR)$(bindir)/mpathcleanup + $(Q)$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules + $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf + $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf +diff --git a/multipath/mpathcleanup b/multipath/mpathcleanup +new file mode 100755 +index 00000000..6fd921e4 +--- /dev/null ++++ b/multipath/mpathcleanup +@@ -0,0 +1,145 @@ ++#!/bin/bash ++# ++# Copyright (C) 2023 Red Hat, Inc. All rights reserved. ++# ++# This file is part of the device-mapper-multipath package. ++# ++# This copyrighted material is made available to anyone wishing to use, ++# modify, copy, or redistribute it subject to the terms and conditions ++# of the GNU General Public License v.2. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software Foundation, ++# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++unset PROGRAM FLUSH DEVICE DEVNAME MAJOR MINOR PATHDEVS PATHDEV HAVE_MULTIPATHD QUEUEING ++ ++function usage ++{ ++ echo "usage: $PROGRAM [-h] [--flush] " ++ echo "" ++ echo "remove a multipath device and its scsi path devices" ++ echo "" ++ echo "options:" ++ echo " -h, --help show this help message and exit" ++ echo " --flush disable queuing on the multipath device and" ++ echo " flush the path devices before removing" ++} ++ ++function parse_args ++{ ++ while [ -n "$1" ]; do ++ case $1 in ++ --flush) ++ FLUSH=1 ++ shift ++ ;; ++ --help | -h) ++ usage ++ exit 1 ++ ;; ++ *) ++ if [ -n "$DEVICE" ]; then ++ usage ++ exit 1 ++ fi ++ DEVICE=$1 ++ shift ++ ;; ++ esac ++ done ++} ++ ++function validate_device ++{ ++ if [ -z "$DEVICE" ]; then ++ usage ++ exit 1 ++ fi ++ if [[ "$DEVICE" =~ ^[[:digit:]]+:[[:digit:]]+$ ]]; then ++ MAJOR=${DEVICE%%:*} ++ MINOR=${DEVICE##*:} ++ DEVNAME=`dmsetup ls --target multipath | grep "($MAJOR, $MINOR)$" | awk '{print $1}'` ++ else ++ DEVNAME=`dmsetup ls --target multipath | awk '{print $1}' | grep "^$DEVICE$"` ++ fi ++ if [ -z "$DEVNAME" ]; then ++ DEVNAME=`multipath -v 1 -l $DEVICE 2>/dev/null` ++ if [ -z "$DEVNAME" ]; then ++ echo "$DEVICE is not a multipath device" ++ exit 1 ++ fi ++ # verify that this is not a native nvme multipath device ++ dmsetup ls --target multipath | awk '{print $1}' | grep -q "^$DEVNAME$" ++ if test $? -eq 1; then ++ echo "$DEVICE is not a device-mapper multipath device" ++ exit 1 ++ fi ++ fi ++ if [ -z "$MINOR" ]; then ++ MINOR=`dmsetup info -c --noheadings -o minor $DEVNAME` ++ fi ++} ++ ++function get_paths ++{ ++ PATHDEVS=`ls /sys/block/dm-$MINOR/slaves` ++ for PATHDEV in $PATHDEVS; do ++ if [[ ! "$PATHDEV" =~ ^sd[a-z]+$ ]]; then ++ echo "$PATHDEV is not a scsi device. $PROGRAM only works with scsi devices" ++ exit 1 ++ fi ++ done ++} ++ ++function remove_devs ++{ ++ pidof multipathd > /dev/null ++ HAVE_MULTIPATHD=$? ++ multipath -v2 -l "$DEVNAME" | grep features | grep -q queue_if_no_path ++ QUEUEING=$? ++ if [ -n "$FLUSH" ] && [ "$QUEUEING" -eq 0 ]; then ++ if test $HAVE_MULTIPATHD -eq 0; then ++ multipathd disablequeueing map "$DEVNAME" > /dev/null ++ else ++ dmsetup message "$DEVNAME" 0 fail_if_no_path ++ fi ++ sleep 1 ++ fi ++ if test $HAVE_MULTIPATHD -eq 0; then ++ multipath -f "$DEVNAME" ++ else ++ multipathd -Df "$DEVNAME" ++ fi ++ if test $? -eq 1; then ++ echo "$DEVICE cannot be removed" ++ exit 1 ++ fi ++ for PATHDEV in $PATHDEVS; do ++ if [ -n "$FLUSH" ]; then ++ blockdev --flushbufs /dev/"$PATHDEV" ++ fi ++ echo 1 > /sys/block/"$PATHDEV"/device/delete ++ done ++} ++ ++function verify_removal ++{ ++ multipath -v 1 -d $DEVNAME | grep -q "^$DEVNAME$" ++ if test $? -eq 0; then ++ echo "$DEVICE removed but path devices still exist" ++ exit 1 ++ fi ++ multipath -v 1 -l $DEVNAME | grep -q "^$DEVNAME$" ++ if test $? -eq 0; then ++ echo "$DEVICE removal succeeded, but device still exists" ++ exit 1 ++ fi ++} ++ ++PROGRAM="$0" ++parse_args "$@" ++validate_device ++get_paths ++remove_devs ++verify_removal diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index 268e4b9..30c0bbf 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,27 +1,68 @@ Name: device-mapper-multipath -Version: 0.9.5 -Release: 2%{?dist} +Version: 0.9.6 +Release: 1%{?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 -L https://github.com/opensvc/multipath-tools/archive/0.9.5.tar.gz -o multipath-tools-0.9.5.tgz -Source0: multipath-tools-0.9.5.tgz +# curl -L https://github.com/opensvc/multipath-tools/archive/0.9.6.tar.gz -o multipath-tools-0.9.6.tgz +Source0: multipath-tools-0.9.6.tgz Source1: multipath.conf -Patch0001: 0001-RH-fixup-udev-rules-for-redhat.patch -Patch0002: 0002-RH-Remove-the-property-blacklist-exception-builtin.patch -Patch0003: 0003-RH-don-t-start-without-a-config-file.patch -Patch0004: 0004-RH-Fix-nvme-function-missing-argument.patch -Patch0005: 0005-RH-use-rpm-optflags-if-present.patch -Patch0006: 0006-RH-add-mpathconf.patch -Patch0007: 0007-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch -Patch0008: 0008-RH-reset-default-find_mutipaths-value-to-off.patch -Patch0009: 0009-RH-attempt-to-get-ANA-info-via-sysfs-first.patch -Patch0010: 0010-RH-make-parse_vpd_pg83-match-scsi_id-output.patch -Patch0011: 0011-RH-add-scsi-device-handlers-to-modules-load.d.patch -Patch0012: 0012-RH-compile-with-libreadline-support.patch +Patch0001: 0001-libmultipath-sysfs_set_scsi_tmo-do-nothing-for-ACT_D.patch +Patch0002: 0002-libmultipath-add-alias_already_taken.patch +Patch0003: 0003-libmultipath-unify-use_existing_alias-and-get_user_f.patch +Patch0004: 0004-libmultipath-never-allocate-an-alias-that-s-already-.patch +Patch0005: 0005-libmultipath-lookup_binding-add-comment-about-the-al.patch +Patch0006: 0006-multipath-tools-test-simplify-debugging-for-condlog-.patch +Patch0007: 0007-multipath-tools-tests-add-tests-for-get_user_friendl.patch +Patch0008: 0008-multipath-tools-test-consistent-use-of-macros-in-ali.patch +Patch0009: 0009-multipath-tools-tests-convert-mock_-failed-used-_ali.patch +Patch0010: 0010-multipath-tools-test-use-mock_bindings_file-consiste.patch +Patch0011: 0011-libmultipath-add-global-variable-for-current-binding.patch +Patch0012: 0012-libmultipath-rename-fix_bindings_file-to-update_bind.patch +Patch0013: 0013-libmultipath-alias.c-move-bindings-related-code-up.patch +Patch0014: 0014-libmultipath-update_bindings_file-take-filename-argu.patch +Patch0015: 0015-libmultipath-update_bindings_file-use-a-single-write.patch +Patch0016: 0016-libmultipath-update_bindings_file-don-t-log-temp-fil.patch +Patch0017: 0017-libmultipath-alias.c-factor-out-read_binding.patch +Patch0018: 0018-libmultipath-keep-bindings-in-memory.patch +Patch0019: 0019-multipath-tools-tests-fix-alias-tests.patch +Patch0020: 0020-libmultipath-dm_get_uuid-return-emtpy-UUID-for-non-e.patch +Patch0021: 0021-libmultipath-adapt-to-new-semantics-of-dm_get_uuid.patch +Patch0022: 0022-libmultipath-sort-aliases-by-length-and-strcmp.patch +Patch0023: 0023-multipath-tools-tests-fix-alias-test-after-sort-orde.patch +Patch0024: 0024-libmultipath-simplify-get_free_id-assuming-total-ord.patch +Patch0025: 0025-multipath-tools-tests-adapt-alias-tests-for-total-or.patch +Patch0026: 0026-multipath-tools-tests-add-test-for-ordering-of-bindi.patch +Patch0027: 0027-multipathd-watch-bindings-file-with-inotify-timestam.patch +Patch0028: 0028-multipath-tools-tests-mock-pthread_mutex_-lock-unloc.patch +Patch0029: 0029-multipath-tools-Makefile-sanitize-paths-for-configur.patch +Patch0030: 0030-multipath-tools-add-compile-time-configuration-for-e.patch +Patch0031: 0031-multipath-tools-man-pages-generate-with-correct-path.patch +Patch0032: 0032-libdmmp-Makefile-fix-bug-in-install-section.patch +Patch0033: 0033-multipath-tools-README.md-improve-documentation-for-.patch +Patch0034: 0034-libmultipath-print-built-in-values-for-deprecated-op.patch +Patch0035: 0035-multipath-add-a-missing-newline.patch +Patch0036: 0036-multipath-tools-allow-prefixes-with-and-w-o-trailing.patch +Patch0037: 0037-libmultipath-deprecate-bindings_file-wwids_file-prke.patch +Patch0038: 0038-libmultipath-avoid-Warray-bounds-error-in-uatomic-op.patch +Patch0039: 0039-multipath-tools-fix-spelling.patch +Patch0040: 0040-multipathd-Added-support-to-handle-FPIN-Li-events-fo.patch +Patch0041: 0041-RH-fixup-udev-rules-for-redhat.patch +Patch0042: 0042-RH-Remove-the-property-blacklist-exception-builtin.patch +Patch0043: 0043-RH-don-t-start-without-a-config-file.patch +Patch0044: 0044-RH-Fix-nvme-function-missing-argument.patch +Patch0045: 0045-RH-use-rpm-optflags-if-present.patch +Patch0046: 0046-RH-add-mpathconf.patch +Patch0047: 0047-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +Patch0048: 0048-RH-reset-default-find_mutipaths-value-to-off.patch +Patch0049: 0049-RH-attempt-to-get-ANA-info-via-sysfs-first.patch +Patch0050: 0050-RH-make-parse_vpd_pg83-match-scsi_id-output.patch +Patch0051: 0051-RH-add-scsi-device-handlers-to-modules-load.d.patch +Patch0052: 0052-RH-compile-with-libreadline-support.patch +Patch0053: 0053-RH-Add-mpathcleanup.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -108,7 +149,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.9.5 -p1 +%autosetup -n multipath-tools-0.9.6 -p1 cp %{SOURCE1} . %build @@ -158,6 +199,7 @@ fi %{_sbindir}/multipathd %{_sbindir}/multipathc %{_sbindir}/mpathconf +%{_sbindir}/mpathcleanup %{_sbindir}/mpathpersist %{_unitdir}/multipathd.service %{_unitdir}/multipathd.socket @@ -230,6 +272,13 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Fri Sep 22 2023 Benjamin Marzinski - 0.9.6-1 +- Update to the head of the upstream staging branch +- Rename redhat patches + * Previous patches 0001-0012 are now patches 0041-0052 +- Add 0053-RH-Add-mpathcleanup.patch + * add mpathcleanup program + * Wed Jul 19 2023 Fedora Release Engineering - 0.9.5-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild diff --git a/sources b/sources index ece6ffe..5d41f65 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (multipath-tools-0.9.5.tgz) = 39c2e5d45542c6076eb3b17b9994629b4c1f74347aa43e0119001fa2d07d3a606fd5e617962906a11b313afb37a115bd8eec2ef24447e980e61b5900625f9146 +SHA512 (multipath-tools-0.9.6.tgz) = 17d2b46ead9df6826b3266035bc077a2f4d4bea01e2cd59e32d3917cda40c320f11bc8572da7ba66251e312b46d9be317737069193d481d202d49f9aa5fd71b9 SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942