From 3941311b98ecf4f1644de66ced2b17087e901be5 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 19 Feb 2026 19:24:19 -0500 Subject: [PATCH] device-mapper-multipath-0.8.7-45 Add 0208-libmpathpersist-fix-register-retry-status-checking.patch Add 0209-multipathd-remember-number-of-registered-keys-when-i.patch Add 0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch * Fixes RHEL-148462 ("Improve multipathd's handling of updating persistent reservations on restored paths. [rhel-9]") Resolves: RHEL-148462 --- ...t-fix-register-retry-status-checking.patch | 47 ++ ...ber-number-of-registered-keys-when-i.patch | 59 +++ ...fix-code-for-skipping-multipathd-pat.patch | 459 ++++++++++++++++++ device-mapper-multipath.spec | 13 +- 4 files changed, 577 insertions(+), 1 deletion(-) create mode 100644 0208-libmpathpersist-fix-register-retry-status-checking.patch create mode 100644 0209-multipathd-remember-number-of-registered-keys-when-i.patch create mode 100644 0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch diff --git a/0208-libmpathpersist-fix-register-retry-status-checking.patch b/0208-libmpathpersist-fix-register-retry-status-checking.patch new file mode 100644 index 0000000..2dceac3 --- /dev/null +++ b/0208-libmpathpersist-fix-register-retry-status-checking.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 1 Dec 2025 22:02:10 -0500 +Subject: [PATCH] libmpathpersist: fix register retry status checking + +If there libmpathpersist failed to create a thread to retry the register +and ignore command, mpath_prout_reg should fail. Instead, the code was +simply ignoring the failed threads. Fix that. + +Fixes: 2a4ca250 ("libmpathpersist: change how reservation conflicts are handled") +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 72be48c1..6cb56dab 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -858,18 +858,19 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope, + } + } + for (i = 0; i < count; i++) { +- if (thread[i].param.status != MPATH_PR_SKIP && +- thread[i].param.status != MPATH_PR_THREAD_ERROR) { ++ if (thread[i].param.status == MPATH_PR_SKIP) ++ continue; ++ if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { + rc = pthread_join(thread[i].id, NULL); + if (rc) { + condlog(3, "%s: failed to join thread while retrying %d", +- mpp->wwid, i); ++ mpp->wwid, i); + } +- if (thread[i].param.status == MPATH_PR_RETRYABLE_ERROR) +- retryable_error = true; +- else if (status == MPATH_PR_SUCCESS) +- status = thread[i].param.status; + } ++ if (thread[i].param.status == MPATH_PR_RETRYABLE_ERROR) ++ retryable_error = true; ++ else if (status == MPATH_PR_SUCCESS) ++ status = thread[i].param.status; + } + need_retry = false; + } diff --git a/0209-multipathd-remember-number-of-registered-keys-when-i.patch b/0209-multipathd-remember-number-of-registered-keys-when-i.patch new file mode 100644 index 0000000..6911cdb --- /dev/null +++ b/0209-multipathd-remember-number-of-registered-keys-when-i.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 1 Dec 2025 22:02:12 -0500 +Subject: [PATCH] multipathd: remember number of registered keys when ioctl + fails + +If prin_do_scsi_ioctl() fails in update_map_pr() for some reason other +than Persistent Reservations not being supported, It shouldn't clear the +number of registered keys, since there's no reason to think that it has +changed. Similarly, if update_map_pr() fails in mpath_pr_event_handle(), +don't assume that the nr_keys_needed was cleared. Just return whatever +the value is now. This saves multipathd from doing pointless calls to +update_map_pr(), if one of the paths is failing. + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + multipathd/main.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index d91a4d49..2526d8d1 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -3842,7 +3842,9 @@ void unset_pr(struct multipath *mpp) + * The number of found keys must be at least as large as *nr_keys, + * and if MPATH_PR_SUCCESS is returned and mpp->prflag is PR_SET after + * the call, *nr_keys will be set to the number of found keys. Otherwise +- * it will be set to 0. ++ * if mpp->prflag is PR_UNSET it will be set to 0. If MPATH_PR_SUCCESS ++ * is not returned and mpp->prflag is not PR_UNSET, nr_keys will not be ++ * changed. + */ + static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *nr_keys) + { +@@ -3871,11 +3873,12 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n + + ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, &resp, 0); + if (ret != MPATH_PR_SUCCESS) { +- if (ret == MPATH_PR_ILLEGAL_REQ) ++ if (ret == MPATH_PR_ILLEGAL_REQ) { + unset_pr(mpp); ++ *nr_keys = 0; ++ } + condlog(0, "%s : pr in read keys service action failed Error=%d", + mpp->alias, ret); +- *nr_keys = 0; + return ret; + } + +@@ -3990,7 +3993,7 @@ retry: + clear_reg ? "Clearing" : "Setting", pp->dev, ret); + } else if (!clear_reg) { + if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS) +- return 0; ++ return nr_keys_needed; + if (mpp->prflag != PR_SET) { + memset(¶m, 0, sizeof(param)); + clear_reg = true; diff --git a/0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch b/0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch new file mode 100644 index 0000000..90b99d5 --- /dev/null +++ b/0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch @@ -0,0 +1,459 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 15 Dec 2025 15:29:58 -0500 +Subject: [PATCH] libmpathpersist: fix code for skipping multipathd path + registration + +When libmpathpersist notifies multipathd that a key has been registered, +cli_setprstatus() calls pr_register_active_paths() with a flag to let it +know that the paths are likely already registered, and it can skip +re-registering them, as long as the number of active paths matches the +number of registered keys. This shortcut can fail, causing multipathd to +not register needed paths, if either a path becomes usable and another +becomes unusable while libmpathpersist is running or if there already +were registered keys for I_T Nexus's that don't correspond to path +devices. + +To make this shortcut work in cases like that, this commit adds a new +multipathd command "setprstatus map pathlist ", where + is a quoted, whitespace separated list of scsi path devices. +libmpathpersist will send out the list of paths it registered the key +on. pr_register_active_paths() will skip calling mpath_pr_event_handle() +for paths on that list. + +In order to deal with the possiblity of a preempt occuring while +libmpathpersist was running, the code still needs to check that it has +the expected number of keys. + +Fixes: f7d6cd17 ("multipathd: Fix race while registering PR key") +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmpathpersist/mpath_persist.c | 6 +-- + libmpathpersist/mpath_updatepr.c | 50 ++++++++++++++++++------- + libmpathpersist/mpathpr.h | 2 +- + multipathd/cli.c | 2 + + multipathd/cli.h | 2 + + multipathd/cli_handlers.c | 37 +++++++++++++++++-- + multipathd/cli_handlers.h | 1 + + multipathd/main.c | 63 +++++++++++++++++++++----------- + multipathd/main.h | 4 +- + multipathd/multipathd.8 | 10 ++++- + 10 files changed, 132 insertions(+), 45 deletions(-) + +diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c +index 6cb56dab..ab8fa630 100644 +--- a/libmpathpersist/mpath_persist.c ++++ b/libmpathpersist/mpath_persist.c +@@ -527,12 +527,12 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, + case MPATH_PROUT_REG_SA: + case MPATH_PROUT_REG_IGN_SA: + if (unregistering) +- update_prflag(alias, 0); ++ update_prflag(mpp, 0); + else +- update_prflag(alias, 1); ++ update_prflag(mpp, 1); + break; + case MPATH_PROUT_CLEAR_SA: +- update_prflag(alias, 0); ++ update_prflag(mpp, 0); + if (mpp->prkey_source == PRKEY_SOURCE_FILE) + update_prkey(alias, 0); + break; +diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c +index bfa6e089..e24432bb 100644 +--- a/libmpathpersist/mpath_updatepr.c ++++ b/libmpathpersist/mpath_updatepr.c +@@ -19,9 +19,9 @@ + #include "memory.h" + #include "mpathpr.h" + #include "structs.h" ++#include "strbuf.h" + +- +-static char *do_pr(char *alias, char *str) ++static char *do_pr(char *alias, const char *str) + { + int fd; + char *reply; +@@ -51,24 +51,26 @@ static char *do_pr(char *alias, char *str) + return reply; + } + +-static int do_update_pr(char *alias, char *cmd, char *key) ++static int do_update_pr(char *alias, char *cmd, const char *data) + { +- char str[256]; ++ STRBUF_ON_STACK(buf); + char *reply = NULL; + int ret = -1; + +- if (key) +- snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key); ++ if (data) ++ print_strbuf(&buf, "%s map %s %s %s", cmd, alias, ++ strcmp(cmd, "setprkey") ? "pathlist" : "key", data); + else +- snprintf(str,sizeof(str),"%s map %s", cmd, alias); ++ print_strbuf(&buf, "%s map %s", cmd, alias); + +- reply = do_pr(alias, str); ++ reply = do_pr(alias, get_strbuf_str(&buf)); + if (reply) { +- condlog (2, "%s: message=%s reply=%s", alias, str, reply); +- if (reply && strncmp(reply,"ok", 2) == 0) ++ if (strncmp(reply, "ok", 2) == 0) + ret = 0; + else + ret = -1; ++ condlog(ret ? 0 : 4, "%s: message=%s reply=%s", alias, ++ get_strbuf_str(&buf), reply); + } + + free(reply); +@@ -104,9 +106,31 @@ int get_prhold(char *mapname) { + return do_get_pr(mapname, "getprhold"); + } + +-int update_prflag(char *mapname, int set) { +- return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus", +- NULL); ++int update_prflag(struct multipath *mpp, int set) ++{ ++ STRBUF_ON_STACK(buf); ++ int i, j; ++ bool first = true; ++ struct pathgroup *pgp = NULL; ++ struct path *pp = NULL; ++ ++ if (!set) ++ return do_update_pr(mpp->alias, "unsetprstatus", NULL); ++ ++ append_strbuf_str(&buf, "\""); ++ vector_foreach_slot (mpp->pg, pgp, j) { ++ vector_foreach_slot (pgp->paths, pp, i) { ++ if (pp->state == PATH_UP || pp->state == PATH_GHOST) { ++ if (first) { ++ append_strbuf_str(&buf, pp->dev); ++ first = false; ++ } else ++ print_strbuf(&buf, " %s", pp->dev_t); ++ } ++ } ++ } ++ append_strbuf_str(&buf, "\""); ++ return do_update_pr(mpp->alias, "setprstatus", get_strbuf_str(&buf)); + } + + int update_prhold(char *mapname, bool set) { +diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h +index 69f402f2..67d04247 100644 +--- a/libmpathpersist/mpathpr.h ++++ b/libmpathpersist/mpathpr.h +@@ -40,7 +40,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope, + unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, + bool unregister); + +-int update_prflag(char *mapname, int set); ++int update_prflag(struct multipath *mpp, int set); + int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags); + int get_prflag(char *mapname); + int get_prhold(char *mapname); +diff --git a/multipathd/cli.c b/multipathd/cli.c +index d33b571d..9e833b02 100644 +--- a/multipathd/cli.c ++++ b/multipathd/cli.c +@@ -226,6 +226,7 @@ load_keys (void) + r += add_key(keys, "getprhold", GETPRHOLD, 0); + r += add_key(keys, "setprhold", SETPRHOLD, 0); + r += add_key(keys, "unsetprhold", UNSETPRHOLD, 0); ++ r += add_key(keys, "pathlist", PATHLIST, 1); + + if (r) { + free_keys(keys); +@@ -572,6 +573,7 @@ cli_init (void) { + add_handler(SHUTDOWN, NULL); + add_handler(GETPRSTATUS+MAP, NULL); + add_handler(SETPRSTATUS+MAP, NULL); ++ add_handler(SETPRSTATUS+MAP+PATHLIST, NULL); + add_handler(UNSETPRSTATUS+MAP, NULL); + add_handler(GETPRKEY+MAP, NULL); + add_handler(SETPRKEY+MAP+KEY, NULL); +diff --git a/multipathd/cli.h b/multipathd/cli.h +index 4d12f8fd..17344cb4 100644 +--- a/multipathd/cli.h ++++ b/multipathd/cli.h +@@ -50,6 +50,7 @@ enum { + __GETPRHOLD, + __SETPRHOLD, + __UNSETPRHOLD, ++ __PATHLIST, + }; + + #define LIST (1 << __LIST) +@@ -99,6 +100,7 @@ enum { + #define GETPRHOLD (1ULL << __GETPRHOLD) + #define SETPRHOLD (1ULL << __SETPRHOLD) + #define UNSETPRHOLD (1ULL << __UNSETPRHOLD) ++#define PATHLIST (1ULL << __PATHLIST) + + #define INITIAL_REPLY_LEN 1200 + +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 0c63ca9a..f183fceb 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -32,6 +32,7 @@ + #include "foreign.h" + #include "strbuf.h" + #include "cli_handlers.h" ++#include + + #define SET_REPLY_AND_LEN(__rep, __len, string_literal) \ + do { \ +@@ -1308,8 +1309,8 @@ cli_getprstatus (void * v, char ** reply, int * len, void * data) + return 0; + } + +-int +-cli_setprstatus(void * v, char ** reply, int * len, void * data) ++static int do_setprstatus(void * v, char ** reply, int * len, void * data, ++ const struct _vector *registered_paths) + { + struct multipath * mpp; + struct vectors * vecs = (struct vectors *)data; +@@ -1324,7 +1325,7 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data) + + if (mpp->prflag != PR_SET) { + set_pr(mpp); +- pr_register_active_paths(mpp, true); ++ pr_register_active_paths(mpp, registered_paths); + if (mpp->prflag == PR_SET) + condlog(2, "%s: prflag set", param); + else +@@ -1336,6 +1337,36 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data) + return 0; + } + ++int ++cli_setprstatus(void * v, char ** reply, int * len, void * data) ++{ ++ return do_setprstatus(v, reply, len, data, NULL); ++} ++ ++int ++cli_setprstatus_list(void * v, char ** reply, int * len, void *data) ++{ ++ int r; ++ struct _vector registered_paths_vec = {.allocated = 0}; ++ vector registered_paths ++ __attribute__((cleanup(cleanup_reset_vec))) = ®istered_paths_vec; ++ char *ptr = get_keyparam(v, PATHLIST); ++ ++ while (isspace(*ptr)) ++ ptr++; ++ while (*ptr) { ++ if (!vector_alloc_slot(registered_paths)) ++ return -ENOMEM; ++ vector_set_slot(registered_paths, ptr); ++ while (*ptr && !isspace(*ptr)) ++ ptr++; ++ while (isspace(*ptr)) ++ *ptr++ = '\0'; ++ } ++ r = do_setprstatus(v, reply, len, data, registered_paths); ++ return r; ++} ++ + int + cli_unsetprstatus(void * v, char ** reply, int * len, void * data) + { +diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h +index 348c8485..28b6f2bb 100644 +--- a/multipathd/cli_handlers.h ++++ b/multipathd/cli_handlers.h +@@ -46,6 +46,7 @@ int cli_shutdown(void * v, char ** reply, int * len, void * data); + int cli_reassign (void * v, char ** reply, int * len, void * data); + int cli_getprstatus(void * v, char ** reply, int * len, void * data); + int cli_setprstatus(void * v, char ** reply, int * len, void * data); ++int cli_setprstatus_list(void * v, char ** reply, int * len, void * data); + 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); +diff --git a/multipathd/main.c b/multipathd/main.c +index 2526d8d1..09d26fe2 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -548,28 +548,47 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) { + return true; + } + +-void pr_register_active_paths(struct multipath *mpp, bool check_nr_active) ++/* ++ * If reg_paths in non-NULL, it is a vector of paths that libmpathpersist ++ * registered. If the number of registered keys is smaller than the number ++ * of registered paths, then likely a preempt that occurred while ++ * libmpathpersist was registering the key. As long as there are still some ++ * registered keys, treat the preempt as happening first, and make sure to ++ * register keys on all the paths. If the number of registered keys is at ++ * least as large as the number of registered paths, then no preempt happened, ++ * and multipathd does not need to re-register the paths that libmpathpersist ++ * handled ++ */ ++void pr_register_active_paths(struct multipath *mpp, const struct _vector *reg_paths) + { +- unsigned int i, j, nr_keys = 0; +- unsigned int nr_active = 0; ++ unsigned int i, j, k, nr_keys = 0; ++ unsigned int wanted_nr = VECTOR_SIZE(reg_paths); + struct path *pp; + struct pathgroup *pgp; +- +- if (check_nr_active) { +- nr_active = count_active_paths(mpp); +- if (!nr_active) +- return; +- } ++ char *pathname; + + vector_foreach_slot (mpp->pg, pgp, i) { + vector_foreach_slot (pgp->paths, pp, j) { + if (mpp->prflag == PR_UNSET) + return; +- if (pp->state == PATH_UP || pp->state == PATH_GHOST) { +- nr_keys = mpath_pr_event_handle(pp, nr_keys, nr_active); +- if (check_nr_active && nr_keys == nr_active) +- return; ++ if (pp->state != PATH_UP && pp->state != PATH_GHOST) ++ continue; ++ if (wanted_nr && nr_keys) { ++ vector_foreach_slot (reg_paths, pathname, k) { ++ if (strcmp(pp->dev_t, pathname) == 0) { ++ goto skip; ++ } ++ } + } ++ nr_keys = mpath_pr_event_handle(pp, nr_keys, wanted_nr); ++ if (nr_keys && nr_keys < wanted_nr) { ++ /* ++ * Incorrect number of registered keys. Need ++ * to register all devices ++ */ ++ wanted_nr = 0; ++ } ++ skip:; /* a statement must follow a label on pre C23 clang */ + } + } + } +@@ -599,8 +618,7 @@ handle_orphaned_offline_paths(vector offline_paths) + pp->add_when_online = true; + } + +-static void +-cleanup_reset_vec(struct _vector **v) ++void cleanup_reset_vec(struct _vector **v) + { + vector_reset(*v); + } +@@ -656,7 +674,7 @@ fail: + + sync_map_state(mpp); + +- pr_register_active_paths(mpp, false); ++ pr_register_active_paths(mpp, NULL); + + if (VECTOR_SIZE(offline_paths) != 0) + handle_orphaned_offline_paths(offline_paths); +@@ -1279,7 +1297,7 @@ rescan: + + if (retries >= 0) { + if ((mpp->prflag == PR_SET && prflag != PR_SET) || start_waiter) +- pr_register_active_paths(mpp, false); ++ pr_register_active_paths(mpp, NULL); + condlog(2, "%s [%s]: path added to devmap %s", + pp->dev, pp->dev_t, mpp->alias); + return 0; +@@ -1875,6 +1893,7 @@ uxlsnrloop (void * ap) + set_unlocked_handler_callback(SHUTDOWN, cli_shutdown); + set_handler_callback(GETPRSTATUS|MAP, cli_getprstatus); + set_handler_callback(SETPRSTATUS|MAP, cli_setprstatus); ++ set_handler_callback(SETPRSTATUS|MAP|PATHLIST, cli_setprstatus_list); + set_handler_callback(UNSETPRSTATUS|MAP, cli_unsetprstatus); + set_handler_callback(FORCEQ|DAEMON, cli_force_no_daemon_q); + set_handler_callback(RESTOREQ|DAEMON, cli_restore_no_daemon_q); +@@ -2581,7 +2600,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) + mpath_pr_event_handle(pp, 0, 0); + if (pp->mpp->prflag == PR_SET && + prflag != PR_SET) +- pr_register_active_paths(pp->mpp, false); ++ pr_register_active_paths(pp->mpp, NULL); + } + } + +@@ -2950,7 +2969,7 @@ configure (struct vectors * vecs) + vector_foreach_slot(mpvec, mpp, i){ + if (remember_wwid(mpp->wwid) == 1) + trigger_paths_udev_change(mpp, true); +- pr_register_active_paths(mpp, false); ++ pr_register_active_paths(mpp, NULL); + } + + /* +@@ -3933,8 +3952,8 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n + * + * nr_keys_wanted: Only used if nr_keys_needed is 0, so we don't know how + * many keys we currently have. If nr_keys_wanted in non-zero and the +- * number of keys found by the initial call to update_map_pr() matches it, +- * exit early, since we have all the keys we are expecting. ++ * number of keys found by the initial call to update_map_pr() is at least ++ * as large as it, exit early, since we have all the keys we are expecting. + * + * The function returns the number of keys that are registered or 0 if + * it's unknown. +@@ -3957,7 +3976,7 @@ mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed, + nr_keys_needed = 1; + if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS) + return 0; +- if (nr_keys_wanted && nr_keys_wanted == nr_keys_needed) ++ if (nr_keys_wanted && nr_keys_wanted <= nr_keys_needed) + return nr_keys_needed; + } + +diff --git a/multipathd/main.h b/multipathd/main.h +index 8a4c5f88..ea12455f 100644 +--- a/multipathd/main.h ++++ b/multipathd/main.h +@@ -60,5 +60,7 @@ int resize_map(struct multipath *mpp, unsigned long long size, + struct vectors *vecs); + void set_pr(struct multipath *mpp); + void unset_pr(struct multipath *mpp); +-void pr_register_active_paths(struct multipath *mpp, bool check_active_nr); ++void pr_register_active_paths(struct multipath *mpp, ++ const struct _vector *registered_paths); ++void cleanup_reset_vec(struct _vector **v); + #endif /* MAIN_H */ +diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8 +index 2ed036d4..0a76f3e3 100644 +--- a/multipathd/multipathd.8 ++++ b/multipathd/multipathd.8 +@@ -324,11 +324,17 @@ will not be disabled when the daemon stops. + Restores configured queue_without_daemon mode. + . + .TP +-.B map|multipath $map setprstatus ++.B setprstatus map|multipath $map + Enable persistent reservation management on $map. + . + .TP +-.B map|multipath $map unsetprstatus ++.B setprstatus map|multipath $map pathlist $pathlist ++Enable persistent reservation management on $map, and notify multipathd of ++the paths that have been registered, so it doesn't attempt to re-register ++them. ++. ++.TP ++.B unsetprstatus map|multipath $map + Disable persistent reservation management on $map. + . + .TP diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index a39209e..53810a0 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,6 +1,6 @@ Name: device-mapper-multipath Version: 0.8.7 -Release: 44%{?dist} +Release: 45%{?dist} Summary: Tools to manage multipath devices using device-mapper License: GPLv2 URL: http://christophe.varoqui.free.fr/ @@ -217,6 +217,9 @@ Patch0204: 0204-libmultipath-is_uevent_busy-check-servicing_uev-unde.patch Patch0205: 0205-multipathd-make-multipathd-show-status-busy-checker-.patch Patch0206: 0206-libmultipath-add-purge_disconnected-configuration-op.patch Patch0207: 0207-multipathd-implement-purge-functionality-for-disconn.patch +Patch0208: 0208-libmpathpersist-fix-register-retry-status-checking.patch +Patch0209: 0209-multipathd-remember-number-of-registered-keys-when-i.patch +Patch0210: 0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -419,6 +422,14 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Thu Feb 19 2026 Benjamin Marzinski - 0.8.7-45 +- Add 0208-libmpathpersist-fix-register-retry-status-checking.patch +- Add 0209-multipathd-remember-number-of-registered-keys-when-i.patch +- Add 0210-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch + * Fixes RHEL-148462 ("Improve multipathd's handling of updating + persistent reservations on restored paths. [rhel-9]") +- Resolves: RHEL-148462 + * Thu Jan 29 2026 Benjamin Marzinski - 0.8.7-44 - Add 0206-libmultipath-add-purge_disconnected-configuration-op.patch - Add 0207-multipathd-implement-purge-functionality-for-disconn.patch