Compare commits

..

No commits in common. "c8" and "c8s" have entirely different histories.
c8 ... c8s

7 changed files with 2 additions and 927 deletions

View File

@ -1,136 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 20 Dec 2022 17:41:10 -0600
Subject: [PATCH] multipathd: make pr registration consistent
multipathd was inconsistent on what it did with persistent reservations
when a multipath device was created. If a multipath device with a
configured reservation key was created during configure(), multipathd
would try to read the registered keys using an active path. If it saw a
matching key, it would set the prflag, but not attempt to register the
key on any of the other paths. This means that if a new path had
appeared while multipathd was not running, it wouldn't register the key
on this path.
If the multipath device was created during ev_add_path(), multipathd
would used the added path to check if there was a matching key and if
there was, register the key only on the added path and then set the
prflag. This could be problematic if the device was created with
multiple paths, for instance because find_mutipaths was set to "yes" and
a second path just appeared. In this case, if the device happened to be
only registered on the second path, it would not get registered on the
first path.
If the multipath device was added to multipathd during a call to
ev_add_map(), multipathd wouldn't set the prflag or register the key on
any paths.
After a device was created with the prflag set, if a new path appeared
before the creation uevent, and multipathd was forced to delay adding
it, when it finally updated the multipath device, the key would be
registered on all paths, fixing any paths missed during creation.
However, if a new path appeared after the creation uevent, the key would
only be registered on that new path. Any paths that were missed on
creation would stay missed.
persistent key registration needs to be handled consistently. This
patch does so by making sure that however a multipath device is added to
multipathd, it will check to see if the configured key is registered. If
it is, multipathd will set the prflag and register the key on all the
currently active paths.
When a new path is added, multipathd will use it to check for active
keys, as before. But if it finds a matching key and prflag isn't
currently set, it will register the key on all paths.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
multipathd/main.c | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index 769dcaee..d84027dc 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -511,6 +511,21 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) {
return false;
}
+static void
+pr_register_active_paths(struct multipath *mpp)
+{
+ unsigned int i, j;
+ struct path *pp;
+ struct pathgroup *pgp;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
+ mpath_pr_event_handle(pp);
+ }
+ }
+}
+
static int
update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
{
@@ -556,6 +571,11 @@ fail:
sync_map_state(mpp);
+ if (!mpp->prflag)
+ update_map_pr(mpp);
+ if (mpp->prflag)
+ pr_register_active_paths(mpp);
+
if (retries < 0)
condlog(0, "%s: failed reload in new map update", mpp->alias);
return 0;
@@ -1014,6 +1034,7 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
int start_waiter = 0;
int ret;
int ro;
+ unsigned char prflag = 0;
/*
* need path UID to go any further
@@ -1056,6 +1077,8 @@ rescan:
verify_paths(mpp, vecs);
mpp->action = ACT_RELOAD;
+ prflag = mpp->prflag;
+ mpath_pr_event_handle(pp);
} else {
if (!should_multipath(pp, vecs->pathvec, vecs->mpvec)) {
orphan_path(pp, "only one path");
@@ -1074,9 +1097,6 @@ rescan:
goto fail; /* leave path added to pathvec */
}
- /* persistent reservation check*/
- mpath_pr_event_handle(pp);
-
/* ro check - if new path is ro, force map to be ro as well */
ro = sysfs_get_ro(pp);
if (ro == 1)
@@ -1140,6 +1160,10 @@ rescan:
sync_map_state(mpp);
if (retries >= 0) {
+ if (start_waiter)
+ update_map_pr(mpp);
+ if (mpp->prflag && !prflag)
+ pr_register_active_paths(mpp);
condlog(2, "%s [%s]: path added to devmap %s",
pp->dev, pp->dev_t, mpp->alias);
return 0;
@@ -2608,6 +2632,8 @@ configure (struct vectors * vecs)
if (remember_wwid(mpp->wwid) == 1)
trigger_paths_udev_change(mpp, true);
update_map_pr(mpp);
+ if (mpp->prflag)
+ pr_register_active_paths(mpp);
}
/*

View File

@ -1,165 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 20 Dec 2022 17:41:11 -0600
Subject: [PATCH] libmultipath: make prflag an enum
In preparation for a future patch, make prflag an enum, and change the
reply of cli_getprstatus() to a string.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmpathpersist/mpath_persist.c | 2 +-
libmultipath/structs.h | 8 +++++++-
multipathd/cli_handlers.c | 16 +++++++++-------
multipathd/main.c | 14 +++++++-------
4 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index d0744773..e361435a 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -949,7 +949,7 @@ int update_map_pr(struct multipath *mpp)
if (isFound)
{
- mpp->prflag = 1;
+ mpp->prflag = PRFLAG_SET;
condlog(2, "%s: prflag flag set.", mpp->alias );
}
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 44980b4e..8acea3cb 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -377,6 +377,12 @@ struct path {
typedef int (pgpolicyfn) (struct multipath *, vector);
+
+enum prflag_value {
+ PRFLAG_UNSET,
+ PRFLAG_SET,
+};
+
struct multipath {
char wwid[WWID_SIZE];
char alias_old[WWID_SIZE];
@@ -450,7 +456,7 @@ struct multipath {
int prkey_source;
struct be64 reservation_key;
uint8_t sa_flags;
- unsigned char prflag;
+ int prflag;
int all_tg_pt;
struct gen_multipath generic_mp;
bool fpin_must_reload;
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 8b4bd187..6dbbb7e2 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -1407,6 +1407,10 @@ cli_shutdown (void * v, char ** reply, int * len, void * data)
int
cli_getprstatus (void * v, char ** reply, int * len, void * data)
{
+ static const char * const prflag_str[] = {
+ [PRFLAG_UNSET] = "unset\n",
+ [PRFLAG_SET] = "set\n",
+ };
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
@@ -1418,9 +1422,7 @@ cli_getprstatus (void * v, char ** reply, int * len, void * data)
if (!mpp)
return 1;
- condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
-
- *len = asprintf(reply, "%d", mpp->prflag);
+ *len = asprintf(reply, "%s", prflag_str[mpp->prflag]);
if (*len < 0)
return 1;
@@ -1443,8 +1445,8 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data)
if (!mpp)
return 1;
- if (!mpp->prflag) {
- mpp->prflag = 1;
+ if (mpp->prflag != PRFLAG_SET) {
+ mpp->prflag = PRFLAG_SET;
condlog(2, "%s: prflag set", param);
}
@@ -1466,8 +1468,8 @@ cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
if (!mpp)
return 1;
- if (mpp->prflag) {
- mpp->prflag = 0;
+ if (mpp->prflag != PRFLAG_UNSET) {
+ mpp->prflag = PRFLAG_UNSET;
condlog(2, "%s: prflag unset", param);
}
diff --git a/multipathd/main.c b/multipathd/main.c
index d84027dc..81bb0deb 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -571,9 +571,9 @@ fail:
sync_map_state(mpp);
- if (!mpp->prflag)
+ if (mpp->prflag == PRFLAG_UNSET)
update_map_pr(mpp);
- if (mpp->prflag)
+ if (mpp->prflag == PRFLAG_SET)
pr_register_active_paths(mpp);
if (retries < 0)
@@ -1034,7 +1034,7 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
int start_waiter = 0;
int ret;
int ro;
- unsigned char prflag = 0;
+ unsigned char prflag = PRFLAG_UNSET;
/*
* need path UID to go any further
@@ -1162,7 +1162,7 @@ rescan:
if (retries >= 0) {
if (start_waiter)
update_map_pr(mpp);
- if (mpp->prflag && !prflag)
+ if (mpp->prflag == PRFLAG_SET && prflag == PRFLAG_UNSET)
pr_register_active_paths(mpp);
condlog(2, "%s [%s]: path added to devmap %s",
pp->dev, pp->dev_t, mpp->alias);
@@ -2306,7 +2306,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
}
if (newstate == PATH_UP || newstate == PATH_GHOST) {
- if (pp->mpp->prflag) {
+ if (pp->mpp->prflag == PRFLAG_SET) {
/*
* Check Persistent Reservation.
*/
@@ -2632,7 +2632,7 @@ configure (struct vectors * vecs)
if (remember_wwid(mpp->wwid) == 1)
trigger_paths_udev_change(mpp, true);
update_map_pr(mpp);
- if (mpp->prflag)
+ if (mpp->prflag == PRFLAG_SET)
pr_register_active_paths(mpp);
}
@@ -3438,7 +3438,7 @@ void * mpath_pr_event_handler_fn (void * pathp )
{
condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
}
- mpp->prflag = 1;
+ mpp->prflag = PRFLAG_SET;
free(param);
out:

View File

@ -1,152 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Tue, 20 Dec 2022 17:41:12 -0600
Subject: [PATCH] multipathd: handle no active paths in update_map_pr
When a multipath device is first created, if it has a reservation key
configured, update_map_pr() will check for a matching key on the active
paths. If there were no active paths to check with, multipathd was
leaving mpp->prflag in PRFLAG_UNSET, as if there were no matching keys.
It's possible that when update_map_pr() is called, all the paths will be
in the PATH_PENDING state because the checkers haven't completed yet. In
this case, multipathd was treating the device as having no registered
keys without ever checking.
To solve this, multipath devices now start with prflag = PRFLAG_UNKNOWN.
It will remain in this state until multipathd actually tries to get the
registered keys down a path. If the map is in this state, it will check
newly active paths, and if it finds a matching key, it will register
the key down all active paths.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmpathpersist/mpath_persist.c | 8 ++++++++
libmultipath/structs.h | 1 +
multipathd/cli_handlers.c | 1 +
multipathd/main.c | 19 ++++++++++++++-----
4 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
index e361435a..440a329f 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -904,6 +904,7 @@ int update_map_pr(struct multipath *mpp)
if (!get_be64(mpp->reservation_key))
{
/* Nothing to do. Assuming pr mgmt feature is disabled*/
+ mpp->prflag = PRFLAG_UNSET;
condlog(4, "%s: reservation_key not set in multipath.conf",
mpp->alias);
return MPATH_PR_SUCCESS;
@@ -915,6 +916,13 @@ int update_map_pr(struct multipath *mpp)
condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
return MPATH_PR_OTHER;
}
+ if (count_active_paths(mpp) == 0)
+ {
+ condlog(0,"%s: No available paths to check pr status",
+ mpp->alias);
+ return MPATH_PR_OTHER;
+ }
+ mpp->prflag = PRFLAG_UNSET;
ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
if (ret != MPATH_PR_SUCCESS )
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 8acea3cb..7f2fb944 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -379,6 +379,7 @@ typedef int (pgpolicyfn) (struct multipath *, vector);
enum prflag_value {
+ PRFLAG_UNKNOWN,
PRFLAG_UNSET,
PRFLAG_SET,
};
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 6dbbb7e2..260b7a17 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -1408,6 +1408,7 @@ int
cli_getprstatus (void * v, char ** reply, int * len, void * data)
{
static const char * const prflag_str[] = {
+ [PRFLAG_UNKNOWN] = "unknown\n",
[PRFLAG_UNSET] = "unset\n",
[PRFLAG_SET] = "set\n",
};
diff --git a/multipathd/main.c b/multipathd/main.c
index 81bb0deb..e7dad6b9 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -571,7 +571,7 @@ fail:
sync_map_state(mpp);
- if (mpp->prflag == PRFLAG_UNSET)
+ if (mpp->prflag != PRFLAG_SET)
update_map_pr(mpp);
if (mpp->prflag == PRFLAG_SET)
pr_register_active_paths(mpp);
@@ -1162,7 +1162,7 @@ rescan:
if (retries >= 0) {
if (start_waiter)
update_map_pr(mpp);
- if (mpp->prflag == PRFLAG_SET && prflag == PRFLAG_UNSET)
+ if (mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET)
pr_register_active_paths(mpp);
condlog(2, "%s [%s]: path added to devmap %s",
pp->dev, pp->dev_t, mpp->alias);
@@ -2306,13 +2306,17 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
}
if (newstate == PATH_UP || newstate == PATH_GHOST) {
- if (pp->mpp->prflag == PRFLAG_SET) {
+ if (pp->mpp->prflag != PRFLAG_UNSET) {
+ int prflag = pp->mpp->prflag;
/*
* Check Persistent Reservation.
*/
condlog(2, "%s: checking persistent "
"reservation registration", pp->dev);
mpath_pr_event_handle(pp);
+ if (pp->mpp->prflag == PRFLAG_SET &&
+ prflag != PRFLAG_SET)
+ pr_register_active_paths(pp->mpp);
}
}
@@ -3386,6 +3390,7 @@ void * mpath_pr_event_handler_fn (void * pathp )
goto out;
}
+ mpp->prflag = PRFLAG_UNSET;
ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, 0);
if (ret != MPATH_PR_SUCCESS )
{
@@ -3456,12 +3461,12 @@ int mpath_pr_event_handle(struct path *pp)
struct multipath * mpp;
if (pp->bus != SYSFS_BUS_SCSI)
- return 0;
+ goto no_pr;
mpp = pp->mpp;
if (!get_be64(mpp->reservation_key))
- return -1;
+ goto no_pr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
@@ -3474,4 +3479,8 @@ int mpath_pr_event_handle(struct path *pp)
pthread_attr_destroy(&attr);
rc = pthread_join(thread, NULL);
return 0;
+
+no_pr:
+ pp->mpp->prflag = PRFLAG_UNSET;
+ return 0;
}

View File

@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 2 Feb 2023 09:20:35 +0100
Subject: [PATCH] libmpathpersist: fix resource leak in update_map_pr()
The "no available paths" case would leak the memory resp points to.
Found by coverity.
Fixes: 50e2c16 ("multipathd: handle no active paths in update_map_pr")
Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
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 440a329f..a4c1461f 100644
--- a/libmpathpersist/mpath_persist.c
+++ b/libmpathpersist/mpath_persist.c
@@ -899,7 +899,7 @@ int update_map_pr(struct multipath *mpp)
int noisy=0;
struct prin_resp *resp;
unsigned int i;
- int ret, isFound;
+ int ret = MPATH_PR_OTHER, isFound;
if (!get_be64(mpp->reservation_key))
{
@@ -920,7 +920,7 @@ int update_map_pr(struct multipath *mpp)
{
condlog(0,"%s: No available paths to check pr status",
mpp->alias);
- return MPATH_PR_OTHER;
+ goto out;
}
mpp->prflag = PRFLAG_UNSET;
ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
@@ -928,15 +928,15 @@ int update_map_pr(struct multipath *mpp)
if (ret != MPATH_PR_SUCCESS )
{
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
- free(resp);
- return ret;
+ goto out;
}
+ ret = MPATH_PR_SUCCESS;
+
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
{
condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias);
- free(resp);
- return MPATH_PR_SUCCESS;
+ goto out;
}
condlog(2, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
@@ -961,6 +961,7 @@ int update_map_pr(struct multipath *mpp)
condlog(2, "%s: prflag flag set.", mpp->alias );
}
+out:
free(resp);
- return MPATH_PR_SUCCESS;
+ return ret;
}

View File

@ -1,300 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Muneendra <muneendra.kumar@broadcom.com>
Date: Wed, 20 Sep 2023 20:41:15 -0700
Subject: [PATCH] multipathd: Added support to handle FPIN-Li events for
FC-NVMe
This patch adds the support to handle FPIN-Li for FC-NVMe.
On receiving the FPIN-Li events this patch moves the devices paths
which are affected due to link integrity to marginal path groups.
The paths which are set to marginal path group will be unset
on receiving the RSCN events
(mwilck: minor compile fix for 32-bit architectures)
Signed-off-by: Muneendra <muneendra.kumar@broadcom.com>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
multipathd/fpin_handlers.c | 206 +++++++++++++++++++++++++++----------
1 file changed, 151 insertions(+), 55 deletions(-)
diff --git a/multipathd/fpin_handlers.c b/multipathd/fpin_handlers.c
index 599f2893..6b90cded 100644
--- a/multipathd/fpin_handlers.c
+++ b/multipathd/fpin_handlers.c
@@ -60,18 +60,15 @@ static void _udev_device_unref(void *p)
/*set/unset the path state to marginal*/
-static int fpin_set_pathstate(struct path *pp, bool set)
+static void fpin_set_pathstate(struct path *pp, bool set)
{
const char *action = set ? "set" : "unset";
- if (!pp || !pp->mpp || !pp->mpp->alias)
- return -1;
-
- condlog(3, "\n%s: %s marginal path %s (fpin)",
- action, pp->mpp->alias, pp->dev_t);
+ condlog(3, "%s: %s marginal path %s (fpin)",
+ pp->mpp ? pp->mpp->alias : "orphan", action, pp->dev_t);
pp->marginal = set;
- pp->mpp->fpin_must_reload = true;
- return 0;
+ if (pp->mpp)
+ pp->mpp->fpin_must_reload = true;
}
/* This will unset marginal state of a device*/
@@ -82,14 +79,14 @@ static void fpin_path_unsetmarginal(char *devname, struct vectors *vecs)
pp = find_path_by_dev(vecs->pathvec, devname);
if (!pp)
pp = find_path_by_devt(vecs->pathvec, devname);
-
- fpin_set_pathstate(pp, false);
+ if (pp)
+ fpin_set_pathstate(pp, false);
}
/*This will set the marginal state of a device*/
-static int fpin_path_setmarginal(struct path *pp)
+static void fpin_path_setmarginal(struct path *pp)
{
- return fpin_set_pathstate(pp, true);
+ fpin_set_pathstate(pp, true);
}
/* Unsets all the devices in the list from marginal state */
@@ -176,8 +173,8 @@ static void fpin_set_rport_marginal(struct udev_device *rport_dev)
"Marginal", strlen("Marginal"));
}
-/*Add the marginal devices info into the list*/
-static void
+/*Add the marginal devices info into the list and return 0 on success*/
+static int
fpin_add_marginal_dev_info(uint32_t host_num, char *devname)
{
struct marginal_dev_list *newdev = NULL;
@@ -192,65 +189,160 @@ fpin_add_marginal_dev_info(uint32_t host_num, char *devname)
list_add_tail(&(newdev->node),
&fpin_li_marginal_dev_list_head);
pthread_mutex_unlock(&fpin_li_marginal_dev_mutex);
- }
+ } else
+ return -ENOMEM;
+ return 0;
}
/*
- * This function goes through the vecs->pathvec, and for
- * each path, check that the host number,
- * the target WWPN associated with the path matches
- * with the els wwpn and sets the path and port state to
+ * This function compares Transport Address Controller Port pn,
+ * Host Transport Address Controller Port pn with the els wwpn ,attached_wwpn
+ * and return 1 (match) or 0 (no match) or a negative error code
+ */
+static int extract_nvme_addresses_chk_path_pwwn(const char *address,
+ uint64_t els_wwpn, uint64_t els_attached_wwpn)
+
+{
+ uint64_t traddr;
+ uint64_t host_traddr;
+
+ /*
+ * Find the position of "traddr=" and "host_traddr="
+ * and the address will be in the below format
+ * "traddr=nn-0x200400110dff9400:pn-0x200400110dff9400,
+ * host_traddr=nn-0x200400110dff9400:pn-0x200400110dff9400"
+ */
+ const char *traddr_start = strstr(address, "traddr=");
+ const char *host_traddr_start = strstr(address, "host_traddr=");
+
+ if (!traddr_start || !host_traddr_start)
+ return -EINVAL;
+
+ /* Extract traddr pn */
+ if (sscanf(traddr_start, "traddr=nn-%*[^:]:pn-%" SCNx64, &traddr) != 1)
+ return -EINVAL;
+
+ /* Extract host_traddr pn*/
+ if (sscanf(host_traddr_start, "host_traddr=nn-%*[^:]:pn-%" SCNx64,
+ &host_traddr) != 1)
+ return -EINVAL;
+ condlog(4, "traddr 0x%" PRIx64 " hosttraddr 0x%" PRIx64 " els_wwpn 0x%"
+ PRIx64" els_host_traddr 0x%" PRIx64,
+ traddr, host_traddr,
+ els_wwpn, els_attached_wwpn);
+ if ((host_traddr == els_attached_wwpn) && (traddr == els_wwpn))
+ return 1;
+ return 0;
+}
+
+/*
+ * This function check that the Transport Address Controller Port pn,
+ * Host Transport Address Controller Port pn associated with the path matches
+ * with the els wwpn ,attached_wwpn and sets the path state to
* Marginal
*/
-static int fpin_chk_wwn_setpath_marginal(uint16_t host_num, struct vectors *vecs,
+static void fpin_check_set_nvme_path_marginal(uint16_t host_num, struct path *pp,
+ uint64_t els_wwpn, uint64_t attached_wwpn)
+{
+ struct udev_device *ctl = NULL;
+ const char *address = NULL;
+ int ret = 0;
+
+ ctl = udev_device_get_parent_with_subsystem_devtype(pp->udev, "nvme", NULL);
+ if (ctl == NULL) {
+ condlog(2, "%s: No parent device for ", pp->dev);
+ return;
+ }
+ address = udev_device_get_sysattr_value(ctl, "address");
+ if (!address) {
+ condlog(2, "%s: unable to get the address ", pp->dev);
+ return;
+ }
+ condlog(4, "\n address %s: dev :%s\n", address, pp->dev);
+ ret = extract_nvme_addresses_chk_path_pwwn(address, els_wwpn, attached_wwpn);
+ if (ret <= 0)
+ return;
+ ret = fpin_add_marginal_dev_info(host_num, pp->dev);
+ if (ret < 0)
+ return;
+ fpin_path_setmarginal(pp);
+}
+
+/*
+ * This function check the host number, the target WWPN
+ * associated with the path matches with the els wwpn and
+ * sets the path and port state to Marginal
+ */
+static void fpin_check_set_scsi_path_marginal(uint16_t host_num, struct path *pp,
uint64_t els_wwpn)
{
- struct path *pp;
- struct multipath *mpp;
- int i, k;
char rport_id[42];
const char *value = NULL;
struct udev_device *rport_dev = NULL;
uint64_t wwpn;
int ret = 0;
+ sprintf(rport_id, "rport-%d:%d-%d",
+ pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
+ rport_dev = udev_device_new_from_subsystem_sysname(udev,
+ "fc_remote_ports", rport_id);
+ if (!rport_dev) {
+ condlog(2, "%s: No fc_remote_port device for '%s'", pp->dev,
+ rport_id);
+ return;
+ }
+ pthread_cleanup_push(_udev_device_unref, rport_dev);
+ value = udev_device_get_sysattr_value(rport_dev, "port_name");
+ if (!value)
+ goto unref;
+
+ wwpn = strtol(value, NULL, 16);
+ /*
+ * If the port wwpn matches sets the path and port state
+ * to marginal
+ */
+ if (wwpn == els_wwpn) {
+ ret = fpin_add_marginal_dev_info(host_num, pp->dev);
+ if (ret < 0)
+ goto unref;
+ fpin_path_setmarginal(pp);
+ fpin_set_rport_marginal(rport_dev);
+ }
+unref:
+ pthread_cleanup_pop(1);
+ return;
+
+}
+
+/*
+ * This function goes through the vecs->pathvec, and for
+ * each path, it checks and sets the path state to marginal
+ * if the path's associated port wwpn ,hostnum matches with
+ * els wwnpn ,attached_wwpn
+ */
+static int fpin_chk_wwn_setpath_marginal(uint16_t host_num, struct vectors *vecs,
+ uint64_t els_wwpn, uint64_t attached_wwpn)
+{
+ struct path *pp;
+ struct multipath *mpp;
+ int i, k;
+ int ret = 0;
pthread_cleanup_push(cleanup_lock, &vecs->lock);
lock(&vecs->lock);
pthread_testcancel();
vector_foreach_slot(vecs->pathvec, pp, k) {
- /* Checks the host number and also for the SCSI FCP */
- if (pp->bus != SYSFS_BUS_SCSI || pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num != pp->sg_id.host_no)
+ if (!pp->mpp)
continue;
- sprintf(rport_id, "rport-%d:%d-%d",
- pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
- rport_dev = udev_device_new_from_subsystem_sysname(udev,
- "fc_remote_ports", rport_id);
- if (!rport_dev) {
- condlog(2, "%s: No fc_remote_port device for '%s'", pp->dev,
- rport_id);
- continue;
- }
- pthread_cleanup_push(_udev_device_unref, rport_dev);
- value = udev_device_get_sysattr_value(rport_dev, "port_name");
- if (!value)
- goto unref;
-
- if (value)
- wwpn = strtol(value, NULL, 16);
- /*
- * If the port wwpn matches sets the path and port state
- * to marginal
- */
- if (wwpn == els_wwpn) {
- ret = fpin_path_setmarginal(pp);
- if (ret < 0)
- goto unref;
- fpin_set_rport_marginal(rport_dev);
- fpin_add_marginal_dev_info(host_num, pp->dev);
+ /*checks if the bus type is nvme and the protocol is FC-NVMe*/
+ if ((pp->bus == SYSFS_BUS_NVME) && (pp->sg_id.proto_id == NVME_PROTOCOL_FC)) {
+ fpin_check_set_nvme_path_marginal(host_num, pp, els_wwpn, attached_wwpn);
+ } else if ((pp->bus == SYSFS_BUS_SCSI) &&
+ (pp->sg_id.proto_id == SCSI_PROTOCOL_FCP) &&
+ (host_num == pp->sg_id.host_no)) {
+ /* Checks the host number and also for the SCSI FCP */
+ fpin_check_set_scsi_path_marginal(host_num, pp, els_wwpn);
}
-unref:
- pthread_cleanup_pop(1);
}
/* walk backwards because update_path_groups() can remove mpp */
vector_foreach_slot_backwards(vecs->mpvec, mpp, i) {
@@ -279,14 +371,18 @@ fpin_parse_li_els_setpath_marginal(uint16_t host_num, struct fc_tlv_desc *tlv,
struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv;
int count = 0;
int ret = 0;
+ uint64_t attached_wwpn;
/* Update the wwn to list */
wwn_count = be32_to_cpu(li_desc->pname_count);
- condlog(4, "Got wwn count as %d\n", wwn_count);
+ attached_wwpn = be64_to_cpu(li_desc->attached_wwpn);
+ condlog(4, "Got wwn count as %d detecting wwn 0x%" PRIx64
+ " attached_wwpn 0x%" PRIx64 "\n",
+ wwn_count, be64_to_cpu(li_desc->detecting_wwpn), attached_wwpn);
for (iter = 0; iter < wwn_count; iter++) {
wwpn = be64_to_cpu(li_desc->pname_list[iter]);
- ret = fpin_chk_wwn_setpath_marginal(host_num, vecs, wwpn);
+ ret = fpin_chk_wwn_setpath_marginal(host_num, vecs, wwpn, attached_wwpn);
if (ret < 0)
condlog(2, "failed to set the path marginal associated with wwpn: 0x%" PRIx64 "\n", wwpn);

View File

@ -1,76 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 22 Nov 2023 16:41:22 -0500
Subject: [PATCH] multipathd: Make sure to disable queueing if recovery has
failed.
If a multipath device has no_path_retry set to a number and has lost all
paths, gone into recovery mode, and timed out, it will disable
queue_if_no_paths. After that, if the device is reloaded by multipath
outside of multipathd, it will re-enable queuieng on the device. When
multipathd later calls set_no_path_retry() to update the queueing state,
it will not disable queue_if_no_paths, since the device is still in the
recovery state, so it believes no work needs to be done. The device will
remain in the recovery state, with retry_ticks at 0, and queueing
enabled, even though there are no usable paths.
To fix this, in set_no_path_retry(), if no_path_retry is set to a number
and the device is queueing but it is in recovery mode and out of
retries with no usable paths, manually disable queue_if_no_path.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
libmultipath/structs_vec.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 9613252f..0304777b 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -377,8 +377,19 @@ void __set_no_path_retry(struct multipath *mpp, bool check_features)
!mpp->in_recovery)
dm_queue_if_no_path(mpp->alias, 1);
leave_recovery_mode(mpp);
- } else
- enter_recovery_mode(mpp);
+ } else {
+ /*
+ * If in_recovery is set, enter_recovery_mode does
+ * nothing. If the device is already in recovery
+ * mode and has already timed out, manually call
+ * dm_queue_if_no_path to stop it from queueing.
+ */
+ if ((!mpp->features || is_queueing) &&
+ mpp->in_recovery && mpp->retry_tick == 0)
+ dm_queue_if_no_path(mpp->alias, 0);
+ if (pathcount(mpp, PATH_PENDING) == 0)
+ enter_recovery_mode(mpp);
+ }
break;
}
}
@@ -521,6 +532,11 @@ int verify_paths(struct multipath *mpp, struct vectors *vecs)
* -1 (FAIL) : fail_if_no_path
* 0 (UNDEF) : nothing
* >0 : queue_if_no_path enabled, turned off after polling n times
+ *
+ * Since this will only be called when fail_path(), update_multipath(), or
+ * io_err_stat_handle_pathfail() are failing a previously active path, the
+ * device cannot already be in recovery mode, so there will never be a need
+ * to disable queueing here.
*/
void update_queue_mode_del_path(struct multipath *mpp)
{
@@ -534,6 +550,12 @@ void update_queue_mode_del_path(struct multipath *mpp)
condlog(2, "%s: remaining active paths: %d", mpp->alias, active);
}
+/*
+ * Since this will only be called from check_path() -> reinstate_path() after
+ * the queueing state has been updated in set_no_path_retry, this does not
+ * need to worry about modifying the queueing state except when actually
+ * leaving recovery mode.
+ */
void update_queue_mode_add_path(struct multipath *mpp)
{
int active = count_active_paths(mpp);

View File

@ -1,7 +1,7 @@
Summary: Tools to manage multipath devices using device-mapper
Name: device-mapper-multipath
Version: 0.8.4
Release: 41%{?dist}
Release: 37%{?dist}
License: GPLv2
Group: System Environment/Base
URL: http://christophe.varoqui.free.fr/
@ -142,12 +142,6 @@ Patch00128: 0128-libmutipath-validate-the-argument-count-of-config-st.patch
Patch00129: 0129-libmultipath-select-resize-action-even-if-reload-is-.patch
Patch00130: 0130-libmultipath-cleanup-ACT_CREATE-code-in-select_actio.patch
Patch00131: 0131-libmultipath-keep-renames-from-stopping-other-multip.patch
Patch00132: 0132-multipathd-make-pr-registration-consistent.patch
Patch00133: 0133-libmultipath-make-prflag-an-enum.patch
Patch00134: 0134-multipathd-handle-no-active-paths-in-update_map_pr.patch
Patch00135: 0135-libmpathpersist-fix-resource-leak-in-update_map_pr.patch
Patch00136: 0136-multipathd-Added-support-to-handle-FPIN-Li-events-fo.patch
Patch00137: 0137-multipathd-Make-sure-to-disable-queueing-if-recovery.patch
# runtime
Requires: %{name}-libs = %{version}-%{release}
@ -326,7 +320,7 @@ fi
%{!?_licensedir:%global license %%doc}
%license LICENSES/GPL-2.0
%{_sbindir}/kpartx
%{_udevrulesdir}/../kpartx_id
/usr/lib/udev/kpartx_id
%{_mandir}/man8/kpartx.8.gz
%config %{_udevrulesdir}/11-dm-parts.rules
%config %{_udevrulesdir}/66-kpartx.rules
@ -352,28 +346,6 @@ fi
%{_pkgconfdir}/libdmmp.pc
%changelog
* Fri Jan 5 2024 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-41
- Add 0137-multipathd-Make-sure-to-disable-queueing-if-recovery.patch
- Resolves: RHEL-16563
* Thu Nov 2 2023 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-40
- Add 0136-multipathd-Added-support-to-handle-FPIN-Li-events-fo.patch
* Add support in multipathd for NVMe to listen for FPIN-Li events and
mark effected paths as marginal
- Resolves: RHEL-6677
* Thu Mar 16 2023 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-39
- Add OSCI tests directory
- Make kpartx_id installation location relative to %{_udevrulesdir}
- Resolves: bz #2164871
* Wed Mar 15 2023 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-38
- Add 0132-multipathd-make-pr-registration-consistent.patch
- Add 0133-libmultipath-make-prflag-an-enum.patch
- Add 0134-multipathd-handle-no-active-paths-in-update_map_pr.patch
- Add 0135-libmpathpersist-fix-resource-leak-in-update_map_pr.patch
- Resolves: bz #2164871
* Fri Feb 3 2023 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-37
- Fix bugzilla linked to the changes (was previously linked to
the wrong bug, 2162537)