From 942c9b6ed83c2a0f9ce17293245693fa545e5bfa Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 11 Sep 2019 17:06:10 -0500 Subject: [PATCH] device-mapper-multipath-0.8.2-1 Update Source to upstream version 0.8.2 * Previoud patches 0001-0017 & 0027 are included in this commit Rename files * Previous patches 0018-0026 & 0028 are not patches 0021-0030 Add 0001-libmultipath-make-vector_foreach_slot_backwards-work.patch Add 0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch Add 0003-tests-add-path-grouping-policy-unit-tests.patch Add 0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch Add 0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch Add 0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch Add 0007-libmultipath-consolidate-group_by_-functions.patch Add 0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch Add 0009-libmultipath-make-group_paths-handle-marginal-paths.patch Add 0010-tests-add-tests-for-grouping-marginal-paths.patch Add 0011-libmultipath-add-marginal_pathgroups-config-option.patch Add 0012-libmutipath-deprecate-delay_-_checks.patch Add 0013-multipathd-use-marginal_pathgroups.patch Add 0014-multipath-update-man-pages.patch * The above 13 patches add the marinal_pathgroups option Add 0015-multipath.conf-add-enable_foreign-parameter.patch Add 0016-multipath.conf.5-document-foreign-library-support.patch * The above 2 patches add the enable_foreign option Add 0017-mpathpersist-remove-broken-unused-code.patch Add 0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch Add 0019-mpathpersist-fix-leaks.patch Add 0020-libmultipath-fix-mpcontext-initialization.patch * The above 20 patches have been submitted upstream --- .gitignore | 1 + ...sable-user_friendly_names-for-NetApp.patch | 31 - ...e-vector_foreach_slot_backwards-work.patch | 31 + ...-marginal-paths-and-groups-infrastru.patch | 301 +++++++ ...dle-existing-paths-in-marginal_path-.patch | 49 -- ...eanup-marginal-paths-checking-timers.patch | 70 -- ...-add-path-grouping-policy-unit-tests.patch | 749 ++++++++++++++++++ ...d-wrapper-function-around-pgpolicyfn.patch | 260 ++++++ ...h-fix-marginal-paths-queueing-errors.patch | 176 ---- ...h-fix-marginal_paths-nr_active-check.patch | 30 - ...olicy-tests-to-work-with-group_paths.patch | 420 ++++++++++ ...-double-free-in-pgpolicyfn-error-pat.patch | 79 ++ ...tipathd-Fix-miscounting-active-paths.patch | 92 --- ...path-consolidate-group_by_-functions.patch | 253 ++++++ ...ultipathd-ignore-failed-wwid-recheck.patch | 71 -- ...-make-pgpolicyfn-take-a-paths-vector.patch | 174 ++++ ...inue-to-use-old-state-on-PATH_PENDIN.patch | 47 -- ...ke-group_paths-handle-marginal-paths.patch | 185 +++++ ...pdate_path_groups-instead-of-reload_.patch | 76 -- ...conf-add-missing-options-to-man-page.patch | 56 -- ...dd-tests-for-grouping-marginal-paths.patch | 701 ++++++++++++++++ ...-get_uid-fallback-code-for-NVMe-devi.patch | 90 --- ...dd-marginal_pathgroups-config-option.patch | 642 +++++++++++++++ ...bmulitpath-cleanup-uid_fallback-code.patch | 129 --- ...libmutipath-deprecate-delay_-_checks.patch | 381 +++++++++ ...e-changed-wwids-by-removal-and-addit.patch | 83 -- 0013-multipathd-use-marginal_pathgroups.patch | 111 +++ 0014-multipath-update-man-pages.patch | 99 +++ ...d-remove-wwid_changed-path-attribute.patch | 46 -- ...th.conf-add-enable_foreign-parameter.patch | 230 ++++++ ...tipathd-ignore-disable_changed_wwids.patch | 98 --- ...f.5-document-foreign-library-support.patch | 75 ++ ...-use-fallback-code-after-getting-wwi.patch | 135 ---- ...h-silence-dm_is_mpath-error-messages.patch | 31 - ...athpersist-remove-broken-unused-code.patch | 51 ++ ...path-EMC-PowerMax-NVMe-device-config.patch | 33 + 0019-mpathpersist-fix-leaks.patch | 132 +++ ...ltipath-fix-mpcontext-initialization.patch | 232 ++++++ ... 0021-RH-fixup-udev-rules-for-redhat.patch | 10 +- ...property-blacklist-exception-builtin.patch | 68 +- ...RH-don-t-start-without-a-config-file.patch | 16 +- ... 0024-RH-use-rpm-optflags-if-present.patch | 6 +- ...hconf.patch => 0025-RH-add-mpathconf.patch | 12 +- ...om-kernel-cmdline-mpath.wwids-with-A.patch | 38 +- 0027-Fix-systemd-version-detection.patch | 27 - ...-on-invalid-regex-instead-of-failing.patch | 18 +- ...-default-find_mutipaths-value-to-off.patch | 6 +- ...0029-RH-Fix-nvme-compilation-warning.patch | 4 +- ...empt-to-get-ANA-info-via-sysfs-first.patch | 4 +- device-mapper-multipath.spec | 97 ++- sources | 2 +- 51 files changed, 5309 insertions(+), 1449 deletions(-) delete mode 100644 0001-BZ-1668693-disable-user_friendly_names-for-NetApp.patch create mode 100644 0001-libmultipath-make-vector_foreach_slot_backwards-work.patch create mode 100644 0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch delete mode 100644 0002-libmultipath-handle-existing-paths-in-marginal_path-.patch delete mode 100644 0003-multipathd-cleanup-marginal-paths-checking-timers.patch create mode 100644 0003-tests-add-path-grouping-policy-unit-tests.patch create mode 100644 0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch delete mode 100644 0004-libmultipath-fix-marginal-paths-queueing-errors.patch delete mode 100644 0005-libmultipath-fix-marginal_paths-nr_active-check.patch create mode 100644 0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch create mode 100644 0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch delete mode 100644 0006-multipathd-Fix-miscounting-active-paths.patch create mode 100644 0007-libmultipath-consolidate-group_by_-functions.patch delete mode 100644 0007-multipathd-ignore-failed-wwid-recheck.patch create mode 100644 0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch delete mode 100644 0008-libmutipath-continue-to-use-old-state-on-PATH_PENDIN.patch create mode 100644 0009-libmultipath-make-group_paths-handle-marginal-paths.patch delete mode 100644 0009-multipathd-use-update_path_groups-instead-of-reload_.patch delete mode 100644 0010-multipath.conf-add-missing-options-to-man-page.patch create mode 100644 0010-tests-add-tests-for-grouping-marginal-paths.patch delete mode 100644 0011-libmultipath-add-get_uid-fallback-code-for-NVMe-devi.patch create mode 100644 0011-libmultipath-add-marginal_pathgroups-config-option.patch delete mode 100644 0012-libmulitpath-cleanup-uid_fallback-code.patch create mode 100644 0012-libmutipath-deprecate-delay_-_checks.patch delete mode 100644 0013-multipathd-handle-changed-wwids-by-removal-and-addit.patch create mode 100644 0013-multipathd-use-marginal_pathgroups.patch create mode 100644 0014-multipath-update-man-pages.patch delete mode 100644 0014-multipathd-remove-wwid_changed-path-attribute.patch create mode 100644 0015-multipath.conf-add-enable_foreign-parameter.patch delete mode 100644 0015-multipathd-ignore-disable_changed_wwids.patch create mode 100644 0016-multipath.conf.5-document-foreign-library-support.patch delete mode 100644 0016-multipathd-Don-t-use-fallback-code-after-getting-wwi.patch delete mode 100644 0017-libmultipath-silence-dm_is_mpath-error-messages.patch create mode 100644 0017-mpathpersist-remove-broken-unused-code.patch create mode 100644 0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch create mode 100644 0019-mpathpersist-fix-leaks.patch create mode 100644 0020-libmultipath-fix-mpcontext-initialization.patch rename 0018-RH-fixup-udev-rules-for-redhat.patch => 0021-RH-fixup-udev-rules-for-redhat.patch (92%) rename 0019-RH-Remove-the-property-blacklist-exception-builtin.patch => 0022-RH-Remove-the-property-blacklist-exception-builtin.patch (57%) rename 0020-RH-don-t-start-without-a-config-file.patch => 0023-RH-don-t-start-without-a-config-file.patch (91%) rename 0021-RH-use-rpm-optflags-if-present.patch => 0024-RH-use-rpm-optflags-if-present.patch (92%) rename 0022-RH-add-mpathconf.patch => 0025-RH-add-mpathconf.patch (98%) rename 0023-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch => 0026-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch (82%) delete mode 100644 0027-Fix-systemd-version-detection.patch rename 0024-RH-warn-on-invalid-regex-instead-of-failing.patch => 0027-RH-warn-on-invalid-regex-instead-of-failing.patch (88%) rename 0025-RH-reset-default-find_mutipaths-value-to-off.patch => 0028-RH-reset-default-find_mutipaths-value-to-off.patch (88%) rename 0026-RH-Fix-nvme-compilation-warning.patch => 0029-RH-Fix-nvme-compilation-warning.patch (88%) rename 0028-RH-attempt-to-get-ANA-info-via-sysfs-first.patch => 0030-RH-attempt-to-get-ANA-info-via-sysfs-first.patch (96%) diff --git a/.gitignore b/.gitignore index e183506..5bb1f09 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ multipath-tools-091027.tar.gz /multipath-tools-17a6101.tgz /multipath-tools-2df6110.tgz /multipath-tools-0.8.0.tgz +/multipath-tools-0.8.2.tgz diff --git a/0001-BZ-1668693-disable-user_friendly_names-for-NetApp.patch b/0001-BZ-1668693-disable-user_friendly_names-for-NetApp.patch deleted file mode 100644 index 491a21d..0000000 --- a/0001-BZ-1668693-disable-user_friendly_names-for-NetApp.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Thu, 24 Jan 2019 14:09:23 -0600 -Subject: [PATCH] BZ 1668693: disable user_friendly_names for NetApp - -NetApp has tools that rely on devices using WWID names. To avoid -breaking these, NetApp devices should continue to use WWID names, even -if the default config is set to enable user_friendly_names. If users -want to use user_friendly_names on NetApp devices, the must specifically -override the device config. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/hwtable.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c -index d3a8d9b..8776411 100644 ---- a/libmultipath/hwtable.c -+++ b/libmultipath/hwtable.c -@@ -719,6 +719,7 @@ static struct hwentry default_hw[] = { - .flush_on_last_del = FLUSH_ENABLED, - .dev_loss = MAX_DEV_LOSS_TMO, - .prio_name = PRIO_ONTAP, -+ .user_friendly_names = USER_FRIENDLY_NAMES_OFF, - }, - { - /* --- -2.17.2 - diff --git a/0001-libmultipath-make-vector_foreach_slot_backwards-work.patch b/0001-libmultipath-make-vector_foreach_slot_backwards-work.patch new file mode 100644 index 0000000..4533e32 --- /dev/null +++ b/0001-libmultipath-make-vector_foreach_slot_backwards-work.patch @@ -0,0 +1,31 @@ +From 1dd540c6bf5bac70d5d61b869ac652523b91ee2b Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 24 May 2019 17:30:07 -0500 +Subject: [PATCH] libmultipath: make vector_foreach_slot_backwards work as + expected + +All of the code that uses vector_foreach_slot_backwards() treats "i" as +the index of the entry "p", but the way it was coded, that wasn't the +case. "i" was the number of the entry counting from 1, not 0. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/vector.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmultipath/vector.h b/libmultipath/vector.h +index 41d2b896..344dffd5 100644 +--- a/libmultipath/vector.h ++++ b/libmultipath/vector.h +@@ -40,7 +40,7 @@ typedef struct _vector *vector; + #define vector_foreach_slot_after(v,p,i) \ + for (; (v) && i < VECTOR_SIZE(v) && ((p) = (v)->slot[i]); i++) + #define vector_foreach_slot_backwards(v,p,i) \ +- for (i = VECTOR_SIZE(v); i > 0 && ((p) = (v)->slot[i-1]); i--) ++ for (i = VECTOR_SIZE(v) - 1; (int)i >= 0 && ((p) = (v)->slot[i]); i--) + + #define identity(x) (x) + /* +-- +2.17.2 + diff --git a/0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch b/0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch new file mode 100644 index 0000000..cf96b2f --- /dev/null +++ b/0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch @@ -0,0 +1,301 @@ +From 668bc6e2f142ed81936329de144f57026c90edf2 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 1 Jul 2019 15:19:29 -0500 +Subject: [PATCH] libmultipath: add marginal paths and groups infrastructure + +This commit adds a marginal variable ot the paths and pathgroups structs. +The marginal paths variable can be set by + +multipathd path setmarginal + +and cleared by + +multipathd path unsetmarginal + +All of the marginal paths on a multipath device can be cleared by + +multipathd map unsetmarginal + +Currently, the marginal variable of a pathgroup will not change. This +will be added by a future commit. The marginal state of a path or +pathgroup is printable with the %M wildcard, and is displayed in the +json output. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/print.c | 18 ++++++++ + libmultipath/print.h | 6 ++- + libmultipath/structs.h | 2 + + multipathd/cli.c | 5 +++ + multipathd/cli.h | 4 ++ + multipathd/cli_handlers.c | 91 +++++++++++++++++++++++++++++++++++++++ + multipathd/cli_handlers.h | 3 ++ + multipathd/main.c | 3 ++ + 8 files changed, 130 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/print.c b/libmultipath/print.c +index fc40b0f0..907469ad 100644 +--- a/libmultipath/print.c ++++ b/libmultipath/print.c +@@ -502,6 +502,14 @@ snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp) + } + } + ++static int ++snprint_pg_marginal (char * buff, size_t len, const struct pathgroup * pgp) ++{ ++ if (pgp->marginal) ++ return snprintf(buff, len, "marginal"); ++ return snprintf(buff, len, "normal"); ++} ++ + static int + snprint_path_size (char * buff, size_t len, const struct path * pp) + { +@@ -672,6 +680,14 @@ snprint_path_protocol(char * buff, size_t len, const struct path * pp) + } + } + ++int ++snprint_path_marginal(char * buff, size_t len, const struct path * pp) ++{ ++ if (pp->marginal) ++ return snprintf(buff, len, "marginal"); ++ return snprintf(buff, len, "normal"); ++} ++ + struct multipath_data mpd[] = { + {'n', "name", 0, snprint_name}, + {'w', "uuid", 0, snprint_multipath_uuid}, +@@ -713,6 +729,7 @@ struct path_data pd[] = { + {'p', "pri", 0, snprint_pri}, + {'S', "size", 0, snprint_path_size}, + {'z', "serial", 0, snprint_path_serial}, ++ {'M', "marginal_st", 0, snprint_path_marginal}, + {'m', "multipath", 0, snprint_path_mpp}, + {'N', "host WWNN", 0, snprint_host_wwnn}, + {'n', "target WWNN", 0, snprint_tgt_wwnn}, +@@ -729,6 +746,7 @@ struct pathgroup_data pgd[] = { + {'s', "selector", 0, snprint_pg_selector}, + {'p', "pri", 0, snprint_pg_pri}, + {'t', "dm_st", 0, snprint_pg_state}, ++ {'M', "marginal_st", 0, snprint_pg_marginal}, + {0, NULL, 0 , NULL} + }; + +diff --git a/libmultipath/print.h b/libmultipath/print.h +index e2fb865c..7e36ec63 100644 +--- a/libmultipath/print.h ++++ b/libmultipath/print.h +@@ -50,7 +50,8 @@ + #define PRINT_JSON_GROUP "{\n" \ + " \"selector\" : \"%s\",\n" \ + " \"pri\" : %p,\n" \ +- " \"dm_st\" : \"%t\"," ++ " \"dm_st\" : \"%t\",\n" \ ++ " \"marginal_st\" : \"%M\"," + + #define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n" + +@@ -66,7 +67,8 @@ + " \"target_wwnn\" : \"%n\",\n" \ + " \"host_wwpn\" : \"%R\",\n" \ + " \"target_wwpn\" : \"%r\",\n" \ +- " \"host_adapter\" : \"%a\"" ++ " \"host_adapter\" : \"%a\",\n" \ ++ " \"marginal_st\" : \"%M\"" + + #define MAX_LINE_LEN 80 + #define MAX_LINES 64 +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 7879d763..1a3d827b 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -289,6 +289,7 @@ struct path { + int io_err_pathfail_cnt; + int io_err_pathfail_starttime; + int find_multipaths_timeout; ++ int marginal; + /* configlet pointers */ + vector hwe; + struct gen_path generic_path; +@@ -403,6 +404,7 @@ struct pathgroup { + int status; + int priority; + int enabled_paths; ++ int marginal; + vector paths; + struct multipath *mpp; + struct gen_pathgroup generic_pg; +diff --git a/multipathd/cli.c b/multipathd/cli.c +index 17795b61..800c0fbe 100644 +--- a/multipathd/cli.c ++++ b/multipathd/cli.c +@@ -215,6 +215,8 @@ load_keys (void) + r += add_key(keys, "unsetprkey", UNSETPRKEY, 0); + r += add_key(keys, "key", KEY, 1); + r += add_key(keys, "local", LOCAL, 0); ++ r += add_key(keys, "setmarginal", SETMARGINAL, 0); ++ r += add_key(keys, "unsetmarginal", UNSETMARGINAL, 0); + + + if (r) { +@@ -589,6 +591,9 @@ cli_init (void) { + add_handler(UNSETPRKEY+MAP, NULL); + add_handler(FORCEQ+DAEMON, NULL); + add_handler(RESTOREQ+DAEMON, NULL); ++ add_handler(SETMARGINAL+PATH, NULL); ++ add_handler(UNSETMARGINAL+PATH, NULL); ++ add_handler(UNSETMARGINAL+MAP, NULL); + + return 0; + } +diff --git a/multipathd/cli.h b/multipathd/cli.h +index 32dcffac..fdfb9aed 100644 +--- a/multipathd/cli.h ++++ b/multipathd/cli.h +@@ -45,6 +45,8 @@ enum { + __UNSETPRKEY, + __KEY, + __LOCAL, ++ __SETMARGINAL, ++ __UNSETMARGINAL, + }; + + #define LIST (1 << __LIST) +@@ -89,6 +91,8 @@ enum { + #define UNSETPRKEY (1ULL << __UNSETPRKEY) + #define KEY (1ULL << __KEY) + #define LOCAL (1ULL << __LOCAL) ++#define SETMARGINAL (1ULL << __SETMARGINAL) ++#define UNSETMARGINAL (1ULL << __UNSETMARGINAL) + + #define INITIAL_REPLY_LEN 1200 + +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 4c32d953..8a899049 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -1537,3 +1537,94 @@ cli_setprkey(void * v, char ** reply, int * len, void * data) + + return ret; + } ++ ++int cli_set_marginal(void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ char * param = get_keyparam(v, PATH); ++ struct path * pp; ++ ++ param = convert_dev(param, 1); ++ pp = find_path_by_dev(vecs->pathvec, param); ++ ++ if (!pp) ++ pp = find_path_by_devt(vecs->pathvec, param); ++ ++ if (!pp || !pp->mpp || !pp->mpp->alias) ++ return 1; ++ ++ condlog(2, "%s: set marginal path %s (operator)", ++ pp->mpp->alias, pp->dev_t); ++ if (pp->mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, failing set marginal", ++ pp->mpp->alias); ++ return 1; ++ } ++ pp->marginal = 1; ++ ++ return update_path_groups(pp->mpp, vecs, 0); ++} ++ ++int cli_unset_marginal(void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ char * param = get_keyparam(v, PATH); ++ struct path * pp; ++ ++ param = convert_dev(param, 1); ++ pp = find_path_by_dev(vecs->pathvec, param); ++ ++ if (!pp) ++ pp = find_path_by_devt(vecs->pathvec, param); ++ ++ if (!pp || !pp->mpp || !pp->mpp->alias) ++ return 1; ++ ++ condlog(2, "%s: unset marginal path %s (operator)", ++ pp->mpp->alias, pp->dev_t); ++ if (pp->mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, " ++ "failing unset marginal", pp->mpp->alias); ++ return 1; ++ } ++ pp->marginal = 0; ++ ++ return update_path_groups(pp->mpp, vecs, 0); ++} ++ ++int cli_unset_all_marginal(void * v, char ** reply, int * len, void * data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ char * mapname = get_keyparam(v, MAP); ++ struct multipath *mpp; ++ struct pathgroup * pgp; ++ struct path * pp; ++ unsigned int i, j; ++ int minor; ++ ++ mapname = convert_dev(mapname, 0); ++ condlog(2, "%s: unset all marginal paths (operator)", ++ mapname); ++ ++ if (sscanf(mapname, "dm-%d", &minor) == 1) ++ mpp = find_mp_by_minor(vecs->mpvec, minor); ++ else ++ mpp = find_mp_by_alias(vecs->mpvec, mapname); ++ ++ if (!mpp) { ++ condlog(0, "%s: invalid map name. " ++ "cannot unset marginal paths", mapname); ++ return 1; ++ } ++ if (mpp->wait_for_udev) { ++ condlog(2, "%s: device not fully created, " ++ "failing unset all marginal", mpp->alias); ++ return 1; ++ } ++ ++ vector_foreach_slot (mpp->pg, pgp, i) ++ vector_foreach_slot (pgp->paths, pp, j) ++ pp->marginal = 0; ++ ++ return update_path_groups(mpp, vecs, 0); ++} +diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h +index edbdf063..0f451064 100644 +--- a/multipathd/cli_handlers.h ++++ b/multipathd/cli_handlers.h +@@ -49,3 +49,6 @@ int cli_unsetprstatus(void * v, char ** reply, int * len, void * data); + int cli_getprkey(void * v, char ** reply, int * len, void * data); + int cli_setprkey(void * v, char ** reply, int * len, void * data); + int cli_unsetprkey(void * v, char ** reply, int * len, void * data); ++int cli_set_marginal(void * v, char ** reply, int * len, void * data); ++int cli_unset_marginal(void * v, char ** reply, int * len, void * data); ++int cli_unset_all_marginal(void * v, char ** reply, int * len, void * data); +diff --git a/multipathd/main.c b/multipathd/main.c +index 7a5cd115..7db15736 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1609,6 +1609,9 @@ uxlsnrloop (void * ap) + set_handler_callback(GETPRKEY+MAP, cli_getprkey); + set_handler_callback(SETPRKEY+MAP+KEY, cli_setprkey); + set_handler_callback(UNSETPRKEY+MAP, cli_unsetprkey); ++ set_handler_callback(SETMARGINAL+PATH, cli_set_marginal); ++ set_handler_callback(UNSETMARGINAL+PATH, cli_unset_marginal); ++ set_handler_callback(UNSETMARGINAL+MAP, cli_unset_all_marginal); + + umask(077); + uxsock_listen(&uxsock_trigger, ux_sock, ap); +-- +2.17.2 + diff --git a/0002-libmultipath-handle-existing-paths-in-marginal_path-.patch b/0002-libmultipath-handle-existing-paths-in-marginal_path-.patch deleted file mode 100644 index 93a3d7c..0000000 --- a/0002-libmultipath-handle-existing-paths-in-marginal_path-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Fri, 25 Jan 2019 16:45:26 -0600 -Subject: [PATCH] libmultipath: handle existing paths in marginal_path enqueue - -If the path that enqueue_io_err_stat_by_path() is trying to add -is already on the list, just return success. There's no reason -to fail in this case. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/io_err_stat.c | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c -index 02b1453..1cb3ffe 100644 ---- a/libmultipath/io_err_stat.c -+++ b/libmultipath/io_err_stat.c -@@ -254,7 +254,6 @@ static void free_io_err_pathvec(struct io_err_stat_pathvec *p) - * return value - * 0: enqueue OK - * 1: fails because of internal error -- * 2: fails because of existing already - */ - static int enqueue_io_err_stat_by_path(struct path *path) - { -@@ -264,7 +263,7 @@ static int enqueue_io_err_stat_by_path(struct path *path) - p = find_err_path_by_dev(paths->pathvec, path->dev); - if (p) { - pthread_mutex_unlock(&paths->mutex); -- return 2; -+ return 0; - } - pthread_mutex_unlock(&paths->mutex); - -@@ -418,9 +417,8 @@ int hit_io_err_recheck_time(struct path *pp) - io_err_stat_log(3, "%s: enqueue fails, to recover", - pp->dev); - goto recover; -- } else if (!r) { -+ } else - pp->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; -- } - } - - return 1; --- -2.17.2 - diff --git a/0003-multipathd-cleanup-marginal-paths-checking-timers.patch b/0003-multipathd-cleanup-marginal-paths-checking-timers.patch deleted file mode 100644 index ece5218..0000000 --- a/0003-multipathd-cleanup-marginal-paths-checking-timers.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Fri, 25 Jan 2019 17:09:42 -0600 -Subject: [PATCH] multipathd: cleanup marginal paths checking timers - -When a path gets recovered in hit_io_err_recheck_time(), it will -continue running in check_path(), so there is no reason to schedule -another path check as soon as possible (since one is currently -happening). - -Also, there isn't much point in restarting the io err stat checking when -the path is down, so hit_io_err_recheck_time() should only be run when -the path is up. Downed marginal paths can be treated just like any other -downed path. - -Finally, there is no reason to set reset pp->io_err_dis_reinstate_time -when we decide to enqueue a path. Either th enqueue will fail and the -path will get recovered, or it will succeed, and we won't check the -reinstate time again until poll_io_err_stat() marks the path as needing -a requeue. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/io_err_stat.c | 8 -------- - multipathd/main.c | 3 ++- - 2 files changed, 2 insertions(+), 9 deletions(-) - -diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c -index 1cb3ffe..416e13a 100644 ---- a/libmultipath/io_err_stat.c -+++ b/libmultipath/io_err_stat.c -@@ -400,13 +400,6 @@ int hit_io_err_recheck_time(struct path *pp) - io_err_stat_log(4, "%s: reschedule checking after %d seconds", - pp->dev, - pp->mpp->marginal_path_err_recheck_gap_time); -- /* -- * to reschedule io error checking again -- * if the path is good enough, we claim it is good -- * and can be reinsated as soon as possible in the -- * check_path routine. -- */ -- pp->io_err_dis_reinstate_time = curr_time.tv_sec; - r = enqueue_io_err_stat_by_path(pp); - /* - * Enqueue fails because of internal error. -@@ -426,7 +419,6 @@ int hit_io_err_recheck_time(struct path *pp) - recover: - pp->io_err_pathfail_cnt = 0; - pp->io_err_disable_reinstate = 0; -- pp->tick = 1; - return 0; - } - -diff --git a/multipathd/main.c b/multipathd/main.c -index fb520b6..fe6d8ef 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -2079,7 +2079,8 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) - return 1; - } - -- if (pp->io_err_disable_reinstate && hit_io_err_recheck_time(pp)) { -+ if ((newstate == PATH_UP || newstate == PATH_GHOST) && -+ pp->io_err_disable_reinstate && hit_io_err_recheck_time(pp)) { - pp->state = PATH_SHAKY; - /* - * to reschedule as soon as possible,so that this path can --- -2.17.2 - diff --git a/0003-tests-add-path-grouping-policy-unit-tests.patch b/0003-tests-add-path-grouping-policy-unit-tests.patch new file mode 100644 index 0000000..e6478c0 --- /dev/null +++ b/0003-tests-add-path-grouping-policy-unit-tests.patch @@ -0,0 +1,749 @@ +From a8f8ac6519aa46c4514c0f16073c2c6a7cb48a6a Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 9 Jul 2019 16:31:25 -0500 +Subject: [PATCH] tests: add path grouping policy unit tests. + +In preparation for changing the path grouping code, add some unit tests +to verify that it works correctly. The only test that currently fails +(and so it being skipped) is using MULTIBUS when mp->paths is empty. All +the other path grouping policies free mp->paths, even if it is empty. +one_group() should as well. This will be fixed when the path grouping +code is updated. + +Signed-off-by: Benjamin Marzinski +--- + tests/Makefile | 2 +- + tests/pgpolicy.c | 708 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 709 insertions(+), 1 deletion(-) + create mode 100644 tests/pgpolicy.c + +diff --git a/tests/Makefile b/tests/Makefile +index bf159b2d..a5cdf390 100644 +--- a/tests/Makefile ++++ b/tests/Makefile +@@ -3,7 +3,7 @@ include ../Makefile.inc + CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) + LIBDEPS += -L$(multipathdir) -lmultipath -lcmocka + +-TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd ++TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy + + .SILENT: $(TESTS:%=%.o) + .PRECIOUS: $(TESTS:%=%-test) +diff --git a/tests/pgpolicy.c b/tests/pgpolicy.c +new file mode 100644 +index 00000000..fbb8589e +--- /dev/null ++++ b/tests/pgpolicy.c +@@ -0,0 +1,708 @@ ++/* ++ * Copyright (c) 2018 Benjamin Marzinski, Redhat ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "globals.c" ++#include "pgpolicies.h" ++ ++struct multipath mp8, mp4, mp1, mp0, mp_null; ++struct path p8[8], p4[4], p1[1]; ++ ++ ++static void set_priority(struct path *pp, int *prio, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++) { ++ pp[i].priority = prio[i]; ++ } ++} ++ ++static void set_tgt_node_name(struct path *pp, char **tgt_node_name, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++) { ++ strcpy(pp[i].tgt_node_name, tgt_node_name[i]); ++ } ++} ++ ++static void set_serial(struct path *pp, char **serial, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++) { ++ strcpy(pp[i].serial, serial[i]); ++ } ++} ++ ++static int setup(void **state) ++{ ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(p8[i].dev, "p8_%d", i); ++ sprintf(p8[i].dev_t, "8:%d", i); ++ p8[i].state = PATH_UP; ++ } ++ for (i = 0; i < 4; i++) { ++ sprintf(p4[i].dev, "p4_%d", i); ++ sprintf(p4[i].dev_t, "4:%d", i); ++ p4[i].state = PATH_UP; ++ } ++ sprintf(p1[0].dev, "p1_0"); ++ sprintf(p1[0].dev_t, "4:0"); ++ p1[0].state = PATH_UP; ++ return 0; ++} ++ ++static int setupX(struct multipath *mp, struct path *pp, int size) ++{ ++ int i; ++ int prio[8] = {10, 10, 10, 10, 10, 10, 10, 10}; ++ ++ mp->paths = vector_alloc(); ++ if (!mp->paths) ++ return -1; ++ for (i = 0; i < size; i++) { ++ if (!vector_alloc_slot(mp->paths)) ++ return -1; ++ vector_set_slot(mp->paths, &pp[i]); ++ } ++ set_priority(pp, prio, size); ++ return 0; ++} ++ ++static int setup8(void **state) ++{ ++ return setupX(&mp8, p8, 8); ++} ++ ++static int setup4(void **state) ++{ ++ return setupX(&mp4, p4, 4); ++} ++ ++static int setup1(void **state) ++{ ++ return setupX(&mp1, p1, 1); ++} ++ ++static int setup0(void **state) ++{ ++ return setupX(&mp0, NULL, 0); ++} ++ ++static int setup_null(void **state) ++{ ++ return 0; ++} ++ ++static int teardownX(struct multipath *mp) ++{ ++ free_pgvec(mp->pg, KEEP_PATHS); ++ mp->pg = NULL; ++ return 0; ++} ++ ++static int teardown8(void **state) ++{ ++ return teardownX(&mp8); ++} ++ ++static int teardown4(void **state) ++{ ++ return teardownX(&mp4); ++} ++ ++static int teardown1(void **state) ++{ ++ return teardownX(&mp1); ++} ++ ++static int teardown0(void **state) ++{ ++ return teardownX(&mp0); ++} ++ ++static int teardown_null(void **state) ++{ ++ return teardownX(&mp_null); ++} ++ ++static void ++verify_pathgroups(struct multipath *mp, struct path *pp, int **groups, ++ int *group_size, int size) ++{ ++ int i, j; ++ struct pathgroup *pgp; ++ ++ assert_null(mp->paths); ++ assert_non_null(mp->pg); ++ assert_int_equal(VECTOR_SIZE(mp->pg), size); ++ for (i = 0; i < size; i++) { ++ pgp = VECTOR_SLOT(mp->pg, i); ++ assert_non_null(pgp); ++ assert_non_null(pgp->paths); ++ assert_int_equal(VECTOR_SIZE(pgp->paths), group_size[i]); ++ for (j = 0; j < group_size[i]; j++) { ++ int path_nr = groups[i][j]; ++ struct path *pgp_path = VECTOR_SLOT(pgp->paths, j); ++ struct path *pp_path = &pp[path_nr]; ++ /* Test names instead of pointers to get a more ++ * useful error message */ ++ assert_string_equal(pgp_path->dev, pp_path->dev); ++ /* This test is just a backkup in case the ++ * something wenth wrong naming the paths */ ++ assert_ptr_equal(pgp_path, pp_path); ++ } ++ } ++} ++ ++static void test_one_group8(void **state) ++{ ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {paths}; ++ int group_size[] = {8}; ++ ++ assert_int_equal(one_group(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 1); ++} ++ ++static void test_one_group4(void **state) ++{ ++ int paths[] = {0,1,2,3}; ++ int *groups[] = {paths}; ++ int group_size[] = {4}; ++ ++ assert_int_equal(one_group(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 1); ++} ++ ++static void test_one_group1(void **state) ++{ ++ int paths[] = {0}; ++ int *groups[] = {paths}; ++ int group_size[] = {1}; ++ ++ assert_int_equal(one_group(&mp1), 0); ++ verify_pathgroups(&mp1, p1, groups, group_size, 1); ++} ++ ++static void test_one_group0(void **state) ++{ ++ assert_int_equal(one_group(&mp0), 0); ++ skip(); /* BROKEN */ ++ verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++} ++ ++static void test_one_group_null(void **state) ++{ ++ assert_int_equal(one_group(&mp_null), 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++} ++ ++static void test_one_path_per_group_same8(void **state) ++{ ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ assert_int_equal(one_path_per_group(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_one_path_per_group_increasing8(void **state) ++{ ++ int prio[] = {1,2,3,4,5,6,7,8}; ++ int paths[] = {7,6,5,4,3,2,1,0}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(one_path_per_group(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_one_path_per_group_decreasing8(void **state) ++{ ++ int prio[] = {8,7,6,5,4,3,2,1}; ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(one_path_per_group(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_one_path_per_group_mixed8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int paths[] = {6,0,4,2,3,5,7,1}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(one_path_per_group(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_one_path_per_group4(void **state) ++{ ++ int paths[] = {0,1,2,3}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3]}; ++ int group_size[] = {1,1,1,1}; ++ ++ assert_int_equal(one_path_per_group(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 4); ++} ++ ++static void test_one_path_per_group1(void **state) ++{ ++ int paths[] = {0}; ++ int *groups[] = {paths}; ++ int group_size[] = {1}; ++ ++ assert_int_equal(one_path_per_group(&mp1), 0); ++ verify_pathgroups(&mp1, p1, groups, group_size, 1); ++} ++ ++static void test_one_path_per_group0(void **state) ++{ ++ assert_int_equal(one_path_per_group(&mp0), 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++} ++ ++static void test_one_path_per_group_null(void **state) ++{ ++ assert_int_equal(one_path_per_group(&mp_null), 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_prio_same8(void **state) ++{ ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {paths}; ++ int group_size[] = {8}; ++ ++ assert_int_equal(group_by_prio(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 1); ++} ++ ++static void test_group_by_prio_increasing8(void **state) ++{ ++ int prio[] = {1,2,3,4,5,6,7,8}; ++ int paths[] = {7,6,5,4,3,2,1,0}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(group_by_prio(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_group_by_prio_decreasing8(void **state) ++{ ++ int prio[] = {8,7,6,5,4,3,2,1}; ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(group_by_prio(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_group_by_prio_mixed8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int group0[] = {6}; ++ int group1[] = {0}; ++ int group2[] = {4}; ++ int group3[] = {2,3}; ++ int group4[] = {5,7}; ++ int group5[] = {1}; ++ int *groups[] = {group0, group1, group2, group3, ++ group4, group5}; ++ int group_size[] = {1,1,1,2,2,1}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(group_by_prio(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 6); ++} ++ ++static void test_group_by_prio_2_groups8(void **state) ++{ ++ int prio[] = {1,2,2,1,2,1,1,2}; ++ int group0[] = {1,2,4,7}; ++ int group1[] = {0,3,5,6}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {4,4}; ++ ++ set_priority(p8, prio, 8); ++ assert_int_equal(group_by_prio(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 2); ++} ++ ++static void test_group_by_prio_mixed4(void **state) ++{ ++ int prio[] = {2,3,1,3}; ++ int group0[] = {1,3}; ++ int group1[] = {0}; ++ int group2[] = {2}; ++ int *groups[] = {group0, group1, group2}; ++ int group_size[] = {2,1,1}; ++ ++ set_priority(p4, prio, 4); ++ assert_int_equal(group_by_prio(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 3); ++} ++ ++static void test_group_by_prio_2_groups4(void **state) ++{ ++ int prio[] = {2,1,1,2}; ++ int group0[] = {0,3}; ++ int group1[] = {1,2}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {2,2}; ++ ++ set_priority(p4, prio, 4); ++ assert_int_equal(group_by_prio(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 2); ++} ++ ++static void test_group_by_prio1(void **state) ++{ ++ int paths[] = {0}; ++ int *groups[] = {paths}; ++ int group_size[] = {1}; ++ ++ assert_int_equal(group_by_prio(&mp1), 0); ++ verify_pathgroups(&mp1, p1, groups, group_size, 1); ++} ++ ++static void test_group_by_prio0(void **state) ++{ ++ assert_int_equal(group_by_prio(&mp0), 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_prio_null(void **state) ++{ ++ assert_int_equal(group_by_prio(&mp_null), 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_node_name_same8(void **state) ++{ ++ char *node_name[] = {"a","a","a","a","a","a","a","a"}; ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {paths}; ++ int group_size[] = {8}; ++ ++ set_tgt_node_name(p8, node_name, 8); ++ assert_int_equal(group_by_node_name(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 1); ++} ++ ++static void test_group_by_node_name_increasing8(void **state) ++{ ++ char *node_name[] = {"a","b","c","d","e","f","g","h"}; ++ int prio[] = {1,2,3,4,5,6,7,8}; ++ int paths[] = {7,6,5,4,3,2,1,0}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_tgt_node_name(p8, node_name, 8); ++ assert_int_equal(group_by_node_name(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_group_by_node_name_3_groups8(void **state) ++{ ++ char *node_name[] = {"a","b","a","c","b","c","c","a"}; ++ int prio[] = {4,1,4,1,1,1,1,4}; ++ int group0[] = {0,2,7}; ++ int group1[] = {3,5,6}; ++ int group2[] = {1,4}; ++ int *groups[] = {group0, group1, group2}; ++ int group_size[] = {3,3,2}; ++ ++ set_priority(p8, prio, 8); ++ set_tgt_node_name(p8, node_name, 8); ++ assert_int_equal(group_by_node_name(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 3); ++} ++ ++static void test_group_by_node_name_2_groups8(void **state) ++{ ++ char *node_name[] = {"a", "a", "b", "a", "b", "b", "b", "a"}; ++ int prio[] = {4,1,2,1,2,2,2,1}; ++ int group0[] = {2,4,5,6}; ++ int group1[] = {0,1,3,7}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {4,4}; ++ ++ set_priority(p8, prio, 8); ++ set_tgt_node_name(p8, node_name, 8); ++ assert_int_equal(group_by_node_name(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 2); ++} ++ ++static void test_group_by_node_name_3_groups4(void **state) ++{ ++ char *node_name[] = {"a","b","c","a"}; ++ int prio[] = {3,1,3,1}; ++ int group0[] = {2}; ++ int group1[] = {0,3}; ++ int group2[] = {1}; ++ int *groups[] = {group0, group1, group2}; ++ int group_size[] = {1,2,1}; ++ ++ set_priority(p4, prio, 4); ++ set_tgt_node_name(p4, node_name, 4); ++ assert_int_equal(group_by_node_name(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 3); ++} ++ ++static void test_group_by_node_name_2_groups4(void **state) ++{ ++ char *node_name[] = {"a","b","b","a"}; ++ int prio[] = {2,1,1,2}; ++ int group0[] = {0,3}; ++ int group1[] = {1,2}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {2,2}; ++ ++ set_priority(p4, prio, 4); ++ set_tgt_node_name(p4, node_name, 4); ++ assert_int_equal(group_by_node_name(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 2); ++} ++ ++static void test_group_by_node_name1(void **state) ++{ ++ char *node_name[] = {"a"}; ++ int paths[] = {0}; ++ int *groups[] = {paths}; ++ int group_size[] = {1}; ++ ++ set_tgt_node_name(p1, node_name, 1); ++ assert_int_equal(group_by_node_name(&mp1), 0); ++ verify_pathgroups(&mp1, p1, groups, group_size, 1); ++} ++ ++static void test_group_by_node_name0(void **state) ++{ ++ assert_int_equal(group_by_node_name(&mp0), 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_node_name_null(void **state) ++{ ++ assert_int_equal(group_by_node_name(&mp_null), 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_serial_same8(void **state) ++{ ++ char *serial[] = {"1","1","1","1","1","1","1","1"}; ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {paths}; ++ int group_size[] = {8}; ++ ++ set_serial(p8, serial, 8); ++ assert_int_equal(group_by_serial(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 1); ++} ++ ++static void test_group_by_serial_increasing8(void **state) ++{ ++ char *serial[] = {"1","2","3","4","5","6","7","8"}; ++ int prio[] = {1,2,3,4,5,6,7,8}; ++ int paths[] = {7,6,5,4,3,2,1,0}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_serial(p8, serial, 8); ++ assert_int_equal(group_by_serial(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 8); ++} ++ ++static void test_group_by_serial_3_groups8(void **state) ++{ ++ char *serial[] = {"1","2","1","3","2","3","2","1"}; ++ int prio[] = {4,1,4,3,1,3,1,4}; ++ int group0[] = {0,2,7}; ++ int group1[] = {3,5}; ++ int group2[] = {1,4,6}; ++ int *groups[] = {group0, group1, group2}; ++ int group_size[] = {3,2,3}; ++ ++ set_priority(p8, prio, 8); ++ set_serial(p8, serial, 8); ++ assert_int_equal(group_by_serial(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 3); ++} ++ ++static void test_group_by_serial_2_groups8(void **state) ++{ ++ char *serial[] = {"1", "2", "1", "1", "2", "2", "1", "2"}; ++ int prio[] = {3,2,2,1,2,2,1,2}; ++ int group0[] = {1,4,5,7}; ++ int group1[] = {0,2,3,6}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {4,4}; ++ ++ set_priority(p8, prio, 8); ++ set_serial(p8, serial, 8); ++ assert_int_equal(group_by_serial(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, 2); ++} ++ ++static void test_group_by_serial_3_groups4(void **state) ++{ ++ char *serial[] = {"1","2","3","2"}; ++ int prio[] = {3,1,3,1}; ++ int group0[] = {0}; ++ int group1[] = {2}; ++ int group2[] = {1,3}; ++ int *groups[] = {group0, group1, group2}; ++ int group_size[] = {1,1,2}; ++ ++ set_priority(p4, prio, 4); ++ set_serial(p4, serial, 4); ++ assert_int_equal(group_by_serial(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 3); ++} ++ ++static void test_group_by_serial_2_groups4(void **state) ++{ ++ char *serial[] = {"1","2","1","2"}; ++ int prio[] = {3,1,3,1}; ++ int group0[] = {0,2}; ++ int group1[] = {1,3}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {2,2}; ++ ++ set_priority(p4, prio, 4); ++ set_serial(p4, serial, 4); ++ assert_int_equal(group_by_serial(&mp4), 0); ++ verify_pathgroups(&mp4, p4, groups, group_size, 2); ++} ++ ++static void test_group_by_serial1(void **state) ++{ ++ char *serial[1] = {"1"}; ++ int paths[1] = {0}; ++ int *groups[1] = {paths}; ++ int group_size[1] = {1}; ++ ++ set_serial(p1, serial, 1); ++ assert_int_equal(group_by_serial(&mp1), 0); ++ verify_pathgroups(&mp1, p1, groups, group_size, 1); ++} ++ ++static void test_group_by_serial0(void **state) ++{ ++ assert_int_equal(group_by_serial(&mp0), 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_serial_null(void **state) ++{ ++ assert_int_equal(group_by_serial(&mp_null), 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++} ++ ++#define setup_test(name, nr) \ ++cmocka_unit_test_setup_teardown(name ## nr, setup ## nr, teardown ## nr) ++ ++int test_pgpolicies(void) ++{ ++ const struct CMUnitTest tests[] = { ++ setup_test(test_one_group, 8), ++ setup_test(test_one_group, 4), ++ setup_test(test_one_group, 1), ++ setup_test(test_one_group, 0), ++ setup_test(test_one_group, _null), ++ setup_test(test_one_path_per_group_same, 8), ++ setup_test(test_one_path_per_group_increasing, 8), ++ setup_test(test_one_path_per_group_decreasing, 8), ++ setup_test(test_one_path_per_group_mixed, 8), ++ setup_test(test_one_path_per_group, 4), ++ setup_test(test_one_path_per_group, 1), ++ setup_test(test_one_path_per_group, 0), ++ setup_test(test_one_path_per_group, _null), ++ setup_test(test_group_by_prio_same, 8), ++ setup_test(test_group_by_prio_increasing, 8), ++ setup_test(test_group_by_prio_decreasing, 8), ++ setup_test(test_group_by_prio_mixed, 8), ++ setup_test(test_group_by_prio_2_groups, 8), ++ setup_test(test_group_by_prio_mixed, 4), ++ setup_test(test_group_by_prio_2_groups, 4), ++ setup_test(test_group_by_prio, 1), ++ setup_test(test_group_by_prio, 0), ++ setup_test(test_group_by_prio, _null), ++ setup_test(test_group_by_node_name_same, 8), ++ setup_test(test_group_by_node_name_increasing, 8), ++ setup_test(test_group_by_node_name_3_groups, 8), ++ setup_test(test_group_by_node_name_2_groups, 8), ++ setup_test(test_group_by_node_name_3_groups, 4), ++ setup_test(test_group_by_node_name_2_groups, 4), ++ setup_test(test_group_by_node_name, 1), ++ setup_test(test_group_by_node_name, 0), ++ setup_test(test_group_by_node_name, _null), ++ setup_test(test_group_by_serial_same, 8), ++ setup_test(test_group_by_serial_increasing, 8), ++ setup_test(test_group_by_serial_3_groups, 8), ++ setup_test(test_group_by_serial_2_groups, 8), ++ setup_test(test_group_by_serial_3_groups, 4), ++ setup_test(test_group_by_serial_2_groups, 4), ++ setup_test(test_group_by_serial, 1), ++ setup_test(test_group_by_serial, 0), ++ setup_test(test_group_by_serial, _null), ++ }; ++ return cmocka_run_group_tests(tests, setup, NULL); ++} ++ ++int main(void) ++{ ++ int ret = 0; ++ ++ ret += test_pgpolicies(); ++ return ret; ++} +-- +2.17.2 + diff --git a/0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch b/0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch new file mode 100644 index 0000000..2dac911 --- /dev/null +++ b/0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch @@ -0,0 +1,260 @@ +From cc1f4c53100ae50e0fba379c40ac8e1fe72c1fb1 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 2 Jul 2019 16:28:16 -0500 +Subject: [PATCH] libmultipath: add wrapper function around pgpolicyfn + +group_paths() is a wrapper around the pgpolicy functions, that pulls out +the common code from the beginning and the end. For this to work, +one_group() needs to change how it sets up the pathgroups vector to work +like the other pgpolicy functions. This does means that the pathgroups +in group_by_prio are now needlessly sorted afterwards. That will be +dealt with in a later patch. Also, since store_pathgroup() is only +called by add_pathgroup(), it doesn't need to exist as a seperate +function. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 2 +- + libmultipath/pgpolicies.c | 83 ++++++++++++++------------------------- + libmultipath/pgpolicies.h | 2 +- + libmultipath/structs.c | 16 ++------ + libmultipath/structs.h | 1 - + 5 files changed, 35 insertions(+), 69 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index b09ef529..3c309d64 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -387,7 +387,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + vector_free(mpp->pg); + mpp->pg = NULL; + } +- if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp)) ++ if (group_paths(mpp)) + return 1; + + /* +diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c +index 660768a4..1b59485c 100644 +--- a/libmultipath/pgpolicies.c ++++ b/libmultipath/pgpolicies.c +@@ -84,6 +84,26 @@ sort_pathgroups (struct multipath *mp) { + } + + ++int group_paths(struct multipath *mp) ++{ ++ if (!mp->pg) ++ mp->pg = vector_alloc(); ++ if (!mp->pg) ++ return 1; ++ ++ if (VECTOR_SIZE(mp->paths) > 0 && ++ (!mp->pgpolicyfn || mp->pgpolicyfn(mp))) { ++ vector_free(mp->pg); ++ mp->pg = NULL; ++ return 1; ++ } ++ ++ sort_pathgroups(mp); ++ vector_free(mp->paths); ++ mp->paths = NULL; ++ return 0; ++} ++ + /* + * One path group per unique tgt_node_name present in the path vector + */ +@@ -95,12 +115,6 @@ int group_by_node_name(struct multipath * mp) + struct pathgroup * pgp; + struct path * pp2; + +- if (!mp->pg) +- mp->pg = vector_alloc(); +- +- if (!mp->pg) +- return 1; +- + /* init the bitmap */ + bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int)); + +@@ -146,9 +160,6 @@ int group_by_node_name(struct multipath * mp) + } + } + FREE(bitmap); +- sort_pathgroups(mp); +- free_pathvec(mp->paths, KEEP_PATHS); +- mp->paths = NULL; + return 0; + out2: + free_pathgroup(pgp, KEEP_PATHS); +@@ -171,12 +182,6 @@ int group_by_serial(struct multipath * mp) + struct pathgroup * pgp; + struct path * pp2; + +- if (!mp->pg) +- mp->pg = vector_alloc(); +- +- if (!mp->pg) +- return 1; +- + /* init the bitmap */ + bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int)); + +@@ -221,9 +226,6 @@ int group_by_serial(struct multipath * mp) + } + } + FREE(bitmap); +- sort_pathgroups(mp); +- free_pathvec(mp->paths, KEEP_PATHS); +- mp->paths = NULL; + return 0; + out2: + free_pathgroup(pgp, KEEP_PATHS); +@@ -241,12 +243,6 @@ int one_path_per_group(struct multipath *mp) + struct path * pp; + struct pathgroup * pgp; + +- if (!mp->pg) +- mp->pg = vector_alloc(); +- +- if (!mp->pg) +- return 1; +- + for (i = 0; i < VECTOR_SIZE(mp->paths); i++) { + pp = VECTOR_SLOT(mp->paths, i); + pgp = alloc_pathgroup(); +@@ -260,9 +256,6 @@ int one_path_per_group(struct multipath *mp) + if (store_path(pgp->paths, pp)) + goto out1; + } +- sort_pathgroups(mp); +- free_pathvec(mp->paths, KEEP_PATHS); +- mp->paths = NULL; + return 0; + out1: + free_pathgroup(pgp, KEEP_PATHS); +@@ -274,32 +267,24 @@ out: + + int one_group(struct multipath *mp) /* aka multibus */ + { ++ int i; ++ struct path * pp; + struct pathgroup * pgp; + +- if (VECTOR_SIZE(mp->paths) < 0) +- return 0; ++ pgp = alloc_pathgroup(); + +- if (!mp->pg) +- mp->pg = vector_alloc(); ++ if (!pgp) ++ goto out; + +- if (!mp->pg) +- return 1; ++ if (add_pathgroup(mp, pgp)) ++ goto out1; + +- if (VECTOR_SIZE(mp->paths) > 0) { +- pgp = alloc_pathgroup(); ++ for (i = 0; i < VECTOR_SIZE(mp->paths); i++) { ++ pp = VECTOR_SLOT(mp->paths, i); + +- if (!pgp) ++ if (store_path(pgp->paths, pp)) + goto out; +- +- vector_free(pgp->paths); +- +- if (add_pathgroup(mp, pgp)) +- goto out1; +- +- pgp->paths = mp->paths; +- mp->paths = NULL; + } +- + return 0; + out1: + free_pathgroup(pgp, KEEP_PATHS); +@@ -317,12 +302,6 @@ int group_by_prio(struct multipath *mp) + struct pathgroup * pgp; + vector pathvec = NULL; + +- if (!mp->pg) +- mp->pg = vector_alloc(); +- +- if (!mp->pg) +- return 1; +- + pathvec = vector_alloc(); + if (!pathvec) + goto out; +@@ -387,8 +366,6 @@ int group_by_prio(struct multipath *mp) + } + } + free_pathvec(pathvec, KEEP_PATHS); +- free_pathvec(mp->paths, KEEP_PATHS); +- mp->paths = NULL; + return 0; + out2: + free_pathgroup(pgp, KEEP_PATHS); +diff --git a/libmultipath/pgpolicies.h b/libmultipath/pgpolicies.h +index c0eaa7f4..11834011 100644 +--- a/libmultipath/pgpolicies.h ++++ b/libmultipath/pgpolicies.h +@@ -21,7 +21,7 @@ enum iopolicies { + + int get_pgpolicy_id(char *); + int get_pgpolicy_name (char *, int, int); +- ++int group_paths(struct multipath *); + /* + * policies + */ +diff --git a/libmultipath/structs.c b/libmultipath/structs.c +index fee899bd..bf7fdd73 100644 +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -318,23 +318,13 @@ store_path (vector pathvec, struct path * pp) + return 0; + } + +-int +-store_pathgroup (vector pgvec, struct pathgroup * pgp) ++int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp) + { +- if (!vector_alloc_slot(pgvec)) ++ if (!vector_alloc_slot(mpp->pg)) + return 1; + +- vector_set_slot(pgvec, pgp); +- +- return 0; +-} +- +-int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp) +-{ +- int ret = store_pathgroup(mpp->pg, pgp); ++ vector_set_slot(mpp->pg, pgp); + +- if (ret) +- return ret; + pgp->mpp = mpp; + return 0; + } +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 1a3d827b..893074eb 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -445,7 +445,6 @@ int store_adaptergroup(vector adapters, struct adapter_group *agp); + int store_hostgroup(vector hostgroupvec, struct host_group *hgp); + + int store_path (vector pathvec, struct path * pp); +-int store_pathgroup (vector pgvec, struct pathgroup * pgp); + int add_pathgroup(struct multipath*, struct pathgroup *); + + struct multipath * find_mp_by_alias (const struct _vector *mp, const char *alias); +-- +2.17.2 + diff --git a/0004-libmultipath-fix-marginal-paths-queueing-errors.patch b/0004-libmultipath-fix-marginal-paths-queueing-errors.patch deleted file mode 100644 index 9417741..0000000 --- a/0004-libmultipath-fix-marginal-paths-queueing-errors.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Mon, 28 Jan 2019 00:20:53 -0600 -Subject: [PATCH] libmultipath: fix marginal paths queueing errors - -The current marginal paths code tries to enqueue paths for io error -checking when multipathd receives a uevent on path failure. This can run -into a couple of problems. First, this uevent could happen before or -after multipathd actually fails the path, so simply checking nr_active -doesn't tell us if this is the last active path. Also, The code to fail -the path in enqueue_io_err_stat_by_path() doesn't ever update the path -state. This can cause the path to get failed twice, temporarily leading -to incorrect nr_active counts. Further, The point when multipathd should -care if this is the last active path is when the path has come up again, -not when it goes down. Lastly, if the path is down, it is often -impossible to open the path device, causing setup_directio_ctx() to -fail, which causes multipathd to skip io error checking and mark the -path as not marginal. - -Instead, multipathd should just make sure that if the path is marginal, -it gets failed in the uevent, so as not to race with the checkerloop -thread. Then, when the path comes back up, check_path() can enqueue it, -just like it does for paths that need to get rechecked. To make it -obvious that the state PATH_IO_ERR_IN_POLLING_RECHECK and the function -hit_io_err_recheck_time() now apply to paths waiting to be enqueued for -the first time as well, I've also changed their names to -PATH_IO_ERR_WAITING_TO_CHECK and need_io_err_check(), respectively. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/io_err_stat.c | 55 +++++++++++++++++--------------------- - libmultipath/io_err_stat.h | 2 +- - multipathd/main.c | 2 +- - 3 files changed, 27 insertions(+), 32 deletions(-) - -diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c -index 416e13a..72aacf3 100644 ---- a/libmultipath/io_err_stat.c -+++ b/libmultipath/io_err_stat.c -@@ -41,7 +41,7 @@ - #define CONCUR_NR_EVENT 32 - - #define PATH_IO_ERR_IN_CHECKING -1 --#define PATH_IO_ERR_IN_POLLING_RECHECK -2 -+#define PATH_IO_ERR_WAITING_TO_CHECK -2 - - #define io_err_stat_log(prio, fmt, args...) \ - condlog(prio, "io error statistic: " fmt, ##args) -@@ -283,24 +283,6 @@ static int enqueue_io_err_stat_by_path(struct path *path) - vector_set_slot(paths->pathvec, p); - pthread_mutex_unlock(&paths->mutex); - -- if (!path->io_err_disable_reinstate) { -- /* -- *fail the path in the kernel for the time of the to make -- *the test more reliable -- */ -- io_err_stat_log(3, "%s: fail dm path %s before checking", -- path->mpp->alias, path->dev); -- path->io_err_disable_reinstate = 1; -- dm_fail_path(path->mpp->alias, path->dev_t); -- update_queue_mode_del_path(path->mpp); -- -- /* -- * schedule path check as soon as possible to -- * update path state to delayed state -- */ -- path->tick = 1; -- -- } - io_err_stat_log(2, "%s: enqueue path %s to check", - path->mpp->alias, path->dev); - return 0; -@@ -317,7 +299,6 @@ free_ioerr_path: - int io_err_stat_handle_pathfail(struct path *path) - { - struct timespec curr_time; -- int res; - - if (uatomic_read(&io_err_thread_running) == 0) - return 1; -@@ -332,8 +313,6 @@ int io_err_stat_handle_pathfail(struct path *path) - - if (!path->mpp) - return 1; -- if (path->mpp->nr_active <= 1) -- return 1; - if (path->mpp->marginal_path_double_failed_time <= 0 || - path->mpp->marginal_path_err_sample_time <= 0 || - path->mpp->marginal_path_err_recheck_gap_time <= 0 || -@@ -371,17 +350,33 @@ int io_err_stat_handle_pathfail(struct path *path) - } - path->io_err_pathfail_cnt++; - if (path->io_err_pathfail_cnt >= FLAKY_PATHFAIL_THRESHOLD) { -- res = enqueue_io_err_stat_by_path(path); -- if (!res) -- path->io_err_pathfail_cnt = PATH_IO_ERR_IN_CHECKING; -- else -- path->io_err_pathfail_cnt = 0; -+ path->io_err_disable_reinstate = 1; -+ path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; -+ /* enqueue path as soon as it comes up */ -+ path->io_err_dis_reinstate_time = 0; -+ if (path->state != PATH_DOWN) { -+ struct config *conf; -+ int oldstate = path->state; -+ int checkint; -+ -+ conf = get_multipath_config(); -+ checkint = conf->checkint; -+ put_multipath_config(conf); -+ io_err_stat_log(2, "%s: mark as failed", path->dev); -+ path->mpp->stat_path_failures++; -+ path->state = PATH_DOWN; -+ path->dmstate = PSTATE_FAILED; -+ if (oldstate == PATH_UP || oldstate == PATH_GHOST) -+ update_queue_mode_del_path(path->mpp); -+ if (path->tick > checkint) -+ path->tick = checkint; -+ } - } - - return 0; - } - --int hit_io_err_recheck_time(struct path *pp) -+int need_io_err_check(struct path *pp) - { - struct timespec curr_time; - int r; -@@ -392,7 +387,7 @@ int hit_io_err_recheck_time(struct path *pp) - io_err_stat_log(2, "%s: recover path early", pp->dev); - goto recover; - } -- if (pp->io_err_pathfail_cnt != PATH_IO_ERR_IN_POLLING_RECHECK) -+ if (pp->io_err_pathfail_cnt != PATH_IO_ERR_WAITING_TO_CHECK) - return 1; - if (clock_gettime(CLOCK_MONOTONIC, &curr_time) != 0 || - (curr_time.tv_sec - pp->io_err_dis_reinstate_time) > -@@ -489,7 +484,7 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) - } else if (path->mpp && path->mpp->nr_active > 1) { - io_err_stat_log(3, "%s: keep failing the dm path %s", - path->mpp->alias, path->dev); -- path->io_err_pathfail_cnt = PATH_IO_ERR_IN_POLLING_RECHECK; -+ path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; - path->io_err_disable_reinstate = 1; - path->io_err_dis_reinstate_time = currtime.tv_sec; - io_err_stat_log(3, "%s: disable reinstating of %s", -diff --git a/libmultipath/io_err_stat.h b/libmultipath/io_err_stat.h -index bbf31b4..53d6d7d 100644 ---- a/libmultipath/io_err_stat.h -+++ b/libmultipath/io_err_stat.h -@@ -10,6 +10,6 @@ extern pthread_attr_t io_err_stat_attr; - int start_io_err_stat_thread(void *data); - void stop_io_err_stat_thread(void); - int io_err_stat_handle_pathfail(struct path *path); --int hit_io_err_recheck_time(struct path *pp); -+int need_io_err_check(struct path *pp); - - #endif /* _IO_ERR_STAT_H */ -diff --git a/multipathd/main.c b/multipathd/main.c -index fe6d8ef..43830e8 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -2080,7 +2080,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) - } - - if ((newstate == PATH_UP || newstate == PATH_GHOST) && -- pp->io_err_disable_reinstate && hit_io_err_recheck_time(pp)) { -+ pp->io_err_disable_reinstate && need_io_err_check(pp)) { - pp->state = PATH_SHAKY; - /* - * to reschedule as soon as possible,so that this path can --- -2.17.2 - diff --git a/0005-libmultipath-fix-marginal_paths-nr_active-check.patch b/0005-libmultipath-fix-marginal_paths-nr_active-check.patch deleted file mode 100644 index 486e03a..0000000 --- a/0005-libmultipath-fix-marginal_paths-nr_active-check.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Tue, 29 Jan 2019 18:26:04 -0600 -Subject: [PATCH] libmultipath: fix marginal_paths nr_active check - -Marginal paths are SHAKY, so they don't count towards the number of -active paths. poll_io_err_stat() shouldn't automatically reinstate a -marginal path if there already is an active path. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/io_err_stat.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c -index 72aacf3..554b777 100644 ---- a/libmultipath/io_err_stat.c -+++ b/libmultipath/io_err_stat.c -@@ -481,7 +481,7 @@ static int poll_io_err_stat(struct vectors *vecs, struct io_err_stat_path *pp) - */ - path->tick = 1; - -- } else if (path->mpp && path->mpp->nr_active > 1) { -+ } else if (path->mpp && path->mpp->nr_active > 0) { - io_err_stat_log(3, "%s: keep failing the dm path %s", - path->mpp->alias, path->dev); - path->io_err_pathfail_cnt = PATH_IO_ERR_WAITING_TO_CHECK; --- -2.17.2 - diff --git a/0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch b/0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch new file mode 100644 index 0000000..b304fcd --- /dev/null +++ b/0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch @@ -0,0 +1,420 @@ +From 03741e7467fdef6cd2fc91457a406ad60047f50e Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 9 Jul 2019 17:41:32 -0500 +Subject: [PATCH] tests: update pgpolicy tests to work with group_paths() + +The pgpolicy unit tests now work again, using group_paths(). +test_one_group0(), which was skipped with the old path grouping code +because it failed, is now working correctly. + +Signed-off-by: Benjamin Marzinski +--- + tests/pgpolicy.c | 125 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 83 insertions(+), 42 deletions(-) + +diff --git a/tests/pgpolicy.c b/tests/pgpolicy.c +index fbb8589e..04a77c4c 100644 +--- a/tests/pgpolicy.c ++++ b/tests/pgpolicy.c +@@ -92,6 +92,7 @@ static int setupX(struct multipath *mp, struct path *pp, int size) + vector_set_slot(mp->paths, &pp[i]); + } + set_priority(pp, prio, size); ++ mp->pgpolicyfn = NULL; + return 0; + } + +@@ -187,7 +188,8 @@ static void test_one_group8(void **state) + int *groups[] = {paths}; + int group_size[] = {8}; + +- assert_int_equal(one_group(&mp8), 0); ++ mp8.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 1); + } + +@@ -197,7 +199,8 @@ static void test_one_group4(void **state) + int *groups[] = {paths}; + int group_size[] = {4}; + +- assert_int_equal(one_group(&mp4), 0); ++ mp4.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 1); + } + +@@ -207,20 +210,22 @@ static void test_one_group1(void **state) + int *groups[] = {paths}; + int group_size[] = {1}; + +- assert_int_equal(one_group(&mp1), 0); ++ mp1.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp1), 0); + verify_pathgroups(&mp1, p1, groups, group_size, 1); + } + + static void test_one_group0(void **state) + { +- assert_int_equal(one_group(&mp0), 0); +- skip(); /* BROKEN */ ++ mp0.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, 0); + } + + static void test_one_group_null(void **state) + { +- assert_int_equal(one_group(&mp_null), 0); ++ mp_null.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp_null), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); + } + +@@ -231,7 +236,8 @@ static void test_one_path_per_group_same8(void **state) + &paths[4], &paths[5], &paths[6], &paths[7]}; + int group_size[] = {1,1,1,1,1,1,1,1}; + +- assert_int_equal(one_path_per_group(&mp8), 0); ++ mp8.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -244,7 +250,8 @@ static void test_one_path_per_group_increasing8(void **state) + int group_size[] = {1,1,1,1,1,1,1,1}; + + set_priority(p8, prio, 8); +- assert_int_equal(one_path_per_group(&mp8), 0); ++ mp8.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -257,7 +264,8 @@ static void test_one_path_per_group_decreasing8(void **state) + int group_size[] = {1,1,1,1,1,1,1,1}; + + set_priority(p8, prio, 8); +- assert_int_equal(one_path_per_group(&mp8), 0); ++ mp8.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -270,7 +278,8 @@ static void test_one_path_per_group_mixed8(void **state) + int group_size[] = {1,1,1,1,1,1,1,1}; + + set_priority(p8, prio, 8); +- assert_int_equal(one_path_per_group(&mp8), 0); ++ mp8.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -280,7 +289,8 @@ static void test_one_path_per_group4(void **state) + int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3]}; + int group_size[] = {1,1,1,1}; + +- assert_int_equal(one_path_per_group(&mp4), 0); ++ mp4.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 4); + } + +@@ -290,19 +300,22 @@ static void test_one_path_per_group1(void **state) + int *groups[] = {paths}; + int group_size[] = {1}; + +- assert_int_equal(one_path_per_group(&mp1), 0); ++ mp1.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp1), 0); + verify_pathgroups(&mp1, p1, groups, group_size, 1); + } + + static void test_one_path_per_group0(void **state) + { +- assert_int_equal(one_path_per_group(&mp0), 0); ++ mp0.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, 0); + } + + static void test_one_path_per_group_null(void **state) + { +- assert_int_equal(one_path_per_group(&mp_null), 0); ++ mp_null.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp_null), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); + } + +@@ -312,7 +325,8 @@ static void test_group_by_prio_same8(void **state) + int *groups[] = {paths}; + int group_size[] = {8}; + +- assert_int_equal(group_by_prio(&mp8), 0); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 1); + } + +@@ -325,7 +339,8 @@ static void test_group_by_prio_increasing8(void **state) + int group_size[] = {1,1,1,1,1,1,1,1}; + + set_priority(p8, prio, 8); +- assert_int_equal(group_by_prio(&mp8), 0); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -338,7 +353,8 @@ static void test_group_by_prio_decreasing8(void **state) + int group_size[] = {1,1,1,1,1,1,1,1}; + + set_priority(p8, prio, 8); +- assert_int_equal(group_by_prio(&mp8), 0); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -356,7 +372,8 @@ static void test_group_by_prio_mixed8(void **state) + int group_size[] = {1,1,1,2,2,1}; + + set_priority(p8, prio, 8); +- assert_int_equal(group_by_prio(&mp8), 0); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 6); + } + +@@ -369,7 +386,8 @@ static void test_group_by_prio_2_groups8(void **state) + int group_size[] = {4,4}; + + set_priority(p8, prio, 8); +- assert_int_equal(group_by_prio(&mp8), 0); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 2); + } + +@@ -383,7 +401,8 @@ static void test_group_by_prio_mixed4(void **state) + int group_size[] = {2,1,1}; + + set_priority(p4, prio, 4); +- assert_int_equal(group_by_prio(&mp4), 0); ++ mp4.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 3); + } + +@@ -396,7 +415,8 @@ static void test_group_by_prio_2_groups4(void **state) + int group_size[] = {2,2}; + + set_priority(p4, prio, 4); +- assert_int_equal(group_by_prio(&mp4), 0); ++ mp4.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 2); + } + +@@ -406,19 +426,22 @@ static void test_group_by_prio1(void **state) + int *groups[] = {paths}; + int group_size[] = {1}; + +- assert_int_equal(group_by_prio(&mp1), 0); ++ mp1.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp1), 0); + verify_pathgroups(&mp1, p1, groups, group_size, 1); + } + + static void test_group_by_prio0(void **state) + { +- assert_int_equal(group_by_prio(&mp0), 0); ++ mp0.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, 0); + } + + static void test_group_by_prio_null(void **state) + { +- assert_int_equal(group_by_prio(&mp_null), 0); ++ mp_null.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp_null), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); + } + +@@ -430,7 +453,8 @@ static void test_group_by_node_name_same8(void **state) + int group_size[] = {8}; + + set_tgt_node_name(p8, node_name, 8); +- assert_int_equal(group_by_node_name(&mp8), 0); ++ mp8.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 1); + } + +@@ -445,7 +469,8 @@ static void test_group_by_node_name_increasing8(void **state) + + set_priority(p8, prio, 8); + set_tgt_node_name(p8, node_name, 8); +- assert_int_equal(group_by_node_name(&mp8), 0); ++ mp8.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -461,7 +486,8 @@ static void test_group_by_node_name_3_groups8(void **state) + + set_priority(p8, prio, 8); + set_tgt_node_name(p8, node_name, 8); +- assert_int_equal(group_by_node_name(&mp8), 0); ++ mp8.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 3); + } + +@@ -476,7 +502,8 @@ static void test_group_by_node_name_2_groups8(void **state) + + set_priority(p8, prio, 8); + set_tgt_node_name(p8, node_name, 8); +- assert_int_equal(group_by_node_name(&mp8), 0); ++ mp8.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 2); + } + +@@ -492,7 +519,8 @@ static void test_group_by_node_name_3_groups4(void **state) + + set_priority(p4, prio, 4); + set_tgt_node_name(p4, node_name, 4); +- assert_int_equal(group_by_node_name(&mp4), 0); ++ mp4.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 3); + } + +@@ -507,7 +535,8 @@ static void test_group_by_node_name_2_groups4(void **state) + + set_priority(p4, prio, 4); + set_tgt_node_name(p4, node_name, 4); +- assert_int_equal(group_by_node_name(&mp4), 0); ++ mp4.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 2); + } + +@@ -519,19 +548,22 @@ static void test_group_by_node_name1(void **state) + int group_size[] = {1}; + + set_tgt_node_name(p1, node_name, 1); +- assert_int_equal(group_by_node_name(&mp1), 0); ++ mp1.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp1), 0); + verify_pathgroups(&mp1, p1, groups, group_size, 1); + } + + static void test_group_by_node_name0(void **state) + { +- assert_int_equal(group_by_node_name(&mp0), 0); ++ mp0.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, 0); + } + + static void test_group_by_node_name_null(void **state) + { +- assert_int_equal(group_by_node_name(&mp_null), 0); ++ mp_null.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp_null), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); + } + +@@ -543,7 +575,8 @@ static void test_group_by_serial_same8(void **state) + int group_size[] = {8}; + + set_serial(p8, serial, 8); +- assert_int_equal(group_by_serial(&mp8), 0); ++ mp8.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 1); + } + +@@ -558,7 +591,8 @@ static void test_group_by_serial_increasing8(void **state) + + set_priority(p8, prio, 8); + set_serial(p8, serial, 8); +- assert_int_equal(group_by_serial(&mp8), 0); ++ mp8.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 8); + } + +@@ -574,7 +608,8 @@ static void test_group_by_serial_3_groups8(void **state) + + set_priority(p8, prio, 8); + set_serial(p8, serial, 8); +- assert_int_equal(group_by_serial(&mp8), 0); ++ mp8.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 3); + } + +@@ -589,7 +624,8 @@ static void test_group_by_serial_2_groups8(void **state) + + set_priority(p8, prio, 8); + set_serial(p8, serial, 8); +- assert_int_equal(group_by_serial(&mp8), 0); ++ mp8.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp8), 0); + verify_pathgroups(&mp8, p8, groups, group_size, 2); + } + +@@ -605,7 +641,8 @@ static void test_group_by_serial_3_groups4(void **state) + + set_priority(p4, prio, 4); + set_serial(p4, serial, 4); +- assert_int_equal(group_by_serial(&mp4), 0); ++ mp4.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 3); + } + +@@ -620,7 +657,8 @@ static void test_group_by_serial_2_groups4(void **state) + + set_priority(p4, prio, 4); + set_serial(p4, serial, 4); +- assert_int_equal(group_by_serial(&mp4), 0); ++ mp4.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp4), 0); + verify_pathgroups(&mp4, p4, groups, group_size, 2); + } + +@@ -632,19 +670,22 @@ static void test_group_by_serial1(void **state) + int group_size[1] = {1}; + + set_serial(p1, serial, 1); +- assert_int_equal(group_by_serial(&mp1), 0); ++ mp1.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp1), 0); + verify_pathgroups(&mp1, p1, groups, group_size, 1); + } + + static void test_group_by_serial0(void **state) + { +- assert_int_equal(group_by_serial(&mp0), 0); ++ mp0.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, 0); + } + + static void test_group_by_serial_null(void **state) + { +- assert_int_equal(group_by_serial(&mp_null), 0); ++ mp_null.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp_null), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); + } + +-- +2.17.2 + diff --git a/0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch b/0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch new file mode 100644 index 0000000..d0f32d3 --- /dev/null +++ b/0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch @@ -0,0 +1,79 @@ +From 3209740e5a3e80b5f76dbc2ddaa63f2045aafd53 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 2 Jul 2019 17:30:32 -0500 +Subject: [PATCH] libmultipath: fix double free in pgpolicyfn error paths + +In the pgpolicy functions, if an error is encountered after +alloc_pathgroup() is called, but before the path group is added to a +multipath device with add_pathgroup(), the pathgroup needs to be cleaned +up by calling free_pathgroup(). However, after the pathgroup has been +added to the multipath device, calling free_pgvec() will clean it up. In +this case, if free_pathgroup() is called first, the recently added +pathgroup will be freed twice. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/pgpolicies.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c +index 1b59485c..1af42f52 100644 +--- a/libmultipath/pgpolicies.c ++++ b/libmultipath/pgpolicies.c +@@ -139,7 +139,7 @@ int group_by_node_name(struct multipath * mp) + + /* feed the first path */ + if (store_path(pgp->paths, pp)) +- goto out2; ++ goto out1; + + bitmap[i] = 1; + +@@ -153,7 +153,7 @@ int group_by_node_name(struct multipath * mp) + if (!strncmp(pp->tgt_node_name, pp2->tgt_node_name, + NODE_NAME_SIZE)) { + if (store_path(pgp->paths, pp2)) +- goto out2; ++ goto out1; + + bitmap[j] = 1; + } +@@ -206,7 +206,7 @@ int group_by_serial(struct multipath * mp) + + /* feed the first path */ + if (store_path(pgp->paths, pp)) +- goto out2; ++ goto out1; + + bitmap[i] = 1; + +@@ -219,7 +219,7 @@ int group_by_serial(struct multipath * mp) + + if (0 == strcmp(pp->serial, pp2->serial)) { + if (store_path(pgp->paths, pp2)) +- goto out2; ++ goto out1; + + bitmap[j] = 1; + } +@@ -254,7 +254,7 @@ int one_path_per_group(struct multipath *mp) + goto out1; + + if (store_path(pgp->paths, pp)) +- goto out1; ++ goto out; + } + return 0; + out1: +@@ -358,7 +358,7 @@ int group_by_prio(struct multipath *mp) + vector_foreach_slot(pathvec, pp, i) { + if (pp->priority == prio) { + if (store_path(pgp->paths, pp)) +- goto out2; ++ goto out1; + + vector_del_slot(pathvec, i); + i--; +-- +2.17.2 + diff --git a/0006-multipathd-Fix-miscounting-active-paths.patch b/0006-multipathd-Fix-miscounting-active-paths.patch deleted file mode 100644 index 4eb50f5..0000000 --- a/0006-multipathd-Fix-miscounting-active-paths.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Fri, 15 Feb 2019 17:19:46 -0600 -Subject: [PATCH] multipathd: Fix miscounting active paths - -When multipathd gets a change uevent, it calls pathinfo with DI_NOIO. -This sets the path state to the return value of path_offline(). If a -path is in the PATH_DOWN state but path_offline() returns PATH_UP, when -that path gets a change event, its state will get moved to PATH_UP -without either reinstating the path, or reloading the map. The next -call to check_path() will move the path back to PATH_DOWN. Since -check_path() simply increments and decrements nr_active instead of -calculating it based on the actual number of active paths, nr_active -will get decremented a second time for this failed path, potentially -putting the multipath device into recovery mode. - -This commit does two things to avoid this situation. It makes the -DI_NOIO flag only set pp->state in pathinfo() if DI_CHECKER is also set. -This isn't set in uev_update_path() to avoid changing the path state in -this case. Also, to guard against pp->state getting changed in some -other code path without properly updating the map state, check_path() -now calls set_no_path_retry, which recalculates nr_active based on the -actual number of active paths, and makes sure that the queue_if_no_path -value in the features line is correct. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/discovery.c | 11 ++++++----- - multipath/main.c | 2 +- - multipathd/main.c | 4 +++- - 3 files changed, 10 insertions(+), 7 deletions(-) - -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index 10bd8cd..729bcb9 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1914,11 +1914,12 @@ int pathinfo(struct path *pp, struct config *conf, int mask) - if (path_state == PATH_REMOVED) - goto blank; - else if (mask & DI_NOIO) { -- /* -- * Avoid any IO on the device itself. -- * Behave like DI_CHECKER in the "path unavailable" case. -- */ -- pp->chkrstate = pp->state = path_state; -+ if (mask & DI_CHECKER) -+ /* -+ * Avoid any IO on the device itself. -+ * simply use the path_offline() return as its state -+ */ -+ pp->chkrstate = pp->state = path_state; - return PATHINFO_OK; - } - -diff --git a/multipath/main.c b/multipath/main.c -index 5abb118..69141db 100644 ---- a/multipath/main.c -+++ b/multipath/main.c -@@ -356,7 +356,7 @@ static int check_usable_paths(struct config *conf, - pp->udev = get_udev_device(pp->dev_t, DEV_DEVT); - if (pp->udev == NULL) - continue; -- if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK) -+ if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO|DI_CHECKER) != PATHINFO_OK) - continue; - - if (pp->state == PATH_UP && -diff --git a/multipathd/main.c b/multipathd/main.c -index 43830e8..678ecf8 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -392,7 +392,8 @@ static void set_no_path_retry(struct multipath *mpp) - default: - if (mpp->nr_active > 0) { - mpp->retry_tick = 0; -- dm_queue_if_no_path(mpp->alias, 1); -+ if (!is_queueing) -+ dm_queue_if_no_path(mpp->alias, 1); - } else if (is_queueing && mpp->retry_tick == 0) - enter_recovery_mode(mpp); - break; -@@ -2072,6 +2073,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) - /* if update_multipath_strings orphaned the path, quit early */ - if (!pp->mpp) - return 0; -+ set_no_path_retry(pp->mpp); - - if ((newstate == PATH_UP || newstate == PATH_GHOST) && - check_path_reinstate_state(pp)) { --- -2.17.2 - diff --git a/0007-libmultipath-consolidate-group_by_-functions.patch b/0007-libmultipath-consolidate-group_by_-functions.patch new file mode 100644 index 0000000..98929d1 --- /dev/null +++ b/0007-libmultipath-consolidate-group_by_-functions.patch @@ -0,0 +1,253 @@ +From 9cccb06523154911282fd5b0840c6cfa6edd017e Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 3 Jul 2019 14:46:40 -0500 +Subject: [PATCH] libmultipath: consolidate group_by_* functions + +group_by_node_name() and group_by_serial() are exactly the same except +for how the paths are compared. group_by_prio() is different but its +pathvec solves the same issue as the bitmap from the other two +functions, and since we are always running sort_pathgroups() after +calling pgpriorityfn, there is no need to sort the pathgroups in +group_by_prio(). This means that all three functions can be replaced +with one function, group_by_match() that takes a match function as an +argument. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/pgpolicies.c | 189 +++++++++----------------------------- + 1 file changed, 41 insertions(+), 148 deletions(-) + +diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c +index 1af42f52..2e4db74c 100644 +--- a/libmultipath/pgpolicies.c ++++ b/libmultipath/pgpolicies.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "util.h" +@@ -104,10 +105,29 @@ int group_paths(struct multipath *mp) + return 0; + } + +-/* +- * One path group per unique tgt_node_name present in the path vector +- */ +-int group_by_node_name(struct multipath * mp) ++typedef bool (path_match_fn)(struct path *pp1, struct path *pp2); ++ ++bool ++node_names_match(struct path *pp1, struct path *pp2) ++{ ++ return (strncmp(pp1->tgt_node_name, pp2->tgt_node_name, ++ NODE_NAME_SIZE) == 0); ++} ++ ++bool ++serials_match(struct path *pp1, struct path *pp2) ++{ ++ return (strncmp(pp1->serial, pp2->serial, SERIAL_SIZE) == 0); ++} ++ ++bool ++prios_match(struct path *pp1, struct path *pp2) ++{ ++ return (pp1->priority == pp2->priority); ++} ++ ++int group_by_match(struct multipath * mp, ++ bool (*path_match_fn)(struct path *, struct path *)) + { + int i, j; + int * bitmap; +@@ -150,8 +170,7 @@ int group_by_node_name(struct multipath * mp) + + pp2 = VECTOR_SLOT(mp->paths, j); + +- if (!strncmp(pp->tgt_node_name, pp2->tgt_node_name, +- NODE_NAME_SIZE)) { ++ if (path_match_fn(pp, pp2)) { + if (store_path(pgp->paths, pp2)) + goto out1; + +@@ -171,70 +190,28 @@ out: + return 1; + } + ++/* ++ * One path group per unique tgt_node_name present in the path vector ++ */ ++int group_by_node_name(struct multipath * mp) ++{ ++ return group_by_match(mp, node_names_match); ++} ++ + /* + * One path group per unique serial number present in the path vector + */ + int group_by_serial(struct multipath * mp) + { +- int i, j; +- int * bitmap; +- struct path * pp; +- struct pathgroup * pgp; +- struct path * pp2; +- +- /* init the bitmap */ +- bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int)); +- +- if (!bitmap) +- goto out; +- +- for (i = 0; i < VECTOR_SIZE(mp->paths); i++) { +- +- if (bitmap[i]) +- continue; +- +- pp = VECTOR_SLOT(mp->paths, i); +- +- /* here, we really got a new pg */ +- pgp = alloc_pathgroup(); +- +- if (!pgp) +- goto out1; +- +- if (add_pathgroup(mp, pgp)) +- goto out2; +- +- /* feed the first path */ +- if (store_path(pgp->paths, pp)) +- goto out1; +- +- bitmap[i] = 1; +- +- for (j = i + 1; j < VECTOR_SIZE(mp->paths); j++) { +- +- if (bitmap[j]) +- continue; +- +- pp2 = VECTOR_SLOT(mp->paths, j); +- +- if (0 == strcmp(pp->serial, pp2->serial)) { +- if (store_path(pgp->paths, pp2)) +- goto out1; ++ return group_by_match(mp, serials_match); ++} + +- bitmap[j] = 1; +- } +- } +- } +- FREE(bitmap); +- return 0; +-out2: +- free_pathgroup(pgp, KEEP_PATHS); +-out1: +- FREE(bitmap); +-out: +- free_pgvec(mp->pg, KEEP_PATHS); +- mp->pg = NULL; +- return 1; ++/* ++ * One path group per priority present in the path vector ++ */ ++int group_by_prio(struct multipath *mp) ++{ ++ return group_by_match(mp, prios_match); + } + + int one_path_per_group(struct multipath *mp) +@@ -293,87 +270,3 @@ out: + mp->pg = NULL; + return 1; + } +- +-int group_by_prio(struct multipath *mp) +-{ +- int i; +- int prio; +- struct path * pp; +- struct pathgroup * pgp; +- vector pathvec = NULL; +- +- pathvec = vector_alloc(); +- if (!pathvec) +- goto out; +- +- vector_foreach_slot(mp->paths, pp, i) { +- if (!vector_alloc_slot(pathvec)) +- goto out1; +- vector_set_slot(pathvec, pp); +- } +- +- while (VECTOR_SIZE(pathvec) > 0) { +- pp = VECTOR_SLOT(pathvec, 0); +- prio = pp->priority; +- +- /* +- * Find the position to insert the new path group. All groups +- * are ordered by the priority value (higher value first). +- */ +- vector_foreach_slot(mp->pg, pgp, i) { +- pp = VECTOR_SLOT(pgp->paths, 0); +- +- if (prio > pp->priority) +- break; +- } +- +- /* +- * Initialize the new path group. +- */ +- pgp = alloc_pathgroup(); +- +- if (!pgp) +- goto out1; +- +- if (store_path(pgp->paths, VECTOR_SLOT(pathvec, 0))) +- goto out2; +- +- vector_del_slot(pathvec, 0); +- +- /* +- * Store the new path group into the vector. +- */ +- if (i < VECTOR_SIZE(mp->pg)) { +- if (!vector_insert_slot(mp->pg, i, pgp)) +- goto out2; +- pgp->mpp = mp; +- } else { +- if (add_pathgroup(mp, pgp)) +- goto out2; +- } +- +- /* +- * add the other paths with the same prio +- */ +- vector_foreach_slot(pathvec, pp, i) { +- if (pp->priority == prio) { +- if (store_path(pgp->paths, pp)) +- goto out1; +- +- vector_del_slot(pathvec, i); +- i--; +- } +- } +- } +- free_pathvec(pathvec, KEEP_PATHS); +- return 0; +-out2: +- free_pathgroup(pgp, KEEP_PATHS); +-out1: +- free_pathvec(pathvec, KEEP_PATHS); +-out: +- free_pgvec(mp->pg, KEEP_PATHS); +- mp->pg = NULL; +- return 1; +- +-} +-- +2.17.2 + diff --git a/0007-multipathd-ignore-failed-wwid-recheck.patch b/0007-multipathd-ignore-failed-wwid-recheck.patch deleted file mode 100644 index 37fdae1..0000000 --- a/0007-multipathd-ignore-failed-wwid-recheck.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Wed, 20 Feb 2019 17:05:08 -0600 -Subject: [PATCH] multipathd: ignore failed wwid recheck - -If disable_changed_wwids is set, when multipathd gets a change event on -a path, it verifies that the wwid hasn't changed in uev_update_path(). -If get_uid() failed, uev_update_path treated this as a wwid change to 0. -This could cause paths to suddenly be dropped due to an issue with -getting the wwid. Even if get_uid() failed because the path was down, -it no change uevent happend when it later became active, multipathd -would continue to ignore the path. Also, scsi_uid_fallback() clears the -failure return if it doesn't attempt to fallback, causing get_uid() -to return success, when it actually failed. - -Multipathd should neither set nor clear wwid_changed if get_uid() -returned failure. Also, scsi_uid_fallback() should retain the old return -value if it doesn't attempt to fallback. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/discovery.c | 6 +++--- - multipathd/main.c | 6 ++++-- - 2 files changed, 7 insertions(+), 5 deletions(-) - -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index 729bcb9..b08cb2d 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1755,9 +1755,9 @@ get_vpd_uid(struct path * pp) - } - - static ssize_t scsi_uid_fallback(struct path *pp, int path_state, -- const char **origin) -+ const char **origin, ssize_t old_len) - { -- ssize_t len = 0; -+ ssize_t len = old_len; - int retrigger; - struct config *conf; - -@@ -1828,7 +1828,7 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) - origin = "sysfs"; - } - if (len <= 0 && pp->bus == SYSFS_BUS_SCSI) -- len = scsi_uid_fallback(pp, path_state, &origin); -+ len = scsi_uid_fallback(pp, path_state, &origin, len); - } - if ( len < 0 ) { - condlog(1, "%s: failed to get %s uid: %s", -diff --git a/multipathd/main.c b/multipathd/main.c -index 678ecf8..fd83a6a 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -1234,9 +1234,11 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - goto out; - - strcpy(wwid, pp->wwid); -- get_uid(pp, pp->state, uev->udev); -+ rc = get_uid(pp, pp->state, uev->udev); - -- if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { -+ if (rc != 0) -+ strcpy(pp->wwid, wwid); -+ else if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { - condlog(0, "%s: path wwid changed from '%s' to '%s'. %s", - uev->kernel, wwid, pp->wwid, - (disable_changed_wwids ? "disallowing" : --- -2.17.2 - diff --git a/0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch b/0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch new file mode 100644 index 0000000..35f96d7 --- /dev/null +++ b/0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch @@ -0,0 +1,174 @@ +From 1e45eb6db98185ac8917c0c8feec69b7c0226230 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 11 Jul 2019 18:13:06 -0500 +Subject: [PATCH] libmultipath: make pgpolicyfn take a paths vector + +To enable future changes, mp->pgpolicyfn() now takes a vector of +paths instead of always using mp->paths. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/pgpolicies.c | 38 +++++++++++++++++++------------------- + libmultipath/pgpolicies.h | 10 +++++----- + libmultipath/structs.h | 2 +- + 3 files changed, 25 insertions(+), 25 deletions(-) + +diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c +index 2e4db74c..2e7c0502 100644 +--- a/libmultipath/pgpolicies.c ++++ b/libmultipath/pgpolicies.c +@@ -93,7 +93,7 @@ int group_paths(struct multipath *mp) + return 1; + + if (VECTOR_SIZE(mp->paths) > 0 && +- (!mp->pgpolicyfn || mp->pgpolicyfn(mp))) { ++ (!mp->pgpolicyfn || mp->pgpolicyfn(mp, mp->paths))) { + vector_free(mp->pg); + mp->pg = NULL; + return 1; +@@ -126,7 +126,7 @@ prios_match(struct path *pp1, struct path *pp2) + return (pp1->priority == pp2->priority); + } + +-int group_by_match(struct multipath * mp, ++int group_by_match(struct multipath * mp, vector paths, + bool (*path_match_fn)(struct path *, struct path *)) + { + int i, j; +@@ -136,17 +136,17 @@ int group_by_match(struct multipath * mp, + struct path * pp2; + + /* init the bitmap */ +- bitmap = (int *)MALLOC(VECTOR_SIZE(mp->paths) * sizeof (int)); ++ bitmap = (int *)MALLOC(VECTOR_SIZE(paths) * sizeof (int)); + + if (!bitmap) + goto out; + +- for (i = 0; i < VECTOR_SIZE(mp->paths); i++) { ++ for (i = 0; i < VECTOR_SIZE(paths); i++) { + + if (bitmap[i]) + continue; + +- pp = VECTOR_SLOT(mp->paths, i); ++ pp = VECTOR_SLOT(paths, i); + + /* here, we really got a new pg */ + pgp = alloc_pathgroup(); +@@ -163,12 +163,12 @@ int group_by_match(struct multipath * mp, + + bitmap[i] = 1; + +- for (j = i + 1; j < VECTOR_SIZE(mp->paths); j++) { ++ for (j = i + 1; j < VECTOR_SIZE(paths); j++) { + + if (bitmap[j]) + continue; + +- pp2 = VECTOR_SLOT(mp->paths, j); ++ pp2 = VECTOR_SLOT(paths, j); + + if (path_match_fn(pp, pp2)) { + if (store_path(pgp->paths, pp2)) +@@ -193,35 +193,35 @@ out: + /* + * One path group per unique tgt_node_name present in the path vector + */ +-int group_by_node_name(struct multipath * mp) ++int group_by_node_name(struct multipath * mp, vector paths) + { +- return group_by_match(mp, node_names_match); ++ return group_by_match(mp, paths, node_names_match); + } + + /* + * One path group per unique serial number present in the path vector + */ +-int group_by_serial(struct multipath * mp) ++int group_by_serial(struct multipath * mp, vector paths) + { +- return group_by_match(mp, serials_match); ++ return group_by_match(mp, paths, serials_match); + } + + /* + * One path group per priority present in the path vector + */ +-int group_by_prio(struct multipath *mp) ++int group_by_prio(struct multipath *mp, vector paths) + { +- return group_by_match(mp, prios_match); ++ return group_by_match(mp, paths, prios_match); + } + +-int one_path_per_group(struct multipath *mp) ++int one_path_per_group(struct multipath *mp, vector paths) + { + int i; + struct path * pp; + struct pathgroup * pgp; + +- for (i = 0; i < VECTOR_SIZE(mp->paths); i++) { +- pp = VECTOR_SLOT(mp->paths, i); ++ for (i = 0; i < VECTOR_SIZE(paths); i++) { ++ pp = VECTOR_SLOT(paths, i); + pgp = alloc_pathgroup(); + + if (!pgp) +@@ -242,7 +242,7 @@ out: + return 1; + } + +-int one_group(struct multipath *mp) /* aka multibus */ ++int one_group(struct multipath *mp, vector paths) /* aka multibus */ + { + int i; + struct path * pp; +@@ -256,8 +256,8 @@ int one_group(struct multipath *mp) /* aka multibus */ + if (add_pathgroup(mp, pgp)) + goto out1; + +- for (i = 0; i < VECTOR_SIZE(mp->paths); i++) { +- pp = VECTOR_SLOT(mp->paths, i); ++ for (i = 0; i < VECTOR_SIZE(paths); i++) { ++ pp = VECTOR_SLOT(paths, i); + + if (store_path(pgp->paths, pp)) + goto out; +diff --git a/libmultipath/pgpolicies.h b/libmultipath/pgpolicies.h +index 11834011..7532d75f 100644 +--- a/libmultipath/pgpolicies.h ++++ b/libmultipath/pgpolicies.h +@@ -25,10 +25,10 @@ int group_paths(struct multipath *); + /* + * policies + */ +-int one_path_per_group(struct multipath *); +-int one_group(struct multipath *); +-int group_by_serial(struct multipath *); +-int group_by_prio(struct multipath *); +-int group_by_node_name(struct multipath *); ++int one_path_per_group(struct multipath *, vector); ++int one_group(struct multipath *, vector); ++int group_by_serial(struct multipath *, vector); ++int group_by_prio(struct multipath *, vector); ++int group_by_node_name(struct multipath *, vector); + + #endif +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 893074eb..a8b9d325 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -295,7 +295,7 @@ struct path { + struct gen_path generic_path; + }; + +-typedef int (pgpolicyfn) (struct multipath *); ++typedef int (pgpolicyfn) (struct multipath *, vector); + + struct multipath { + char wwid[WWID_SIZE]; +-- +2.17.2 + diff --git a/0008-libmutipath-continue-to-use-old-state-on-PATH_PENDIN.patch b/0008-libmutipath-continue-to-use-old-state-on-PATH_PENDIN.patch deleted file mode 100644 index aa43b94..0000000 --- a/0008-libmutipath-continue-to-use-old-state-on-PATH_PENDIN.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Thu, 21 Feb 2019 13:05:43 -0600 -Subject: [PATCH] libmutipath: continue to use old state on PATH_PENDING - -When pathinfo() sets pp->state to PATH_PENDING, it can cause problems -with path checking. It should act more like check_path(). When -check_path() sees a new state of PATH_PENDING, it doesn't update the -path state at all, so a path's old state is normally never PATH_PENDING. - -As and example of the problems of setting a path to PATH_PENDING, If -check_path() sets a path's state to PATH_UP, then a call to pathinfo() -sets the state to PATH_PENDING, and then another call the check_path() -sets the state to PATH_DOWN, multipathd won't fail the path in the -kernel. Also, if a path's state is PATH_PENDING, and nr_active is -recalculated, that path will count as down, even if the state was -previously PATH_UP. If a path already has a state of PATH_WILD or -PATH_UNCHECKED, changing it to PATH_PENDING won't hurt anything, and it -will help anyone who sees it know what's actually happening. But -otherwise, pathinfo() should leave the previous state alone. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/discovery.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index b08cb2d..28c00e5 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1946,8 +1946,11 @@ int pathinfo(struct path *pp, struct config *conf, int mask) - - if (mask & DI_CHECKER) { - if (path_state == PATH_UP) { -- pp->chkrstate = pp->state = get_state(pp, conf, 0, -- path_state); -+ int newstate = get_state(pp, conf, 0, path_state); -+ if (newstate != PATH_PENDING || -+ pp->state == PATH_UNCHECKED || -+ pp->state == PATH_WILD) -+ pp->chkrstate = pp->state = newstate; - if (pp->state == PATH_TIMEOUT) - pp->state = PATH_DOWN; - if (pp->state == PATH_UP && !pp->size) { --- -2.17.2 - diff --git a/0009-libmultipath-make-group_paths-handle-marginal-paths.patch b/0009-libmultipath-make-group_paths-handle-marginal-paths.patch new file mode 100644 index 0000000..9791689 --- /dev/null +++ b/0009-libmultipath-make-group_paths-handle-marginal-paths.patch @@ -0,0 +1,185 @@ +From 227a9fceb8c20f153f4f136caeb28faff5bd80fe Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 12 Jul 2019 15:39:26 -0500 +Subject: [PATCH] libmultipath: make group_paths handle marginal paths + +group_paths() will now create seperate path groups for marginal and +normal paths, and place all of the marginal path groups after the normal +ones, in order by priority. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/pgpolicies.c | 83 +++++++++++++++++++++++++++++++++----- + libmultipath/switchgroup.c | 15 ++++++- + 2 files changed, 88 insertions(+), 10 deletions(-) + +diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c +index 2e7c0502..6fb2d28a 100644 +--- a/libmultipath/pgpolicies.c ++++ b/libmultipath/pgpolicies.c +@@ -72,9 +72,11 @@ sort_pathgroups (struct multipath *mp) { + pgp2 = VECTOR_SLOT(mp->pg, j); + if (!pgp2) + continue; +- if (pgp2->priority > pgp1->priority || +- (pgp2->priority == pgp1->priority && +- pgp2->enabled_paths >= pgp1->enabled_paths)) { ++ if (pgp2->marginal < pgp1->marginal || ++ (pgp2->marginal == pgp1->marginal && ++ (pgp2->priority > pgp1->priority || ++ (pgp2->priority == pgp1->priority && ++ pgp2->enabled_paths >= pgp1->enabled_paths)))) { + vector_move_up(mp->pg, i, j + 1); + break; + } +@@ -84,25 +86,88 @@ sort_pathgroups (struct multipath *mp) { + } + } + ++static int ++split_marginal_paths(vector paths, vector *normal_p, vector *marginal_p) ++{ ++ int i; ++ int has_marginal = 0; ++ int has_normal = 0; ++ struct path *pp; ++ vector normal = NULL; ++ vector marginal = NULL; ++ ++ *normal_p = *marginal_p = NULL; ++ vector_foreach_slot(paths, pp, i) { ++ if (pp->marginal) ++ has_marginal = 1; ++ else ++ has_normal = 1; ++ } ++ ++ if (!has_marginal || !has_normal) ++ return -1; ++ ++ normal = vector_alloc(); ++ marginal = vector_alloc(); ++ if (!normal || !marginal) ++ goto fail; ++ ++ vector_foreach_slot(paths, pp, i) { ++ if (pp->marginal) { ++ if (store_path(marginal, pp)) ++ goto fail; ++ } ++ else { ++ if (store_path(normal, pp)) ++ goto fail; ++ } ++ } ++ *normal_p = normal; ++ *marginal_p = marginal; ++ return 0; ++fail: ++ vector_free(normal); ++ vector_free(marginal); ++ return -1; ++} + + int group_paths(struct multipath *mp) + { ++ vector normal, marginal; ++ + if (!mp->pg) + mp->pg = vector_alloc(); + if (!mp->pg) + return 1; + +- if (VECTOR_SIZE(mp->paths) > 0 && +- (!mp->pgpolicyfn || mp->pgpolicyfn(mp, mp->paths))) { +- vector_free(mp->pg); +- mp->pg = NULL; +- return 1; ++ if (VECTOR_SIZE(mp->paths) == 0) ++ goto out; ++ if (!mp->pgpolicyfn) ++ goto fail; ++ ++ if (split_marginal_paths(mp->paths, &normal, &marginal) != 0) { ++ if (mp->pgpolicyfn(mp, mp->paths) != 0) ++ goto fail; ++ } else { ++ if (mp->pgpolicyfn(mp, normal) != 0) ++ goto fail_marginal; ++ if (mp->pgpolicyfn(mp, marginal) != 0) ++ goto fail_marginal; ++ vector_free(normal); ++ vector_free(marginal); + } +- + sort_pathgroups(mp); ++out: + vector_free(mp->paths); + mp->paths = NULL; + return 0; ++fail_marginal: ++ vector_free(normal); ++ vector_free(marginal); ++fail: ++ vector_free(mp->pg); ++ mp->pg = NULL; ++ return 1; + } + + typedef bool (path_match_fn)(struct path *pp1, struct path *pp2); +diff --git a/libmultipath/switchgroup.c b/libmultipath/switchgroup.c +index 9632ce2d..6fdfcfa7 100644 +--- a/libmultipath/switchgroup.c ++++ b/libmultipath/switchgroup.c +@@ -11,6 +11,7 @@ void path_group_prio_update(struct pathgroup *pgp) + { + int i; + int priority = 0; ++ int marginal = 0; + struct path * pp; + + pgp->enabled_paths = 0; +@@ -19,6 +20,8 @@ void path_group_prio_update(struct pathgroup *pgp) + return; + } + vector_foreach_slot (pgp->paths, pp, i) { ++ if (pp->marginal) ++ marginal++; + if (pp->state == PATH_UP || + pp->state == PATH_GHOST) { + priority += pp->priority; +@@ -29,11 +32,14 @@ void path_group_prio_update(struct pathgroup *pgp) + pgp->priority = priority / pgp->enabled_paths; + else + pgp->priority = 0; ++ if (marginal && marginal == i) ++ pgp->marginal = 1; + } + + int select_path_group(struct multipath *mpp) + { + int i; ++ int normal_pgp = 0; + int max_priority = 0; + int bestpg = 1; + int max_enabled_paths = 1; +@@ -47,8 +53,15 @@ int select_path_group(struct multipath *mpp) + continue; + + path_group_prio_update(pgp); ++ if (pgp->marginal && normal_pgp) ++ continue; + if (pgp->enabled_paths) { +- if (pgp->priority > max_priority) { ++ if (!pgp->marginal && !normal_pgp) { ++ normal_pgp = 1; ++ max_priority = pgp->priority; ++ max_enabled_paths = pgp->enabled_paths; ++ bestpg = i + 1; ++ } else if (pgp->priority > max_priority) { + max_priority = pgp->priority; + max_enabled_paths = pgp->enabled_paths; + bestpg = i + 1; +-- +2.17.2 + diff --git a/0009-multipathd-use-update_path_groups-instead-of-reload_.patch b/0009-multipathd-use-update_path_groups-instead-of-reload_.patch deleted file mode 100644 index cc429c5..0000000 --- a/0009-multipathd-use-update_path_groups-instead-of-reload_.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Thu, 21 Feb 2019 17:00:17 -0600 -Subject: [PATCH] multipathd: use update_path_groups instead of reload_map - -reload_map() doesn't do the work to sync the state after reloading the -map. Instead of calling it directly, cli_reload() and uev_update_path() -should call update_path_groups(), which calls reload_map() with all the -necessary syncing. - -Signed-off-by: Benjamin Marzinski ---- - multipathd/cli_handlers.c | 2 +- - multipathd/main.c | 13 ++++++++----- - multipathd/main.h | 2 ++ - 3 files changed, 11 insertions(+), 6 deletions(-) - -diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c -index f95813e..60e17d6 100644 ---- a/multipathd/cli_handlers.c -+++ b/multipathd/cli_handlers.c -@@ -877,7 +877,7 @@ cli_reload(void *v, char **reply, int *len, void *data) - return 1; - } - -- return reload_map(vecs, mpp, 0, 1); -+ return update_path_groups(mpp, vecs, 0); - } - - int resize_map(struct multipath *mpp, unsigned long long size, -diff --git a/multipathd/main.c b/multipathd/main.c -index fd83a6a..7a317d9 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -1273,10 +1273,13 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - else { - if (ro == 1) - pp->mpp->force_readonly = 1; -- retval = reload_map(vecs, mpp, 0, 1); -- pp->mpp->force_readonly = 0; -- condlog(2, "%s: map %s reloaded (retval %d)", -- uev->kernel, mpp->alias, retval); -+ retval = update_path_groups(mpp, vecs, 0); -+ if (retval == 2) -+ condlog(2, "%s: map removed during reload", pp->dev); -+ else { -+ pp->mpp->force_readonly = 0; -+ condlog(2, "%s: map %s reloaded (retval %d)", uev->kernel, mpp->alias, retval); -+ } - } - } - } -@@ -1832,7 +1835,7 @@ int update_path_groups(struct multipath *mpp, struct vectors *vecs, int refresh) - - dm_lib_release(); - if (setup_multipath(vecs, mpp) != 0) -- return 1; -+ return 2; - sync_map_state(mpp); - - return 0; -diff --git a/multipathd/main.h b/multipathd/main.h -index 8fd426b..e5c1398 100644 ---- a/multipathd/main.h -+++ b/multipathd/main.h -@@ -43,5 +43,7 @@ int __setup_multipath (struct vectors * vecs, struct multipath * mpp, - int reset); - #define setup_multipath(vecs, mpp) __setup_multipath(vecs, mpp, 1) - int update_multipath (struct vectors *vecs, char *mapname, int reset); -+int update_path_groups(struct multipath *mpp, struct vectors *vecs, -+ int refresh); - - #endif /* MAIN_H */ --- -2.17.2 - diff --git a/0010-multipath.conf-add-missing-options-to-man-page.patch b/0010-multipath.conf-add-missing-options-to-man-page.patch deleted file mode 100644 index 394952d..0000000 --- a/0010-multipath.conf-add-missing-options-to-man-page.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Tue, 26 Feb 2019 12:22:59 -0600 -Subject: [PATCH] multipath.conf: add missing options to man page - -Signed-off-by: Benjamin Marzinski ---- - multipath/multipath.conf.5 | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 -index 0fe8461..864d7eb 100644 ---- a/multipath/multipath.conf.5 -+++ b/multipath/multipath.conf.5 -@@ -1468,6 +1468,8 @@ section: - .TP - .B uid_attribute - .TP -+.B getuid_callout -+.TP - .B path_selector - .TP - .B path_checker -@@ -1494,6 +1496,8 @@ section: - .TP - .B flush_on_last_del - .TP -+.B user_friendly_names -+.TP - .B retain_attached_hw_handler - .TP - .B detect_prio -@@ -1525,6 +1529,8 @@ section: - .B max_sectors_kb - .TP - .B ghost_delay -+.TP -+.B all_tg_pt - .RE - .PD - .LP -@@ -1604,7 +1610,11 @@ the values are taken from the \fIdevices\fR or \fIdefaults\fR sections: - .TP - .B skip_kpartx - .TP -+.B max_sectors_kb -+.TP - .B ghost_delay -+.TP -+.B all_tg_pt - .RE - .PD - .LP --- -2.17.2 - diff --git a/0010-tests-add-tests-for-grouping-marginal-paths.patch b/0010-tests-add-tests-for-grouping-marginal-paths.patch new file mode 100644 index 0000000..aba1563 --- /dev/null +++ b/0010-tests-add-tests-for-grouping-marginal-paths.patch @@ -0,0 +1,701 @@ +From ede846d1761709e2832c0a4c777369ae89692841 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 23 Jul 2019 13:21:12 -0500 +Subject: [PATCH] tests: add tests for grouping marginal paths. + +Signed-off-by: Benjamin Marzinski +--- + tests/pgpolicy.c | 337 +++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 295 insertions(+), 42 deletions(-) + +diff --git a/tests/pgpolicy.c b/tests/pgpolicy.c +index 04a77c4c..ab09f91c 100644 +--- a/tests/pgpolicy.c ++++ b/tests/pgpolicy.c +@@ -40,6 +40,15 @@ static void set_priority(struct path *pp, int *prio, int size) + } + } + ++static void set_marginal(struct path *pp, int *marginal, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++) { ++ pp[i].marginal = marginal[i]; ++ } ++} ++ + static void set_tgt_node_name(struct path *pp, char **tgt_node_name, int size) + { + int i; +@@ -82,6 +91,7 @@ static int setupX(struct multipath *mp, struct path *pp, int size) + { + int i; + int prio[8] = {10, 10, 10, 10, 10, 10, 10, 10}; ++ int marginal[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + mp->paths = vector_alloc(); + if (!mp->paths) +@@ -92,6 +102,7 @@ static int setupX(struct multipath *mp, struct path *pp, int size) + vector_set_slot(mp->paths, &pp[i]); + } + set_priority(pp, prio, size); ++ set_marginal(pp, marginal, size); + mp->pgpolicyfn = NULL; + return 0; + } +@@ -155,7 +166,7 @@ static int teardown_null(void **state) + + static void + verify_pathgroups(struct multipath *mp, struct path *pp, int **groups, +- int *group_size, int size) ++ int *group_size, int *marginal, int size) + { + int i, j; + struct pathgroup *pgp; +@@ -168,6 +179,10 @@ verify_pathgroups(struct multipath *mp, struct path *pp, int **groups, + assert_non_null(pgp); + assert_non_null(pgp->paths); + assert_int_equal(VECTOR_SIZE(pgp->paths), group_size[i]); ++ if (marginal) ++ assert_int_equal(pgp->marginal, marginal[i]); ++ else ++ assert_int_equal(pgp->marginal, 0); + for (j = 0; j < group_size[i]; j++) { + int path_nr = groups[i][j]; + struct path *pgp_path = VECTOR_SLOT(pgp->paths, j); +@@ -190,7 +205,7 @@ static void test_one_group8(void **state) + + mp8.pgpolicyfn = one_group; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 1); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + + static void test_one_group4(void **state) +@@ -201,7 +216,7 @@ static void test_one_group4(void **state) + + mp4.pgpolicyfn = one_group; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 1); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 1); + } + + static void test_one_group1(void **state) +@@ -212,21 +227,65 @@ static void test_one_group1(void **state) + + mp1.pgpolicyfn = one_group; + assert_int_equal(group_paths(&mp1), 0); +- verify_pathgroups(&mp1, p1, groups, group_size, 1); ++ verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_one_group0(void **state) + { + mp0.pgpolicyfn = one_group; + assert_int_equal(group_paths(&mp0), 0); +- verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_one_group_null(void **state) + { + mp_null.pgpolicyfn = one_group; + assert_int_equal(group_paths(&mp_null), 0); +- verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); ++} ++ ++static void test_one_group_all_marginal8(void **state) ++{ ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int marginal[] = {1,1,1,1,1,1,1,1}; ++ int *groups[] = {paths}; ++ int group_size[] = {8}; ++ int group_marginal[] = {1}; ++ ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 1); ++} ++ ++static void test_one_group_half_marginal8(void **state) ++{ ++ int marginal[] = {1,0,1,0,1,1,0,0}; ++ int group0[] = {1,3,6,7}; ++ int group1[] = {0,2,4,5}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {4,4}; ++ int group_marginal[] = {0,1}; ++ ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); ++} ++ ++static void test_one_group_one_marginal8(void **state) ++{ ++ int marginal[] = {0,0,0,0,0,1,0,0}; ++ int group0[] = {0,1,2,3,4,6,7}; ++ int group1[] = {5}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {7,1}; ++ int group_marginal[] = {0,1}; ++ ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); + } + + static void test_one_path_per_group_same8(void **state) +@@ -238,7 +297,7 @@ static void test_one_path_per_group_same8(void **state) + + mp8.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_one_path_per_group_increasing8(void **state) +@@ -252,7 +311,7 @@ static void test_one_path_per_group_increasing8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_one_path_per_group_decreasing8(void **state) +@@ -266,7 +325,7 @@ static void test_one_path_per_group_decreasing8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_one_path_per_group_mixed8(void **state) +@@ -280,7 +339,7 @@ static void test_one_path_per_group_mixed8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_one_path_per_group4(void **state) +@@ -291,7 +350,7 @@ static void test_one_path_per_group4(void **state) + + mp4.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 4); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 4); + } + + static void test_one_path_per_group1(void **state) +@@ -302,21 +361,55 @@ static void test_one_path_per_group1(void **state) + + mp1.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp1), 0); +- verify_pathgroups(&mp1, p1, groups, group_size, 1); ++ verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_one_path_per_group0(void **state) + { + mp0.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp0), 0); +- verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_one_path_per_group_null(void **state) + { + mp_null.pgpolicyfn = one_path_per_group; + assert_int_equal(group_paths(&mp_null), 0); +- verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); ++} ++ ++static void test_one_path_per_group_mixed_all_marginal8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int marginal[] = {1,1,1,1,1,1,1,1}; ++ int paths[] = {6,0,4,2,3,5,7,1}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ int group_marginal[] = {1,1,1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 8); ++} ++ ++static void test_one_path_per_group_mixed_half_marginal8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int marginal[] = {0,1,1,0,0,0,1,1}; ++ int paths[] = {0,4,3,5,6,2,7,1}; ++ int *groups[] = {&paths[0], &paths[1], &paths[2], &paths[3], ++ &paths[4], &paths[5], &paths[6], &paths[7]}; ++ int group_size[] = {1,1,1,1,1,1,1,1}; ++ int group_marginal[] = {0,0,0,0,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = one_path_per_group; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 8); + } + + static void test_group_by_prio_same8(void **state) +@@ -327,7 +420,7 @@ static void test_group_by_prio_same8(void **state) + + mp8.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 1); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + + static void test_group_by_prio_increasing8(void **state) +@@ -341,7 +434,7 @@ static void test_group_by_prio_increasing8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_group_by_prio_decreasing8(void **state) +@@ -355,7 +448,7 @@ static void test_group_by_prio_decreasing8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_group_by_prio_mixed8(void **state) +@@ -374,7 +467,7 @@ static void test_group_by_prio_mixed8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 6); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 6); + } + + static void test_group_by_prio_2_groups8(void **state) +@@ -388,7 +481,7 @@ static void test_group_by_prio_2_groups8(void **state) + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 2); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 2); + } + + static void test_group_by_prio_mixed4(void **state) +@@ -403,7 +496,7 @@ static void test_group_by_prio_mixed4(void **state) + set_priority(p4, prio, 4); + mp4.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 3); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 3); + } + + static void test_group_by_prio_2_groups4(void **state) +@@ -417,7 +510,7 @@ static void test_group_by_prio_2_groups4(void **state) + set_priority(p4, prio, 4); + mp4.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 2); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 2); + } + + static void test_group_by_prio1(void **state) +@@ -428,21 +521,89 @@ static void test_group_by_prio1(void **state) + + mp1.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp1), 0); +- verify_pathgroups(&mp1, p1, groups, group_size, 1); ++ verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_group_by_prio0(void **state) + { + mp0.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp0), 0); +- verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_group_by_prio_null(void **state) + { + mp_null.pgpolicyfn = group_by_prio; + assert_int_equal(group_paths(&mp_null), 0); +- verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_prio_mixed_all_marginal8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int marginal[] = {1,1,1,1,1,1,1,1}; ++ int group0[] = {6}; ++ int group1[] = {0}; ++ int group2[] = {4}; ++ int group3[] = {2,3}; ++ int group4[] = {5,7}; ++ int group5[] = {1}; ++ int *groups[] = {group0, group1, group2, group3, ++ group4, group5}; ++ int group_size[] = {1,1,1,2,2,1}; ++ int group_marginal[] = {1,1,1,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 6); ++} ++ ++static void test_group_by_prio_mixed_half_marginal8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int marginal[] = {0,0,0,1,0,1,1,1}; ++ int group0[] = {0}; ++ int group1[] = {4}; ++ int group2[] = {2}; ++ int group3[] = {1}; ++ int group4[] = {6}; ++ int group5[] = {3}; ++ int group6[] = {5,7}; ++ int *groups[] = {group0, group1, group2, group3, ++ group4, group5, group6}; ++ int group_size[] = {1,1,1,1,1,1,2}; ++ int group_marginal[] = {0,0,0,0,1,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 7); ++} ++ ++static void test_group_by_prio_mixed_one_marginal8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int marginal[] = {0,0,0,0,0,1,0,0}; ++ int group0[] = {6}; ++ int group1[] = {0}; ++ int group2[] = {4}; ++ int group3[] = {2,3}; ++ int group4[] = {7}; ++ int group5[] = {1}; ++ int group6[] = {5}; ++ int *groups[] = {group0, group1, group2, group3, ++ group4, group5, group6}; ++ int group_size[] = {1,1,1,2,1,1,1}; ++ int group_marginal[] = {0,0,0,0,0,0,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 7); + } + + static void test_group_by_node_name_same8(void **state) +@@ -455,7 +616,7 @@ static void test_group_by_node_name_same8(void **state) + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 1); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + + static void test_group_by_node_name_increasing8(void **state) +@@ -471,7 +632,7 @@ static void test_group_by_node_name_increasing8(void **state) + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_group_by_node_name_3_groups8(void **state) +@@ -488,7 +649,7 @@ static void test_group_by_node_name_3_groups8(void **state) + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 3); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 3); + } + + static void test_group_by_node_name_2_groups8(void **state) +@@ -504,7 +665,7 @@ static void test_group_by_node_name_2_groups8(void **state) + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 2); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 2); + } + + static void test_group_by_node_name_3_groups4(void **state) +@@ -521,7 +682,7 @@ static void test_group_by_node_name_3_groups4(void **state) + set_tgt_node_name(p4, node_name, 4); + mp4.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 3); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 3); + } + + static void test_group_by_node_name_2_groups4(void **state) +@@ -537,7 +698,7 @@ static void test_group_by_node_name_2_groups4(void **state) + set_tgt_node_name(p4, node_name, 4); + mp4.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 2); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 2); + } + + static void test_group_by_node_name1(void **state) +@@ -550,21 +711,61 @@ static void test_group_by_node_name1(void **state) + set_tgt_node_name(p1, node_name, 1); + mp1.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp1), 0); +- verify_pathgroups(&mp1, p1, groups, group_size, 1); ++ verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_group_by_node_name0(void **state) + { + mp0.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp0), 0); +- verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_group_by_node_name_null(void **state) + { + mp_null.pgpolicyfn = group_by_node_name; + assert_int_equal(group_paths(&mp_null), 0); +- verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_node_name_2_groups_all_marginal8(void **state) ++{ ++ char *node_name[] = {"a", "a", "b", "a", "b", "b", "b", "a"}; ++ int prio[] = {4,1,2,1,2,2,2,1}; ++ int marginal[] = {1,1,1,1,1,1,1,1}; ++ int group0[] = {2,4,5,6}; ++ int group1[] = {0,1,3,7}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {4,4}; ++ int group_marginal[] = {1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ set_tgt_node_name(p8, node_name, 8); ++ mp8.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); ++} ++ ++static void test_group_by_node_name_2_groups_half_marginal8(void **state) ++{ ++ char *node_name[] = {"a", "a", "b", "a", "b", "b", "b", "a"}; ++ int prio[] = {4,1,2,1,2,2,2,1}; ++ int marginal[] = {1,0,1,1,0,1,0,0}; ++ int group0[] = {4,6}; ++ int group1[] = {1,7}; ++ int group2[] = {0,3}; ++ int group3[] = {2,5}; ++ int *groups[] = {group0, group1, group2, group3}; ++ int group_size[] = {2,2,2,2}; ++ int group_marginal[] = {0,0,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_marginal(p8, marginal, 8); ++ set_tgt_node_name(p8, node_name, 8); ++ mp8.pgpolicyfn = group_by_node_name; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 4); + } + + static void test_group_by_serial_same8(void **state) +@@ -577,7 +778,7 @@ static void test_group_by_serial_same8(void **state) + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 1); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + + static void test_group_by_serial_increasing8(void **state) +@@ -593,7 +794,7 @@ static void test_group_by_serial_increasing8(void **state) + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 8); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + + static void test_group_by_serial_3_groups8(void **state) +@@ -610,7 +811,7 @@ static void test_group_by_serial_3_groups8(void **state) + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 3); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 3); + } + + static void test_group_by_serial_2_groups8(void **state) +@@ -626,7 +827,7 @@ static void test_group_by_serial_2_groups8(void **state) + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp8), 0); +- verify_pathgroups(&mp8, p8, groups, group_size, 2); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 2); + } + + static void test_group_by_serial_3_groups4(void **state) +@@ -643,7 +844,7 @@ static void test_group_by_serial_3_groups4(void **state) + set_serial(p4, serial, 4); + mp4.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 3); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 3); + } + + static void test_group_by_serial_2_groups4(void **state) +@@ -659,7 +860,7 @@ static void test_group_by_serial_2_groups4(void **state) + set_serial(p4, serial, 4); + mp4.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp4), 0); +- verify_pathgroups(&mp4, p4, groups, group_size, 2); ++ verify_pathgroups(&mp4, p4, groups, group_size, NULL, 2); + } + + static void test_group_by_serial1(void **state) +@@ -672,21 +873,61 @@ static void test_group_by_serial1(void **state) + set_serial(p1, serial, 1); + mp1.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp1), 0); +- verify_pathgroups(&mp1, p1, groups, group_size, 1); ++ verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_group_by_serial0(void **state) + { + mp0.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp0), 0); +- verify_pathgroups(&mp0, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_group_by_serial_null(void **state) + { + mp_null.pgpolicyfn = group_by_serial; + assert_int_equal(group_paths(&mp_null), 0); +- verify_pathgroups(&mp_null, NULL, NULL, NULL, 0); ++ verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); ++} ++ ++static void test_group_by_serial_2_groups8_all_marginal8(void **state) ++{ ++ char *serial[] = {"1", "2", "1", "1", "2", "2", "1", "2"}; ++ int marginal[] = {1,1,1,1,1,1,1,1}; ++ int prio[] = {3,2,2,1,2,2,1,2}; ++ int group0[] = {1,4,5,7}; ++ int group1[] = {0,2,3,6}; ++ int *groups[] = {group0, group1}; ++ int group_size[] = {4,4}; ++ int group_marginal[] = {1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_serial(p8, serial, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); ++} ++ ++static void test_group_by_serial_2_groups8_half_marginal8(void **state) ++{ ++ char *serial[] = {"1", "2", "1", "1", "2", "2", "1", "2"}; ++ int marginal[] = {0,0,1,1,1,1,0,0}; ++ int prio[] = {3,2,2,1,2,2,1,2}; ++ int group0[] = {0,6}; ++ int group1[] = {1,7}; ++ int group2[] = {4,5}; ++ int group3[] = {2,3}; ++ int *groups[] = {group0, group1, group2, group3}; ++ int group_size[] = {2,2,2,2}; ++ int group_marginal[] = {0,0,1,1}; ++ ++ set_priority(p8, prio, 8); ++ set_serial(p8, serial, 8); ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = group_by_serial; ++ assert_int_equal(group_paths(&mp8), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 4); + } + + #define setup_test(name, nr) \ +@@ -700,6 +941,9 @@ int test_pgpolicies(void) + setup_test(test_one_group, 1), + setup_test(test_one_group, 0), + setup_test(test_one_group, _null), ++ setup_test(test_one_group_all_marginal, 8), ++ setup_test(test_one_group_half_marginal, 8), ++ setup_test(test_one_group_one_marginal, 8), + setup_test(test_one_path_per_group_same, 8), + setup_test(test_one_path_per_group_increasing, 8), + setup_test(test_one_path_per_group_decreasing, 8), +@@ -708,6 +952,8 @@ int test_pgpolicies(void) + setup_test(test_one_path_per_group, 1), + setup_test(test_one_path_per_group, 0), + setup_test(test_one_path_per_group, _null), ++ setup_test(test_one_path_per_group_mixed_all_marginal, 8), ++ setup_test(test_one_path_per_group_mixed_half_marginal, 8), + setup_test(test_group_by_prio_same, 8), + setup_test(test_group_by_prio_increasing, 8), + setup_test(test_group_by_prio_decreasing, 8), +@@ -718,6 +964,9 @@ int test_pgpolicies(void) + setup_test(test_group_by_prio, 1), + setup_test(test_group_by_prio, 0), + setup_test(test_group_by_prio, _null), ++ setup_test(test_group_by_prio_mixed_all_marginal, 8), ++ setup_test(test_group_by_prio_mixed_half_marginal, 8), ++ setup_test(test_group_by_prio_mixed_one_marginal, 8), + setup_test(test_group_by_node_name_same, 8), + setup_test(test_group_by_node_name_increasing, 8), + setup_test(test_group_by_node_name_3_groups, 8), +@@ -727,6 +976,8 @@ int test_pgpolicies(void) + setup_test(test_group_by_node_name, 1), + setup_test(test_group_by_node_name, 0), + setup_test(test_group_by_node_name, _null), ++ setup_test(test_group_by_node_name_2_groups_all_marginal, 8), ++ setup_test(test_group_by_node_name_2_groups_half_marginal, 8), + setup_test(test_group_by_serial_same, 8), + setup_test(test_group_by_serial_increasing, 8), + setup_test(test_group_by_serial_3_groups, 8), +@@ -736,6 +987,8 @@ int test_pgpolicies(void) + setup_test(test_group_by_serial, 1), + setup_test(test_group_by_serial, 0), + setup_test(test_group_by_serial, _null), ++ setup_test(test_group_by_serial_2_groups8_all_marginal, 8), ++ setup_test(test_group_by_serial_2_groups8_half_marginal, 8), + }; + return cmocka_run_group_tests(tests, setup, NULL); + } +-- +2.17.2 + diff --git a/0011-libmultipath-add-get_uid-fallback-code-for-NVMe-devi.patch b/0011-libmultipath-add-get_uid-fallback-code-for-NVMe-devi.patch deleted file mode 100644 index 31cabca..0000000 --- a/0011-libmultipath-add-get_uid-fallback-code-for-NVMe-devi.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Thu, 7 Mar 2019 16:14:35 -0600 -Subject: [PATCH] libmultipath: add get_uid fallback code for NVMe devices - -If multipath can't get the uid for NVMe devices from udev, it can get it -directly from sysfs. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/discovery.c | 49 ++++++++++++++++++++++++++++------------ - 1 file changed, 34 insertions(+), 15 deletions(-) - -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index 28c00e5..bece67c 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1754,8 +1754,8 @@ get_vpd_uid(struct path * pp) - return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE); - } - --static ssize_t scsi_uid_fallback(struct path *pp, int path_state, -- const char **origin, ssize_t old_len) -+static ssize_t uid_fallback(struct path *pp, int path_state, -+ const char **origin, ssize_t old_len) - { - ssize_t len = old_len; - int retrigger; -@@ -1764,17 +1764,36 @@ static ssize_t scsi_uid_fallback(struct path *pp, int path_state, - conf = get_multipath_config(); - retrigger = conf->retrigger_tries; - put_multipath_config(conf); -- if (pp->retriggers >= retrigger && -- !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) { -- len = get_vpd_uid(pp); -- *origin = "sysfs"; -- pp->uid_attribute = NULL; -- if (len < 0 && path_state == PATH_UP) { -- condlog(1, "%s: failed to get sysfs uid: %s", -- pp->dev, strerror(-len)); -- len = get_vpd_sgio(pp->fd, 0x83, pp->wwid, -- WWID_SIZE); -- *origin = "sgio"; -+ if (pp->retriggers >= retrigger) { -+ if (pp->bus == SYSFS_BUS_SCSI && -+ !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) { -+ len = get_vpd_uid(pp); -+ *origin = "sysfs"; -+ pp->uid_attribute = NULL; -+ if (len < 0 && path_state == PATH_UP) { -+ condlog(1, "%s: failed to get sysfs uid: %s", -+ pp->dev, strerror(-len)); -+ len = get_vpd_sgio(pp->fd, 0x83, pp->wwid, -+ WWID_SIZE); -+ *origin = "sgio"; -+ } -+ } else if (pp->bus == SYSFS_BUS_NVME) { -+ char value[256]; -+ len = sysfs_attr_get_value(pp->udev, "wwid", value, -+ sizeof(value)); -+ if (len <= 0) -+ return -1; -+ len = strlcpy(pp->wwid, value, WWID_SIZE); -+ if (len >= WWID_SIZE) { -+ len = fix_broken_nvme_wwid(pp, value, -+ WWID_SIZE); -+ if (len > 0) -+ return len; -+ condlog(0, "%s: wwid overflow", pp->dev); -+ len = WWID_SIZE; -+ } -+ *origin = "sysfs"; -+ pp->uid_attribute = NULL; - } - } - return len; -@@ -1827,8 +1846,8 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) - len = get_vpd_uid(pp); - origin = "sysfs"; - } -- if (len <= 0 && pp->bus == SYSFS_BUS_SCSI) -- len = scsi_uid_fallback(pp, path_state, &origin, len); -+ if (len <= 0) -+ len = uid_fallback(pp, path_state, &origin, len); - } - if ( len < 0 ) { - condlog(1, "%s: failed to get %s uid: %s", --- -2.17.2 - diff --git a/0011-libmultipath-add-marginal_pathgroups-config-option.patch b/0011-libmultipath-add-marginal_pathgroups-config-option.patch new file mode 100644 index 0000000..3558922 --- /dev/null +++ b/0011-libmultipath-add-marginal_pathgroups-config-option.patch @@ -0,0 +1,642 @@ +From febf9b26fcc67d94ad06f06fc599f0ef90d84132 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 24 Jul 2019 10:04:40 -0500 +Subject: [PATCH] libmultipath: add marginal_pathgroups config option + +group_paths now gets passed this to determine whether to enable +marginal pathgroups. The unit tests have also been updated. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.h | 1 + + libmultipath/configure.c | 5 +- + libmultipath/dict.c | 3 + + libmultipath/pgpolicies.c | 5 +- + libmultipath/pgpolicies.h | 2 +- + tests/pgpolicy.c | 140 +++++++++++++++++++++++--------------- + 6 files changed, 98 insertions(+), 58 deletions(-) + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index ff2b4e86..0b978970 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -186,6 +186,7 @@ struct config { + int max_sectors_kb; + int ghost_delay; + int find_multipaths_timeout; ++ int marginal_pathgroups; + unsigned int version[3]; + + char * multipath_dir; +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 3c309d64..3238d485 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -297,7 +297,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + { + struct pathgroup * pgp; + struct config *conf; +- int i, n_paths; ++ int i, n_paths, marginal_pathgroups; + + /* + * don't bother if devmap size is unknown +@@ -357,6 +357,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + select_flush_on_last_del(conf, mpp); + + sysfs_set_scsi_tmo(mpp, conf->checkint); ++ marginal_pathgroups = conf->marginal_pathgroups; + pthread_cleanup_pop(1); + + if (marginal_path_check_enabled(mpp)) { +@@ -387,7 +388,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + vector_free(mpp->pg); + mpp->pg = NULL; + } +- if (group_paths(mpp)) ++ if (group_paths(mpp, marginal_pathgroups)) + return 1; + + /* +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index c6eba0f6..b5feb884 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -1339,6 +1339,8 @@ declare_ovr_snprint(all_tg_pt, print_yes_no_undef) + declare_hw_handler(all_tg_pt, set_yes_no_undef) + declare_hw_snprint(all_tg_pt, print_yes_no_undef) + ++declare_def_handler(marginal_pathgroups, set_yes_no) ++declare_def_snprint(marginal_pathgroups, print_yes_no) + + static int + def_uxsock_timeout_handler(struct config *conf, vector strvec) +@@ -1710,6 +1712,7 @@ init_keywords(vector keywords) + install_keyword("find_multipaths_timeout", + &def_find_multipaths_timeout_handler, + &snprint_def_find_multipaths_timeout); ++ install_keyword("marginal_pathgroups", &def_marginal_pathgroups_handler, &snprint_def_marginal_pathgroups); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c +index 6fb2d28a..8f7c6b13 100644 +--- a/libmultipath/pgpolicies.c ++++ b/libmultipath/pgpolicies.c +@@ -131,7 +131,7 @@ fail: + return -1; + } + +-int group_paths(struct multipath *mp) ++int group_paths(struct multipath *mp, int marginal_pathgroups) + { + vector normal, marginal; + +@@ -145,7 +145,8 @@ int group_paths(struct multipath *mp) + if (!mp->pgpolicyfn) + goto fail; + +- if (split_marginal_paths(mp->paths, &normal, &marginal) != 0) { ++ if (!marginal_pathgroups || ++ split_marginal_paths(mp->paths, &normal, &marginal) != 0) { + if (mp->pgpolicyfn(mp, mp->paths) != 0) + goto fail; + } else { +diff --git a/libmultipath/pgpolicies.h b/libmultipath/pgpolicies.h +index 7532d75f..15927610 100644 +--- a/libmultipath/pgpolicies.h ++++ b/libmultipath/pgpolicies.h +@@ -21,7 +21,7 @@ enum iopolicies { + + int get_pgpolicy_id(char *); + int get_pgpolicy_name (char *, int, int); +-int group_paths(struct multipath *); ++int group_paths(struct multipath *, int); + /* + * policies + */ +diff --git a/tests/pgpolicy.c b/tests/pgpolicy.c +index ab09f91c..3f61b123 100644 +--- a/tests/pgpolicy.c ++++ b/tests/pgpolicy.c +@@ -204,7 +204,7 @@ static void test_one_group8(void **state) + int group_size[] = {8}; + + mp8.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + +@@ -215,7 +215,7 @@ static void test_one_group4(void **state) + int group_size[] = {4}; + + mp4.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 1); + } + +@@ -226,21 +226,21 @@ static void test_one_group1(void **state) + int group_size[] = {1}; + + mp1.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp1), 0); ++ assert_int_equal(group_paths(&mp1, 0), 0); + verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_one_group0(void **state) + { + mp0.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp0), 0); ++ assert_int_equal(group_paths(&mp0, 0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_one_group_null(void **state) + { + mp_null.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp_null), 0); ++ assert_int_equal(group_paths(&mp_null, 0), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); + } + +@@ -254,7 +254,7 @@ static void test_one_group_all_marginal8(void **state) + + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 1); + } + +@@ -269,10 +269,23 @@ static void test_one_group_half_marginal8(void **state) + + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); + } + ++static void test_one_group_ignore_marginal8(void **state) ++{ ++ int marginal[] = {1,0,1,0,1,1,0,0}; ++ int paths[] = {0,1,2,3,4,5,6,7}; ++ int *groups[] = {paths}; ++ int group_size[] = {8}; ++ ++ set_marginal(p8, marginal, 8); ++ mp8.pgpolicyfn = one_group; ++ assert_int_equal(group_paths(&mp8, 0), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); ++} ++ + static void test_one_group_one_marginal8(void **state) + { + int marginal[] = {0,0,0,0,0,1,0,0}; +@@ -284,7 +297,7 @@ static void test_one_group_one_marginal8(void **state) + + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = one_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); + } + +@@ -296,7 +309,7 @@ static void test_one_path_per_group_same8(void **state) + int group_size[] = {1,1,1,1,1,1,1,1}; + + mp8.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -310,7 +323,7 @@ static void test_one_path_per_group_increasing8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -324,7 +337,7 @@ static void test_one_path_per_group_decreasing8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -338,7 +351,7 @@ static void test_one_path_per_group_mixed8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -349,7 +362,7 @@ static void test_one_path_per_group4(void **state) + int group_size[] = {1,1,1,1}; + + mp4.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 4); + } + +@@ -360,21 +373,21 @@ static void test_one_path_per_group1(void **state) + int group_size[] = {1}; + + mp1.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp1), 0); ++ assert_int_equal(group_paths(&mp1, 0), 0); + verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_one_path_per_group0(void **state) + { + mp0.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp0), 0); ++ assert_int_equal(group_paths(&mp0, 0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_one_path_per_group_null(void **state) + { + mp_null.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp_null), 0); ++ assert_int_equal(group_paths(&mp_null, 0), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); + } + +@@ -391,7 +404,7 @@ static void test_one_path_per_group_mixed_all_marginal8(void **state) + set_priority(p8, prio, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 8); + } + +@@ -408,7 +421,7 @@ static void test_one_path_per_group_mixed_half_marginal8(void **state) + set_priority(p8, prio, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = one_path_per_group; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 8); + } + +@@ -419,7 +432,7 @@ static void test_group_by_prio_same8(void **state) + int group_size[] = {8}; + + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + +@@ -433,7 +446,7 @@ static void test_group_by_prio_increasing8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -447,7 +460,7 @@ static void test_group_by_prio_decreasing8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -466,7 +479,26 @@ static void test_group_by_prio_mixed8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); ++ verify_pathgroups(&mp8, p8, groups, group_size, NULL, 6); ++} ++ ++static void test_group_by_prio_mixed_no_marginal8(void **state) ++{ ++ int prio[] = {7,1,3,3,5,2,8,2}; ++ int group0[] = {6}; ++ int group1[] = {0}; ++ int group2[] = {4}; ++ int group3[] = {2,3}; ++ int group4[] = {5,7}; ++ int group5[] = {1}; ++ int *groups[] = {group0, group1, group2, group3, ++ group4, group5}; ++ int group_size[] = {1,1,1,2,2,1}; ++ ++ set_priority(p8, prio, 8); ++ mp8.pgpolicyfn = group_by_prio; ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 6); + } + +@@ -480,7 +512,7 @@ static void test_group_by_prio_2_groups8(void **state) + + set_priority(p8, prio, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 2); + } + +@@ -495,7 +527,7 @@ static void test_group_by_prio_mixed4(void **state) + + set_priority(p4, prio, 4); + mp4.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 3); + } + +@@ -509,7 +541,7 @@ static void test_group_by_prio_2_groups4(void **state) + + set_priority(p4, prio, 4); + mp4.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 2); + } + +@@ -520,21 +552,21 @@ static void test_group_by_prio1(void **state) + int group_size[] = {1}; + + mp1.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp1), 0); ++ assert_int_equal(group_paths(&mp1, 0), 0); + verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_group_by_prio0(void **state) + { + mp0.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp0), 0); ++ assert_int_equal(group_paths(&mp0, 0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_group_by_prio_null(void **state) + { + mp_null.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp_null), 0); ++ assert_int_equal(group_paths(&mp_null, 0), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); + } + +@@ -556,7 +588,7 @@ static void test_group_by_prio_mixed_all_marginal8(void **state) + set_priority(p8, prio, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 6); + } + +@@ -579,7 +611,7 @@ static void test_group_by_prio_mixed_half_marginal8(void **state) + set_priority(p8, prio, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 7); + } + +@@ -602,7 +634,7 @@ static void test_group_by_prio_mixed_one_marginal8(void **state) + set_priority(p8, prio, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = group_by_prio; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 7); + } + +@@ -615,7 +647,7 @@ static void test_group_by_node_name_same8(void **state) + + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + +@@ -631,7 +663,7 @@ static void test_group_by_node_name_increasing8(void **state) + set_priority(p8, prio, 8); + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -648,7 +680,7 @@ static void test_group_by_node_name_3_groups8(void **state) + set_priority(p8, prio, 8); + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 3); + } + +@@ -664,7 +696,7 @@ static void test_group_by_node_name_2_groups8(void **state) + set_priority(p8, prio, 8); + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 2); + } + +@@ -681,7 +713,7 @@ static void test_group_by_node_name_3_groups4(void **state) + set_priority(p4, prio, 4); + set_tgt_node_name(p4, node_name, 4); + mp4.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 3); + } + +@@ -697,7 +729,7 @@ static void test_group_by_node_name_2_groups4(void **state) + set_priority(p4, prio, 4); + set_tgt_node_name(p4, node_name, 4); + mp4.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 2); + } + +@@ -710,21 +742,21 @@ static void test_group_by_node_name1(void **state) + + set_tgt_node_name(p1, node_name, 1); + mp1.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp1), 0); ++ assert_int_equal(group_paths(&mp1,0), 0); + verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_group_by_node_name0(void **state) + { + mp0.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp0), 0); ++ assert_int_equal(group_paths(&mp0, 0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_group_by_node_name_null(void **state) + { + mp_null.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp_null), 0); ++ assert_int_equal(group_paths(&mp_null, 0), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); + } + +@@ -743,7 +775,7 @@ static void test_group_by_node_name_2_groups_all_marginal8(void **state) + set_marginal(p8, marginal, 8); + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); + } + +@@ -764,7 +796,7 @@ static void test_group_by_node_name_2_groups_half_marginal8(void **state) + set_marginal(p8, marginal, 8); + set_tgt_node_name(p8, node_name, 8); + mp8.pgpolicyfn = group_by_node_name; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 4); + } + +@@ -777,7 +809,7 @@ static void test_group_by_serial_same8(void **state) + + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 1); + } + +@@ -793,7 +825,7 @@ static void test_group_by_serial_increasing8(void **state) + set_priority(p8, prio, 8); + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 8); + } + +@@ -810,7 +842,7 @@ static void test_group_by_serial_3_groups8(void **state) + set_priority(p8, prio, 8); + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 3); + } + +@@ -826,7 +858,7 @@ static void test_group_by_serial_2_groups8(void **state) + set_priority(p8, prio, 8); + set_serial(p8, serial, 8); + mp8.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 0), 0); + verify_pathgroups(&mp8, p8, groups, group_size, NULL, 2); + } + +@@ -843,7 +875,7 @@ static void test_group_by_serial_3_groups4(void **state) + set_priority(p4, prio, 4); + set_serial(p4, serial, 4); + mp4.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 3); + } + +@@ -859,7 +891,7 @@ static void test_group_by_serial_2_groups4(void **state) + set_priority(p4, prio, 4); + set_serial(p4, serial, 4); + mp4.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp4), 0); ++ assert_int_equal(group_paths(&mp4, 0), 0); + verify_pathgroups(&mp4, p4, groups, group_size, NULL, 2); + } + +@@ -872,21 +904,21 @@ static void test_group_by_serial1(void **state) + + set_serial(p1, serial, 1); + mp1.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp1), 0); ++ assert_int_equal(group_paths(&mp1, 0), 0); + verify_pathgroups(&mp1, p1, groups, group_size, NULL, 1); + } + + static void test_group_by_serial0(void **state) + { + mp0.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp0), 0); ++ assert_int_equal(group_paths(&mp0, 0), 0); + verify_pathgroups(&mp0, NULL, NULL, NULL, NULL, 0); + } + + static void test_group_by_serial_null(void **state) + { + mp_null.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp_null), 0); ++ assert_int_equal(group_paths(&mp_null, 0), 0); + verify_pathgroups(&mp_null, NULL, NULL, NULL, NULL, 0); + } + +@@ -905,7 +937,7 @@ static void test_group_by_serial_2_groups8_all_marginal8(void **state) + set_serial(p8, serial, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 2); + } + +@@ -926,7 +958,7 @@ static void test_group_by_serial_2_groups8_half_marginal8(void **state) + set_serial(p8, serial, 8); + set_marginal(p8, marginal, 8); + mp8.pgpolicyfn = group_by_serial; +- assert_int_equal(group_paths(&mp8), 0); ++ assert_int_equal(group_paths(&mp8, 1), 0); + verify_pathgroups(&mp8, p8, groups, group_size, group_marginal, 4); + } + +@@ -943,6 +975,7 @@ int test_pgpolicies(void) + setup_test(test_one_group, _null), + setup_test(test_one_group_all_marginal, 8), + setup_test(test_one_group_half_marginal, 8), ++ setup_test(test_one_group_ignore_marginal, 8), + setup_test(test_one_group_one_marginal, 8), + setup_test(test_one_path_per_group_same, 8), + setup_test(test_one_path_per_group_increasing, 8), +@@ -958,6 +991,7 @@ int test_pgpolicies(void) + setup_test(test_group_by_prio_increasing, 8), + setup_test(test_group_by_prio_decreasing, 8), + setup_test(test_group_by_prio_mixed, 8), ++ setup_test(test_group_by_prio_mixed_no_marginal, 8), + setup_test(test_group_by_prio_2_groups, 8), + setup_test(test_group_by_prio_mixed, 4), + setup_test(test_group_by_prio_2_groups, 4), +-- +2.17.2 + diff --git a/0012-libmulitpath-cleanup-uid_fallback-code.patch b/0012-libmulitpath-cleanup-uid_fallback-code.patch deleted file mode 100644 index c47f70a..0000000 --- a/0012-libmulitpath-cleanup-uid_fallback-code.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Wed, 27 Mar 2019 12:21:57 -0500 -Subject: [PATCH] libmulitpath: cleanup uid_fallback code - -Instead of always calling uid_fallback() if the configured method to get -the uid failed, get_uid now checks if the path supports fallbacks and if -all the retriggers have occurred. If so, it calls uid_fallback(), which -just attempts to get the uid using the appropriate fallback method. None -of these changes should make the code function any differently. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/discovery.c | 85 ++++++++++++++++++++++------------------ - 1 file changed, 46 insertions(+), 39 deletions(-) - -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index bece67c..3ec60d6 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1755,50 +1755,50 @@ get_vpd_uid(struct path * pp) - } - - static ssize_t uid_fallback(struct path *pp, int path_state, -- const char **origin, ssize_t old_len) -+ const char **origin) - { -- ssize_t len = old_len; -- int retrigger; -- struct config *conf; -- -- conf = get_multipath_config(); -- retrigger = conf->retrigger_tries; -- put_multipath_config(conf); -- if (pp->retriggers >= retrigger) { -- if (pp->bus == SYSFS_BUS_SCSI && -- !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) { -- len = get_vpd_uid(pp); -- *origin = "sysfs"; -- pp->uid_attribute = NULL; -- if (len < 0 && path_state == PATH_UP) { -- condlog(1, "%s: failed to get sysfs uid: %s", -- pp->dev, strerror(-len)); -- len = get_vpd_sgio(pp->fd, 0x83, pp->wwid, -+ ssize_t len = -1; -+ -+ if (pp->bus == SYSFS_BUS_SCSI && -+ !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) { -+ len = get_vpd_uid(pp); -+ *origin = "sysfs"; -+ pp->uid_attribute = NULL; -+ if (len < 0 && path_state == PATH_UP) { -+ condlog(1, "%s: failed to get sysfs uid: %s", -+ pp->dev, strerror(-len)); -+ len = get_vpd_sgio(pp->fd, 0x83, pp->wwid, -+ WWID_SIZE); -+ *origin = "sgio"; -+ } -+ } else if (pp->bus == SYSFS_BUS_NVME) { -+ char value[256]; -+ len = sysfs_attr_get_value(pp->udev, "wwid", value, -+ sizeof(value)); -+ if (len <= 0) -+ return -1; -+ len = strlcpy(pp->wwid, value, WWID_SIZE); -+ if (len >= WWID_SIZE) { -+ len = fix_broken_nvme_wwid(pp, value, - WWID_SIZE); -- *origin = "sgio"; -- } -- } else if (pp->bus == SYSFS_BUS_NVME) { -- char value[256]; -- len = sysfs_attr_get_value(pp->udev, "wwid", value, -- sizeof(value)); -- if (len <= 0) -- return -1; -- len = strlcpy(pp->wwid, value, WWID_SIZE); -- if (len >= WWID_SIZE) { -- len = fix_broken_nvme_wwid(pp, value, -- WWID_SIZE); -- if (len > 0) -- return len; -- condlog(0, "%s: wwid overflow", pp->dev); -- len = WWID_SIZE; -- } -- *origin = "sysfs"; -- pp->uid_attribute = NULL; -+ if (len > 0) -+ return len; -+ condlog(0, "%s: wwid overflow", pp->dev); -+ len = WWID_SIZE; - } -+ *origin = "sysfs"; -+ pp->uid_attribute = NULL; - } - return len; - } - -+static int has_uid_fallback(struct path *pp) -+{ -+ return ((pp->bus == SYSFS_BUS_SCSI && -+ !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) || -+ pp->bus == SYSFS_BUS_NVME); -+} -+ - int - get_uid (struct path * pp, int path_state, struct udev_device *udev) - { -@@ -1846,8 +1846,15 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) - len = get_vpd_uid(pp); - origin = "sysfs"; - } -- if (len <= 0) -- len = uid_fallback(pp, path_state, &origin, len); -+ if (len <= 0 && has_uid_fallback(pp)) { -+ int retrigger_tries; -+ -+ conf = get_multipath_config(); -+ retrigger_tries = conf->retrigger_tries; -+ put_multipath_config(conf); -+ if (pp->retriggers >= retrigger_tries) -+ len = uid_fallback(pp, path_state, &origin); -+ } - } - if ( len < 0 ) { - condlog(1, "%s: failed to get %s uid: %s", --- -2.17.2 - diff --git a/0012-libmutipath-deprecate-delay_-_checks.patch b/0012-libmutipath-deprecate-delay_-_checks.patch new file mode 100644 index 0000000..55f4ca1 --- /dev/null +++ b/0012-libmutipath-deprecate-delay_-_checks.patch @@ -0,0 +1,381 @@ +From ef0b288867f20b4a1a532d693ac7b64e088b235a Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 30 Jul 2019 11:09:07 -0500 +Subject: [PATCH] libmutipath: deprecate delay_*_checks + +The delay_checks shaky paths detection method works the same way as the +san_path_err method, but not as well, with less configurability, and +with the code spread all over check_path(). The only real difference is +that marks the path as marginal for a certain number of path checks +instead of for a specific time. This patch deprecates the delay_checks +method and maps it to the the san_path_err method. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/configure.c | 18 +------- + libmultipath/propsel.c | 89 ++++++++++++++++++++++++++++---------- + libmultipath/propsel.h | 3 +- + libmultipath/structs.h | 10 ----- + multipath/multipath.conf.5 | 40 +++++++++-------- + multipathd/main.c | 34 ++------------- + 6 files changed, 96 insertions(+), 98 deletions(-) + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 3238d485..9897cc37 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -342,8 +342,6 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + select_dev_loss(conf, mpp); + select_reservation_key(conf, mpp); + select_deferred_remove(conf, mpp); +- select_delay_watch_checks(conf, mpp); +- select_delay_wait_checks(conf, mpp); + select_marginal_path_err_sample_time(conf, mpp); + select_marginal_path_err_rate_threshold(conf, mpp); + select_marginal_path_err_recheck_gap_time(conf, mpp); +@@ -351,6 +349,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + select_san_path_err_threshold(conf, mpp); + select_san_path_err_forget_rate(conf, mpp); + select_san_path_err_recovery_time(conf, mpp); ++ select_delay_checks(conf, mpp); + select_skip_kpartx(conf, mpp); + select_max_sectors_kb(conf, mpp); + select_ghost_delay(conf, mpp); +@@ -360,21 +359,8 @@ int setup_map(struct multipath *mpp, char *params, int params_size, + marginal_pathgroups = conf->marginal_pathgroups; + pthread_cleanup_pop(1); + +- if (marginal_path_check_enabled(mpp)) { +- if (delay_check_enabled(mpp)) { +- condlog(1, "%s: WARNING: both marginal_path and delay_checks error detection selected", +- mpp->alias); +- condlog(0, "%s: unexpected behavior may occur!", +- mpp->alias); +- } ++ if (marginal_path_check_enabled(mpp)) + start_io_err_stat_thread(vecs); +- } +- if (san_path_check_enabled(mpp) && delay_check_enabled(mpp)) { +- condlog(1, "%s: WARNING: both san_path_err and delay_checks error detection selected", +- mpp->alias); +- condlog(0, "%s: unexpected behavior may occur!", +- mpp->alias); +- } + + n_paths = VECTOR_SIZE(mpp->paths); + /* +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 6af2513d..27e8d68a 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -85,6 +85,10 @@ static const char autodetect_origin[] = + "(setting: storage device autodetected)"; + static const char marginal_path_origin[] = + "(setting: implied by marginal_path check)"; ++static const char delay_watch_origin[] = ++ "(setting: implied by delay_watch_checks)"; ++static const char delay_wait_origin[] = ++ "(setting: implied by delay_wait_checks)"; + + #define do_default(dest, value) \ + do { \ +@@ -877,39 +881,80 @@ out: + return 0; + } + +-int select_delay_watch_checks(struct config *conf, struct multipath *mp) ++static inline int san_path_check_options_set(const struct multipath *mp) + { +- const char *origin; ++ return mp->san_path_err_threshold > 0 || ++ mp->san_path_err_forget_rate > 0 || ++ mp->san_path_err_recovery_time > 0; ++} ++ ++static int ++use_delay_watch_checks(struct config *conf, struct multipath *mp) ++{ ++ int value = NU_UNDEF; ++ const char *origin = default_origin; + char buff[12]; + +- mp_set_mpe(delay_watch_checks); +- mp_set_ovr(delay_watch_checks); +- mp_set_hwe(delay_watch_checks); +- mp_set_conf(delay_watch_checks); +- mp_set_default(delay_watch_checks, DEFAULT_DELAY_CHECKS); ++ do_set(delay_watch_checks, mp->mpe, value, multipaths_origin); ++ do_set(delay_watch_checks, conf->overrides, value, overrides_origin); ++ do_set_from_hwe(delay_watch_checks, mp, value, hwe_origin); ++ do_set(delay_watch_checks, conf, value, conf_origin); + out: +- if (print_off_int_undef(buff, 12, mp->delay_watch_checks) != 0) +- condlog(3, "%s: delay_watch_checks = %s %s", +- mp->alias, buff, origin); +- return 0; ++ if (print_off_int_undef(buff, 12, value) != 0) ++ condlog(3, "%s: delay_watch_checks = %s %s", mp->alias, buff, ++ origin); ++ return value; + } + +-int select_delay_wait_checks(struct config *conf, struct multipath *mp) ++static int ++use_delay_wait_checks(struct config *conf, struct multipath *mp) + { +- const char *origin; ++ int value = NU_UNDEF; ++ const char *origin = default_origin; + char buff[12]; + +- mp_set_mpe(delay_wait_checks); +- mp_set_ovr(delay_wait_checks); +- mp_set_hwe(delay_wait_checks); +- mp_set_conf(delay_wait_checks); +- mp_set_default(delay_wait_checks, DEFAULT_DELAY_CHECKS); ++ do_set(delay_wait_checks, mp->mpe, value, multipaths_origin); ++ do_set(delay_wait_checks, conf->overrides, value, overrides_origin); ++ do_set_from_hwe(delay_wait_checks, mp, value, hwe_origin); ++ do_set(delay_wait_checks, conf, value, conf_origin); + out: +- if (print_off_int_undef(buff, 12, mp->delay_wait_checks) != 0) +- condlog(3, "%s: delay_wait_checks = %s %s", +- mp->alias, buff, origin); +- return 0; ++ if (print_off_int_undef(buff, 12, value) != 0) ++ condlog(3, "%s: delay_wait_checks = %s %s", mp->alias, buff, ++ origin); ++ return value; ++} ++ ++int select_delay_checks(struct config *conf, struct multipath *mp) ++{ ++ int watch_checks, wait_checks; ++ char buff[12]; + ++ watch_checks = use_delay_watch_checks(conf, mp); ++ wait_checks = use_delay_wait_checks(conf, mp); ++ if (watch_checks <= 0 && wait_checks <= 0) ++ return 0; ++ if (san_path_check_options_set(mp)) { ++ condlog(3, "%s: both marginal_path and delay_checks error detection options selected", mp->alias); ++ condlog(3, "%s: ignoring delay_checks options", mp->alias); ++ return 0; ++ } ++ mp->san_path_err_threshold = 1; ++ condlog(3, "%s: san_path_err_threshold = 1 %s", mp->alias, ++ (watch_checks > 0)? delay_watch_origin : delay_wait_origin); ++ if (watch_checks > 0) { ++ mp->san_path_err_forget_rate = watch_checks; ++ print_off_int_undef(buff, 12, mp->san_path_err_forget_rate); ++ condlog(3, "%s: san_path_err_forget_rate = %s %s", mp->alias, ++ buff, delay_watch_origin); ++ } ++ if (wait_checks > 0) { ++ mp->san_path_err_recovery_time = wait_checks * ++ conf->max_checkint; ++ print_off_int_undef(buff, 12, mp->san_path_err_recovery_time); ++ condlog(3, "%s: san_path_err_recovery_time = %s %s", mp->alias, ++ buff, delay_wait_origin); ++ } ++ return 0; + } + + static int san_path_deprecated_warned; +diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h +index b352c16a..ddfd6262 100644 +--- a/libmultipath/propsel.h ++++ b/libmultipath/propsel.h +@@ -22,8 +22,7 @@ int select_retain_hwhandler (struct config *conf, struct multipath * mp); + int select_detect_prio(struct config *conf, struct path * pp); + int select_detect_checker(struct config *conf, struct path * pp); + int select_deferred_remove(struct config *conf, struct multipath *mp); +-int select_delay_watch_checks (struct config *conf, struct multipath * mp); +-int select_delay_wait_checks (struct config *conf, struct multipath * mp); ++int select_delay_checks(struct config *conf, struct multipath * mp); + int select_skip_kpartx (struct config *conf, struct multipath * mp); + int select_max_sectors_kb (struct config *conf, struct multipath * mp); + int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp); +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index a8b9d325..a3adf906 100644 +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -268,8 +268,6 @@ struct path { + int pgindex; + int detect_prio; + int detect_checker; +- int watch_checks; +- int wait_checks; + int tpgs; + char * uid_attribute; + char * getuid; +@@ -321,8 +319,6 @@ struct multipath { + int fast_io_fail; + int retain_hwhandler; + int deferred_remove; +- int delay_watch_checks; +- int delay_wait_checks; + int san_path_err_threshold; + int san_path_err_forget_rate; + int san_path_err_recovery_time; +@@ -393,12 +389,6 @@ static inline int san_path_check_enabled(const struct multipath *mpp) + mpp->san_path_err_recovery_time > 0; + } + +-static inline int delay_check_enabled(const struct multipath *mpp) +-{ +- return mpp->delay_watch_checks != NU_NO || +- mpp->delay_wait_checks != NU_NO; +-} +- + struct pathgroup { + long id; + int status; +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index f7d21b4c..08297a41 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -1013,10 +1013,12 @@ The default is: \fBno\fR + . + .TP + .B delay_watch_checks +-If set to a value greater than 0, multipathd will watch paths that have +-recently become valid for this many checks. If they fail again while they are +-being watched, when they next become valid, they will not be used until they +-have stayed up for \fIdelay_wait_checks\fR checks. See "Shaky paths detection" below. ++This option is \fBdeprecated\fR, and mapped to \fIsan_path_err_forget_rate\fR. ++If this is set to a value greater than 0 and no \fIsan_path_err\fR options ++are set, \fIsan_path_err_forget_rate\fR will be set to the value of ++\fIdelay_watch_checks\fR and \fIsan_path_err_threshold\fR will be set to 1. ++See the \fIsan_path_err_forget_rate\fR and \fIsan_path_err_threshold\fR ++options, and "Shaky paths detection" below for more information. + .RS + .TP + The default is: \fBno\fR +@@ -1025,10 +1027,14 @@ The default is: \fBno\fR + . + .TP + .B delay_wait_checks +-If set to a value greater than 0, when a device that has recently come back +-online fails again within \fIdelay_watch_checks\fR checks, the next time it +-comes back online, it will marked and delayed, and not used until it has passed +-\fIdelay_wait_checks\fR checks. See "Shaky paths detection" below. ++This option is \fBdeprecated\fR, and mapped to \fIsan_path_err_recovery_time\fR. ++If this is set to a value greater than 0 and no \fIsan_path_err\fR options ++are set, \fIsan_path_err_recovery_time\fR will be set to the value of ++\fIdelay_wait_checks\fR times \fImax_polling_interval\fR. This will give ++approximately the same wait time as delay_wait_checks previously did. ++Also, \fIsan_path_err_threshold\fR will be set to 1. See the ++\fIsan_path_err_recovery_time\fR and \fIsan_path_err_threshold\fR ++options, and "Shaky paths detection" below for more information. + .RS + .TP + The default is: \fBno\fR +@@ -1689,13 +1695,10 @@ if the healthy state appears to be stable. The logic of determining + differs between the three methods. + .TP 8 + .B \(dqdelay_checks\(dq failure tracking +-If a path fails again within a +-\fIdelay_watch_checks\fR interval after a failure, don't +-reinstate it until it passes a \fIdelay_wait_checks\fR interval +-in always good status. +-The intervals are measured in \(dqticks\(dq, i.e. the +-time between path checks by multipathd, which is variable and controlled by the +-\fIpolling_interval\fR and \fImax_polling_interval\fR parameters. ++This method is \fBdeprecated\fR and mapped to the \(dqsan_path_err\(dq method. ++See the \fIdelay_watch_checks\fR and \fIdelay_wait_checks\fR options above ++for more information. ++ + .TP + .B \(dqmarginal_path\(dq failure tracking + If a second failure event (good->bad transition) occurs within +@@ -1712,12 +1715,13 @@ in seconds. + .B \(dqsan_path_err\(dq failure tracking + multipathd counts path failures for each path. Once the number of failures + exceeds the value given by \fIsan_path_err_threshold\fR, the path is not +-reinstated for \fIsan_path_err_recovery_time\fR ticks. While counting ++reinstated for \fIsan_path_err_recovery_time\fR seconds. While counting + failures, multipathd \(dqforgets\(dq one past failure every + \(dqsan_path_err_forget_rate\(dq ticks; thus if errors don't occur more + often then once in the forget rate interval, the failure count doesn't +-increase and the threshold is never reached. As for the \fIdelay_xy\fR method, +-intervals are measured in \(dqticks\(dq. ++increase and the threshold is never reached. Ticks are the time between ++path checks by multipathd, which is variable and controlled by the ++\fIpolling_interval\fR and \fImax_polling_interval\fR parameters. + . + .RS 8 + .LP +diff --git a/multipathd/main.c b/multipathd/main.c +index 7db15736..dca2214c 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2122,16 +2122,6 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + return 1; + } + +- if ((newstate == PATH_UP || newstate == PATH_GHOST) && +- pp->wait_checks > 0) { +- if (pp->mpp->nr_active > 0) { +- pp->state = PATH_DELAYED; +- pp->wait_checks--; +- return 1; +- } else +- pp->wait_checks = 0; +- } +- + /* + * don't reinstate failed path, if its in stand-by + * and if target supports only implicit tpgs mode. +@@ -2162,19 +2152,10 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + * proactively fail path in the DM + */ + if (oldstate == PATH_UP || +- oldstate == PATH_GHOST) { ++ oldstate == PATH_GHOST) + fail_path(pp, 1); +- if (pp->mpp->delay_wait_checks > 0 && +- pp->watch_checks > 0) { +- pp->wait_checks = pp->mpp->delay_wait_checks; +- pp->watch_checks = 0; +- } +- } else { ++ else + fail_path(pp, 0); +- if (pp->wait_checks > 0) +- pp->wait_checks = +- pp->mpp->delay_wait_checks; +- } + + /* + * cancel scheduled failback +@@ -2200,15 +2181,10 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + * reinstate this path + */ + if (oldstate != PATH_UP && +- oldstate != PATH_GHOST) { +- if (pp->mpp->delay_watch_checks > 0) +- pp->watch_checks = pp->mpp->delay_watch_checks; ++ oldstate != PATH_GHOST) + add_active = 1; +- } else { +- if (pp->watch_checks > 0) +- pp->watch_checks--; ++ else + add_active = 0; +- } + if (!disable_reinstate && reinstate_path(pp, add_active)) { + condlog(3, "%s: reload map", pp->dev); + ev_add_path(pp, vecs, 1); +@@ -2253,8 +2229,6 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + condlog(4, "%s: delay next check %is", + pp->dev_t, pp->checkint); + } +- if (pp->watch_checks > 0) +- pp->watch_checks--; + pp->tick = pp->checkint; + } + } +-- +2.17.2 + diff --git a/0013-multipathd-handle-changed-wwids-by-removal-and-addit.patch b/0013-multipathd-handle-changed-wwids-by-removal-and-addit.patch deleted file mode 100644 index 45c0366..0000000 --- a/0013-multipathd-handle-changed-wwids-by-removal-and-addit.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Wed, 27 Mar 2019 23:27:47 -0500 -Subject: [PATCH] multipathd: handle changed wwids by removal and addition - -If a path's WWID changes, it's not necessarily failed. But it certainly -has to be removed from an existing map, otherwise data corruption is -imminent. Instead of keeping the path in the map, failing it, and -remembering the "changed WWID" state, this patch simply removes and -re-adds the path. - -This is patch is heavily based on the previous patch of the same name -by Martin Wilck. - -Signed-off-by: Benjamin Marzinski ---- - multipathd/main.c | 28 ++++++---------------------- - 1 file changed, 6 insertions(+), 22 deletions(-) - -diff --git a/multipathd/main.c b/multipathd/main.c -index 7a317d9..b3571d9 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -1191,7 +1191,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - int ro, retval = 0, rc; - struct path * pp; - struct config *conf; -- int disable_changed_wwids; - int needs_reinit = 0; - - switch ((rc = change_foreign(uev->udev))) { -@@ -1209,12 +1208,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - break; - } - -- conf = get_multipath_config(); -- disable_changed_wwids = conf->disable_changed_wwids; -- put_multipath_config(conf); -- -- ro = uevent_get_disk_ro(uev); -- - pthread_cleanup_push(cleanup_lock, &vecs->lock); - lock(&vecs->lock); - pthread_testcancel(); -@@ -1239,22 +1232,12 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - if (rc != 0) - strcpy(pp->wwid, wwid); - else if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { -- condlog(0, "%s: path wwid changed from '%s' to '%s'. %s", -- uev->kernel, wwid, pp->wwid, -- (disable_changed_wwids ? "disallowing" : -- "continuing")); -- strcpy(pp->wwid, wwid); -- if (disable_changed_wwids) { -- if (!pp->wwid_changed) { -- pp->wwid_changed = 1; -- pp->tick = 1; -- if (pp->mpp) -- dm_fail_path(pp->mpp->alias, pp->dev_t); -- } -- goto out; -- } -+ condlog(0, "%s: path wwid changed from '%s' to '%s'", -+ uev->kernel, wwid, pp->wwid); -+ ev_remove_path(pp, vecs, 1); -+ needs_reinit = 1; -+ goto out; - } else { -- pp->wwid_changed = 0; - udev_device_unref(pp->udev); - pp->udev = udev_device_ref(uev->udev); - conf = get_multipath_config(); -@@ -1265,6 +1248,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - pthread_cleanup_pop(1); - } - -+ ro = uevent_get_disk_ro(uev); - if (mpp && ro >= 0) { - condlog(2, "%s: update path write_protect to '%d' (uevent)", uev->kernel, ro); - --- -2.17.2 - diff --git a/0013-multipathd-use-marginal_pathgroups.patch b/0013-multipathd-use-marginal_pathgroups.patch new file mode 100644 index 0000000..86cbc49 --- /dev/null +++ b/0013-multipathd-use-marginal_pathgroups.patch @@ -0,0 +1,111 @@ +From d43ffc1112c0385737f88bab1c884e4ff4c316f5 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 31 Jul 2019 18:11:41 -0500 +Subject: [PATCH] multipathd: use marginal_pathgroups + +This commit makes the marginal_pathgroups option work with the +existing methods for determining marginal paths. It also merges the +code for the marginal_path and sand_path_err methods. This has the +side effect of making the marginal_path code set a marginal path's state +to "delayed" instead of "shaky" like it previously did. + +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 53 +++++++++++++++++++++++++++++++++-------------- + 1 file changed, 38 insertions(+), 15 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index dca2214c..04b2b56a 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1960,6 +1960,18 @@ reinstate_path: + return 0; + } + ++static int ++should_skip_path(struct path *pp){ ++ if (marginal_path_check_enabled(pp->mpp)) { ++ if (pp->io_err_disable_reinstate && need_io_err_check(pp)) ++ return 1; ++ } else if (san_path_check_enabled(pp->mpp)) { ++ if (check_path_reinstate_state(pp)) ++ return 1; ++ } ++ return 0; ++} ++ + /* + * Returns '1' if the path has been checked, '-1' if it was blacklisted + * and '0' otherwise +@@ -1975,6 +1987,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + int oldchkrstate = pp->chkrstate; + int retrigger_tries, checkint, max_checkint, verbosity; + struct config *conf; ++ int marginal_pathgroups, marginal_changed = 0; + int ret; + + if ((pp->initialized == INIT_OK || +@@ -1991,6 +2004,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + checkint = conf->checkint; + max_checkint = conf->max_checkint; + verbosity = conf->verbosity; ++ marginal_pathgroups = conf->marginal_pathgroups; + put_multipath_config(conf); + + if (pp->checkint == CHECKINT_UNDEF) { +@@ -2106,20 +2120,27 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + set_no_path_retry(pp->mpp); + + if ((newstate == PATH_UP || newstate == PATH_GHOST) && +- check_path_reinstate_state(pp)) { +- pp->state = PATH_DELAYED; +- return 1; +- } +- +- if ((newstate == PATH_UP || newstate == PATH_GHOST) && +- pp->io_err_disable_reinstate && need_io_err_check(pp)) { +- pp->state = PATH_SHAKY; +- /* +- * to reschedule as soon as possible,so that this path can +- * be recoverd in time +- */ +- pp->tick = 1; +- return 1; ++ (san_path_check_enabled(pp->mpp) || ++ marginal_path_check_enabled(pp->mpp))) { ++ int was_marginal = pp->marginal; ++ if (should_skip_path(pp)) { ++ if (!marginal_pathgroups) { ++ if (marginal_path_check_enabled(pp->mpp)) ++ /* to reschedule as soon as possible, ++ * so that this path can be recovered ++ * in time */ ++ pp->tick = 1; ++ pp->state = PATH_DELAYED; ++ return 1; ++ } ++ if (!was_marginal) { ++ pp->marginal = 1; ++ marginal_changed = 1; ++ } ++ } else if (marginal_pathgroups && was_marginal) { ++ pp->marginal = 0; ++ marginal_changed = 1; ++ } + } + + /* +@@ -2258,7 +2279,9 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) + */ + condlog(4, "path prio refresh"); + +- if (update_prio(pp, new_path_up) && ++ if (marginal_changed) ++ update_path_groups(pp->mpp, vecs, 1); ++ else if (update_prio(pp, new_path_up) && + (pp->mpp->pgpolicyfn == (pgpolicyfn *)group_by_prio) && + pp->mpp->pgfailback == -FAILBACK_IMMEDIATE) + update_path_groups(pp->mpp, vecs, !new_path_up); +-- +2.17.2 + diff --git a/0014-multipath-update-man-pages.patch b/0014-multipath-update-man-pages.patch new file mode 100644 index 0000000..6c7261b --- /dev/null +++ b/0014-multipath-update-man-pages.patch @@ -0,0 +1,99 @@ +From 0992a545413cf2bcbde18c90f04b9e5b1077fd62 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 1 Aug 2019 16:29:41 -0500 +Subject: [PATCH] multipath: update man pages + +Add documentation for the marginal_pathgroups option and the +(un)setmarginal commands. + +Signed-off-by: Benjamin Marzinski +--- + multipath/multipath.conf.5 | 34 ++++++++++++++++++++++++++++++---- + multipathd/multipathd.8 | 19 +++++++++++++++++++ + 2 files changed, 49 insertions(+), 4 deletions(-) + +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index 08297a41..ac8eadd0 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -1042,6 +1042,28 @@ The default is: \fBno\fR + . + . + .TP ++.B marginal_pathgroups ++If set to \fIno\fR, the \fIdelay_*_checks\fR, \fImarginal_path_*\fR, and ++\fIsan_path_err_*\fR options will keep marginal, or \(dqshaky\(dq, paths from ++being reinstated until they have been monitored for some time. This can cause ++situations where all non-marginal paths are down, and no paths are usable ++until multipathd detects this and reinstates a marginal path. If the multipath ++device is not configured to queue IO in this case, it can cause IO errors to ++occur, even though there are marginal paths available. However, if this ++option is set to \fIyes\fR, when one of the marginal path detecting methods ++determines that a path is marginal, it will be reinstated and placed in a ++seperate pathgroup that will only be used after all the non-marginal pathgroups ++have been tried first. This prevents the possibility of IO errors occuring ++while marginal paths are still usable. After the path has been monitored ++for the configured time, and is declared healthy, it will be returned to its ++normal pathgroup. See "Shaky paths detection" below for more information. ++.RS ++.TP ++The default is: \fBno\fR ++.RE ++. ++. ++.TP + .B find_multipaths + This option controls whether multipath and multipathd try to create multipath + maps over non-blacklisted devices they encounter. This matters a) when a device is +@@ -1689,10 +1711,14 @@ events. \fImultipathd\fR supports three different methods for detecting this + situation and dealing with it. All methods share the same basic mode of + operation: If a path is found to be \(dqshaky\(dq or \(dqflipping\(dq, + and appears to be in healthy status, it is not reinstated (put back to use) +-immediately. Instead, it is watched for some time, and only reinstated +-if the healthy state appears to be stable. The logic of determining +-\(dqshaky\(dq condition, as well as the logic when to reinstate, +-differs between the three methods. ++immediately. Instead, it is placed in the \(dqdelayed\(dq state and watched ++for some time, and only reinstated if the healthy state appears to be stable. ++If the \fImarginal_pathgroups\fR option is set, the path will reinstated ++immediately, but placed in a special pathgroup for marginal paths. Marginal ++pathgroups will not be used until all other pathgroups have been tried. At the ++time when the path would normally be reinstated, it will be returned to its ++normal pathgroup. The logic of determining \(dqshaky\(dq condition, as well as ++the logic when to reinstate, differs between the three methods. + .TP 8 + .B \(dqdelay_checks\(dq failure tracking + This method is \fBdeprecated\fR and mapped to the \(dqsan_path_err\(dq method. +diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8 +index edac7a92..048a838d 100644 +--- a/multipathd/multipathd.8 ++++ b/multipathd/multipathd.8 +@@ -277,6 +277,25 @@ Remove the persistent reservation key associated with $map from the + \fIreservation_key\fR is set to \fBfile\fR in \fI/etc/multipath.conf\fR. + . + .TP ++.B path $path setmarginal ++move $path to a marginal pathgroup. The path will remain in the marginal ++path group until \fIunsetmarginal\fR is called. This command will only ++work if \fImarginal_pathgroups\fR is enabled and there is no Shaky paths ++detection method configured (see the multipath.conf man page for details). ++. ++.TP ++.B path $path unsetmarginal ++return marginal path $path to its normal pathgroup. This command will only ++work if \fImarginal_pathgroups\fR is enabled and there is no Shaky paths ++detection method configured (see the multipath.conf man page for details). ++. ++.TP ++.B map $map unsetmarginal ++return all marginal paths in $map to their normal pathgroups. This command ++will only work if \fImarginal_pathgroups\fR is enabled and there is no Shaky ++paths detection method configured (see the multipath.conf man page for details). ++. ++.TP + .B quit|exit + End interactive session. + . +-- +2.17.2 + diff --git a/0014-multipathd-remove-wwid_changed-path-attribute.patch b/0014-multipathd-remove-wwid_changed-path-attribute.patch deleted file mode 100644 index 59279e5..0000000 --- a/0014-multipathd-remove-wwid_changed-path-attribute.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -Date: Mon, 18 Mar 2019 13:12:34 +0100 -Subject: [PATCH] multipathd: remove "wwid_changed" path attribute - -This is now not needed any more. - -Signed-off-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - libmultipath/structs.h | 1 - - multipathd/main.c | 6 ------ - 2 files changed, 7 deletions(-) - -diff --git a/libmultipath/structs.h b/libmultipath/structs.h -index b794b0d..7879d76 100644 ---- a/libmultipath/structs.h -+++ b/libmultipath/structs.h -@@ -280,7 +280,6 @@ struct path { - int fd; - int initialized; - int retriggers; -- int wwid_changed; - unsigned int path_failures; - time_t dis_reinstate_time; - int disable_reinstate; -diff --git a/multipathd/main.c b/multipathd/main.c -index b3571d9..e4f95a0 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -2001,12 +2001,6 @@ check_path (struct vectors * vecs, struct path * pp, int ticks) - if (newstate == PATH_REMOVED) - newstate = PATH_DOWN; - -- if (pp->wwid_changed) { -- condlog(2, "%s: path wwid has changed. Refusing to use", -- pp->dev); -- newstate = PATH_DOWN; -- } -- - if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { - condlog(2, "%s: unusable path (%s) - checker failed", - pp->dev, checker_state_name(newstate)); --- -2.17.2 - diff --git a/0015-multipath.conf-add-enable_foreign-parameter.patch b/0015-multipath.conf-add-enable_foreign-parameter.patch new file mode 100644 index 0000000..97ef17c --- /dev/null +++ b/0015-multipath.conf-add-enable_foreign-parameter.patch @@ -0,0 +1,230 @@ +From 959cf306b6ad0bbfc73e7745161ef4edfa821a47 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 15 Aug 2019 14:46:54 +0000 +Subject: [PATCH] multipath.conf: add "enable_foreign" parameter + +This new configuration parameter can be used to selectively +enable foreign libraries. The value is a regular expression, +against which foreign library names such as "nvme" are matched. +By setting this to a value that matches no foreign library +(e.g. "^$" or "NONE"), foreign code is completely disabled. +By default, all available foreign libraries are loaded. + +Signed-off-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.h | 1 + + libmultipath/defaults.h | 2 ++ + libmultipath/dict.c | 6 +++++ + libmultipath/foreign.c | 53 +++++++++++++++++++++++++++++++++++++---- + libmultipath/foreign.h | 3 ++- + multipath/main.c | 2 +- + multipathd/main.c | 2 +- + 7 files changed, 62 insertions(+), 7 deletions(-) + +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 0b978970..ffec3103 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -225,6 +225,7 @@ struct config { + vector elist_device; + vector elist_property; + vector elist_protocol; ++ char *enable_foreign; + }; + + extern struct udev * udev; +diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h +index decc9335..4dfe007c 100644 +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -48,6 +48,8 @@ + #define DEFAULT_FIND_MULTIPATHS_TIMEOUT -10 + #define DEFAULT_UNKNOWN_FIND_MULTIPATHS_TIMEOUT 1 + #define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF ++/* Enable all foreign libraries by default */ ++#define DEFAULT_ENABLE_FOREIGN "" + + #define CHECKINT_UNDEF (~0U) + #define DEFAULT_CHECKINT 5 +diff --git a/libmultipath/dict.c b/libmultipath/dict.c +index b5feb884..1b3d0373 100644 +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -610,6 +610,10 @@ declare_def_handler(find_multipaths_timeout, set_int) + declare_def_snprint_defint(find_multipaths_timeout, print_int, + DEFAULT_FIND_MULTIPATHS_TIMEOUT) + ++declare_def_handler(enable_foreign, set_str) ++declare_def_snprint_defstr(enable_foreign, print_str, ++ DEFAULT_ENABLE_FOREIGN) ++ + static int + def_config_dir_handler(struct config *conf, vector strvec) + { +@@ -1713,6 +1717,8 @@ init_keywords(vector keywords) + &def_find_multipaths_timeout_handler, + &snprint_def_find_multipaths_timeout); + install_keyword("marginal_pathgroups", &def_marginal_pathgroups_handler, &snprint_def_marginal_pathgroups); ++ install_keyword("enable_foreign", &def_enable_foreign_handler, ++ &snprint_def_enable_foreign); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL); +diff --git a/libmultipath/foreign.c b/libmultipath/foreign.c +index 48e8d247..4b34e141 100644 +--- a/libmultipath/foreign.c ++++ b/libmultipath/foreign.c +@@ -16,6 +16,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -25,6 +26,7 @@ + #include + #include + #include ++#include + #include "vector.h" + #include "debug.h" + #include "util.h" +@@ -111,17 +113,45 @@ static int select_foreign_libs(const struct dirent *di) + return fnmatch(foreign_pattern, di->d_name, FNM_FILE_NAME) == 0; + } + +-static int _init_foreign(const char *multipath_dir) ++static void free_pre(void *arg) ++{ ++ regex_t **pre = arg; ++ ++ if (pre != NULL && *pre != NULL) { ++ regfree(*pre); ++ free(*pre); ++ *pre = NULL; ++ } ++} ++ ++static int _init_foreign(const char *multipath_dir, const char *enable) + { + char pathbuf[PATH_MAX]; + struct dirent **di; + struct scandir_result sr; + int r, i; ++ regex_t *enable_re = NULL; + + foreigns = vector_alloc(); + if (foreigns == NULL) + return -ENOMEM; + ++ pthread_cleanup_push(free_pre, &enable_re); ++ enable_re = calloc(1, sizeof(*enable_re)); ++ if (enable_re) { ++ const char *str = enable ? enable : DEFAULT_ENABLE_FOREIGN; ++ ++ r = regcomp(enable_re, str, REG_EXTENDED|REG_NOSUB); ++ if (r != 0) { ++ char errbuf[64]; ++ ++ (void)regerror(r, enable_re, errbuf, sizeof(errbuf)); ++ condlog (2, "%s: error compiling enable_foreign = \"%s\": \"%s\"", ++ __func__, str, errbuf); ++ free_pre(&enable_re); ++ } ++ } ++ + r = scandir(multipath_dir, &di, select_foreign_libs, alphasort); + + if (r == 0) { +@@ -163,6 +193,20 @@ static int _init_foreign(const char *multipath_dir) + memset(fgn, 0, sizeof(*fgn)); + strlcpy((char*)fgn + offsetof(struct foreign, name), c, namesz); + ++ if (enable_re != NULL) { ++ int ret = regexec(enable_re, fgn->name, 0, NULL, 0); ++ ++ if (ret == REG_NOMATCH) { ++ condlog(3, "%s: foreign library \"%s\" is not enabled", ++ __func__, fgn->name); ++ free(fgn); ++ continue; ++ } else if (ret != 0) ++ /* assume it matches */ ++ condlog(2, "%s: error %d in regexec() for %s", ++ __func__, ret, fgn->name); ++ } ++ + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", multipath_dir, fn); + fgn->handle = dlopen(pathbuf, RTLD_NOW|RTLD_LOCAL); + msg = dlerror(); +@@ -205,11 +249,12 @@ static int _init_foreign(const char *multipath_dir) + dl_err: + free_foreign(fgn); + } +- pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); /* free_scandir_result */ ++ pthread_cleanup_pop(1); /* free_pre */ + return 0; + } + +-int init_foreign(const char *multipath_dir) ++int init_foreign(const char *multipath_dir, const char *enable) + { + int ret; + +@@ -222,7 +267,7 @@ int init_foreign(const char *multipath_dir) + } + + pthread_cleanup_push(unlock_foreigns, NULL); +- ret = _init_foreign(multipath_dir); ++ ret = _init_foreign(multipath_dir, enable); + pthread_cleanup_pop(1); + + return ret; +diff --git a/libmultipath/foreign.h b/libmultipath/foreign.h +index 697f12f8..acd33601 100644 +--- a/libmultipath/foreign.h ++++ b/libmultipath/foreign.h +@@ -195,9 +195,10 @@ struct foreign { + * init_foreign(dir) + * load and initialize foreign multipath libraries in dir (libforeign-*.so). + * @param dir: directory to search ++ * @param enable: regex to match foreign library name ("*" above) against + * @returns: 0 on success, negative value on failure. + */ +-int init_foreign(const char *multipath_dir); ++int init_foreign(const char *multipath_dir, const char *enable); + + /** + * cleanup_foreign(dir) +diff --git a/multipath/main.c b/multipath/main.c +index 96a11468..4f4d8e89 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -1050,7 +1050,7 @@ main (int argc, char *argv[]) + goto out; + } + /* Failing here is non-fatal */ +- init_foreign(conf->multipath_dir); ++ init_foreign(conf->multipath_dir, conf->enable_foreign); + if (cmd == CMD_USABLE_PATHS) { + r = check_usable_paths(conf, dev, dev_type) ? + RTVL_FAIL : RTVL_OK; +diff --git a/multipathd/main.c b/multipathd/main.c +index 04b2b56a..8826620d 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -2848,7 +2848,7 @@ child (void * param) + } + /* Failing this is non-fatal */ + +- init_foreign(conf->multipath_dir); ++ init_foreign(conf->multipath_dir, conf->enable_foreign); + + if (poll_dmevents) + poll_dmevents = dmevent_poll_supported(); +-- +2.17.2 + diff --git a/0015-multipathd-ignore-disable_changed_wwids.patch b/0015-multipathd-ignore-disable_changed_wwids.patch deleted file mode 100644 index 8565203..0000000 --- a/0015-multipathd-ignore-disable_changed_wwids.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Martin Wilck -Date: Mon, 18 Mar 2019 13:12:35 +0100 -Subject: [PATCH] multipathd: ignore "disable_changed_wwids" - -This option has no effect any more. - -Signed-off-by: Martin Wilck -Signed-off-by: Benjamin Marzinski ---- - libmultipath/config.c | 1 - - libmultipath/config.h | 1 - - libmultipath/dict.c | 18 +++++++++++++++--- - multipath/multipath.conf.5 | 8 ++------ - 4 files changed, 17 insertions(+), 11 deletions(-) - -diff --git a/libmultipath/config.c b/libmultipath/config.c -index 24d71ae..141f092 100644 ---- a/libmultipath/config.c -+++ b/libmultipath/config.c -@@ -715,7 +715,6 @@ load_config (char * file) - conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES; - conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY; - conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT; -- conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS; - conf->remove_retries = 0; - conf->ghost_delay = DEFAULT_GHOST_DELAY; - conf->all_tg_pt = DEFAULT_ALL_TG_PT; -diff --git a/libmultipath/config.h b/libmultipath/config.h -index b938c26..f5bf5b1 100644 ---- a/libmultipath/config.h -+++ b/libmultipath/config.h -@@ -182,7 +182,6 @@ struct config { - int delayed_reconfig; - int uev_wait_timeout; - int skip_kpartx; -- int disable_changed_wwids; - int remove_retries; - int max_sectors_kb; - int ghost_delay; -diff --git a/libmultipath/dict.c b/libmultipath/dict.c -index eaad4f1..96815f8 100644 ---- a/libmultipath/dict.c -+++ b/libmultipath/dict.c -@@ -156,6 +156,12 @@ out: - return len; - } - -+static int -+print_ignored (char *buff, int len) -+{ -+ return snprintf(buff, len, "ignored"); -+} -+ - static int - print_yes_no (char *buff, int len, long v) - { -@@ -548,9 +554,15 @@ declare_hw_handler(skip_kpartx, set_yes_no_undef) - declare_hw_snprint(skip_kpartx, print_yes_no_undef) - declare_mp_handler(skip_kpartx, set_yes_no_undef) - declare_mp_snprint(skip_kpartx, print_yes_no_undef) -- --declare_def_handler(disable_changed_wwids, set_yes_no) --declare_def_snprint(disable_changed_wwids, print_yes_no) -+static int def_disable_changed_wwids_handler(struct config *conf, vector strvec) -+{ -+ return 0; -+} -+static int snprint_def_disable_changed_wwids(struct config *conf, char *buff, -+ int len, const void *data) -+{ -+ return print_ignored(buff, len); -+} - - declare_def_handler(remove_retries, set_int) - declare_def_snprint(remove_retries, print_int) -diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 -index 864d7eb..646c156 100644 ---- a/multipath/multipath.conf.5 -+++ b/multipath/multipath.conf.5 -@@ -1148,12 +1148,8 @@ The default is: \fBno\fR - . - .TP - .B disable_changed_wwids --If set to \fIyes\fR, multipathd will check the path wwid on change events, and --if it has changed from the wwid of the multipath device, multipathd will --disable access to the path until the wwid changes back. --.RS --.TP --The default is: \fBno\fR -+This option is deprecated and ignored. If the WWID of a path suddenly changes, -+multipathd handles it as if it was removed and then added again. - .RE - . - . --- -2.17.2 - diff --git a/0016-multipath.conf.5-document-foreign-library-support.patch b/0016-multipath.conf.5-document-foreign-library-support.patch new file mode 100644 index 0000000..4988e4d --- /dev/null +++ b/0016-multipath.conf.5-document-foreign-library-support.patch @@ -0,0 +1,75 @@ +From 1439bf7acc88b6a398e1a390045dcac9e3163e53 Mon Sep 17 00:00:00 2001 +From: Martin Wilck +Date: Thu, 15 Aug 2019 14:46:56 +0000 +Subject: [PATCH] multipath.conf.5: document foreign library support + +Add documentation for foreign library support, and for the +"enable_foreign" parameter. + +Signed-off-by: Martin Wilck +Signed-off-by: Benjamin Marzinski +--- + multipath/multipath.conf.5 | 40 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +index ac8eadd0..101e1a88 100644 +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -1222,6 +1222,21 @@ makes multipath immediately mark a device with only ghost paths as ready. + The default is: \fBno\fR + .RE + . ++. ++.TP ++.B enable_foreign ++Enables or disables foreign libraries (see section ++.I FOREIGN MULTIPATH SUPPORT ++below). The value is a regular expression; foreign libraries are loaded ++if their name (e.g. \(dqnvme\(dq) matches the expression. By default, ++all foreign libraries are enabled. ++.RS ++.TP ++The default is: \fB\(dq\(dq\fR (the empty regular expression) ++.RE ++. ++. ++ + . + .\" ---------------------------------------------------------------------------- + .SH "blacklist and blacklist_exceptions sections" +@@ -1765,6 +1780,31 @@ unpredictable ways. If the \(dqmarginal_path\(dq method is active, the + . + . + .\" ---------------------------------------------------------------------------- ++.SH "FOREIGN MULTIPATH SUPPORT" ++.\" ---------------------------------------------------------------------------- ++. ++multipath and multipathd can load \(dqforeign\(dq libraries to add ++support for other multipathing technologies besides the Linux device mapper. ++Currently this support is limited to printing detected information about ++multipath setup. In topology output, the names of foreign maps are prefixed by ++the foreign library name in square brackets, as in this example: ++. ++.P ++.EX ++# multipath -ll ++uuid.fedcba98-3579-4567-8765-123456789abc [nvme]:nvme4n9 NVMe,Some NVMe controller,FFFFFFFF ++size=167772160 features='n/a' hwhandler='ANA' wp=rw ++|-+- policy='n/a' prio=50 status=optimized ++| `- 4:38:1 nvme4c38n1 0:0 n/a optimized live ++`-+- policy='n/a' prio=50 status=optimized ++ `- 4:39:1 nvme4c39n1 0:0 n/a optimized live ++.EE ++. ++.P ++The \(dqnvme\(dq foreign library provides support for NVMe native multipathing ++in the kernel. It is part of the standard multipath package. ++. ++.\" ---------------------------------------------------------------------------- + .SH "KNOWN ISSUES" + .\" ---------------------------------------------------------------------------- + . +-- +2.17.2 + diff --git a/0016-multipathd-Don-t-use-fallback-code-after-getting-wwi.patch b/0016-multipathd-Don-t-use-fallback-code-after-getting-wwi.patch deleted file mode 100644 index 61e0f0d..0000000 --- a/0016-multipathd-Don-t-use-fallback-code-after-getting-wwi.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Thu, 28 Mar 2019 15:17:48 -0500 -Subject: [PATCH] multipathd: Don't use fallback code after getting wwid - -The fallback code is necessary to set up mutipath devices, if multipath -temporarily can't get the information from udev. However, once the -devices are set up, udev is the definitive source of this information. - -The wwid gotten from the fallback code and the udev code should always -be the same, in which case it doesn't matter where we get the wwid -from. But if they are different, it's important to try to do the -right thing. - -Working under the assumption that udev will either never give us this -information, or that it usually will. multipath should assume that if -there are multiple paths to a device, either they will all never get -a wwid from udev, or some of them will likely already have gotten the -correct wwid from udev. In this case, we should fix this as soon as -possible. - -This does mean that devices where udev will never give out the uuid -will not notice if the wwid changes, but that's a small price to pay -for doing the right thing most of the time. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/discovery.c | 22 +++++++++------------- - libmultipath/discovery.h | 3 ++- - multipathd/main.c | 2 +- - 3 files changed, 12 insertions(+), 15 deletions(-) - -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index 3ec60d6..744cf2c 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -1763,7 +1763,6 @@ static ssize_t uid_fallback(struct path *pp, int path_state, - !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) { - len = get_vpd_uid(pp); - *origin = "sysfs"; -- pp->uid_attribute = NULL; - if (len < 0 && path_state == PATH_UP) { - condlog(1, "%s: failed to get sysfs uid: %s", - pp->dev, strerror(-len)); -@@ -1787,7 +1786,6 @@ static ssize_t uid_fallback(struct path *pp, int path_state, - len = WWID_SIZE; - } - *origin = "sysfs"; -- pp->uid_attribute = NULL; - } - return len; - } -@@ -1800,12 +1798,14 @@ static int has_uid_fallback(struct path *pp) - } - - int --get_uid (struct path * pp, int path_state, struct udev_device *udev) -+get_uid (struct path * pp, int path_state, struct udev_device *udev, -+ int allow_fallback) - { - char *c; - const char *origin = "unknown"; - ssize_t len = 0; - struct config *conf; -+ int used_fallback = 0; - - if (!pp->uid_attribute && !pp->getuid) { - conf = get_multipath_config(); -@@ -1846,14 +1846,9 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) - len = get_vpd_uid(pp); - origin = "sysfs"; - } -- if (len <= 0 && has_uid_fallback(pp)) { -- int retrigger_tries; -- -- conf = get_multipath_config(); -- retrigger_tries = conf->retrigger_tries; -- put_multipath_config(conf); -- if (pp->retriggers >= retrigger_tries) -- len = uid_fallback(pp, path_state, &origin); -+ if (len <= 0 && allow_fallback && has_uid_fallback(pp)) { -+ used_fallback = 1; -+ len = uid_fallback(pp, path_state, &origin); - } - } - if ( len < 0 ) { -@@ -1870,7 +1865,7 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) - c--; - } - } -- condlog(3, "%s: uid = %s (%s)", pp->dev, -+ condlog((used_fallback)? 1 : 3, "%s: uid = %s (%s)", pp->dev, - *pp->wwid == '\0' ? "" : pp->wwid, origin); - return 0; - } -@@ -1994,7 +1989,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask) - } - - if ((mask & DI_WWID) && !strlen(pp->wwid)) { -- get_uid(pp, path_state, pp->udev); -+ get_uid(pp, path_state, pp->udev, -+ (pp->retriggers >= conf->retrigger_tries)); - if (!strlen(pp->wwid)) { - if (pp->bus == SYSFS_BUS_UNDEF) - return PATHINFO_SKIPPED; -diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h -index 9aacf75..8fd126b 100644 ---- a/libmultipath/discovery.h -+++ b/libmultipath/discovery.h -@@ -52,7 +52,8 @@ ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff, - size_t len); - int sysfs_get_asymmetric_access_state(struct path *pp, - char *buff, int buflen); --int get_uid(struct path * pp, int path_state, struct udev_device *udev); -+int get_uid(struct path * pp, int path_state, struct udev_device *udev, -+ int allow_fallback); - - /* - * discovery bitmask -diff --git a/multipathd/main.c b/multipathd/main.c -index e4f95a0..1413c6d 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -1227,7 +1227,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) - goto out; - - strcpy(wwid, pp->wwid); -- rc = get_uid(pp, pp->state, uev->udev); -+ rc = get_uid(pp, pp->state, uev->udev, 0); - - if (rc != 0) - strcpy(pp->wwid, wwid); --- -2.17.2 - diff --git a/0017-libmultipath-silence-dm_is_mpath-error-messages.patch b/0017-libmultipath-silence-dm_is_mpath-error-messages.patch deleted file mode 100644 index 203ed74..0000000 --- a/0017-libmultipath-silence-dm_is_mpath-error-messages.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Marzinski -Date: Thu, 28 Mar 2019 17:49:38 -0500 -Subject: [PATCH] libmultipath: silence dm_is_mpath error messages - -When "multipath -F" is run, dm_is_mpath was printing error messages -about partition devices, because they had already been removed, when -it checked. Lower the error logging level so this doesn't happen on -the default verbosity. - -Signed-off-by: Benjamin Marzinski ---- - libmultipath/devmapper.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c -index 3294bd4..2e79667 100644 ---- a/libmultipath/devmapper.c -+++ b/libmultipath/devmapper.c -@@ -746,7 +746,7 @@ out_task: - dm_task_destroy(dmt); - out: - if (r < 0) -- condlog(2, "%s: dm command failed in %s", name, __FUNCTION__); -+ condlog(3, "%s: dm command failed in %s: %s", name, __FUNCTION__, strerror(errno)); - return r; - } - --- -2.17.2 - diff --git a/0017-mpathpersist-remove-broken-unused-code.patch b/0017-mpathpersist-remove-broken-unused-code.patch new file mode 100644 index 0000000..82d1341 --- /dev/null +++ b/0017-mpathpersist-remove-broken-unused-code.patch @@ -0,0 +1,51 @@ +From 826c100b0cbe72c5d770614cea8898afec09628c Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 9 Sep 2019 16:18:33 -0500 +Subject: [PATCH] mpathpersist: remove broken/unused code + +The test for an empty pp->dev in updatepaths() dates back to when +disassemble_map() didn't fill in pp->dev for newly added paths, and it +was meant to catch paths that got added by disassemble_map(). With the +mpathpersist speedup code, all paths get added by disassemble_map(). +However, disassemble_map() now calls devt2devname() to set pp->dev if +possible. This means that there is no point in calling devt2devname() +again in updatepaths(). If for some reason it did return success, the +current code would still fail, since it doesn't set pp->udev in this +code path. The best thing to do if disassemble_map() couldn't set +pp->dev is simply to fail the path. + +Signed-off-by: Benjamin Marzinski +--- + libmpathpersist/mpath_persist.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 53022f5b..603cfc3b 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -82,18 +82,10 @@ updatepaths (struct multipath * mpp) + + vector_foreach_slot (pgp->paths, pp, j){ + if (!strlen(pp->dev)){ +- if (devt2devname(pp->dev, FILE_NAME_SIZE, +- pp->dev_t)){ +- /* +- * path is not in sysfs anymore +- */ +- pp->state = PATH_DOWN; +- continue; +- } +- pp->mpp = mpp; +- conf = get_multipath_config(); +- pathinfo(pp, conf, DI_ALL); +- put_multipath_config(conf); ++ /* ++ * path is not in sysfs anymore ++ */ ++ pp->state = PATH_DOWN; + continue; + } + pp->mpp = mpp; +-- +2.17.2 + diff --git a/0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch b/0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch new file mode 100644 index 0000000..68d5852 --- /dev/null +++ b/0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch @@ -0,0 +1,33 @@ +From 16116095d5a11c5134e0696398a9908dafc415bc Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 9 Sep 2019 17:18:08 -0500 +Subject: [PATCH] libmultipath: EMC PowerMax NVMe device config + +Got this config from Dell. + +Cc: heyi +Signed-off-by: Benjamin Marzinski +--- + libmultipath/hwtable.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index 96e8b25d..ca217e65 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -360,6 +360,12 @@ static struct hwentry default_hw[] = { + .pgfailback = -FAILBACK_IMMEDIATE, + .no_path_retry = 30, + }, ++ { ++ /* EMC PowerMax NVMe */ ++ .vendor = "NVME", ++ .product = "^EMC PowerMax_", ++ .pgpolicy = MULTIBUS, ++ }, + /* + * Fujitsu + */ +-- +2.17.2 + diff --git a/0019-mpathpersist-fix-leaks.patch b/0019-mpathpersist-fix-leaks.patch new file mode 100644 index 0000000..8610633 --- /dev/null +++ b/0019-mpathpersist-fix-leaks.patch @@ -0,0 +1,132 @@ +From 385f0a62f83af67eb0b4b67f3af43e149619c0af Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 10 Sep 2019 10:44:50 -0500 +Subject: [PATCH] mpathpersist: fix leaks + +If handle_args() fails while looping through the argument list, it needs +to free batch_fn, if it has been set. Also handle_args() needs to make +sure to free the file descriptor after it has been opened. + +Signed-off-by: Benjamin Marzinski +--- + mpathpersist/main.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +diff --git a/mpathpersist/main.c b/mpathpersist/main.c +index 5ad06a97..2368b429 100644 +--- a/mpathpersist/main.c ++++ b/mpathpersist/main.c +@@ -155,7 +155,8 @@ static int do_batch_file(const char *batch_fn) + + static int handle_args(int argc, char * argv[], int nline) + { +- int fd, c; ++ int c; ++ int fd = -1; + const char *device_name = NULL; + int num_prin_sa = 0; + int num_prout_sa = 0; +@@ -213,7 +214,8 @@ static int handle_args(int argc, char * argv[], int nline) + if (nline == 0 && 1 != sscanf (optarg, "%d", &loglevel)) + { + fprintf (stderr, "bad argument to '--verbose'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + break; + +@@ -228,6 +230,7 @@ static int handle_args(int argc, char * argv[], int nline) + + case 'h': + usage (); ++ free(batch_fn); + return 0; + + case 'H': +@@ -254,7 +257,8 @@ static int handle_args(int argc, char * argv[], int nline) + if (1 != sscanf (optarg, "%" SCNx64 "", ¶m_rk)) + { + fprintf (stderr, "bad argument to '--param-rk'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + ++num_prout_param; + break; +@@ -263,7 +267,8 @@ static int handle_args(int argc, char * argv[], int nline) + if (1 != sscanf (optarg, "%" SCNx64 "", ¶m_sark)) + { + fprintf (stderr, "bad argument to '--param-sark'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + ++num_prout_param; + break; +@@ -282,7 +287,8 @@ static int handle_args(int argc, char * argv[], int nline) + if (1 != sscanf (optarg, "%x", &prout_type)) + { + fprintf (stderr, "bad argument to '--prout-type'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + ++num_prout_param; + break; +@@ -330,7 +336,8 @@ static int handle_args(int argc, char * argv[], int nline) + case 'X': + if (0 != construct_transportid(optarg, transportids, num_transport)) { + fprintf(stderr, "bad argument to '--transport-id'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + + ++num_transport; +@@ -339,11 +346,13 @@ static int handle_args(int argc, char * argv[], int nline) + case 'l': + if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) { + fprintf(stderr, "bad argument to '--alloc-length'\n"); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) { + fprintf(stderr, "'--alloc-length' argument exceeds maximum" + " limit(%d)\n", MPATH_MAX_PARAM_LEN); +- return MPATH_PR_SYNTAX_ERROR; ++ ret = MPATH_PR_SYNTAX_ERROR; ++ goto out; + } + break; + +@@ -481,14 +490,14 @@ static int handle_args(int argc, char * argv[], int nline) + { + fprintf (stderr, "failed to allocate PRIN response buffer\n"); + ret = MPATH_PR_OTHER; +- goto out; ++ goto out_fd; + } + + ret = __mpath_persistent_reserve_in (fd, prin_sa, resp, noisy); + if (ret != MPATH_PR_SUCCESS ) + { + fprintf (stderr, "Persistent Reserve IN command failed\n"); +- goto out; ++ goto out_fd; + } + + switch(prin_sa) +@@ -568,8 +577,8 @@ static int handle_args(int argc, char * argv[], int nline) + printf("PR out: command failed\n"); + } + ++out_fd: + close (fd); +- + out : + if (ret == MPATH_PR_SYNTAX_ERROR) { + free(batch_fn); +-- +2.17.2 + diff --git a/0020-libmultipath-fix-mpcontext-initialization.patch b/0020-libmultipath-fix-mpcontext-initialization.patch new file mode 100644 index 0000000..1ed3a7b --- /dev/null +++ b/0020-libmultipath-fix-mpcontext-initialization.patch @@ -0,0 +1,232 @@ +From 33a6f6b05d7041716142f080a2708db351c92eaa Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 10 Sep 2019 15:46:28 -0500 +Subject: [PATCH] libmultipath: fix mpcontext initialization + +If a path is discovered before there is a multipath device for it to +belong to, the checker will not have its mpcontext initialized, even if +that path later belongs to a multipath device. A checker's mpcontext is +only set when the checker is selected, and is set to NULL if there is no +multipath device associated with the path. This only impacts the emc +checker. However, it makes the emc checker unable to determine if a +passive path is connected to an inactive snapshot or not. + +This can be solved by adding a new checker class function, mp_init(). +This is called when the checker is first initialized, and whenever the +checker is called, if the checker's mpcontext hasn't been initialized. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/checkers.c | 29 ++++++++++++++++++++++++++-- + libmultipath/checkers.h | 1 + + libmultipath/checkers/cciss_tur.c | 5 +++++ + libmultipath/checkers/directio.c | 5 +++++ + libmultipath/checkers/emc_clariion.c | 7 +++++++ + libmultipath/checkers/hp_sw.c | 5 +++++ + libmultipath/checkers/rdac.c | 5 +++++ + libmultipath/checkers/readsector0.c | 5 +++++ + libmultipath/checkers/tur.c | 5 +++++ + libmultipath/discovery.c | 2 ++ + 10 files changed, 67 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c +index f4fdcae9..240b0f29 100644 +--- a/libmultipath/checkers.c ++++ b/libmultipath/checkers.c +@@ -16,6 +16,7 @@ struct checker_class { + char name[CHECKER_NAME_LEN]; + int (*check)(struct checker *); + int (*init)(struct checker *); /* to allocate the context */ ++ int (*mp_init)(struct checker *); /* to allocate the mpcontext */ + void (*free)(struct checker *); /* to free the context */ + const char **msgtable; + short msgtable_size; +@@ -140,6 +141,13 @@ static struct checker_class *add_checker_class(const char *multipath_dir, + if (!c->init) + goto out; + ++ c->mp_init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_mp_init"); ++ errstr = dlerror(); ++ if (errstr != NULL) ++ condlog(0, "A dynamic linking error occurred: (%s)", errstr); ++ if (!c->mp_init) ++ goto out; ++ + c->free = (void (*)(struct checker *)) dlsym(c->handle, "libcheck_free"); + errstr = dlerror(); + if (errstr != NULL) +@@ -212,8 +220,25 @@ int checker_init (struct checker * c, void ** mpctxt_addr) + if (!c || !c->cls) + return 1; + c->mpcontext = mpctxt_addr; +- if (c->cls->init) +- return c->cls->init(c); ++ if (c->cls->init && c->cls->init(c) != 0) ++ return 1; ++ if (mpctxt_addr && *mpctxt_addr == NULL && c->cls->mp_init && ++ c->cls->mp_init(c) != 0) /* continue even if mp_init fails */ ++ c->mpcontext = NULL; ++ return 0; ++} ++ ++int checker_mp_init(struct checker * c, void ** mpctxt_addr) ++{ ++ if (!c || !c->cls) ++ return 1; ++ if (c->cls->mp_init && !c->mpcontext && mpctxt_addr) { ++ c->mpcontext = mpctxt_addr; ++ if (c->cls->mp_init(c) != 0) { ++ c->mpcontext = NULL; ++ return 1; ++ } ++ } + return 0; + } + +diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h +index dab197f9..5237e7ec 100644 +--- a/libmultipath/checkers.h ++++ b/libmultipath/checkers.h +@@ -138,6 +138,7 @@ const char *checker_state_name(int); + int init_checkers(const char *); + void cleanup_checkers (void); + int checker_init (struct checker *, void **); ++int checker_mp_init(struct checker *, void **); + void checker_clear (struct checker *); + void checker_put (struct checker *); + void checker_reset (struct checker *); +diff --git a/libmultipath/checkers/cciss_tur.c b/libmultipath/checkers/cciss_tur.c +index ea843742..b570ed65 100644 +--- a/libmultipath/checkers/cciss_tur.c ++++ b/libmultipath/checkers/cciss_tur.c +@@ -51,6 +51,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init (struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +diff --git a/libmultipath/checkers/directio.c b/libmultipath/checkers/directio.c +index 1b00b775..96f223b2 100644 +--- a/libmultipath/checkers/directio.c ++++ b/libmultipath/checkers/directio.c +@@ -103,6 +103,11 @@ out: + return 1; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + struct directio_context * ct = (struct directio_context *)c->context; +diff --git a/libmultipath/checkers/emc_clariion.c b/libmultipath/checkers/emc_clariion.c +index 6fc89113..5cd63aca 100644 +--- a/libmultipath/checkers/emc_clariion.c ++++ b/libmultipath/checkers/emc_clariion.c +@@ -107,11 +107,18 @@ int libcheck_init (struct checker * c) + return 1; + ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0; + ++ return 0; ++} ++ ++int libcheck_mp_init (struct checker * c) ++{ + /* + * Allocate and initialize the multi-path global context. + */ + if (c->mpcontext && *c->mpcontext == NULL) { + void * mpctxt = malloc(sizeof(int)); ++ if (!mpctxt) ++ return 1; + *c->mpcontext = mpctxt; + CLR_INACTIVE_SNAP(c); + } +diff --git a/libmultipath/checkers/hp_sw.c b/libmultipath/checkers/hp_sw.c +index 1a820223..35aca204 100644 +--- a/libmultipath/checkers/hp_sw.c ++++ b/libmultipath/checkers/hp_sw.c +@@ -37,6 +37,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +diff --git a/libmultipath/checkers/rdac.c b/libmultipath/checkers/rdac.c +index 8a3b73ec..805d153e 100644 +--- a/libmultipath/checkers/rdac.c ++++ b/libmultipath/checkers/rdac.c +@@ -133,6 +133,11 @@ out: + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +diff --git a/libmultipath/checkers/readsector0.c b/libmultipath/checkers/readsector0.c +index cf79e067..71db9f80 100644 +--- a/libmultipath/checkers/readsector0.c ++++ b/libmultipath/checkers/readsector0.c +@@ -15,6 +15,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + void libcheck_free (struct checker * c) + { + return; +diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c +index 6b08dbbb..138b9e58 100644 +--- a/libmultipath/checkers/tur.c ++++ b/libmultipath/checkers/tur.c +@@ -79,6 +79,11 @@ int libcheck_init (struct checker * c) + return 0; + } + ++int libcheck_mp_init(struct checker * c) ++{ ++ return 0; ++} ++ + static void cleanup_context(struct tur_checker_context *ct) + { + pthread_mutex_destroy(&ct->lock); +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index acca466c..72f455e8 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -1608,6 +1608,8 @@ get_state (struct path * pp, struct config *conf, int daemon, int oldstate) + return PATH_UNCHECKED; + } + } ++ if (pp->mpp && !c->mpcontext) ++ checker_mp_init(c, &pp->mpp->mpcontext); + checker_clear_message(c); + if (daemon) { + if (conf->force_sync == 0) +-- +2.17.2 + diff --git a/0018-RH-fixup-udev-rules-for-redhat.patch b/0021-RH-fixup-udev-rules-for-redhat.patch similarity index 92% rename from 0018-RH-fixup-udev-rules-for-redhat.patch rename to 0021-RH-fixup-udev-rules-for-redhat.patch index 6c1bf63..444f5cf 100644 --- a/0018-RH-fixup-udev-rules-for-redhat.patch +++ b/0021-RH-fixup-udev-rules-for-redhat.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From c1df27f4efd0c36d6ceecf5c850a68859e7d5fe5 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 13 Apr 2017 07:22:23 -0500 Subject: [PATCH] RH: fixup udev rules for redhat @@ -15,10 +15,10 @@ Signed-off-by: Benjamin Marzinski 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.inc b/Makefile.inc -index fc728ca..2f0bcea 100644 +index 56c3eda0..2e8946ca 100644 --- a/Makefile.inc +++ b/Makefile.inc -@@ -48,7 +48,7 @@ endif +@@ -53,7 +53,7 @@ endif prefix = exec_prefix = $(prefix) usr_prefix = $(prefix) @@ -28,7 +28,7 @@ index fc728ca..2f0bcea 100644 udevrulesdir = $(libudevdir)/rules.d multipathdir = $(TOPDIR)/libmultipath diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules -index 8f99049..8a3a171 100644 +index 8f990494..8a3a1718 100644 --- a/kpartx/kpartx.rules +++ b/kpartx/kpartx.rules @@ -32,6 +32,6 @@ LABEL="mpath_kpartx_end" @@ -40,7 +40,7 @@ index 8f99049..8a3a171 100644 LABEL="kpartx_end" diff --git a/multipath/Makefile b/multipath/Makefile -index 0828a8f..b9bbb3c 100644 +index 0828a8f7..b9bbb3cf 100644 --- a/multipath/Makefile +++ b/multipath/Makefile @@ -24,7 +24,7 @@ install: diff --git a/0019-RH-Remove-the-property-blacklist-exception-builtin.patch b/0022-RH-Remove-the-property-blacklist-exception-builtin.patch similarity index 57% rename from 0019-RH-Remove-the-property-blacklist-exception-builtin.patch rename to 0022-RH-Remove-the-property-blacklist-exception-builtin.patch index 81c12b9..925aab9 100644 --- a/0019-RH-Remove-the-property-blacklist-exception-builtin.patch +++ b/0022-RH-Remove-the-property-blacklist-exception-builtin.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 46cfd1a474d1c3e2724782c493d0ea72c8438807 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 2 Jul 2014 12:49:53 -0500 Subject: [PATCH] RH: Remove the property blacklist exception builtin @@ -13,12 +13,13 @@ it. Signed-off-by: Benjamin Marzinski --- - libmultipath/blacklist.c | 12 ++++-------- - multipath/multipath.conf.5 | 14 ++++++-------- - 2 files changed, 10 insertions(+), 16 deletions(-) + libmultipath/blacklist.c | 9 ++------- + multipath/multipath.conf.5 | 12 ++++++------ + tests/blacklist.c | 6 ++---- + 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c -index e0d0279..556c0b9 100644 +index 00e8dbdb..d9691b17 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c @@ -204,12 +204,6 @@ setup_default_blist (struct config * conf) @@ -34,14 +35,10 @@ index e0d0279..556c0b9 100644 vector_foreach_slot (conf->hwtable, hwe, i) { if (hwe->bl_product) { if (find_blacklist_device(conf->blist_device, -@@ -394,9 +388,11 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl) - if (udev) { - /* - * This is the inverse of the 'normal' matching; -- * the environment variable _has_ to match. -+ * the environment variable _has_ to match -+ * if a whitelist is present. - */ +@@ -411,7 +405,8 @@ filter_property(struct config *conf, struct udev_device *udev, int lvl, + *uid_attribute != '\0'; + bool uid_attr_seen = false; + - r = MATCH_PROPERTY_BLIST_MISSING; + if (VECTOR_SIZE(conf->elist_property)) + r = MATCH_PROPERTY_BLIST_MISSING; @@ -49,10 +46,10 @@ index e0d0279..556c0b9 100644 udev_device_get_properties_list_entry(udev)) { diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 -index 646c156..768ab83 100644 +index 101e1a88..b4837b15 100644 --- a/multipath/multipath.conf.5 +++ b/multipath/multipath.conf.5 -@@ -1235,16 +1235,14 @@ keywords. Both are regular expressions. For a full description of these keywords +@@ -1287,9 +1287,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, @@ -61,20 +58,49 @@ index 646c156..768ab83 100644 +least one whitelisted udev property; otherwise they're treated as blacklisted, and the message "\fIblacklisted, udev property missing\fR" is displayed in the logs. --. --.RS ++For example, setting the property blacklist_exception to ++\fB(SCSI_IDENT_|ID_WWN)\fR, will cause well-behaved SCSI devices and devices ++that provide a WWN (World Wide Number) to be included, and all others to be ++excluded. This works to exclude most non-multipathable devices. + . + .RS + .PP +@@ -1300,11 +1305,6 @@ Blacklisting by missing properties is only applied to devices which do have the + property specified by \fIuid_attribute\fR (e.g. \fIID_SERIAL\fR) + set. Previously, it was applied to every device, possibly causing devices to be + blacklisted because of temporary I/O error conditions. -.PP -The default \fIblacklist exception\fR is: \fB(SCSI_IDENT_|ID_WWN)\fR, causing -well-behaved SCSI devices and devices that provide a WWN (World Wide Number) -to be included, and all others to be excluded. -.RE -+For example, setting the property blacklist_exception to -+\fB(SCSI_IDENT_|ID_WWN)\fR, will cause well-behaved SCSI devices and devices -+that provide a WWN (World Wide Number) to be included, and all others to be -+excluded. This works to exclude most non-multipathable devices. .TP .B protocol Regular expression for the protocol of a device to be excluded/included. +diff --git a/tests/blacklist.c b/tests/blacklist.c +index 362c44d9..ea284939 100644 +--- a/tests/blacklist.c ++++ b/tests/blacklist.c +@@ -291,7 +291,7 @@ static void test_property_missing(void **state) + conf.blist_property = blist_property_wwn; + expect_condlog(3, "sdb: blacklisted, udev property missing\n"); + assert_int_equal(filter_property(&conf, &udev, 3, "ID_SERIAL"), +- MATCH_PROPERTY_BLIST_MISSING); ++ MATCH_NOTHING); + assert_int_equal(filter_property(&conf, &udev, 3, "ID_BLAH"), + MATCH_NOTHING); + assert_int_equal(filter_property(&conf, &udev, 3, ""), +@@ -383,9 +383,7 @@ static void test_filter_path_missing1(void **state) + conf.blist_device = blist_device_foo_bar; + conf.blist_protocol = blist_protocol_fcp; + conf.blist_wwid = blist_wwid_xyzzy; +- expect_condlog(3, "sdb: blacklisted, udev property missing\n"); +- assert_int_equal(filter_path(&conf, &miss1_pp), +- MATCH_PROPERTY_BLIST_MISSING); ++ assert_int_equal(filter_path(&conf, &miss1_pp), MATCH_NOTHING); + } + + /* This one matches the property whitelist, to test the other missing -- 2.17.2 diff --git a/0020-RH-don-t-start-without-a-config-file.patch b/0023-RH-don-t-start-without-a-config-file.patch similarity index 91% rename from 0020-RH-don-t-start-without-a-config-file.patch rename to 0023-RH-don-t-start-without-a-config-file.patch index d840c33..7d5fe18 100644 --- a/0020-RH-don-t-start-without-a-config-file.patch +++ b/0023-RH-don-t-start-without-a-config-file.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 4e4c589657eecfe5d37636ce91eb2945f63fc0a6 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 15 Oct 2014 10:39:30 -0500 Subject: [PATCH] RH: don't start without a config file @@ -20,7 +20,7 @@ Signed-off-by: Benjamin Marzinski 5 files changed, 20 insertions(+) diff --git a/libmultipath/config.c b/libmultipath/config.c -index 141f092..544d2fb 100644 +index 20e3b8bf..c36bc69c 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c @@ -26,6 +26,7 @@ @@ -31,7 +31,7 @@ index 141f092..544d2fb 100644 static int hwe_strmatch (const struct hwentry *hwe1, const struct hwentry *hwe2) -@@ -745,6 +746,20 @@ load_config (char * file) +@@ -743,6 +744,20 @@ load_config (char * file) goto out; } factorize_hwtable(conf->hwtable, builtin_hwtable_size, file); @@ -53,7 +53,7 @@ index 141f092..544d2fb 100644 conf->processed_main_config = 1; diff --git a/libmultipath/config.h b/libmultipath/config.h -index f5bf5b1..8803967 100644 +index ffec3103..6dbf553d 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -9,6 +9,7 @@ @@ -65,7 +65,7 @@ index f5bf5b1..8803967 100644 /* * In kernel, fast_io_fail == 0 means immediate failure on rport delete. diff --git a/multipath/multipath.rules b/multipath/multipath.rules -index 9df11a9..0486bf7 100644 +index 9df11a95..0486bf70 100644 --- a/multipath/multipath.rules +++ b/multipath/multipath.rules @@ -9,6 +9,7 @@ IMPORT{cmdline}="nompath" @@ -77,10 +77,10 @@ index 9df11a9..0486bf7 100644 ENV{DEVTYPE}!="partition", GOTO="test_dev" IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH" diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8 -index 94c3f97..ed13efd 100644 +index 048a838d..8bd47a80 100644 --- a/multipathd/multipathd.8 +++ b/multipathd/multipathd.8 -@@ -38,6 +38,8 @@ map regains its maximum performance and redundancy. +@@ -39,6 +39,8 @@ map regains its maximum performance and redundancy. This daemon executes the external \fBmultipath\fR tool when events occur. In turn, the multipath tool signals the multipathd daemon when it is done with devmap reconfiguration, so that it can refresh its failed path list. @@ -90,7 +90,7 @@ index 94c3f97..ed13efd 100644 . .\" ---------------------------------------------------------------------------- diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service -index ba24983..17434ce 100644 +index ba24983e..17434cef 100644 --- a/multipathd/multipathd.service +++ b/multipathd/multipathd.service @@ -4,6 +4,7 @@ Wants=systemd-udev-trigger.service systemd-udev-settle.service diff --git a/0021-RH-use-rpm-optflags-if-present.patch b/0024-RH-use-rpm-optflags-if-present.patch similarity index 92% rename from 0021-RH-use-rpm-optflags-if-present.patch rename to 0024-RH-use-rpm-optflags-if-present.patch index 4b41d9e..8721a82 100644 --- a/0021-RH-use-rpm-optflags-if-present.patch +++ b/0024-RH-use-rpm-optflags-if-present.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From e08dd1d6abe62714c484b046a68c95c3803716dd Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 19 Apr 2017 06:10:01 -0500 Subject: [PATCH] RH: use rpm optflags if present @@ -13,10 +13,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Makefile.inc b/Makefile.inc -index 2f0bcea..b98800a 100644 +index 2e8946ca..1b2f47a8 100644 --- a/Makefile.inc +++ b/Makefile.inc -@@ -83,15 +83,23 @@ TEST_CC_OPTION = $(shell \ +@@ -88,15 +88,23 @@ TEST_CC_OPTION = $(shell \ echo "$(2)"; \ fi) diff --git a/0022-RH-add-mpathconf.patch b/0025-RH-add-mpathconf.patch similarity index 98% rename from 0022-RH-add-mpathconf.patch rename to 0025-RH-add-mpathconf.patch index afa2761..3f3c570 100644 --- a/0022-RH-add-mpathconf.patch +++ b/0025-RH-add-mpathconf.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 64b336a47365eb0ee91a917d6b98c6c695775a36 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 16 Oct 2014 15:49:01 -0500 Subject: [PATCH] RH: add mpathconf @@ -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 544d2fb..deb80c2 100644 +index c36bc69c..fcd17dd4 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c -@@ -748,6 +748,8 @@ load_config (char * file) +@@ -746,6 +746,8 @@ load_config (char * file) factorize_hwtable(conf->hwtable, builtin_hwtable_size, file); } else { condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices."); @@ -34,7 +34,7 @@ index 544d2fb..deb80c2 100644 conf->blist_devnode = vector_alloc(); if (!conf->blist_devnode) { diff --git a/multipath/Makefile b/multipath/Makefile -index b9bbb3c..e720c7f 100644 +index b9bbb3cf..e720c7f6 100644 --- a/multipath/Makefile +++ b/multipath/Makefile @@ -18,10 +18,12 @@ $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so @@ -69,7 +69,7 @@ index b9bbb3c..e720c7f 100644 $(RM) core *.o $(EXEC) *.gz diff --git a/multipath/mpathconf b/multipath/mpathconf new file mode 100644 -index 0000000..e839134 +index 00000000..e8391347 --- /dev/null +++ b/multipath/mpathconf @@ -0,0 +1,464 @@ @@ -539,7 +539,7 @@ index 0000000..e839134 +fi diff --git a/multipath/mpathconf.8 b/multipath/mpathconf.8 new file mode 100644 -index 0000000..5b7ae0c +index 00000000..5b7ae0c3 --- /dev/null +++ b/multipath/mpathconf.8 @@ -0,0 +1,119 @@ diff --git a/0023-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch b/0026-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch similarity index 82% rename from 0023-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch rename to 0026-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch index 86bb2db..5446efa 100644 --- a/0023-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +++ b/0026-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From bba3bc3cfd910921ab5887acdc9503610e7efa18 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 17 Oct 2014 11:20:34 -0500 Subject: [PATCH] RH: add wwids from kernel cmdline mpath.wwids with -A @@ -22,10 +22,10 @@ Signed-off-by: Benjamin Marzinski 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c -index 53e7951..39e08cd 100644 +index ef748125..349da8b7 100644 --- a/libmultipath/wwids.c +++ b/libmultipath/wwids.c -@@ -443,3 +443,47 @@ int op ## _wwid(const char *wwid) \ +@@ -444,3 +444,47 @@ int op ## _wwid(const char *wwid) \ declare_failed_wwid_op(is_failed, false) declare_failed_wwid_op(mark_failed, true) declare_failed_wwid_op(unmark_failed, true) @@ -74,7 +74,7 @@ index 53e7951..39e08cd 100644 + return ret; +} diff --git a/libmultipath/wwids.h b/libmultipath/wwids.h -index 0c6ee54..e32a0b0 100644 +index 0c6ee54d..e32a0b0e 100644 --- a/libmultipath/wwids.h +++ b/libmultipath/wwids.h @@ -17,6 +17,7 @@ int remember_wwid(char *wwid); @@ -86,19 +86,19 @@ index 0c6ee54..e32a0b0 100644 enum { WWID_IS_NOT_FAILED = 0, diff --git a/multipath/main.c b/multipath/main.c -index 69141db..e7771c0 100644 +index 4f4d8e89..22aff7be 100644 --- a/multipath/main.c +++ b/multipath/main.c -@@ -133,7 +133,7 @@ usage (char * progname) - { - fprintf (stderr, VERSION_STRING); - fprintf (stderr, "Usage:\n"); -- fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); -+ fprintf (stderr, " %s [-a|-A|-c|-w|-W] [-d] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); - fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [-R num] [dev]\n", progname); - fprintf (stderr, " %s -F [-v lvl] [-R num]\n", progname); - fprintf (stderr, " %s [-t|-T]\n", progname); -@@ -147,6 +147,8 @@ usage (char * progname) +@@ -138,7 +138,7 @@ usage (char * progname) + fprintf (stderr, " %s [-v level] [-R retries] -F\n", progname); + fprintf (stderr, " %s [-v level] [-l|-ll] [device]\n", progname); + fprintf (stderr, " %s [-v level] [-a|-w] device\n", progname); +- fprintf (stderr, " %s [-v level] -W\n", progname); ++ fprintf (stderr, " %s [-v level] [-A|-W]\n", progname); + fprintf (stderr, " %s [-v level] [-i] [-c|-C] device\n", progname); + fprintf (stderr, " %s [-v level] [-i] [-u|-U]\n", progname); + fprintf (stderr, " %s [-h|-t|-T]\n", progname); +@@ -151,6 +151,8 @@ usage (char * progname) " -f flush a multipath device map\n" " -F flush all multipath device maps\n" " -a add a device wwid to the wwids file\n" @@ -107,7 +107,7 @@ index 69141db..e7771c0 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" -@@ -870,7 +872,7 @@ main (int argc, char *argv[]) +@@ -905,7 +907,7 @@ main (int argc, char *argv[]) exit(RTVL_FAIL); multipath_conf = conf; conf->retrigger_tries = 0; @@ -116,7 +116,7 @@ index 69141db..e7771c0 100644 switch(arg) { case 1: printf("optarg : %s\n",optarg); break; -@@ -940,6 +942,10 @@ main (int argc, char *argv[]) +@@ -975,6 +977,10 @@ main (int argc, char *argv[]) case 'T': cmd = CMD_DUMP_CONFIG; break; @@ -128,7 +128,7 @@ index 69141db..e7771c0 100644 usage(argv[0]); exit(RTVL_OK); diff --git a/multipath/multipath.8 b/multipath/multipath.8 -index 9cdd05a..8befc45 100644 +index 9cdd05a3..8befc45a 100644 --- a/multipath/multipath.8 +++ b/multipath/multipath.8 @@ -63,7 +63,7 @@ multipath \- Device mapper target autoconfig. @@ -153,7 +153,7 @@ index 9cdd05a..8befc45 100644 Remove the WWID for the specified device from the WWIDs file. . diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service -index 17434ce..0fbcc46 100644 +index 17434cef..0fbcc46b 100644 --- a/multipathd/multipathd.service +++ b/multipathd/multipathd.service @@ -15,6 +15,7 @@ Type=notify diff --git a/0027-Fix-systemd-version-detection.patch b/0027-Fix-systemd-version-detection.patch deleted file mode 100644 index 7414638..0000000 --- a/0027-Fix-systemd-version-detection.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Tue, 26 Mar 2019 16:34:32 -0500 -Subject: [PATCH] Fix systemd version detection - -Signed-off-by: Igor Gnatenko -Signed-off-by: Benjamin Marzinski ---- - Makefile.inc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Makefile.inc b/Makefile.inc -index b98800a..da49852 100644 ---- a/Makefile.inc -+++ b/Makefile.inc -@@ -37,7 +37,7 @@ endif - - ifndef SYSTEMD - ifeq ($(shell systemctl --version > /dev/null 2>&1 && echo 1), 1) -- SYSTEMD = $(shell systemctl --version 2> /dev/null | sed -n 's/systemd \([0-9]*\)/\1/p') -+ SYSTEMD = $(shell systemctl --version 2> /dev/null | sed -n 's/systemd \([0-9]*\).*/\1/p') - endif - endif - --- -2.17.2 - diff --git a/0024-RH-warn-on-invalid-regex-instead-of-failing.patch b/0027-RH-warn-on-invalid-regex-instead-of-failing.patch similarity index 88% rename from 0024-RH-warn-on-invalid-regex-instead-of-failing.patch rename to 0027-RH-warn-on-invalid-regex-instead-of-failing.patch index ded4ccb..5250415 100644 --- a/0024-RH-warn-on-invalid-regex-instead-of-failing.patch +++ b/0027-RH-warn-on-invalid-regex-instead-of-failing.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 779d51dcaff09fc8910d5a71e74d735f573ece9e Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 6 Nov 2017 21:39:28 -0600 Subject: [PATCH] RH: warn on invalid regex instead of failing @@ -16,7 +16,7 @@ Signed-off-by: Benjamin Marzinski 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/libmultipath/dict.c b/libmultipath/dict.c -index 96815f8..3b1b652 100644 +index 1b3d0373..695c8404 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -58,6 +58,21 @@ set_str(vector strvec, void *ptr) @@ -41,7 +41,7 @@ index 96815f8..3b1b652 100644 static int set_yes_no(vector strvec, void *ptr) { -@@ -1386,7 +1401,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \ +@@ -1422,7 +1437,7 @@ ble_ ## option ## _handler (struct config *conf, vector strvec) \ if (!conf->option) \ return 1; \ \ @@ -50,7 +50,7 @@ index 96815f8..3b1b652 100644 if (!buff) \ return 1; \ \ -@@ -1402,7 +1417,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \ +@@ -1438,7 +1453,7 @@ ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \ if (!conf->option) \ return 1; \ \ @@ -59,7 +59,7 @@ index 96815f8..3b1b652 100644 if (!buff) \ return 1; \ \ -@@ -1505,16 +1520,16 @@ device_handler(struct config *conf, vector strvec) +@@ -1541,16 +1556,16 @@ device_handler(struct config *conf, vector strvec) return 0; } @@ -81,11 +81,11 @@ index 96815f8..3b1b652 100644 declare_hw_handler(hwhandler, set_str) diff --git a/libmultipath/parser.c b/libmultipath/parser.c -index 92ef7cf..4289336 100644 +index e00c5fff..15495d26 100644 --- a/libmultipath/parser.c +++ b/libmultipath/parser.c -@@ -384,6 +384,19 @@ set_value(vector strvec) - return alloc; +@@ -382,6 +382,19 @@ oom: + return NULL; } +void * @@ -105,7 +105,7 @@ index 92ef7cf..4289336 100644 static int kw_level = 0; diff --git a/libmultipath/parser.h b/libmultipath/parser.h -index 62906e9..b791705 100644 +index 62906e98..b7917052 100644 --- a/libmultipath/parser.h +++ b/libmultipath/parser.h @@ -77,6 +77,7 @@ extern void dump_keywords(vector keydump, int level); diff --git a/0025-RH-reset-default-find_mutipaths-value-to-off.patch b/0028-RH-reset-default-find_mutipaths-value-to-off.patch similarity index 88% rename from 0025-RH-reset-default-find_mutipaths-value-to-off.patch rename to 0028-RH-reset-default-find_mutipaths-value-to-off.patch index 2f6bbe9..2ea9db8 100644 --- a/0025-RH-reset-default-find_mutipaths-value-to-off.patch +++ b/0028-RH-reset-default-find_mutipaths-value-to-off.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 1f5156bc77ef05f5d93e7a9df6e270a587eb6a30 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 7 Jun 2018 17:43:52 -0500 Subject: [PATCH] RH: reset default find_mutipaths value to off @@ -12,10 +12,10 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h -index 6576939..2ad6308 100644 +index 4dfe007c..d910da51 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h -@@ -17,7 +17,7 @@ +@@ -20,7 +20,7 @@ #define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF #define DEFAULT_VERBOSITY 2 #define DEFAULT_REASSIGN_MAPS 0 diff --git a/0026-RH-Fix-nvme-compilation-warning.patch b/0029-RH-Fix-nvme-compilation-warning.patch similarity index 88% rename from 0026-RH-Fix-nvme-compilation-warning.patch rename to 0029-RH-Fix-nvme-compilation-warning.patch index 6de061a..f0308a7 100644 --- a/0026-RH-Fix-nvme-compilation-warning.patch +++ b/0029-RH-Fix-nvme-compilation-warning.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 938d211bf5e8d96849bfbf4d2707507adc7f718e Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 25 Jan 2019 14:54:56 -0600 Subject: [PATCH] RH: Fix nvme compilation warning @@ -9,7 +9,7 @@ Signed-off-by: Benjamin Marzinski 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/nvme/argconfig.h b/libmultipath/nvme/argconfig.h -index adb192b..bfd10ef 100644 +index adb192b6..bfd10ef8 100644 --- a/libmultipath/nvme/argconfig.h +++ b/libmultipath/nvme/argconfig.h @@ -76,7 +76,7 @@ struct argconfig_commandline_options { diff --git a/0028-RH-attempt-to-get-ANA-info-via-sysfs-first.patch b/0030-RH-attempt-to-get-ANA-info-via-sysfs-first.patch similarity index 96% rename from 0028-RH-attempt-to-get-ANA-info-via-sysfs-first.patch rename to 0030-RH-attempt-to-get-ANA-info-via-sysfs-first.patch index 36954ad..b85edca 100644 --- a/0028-RH-attempt-to-get-ANA-info-via-sysfs-first.patch +++ b/0030-RH-attempt-to-get-ANA-info-via-sysfs-first.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From cff4e6981d8b168cabd81b3de6f9f97735de7e1a Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 11 Apr 2019 13:25:42 -0500 Subject: [PATCH] RH: attempt to get ANA info via sysfs first @@ -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 990d935..d84571b 100644 +index 2673d9d9..f34ade28 100644 --- a/libmultipath/prioritizers/ana.c +++ b/libmultipath/prioritizers/ana.c @@ -24,6 +24,7 @@ diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index 66b930a..5d8f198 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,43 +1,45 @@ Name: device-mapper-multipath -Version: 0.8.0 -Release: 3%{?dist} +Version: 0.8.2 +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 "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;h=17a6101;sf=tgz" -o multipath-tools-17a6101.tgz -Source0: multipath-tools-0.8.0.tgz +# curl "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;h=refs/tags/0.8.2;sf=tgz" -o multipath-tools-0.8.2.tgz +Source0: multipath-tools-0.8.2.tgz Source1: multipath.conf -Patch0001: 0001-BZ-1668693-disable-user_friendly_names-for-NetApp.patch -Patch0002: 0002-libmultipath-handle-existing-paths-in-marginal_path-.patch -Patch0003: 0003-multipathd-cleanup-marginal-paths-checking-timers.patch -Patch0004: 0004-libmultipath-fix-marginal-paths-queueing-errors.patch -Patch0005: 0005-libmultipath-fix-marginal_paths-nr_active-check.patch -Patch0006: 0006-multipathd-Fix-miscounting-active-paths.patch -Patch0007: 0007-multipathd-ignore-failed-wwid-recheck.patch -Patch0008: 0008-libmutipath-continue-to-use-old-state-on-PATH_PENDIN.patch -Patch0009: 0009-multipathd-use-update_path_groups-instead-of-reload_.patch -Patch0010: 0010-multipath.conf-add-missing-options-to-man-page.patch -Patch0011: 0011-libmultipath-add-get_uid-fallback-code-for-NVMe-devi.patch -Patch0012: 0012-libmulitpath-cleanup-uid_fallback-code.patch -Patch0013: 0013-multipathd-handle-changed-wwids-by-removal-and-addit.patch -Patch0014: 0014-multipathd-remove-wwid_changed-path-attribute.patch -Patch0015: 0015-multipathd-ignore-disable_changed_wwids.patch -Patch0016: 0016-multipathd-Don-t-use-fallback-code-after-getting-wwi.patch -Patch0017: 0017-libmultipath-silence-dm_is_mpath-error-messages.patch -Patch0018: 0018-RH-fixup-udev-rules-for-redhat.patch -Patch0019: 0019-RH-Remove-the-property-blacklist-exception-builtin.patch -Patch0020: 0020-RH-don-t-start-without-a-config-file.patch -Patch0021: 0021-RH-use-rpm-optflags-if-present.patch -Patch0022: 0022-RH-add-mpathconf.patch -Patch0023: 0023-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch -Patch0024: 0024-RH-warn-on-invalid-regex-instead-of-failing.patch -Patch0025: 0025-RH-reset-default-find_mutipaths-value-to-off.patch -Patch0026: 0026-RH-Fix-nvme-compilation-warning.patch -Patch0027: 0027-Fix-systemd-version-detection.patch -Patch0028: 0028-RH-attempt-to-get-ANA-info-via-sysfs-first.patch +Patch0001: 0001-libmultipath-make-vector_foreach_slot_backwards-work.patch +Patch0002: 0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch +Patch0003: 0003-tests-add-path-grouping-policy-unit-tests.patch +Patch0004: 0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch +Patch0005: 0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch +Patch0006: 0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch +Patch0007: 0007-libmultipath-consolidate-group_by_-functions.patch +Patch0008: 0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch +Patch0009: 0009-libmultipath-make-group_paths-handle-marginal-paths.patch +Patch0010: 0010-tests-add-tests-for-grouping-marginal-paths.patch +Patch0011: 0011-libmultipath-add-marginal_pathgroups-config-option.patch +Patch0012: 0012-libmutipath-deprecate-delay_-_checks.patch +Patch0013: 0013-multipathd-use-marginal_pathgroups.patch +Patch0014: 0014-multipath-update-man-pages.patch +Patch0015: 0015-multipath.conf-add-enable_foreign-parameter.patch +Patch0016: 0016-multipath.conf.5-document-foreign-library-support.patch +Patch0017: 0017-mpathpersist-remove-broken-unused-code.patch +Patch0018: 0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch +Patch0019: 0019-mpathpersist-fix-leaks.patch +Patch0020: 0020-libmultipath-fix-mpcontext-initialization.patch +Patch0021: 0021-RH-fixup-udev-rules-for-redhat.patch +Patch0022: 0022-RH-Remove-the-property-blacklist-exception-builtin.patch +Patch0023: 0023-RH-don-t-start-without-a-config-file.patch +Patch0024: 0024-RH-use-rpm-optflags-if-present.patch +Patch0025: 0025-RH-add-mpathconf.patch +Patch0026: 0026-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch +Patch0027: 0027-RH-warn-on-invalid-regex-instead-of-failing.patch +Patch0028: 0028-RH-reset-default-find_mutipaths-value-to-off.patch +Patch0029: 0029-RH-Fix-nvme-compilation-warning.patch +Patch0030: 0030-RH-attempt-to-get-ANA-info-via-sysfs-first.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -120,7 +122,7 @@ This package contains the files needed to develop applications that use device-mapper-multipath's libdmmp C API library %prep -%autosetup -n multipath-tools-0.8.0 -p1 +%autosetup -n multipath-tools-0.8.2 -p1 cp %{SOURCE1} . %build @@ -232,6 +234,35 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Wed Sep 11 2019 Benjamin Marzinski - 0.8.2-1 +- Update Source to upstream version 0.8.2 + * Previoud patches 0001-0017 & 0027 are included in this commit +- Rename files + * Previous patches 0018-0026 & 0028 are not patches 0021-0030 +- Add 0001-libmultipath-make-vector_foreach_slot_backwards-work.patch +- Add 0002-libmultipath-add-marginal-paths-and-groups-infrastru.patch +- Add 0003-tests-add-path-grouping-policy-unit-tests.patch +- Add 0004-libmultipath-add-wrapper-function-around-pgpolicyfn.patch +- Add 0005-tests-update-pgpolicy-tests-to-work-with-group_paths.patch +- Add 0006-libmultipath-fix-double-free-in-pgpolicyfn-error-pat.patch +- Add 0007-libmultipath-consolidate-group_by_-functions.patch +- Add 0008-libmultipath-make-pgpolicyfn-take-a-paths-vector.patch +- Add 0009-libmultipath-make-group_paths-handle-marginal-paths.patch +- Add 0010-tests-add-tests-for-grouping-marginal-paths.patch +- Add 0011-libmultipath-add-marginal_pathgroups-config-option.patch +- Add 0012-libmutipath-deprecate-delay_-_checks.patch +- Add 0013-multipathd-use-marginal_pathgroups.patch +- Add 0014-multipath-update-man-pages.patch + * The above 13 patches add the marinal_pathgroups option +- Add 0015-multipath.conf-add-enable_foreign-parameter.patch +- Add 0016-multipath.conf.5-document-foreign-library-support.patch + * The above 2 patches add the enable_foreign option +- Add 0017-mpathpersist-remove-broken-unused-code.patch +- Add 0018-libmultipath-EMC-PowerMax-NVMe-device-config.patch +- Add 0019-mpathpersist-fix-leaks.patch +- Add 0020-libmultipath-fix-mpcontext-initialization.patch + * The above 20 patches have been submitted upstream + * Wed Jul 24 2019 Fedora Release Engineering - 0.8.0-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild diff --git a/sources b/sources index 3be9e67..1e3c506 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (multipath-tools-0.8.0.tgz) = e2ed6936f76da8b703babea22b6b02be19abea3ba55105a13596f306e483c453d105316c2416027be3524e49834ea27ff745963e86e933ffe4c9ee729a2371ba +SHA512 (multipath-tools-0.8.2.tgz) = 31cc4054a2f645fa40b7a16aa8715871b848167a32bf3f34e1c900714f61a46f5d79cbda373bda7f8a8fd2280b96e045c1fd27f4b87aa84fc5305097d72edcd6 SHA512 (multipath.conf) = 71953dce5a68adcf60a942305f5a66023e6f4c4baf53b1bfdb4edf65ed5b8e03db804363c36d1dcfd85591f4766f52b515269904c53b84d7b076da0b80b09942