From 5c36cc0ea25b648257cba68f4a6ccd3e54855fbe Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 19 Feb 2026 19:03:23 -0500 Subject: [PATCH] device-mapper-multipath-0.9.9-18 Add 0085-libmpathpersist-fix-register-retry-status-checking.patch Add 0086-multipathd-remember-number-of-registered-keys-when-i.patch Add 0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch * Fixes RHEL-129442 ("Improve multipathd's handling of updating persistent reservations on restored paths.") Resolves: RHEL-129442 --- ...t-fix-register-retry-status-checking.patch | 47 ++ ...ber-number-of-registered-keys-when-i.patch | 59 +++ ...fix-code-for-skipping-multipathd-pat.patch | 461 ++++++++++++++++++ device-mapper-multipath.spec | 13 +- 4 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 0085-libmpathpersist-fix-register-retry-status-checking.patch create mode 100644 0086-multipathd-remember-number-of-registered-keys-when-i.patch create mode 100644 0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch diff --git a/0085-libmpathpersist-fix-register-retry-status-checking.patch b/0085-libmpathpersist-fix-register-retry-status-checking.patch new file mode 100644 index 0000000..bf82fcb --- /dev/null +++ b/0085-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_int.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c +index 00334a1a..3f331294 100644 +--- a/libmpathpersist/mpath_persist_int.c ++++ b/libmpathpersist/mpath_persist_int.c +@@ -542,19 +542,19 @@ static 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); + } +- 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/0086-multipathd-remember-number-of-registered-keys-when-i.patch b/0086-multipathd-remember-number-of-registered-keys-when-i.patch new file mode 100644 index 0000000..60cdf1d --- /dev/null +++ b/0086-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 7cb57e3c..46600527 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -4059,7 +4059,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) + { +@@ -4088,11 +4090,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; + } + +@@ -4208,7 +4211,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/0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch b/0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch new file mode 100644 index 0000000..437f702 --- /dev/null +++ b/0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch @@ -0,0 +1,461 @@ +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 +--- + .github/actions/spelling/expect.txt | 1 + + libmpathpersist/mpath_persist_int.c | 6 +-- + libmpathpersist/mpath_updatepr.c | 49 +++++++++++++++++------ + libmpathpersist/mpathpr.h | 4 +- + multipathd/callbacks.c | 2 + + multipathd/cli.c | 1 + + multipathd/cli.h | 2 + + multipathd/cli_handlers.c | 35 ++++++++++++++-- + multipathd/main.c | 62 +++++++++++++++++++---------- + multipathd/main.h | 4 +- + multipathd/multipathd.8.in | 10 ++++- + 11 files changed, 132 insertions(+), 44 deletions(-) + +diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt +index e2d4acf9..9bb8f8dd 100644 +--- a/.github/actions/spelling/expect.txt ++++ b/.github/actions/spelling/expect.txt +@@ -143,6 +143,7 @@ OPTFLAGS + paramp + partx + pathgroup ++pathlist + petabytes + pgpolicy + plugindir +diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c +index 3f331294..b2c3e27a 100644 +--- a/libmpathpersist/mpath_persist_int.c ++++ b/libmpathpersist/mpath_persist_int.c +@@ -1018,12 +1018,12 @@ 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 dd8dd48e..f943b1bf 100644 +--- a/libmpathpersist/mpath_updatepr.c ++++ b/libmpathpersist/mpath_updatepr.c +@@ -20,8 +20,9 @@ + #include "uxsock.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 +52,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); +@@ -106,9 +109,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 b668ef58..baee9a59 100644 +--- a/libmpathpersist/mpathpr.h ++++ b/libmpathpersist/mpathpr.h +@@ -1,12 +1,14 @@ + #ifndef MPATHPR_H + #define MPATHPR_H + ++#include "structs.h" ++ + /* + * This header file contains symbols that are only used by + * libmpathpersist internally. + */ + +-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/callbacks.c b/multipathd/callbacks.c +index b6b57f45..2027c3a6 100644 +--- a/multipathd/callbacks.c ++++ b/multipathd/callbacks.c +@@ -59,6 +59,8 @@ void init_handler_callbacks(void) + set_unlocked_handler_callback(VRB_SHUTDOWN, HANDLER(cli_shutdown)); + set_handler_callback(VRB_GETPRSTATUS | Q1_MAP, HANDLER(cli_getprstatus)); + set_handler_callback(VRB_SETPRSTATUS | Q1_MAP, HANDLER(cli_setprstatus)); ++ set_handler_callback(VRB_SETPRSTATUS | Q1_MAP | Q2_PATHLIST, ++ HANDLER(cli_setprstatus_list)); + set_handler_callback(VRB_UNSETPRSTATUS | Q1_MAP, HANDLER(cli_unsetprstatus)); + set_handler_callback(VRB_FORCEQ | Q1_DAEMON, HANDLER(cli_force_no_daemon_q)); + set_handler_callback(VRB_RESTOREQ | Q1_DAEMON, HANDLER(cli_restore_no_daemon_q)); +diff --git a/multipathd/cli.c b/multipathd/cli.c +index bccdda48..4ff229a5 100644 +--- a/multipathd/cli.c ++++ b/multipathd/cli.c +@@ -227,6 +227,7 @@ load_keys (void) + r += add_key(keys, "getprhold", VRB_GETPRHOLD, 0); + r += add_key(keys, "setprhold", VRB_SETPRHOLD, 0); + r += add_key(keys, "unsetprhold", VRB_UNSETPRHOLD, 0); ++ r += add_key(keys, "pathlist", KEY_PATHLIST, 1); + + if (r) { + free_keys(keys); +diff --git a/multipathd/cli.h b/multipathd/cli.h +index 925575ad..70a2d3f0 100644 +--- a/multipathd/cli.h ++++ b/multipathd/cli.h +@@ -62,6 +62,7 @@ enum { + KEY_LOCAL = 81, + KEY_GROUP = 82, + KEY_KEY = 83, ++ KEY_PATHLIST = 84, + }; + + /* +@@ -94,6 +95,7 @@ enum { + Q2_LOCAL = KEY_LOCAL << 16, + Q2_GROUP = KEY_GROUP << 16, + Q2_KEY = KEY_KEY << 16, ++ Q2_PATHLIST = KEY_PATHLIST << 16, + + /* byte 3: qualifier 3 */ + Q3_FMT = KEY_FMT << 24, +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 1677dd1e..854f6192 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -32,6 +32,7 @@ + #include "strbuf.h" + #include "cli_handlers.h" + #include "devmapper.h" ++#include + + static struct path * + find_path_by_str(const struct _vector *pathvec, const char *str, +@@ -1266,8 +1267,8 @@ cli_getprstatus (void * v, struct strbuf *reply, void * data) + return 0; + } + +-static int +-cli_setprstatus(void * v, struct strbuf *reply, void * data) ++static int do_setprstatus(void *v, struct strbuf *reply, void *data, ++ const struct _vector *registered_paths) + { + struct multipath * mpp; + struct vectors * vecs = (struct vectors *)data; +@@ -1281,7 +1282,7 @@ cli_setprstatus(void * v, struct strbuf *reply, 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 +@@ -1292,6 +1293,34 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data) + return 0; + } + ++static int cli_setprstatus(void *v, struct strbuf *reply, void *data) ++{ ++ return do_setprstatus(v, reply, data, NULL); ++} ++ ++static int cli_setprstatus_list(void *v, struct strbuf *reply, 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, KEY_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, data, registered_paths); ++ return r; ++} ++ + static int + cli_unsetprstatus(void * v, struct strbuf *reply, void * data) + { +diff --git a/multipathd/main.c b/multipathd/main.c +index 46600527..bdb04a1f 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -637,28 +637,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 */ + } + } + } +@@ -688,8 +707,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); + } +@@ -745,7 +763,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); +@@ -1393,7 +1411,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; +@@ -2688,7 +2706,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); + } + } + +@@ -3091,7 +3109,7 @@ configure (struct vectors * vecs, enum force_reload_types reload_type) + 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); + } + + /* +@@ -4151,8 +4169,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. +@@ -4175,7 +4193,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 25ddbaa7..0742ca2e 100644 +--- a/multipathd/main.h ++++ b/multipathd/main.h +@@ -54,5 +54,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.in b/multipathd/multipathd.8.in +index 342e363e..2420d698 100644 +--- a/multipathd/multipathd.8.in ++++ b/multipathd/multipathd.8.in +@@ -346,11 +346,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 388441d..08b76ac 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,6 +1,6 @@ Name: device-mapper-multipath Version: 0.9.9 -Release: 17%{?dist} +Release: 18%{?dist} Summary: Tools to manage multipath devices using device-mapper License: GPLv2 URL: http://christophe.varoqui.free.fr/ @@ -94,6 +94,9 @@ Patch0081: 0081-multipathd-make-multipathd-show-status-busy-checker-.patch Patch0082: 0082-multipathd-print-path-offline-message-even-without-a.patch Patch0083: 0083-libmultipath-add-purge_disconnected-configuration-op.patch Patch0084: 0084-multipathd-implement-purge-functionality-for-disconn.patch +Patch0085: 0085-libmpathpersist-fix-register-retry-status-checking.patch +Patch0086: 0086-multipathd-remember-number-of-registered-keys-when-i.patch +Patch0087: 0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -303,6 +306,14 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Thu Feb 19 2026 Benjamin Marzinski - 0.9.9-18 +- Add 0085-libmpathpersist-fix-register-retry-status-checking.patch +- Add 0086-multipathd-remember-number-of-registered-keys-when-i.patch +- Add 0087-libmpathpersist-fix-code-for-skipping-multipathd-pat.patch + * Fixes RHEL-129442 ("Improve multipathd's handling of updating + persistent reservations on restored paths.") +- Resolves: RHEL-129442 + * Thu Jan 29 2026 Benjamin Marzinski - 0.9.9-17 - Add 0083-libmultipath-add-purge_disconnected-configuration-op.patch - Add 0084-multipathd-implement-purge-functionality-for-disconn.patch