* [PATCH 0/4] multipath-tools: Yet Another PR fix
@ 2025-12-02 3:02 Benjamin Marzinski
2025-12-02 3:02 ` [PATCH 1/4] libmpathpersist: fix register retry status checking Benjamin Marzinski
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Benjamin Marzinski @ 2025-12-02 3:02 UTC (permalink / raw)
To: Christophe Varoqui; +Cc: device-mapper development, Martin Wilck
I ran into some cases where checking the number of registered keys made
multipathd think all paths had been registered, when they hadn't. The
last two patches in this patchset rework that code. The first two are
just fixes to other issues I happened to notice while working on this
code.
Benjamin Marzinski (4):
libmpathpersist: fix register retry status checking
multipath-tools man pages: fix multipathd commands keyword ordering
multipathd: remember number of registered keys when ioctl fails
libmpathpersist: fix code for skipping multipathd path registration
libmpathpersist/mpath_persist_int.c | 20 ++++----
libmpathpersist/mpath_updatepr.c | 48 ++++++++++++++-----
libmpathpersist/mpathpr.h | 4 +-
multipathd/callbacks.c | 1 +
multipathd/cli.c | 1 +
multipathd/cli.h | 2 +
multipathd/cli_handlers.c | 39 ++++++++++++++--
multipathd/main.c | 72 +++++++++++++++++++----------
multipathd/main.h | 3 +-
multipathd/multipathd.8.in | 24 ++++++----
10 files changed, 155 insertions(+), 59 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 1/4] libmpathpersist: fix register retry status checking 2025-12-02 3:02 [PATCH 0/4] multipath-tools: Yet Another PR fix Benjamin Marzinski @ 2025-12-02 3:02 ` Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 2/4] multipath-tools man pages: fix multipathd commands keyword ordering Benjamin Marzinski ` (3 subsequent siblings) 4 siblings, 0 replies; 10+ messages in thread From: Benjamin Marzinski @ 2025-12-02 3:02 UTC (permalink / raw) To: Christophe Varoqui; +Cc: device-mapper development, Martin Wilck 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 <bmarzins@redhat.com> --- 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 ea8d65ea..91c53419 100644 --- a/libmpathpersist/mpath_persist_int.c +++ b/libmpathpersist/mpath_persist_int.c @@ -536,19 +536,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; } -- 2.50.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/4] multipath-tools man pages: fix multipathd commands keyword ordering 2025-12-02 3:02 [PATCH 0/4] multipath-tools: Yet Another PR fix Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 1/4] libmpathpersist: fix register retry status checking Benjamin Marzinski @ 2025-12-02 3:02 ` Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 3/4] multipathd: remember number of registered keys when ioctl fails Benjamin Marzinski ` (2 subsequent siblings) 4 siblings, 0 replies; 10+ messages in thread From: Benjamin Marzinski @ 2025-12-02 3:02 UTC (permalink / raw) To: Christophe Varoqui; +Cc: device-mapper development, Martin Wilck multipathd now has a fixed ordering of the keywords. Specifically, verbs must come first. Fix the man page to reflect the ordering. Fixes: f812466f6 ("multipathd: more robust command parsing") Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> --- multipathd/multipathd.8.in | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in index 8815e099..7ffb8d4c 100644 --- a/multipathd/multipathd.8.in +++ b/multipathd/multipathd.8.in @@ -344,48 +344,48 @@ 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 unsetprstatus map|multipath $map Disable persistent reservation management on $map. . .TP -.B map|multipath $map getprstatus +.B getprstatus map|multipath $map Get the current persistent reservation management status of $map. . .TP -.B map|multipath $map getprkey +.B getprkey map|multipath $map Get the current persistent reservation key associated with $map. . .TP -.B map|multipath $map setprkey key $key +.B setprkey map|multipath $map key $key Set the persistent reservation key associated with $map to $key in the \fIprkeys_file\fR. This key will only be used by multipathd if \fIreservation_key\fR is set to \fBfile\fR in \fI@CONFIGFILE@\fR. . .TP -.B map|multipath $map unsetprkey +.B unsetprkey map|multipath $map Remove the persistent reservation key associated with $map from the \fIprkeys_file\fR. This will only unset the key used by multipathd if \fIreservation_key\fR is set to \fBfile\fR in \fI@CONFIGFILE@\fR. . .TP -.B path $path setmarginal +.B setmarginal path $path 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 +.B unsetmarginal path $path 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 +.B unsetmarginal map $map 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). -- 2.50.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] multipathd: remember number of registered keys when ioctl fails 2025-12-02 3:02 [PATCH 0/4] multipath-tools: Yet Another PR fix Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 1/4] libmpathpersist: fix register retry status checking Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 2/4] multipath-tools man pages: fix multipathd commands keyword ordering Benjamin Marzinski @ 2025-12-02 3:02 ` Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration Benjamin Marzinski 2025-12-08 14:48 ` [PATCH 0/4] multipath-tools: Yet Another PR fix Martin Wilck 4 siblings, 0 replies; 10+ messages in thread From: Benjamin Marzinski @ 2025-12-02 3:02 UTC (permalink / raw) To: Christophe Varoqui; +Cc: device-mapper development, Martin Wilck 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 <bmarzins@redhat.com> --- multipathd/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/multipathd/main.c b/multipathd/main.c index 4c86f31e..a7650639 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -4278,7 +4278,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) { @@ -4307,11 +4309,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; } @@ -4427,7 +4430,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; -- 2.50.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration 2025-12-02 3:02 [PATCH 0/4] multipath-tools: Yet Another PR fix Benjamin Marzinski ` (2 preceding siblings ...) 2025-12-02 3:02 ` [PATCH 3/4] multipathd: remember number of registered keys when ioctl fails Benjamin Marzinski @ 2025-12-02 3:02 ` Benjamin Marzinski 2025-12-08 14:46 ` Martin Wilck 2025-12-08 14:55 ` Martin Wilck 2025-12-08 14:48 ` [PATCH 0/4] multipath-tools: Yet Another PR fix Martin Wilck 4 siblings, 2 replies; 10+ messages in thread From: Benjamin Marzinski @ 2025-12-02 3:02 UTC (permalink / raw) To: Christophe Varoqui; +Cc: device-mapper development, Martin Wilck 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 <map> pathlist <pathlist>", where <pathlist> is a quoted, comma 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 <bmarzins@redhat.com> --- libmpathpersist/mpath_persist_int.c | 6 +-- libmpathpersist/mpath_updatepr.c | 48 +++++++++++++++++------ libmpathpersist/mpathpr.h | 4 +- multipathd/callbacks.c | 1 + multipathd/cli.c | 1 + multipathd/cli.h | 2 + multipathd/cli_handlers.c | 39 ++++++++++++++++-- multipathd/main.c | 61 +++++++++++++++++++---------- multipathd/main.h | 3 +- multipathd/multipathd.8.in | 6 +++ 10 files changed, 132 insertions(+), 39 deletions(-) diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c index 91c53419..14f7ba83 100644 --- a/libmpathpersist/mpath_persist_int.c +++ b/libmpathpersist/mpath_persist_int.c @@ -1001,12 +1001,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(mpp->alias, 0); + update_prflag(mpp, 0); else - update_prflag(mpp->alias, 1); + update_prflag(mpp, 1); break; case MPATH_PROUT_CLEAR_SA: - update_prflag(mpp->alias, 0); + update_prflag(mpp, 0); if (mpp->prkey_source == PRKEY_SOURCE_FILE) update_prkey(mpp->alias, 0); break; diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c index bd8ed2be..bc9c79e2 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,27 @@ 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) { if (strncmp(reply, "ok", 2) == 0) ret = 0; else ret = -1; - condlog(ret ? 0 : 4, "%s: message=%s reply=%s", alias, str, reply); + condlog(ret ? 0 : 4, "%s: message=%s reply=%s", alias, + get_strbuf_str(&buf), reply); } free(reply); @@ -106,9 +110,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); + } + } + } + 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 99d6b82f..adbfc865 100644 --- a/libmpathpersist/mpathpr.h +++ b/libmpathpersist/mpathpr.h @@ -1,12 +1,14 @@ #ifndef MPATHPR_H_INCLUDED #define MPATHPR_H_INCLUDED +#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..1129855b 100644 --- a/multipathd/callbacks.c +++ b/multipathd/callbacks.c @@ -59,6 +59,7 @@ 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 d0e6cebc..0d679c86 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 5a943a45..3e607389 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 2812d01e..5770dcec 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -31,6 +31,7 @@ #include "foreign.h" #include "strbuf.h" #include "cli_handlers.h" +#include <ctype.h> static struct path * find_path_by_str(const struct vector_s *pathvec, const char *str, @@ -1276,8 +1277,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_s *registered_paths) { struct multipath * mpp; struct vectors * vecs = (struct vectors *)data; @@ -1291,7 +1292,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 @@ -1302,6 +1303,38 @@ 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_s registered_paths = { .allocated = 0 }; + char *ptr = get_keyparam(v, KEY_PATHLIST); + + while (isspace(*ptr)) + ptr++; + while (*ptr) { + if (!vector_alloc_slot(®istered_paths)) { + r = -ENOMEM; + goto out; + } + vector_set_slot(®istered_paths, ptr); + while (*ptr && !isspace(*ptr)) + ptr++; + while (isspace(*ptr)) + *ptr++ = '\0'; + } + r = do_setprstatus(v, reply, data, ®istered_paths); +out: + vector_reset(®istered_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 a7650639..2cd5c952 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -630,28 +630,49 @@ 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_s *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, pathname) == 0 || + 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: } } } @@ -739,7 +760,7 @@ fail: sync_map_state(mpp, false); - pr_register_active_paths(mpp, false); + pr_register_active_paths(mpp, NULL); if (VECTOR_SIZE(offline_paths) != 0) handle_orphaned_offline_paths(offline_paths); @@ -1413,7 +1434,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; @@ -2658,7 +2679,7 @@ update_path_state (struct vectors * vecs, struct path * pp) "reservation registration", pp->dev); 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); } /* @@ -3319,7 +3340,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); } /* @@ -4370,8 +4391,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. @@ -4394,7 +4415,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 6d60ee81..85b533cd 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -54,5 +54,6 @@ 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_s *registered_paths); #endif /* MAIN_H_INCLUDED */ diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in index 7ffb8d4c..38a243e3 100644 --- a/multipathd/multipathd.8.in +++ b/multipathd/multipathd.8.in @@ -348,6 +348,12 @@ Restores configured queue_without_daemon mode. Enable persistent reservation management on $map. . .TP +.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. . -- 2.50.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration 2025-12-02 3:02 ` [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration Benjamin Marzinski @ 2025-12-08 14:46 ` Martin Wilck 2025-12-08 20:50 ` Benjamin Marzinski 2025-12-08 14:55 ` Martin Wilck 1 sibling, 1 reply; 10+ messages in thread From: Martin Wilck @ 2025-12-08 14:46 UTC (permalink / raw) To: Benjamin Marzinski, Christophe Varoqui; +Cc: device-mapper development On Mon, 2025-12-01 at 22:02 -0500, Benjamin Marzinski wrote: > 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 <map> pathlist <pathlist>", where > <pathlist> is a quoted, comma 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 <bmarzins@redhat.com> > --- > libmpathpersist/mpath_persist_int.c | 6 +-- > libmpathpersist/mpath_updatepr.c | 48 +++++++++++++++++------ > libmpathpersist/mpathpr.h | 4 +- > multipathd/callbacks.c | 1 + > multipathd/cli.c | 1 + > multipathd/cli.h | 2 + > multipathd/cli_handlers.c | 39 ++++++++++++++++-- > multipathd/main.c | 61 +++++++++++++++++++-------- > -- > multipathd/main.h | 3 +- > multipathd/multipathd.8.in | 6 +++ > 10 files changed, 132 insertions(+), 39 deletions(-) I may be missing something, but this is quite a lot of additional complexity just for the shortcut. Have you considered just not taking the shortcut in the first place? Martin ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration 2025-12-08 14:46 ` Martin Wilck @ 2025-12-08 20:50 ` Benjamin Marzinski 2025-12-09 11:09 ` Martin Wilck 0 siblings, 1 reply; 10+ messages in thread From: Benjamin Marzinski @ 2025-12-08 20:50 UTC (permalink / raw) To: Martin Wilck; +Cc: Christophe Varoqui, device-mapper development On Mon, Dec 08, 2025 at 03:46:56PM +0100, Martin Wilck wrote: > On Mon, 2025-12-01 at 22:02 -0500, Benjamin Marzinski wrote: > > 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 <map> pathlist <pathlist>", where > > <pathlist> is a quoted, comma 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 <bmarzins@redhat.com> > > --- > > libmpathpersist/mpath_persist_int.c | 6 +-- > > libmpathpersist/mpath_updatepr.c | 48 +++++++++++++++++------ > > libmpathpersist/mpathpr.h | 4 +- > > multipathd/callbacks.c | 1 + > > multipathd/cli.c | 1 + > > multipathd/cli.h | 2 + > > multipathd/cli_handlers.c | 39 ++++++++++++++++-- > > multipathd/main.c | 61 +++++++++++++++++++-------- > > -- > > multipathd/main.h | 3 +- > > multipathd/multipathd.8.in | 6 +++ > > 10 files changed, 132 insertions(+), 39 deletions(-) > > I may be missing something, but this is quite a lot of additional > complexity just for the shortcut. Have you considered just not taking > the shortcut in the first place? Yep. But that means that whenever you register a multipath device with mpathpersist, multipathd will (almost always pointlessly) re-register all the paths, just to make sure it doesn't hit these super rare corner cases. So this added complexity keeps multipathd from running unnecesary scsi PR commands, and should be quicker. All multipathd does is break the new cli message up into pathnames, and then has pr_register_active_paths() check the paths against the pathanames, and skip them if they match and the number of keys is as big as expected (and it needs to check the number of keys regardless of whether it uses the shortcut). I thought briefly about pulling all the path registration work into multipathd, but it ends up making multipathd even more complex than this shortcut, while not saving much complexity from libmpathpersist. If we wanted to make multipathd handle all of libmpathpersists work, that would be a different story, but I'm still not sold on the idea of doing that. That being said, we can drop a chunk of code if we just force multipathd to automatically reregister the paths. So if you think that the reduced work is not worth the added complexity, I'm o.k. with pulling the shortcut out completely. -Ben > Martin ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration 2025-12-08 20:50 ` Benjamin Marzinski @ 2025-12-09 11:09 ` Martin Wilck 0 siblings, 0 replies; 10+ messages in thread From: Martin Wilck @ 2025-12-09 11:09 UTC (permalink / raw) To: Benjamin Marzinski; +Cc: Christophe Varoqui, device-mapper development On Mon, 2025-12-08 at 15:50 -0500, Benjamin Marzinski wrote: > On Mon, Dec 08, 2025 at 03:46:56PM +0100, Martin Wilck wrote: > > > > I may be missing something, but this is quite a lot of additional > > complexity just for the shortcut. Have you considered just not > > taking > > the shortcut in the first place? > > Yep. But that means that whenever you register a multipath device > with > mpathpersist, multipathd will (almost always pointlessly) re-register > all the paths, just to make sure it doesn't hit these super rare > corner > cases. So this added complexity keeps multipathd from running > unnecesary > scsi PR commands, and should be quicker. All multipathd does is break > the new cli message up into pathnames, and then has > pr_register_active_paths() check the paths against the pathanames, > and > skip them if they match and the number of keys is as big as expected > (and it needs to check the number of keys regardless of whether it > uses > the shortcut). > > I thought briefly about pulling all the path registration work into > multipathd, but it ends up making multipathd even more complex than > this > shortcut, while not saving much complexity from libmpathpersist. If > we > wanted to make multipathd handle all of libmpathpersists work, that > would be a different story, but I'm still not sold on the idea of > doing > that. > > That being said, we can drop a chunk of code if we just force > multipathd to automatically reregister the paths. So if you think > that > the reduced work is not worth the added complexity, I'm o.k. with > pulling the shortcut out completely. I admit I am somewhat intimidated by the complexity into which the PR code has grown. Therefore I would be glad to avoid extra complexity if possible. But for that very reason, I don't feel competent to judge whether this complexity is "worth" it, IOW how badly performance would be affected by the extra register commands, in particular during high IO load. I suppose it's not so much a matter of "performance", rather of latency between running mpathpersist and the completion of the task in multipathd, which might be critical in certain situations. This is why I wrote "have you considered". If you, from the vast exprience that you gained in the course of your recent work, think that this extra complexity is worth it, fine with me. I'll go over the patch once more. Martin ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration 2025-12-02 3:02 ` [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration Benjamin Marzinski 2025-12-08 14:46 ` Martin Wilck @ 2025-12-08 14:55 ` Martin Wilck 1 sibling, 0 replies; 10+ messages in thread From: Martin Wilck @ 2025-12-08 14:55 UTC (permalink / raw) To: Benjamin Marzinski, Christophe Varoqui; +Cc: device-mapper development On Mon, 2025-12-01 at 22:02 -0500, Benjamin Marzinski wrote: > 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 <map> pathlist <pathlist>", where > <pathlist> is a quoted, comma 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 <bmarzins@redhat.com> > --- > libmpathpersist/mpath_persist_int.c | 6 +-- > libmpathpersist/mpath_updatepr.c | 48 +++++++++++++++++------ > libmpathpersist/mpathpr.h | 4 +- > multipathd/callbacks.c | 1 + > multipathd/cli.c | 1 + > multipathd/cli.h | 2 + > multipathd/cli_handlers.c | 39 ++++++++++++++++-- > multipathd/main.c | 61 +++++++++++++++++++-------- > -- > multipathd/main.h | 3 +- > multipathd/multipathd.8.in | 6 +++ > 10 files changed, 132 insertions(+), 39 deletions(-) > > > diff --git a/multipathd/main.c b/multipathd/main.c > index a7650639..2cd5c952 100644 > --- a/multipathd/main.c > +++ b/multipathd/main.c > @@ -630,28 +630,49 @@ 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_s *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, > pathname) == 0 || > + 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: This fails on Debian Sid with this error messsage: main.c:677:3: error: label at end of compound statement is a C23 extension [-Werror,-Wc23-extensions] 677 | } | [1] https://github.com/openSUSE/multipath-tools/actions/runs/20031717354/job/57442300023 Martin ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/4] multipath-tools: Yet Another PR fix 2025-12-02 3:02 [PATCH 0/4] multipath-tools: Yet Another PR fix Benjamin Marzinski ` (3 preceding siblings ...) 2025-12-02 3:02 ` [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration Benjamin Marzinski @ 2025-12-08 14:48 ` Martin Wilck 4 siblings, 0 replies; 10+ messages in thread From: Martin Wilck @ 2025-12-08 14:48 UTC (permalink / raw) To: Benjamin Marzinski, Christophe Varoqui; +Cc: device-mapper development On Mon, 2025-12-01 at 22:02 -0500, Benjamin Marzinski wrote: > I ran into some cases where checking the number of registered keys > made > multipathd think all paths had been registered, when they hadn't. The > last two patches in this patchset rework that code. The first two are > just fixes to other issues I happened to notice while working on this > code. > > Benjamin Marzinski (4): > libmpathpersist: fix register retry status checking > multipath-tools man pages: fix multipathd commands keyword ordering > multipathd: remember number of registered keys when ioctl fails > libmpathpersist: fix code for skipping multipathd path registration > > libmpathpersist/mpath_persist_int.c | 20 ++++---- > libmpathpersist/mpath_updatepr.c | 48 ++++++++++++++----- > libmpathpersist/mpathpr.h | 4 +- > multipathd/callbacks.c | 1 + > multipathd/cli.c | 1 + > multipathd/cli.h | 2 + > multipathd/cli_handlers.c | 39 ++++++++++++++-- > multipathd/main.c | 72 +++++++++++++++++++-------- > -- > multipathd/main.h | 3 +- > multipathd/multipathd.8.in | 24 ++++++---- > 10 files changed, 155 insertions(+), 59 deletions(-) For the series, except 4/4: Reviewed-by: Martin Wilck <mwilck@suse.com> ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-12-09 11:09 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-12-02 3:02 [PATCH 0/4] multipath-tools: Yet Another PR fix Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 1/4] libmpathpersist: fix register retry status checking Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 2/4] multipath-tools man pages: fix multipathd commands keyword ordering Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 3/4] multipathd: remember number of registered keys when ioctl fails Benjamin Marzinski 2025-12-02 3:02 ` [PATCH 4/4] libmpathpersist: fix code for skipping multipathd path registration Benjamin Marzinski 2025-12-08 14:46 ` Martin Wilck 2025-12-08 20:50 ` Benjamin Marzinski 2025-12-09 11:09 ` Martin Wilck 2025-12-08 14:55 ` Martin Wilck 2025-12-08 14:48 ` [PATCH 0/4] multipath-tools: Yet Another PR fix Martin Wilck
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.