import UBI device-mapper-multipath-0.8.7-39.el9_7.1
This commit is contained in:
parent
633e98645b
commit
daa7dc6b75
@ -0,0 +1,151 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 3 Jun 2025 23:35:03 -0400
|
||||
Subject: [PATCH] libmpathpersist: retry commands on other paths in
|
||||
mpath_prout_common
|
||||
|
||||
mpath_prout_common() will only try sending the prout command to one
|
||||
path. If that fails, it will give up. There are a number of cases where
|
||||
it is reasonable to assume that sending the command down another path
|
||||
could succeed. Keep trying other available paths in these cases.
|
||||
|
||||
Do do this, this patch adds a new error code, MPATH_PR_RETRYABLE_ERROR.
|
||||
libmpathpersist will not return this error to users. It will change it
|
||||
to MPATH_PR_OTHER if it fails trying on all the paths.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 13 +++++++++----
|
||||
libmpathpersist/mpath_persist.h | 3 +++
|
||||
libmpathpersist/mpath_pr_ioctl.c | 25 ++++++++++++++-----------
|
||||
3 files changed, 26 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 29b64937..af5d3070 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -130,7 +130,7 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
}
|
||||
}
|
||||
}
|
||||
- return ret;
|
||||
+ return (ret == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : ret;
|
||||
}
|
||||
|
||||
static vector curmp;
|
||||
@@ -568,7 +568,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
- return (status);
|
||||
+ return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
void * mpath_prout_pthread_fn(void *p)
|
||||
@@ -588,6 +588,7 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int i,j, ret;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
+ bool found = false;
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, j){
|
||||
vector_foreach_slot (pgp->paths, pp, i){
|
||||
@@ -598,12 +599,16 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
|
||||
+ found = true;
|
||||
ret = send_prout_activepath(pp->dev, rq_servact,
|
||||
rq_scope, rq_type,
|
||||
paramp, noisy);
|
||||
- return ret ;
|
||||
+ if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
+ return ret;
|
||||
}
|
||||
}
|
||||
+ if (found)
|
||||
+ return MPATH_PR_OTHER;
|
||||
condlog (0, "%s: no path available", mpp->wwid);
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
@@ -839,7 +844,7 @@ out1:
|
||||
free (pamp);
|
||||
out:
|
||||
free (pr_buff);
|
||||
- return (status);
|
||||
+ return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
void * mpath_alloc_prin_response(int prin_sa)
|
||||
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
|
||||
index 9e9c0a82..8d441d04 100644
|
||||
--- a/libmpathpersist/mpath_persist.h
|
||||
+++ b/libmpathpersist/mpath_persist.h
|
||||
@@ -63,6 +63,9 @@ extern "C" {
|
||||
#define MPATH_PR_THREAD_ERROR 14 /* pthreads error (e.g. unable to create new thread) */
|
||||
#define MPATH_PR_OTHER 15 /*other error/warning has occurred(transport
|
||||
or driver error) */
|
||||
+#define MPATH_PR_RETRYABLE_ERROR 16 /* error that might be succeed
|
||||
+ down another path. Internal
|
||||
+ only. */
|
||||
|
||||
/* PR MASK */
|
||||
#define MPATH_F_APTPL_MASK 0x01 /* APTPL MASK*/
|
||||
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
|
||||
index 126601c3..9cd83729 100644
|
||||
--- a/libmpathpersist/mpath_pr_ioctl.c
|
||||
+++ b/libmpathpersist/mpath_pr_ioctl.c
|
||||
@@ -54,7 +54,7 @@ int prout_do_scsi_ioctl(char * dev, int rq_servact, int rq_scope,
|
||||
fd = open(devname, O_RDONLY);
|
||||
if(fd < 0){
|
||||
condlog (1, "%s: unable to open device.", dev);
|
||||
- return MPATH_PR_FILE_ERROR;
|
||||
+ return MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
|
||||
unsigned char cdb[MPATH_PROUT_CMDLEN] =
|
||||
@@ -125,14 +125,17 @@ retry :
|
||||
goto retry;
|
||||
}
|
||||
|
||||
- if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
|
||||
- (Sensedata.ASCQ == 0x07))&& (retry > 0))
|
||||
- {
|
||||
- usleep(1000);
|
||||
- --retry;
|
||||
- condlog(3, "%s: retrying for sense 02/04/07."
|
||||
- " Remaining retries = %d", dev, retry);
|
||||
- goto retry;
|
||||
+ if (status == MPATH_PR_SENSE_NOT_READY) {
|
||||
+ if (Sensedata.ASC == 0x04 && Sensedata.ASCQ == 0x07 && retry > 0) {
|
||||
+ usleep(1000);
|
||||
+ --retry;
|
||||
+ condlog(3,
|
||||
+ "%s: retrying for sense 02/04/07."
|
||||
+ " Remaining retries = %d",
|
||||
+ dev, retry);
|
||||
+ goto retry;
|
||||
+ } else
|
||||
+ status = MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -344,7 +347,7 @@ int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int
|
||||
fd = open(devname, O_RDONLY);
|
||||
if(fd < 0){
|
||||
condlog(0, "%s: Unable to open device ", dev);
|
||||
- return MPATH_PR_FILE_ERROR;
|
||||
+ return MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
|
||||
if (mpath_mx_alloc_len)
|
||||
@@ -490,7 +493,7 @@ int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
|
||||
case DID_OK :
|
||||
break;
|
||||
default :
|
||||
- return MPATH_PR_OTHER;
|
||||
+ return MPATH_PR_RETRYABLE_ERROR;
|
||||
}
|
||||
switch(io_hdr.driver_status)
|
||||
{
|
||||
@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 3 Jun 2025 23:35:04 -0400
|
||||
Subject: [PATCH] libmpathpersist: check released key against the reservation
|
||||
key
|
||||
|
||||
According to the SCSI Spec, if a persistent reservation RELEASE is
|
||||
issued using the correct key for the I_T_L Nexus that it is issued on
|
||||
but the reservation is held by a different key, the command should
|
||||
return Success and do nothing. When libmpathpersist tried to release a
|
||||
reservation that was held by a different key, it ended up using the
|
||||
failback code designed to release a reservation held by a failed path to
|
||||
release it anyways. This means that any node could release a scsi
|
||||
persistent reservation held by another node. Fix this to follow the SCSI
|
||||
Spec.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index af5d3070..9d42704d 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -745,7 +745,13 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
- condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid);
|
||||
+ if (!get_be64(mpp->reservation_key) ||
|
||||
+ memcmp(&mpp->reservation_key, resp.prin_descriptor.prin_readresv.key, 8)) {
|
||||
+ condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
+ condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
|
||||
|
||||
pr_buff = mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
|
||||
if (!pr_buff){
|
||||
@ -0,0 +1,112 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 16 Jun 2025 19:25:50 -0400
|
||||
Subject: [PATCH] multipathd: remove thread from mpath_pr_event_handle
|
||||
|
||||
mpath_pr_event_handle() creates a separate thread to do the persistent
|
||||
reservation work, but it doesn't take any advantage of the work being
|
||||
done in another thread. Merge mpath_pr_event_handle() and
|
||||
mpath_pr_event_handler_fn() into a single function with no separate
|
||||
thread.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 49 ++++++++++++-----------------------------------
|
||||
multipathd/main.h | 3 ---
|
||||
2 files changed, 12 insertions(+), 40 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 4119ad79..3f4b8ff6 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -90,6 +90,8 @@
|
||||
#define CMDSIZE 160
|
||||
#define MSG_SIZE 32
|
||||
|
||||
+static void mpath_pr_event_handle(struct path *pp);
|
||||
+
|
||||
#define LOG_MSG(lvl, pp) \
|
||||
do { \
|
||||
if (pp->mpp && checker_selected(&pp->checker) && \
|
||||
@@ -3722,17 +3724,24 @@ main (int argc, char *argv[])
|
||||
return (child(NULL));
|
||||
}
|
||||
|
||||
-void * mpath_pr_event_handler_fn (void * pathp )
|
||||
+static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath * mpp;
|
||||
unsigned int i;
|
||||
int ret, isFound;
|
||||
- struct path * pp = (struct path *)pathp;
|
||||
struct prout_param_descriptor *param;
|
||||
struct prin_resp *resp;
|
||||
|
||||
- rcu_register_thread();
|
||||
mpp = pp->mpp;
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!get_be64(mpp->reservation_key)) {
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
if (!resp){
|
||||
@@ -3799,38 +3808,4 @@ void * mpath_pr_event_handler_fn (void * pathp )
|
||||
out:
|
||||
if (resp)
|
||||
free(resp);
|
||||
- rcu_unregister_thread();
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
-int mpath_pr_event_handle(struct path *pp)
|
||||
-{
|
||||
- pthread_t thread;
|
||||
- int rc;
|
||||
- pthread_attr_t attr;
|
||||
- struct multipath * mpp;
|
||||
-
|
||||
- if (pp->bus != SYSFS_BUS_SCSI)
|
||||
- goto no_pr;
|
||||
-
|
||||
- mpp = pp->mpp;
|
||||
-
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
- goto no_pr;
|
||||
-
|
||||
- pthread_attr_init(&attr);
|
||||
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
-
|
||||
- rc = pthread_create(&thread, NULL , mpath_pr_event_handler_fn, pp);
|
||||
- if (rc) {
|
||||
- condlog(0, "%s: ERROR; return code from pthread_create() is %d", pp->dev, rc);
|
||||
- return -1;
|
||||
- }
|
||||
- pthread_attr_destroy(&attr);
|
||||
- rc = pthread_join(thread, NULL);
|
||||
- return 0;
|
||||
-
|
||||
-no_pr:
|
||||
- pp->mpp->prflag = PRFLAG_UNSET;
|
||||
- return 0;
|
||||
}
|
||||
diff --git a/multipathd/main.h b/multipathd/main.h
|
||||
index 4138faa4..897051e0 100644
|
||||
--- a/multipathd/main.h
|
||||
+++ b/multipathd/main.h
|
||||
@@ -52,10 +52,7 @@ void dumpHex(const char * , int len, int no_ascii);
|
||||
int prout_do_scsi_ioctl(char * , int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor *param, int noisy);
|
||||
-int mpath_pr_event_handle(struct path *pp);
|
||||
-void * mpath_pr_event_handler_fn (void * );
|
||||
int update_map_pr(struct multipath *mpp);
|
||||
-void * mpath_pr_event_handler_fn (void * pathp );
|
||||
void handle_signals(bool);
|
||||
int __setup_multipath (struct vectors * vecs, struct multipath * mpp,
|
||||
int reset);
|
||||
@ -0,0 +1,60 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 16 Jun 2025 19:39:04 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove uneeded wrapper function.
|
||||
|
||||
mpath_send_prin_activepath() just calls prin_do_scsi_ioctl() with exactly
|
||||
the same arguments that it is passed, and returns the same return. remove
|
||||
it.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 15 ++-------------
|
||||
libmpathpersist/mpathpr.h | 1 -
|
||||
2 files changed, 2 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 9d42704d..a7d07963 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -118,8 +118,8 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
|
||||
condlog(3, "%s: sending pr in command to %s ",
|
||||
mpp->wwid, pp->dev);
|
||||
- ret = mpath_send_prin_activepath(pp->dev, rq_servact,
|
||||
- resp, noisy);
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, rq_servact, resp,
|
||||
+ noisy);
|
||||
switch(ret)
|
||||
{
|
||||
case MPATH_PR_SUCCESS:
|
||||
@@ -418,17 +418,6 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid)
|
||||
return MPATH_PR_SUCCESS ;
|
||||
}
|
||||
|
||||
-int mpath_send_prin_activepath (char * dev, int rq_servact,
|
||||
- struct prin_resp * resp, int noisy)
|
||||
-{
|
||||
-
|
||||
- int rc;
|
||||
-
|
||||
- rc = prin_do_scsi_ioctl(dev, rq_servact, resp, noisy);
|
||||
-
|
||||
- return (rc);
|
||||
-}
|
||||
-
|
||||
int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 5ea8cd6f..0292bc50 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -31,7 +31,6 @@ int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int
|
||||
int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
|
||||
void * _mpath_pr_update (void *arg);
|
||||
-int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy);
|
||||
int get_mpvec (vector curmp, vector pathvec, char * refwwid);
|
||||
void * mpath_prout_pthread_fn(void *p);
|
||||
void dumpHex(const char* , int len, int no_ascii);
|
||||
@ -0,0 +1,93 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 16 Jun 2025 20:08:08 -0400
|
||||
Subject: [PATCH] libmpathpersist: reduce log level for persistent reservation
|
||||
checking
|
||||
|
||||
Move logging of minor expected behavior to INFO level. Modify the log
|
||||
level of some messages by whether or not mpp->prflag changed values.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 26 ++++++++++++++------------
|
||||
1 file changed, 14 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index a7d07963..1ce43de1 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -109,7 +109,7 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
vector_foreach_slot (pgp->paths, pp, i){
|
||||
if (!((pp->state == PATH_UP) ||
|
||||
(pp->state == PATH_GHOST))){
|
||||
- condlog(2, "%s: %s not available. Skip.",
|
||||
+ condlog(3, "%s: %s not available. Skip.",
|
||||
mpp->wwid, pp->dev);
|
||||
condlog(3, "%s: status = %d.",
|
||||
mpp->wwid, pp->state);
|
||||
@@ -875,13 +875,13 @@ int update_map_pr(struct multipath *mpp)
|
||||
struct prin_resp *resp;
|
||||
unsigned int i;
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
+ bool was_set = (mpp->prflag == PRFLAG_SET);
|
||||
|
||||
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);
|
||||
+ condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -893,7 +893,7 @@ int update_map_pr(struct multipath *mpp)
|
||||
}
|
||||
if (count_active_paths(mpp) == 0)
|
||||
{
|
||||
- condlog(0,"%s: No available paths to check pr status",
|
||||
+ condlog(2, "%s: No available paths to check pr status",
|
||||
mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
@@ -910,22 +910,24 @@ int update_map_pr(struct multipath *mpp)
|
||||
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
- condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
+ condlog(was_set ? 1 : 3, "%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
|
||||
- condlog(2, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
+ condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
|
||||
isFound =0;
|
||||
for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
{
|
||||
- condlog(2, "%s: PR IN READKEYS[%d] reservation key:", mpp->alias, i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
|
||||
+ if (libmp_verbosity >= 3) {
|
||||
+ condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
+ mpp->alias, i);
|
||||
+ dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8, 1);
|
||||
+ }
|
||||
|
||||
- if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
|
||||
- {
|
||||
- condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
|
||||
+ if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8)) {
|
||||
+ condlog(3, "%s: reservation key found in pr in readkeys response", mpp->alias);
|
||||
isFound =1;
|
||||
}
|
||||
}
|
||||
@@ -933,7 +935,7 @@ int update_map_pr(struct multipath *mpp)
|
||||
if (isFound)
|
||||
{
|
||||
mpp->prflag = PRFLAG_SET;
|
||||
- condlog(2, "%s: prflag flag set.", mpp->alias );
|
||||
+ condlog(was_set ? 3 : 2, "%s: prflag flag set.", mpp->alias );
|
||||
}
|
||||
|
||||
out:
|
||||
@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 23 Jun 2025 13:43:45 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove pointless update_map_pr ret value
|
||||
code
|
||||
|
||||
Don't set ret to MPATH_PR_SUCCESS, after the code just made sure that
|
||||
it was already set to MPATH_PR_SUCCESS.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 1ce43de1..d9439292 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -906,8 +906,6 @@ int update_map_pr(struct multipath *mpp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- ret = MPATH_PR_SUCCESS;
|
||||
-
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
condlog(was_set ? 1 : 3, "%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
@ -0,0 +1,227 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 18 Jun 2025 19:22:07 -0400
|
||||
Subject: [PATCH] multipathd: use update_map_pr in mpath_pr_event_handle
|
||||
|
||||
Clean up the duplicate code in mpath_pr_event_handle() and
|
||||
update_map_pr() by making update_map_pr() take an optional path device
|
||||
to use for its check, instead of checking all path devices and make
|
||||
mpath_pr_event_handle() call update_map_pr() to do its checking.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 21 ++++++----
|
||||
libmpathpersist/mpathpr.h | 2 +-
|
||||
multipathd/main.c | 69 +++++----------------------------
|
||||
multipathd/main.h | 1 -
|
||||
4 files changed, 25 insertions(+), 68 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index d9439292..2c35cb3e 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -869,7 +869,7 @@ void * mpath_alloc_prin_response(int prin_sa)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
-int update_map_pr(struct multipath *mpp)
|
||||
+int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
int noisy=0;
|
||||
struct prin_resp *resp;
|
||||
@@ -882,7 +882,7 @@ int update_map_pr(struct multipath *mpp)
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
- return MPATH_PR_SUCCESS;
|
||||
+ return MPATH_PR_SKIP;
|
||||
}
|
||||
|
||||
resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
@@ -891,14 +891,18 @@ 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)
|
||||
- {
|
||||
+ if (!pp && count_active_paths(mpp) == 0) {
|
||||
condlog(2, "%s: No available paths to check pr status",
|
||||
mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
- ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
+ if (pp)
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp,
|
||||
+ noisy);
|
||||
+ else
|
||||
+ ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp,
|
||||
+ noisy);
|
||||
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
@@ -933,8 +937,11 @@ int update_map_pr(struct multipath *mpp)
|
||||
if (isFound)
|
||||
{
|
||||
mpp->prflag = PRFLAG_SET;
|
||||
- condlog(was_set ? 3 : 2, "%s: prflag flag set.", mpp->alias );
|
||||
- }
|
||||
+ condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
+ mpp->alias);
|
||||
+ } else
|
||||
+ condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
+ mpp->alias);
|
||||
|
||||
out:
|
||||
free(resp);
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 0292bc50..dd84e6d9 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -48,6 +48,6 @@ int update_prflag(char *mapname, int set);
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
|
||||
#define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
|
||||
void * mpath_alloc_prin_response(int prin_sa);
|
||||
-int update_map_pr(struct multipath *mpp);
|
||||
+int update_map_pr(struct multipath *mpp, struct path *pp);
|
||||
|
||||
#endif
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 3f4b8ff6..3b99bbe2 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -68,6 +68,7 @@
|
||||
|
||||
#include "mpath_cmd.h"
|
||||
#include "mpath_persist.h"
|
||||
+#include "mpathpr.h"
|
||||
|
||||
#include "prioritizers/alua_rtpg.h"
|
||||
|
||||
@@ -643,7 +644,7 @@ fail:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (mpp->prflag != PRFLAG_SET)
|
||||
- update_map_pr(mpp);
|
||||
+ update_map_pr(mpp, NULL);
|
||||
if (mpp->prflag == PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
|
||||
@@ -1268,7 +1269,7 @@ rescan:
|
||||
|
||||
if (retries >= 0) {
|
||||
if (start_waiter)
|
||||
- update_map_pr(mpp);
|
||||
+ update_map_pr(mpp, NULL);
|
||||
if (mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
@@ -2883,7 +2884,7 @@ configure (struct vectors * vecs)
|
||||
vector_foreach_slot(mpvec, mpp, i){
|
||||
if (remember_wwid(mpp->wwid) == 1)
|
||||
trigger_paths_udev_change(mpp, true);
|
||||
- update_map_pr(mpp);
|
||||
+ update_map_pr(mpp, NULL);
|
||||
if (mpp->prflag == PRFLAG_SET)
|
||||
pr_register_active_paths(mpp);
|
||||
}
|
||||
@@ -3726,70 +3727,24 @@ main (int argc, char *argv[])
|
||||
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
- struct multipath * mpp;
|
||||
- unsigned int i;
|
||||
- int ret, isFound;
|
||||
+ struct multipath *mpp = pp->mpp;
|
||||
+ int ret;
|
||||
struct prout_param_descriptor *param;
|
||||
- struct prin_resp *resp;
|
||||
|
||||
- mpp = pp->mpp;
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
mpp->prflag = PRFLAG_UNSET;
|
||||
return;
|
||||
}
|
||||
|
||||
- if (!get_be64(mpp->reservation_key)) {
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
return;
|
||||
- }
|
||||
-
|
||||
- resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
- if (!resp){
|
||||
- condlog(0,"%s Alloc failed for prin response", pp->dev);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, 0);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
- condlog(0,"%s : pr in read keys service action failed. Error=%d", pp->dev, ret);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- condlog(3, " event pr=%d addlen=%d",resp->prin_descriptor.prin_readkeys.prgeneration,
|
||||
- resp->prin_descriptor.prin_readkeys.additional_length );
|
||||
-
|
||||
- if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
- {
|
||||
- condlog(1, "%s: No key found. Device may not be registered.", pp->dev);
|
||||
- goto out;
|
||||
- }
|
||||
- condlog(2, "Multipath reservation_key: 0x%" PRIx64 " ",
|
||||
- get_be64(mpp->reservation_key));
|
||||
|
||||
- isFound =0;
|
||||
- for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
- {
|
||||
- condlog(2, "PR IN READKEYS[%d] reservation key:",i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , -1);
|
||||
- if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
|
||||
- {
|
||||
- condlog(2, "%s: pr key found in prin readkeys response", mpp->alias);
|
||||
- isFound =1;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
- if (!isFound)
|
||||
- {
|
||||
- condlog(0, "%s: Either device not registered or ", pp->dev);
|
||||
- condlog(0, "host is not authorised for registration. Skip path");
|
||||
- goto out;
|
||||
- }
|
||||
+ if (mpp->prflag != PRFLAG_SET)
|
||||
+ return;
|
||||
|
||||
param = (struct prout_param_descriptor *)MALLOC(sizeof(struct prout_param_descriptor));
|
||||
if (!param)
|
||||
- goto out;
|
||||
+ return;
|
||||
|
||||
param->sa_flags = mpp->sa_flags;
|
||||
memcpy(param->sa_key, &mpp->reservation_key, 8);
|
||||
@@ -3802,10 +3757,6 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
|
||||
}
|
||||
- mpp->prflag = PRFLAG_SET;
|
||||
|
||||
free(param);
|
||||
-out:
|
||||
- if (resp)
|
||||
- free(resp);
|
||||
}
|
||||
diff --git a/multipathd/main.h b/multipathd/main.h
|
||||
index 897051e0..6d2ae72a 100644
|
||||
--- a/multipathd/main.h
|
||||
+++ b/multipathd/main.h
|
||||
@@ -52,7 +52,6 @@ void dumpHex(const char * , int len, int no_ascii);
|
||||
int prout_do_scsi_ioctl(char * , int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor *param, int noisy);
|
||||
-int update_map_pr(struct multipath *mpp);
|
||||
void handle_signals(bool);
|
||||
int __setup_multipath (struct vectors * vecs, struct multipath * mpp,
|
||||
int reset);
|
||||
@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 20 Jun 2025 14:31:13 -0400
|
||||
Subject: [PATCH] libmpathpersist: limit changing prflag in update_map_pr
|
||||
|
||||
Do not unset mpp->prflag in update_map_pr() unless the device doesn't
|
||||
support persistent reservations or it successfully reads the registered
|
||||
keys and discovers that the device's key is not there. Also, nothing in
|
||||
the libmpathpersist ever returns MPATH_PR_SENSE_INVALID_OP. It instead
|
||||
returns MPATH_PR_ILLEGAL_REQ if the device doesn't support persistent
|
||||
reservations, so check for that instead.
|
||||
|
||||
Also, do not even check for the registered keys in update_map_pr() if
|
||||
mpp->prflag is unset. Otherwise, multipathd will set mpp->prflag if the
|
||||
key was unregistered (and thus prflag was unset) while a path is down
|
||||
(and thus could not have its key unregistered) and then that path comes
|
||||
back up. I should note that the above issue can only occur if multipath
|
||||
is defining PR keys in /etc/multipath.conf, instead of the prkeys file.
|
||||
|
||||
If a device has no registered keys, it must unset prflag, since that
|
||||
means it's no longer registered. Possibly its registration was removed
|
||||
by a CLEAR or PREEMPT action. But if a device has a registered key but
|
||||
it is supposed to be unregistered, it should remain unregistered, since
|
||||
that key is likely one that libmpathpersist could not unregister at the
|
||||
time.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 2c35cb3e..65a81faf 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -123,7 +123,7 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
switch(ret)
|
||||
{
|
||||
case MPATH_PR_SUCCESS:
|
||||
- case MPATH_PR_SENSE_INVALID_OP:
|
||||
+ case MPATH_PR_ILLEGAL_REQ:
|
||||
return ret;
|
||||
default:
|
||||
continue;
|
||||
@@ -877,6 +877,10 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
bool was_set = (mpp->prflag == PRFLAG_SET);
|
||||
|
||||
+ /* If pr is explicitly unset, it must be manually set */
|
||||
+ if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ return MPATH_PR_SKIP;
|
||||
+
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
{
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
@@ -896,7 +900,6 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
mpp->alias);
|
||||
goto out;
|
||||
}
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
if (pp)
|
||||
ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp,
|
||||
noisy);
|
||||
@@ -906,9 +909,12 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
+ if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
goto out;
|
||||
}
|
||||
+ mpp->prflag = PRFLAG_UNSET;
|
||||
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 20 Jun 2025 16:26:01 -0400
|
||||
Subject: [PATCH] multipathd: Don't call update_map_pr unnecessarily
|
||||
|
||||
None of the calls to update_map_pr() outside of mpath_pr_event_handle()
|
||||
add any benefit. When update_map_pr() is called without a path, it tries
|
||||
to read the pr keys list on each usable path until it succeeds, and then
|
||||
checks the keys to see if they include the configured key.
|
||||
|
||||
In all cases where update_map_pr() is called outside of
|
||||
mpath_pr_event_handle(), after it is called, pr_register_active_paths()
|
||||
is called if a matching key was found. pr_register_active_paths() calls
|
||||
mpath_pr_event_handle() on each usable path, which calls update_map_pr()
|
||||
with a path, so it only checks that path. If a matching key is found, it
|
||||
registers a key on the current path. The result is that after
|
||||
pr_register_active_paths() is called, update_map_pr() will be called for
|
||||
each usable path, just like update_map_pr() did. So calling
|
||||
update_map_pr() first doesn't change the results for multipathd, it just
|
||||
adds duplicate work, so remove those calls.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 18 +++++++-----------
|
||||
1 file changed, 7 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 3b99bbe2..bd87851d 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -555,6 +555,8 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, i) {
|
||||
vector_foreach_slot (pgp->paths, pp, j) {
|
||||
+ if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ return;
|
||||
if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
|
||||
mpath_pr_event_handle(pp);
|
||||
}
|
||||
@@ -643,10 +645,7 @@ fail:
|
||||
|
||||
sync_map_state(mpp);
|
||||
|
||||
- if (mpp->prflag != PRFLAG_SET)
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag == PRFLAG_SET)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ pr_register_active_paths(mpp);
|
||||
|
||||
if (VECTOR_SIZE(offline_paths) != 0)
|
||||
handle_orphaned_offline_paths(offline_paths);
|
||||
@@ -1268,10 +1267,9 @@ rescan:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (retries >= 0) {
|
||||
- if (start_waiter)
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ if ((mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET) ||
|
||||
+ start_waiter)
|
||||
+ pr_register_active_paths(mpp);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
pp->dev, pp->dev_t, mpp->alias);
|
||||
return 0;
|
||||
@@ -2884,9 +2882,7 @@ configure (struct vectors * vecs)
|
||||
vector_foreach_slot(mpvec, mpp, i){
|
||||
if (remember_wwid(mpp->wwid) == 1)
|
||||
trigger_paths_udev_change(mpp, true);
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag == PRFLAG_SET)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ pr_register_active_paths(mpp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -0,0 +1,86 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 23 Jun 2025 19:06:12 -0400
|
||||
Subject: [PATCH] libmpathpersist: remove useless function
|
||||
send_prout_activepath
|
||||
|
||||
send_prout_activepath() creates a single separate thread that just calls
|
||||
prout_do_scsi_ioctl() and it doesn't take any advantage of the work
|
||||
being done in another thread. Remove the function and call
|
||||
prout_do_scsi_ioctl() directly.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 38 ++-------------------------------
|
||||
libmpathpersist/mpathpr.h | 2 --
|
||||
2 files changed, 2 insertions(+), 38 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 65a81faf..346abe71 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -589,9 +589,8 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
|
||||
condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
|
||||
found = true;
|
||||
- ret = send_prout_activepath(pp->dev, rq_servact,
|
||||
- rq_scope, rq_type,
|
||||
- paramp, noisy);
|
||||
+ ret = prout_do_scsi_ioctl(pp->dev, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
@@ -602,39 +601,6 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
|
||||
-int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
-{
|
||||
- struct prout_param param;
|
||||
- param.rq_servact = rq_servact;
|
||||
- param.rq_scope = rq_scope;
|
||||
- param.rq_type = rq_type;
|
||||
- param.paramp = paramp;
|
||||
- param.noisy = noisy;
|
||||
- param.status = -1;
|
||||
-
|
||||
- pthread_t thread;
|
||||
- pthread_attr_t attr;
|
||||
- int rc;
|
||||
-
|
||||
- memset(&thread, 0, sizeof(thread));
|
||||
- strlcpy(param.dev, dev, FILE_NAME_SIZE);
|
||||
- /* Initialize and set thread joinable attribute */
|
||||
- pthread_attr_init(&attr);
|
||||
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
-
|
||||
- rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(¶m));
|
||||
- if (rc){
|
||||
- condlog (3, "%s: failed to create thread %d", dev, rc);
|
||||
- return MPATH_PR_THREAD_ERROR;
|
||||
- }
|
||||
- /* Free attribute and wait for the other threads */
|
||||
- pthread_attr_destroy(&attr);
|
||||
- rc = pthread_join(thread, NULL);
|
||||
-
|
||||
- return (param.status);
|
||||
-}
|
||||
-
|
||||
int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index dd84e6d9..0d1075e5 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -41,8 +41,6 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
-int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
|
||||
int update_prflag(char *mapname, int set);
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
|
||||
@ -0,0 +1,72 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Mon, 5 May 2025 12:47:47 +0200
|
||||
Subject: [PATCH] libmpathpersist: fix memory leak in mpath_prout_rel()
|
||||
|
||||
Found by Fedora's static analysis [1].
|
||||
|
||||
[1] https://openscanhub.fedoraproject.org/task/51915/log/device-mapper-multipath-0.11.1-1.fc43/scan-results.html#def44
|
||||
|
||||
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 | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 346abe71..59159737 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -614,10 +614,10 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
struct prin_resp resp;
|
||||
- struct prout_param_descriptor *pamp;
|
||||
+ struct prout_param_descriptor *pamp = NULL;
|
||||
struct prin_resp *pr_buff;
|
||||
int length;
|
||||
- struct transportid *pptr;
|
||||
+ struct transportid *pptr = NULL;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -730,7 +730,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
pamp = (struct prout_param_descriptor *)malloc (length);
|
||||
if (!pamp){
|
||||
condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
|
||||
- goto out1;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
memset(pamp, 0, length);
|
||||
@@ -740,6 +740,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
|
||||
goto out1;
|
||||
}
|
||||
+ pptr = pamp->trnptid_list[0];
|
||||
|
||||
if (get_be64(mpp->reservation_key)){
|
||||
memcpy (pamp->key, &mpp->reservation_key, 8);
|
||||
@@ -751,11 +752,10 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
|
||||
if (status) {
|
||||
condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
|
||||
- goto out1;
|
||||
+ goto out2;
|
||||
}
|
||||
|
||||
pamp->num_transportid = 1;
|
||||
- pptr=pamp->trnptid_list[0];
|
||||
|
||||
for (i = 0; i < num; i++){
|
||||
if (get_be64(mpp->reservation_key) &&
|
||||
@@ -799,7 +799,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
|
||||
}
|
||||
|
||||
-
|
||||
+out2:
|
||||
free(pptr);
|
||||
out1:
|
||||
free (pamp);
|
||||
@ -0,0 +1,307 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 23 Jun 2025 20:40:48 -0400
|
||||
Subject: [PATCH] limpathpersist: redesign failed release workaround
|
||||
|
||||
The workaround for releasing a reservation held by a failed path
|
||||
(clearing all persistent reservation data and then reregistering all the
|
||||
keys) has several problems. It requires devices that support the READ
|
||||
FULL STATUS command and are capable of specifying TransportIDs with
|
||||
REGISTRATION commands (SIP_C), neither of which are mandatory to support
|
||||
SCSI Persistent Reservations. Non SIP_C devices will be left with no
|
||||
registered keys. Also, not all cleared keys are registered, just the
|
||||
ones going to the Target Port receiving the REGISTRATION command. To
|
||||
reregister all the keys, the code would have to also use the "All Target
|
||||
Ports" flag to register keys on different Target Ports, but this could
|
||||
end up registering keys on paths they aren't supposed to be on (for
|
||||
instance if one of the registered keys was only there because the path
|
||||
was down and it couldn't be released).
|
||||
|
||||
The redesign avoids these issues by only using mandatory Persistent
|
||||
Reservation commands, without extra optional parameters or flags, and
|
||||
only effects the keys of the multipath device it is being issued on.
|
||||
The new workaround is:
|
||||
1. Suspend the multipath device to prevent I/O
|
||||
2. Preempt the key to move the reservation to an available path. This
|
||||
also removes the registered keys from every path except the path
|
||||
issuing the PREEMPT command. Since the device is suspended, not I/O
|
||||
can go to these unregisted paths and fail.
|
||||
3. Release the reservation on the path that now holds it.
|
||||
4. Resume the device (since it no longer matters that most of the paths
|
||||
no longer have a registered key)
|
||||
5. Reregister the keys on all the paths.
|
||||
|
||||
If steps 3 or 4 fail, the code will attempt to reregister the keys, and
|
||||
then attempt (or possibly re-attempt) the resume.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 171 ++++++++++++++----------------
|
||||
libmpathpersist/mpathpr.h | 2 -
|
||||
libmultipath/libmultipath.version | 1 +
|
||||
3 files changed, 78 insertions(+), 96 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 59159737..7e60aa47 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -97,6 +97,11 @@ int libmpathpersist_exit(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int mpath_prout_common(struct multipath *mpp,int rq_servact,
|
||||
+ int rq_scope, unsigned int rq_type,
|
||||
+ struct prout_param_descriptor* paramp, int noisy,
|
||||
+ struct path **pptr);
|
||||
+
|
||||
int
|
||||
mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
struct prin_resp * resp, int noisy)
|
||||
@@ -283,6 +288,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
conf = get_multipath_config();
|
||||
select_reservation_key(conf, mpp);
|
||||
select_all_tg_pt(conf, mpp);
|
||||
+ select_skip_kpartx(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
memcpy(&prkey, paramp->sa_key, 8);
|
||||
@@ -319,7 +325,8 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_PREE_SA :
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
- ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
+ ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
+ paramp, noisy, NULL);
|
||||
break;
|
||||
case MPATH_PROUT_REL_SA:
|
||||
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
@@ -571,8 +578,10 @@ void * mpath_prout_pthread_fn(void *p)
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
-int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
|
||||
+static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type,
|
||||
+ struct prout_param_descriptor* paramp, int noisy,
|
||||
+ struct path **pptr)
|
||||
{
|
||||
int i,j, ret;
|
||||
struct pathgroup *pgp = NULL;
|
||||
@@ -591,6 +600,8 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
found = true;
|
||||
ret = prout_do_scsi_ioctl(pp->dev, rq_servact, rq_scope,
|
||||
rq_type, paramp, noisy);
|
||||
+ if (ret == MPATH_PR_SUCCESS && pptr)
|
||||
+ *pptr = pp;
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
@@ -610,14 +621,12 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
struct path *pp = NULL;
|
||||
int active_pathcount = 0;
|
||||
pthread_attr_t attr;
|
||||
- int rc, found = 0;
|
||||
+ int rc;
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
struct prin_resp resp;
|
||||
- struct prout_param_descriptor *pamp = NULL;
|
||||
- struct prin_resp *pr_buff;
|
||||
- int length;
|
||||
- struct transportid *pptr = NULL;
|
||||
+ uint16_t udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
+ bool did_resume = false;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -707,104 +716,78 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
|
||||
+ /*
|
||||
+ * Cannot free the reservation because the path that is holding it
|
||||
+ * is not usable. Workaround this by:
|
||||
+ * 1. Suspending the device
|
||||
+ * 2. Preempting the reservation to move it to a usable path
|
||||
+ * (this removes the registered keys on all paths except the
|
||||
+ * preempting one. Since the device is suspended, no IO can
|
||||
+ * go to these unregistered paths and fail).
|
||||
+ * 3. Releasing the reservation on the path that now holds it.
|
||||
+ * 4. Resuming the device (since it no longer matters that most of
|
||||
+ * that paths no longer have a registered key)
|
||||
+ * 5. Reregistering keys on all the paths
|
||||
+ */
|
||||
|
||||
- pr_buff = mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
|
||||
- if (!pr_buff){
|
||||
- condlog (0, "%s: failed to alloc pr in response buffer.", mpp->wwid);
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_SUSPEND, mpp->alias, 0)) {
|
||||
+ condlog(0, "%s: release: failed to suspend dm device.", mpp->wwid);
|
||||
return MPATH_PR_OTHER;
|
||||
}
|
||||
|
||||
- status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
|
||||
-
|
||||
- if (status != MPATH_PR_SUCCESS){
|
||||
- condlog (0, "%s: pr in read full status command failed.", mpp->wwid);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
|
||||
- if (0 == num){
|
||||
- goto out;
|
||||
- }
|
||||
- length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
|
||||
-
|
||||
- pamp = (struct prout_param_descriptor *)malloc (length);
|
||||
- if (!pamp){
|
||||
- condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- memset(pamp, 0, length);
|
||||
-
|
||||
- pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
|
||||
- if (!pamp->trnptid_list[0]){
|
||||
- condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
|
||||
- goto out1;
|
||||
+ memset(paramp, 0, sizeof(*paramp));
|
||||
+ memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
+ memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
|
||||
+ paramp, noisy, &pp);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: release: pr preempt command failed.", mpp->wwid);
|
||||
+ goto fail_resume;
|
||||
}
|
||||
- pptr = pamp->trnptid_list[0];
|
||||
|
||||
- if (get_be64(mpp->reservation_key)){
|
||||
- memcpy (pamp->key, &mpp->reservation_key, 8);
|
||||
- condlog (3, "%s: reservation key set.", mpp->wwid);
|
||||
+ memset(paramp, 0, sizeof(*paramp));
|
||||
+ memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
+ status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: release on alternate path failed.", mpp->wwid);
|
||||
+ goto out_reregister;
|
||||
}
|
||||
|
||||
- status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
|
||||
- rq_scope, rq_type, pamp, noisy);
|
||||
-
|
||||
- if (status) {
|
||||
- condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
|
||||
- goto out2;
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
+ condlog(0, "%s release: failed to resume dm device.", mpp->wwid);
|
||||
+ /*
|
||||
+ * leave status set to MPATH_PR_SUCCESS, we will have another
|
||||
+ * chance to resume the device.
|
||||
+ */
|
||||
+ goto out_reregister;
|
||||
}
|
||||
+ did_resume = true;
|
||||
|
||||
- pamp->num_transportid = 1;
|
||||
-
|
||||
- for (i = 0; i < num; i++){
|
||||
- if (get_be64(mpp->reservation_key) &&
|
||||
- memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
|
||||
- &mpp->reservation_key, 8)){
|
||||
- /*register with tarnsport id*/
|
||||
- memset(pamp, 0, length);
|
||||
- pamp->trnptid_list[0] = pptr;
|
||||
- memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
|
||||
- memcpy (pamp->sa_key,
|
||||
- pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
|
||||
- pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
|
||||
- pamp->num_transportid = 1;
|
||||
-
|
||||
- memcpy (pamp->trnptid_list[0],
|
||||
- &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
|
||||
- sizeof (struct transportid));
|
||||
- status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
|
||||
- pamp, noisy);
|
||||
-
|
||||
- pamp->sa_flags = 0;
|
||||
- memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
|
||||
- memset (pamp->sa_key, 0, 8);
|
||||
- pamp->num_transportid = 0;
|
||||
- status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
|
||||
- pamp, noisy);
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- if (get_be64(mpp->reservation_key))
|
||||
- found = 1;
|
||||
- }
|
||||
-
|
||||
-
|
||||
- }
|
||||
+out_reregister:
|
||||
+ memset(paramp, 0, sizeof(*paramp));
|
||||
+ memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
+ rc = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope, rq_type,
|
||||
+ paramp, noisy);
|
||||
+ if (rc != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: release: failed to reregister paths.", mpp->wwid);
|
||||
|
||||
- if (found){
|
||||
- memset (pamp, 0, length);
|
||||
- memcpy (pamp->sa_key, &mpp->reservation_key, 8);
|
||||
- memset (pamp->key, 0, 8);
|
||||
- status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
|
||||
+ /*
|
||||
+ * If we failed releasing the reservation or resuming earlier
|
||||
+ * try resuming now. Otherwise, return with the reregistering status
|
||||
+ * This means we will report failure, even though the resevation
|
||||
+ * has been released, since the keys were not reregistered.
|
||||
+ */
|
||||
+ if (did_resume)
|
||||
+ return rc;
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
+ status = rc;
|
||||
+fail_resume:
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
+ condlog(0, "%s: release: failed to resume dm device.", mpp->wwid);
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ status = MPATH_PR_OTHER;
|
||||
}
|
||||
-
|
||||
-out2:
|
||||
- free(pptr);
|
||||
-out1:
|
||||
- free (pamp);
|
||||
-out:
|
||||
- free (pr_buff);
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 0d1075e5..85eac1c7 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -37,8 +37,6 @@ void dumpHex(const char* , int len, int no_ascii);
|
||||
|
||||
int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
-int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
|
||||
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
|
||||
index 46907278..5340957c 100644
|
||||
--- a/libmultipath/libmultipath.version
|
||||
+++ b/libmultipath/libmultipath.version
|
||||
@@ -301,6 +301,7 @@ global:
|
||||
LIBMULTIPATH_9.1.2 {
|
||||
global:
|
||||
cleanup_mutex;
|
||||
+ select_skip_kpartx;
|
||||
} LIBMULTIPATH_9.1.1;
|
||||
|
||||
LIBMULTIPATH_9.1.3 {
|
||||
@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 8 Jul 2025 16:23:13 -0400
|
||||
Subject: [PATCH] libmpathpersist: fail the release if all threads fail
|
||||
|
||||
If none of the threads succeeds in issuing the release, simply return
|
||||
failure, instead of trying the workaround.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 7e60aa47..04a08b76 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -627,6 +627,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
struct prin_resp resp;
|
||||
uint16_t udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
bool did_resume = false;
|
||||
+ bool all_threads_failed;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -688,15 +689,22 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
}
|
||||
|
||||
+ all_threads_failed = true;
|
||||
for (i = 0; i < count; i++){
|
||||
/* check thread status here and return the status */
|
||||
|
||||
- if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
+ if (thread[i].param.status == MPATH_PR_SUCCESS)
|
||||
+ all_threads_failed = false;
|
||||
+ else if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
status = MPATH_PR_RESERV_CONFLICT;
|
||||
- else if (status == MPATH_PR_SUCCESS
|
||||
- && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
}
|
||||
+ if (all_threads_failed) {
|
||||
+ condlog(0, "%s: all threads failed to release reservation.",
|
||||
+ mpp->wwid);
|
||||
+ return status;
|
||||
+ }
|
||||
|
||||
status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
if (status != MPATH_PR_SUCCESS){
|
||||
@ -0,0 +1,124 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 27 Jun 2025 18:17:40 -0400
|
||||
Subject: [PATCH] limpathpersist: Handle changing key corner case
|
||||
|
||||
When you change the reservation key of a registered multipath device,
|
||||
some of paths might be down or even deleted since you originally
|
||||
registered the key. libmpathpersist won't be able to change these
|
||||
registrations. This can be a problem if the path that is down is holding
|
||||
the reservation. Other nodes will assume that the reservation is now
|
||||
under your new key, when it is still under the old one. If they try to
|
||||
preempt the reservation, they will succeed. But they will just
|
||||
unregister all the paths with the new key. They won't take over the
|
||||
reservation, and if the path holding it comes back up, it will still be
|
||||
able to write to the device.
|
||||
|
||||
To avoid this, after libmpathpersist changes the key of a registered
|
||||
device, it now checks to see if its old key is still holding the
|
||||
reservation. If it is, limpathpersist preempts the reservation.
|
||||
Currently this only works on REGISTER commands, not REGISTER AND IGNORE
|
||||
ones. A future patch will add that capability.
|
||||
|
||||
I should note that this relies on the fact that libmpathpersist has
|
||||
never worked correctly if two nodes use the same reservation key for the
|
||||
same device. If another node used the same key, it could be the one
|
||||
holding the reservation, and preempting the reservation would deregister
|
||||
it. However, multipathd has always relied on the fact that two nodes
|
||||
will not use the same registration key to know if it is safe to register
|
||||
a key on a path that was just added or just came back up. If there is
|
||||
already a registered key matching the configured key, multipathd assumes
|
||||
that the device has not been preempted, and registers the key on the
|
||||
path. If there are no keys matching the configured key, multipathd
|
||||
assumes that the device has been preempted, and won't register a key.
|
||||
Again, if another node shared the same key, multipathd could registered
|
||||
paths on a node that had been preempted.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 58 ++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 57 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 04a08b76..c09fbbe7 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -425,6 +425,60 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid)
|
||||
return MPATH_PR_SUCCESS ;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * If you are changing the key registered to a device, and that device is
|
||||
+ * holding the reservation on a path that couldn't get its key updated,
|
||||
+ * either because it is down or no longer part of the multipath device,
|
||||
+ * you need to preempt the reservation to a usable path with the new key
|
||||
+ */
|
||||
+void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
+ int noisy)
|
||||
+{
|
||||
+ uint8_t zero[8] = {0};
|
||||
+ struct prin_resp resp = {0};
|
||||
+ int rq_scope;
|
||||
+ unsigned int rq_type;
|
||||
+ struct prout_param_descriptor paramp = {0};
|
||||
+ int status;
|
||||
+
|
||||
+ /*
|
||||
+ * If you previously didn't have a key registered or you didn't
|
||||
+ * switch to a different key, there's no need to preempt. Also, you
|
||||
+ * can't preempt if you no longer have a registered key
|
||||
+ */
|
||||
+ if (memcmp(key, zero, 8) == 0 || memcmp(sa_key, zero, 8) == 0 ||
|
||||
+ memcmp(key, sa_key, 8) == 0)
|
||||
+ return;
|
||||
+
|
||||
+ status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: register: pr in read reservation command failed.", mpp->wwid);
|
||||
+ return;
|
||||
+ }
|
||||
+ /* If there is no reservation, there's nothing to preempt */
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return;
|
||||
+ /*
|
||||
+ * If there reservation is not held by the old key, you don't
|
||||
+ * want to preempt it
|
||||
+ */
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) != 0)
|
||||
+ return;
|
||||
+ /* Assume this key is being held by an inaccessable path on this
|
||||
+ * node. libmpathpersist has never worked if multiple nodes share
|
||||
+ * the same reservation key for a device
|
||||
+ */
|
||||
+ rq_type = resp.prin_descriptor.prin_readresv.scope_type & MPATH_PR_TYPE_MASK;
|
||||
+ rq_scope = (resp.prin_descriptor.prin_readresv.scope_type & MPATH_PR_SCOPE_MASK) >> 4;
|
||||
+ memcpy(paramp.key, sa_key, 8);
|
||||
+ memcpy(paramp.sa_key, key, 8);
|
||||
+ status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
|
||||
+ ¶mp, noisy, NULL);
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: register: pr preempt command failed.",
|
||||
+ mpp->wwid);
|
||||
+}
|
||||
+
|
||||
int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
@@ -564,6 +618,8 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
}
|
||||
|
||||
@@ -624,7 +680,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int rc;
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
- struct prin_resp resp;
|
||||
+ struct prin_resp resp = {0};
|
||||
uint16_t udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
bool did_resume = false;
|
||||
bool all_threads_failed;
|
||||
@ -0,0 +1,70 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 29 Nov 2022 22:56:48 -0600
|
||||
Subject: [PATCH] libmpathpersist: fix command keyword ordering
|
||||
|
||||
When libmpathpersist was communicating with multipathd, it wasn't using
|
||||
the correct keyword order for the commands, as specified in the CLI
|
||||
commands reference. Since commit f812466f, multipathd requires commands
|
||||
to be ordered correctly. Fix the ordering.
|
||||
|
||||
Fixes: f812466f ("multipathd: more robust command parsing")
|
||||
Reported-by: miaoguanqin <miaoguanqin@huawei.com>
|
||||
Cc: lixiaokeng <lixiaokeng@huawei.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmpathpersist/mpath_updatepr.c | 23 ++++++++++++-----------
|
||||
1 file changed, 12 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index 0aca28eb..af2c5549 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "mpathpr.h"
|
||||
|
||||
|
||||
-static int do_update_pr(char *alias, char *arg)
|
||||
+static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
{
|
||||
int fd;
|
||||
char str[256];
|
||||
@@ -31,7 +31,10 @@ static int do_update_pr(char *alias, char *arg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
- snprintf(str,sizeof(str),"map %s %s", alias, arg);
|
||||
+ if (key)
|
||||
+ snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key);
|
||||
+ else
|
||||
+ snprintf(str,sizeof(str),"%s map %s", cmd, alias);
|
||||
condlog (2, "%s: pr message=%s", alias, str);
|
||||
if (send_packet(fd, str) != 0) {
|
||||
condlog(2, "%s: message=%s send error=%d", alias, str, errno);
|
||||
@@ -56,18 +59,16 @@ static int do_update_pr(char *alias, char *arg)
|
||||
}
|
||||
|
||||
int update_prflag(char *mapname, int set) {
|
||||
- return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus");
|
||||
+ return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus",
|
||||
+ NULL);
|
||||
}
|
||||
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags) {
|
||||
char str[256];
|
||||
- char *flagstr = "";
|
||||
|
||||
- if (sa_flags & MPATH_F_APTPL_MASK)
|
||||
- flagstr = ":aptpl";
|
||||
- if (prkey)
|
||||
- sprintf(str, "setprkey key %" PRIx64 "%s", prkey, flagstr);
|
||||
- else
|
||||
- sprintf(str, "unsetprkey");
|
||||
- return do_update_pr(mapname, str);
|
||||
+ if (!prkey)
|
||||
+ return do_update_pr(mapname, "unsetprkey", NULL);
|
||||
+ sprintf(str, "%" PRIx64 "%s", prkey,
|
||||
+ (sa_flags & MPATH_F_APTPL_MASK) ? ":aptpl" : "");
|
||||
+ return do_update_pr(mapname, "setprkey", str);
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Wilck <mwilck@suse.com>
|
||||
Date: Mon, 2 Jan 2023 12:39:36 +0100
|
||||
Subject: [PATCH] libmpathpersist: use conf->timeout for updating persistent
|
||||
reservations
|
||||
|
||||
On systems with many LUNs, multipathd may fail to respond within the
|
||||
default timeout to a "setprkey" command because the vecs lock is held
|
||||
by the path checker. Honor the globally configured uxsock timeout in
|
||||
libmpathpersist.
|
||||
|
||||
Reported-by: boposki (github.com/opensvc/multipath-tools/pull/58)
|
||||
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_updatepr.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index af2c5549..39dfa218 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <mpath_persist.h>
|
||||
#include "debug.h"
|
||||
#include "mpath_cmd.h"
|
||||
+#include "vector.h"
|
||||
+#include "config.h"
|
||||
#include "uxsock.h"
|
||||
#include "memory.h"
|
||||
#include "mpathpr.h"
|
||||
@@ -24,6 +26,12 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
char str[256];
|
||||
char *reply;
|
||||
int ret = 0;
|
||||
+ int timeout;
|
||||
+ struct config *conf;
|
||||
+
|
||||
+ conf = get_multipath_config();
|
||||
+ timeout = conf->uxsock_timeout;
|
||||
+ put_multipath_config(conf);
|
||||
|
||||
fd = mpath_connect();
|
||||
if (fd == -1) {
|
||||
@@ -41,7 +49,7 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
mpath_disconnect(fd);
|
||||
return -1;
|
||||
}
|
||||
- ret = recv_packet(fd, &reply, DEFAULT_REPLY_TIMEOUT);
|
||||
+ ret = recv_packet(fd, &reply, timeout);
|
||||
if (ret < 0) {
|
||||
condlog(2, "%s: message=%s recv error=%d", alias, str, errno);
|
||||
ret = -1;
|
||||
@ -0,0 +1,180 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 30 Jun 2025 20:10:59 -0400
|
||||
Subject: [PATCH] libmapthpersist: Handle REGISTER AND IGNORE changing key
|
||||
corner case
|
||||
|
||||
When you use REGISTER to change the reservation key of a registered
|
||||
multipath device, where the path holding the reservation is down,
|
||||
libmpathpersist will PREEMPT the failed path to move the reservation to
|
||||
a usable path, so the reservation key will be updated. However, when you
|
||||
use REGISTER AND IGNORE, you don't pass in the old key, so
|
||||
libmpathpersist can't use it to check against the key holding the
|
||||
reservation, which is necessary to know if it needs to PREEMPT.
|
||||
|
||||
Since the SCSI spec says that devices must ignore any passed-in key on
|
||||
REGISTER AND IGNORE, libmpathpersist can still use it to pass in the old
|
||||
key value. But unlike with REGISTER, the command won't fail if device
|
||||
isn't actually registered with the old key, so libmpathpersist needs to
|
||||
check that itself. To do this, it calls update_map_pr() just like
|
||||
multipathd does to check that the device is registered before
|
||||
registering new paths. However, libmpathpersist doesn't track the
|
||||
persistent reservation state like multipathd, so it needs to ask
|
||||
multipathd if it thinks the device is registered, using the "get
|
||||
prstatus map <map>" command.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 20 +++++++++++
|
||||
libmpathpersist/mpath_updatepr.c | 57 ++++++++++++++++++++++++--------
|
||||
libmpathpersist/mpathpr.h | 1 +
|
||||
3 files changed, 64 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index c09fbbe7..324d88a2 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -271,6 +271,23 @@ int __mpath_persistent_reserve_in (int fd, int rq_servact,
|
||||
resp, noisy);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * for MPATH_PROUT_REG_IGN_SA, we use the ignored paramp->key to store the
|
||||
+ * currently registered key.
|
||||
+ */
|
||||
+static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
+{
|
||||
+ memset(key, 0, 8);
|
||||
+ if (!get_be64(mpp->reservation_key))
|
||||
+ return;
|
||||
+ if (get_prflag(mpp->alias) == PRFLAG_UNSET)
|
||||
+ return;
|
||||
+ update_map_pr(mpp, NULL);
|
||||
+ if (mpp->prflag != PRFLAG_SET)
|
||||
+ return;
|
||||
+ memcpy(key, &mpp->reservation_key, 8);
|
||||
+}
|
||||
+
|
||||
static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
struct prout_param_descriptor *paramp, int noisy)
|
||||
@@ -291,6 +308,9 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
select_skip_kpartx(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
+ if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
+ set_ignored_key(mpp, paramp->key);
|
||||
+
|
||||
memcpy(&prkey, paramp->sa_key, 8);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index 39dfa218..1172ec8a 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -18,14 +18,13 @@
|
||||
#include "uxsock.h"
|
||||
#include "memory.h"
|
||||
#include "mpathpr.h"
|
||||
+#include "structs.h"
|
||||
|
||||
|
||||
-static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
+static char *do_pr(char *alias, char *str)
|
||||
{
|
||||
int fd;
|
||||
- char str[256];
|
||||
char *reply;
|
||||
- int ret = 0;
|
||||
int timeout;
|
||||
struct config *conf;
|
||||
|
||||
@@ -36,24 +35,35 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
fd = mpath_connect();
|
||||
if (fd == -1) {
|
||||
condlog (0, "ux socket connect error");
|
||||
- return -1;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
- if (key)
|
||||
- snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key);
|
||||
- else
|
||||
- snprintf(str,sizeof(str),"%s map %s", cmd, alias);
|
||||
condlog (2, "%s: pr message=%s", alias, str);
|
||||
if (send_packet(fd, str) != 0) {
|
||||
condlog(2, "%s: message=%s send error=%d", alias, str, errno);
|
||||
mpath_disconnect(fd);
|
||||
- return -1;
|
||||
+ return NULL;
|
||||
}
|
||||
- ret = recv_packet(fd, &reply, timeout);
|
||||
- if (ret < 0) {
|
||||
+ if (recv_packet(fd, &reply, timeout) < 0)
|
||||
condlog(2, "%s: message=%s recv error=%d", alias, str, errno);
|
||||
- ret = -1;
|
||||
- } else {
|
||||
+
|
||||
+ mpath_disconnect(fd);
|
||||
+ return reply;
|
||||
+}
|
||||
+
|
||||
+static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
+{
|
||||
+ char str[256];
|
||||
+ char *reply = NULL;
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (key)
|
||||
+ snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key);
|
||||
+ else
|
||||
+ snprintf(str,sizeof(str),"%s map %s", cmd, alias);
|
||||
+
|
||||
+ reply = do_pr(alias, str);
|
||||
+ if (reply) {
|
||||
condlog (2, "%s: message=%s reply=%s", alias, str, reply);
|
||||
if (reply && strncmp(reply,"ok", 2) == 0)
|
||||
ret = 0;
|
||||
@@ -62,10 +72,29 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
}
|
||||
|
||||
free(reply);
|
||||
- mpath_disconnect(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+int get_prflag(char *mapname) {
|
||||
+ char str[256];
|
||||
+ char *reply;
|
||||
+ int prflag;
|
||||
+
|
||||
+ snprintf(str, sizeof(str), "getprstatus map %s", mapname);
|
||||
+ reply = do_pr(mapname, str);
|
||||
+ if (!reply)
|
||||
+ prflag = PRFLAG_UNKNOWN;
|
||||
+ else if (strncmp(reply,"unset", 5) == 0)
|
||||
+ prflag = PRFLAG_UNSET;
|
||||
+ else if (strncmp(reply,"set", 3) == 0)
|
||||
+ prflag = PRFLAG_SET;
|
||||
+ else
|
||||
+ prflag = PRFLAG_UNKNOWN;
|
||||
+
|
||||
+ free(reply);
|
||||
+ return prflag;
|
||||
+}
|
||||
+
|
||||
int update_prflag(char *mapname, int set) {
|
||||
return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus",
|
||||
NULL);
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 85eac1c7..35ef82c8 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -42,6 +42,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
|
||||
int update_prflag(char *mapname, int set);
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
|
||||
+int get_prflag(char *mapname);
|
||||
#define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
|
||||
void * mpath_alloc_prin_response(int prin_sa);
|
||||
int update_map_pr(struct multipath *mpp, struct path *pp);
|
||||
242
SOURCES/0167-libmultipath-rename-prflag_value-enums.patch
Normal file
242
SOURCES/0167-libmultipath-rename-prflag_value-enums.patch
Normal file
@ -0,0 +1,242 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 1 Jul 2025 16:45:00 -0400
|
||||
Subject: [PATCH] libmultipath: rename prflag_value enums
|
||||
|
||||
These will also be used by another variable, so make their name more
|
||||
generic.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 16 ++++++++--------
|
||||
libmpathpersist/mpath_updatepr.c | 8 ++++----
|
||||
libmultipath/structs.h | 8 ++++----
|
||||
multipathd/cli_handlers.c | 21 +++++++++++----------
|
||||
multipathd/main.c | 16 ++++++++--------
|
||||
5 files changed, 35 insertions(+), 34 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 324d88a2..2935be76 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -280,10 +280,10 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
memset(key, 0, 8);
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
return;
|
||||
- if (get_prflag(mpp->alias) == PRFLAG_UNSET)
|
||||
+ if (get_prflag(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag != PRFLAG_SET)
|
||||
+ if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
memcpy(key, &mpp->reservation_key, 8);
|
||||
}
|
||||
@@ -908,16 +908,16 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
struct prin_resp *resp;
|
||||
unsigned int i;
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
- bool was_set = (mpp->prflag == PRFLAG_SET);
|
||||
+ bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
- if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
return MPATH_PR_SKIP;
|
||||
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
{
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
return MPATH_PR_SKIP;
|
||||
}
|
||||
@@ -943,11 +943,11 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
goto out;
|
||||
}
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
|
||||
if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
{
|
||||
@@ -975,7 +975,7 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
|
||||
if (isFound)
|
||||
{
|
||||
- mpp->prflag = PRFLAG_SET;
|
||||
+ mpp->prflag = PR_SET;
|
||||
condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
mpp->alias);
|
||||
} else
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index 1172ec8a..00748264 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -83,13 +83,13 @@ int get_prflag(char *mapname) {
|
||||
snprintf(str, sizeof(str), "getprstatus map %s", mapname);
|
||||
reply = do_pr(mapname, str);
|
||||
if (!reply)
|
||||
- prflag = PRFLAG_UNKNOWN;
|
||||
+ prflag = PR_UNKNOWN;
|
||||
else if (strncmp(reply,"unset", 5) == 0)
|
||||
- prflag = PRFLAG_UNSET;
|
||||
+ prflag = PR_UNSET;
|
||||
else if (strncmp(reply,"set", 3) == 0)
|
||||
- prflag = PRFLAG_SET;
|
||||
+ prflag = PR_SET;
|
||||
else
|
||||
- prflag = PRFLAG_UNKNOWN;
|
||||
+ prflag = PR_UNKNOWN;
|
||||
|
||||
free(reply);
|
||||
return prflag;
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 0846e833..f47683c1 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -383,10 +383,10 @@ struct path {
|
||||
typedef int (pgpolicyfn) (struct multipath *, vector);
|
||||
|
||||
|
||||
-enum prflag_value {
|
||||
- PRFLAG_UNKNOWN,
|
||||
- PRFLAG_UNSET,
|
||||
- PRFLAG_SET,
|
||||
+enum pr_value {
|
||||
+ PR_UNKNOWN,
|
||||
+ PR_UNSET,
|
||||
+ PR_SET,
|
||||
};
|
||||
|
||||
struct multipath {
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index aca8e2df..1e735aab 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1279,14 +1279,15 @@ cli_shutdown (void * v, char ** reply, int * len, void * data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const char * const pr_str[] = {
|
||||
+ [PR_UNKNOWN] = "unknown\n",
|
||||
+ [PR_UNSET] = "unset\n",
|
||||
+ [PR_SET] = "set\n",
|
||||
+};
|
||||
+
|
||||
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",
|
||||
- };
|
||||
struct multipath * mpp;
|
||||
struct vectors * vecs = (struct vectors *)data;
|
||||
char * param = get_keyparam(v, MAP);
|
||||
@@ -1298,7 +1299,7 @@ cli_getprstatus (void * v, char ** reply, int * len, void * data)
|
||||
if (!mpp)
|
||||
return 1;
|
||||
|
||||
- *len = asprintf(reply, "%s", prflag_str[mpp->prflag]);
|
||||
+ *len = asprintf(reply, "%s", pr_str[mpp->prflag]);
|
||||
if (*len < 0)
|
||||
return 1;
|
||||
|
||||
@@ -1321,8 +1322,8 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data)
|
||||
if (!mpp)
|
||||
return 1;
|
||||
|
||||
- if (mpp->prflag != PRFLAG_SET) {
|
||||
- mpp->prflag = PRFLAG_SET;
|
||||
+ if (mpp->prflag != PR_SET) {
|
||||
+ mpp->prflag = PR_SET;
|
||||
condlog(2, "%s: prflag set", param);
|
||||
}
|
||||
|
||||
@@ -1344,8 +1345,8 @@ cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
|
||||
if (!mpp)
|
||||
return 1;
|
||||
|
||||
- if (mpp->prflag != PRFLAG_UNSET) {
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ if (mpp->prflag != PR_UNSET) {
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
condlog(2, "%s: prflag unset", param);
|
||||
}
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index bd87851d..56050a06 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -555,7 +555,7 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, i) {
|
||||
vector_foreach_slot (pgp->paths, pp, j) {
|
||||
- if (mpp->prflag == PRFLAG_UNSET)
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
return;
|
||||
if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
|
||||
mpath_pr_event_handle(pp);
|
||||
@@ -1139,7 +1139,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 = PRFLAG_UNSET;
|
||||
+ unsigned char prflag = PR_UNSET;
|
||||
|
||||
/*
|
||||
* need path UID to go any further
|
||||
@@ -1267,7 +1267,7 @@ rescan:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (retries >= 0) {
|
||||
- if ((mpp->prflag == PRFLAG_SET && prflag != PRFLAG_SET) ||
|
||||
+ if ((mpp->prflag == PR_SET && prflag != PR_SET) ||
|
||||
start_waiter)
|
||||
pr_register_active_paths(mpp);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
@@ -2535,7 +2535,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
}
|
||||
|
||||
if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||||
- if (pp->mpp->prflag != PRFLAG_UNSET) {
|
||||
+ if (pp->mpp->prflag != PR_UNSET) {
|
||||
int prflag = pp->mpp->prflag;
|
||||
/*
|
||||
* Check Persistent Reservation.
|
||||
@@ -2543,8 +2543,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
condlog(2, "%s: checking persistent "
|
||||
"reservation registration", pp->dev);
|
||||
mpath_pr_event_handle(pp);
|
||||
- if (pp->mpp->prflag == PRFLAG_SET &&
|
||||
- prflag != PRFLAG_SET)
|
||||
+ if (pp->mpp->prflag == PR_SET &&
|
||||
+ prflag != PR_SET)
|
||||
pr_register_active_paths(pp->mpp);
|
||||
}
|
||||
}
|
||||
@@ -3728,14 +3728,14 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
struct prout_param_descriptor *param;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
- mpp->prflag = PRFLAG_UNSET;
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
return;
|
||||
|
||||
- if (mpp->prflag != PRFLAG_SET)
|
||||
+ if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
|
||||
param = (struct prout_param_descriptor *)MALLOC(sizeof(struct prout_param_descriptor));
|
||||
@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 3 Jul 2025 14:09:08 -0400
|
||||
Subject: [PATCH] libmpathpersist: use a switch statement for prout command
|
||||
finalizing
|
||||
|
||||
Change the code at the end of do_mpath_persistent_reserve_out() to
|
||||
use a switch statement instead of multiple if statements. A future
|
||||
patch will add more actions here, and a switch statement looks cleaner.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 11 ++++++++---
|
||||
1 file changed, 8 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 2935be76..12888f90 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -356,15 +356,20 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
goto out1;
|
||||
}
|
||||
|
||||
- if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
|
||||
- (rq_servact == MPATH_PROUT_REG_IGN_SA)))
|
||||
+ if (ret != MPATH_PR_SUCCESS)
|
||||
+ goto out1;
|
||||
+
|
||||
+ switch(rq_servact)
|
||||
{
|
||||
+ case MPATH_PROUT_REG_SA:
|
||||
+ case MPATH_PROUT_REG_IGN_SA:
|
||||
if (prkey == 0) {
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
} else
|
||||
update_prflag(alias, 1);
|
||||
- } else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) {
|
||||
+ break;
|
||||
+ case MPATH_PROUT_CLEAR_SA:
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
}
|
||||
@ -0,0 +1,477 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 2 Jul 2025 12:39:08 -0400
|
||||
Subject: [PATCH] libmpathpersist: Add safety check for preempting on key
|
||||
change
|
||||
|
||||
When a reservation key is changed from one non-zero value to another,
|
||||
libmpathpersist checks if the old key is still holding the reservation,
|
||||
and preempts it if it is. This was only safe if two nodes never share
|
||||
the same key. If a node uses the same key as another node that is
|
||||
holding the reservation, and switches keys so that it no longer matches,
|
||||
it will end up preempting the reservation. This is clearly unexpected
|
||||
behavior, and it can come about by a simple accident of registering a
|
||||
device with the wrong key, and then immediately fixing it.
|
||||
|
||||
To handle this, add code to track if a device is the reservation holder
|
||||
to multipathd. multipathd now has three new commands "getprhold",
|
||||
"setprhold", and "unsetprhold". These commands work like the equivalent
|
||||
*prstatus commands. libmpathpersist calls setprhold on RESERVE commands
|
||||
and PREEMPT commands when the preempted key is holding the reservation
|
||||
and unsetprhold on RELEASE commands. Also, calling unsetprflag causes
|
||||
prhold to be unset as well, so CLEAR commands and REGISTER commands with
|
||||
a 0x0 service action key will also unset prhold. libmpathpersist() will
|
||||
also unset prhold if it notices that the device cannot be holding a
|
||||
reservation in preempt_missing_path().
|
||||
|
||||
When a new multipath device is created, its initial prhold state is
|
||||
PR_UNKNOWN until it checks the current reservation, just like with
|
||||
prflag. If multipathd ever finds that a device's registration has been
|
||||
preempted or cleared in update_map_pr(), it unsets prhold, just like
|
||||
with prflag.
|
||||
|
||||
Now, before libmpathpersist preempts a reservation when changing keys
|
||||
it also checks if multipathd thinks that the device is holding
|
||||
the reservation. If it does not, then libmpathpersist won't preempt
|
||||
the key. It will assume that another node is holding the reservation
|
||||
with the same key.
|
||||
|
||||
I should note that this safety check only stops a node not holding the
|
||||
reservation from preempting the node holding the reservation. If the
|
||||
node holding the reservation changes its key, but it fails to change the
|
||||
resevation key, because that path is down or gone, it will still issue
|
||||
the preempt to move the reservation to a usable path, even if another
|
||||
node is using the same key. This will remove the registrations for that
|
||||
other node. It also will not work correctly if multipathd stops tracking
|
||||
a device for some reason. It's only a best-effort safety check.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 84 +++++++++++++++++++++++++++-----
|
||||
libmpathpersist/mpath_updatepr.c | 17 ++++++-
|
||||
libmpathpersist/mpathpr.h | 2 +
|
||||
libmultipath/structs.h | 1 +
|
||||
multipathd/cli.c | 7 ++-
|
||||
multipathd/cli.h | 6 +++
|
||||
multipathd/cli_handlers.c | 54 ++++++++++++++++++++
|
||||
multipathd/cli_handlers.h | 3 ++
|
||||
multipathd/main.c | 36 +++++++++++++-
|
||||
9 files changed, 194 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 12888f90..e47e9190 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -271,19 +271,39 @@ int __mpath_persistent_reserve_in (int fd, int rq_servact,
|
||||
resp, noisy);
|
||||
}
|
||||
|
||||
+static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
+ int noisy)
|
||||
+{
|
||||
+ struct prin_resp resp = {0};
|
||||
+ int status;
|
||||
+
|
||||
+ status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: pr in read reservation command failed.",
|
||||
+ mpp->wwid);
|
||||
+ return YNU_UNDEF;
|
||||
+ }
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return YNU_NO;
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0)
|
||||
+ return YNU_YES;
|
||||
+ return YNU_NO;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* for MPATH_PROUT_REG_IGN_SA, we use the ignored paramp->key to store the
|
||||
- * currently registered key.
|
||||
+ * currently registered key for use in preempt_missing_path(), but only if
|
||||
+ * the key is holding the reservation.
|
||||
*/
|
||||
static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
{
|
||||
memset(key, 0, 8);
|
||||
if (!get_be64(mpp->reservation_key))
|
||||
return;
|
||||
- if (get_prflag(mpp->alias) == PR_UNSET)
|
||||
+ if (get_prhold(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
- update_map_pr(mpp, NULL);
|
||||
- if (mpp->prflag != PR_SET)
|
||||
+ if (reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key,
|
||||
+ 0) == YNU_NO)
|
||||
return;
|
||||
memcpy(key, &mpp->reservation_key, 8);
|
||||
}
|
||||
@@ -297,6 +317,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int ret;
|
||||
uint64_t prkey;
|
||||
struct config *conf;
|
||||
+ bool preempting_reservation = false;
|
||||
|
||||
ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -341,9 +362,12 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
break;
|
||||
- case MPATH_PROUT_RES_SA :
|
||||
case MPATH_PROUT_PREE_SA :
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
+ if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES)
|
||||
+ preempting_reservation = true;
|
||||
+ /* fallthrough */
|
||||
+ case MPATH_PROUT_RES_SA :
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
paramp, noisy, NULL);
|
||||
@@ -372,6 +396,15 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
+ break;
|
||||
+ case MPATH_PROUT_RES_SA:
|
||||
+ case MPATH_PROUT_REL_SA:
|
||||
+ update_prhold(alias, (rq_servact == MPATH_PROUT_RES_SA));
|
||||
+ break;
|
||||
+ case MPATH_PROUT_PREE_SA:
|
||||
+ case MPATH_PROUT_PREE_AB_SA:
|
||||
+ if (preempting_reservation)
|
||||
+ update_prhold(alias, 1);
|
||||
}
|
||||
out1:
|
||||
FREE(alias);
|
||||
@@ -455,6 +488,10 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid)
|
||||
* holding the reservation on a path that couldn't get its key updated,
|
||||
* either because it is down or no longer part of the multipath device,
|
||||
* you need to preempt the reservation to a usable path with the new key
|
||||
+ *
|
||||
+ * Also, it's possible that the reservation was preempted, and the device
|
||||
+ * is being re-registered. If it appears that is the case, clear
|
||||
+ * mpp->prhold in multipathd.
|
||||
*/
|
||||
void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
int noisy)
|
||||
@@ -467,12 +504,19 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
int status;
|
||||
|
||||
/*
|
||||
- * If you previously didn't have a key registered or you didn't
|
||||
- * switch to a different key, there's no need to preempt. Also, you
|
||||
- * can't preempt if you no longer have a registered key
|
||||
+ * If you previously didn't have a key registered, you can't
|
||||
+ * be holding the reservation. Also, you can't preempt if you
|
||||
+ * no longer have a registered key
|
||||
*/
|
||||
- if (memcmp(key, zero, 8) == 0 || memcmp(sa_key, zero, 8) == 0 ||
|
||||
- memcmp(key, sa_key, 8) == 0)
|
||||
+ if (memcmp(key, zero, 8) == 0 || memcmp(sa_key, zero, 8) == 0) {
|
||||
+ update_prhold(mpp->alias, false);
|
||||
+ return;
|
||||
+ }
|
||||
+ /*
|
||||
+ * If you didn't switch to a different key, there is no need to
|
||||
+ * preempt.
|
||||
+ */
|
||||
+ if (memcmp(key, sa_key, 8) == 0)
|
||||
return;
|
||||
|
||||
status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
@@ -481,13 +525,29 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
return;
|
||||
}
|
||||
/* If there is no reservation, there's nothing to preempt */
|
||||
- if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length) {
|
||||
+ update_prhold(mpp->alias, false);
|
||||
return;
|
||||
+ }
|
||||
/*
|
||||
* If there reservation is not held by the old key, you don't
|
||||
* want to preempt it
|
||||
*/
|
||||
- if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) != 0)
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) != 0) {
|
||||
+ /*
|
||||
+ * If reseravation key doesn't match either the old or
|
||||
+ * the new key, then clear prhold.
|
||||
+ */
|
||||
+ if (memcmp(sa_key, resp.prin_descriptor.prin_readresv.key, 8) != 0)
|
||||
+ update_prhold(mpp->alias, false);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If multipathd doesn't think it is holding the reservation, don't
|
||||
+ * preempt it
|
||||
+ */
|
||||
+ if (get_prhold(mpp->alias) != PR_SET)
|
||||
return;
|
||||
/* Assume this key is being held by an inaccessable path on this
|
||||
* node. libmpathpersist has never worked if multiple nodes share
|
||||
diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c
|
||||
index 00748264..bfa6e089 100644
|
||||
--- a/libmpathpersist/mpath_updatepr.c
|
||||
+++ b/libmpathpersist/mpath_updatepr.c
|
||||
@@ -75,12 +75,13 @@ static int do_update_pr(char *alias, char *cmd, char *key)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-int get_prflag(char *mapname) {
|
||||
+
|
||||
+static int do_get_pr(char *mapname, const char *cmd) {
|
||||
char str[256];
|
||||
char *reply;
|
||||
int prflag;
|
||||
|
||||
- snprintf(str, sizeof(str), "getprstatus map %s", mapname);
|
||||
+ snprintf(str, sizeof(str), "%s map %s", cmd, mapname);
|
||||
reply = do_pr(mapname, str);
|
||||
if (!reply)
|
||||
prflag = PR_UNKNOWN;
|
||||
@@ -95,11 +96,23 @@ int get_prflag(char *mapname) {
|
||||
return prflag;
|
||||
}
|
||||
|
||||
+int get_prflag(char *mapname) {
|
||||
+ return do_get_pr(mapname, "getprstatus");
|
||||
+}
|
||||
+
|
||||
+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_prhold(char *mapname, bool set) {
|
||||
+ return do_update_pr(mapname, (set)? "setprhold" : "unsetprhold", NULL);
|
||||
+}
|
||||
+
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags) {
|
||||
char str[256];
|
||||
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 35ef82c8..60fa0b09 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -43,6 +43,8 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int update_prflag(char *mapname, 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);
|
||||
+int update_prhold(char *mapname, bool set);
|
||||
#define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
|
||||
void * mpath_alloc_prin_response(int prin_sa);
|
||||
int update_map_pr(struct multipath *mpp, struct path *pp);
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index f47683c1..761fc642 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -466,6 +466,7 @@ struct multipath {
|
||||
int all_tg_pt;
|
||||
struct gen_multipath generic_mp;
|
||||
bool fpin_must_reload;
|
||||
+ int prhold;
|
||||
};
|
||||
|
||||
static inline int marginal_path_check_enabled(const struct multipath *mpp)
|
||||
diff --git a/multipathd/cli.c b/multipathd/cli.c
|
||||
index 03ad0d64..d33b571d 100644
|
||||
--- a/multipathd/cli.c
|
||||
+++ b/multipathd/cli.c
|
||||
@@ -223,7 +223,9 @@ load_keys (void)
|
||||
r += add_key(keys, "local", LOCAL, 0);
|
||||
r += add_key(keys, "setmarginal", SETMARGINAL, 0);
|
||||
r += add_key(keys, "unsetmarginal", UNSETMARGINAL, 0);
|
||||
-
|
||||
+ r += add_key(keys, "getprhold", GETPRHOLD, 0);
|
||||
+ r += add_key(keys, "setprhold", SETPRHOLD, 0);
|
||||
+ r += add_key(keys, "unsetprhold", UNSETPRHOLD, 0);
|
||||
|
||||
if (r) {
|
||||
free_keys(keys);
|
||||
@@ -574,6 +576,9 @@ cli_init (void) {
|
||||
add_handler(GETPRKEY+MAP, NULL);
|
||||
add_handler(SETPRKEY+MAP+KEY, NULL);
|
||||
add_handler(UNSETPRKEY+MAP, NULL);
|
||||
+ add_handler(GETPRHOLD+MAP, NULL);
|
||||
+ add_handler(SETPRHOLD+MAP, NULL);
|
||||
+ add_handler(UNSETPRHOLD+MAP, NULL);
|
||||
add_handler(FORCEQ+DAEMON, NULL);
|
||||
add_handler(RESTOREQ+DAEMON, NULL);
|
||||
add_handler(SETMARGINAL+PATH, NULL);
|
||||
diff --git a/multipathd/cli.h b/multipathd/cli.h
|
||||
index fdfb9aed..4d12f8fd 100644
|
||||
--- a/multipathd/cli.h
|
||||
+++ b/multipathd/cli.h
|
||||
@@ -47,6 +47,9 @@ enum {
|
||||
__LOCAL,
|
||||
__SETMARGINAL,
|
||||
__UNSETMARGINAL,
|
||||
+ __GETPRHOLD,
|
||||
+ __SETPRHOLD,
|
||||
+ __UNSETPRHOLD,
|
||||
};
|
||||
|
||||
#define LIST (1 << __LIST)
|
||||
@@ -93,6 +96,9 @@ enum {
|
||||
#define LOCAL (1ULL << __LOCAL)
|
||||
#define SETMARGINAL (1ULL << __SETMARGINAL)
|
||||
#define UNSETMARGINAL (1ULL << __UNSETMARGINAL)
|
||||
+#define GETPRHOLD (1ULL << __GETPRHOLD)
|
||||
+#define SETPRHOLD (1ULL << __SETPRHOLD)
|
||||
+#define UNSETPRHOLD (1ULL << __UNSETPRHOLD)
|
||||
|
||||
#define INITIAL_REPLY_LEN 1200
|
||||
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 1e735aab..f6353b61 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1349,6 +1349,10 @@ cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
|
||||
mpp->prflag = PR_UNSET;
|
||||
condlog(2, "%s: prflag unset", param);
|
||||
}
|
||||
+ if (mpp->prhold != PR_UNSET) {
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ condlog(2, "%s: prhold unset (by clearing prflag)", param);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1441,6 +1445,56 @@ cli_setprkey(void * v, char ** reply, int * len, void * data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int
|
||||
+do_prhold(struct vectors *vecs, char *param, int prhold) {
|
||||
+ struct multipath *mpp = find_mp_by_str(vecs->mpvec, param);
|
||||
+
|
||||
+ if (!mpp)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (mpp->prhold != prhold) {
|
||||
+ mpp->prhold = prhold;
|
||||
+ condlog(2, "%s: prhold %s", param, pr_str[prhold]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+cli_setprhold(void * v, char ** reply, int * len, void * data)
|
||||
+{
|
||||
+ return do_prhold((struct vectors *)data, get_keyparam(v, MAP),
|
||||
+ PR_SET);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+cli_unsetprhold(void * v, char ** reply, int * len, void * data)
|
||||
+{
|
||||
+ return do_prhold((struct vectors *)data, get_keyparam(v, MAP),
|
||||
+ PR_UNSET);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+cli_getprhold(void * v, char ** reply, int * len, void * data)
|
||||
+{
|
||||
+ struct multipath *mpp;
|
||||
+ struct vectors *vecs = (struct vectors *)data;
|
||||
+ char *param = get_keyparam(v, MAP);
|
||||
+
|
||||
+ param = convert_dev(param, 0);
|
||||
+
|
||||
+ mpp = find_mp_by_str(vecs->mpvec, param);
|
||||
+ if (!mpp)
|
||||
+ return 1;
|
||||
+
|
||||
+ *len = asprintf(reply, "%s", pr_str[mpp->prhold]);
|
||||
+ if (*len < 0)
|
||||
+ return 1;
|
||||
+
|
||||
+ condlog(3, "%s: reply = %s", param, *reply);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int cli_set_marginal(void * v, char ** reply, int * len, void * data)
|
||||
{
|
||||
struct vectors * vecs = (struct vectors *)data;
|
||||
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
|
||||
index 6f57b429..348c8485 100644
|
||||
--- a/multipathd/cli_handlers.h
|
||||
+++ b/multipathd/cli_handlers.h
|
||||
@@ -53,3 +53,6 @@ int cli_unsetprkey(void * v, char ** reply, int * len, void * data);
|
||||
int cli_set_marginal(void * v, char ** reply, int * len, void * data);
|
||||
int cli_unset_marginal(void * v, char ** reply, int * len, void * data);
|
||||
int cli_unset_all_marginal(void * v, char ** reply, int * len, void * data);
|
||||
+int cli_getprhold(void * v, char ** reply, int * len, void * data);
|
||||
+int cli_setprhold(void * v, char ** reply, int * len, void * data);
|
||||
+int cli_unsetprhold(void * v, char ** reply, int * len, void * data);
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 56050a06..060d3468 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -1874,6 +1874,9 @@ uxlsnrloop (void * ap)
|
||||
set_handler_callback(SETMARGINAL|PATH, cli_set_marginal);
|
||||
set_handler_callback(UNSETMARGINAL|PATH, cli_unset_marginal);
|
||||
set_handler_callback(UNSETMARGINAL|MAP, cli_unset_all_marginal);
|
||||
+ set_handler_callback(GETPRHOLD|MAP, cli_getprhold);
|
||||
+ set_handler_callback(SETPRHOLD|MAP, cli_setprhold);
|
||||
+ set_handler_callback(UNSETPRHOLD|MAP, cli_unsetprhold);
|
||||
|
||||
umask(077);
|
||||
uxsock_listen(num, ux_sock, ap);
|
||||
@@ -3721,6 +3724,32 @@ main (int argc, char *argv[])
|
||||
return (child(NULL));
|
||||
}
|
||||
|
||||
+static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
+{
|
||||
+ struct prin_resp resp = {0};
|
||||
+ int status;
|
||||
+
|
||||
+ if (mpp->prflag == PR_UNSET) {
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ return;
|
||||
+ }
|
||||
+ if (mpp->prflag != PR_SET || mpp->prhold != PR_UNKNOWN)
|
||||
+ return;
|
||||
+
|
||||
+ status = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RRES_SA, &resp, 0);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog (0, "%s: pr in read reservation command failed: %d",
|
||||
+ mpp->wwid, status);
|
||||
+ return;
|
||||
+ }
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
+ return;
|
||||
+
|
||||
+ if (memcmp(&mpp->reservation_key, resp.prin_descriptor.prin_readresv.key, 8) == 0)
|
||||
+ mpp->prhold = PR_SET;
|
||||
+}
|
||||
+
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
@@ -3732,8 +3761,13 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
+ if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS) {
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
return;
|
||||
+ }
|
||||
+
|
||||
+ check_prhold(mpp, pp);
|
||||
|
||||
if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 14 Jul 2025 20:14:06 -0400
|
||||
Subject: [PATCH] limpathpersist: remove update_map_pr code for NULL pp
|
||||
|
||||
Since update_map_pr is always called with pp set now, remove the code
|
||||
to handle being called with NULL pp.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 12 +-----------
|
||||
1 file changed, 1 insertion(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index e47e9190..fbf6161f 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -993,18 +993,8 @@ int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
return MPATH_PR_OTHER;
|
||||
}
|
||||
- if (!pp && count_active_paths(mpp) == 0) {
|
||||
- condlog(2, "%s: No available paths to check pr status",
|
||||
- mpp->alias);
|
||||
- goto out;
|
||||
- }
|
||||
- if (pp)
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp,
|
||||
- noisy);
|
||||
- else
|
||||
- ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp,
|
||||
- noisy);
|
||||
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
@ -0,0 +1,208 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 14 Jul 2025 20:20:08 -0400
|
||||
Subject: [PATCH] libmpathpersist: move update_map_pr to multipathd
|
||||
|
||||
multipathd is now the only program that calls update_map_pr(), so move
|
||||
it there, and make it static. There are no other code changes.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/libmpathpersist.version | 1 -
|
||||
libmpathpersist/mpath_persist.c | 75 -------------------------
|
||||
libmpathpersist/mpathpr.h | 1 -
|
||||
multipathd/main.c | 75 +++++++++++++++++++++++++
|
||||
4 files changed, 75 insertions(+), 77 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/libmpathpersist.version b/libmpathpersist/libmpathpersist.version
|
||||
index e0748138..2758e233 100644
|
||||
--- a/libmpathpersist/libmpathpersist.version
|
||||
+++ b/libmpathpersist/libmpathpersist.version
|
||||
@@ -26,7 +26,6 @@ global:
|
||||
mpath_persistent_reserve_free_vecs;
|
||||
prin_do_scsi_ioctl;
|
||||
prout_do_scsi_ioctl;
|
||||
- update_map_pr;
|
||||
|
||||
local: *;
|
||||
};
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index fbf6161f..22d4e117 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -966,78 +966,3 @@ void * mpath_alloc_prin_response(int prin_sa)
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
-
|
||||
-int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
-{
|
||||
- int noisy=0;
|
||||
- struct prin_resp *resp;
|
||||
- unsigned int i;
|
||||
- int ret = MPATH_PR_OTHER, isFound;
|
||||
- bool was_set = (mpp->prflag == PR_SET);
|
||||
-
|
||||
- /* If pr is explicitly unset, it must be manually set */
|
||||
- if (mpp->prflag == PR_UNSET)
|
||||
- return MPATH_PR_SKIP;
|
||||
-
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
- {
|
||||
- /* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
- mpp->prflag = PR_UNSET;
|
||||
- condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
- return MPATH_PR_SKIP;
|
||||
- }
|
||||
-
|
||||
- resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
- if (!resp)
|
||||
- {
|
||||
- condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
-
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
- if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
- mpp->prflag = PR_UNSET;
|
||||
- condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
- goto out;
|
||||
- }
|
||||
- mpp->prflag = PR_UNSET;
|
||||
-
|
||||
- if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
- {
|
||||
- condlog(was_set ? 1 : 3, "%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
- get_be64(mpp->reservation_key));
|
||||
-
|
||||
- isFound =0;
|
||||
- for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
- {
|
||||
- if (libmp_verbosity >= 3) {
|
||||
- condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
- mpp->alias, i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8, 1);
|
||||
- }
|
||||
-
|
||||
- if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8)) {
|
||||
- condlog(3, "%s: reservation key found in pr in readkeys response", mpp->alias);
|
||||
- isFound =1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (isFound)
|
||||
- {
|
||||
- mpp->prflag = PR_SET;
|
||||
- condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
- mpp->alias);
|
||||
- } else
|
||||
- condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
- mpp->alias);
|
||||
-
|
||||
-out:
|
||||
- free(resp);
|
||||
- return ret;
|
||||
-}
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 60fa0b09..052af85d 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -47,6 +47,5 @@ int get_prhold(char *mapname);
|
||||
int update_prhold(char *mapname, bool set);
|
||||
#define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0)
|
||||
void * mpath_alloc_prin_response(int prin_sa);
|
||||
-int update_map_pr(struct multipath *mpp, struct path *pp);
|
||||
|
||||
#endif
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 060d3468..29c788e3 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3750,6 +3750,81 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
mpp->prhold = PR_SET;
|
||||
}
|
||||
|
||||
+static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
+{
|
||||
+ int noisy=0;
|
||||
+ struct prin_resp *resp;
|
||||
+ unsigned int i;
|
||||
+ int ret = MPATH_PR_OTHER, isFound;
|
||||
+ bool was_set = (mpp->prflag == PR_SET);
|
||||
+
|
||||
+ /* If pr is explicitly unset, it must be manually set */
|
||||
+ if (mpp->prflag == PR_UNSET)
|
||||
+ return MPATH_PR_SKIP;
|
||||
+
|
||||
+ if (!get_be64(mpp->reservation_key))
|
||||
+ {
|
||||
+ /* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+ condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
+ return MPATH_PR_SKIP;
|
||||
+ }
|
||||
+
|
||||
+ resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
+ if (!resp)
|
||||
+ {
|
||||
+ condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ }
|
||||
+
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
+ if (ret != MPATH_PR_SUCCESS )
|
||||
+ {
|
||||
+ if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+ condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+
|
||||
+ if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
+ {
|
||||
+ condlog(was_set ? 1 : 3, "%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
+ get_be64(mpp->reservation_key));
|
||||
+
|
||||
+ isFound =0;
|
||||
+ for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
+ {
|
||||
+ if (libmp_verbosity >= 3) {
|
||||
+ condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
+ mpp->alias, i);
|
||||
+ dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8, 1);
|
||||
+ }
|
||||
+
|
||||
+ if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8)) {
|
||||
+ condlog(3, "%s: reservation key found in pr in readkeys response", mpp->alias);
|
||||
+ isFound =1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (isFound)
|
||||
+ {
|
||||
+ mpp->prflag = PR_SET;
|
||||
+ condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
+ mpp->alias);
|
||||
+ } else
|
||||
+ condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
+ mpp->alias);
|
||||
+
|
||||
+out:
|
||||
+ free(resp);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
@ -0,0 +1,150 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 15 Jul 2025 14:14:42 -0400
|
||||
Subject: [PATCH] multipathd: clean up update_map_pr and mpath_pr_event_handle
|
||||
|
||||
Store the READ KEYS response and the prout_param_descriptor on the stack
|
||||
to avoid having to fail these functions for allocation reasons. Don't
|
||||
explicitly check for additional_length == 0, since the for-loop already
|
||||
handles that. Also cleanup formatting issues,remove redundant messages,
|
||||
and reduce the log level of others.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 70 ++++++++++++++++-------------------------------
|
||||
1 file changed, 24 insertions(+), 46 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 29c788e3..8466d4d4 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3752,8 +3752,7 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
- int noisy=0;
|
||||
- struct prin_resp *resp;
|
||||
+ struct prin_resp resp;
|
||||
unsigned int i;
|
||||
int ret = MPATH_PR_OTHER, isFound;
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
@@ -3762,57 +3761,42 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
if (mpp->prflag == PR_UNSET)
|
||||
return MPATH_PR_SKIP;
|
||||
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
- {
|
||||
+ if (!get_be64(mpp->reservation_key)) {
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
mpp->prflag = PR_UNSET;
|
||||
condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
return MPATH_PR_SKIP;
|
||||
}
|
||||
|
||||
- resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
|
||||
- if (!resp)
|
||||
- {
|
||||
- condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
+ memset(&resp, 0, sizeof(resp));
|
||||
|
||||
- ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, resp, noisy);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
+ ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, &resp, 0);
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
mpp->prflag = PR_UNSET;
|
||||
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
- goto out;
|
||||
+ return ret;
|
||||
}
|
||||
mpp->prflag = PR_UNSET;
|
||||
|
||||
- if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
|
||||
- {
|
||||
- condlog(was_set ? 1 : 3, "%s: No key found. Device may not be registered. ", mpp->alias);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- condlog(3, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
+ condlog(4, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
|
||||
- isFound =0;
|
||||
- for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
|
||||
- {
|
||||
- if (libmp_verbosity >= 3) {
|
||||
- condlog(3, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
+ isFound = 0;
|
||||
+ for (i = 0; i < resp.prin_descriptor.prin_readkeys.additional_length / 8; i++) {
|
||||
+ uint8_t *keyp = &resp.prin_descriptor.prin_readkeys.key_list[i * 8];
|
||||
+
|
||||
+ if (libmp_verbosity >= 4) {
|
||||
+ condlog(4, "%s: PR IN READKEYS[%d] reservation key:",
|
||||
mpp->alias, i);
|
||||
- dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8, 1);
|
||||
+ dumpHex((char *)keyp, 8, 1);
|
||||
}
|
||||
|
||||
- if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i * 8], 8)) {
|
||||
- condlog(3, "%s: reservation key found in pr in readkeys response", mpp->alias);
|
||||
- isFound =1;
|
||||
- }
|
||||
+ if (!memcmp(&mpp->reservation_key, keyp, 8))
|
||||
+ isFound = 1;
|
||||
}
|
||||
|
||||
- if (isFound)
|
||||
- {
|
||||
+ if (isFound) {
|
||||
mpp->prflag = PR_SET;
|
||||
condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
mpp->alias);
|
||||
@@ -3820,16 +3804,14 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
mpp->alias);
|
||||
|
||||
-out:
|
||||
- free(resp);
|
||||
- return ret;
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
static void mpath_pr_event_handle(struct path *pp)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
- struct prout_param_descriptor *param;
|
||||
+ struct prout_param_descriptor param;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
mpp->prflag = PR_UNSET;
|
||||
@@ -3847,21 +3829,17 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
if (mpp->prflag != PR_SET)
|
||||
return;
|
||||
|
||||
- param = (struct prout_param_descriptor *)MALLOC(sizeof(struct prout_param_descriptor));
|
||||
- if (!param)
|
||||
- return;
|
||||
+ memset(¶m, 0, sizeof(param));
|
||||
|
||||
- param->sa_flags = mpp->sa_flags;
|
||||
- memcpy(param->sa_key, &mpp->reservation_key, 8);
|
||||
- param->num_transportid = 0;
|
||||
+ param.sa_flags = mpp->sa_flags;
|
||||
+ memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
+ param.num_transportid = 0;
|
||||
|
||||
condlog(3, "device %s:%s", pp->dev, pp->mpp->wwid);
|
||||
|
||||
- ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, param, 0);
|
||||
+ ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, ¶m, 0);
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
|
||||
}
|
||||
-
|
||||
- free(param);
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 15 Jul 2025 14:50:55 -0400
|
||||
Subject: [PATCH] libmpathpersist: clean up duplicate function declarations
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_pr_ioctl.c | 10 +++-------
|
||||
mpathpersist/main.c | 3 +--
|
||||
multipathd/main.h | 6 ------
|
||||
3 files changed, 4 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
|
||||
index 9cd83729..e5b25692 100644
|
||||
--- a/libmpathpersist/mpath_pr_ioctl.c
|
||||
+++ b/libmpathpersist/mpath_pr_ioctl.c
|
||||
@@ -15,20 +15,16 @@
|
||||
#include "mpath_pr_ioctl.h"
|
||||
#include "mpath_persist.h"
|
||||
#include "unaligned.h"
|
||||
-
|
||||
#include "debug.h"
|
||||
|
||||
#define FILE_NAME_SIZE 256
|
||||
+#include "mpathpr.h"
|
||||
|
||||
#define TIMEOUT 2000
|
||||
#define MAXRETRY 5
|
||||
|
||||
-int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp *resp, int noisy);
|
||||
-int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
|
||||
- SenseData_t *Sensedata);
|
||||
-void dumpHex(const char* str, int len, int no_ascii);
|
||||
-int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
|
||||
+int mpath_translate_response(char *dev, struct sg_io_hdr io_hdr,
|
||||
+ SenseData_t *Sensedata);
|
||||
uint32_t format_transportids(struct prout_param_descriptor *paramp);
|
||||
void convert_be32_to_cpu(uint32_t *num);
|
||||
void convert_be16_to_cpu(uint16_t *num);
|
||||
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
|
||||
index 14245cc3..26c69b01 100644
|
||||
--- a/mpathpersist/main.c
|
||||
+++ b/mpathpersist/main.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "version.h"
|
||||
+#include "mpathpr.h"
|
||||
|
||||
static const char * pr_type_strs[] = {
|
||||
"obsolete [0]",
|
||||
@@ -37,8 +38,6 @@ void mpath_print_buf_readcap(struct prin_resp *pr_buff);
|
||||
void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
|
||||
void mpath_print_buf_readresv(struct prin_resp *pr_buff);
|
||||
void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
|
||||
-void dumpHex(const char* str, int len, int no_ascii);
|
||||
-void * mpath_alloc_prin_response(int prin_sa);
|
||||
void mpath_print_transport_id(struct prin_fulldescr *fdesc);
|
||||
int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
|
||||
|
||||
diff --git a/multipathd/main.h b/multipathd/main.h
|
||||
index 6d2ae72a..5b5840c0 100644
|
||||
--- a/multipathd/main.h
|
||||
+++ b/multipathd/main.h
|
||||
@@ -46,12 +46,6 @@ int ev_remove_map (char *, char *, int, struct vectors *);
|
||||
int flush_map(struct multipath *, struct vectors *);
|
||||
int set_config_state(enum daemon_status);
|
||||
void * mpath_alloc_prin_response(int prin_sa);
|
||||
-int prin_do_scsi_ioctl(char *, int rq_servact, struct prin_resp * resp,
|
||||
- int noisy);
|
||||
-void dumpHex(const char * , int len, int no_ascii);
|
||||
-int prout_do_scsi_ioctl(char * , int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type,
|
||||
- struct prout_param_descriptor *param, int noisy);
|
||||
void handle_signals(bool);
|
||||
int __setup_multipath (struct vectors * vecs, struct multipath * mpp,
|
||||
int reset);
|
||||
148
SOURCES/0174-multipathd-wrap-setting-and-unsetting-prflag.patch
Normal file
148
SOURCES/0174-multipathd-wrap-setting-and-unsetting-prflag.patch
Normal file
@ -0,0 +1,148 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 15 Jul 2025 17:54:16 -0400
|
||||
Subject: [PATCH] multipathd: wrap setting and unsetting prflag
|
||||
|
||||
When prflag is unset, prhold and sa_flags should also be unset. A future
|
||||
patch will add another variable to be set when prflag is set. Wrap all
|
||||
these actions in set_pr() and unset_pr().
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/cli_handlers.c | 11 +++++------
|
||||
multipathd/main.c | 34 ++++++++++++++++++++--------------
|
||||
multipathd/main.h | 2 ++
|
||||
3 files changed, 27 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index f6353b61..93768ef3 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1323,7 +1323,7 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data)
|
||||
return 1;
|
||||
|
||||
if (mpp->prflag != PR_SET) {
|
||||
- mpp->prflag = PR_SET;
|
||||
+ set_pr(mpp);
|
||||
condlog(2, "%s: prflag set", param);
|
||||
}
|
||||
|
||||
@@ -1346,12 +1346,11 @@ cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
|
||||
return 1;
|
||||
|
||||
if (mpp->prflag != PR_UNSET) {
|
||||
- mpp->prflag = PR_UNSET;
|
||||
condlog(2, "%s: prflag unset", param);
|
||||
- }
|
||||
- if (mpp->prhold != PR_UNSET) {
|
||||
- mpp->prhold = PR_UNSET;
|
||||
- condlog(2, "%s: prhold unset (by clearing prflag)", param);
|
||||
+ if (mpp->prhold != PR_UNSET)
|
||||
+ condlog(2, "%s: prhold unset (by clearing prflag)",
|
||||
+ param);
|
||||
+ unset_pr(mpp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 8466d4d4..bc4cf66e 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3729,10 +3729,6 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
struct prin_resp resp = {0};
|
||||
int status;
|
||||
|
||||
- if (mpp->prflag == PR_UNSET) {
|
||||
- mpp->prhold = PR_UNSET;
|
||||
- return;
|
||||
- }
|
||||
if (mpp->prflag != PR_SET || mpp->prhold != PR_UNKNOWN)
|
||||
return;
|
||||
|
||||
@@ -3750,6 +3746,18 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
mpp->prhold = PR_SET;
|
||||
}
|
||||
|
||||
+void set_pr(struct multipath *mpp)
|
||||
+{
|
||||
+ mpp->prflag = PR_SET;
|
||||
+}
|
||||
+
|
||||
+void unset_pr(struct multipath *mpp)
|
||||
+{
|
||||
+ mpp->prflag = PR_UNSET;
|
||||
+ mpp->prhold = PR_UNSET;
|
||||
+ mpp->sa_flags = 0;
|
||||
+}
|
||||
+
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
struct prin_resp resp;
|
||||
@@ -3763,7 +3771,7 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
|
||||
if (!get_be64(mpp->reservation_key)) {
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
- mpp->prflag = PR_UNSET;
|
||||
+ unset_pr(mpp);
|
||||
condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
return MPATH_PR_SKIP;
|
||||
}
|
||||
@@ -3773,11 +3781,10 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, &resp, 0);
|
||||
if (ret != MPATH_PR_SUCCESS) {
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
- mpp->prflag = PR_UNSET;
|
||||
+ unset_pr(mpp);
|
||||
condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
return ret;
|
||||
}
|
||||
- mpp->prflag = PR_UNSET;
|
||||
|
||||
condlog(4, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
@@ -3797,12 +3804,14 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
}
|
||||
|
||||
if (isFound) {
|
||||
- mpp->prflag = PR_SET;
|
||||
+ set_pr(mpp);
|
||||
condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
mpp->alias);
|
||||
- } else
|
||||
+ } else {
|
||||
+ unset_pr(mpp);
|
||||
condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
mpp->alias);
|
||||
+ }
|
||||
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
@@ -3814,15 +3823,12 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
struct prout_param_descriptor param;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
- mpp->prflag = PR_UNSET;
|
||||
+ unset_pr(mpp);
|
||||
return;
|
||||
}
|
||||
|
||||
- if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS) {
|
||||
- if (mpp->prflag == PR_UNSET)
|
||||
- mpp->prhold = PR_UNSET;
|
||||
+ if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
return;
|
||||
- }
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
|
||||
diff --git a/multipathd/main.h b/multipathd/main.h
|
||||
index 5b5840c0..77603751 100644
|
||||
--- a/multipathd/main.h
|
||||
+++ b/multipathd/main.h
|
||||
@@ -58,4 +58,6 @@ void handle_path_wwid_change(struct path *pp, struct vectors *vecs);
|
||||
bool check_path_wwid_change(struct path *pp);
|
||||
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);
|
||||
#endif /* MAIN_H */
|
||||
@ -0,0 +1,141 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 16 Jul 2025 13:15:05 -0400
|
||||
Subject: [PATCH] multipathd: unregister PR key when path is restored if
|
||||
necessary
|
||||
|
||||
It is possible that a path was unavailable and either the registered PR
|
||||
key was removed or the registered PR key was changed and then that new
|
||||
key was preempted. In both of these situations, this path will still
|
||||
have a registered key (just not one that matches mpp->reservation_key)
|
||||
but it should not have one. If the path becomes usable again in this
|
||||
state, it may allow the multipath device to access storage that it
|
||||
shouldn't be allowed to access.
|
||||
|
||||
To deal with this, track if a multipath device ever had a registered PR
|
||||
key. If so, and the device no longer has a registered key, explicitly
|
||||
clear the key when paths get restored.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/structs.h | 1 +
|
||||
multipathd/main.c | 46 ++++++++++++++++++++++++++++++++----------
|
||||
2 files changed, 36 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 761fc642..a67e767d 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -467,6 +467,7 @@ struct multipath {
|
||||
struct gen_multipath generic_mp;
|
||||
bool fpin_must_reload;
|
||||
int prhold;
|
||||
+ bool ever_registered_pr;
|
||||
};
|
||||
|
||||
static inline int marginal_path_check_enabled(const struct multipath *mpp)
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index bc4cf66e..56d51c48 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -2538,7 +2538,8 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
}
|
||||
|
||||
if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||||
- if (pp->mpp->prflag != PR_UNSET) {
|
||||
+ if (pp->mpp->prflag != PR_UNSET ||
|
||||
+ pp->mpp->ever_registered_pr) {
|
||||
int prflag = pp->mpp->prflag;
|
||||
/*
|
||||
* Check Persistent Reservation.
|
||||
@@ -3748,6 +3749,7 @@ static void check_prhold(struct multipath *mpp, struct path *pp)
|
||||
|
||||
void set_pr(struct multipath *mpp)
|
||||
{
|
||||
+ mpp->ever_registered_pr = true;
|
||||
mpp->prflag = PR_SET;
|
||||
}
|
||||
|
||||
@@ -3758,22 +3760,27 @@ void unset_pr(struct multipath *mpp)
|
||||
mpp->sa_flags = 0;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Returns MPATH_PR_SUCCESS unless if fails to read the PR keys. If
|
||||
+ * MPATH_PR_SUCCESS is returned, mpp->prflag will be either PR_SET or
|
||||
+ * PR_UNSET.
|
||||
+ */
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
{
|
||||
struct prin_resp resp;
|
||||
unsigned int i;
|
||||
- int ret = MPATH_PR_OTHER, isFound;
|
||||
+ int ret, isFound;
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
if (mpp->prflag == PR_UNSET)
|
||||
- return MPATH_PR_SKIP;
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
|
||||
if (!get_be64(mpp->reservation_key)) {
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
unset_pr(mpp);
|
||||
condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
- return MPATH_PR_SKIP;
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
@@ -3821,6 +3828,7 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
struct prout_param_descriptor param;
|
||||
+ bool clear_reg = false;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
unset_pr(mpp);
|
||||
@@ -3832,20 +3840,36 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
|
||||
- if (mpp->prflag != PR_SET)
|
||||
- return;
|
||||
+ if (mpp->prflag != PR_SET) {
|
||||
+ if (!mpp->ever_registered_pr)
|
||||
+ return;
|
||||
+ /*
|
||||
+ * This path may have been unusable and either the
|
||||
+ * registration was cleared or the registered
|
||||
+ * key was switched and then that new key was preempted.
|
||||
+ * In either case, this path should not have a registration
|
||||
+ * but it might still have one, just with a different
|
||||
+ * key than mpp->reservation_key is currently set to.
|
||||
+ * clear it to be sure.
|
||||
+ */
|
||||
+ clear_reg = true;
|
||||
+ }
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
||||
- param.sa_flags = mpp->sa_flags;
|
||||
- memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
- param.num_transportid = 0;
|
||||
+ if (!clear_reg) {
|
||||
+ param.sa_flags = mpp->sa_flags;
|
||||
+ memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
+ param.num_transportid = 0;
|
||||
+ }
|
||||
|
||||
- condlog(3, "device %s:%s", pp->dev, pp->mpp->wwid);
|
||||
+ condlog(3, "%s registration for device %s:%s",
|
||||
+ clear_reg ? "Clearing" : "Setting", pp->dev, pp->mpp->wwid);
|
||||
|
||||
ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, ¶m, 0);
|
||||
if (ret != MPATH_PR_SUCCESS )
|
||||
{
|
||||
- condlog(0,"%s: Reservation registration failed. Error: %d", pp->dev, ret);
|
||||
+ condlog(0, "%s: %s reservation registration failed. Error: %d",
|
||||
+ clear_reg ? "Clearing" : "Setting", pp->dev, ret);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 17 Jul 2025 15:32:37 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix-up reservation_key checking
|
||||
|
||||
The reservation key checking in do_mpath_persistent_reserve_out() was
|
||||
slightly wrong. It allowed invalid keys for preempting. It now correctly
|
||||
checks the reservation key for the preempt commands.
|
||||
|
||||
It also was a little overly strict in some places. Formerly, it only
|
||||
allowed registering from any key to the configured key or registering
|
||||
from the configured key to any key (as long as you use the prkeys file).
|
||||
Now it also allows unregistering from any key and registering an
|
||||
unregistered device to any key (as long as you use the prkeys file).
|
||||
|
||||
Also, clarify the code by replacing prkey with a bool tracking if you
|
||||
are registering or unregistering.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 49 +++++++++++++++++++++++++--------
|
||||
1 file changed, 38 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 22d4e117..98b6997c 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -315,9 +315,9 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
struct multipath *mpp;
|
||||
char *alias;
|
||||
int ret;
|
||||
- uint64_t prkey;
|
||||
+ uint64_t zerokey = 0;
|
||||
struct config *conf;
|
||||
- bool preempting_reservation = false;
|
||||
+ bool unregistering, preempting_reservation = false;
|
||||
|
||||
ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -332,11 +332,12 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
set_ignored_key(mpp, paramp->key);
|
||||
|
||||
- memcpy(&prkey, paramp->sa_key, 8);
|
||||
- if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey &&
|
||||
+ unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
+ if (mpp->prkey_source == PRKEY_SOURCE_FILE && !unregistering &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
(rq_servact == MPATH_PROUT_REG_SA &&
|
||||
(!get_be64(mpp->reservation_key) ||
|
||||
+ memcmp(paramp->key, &zerokey, 8) == 0 ||
|
||||
memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
|
||||
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
|
||||
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
|
||||
@@ -348,12 +349,38 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
}
|
||||
}
|
||||
|
||||
- if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
|
||||
- memcmp(paramp->sa_key, &mpp->reservation_key, 8) &&
|
||||
- (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) {
|
||||
- condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
|
||||
- ret = MPATH_PR_SYNTAX_ERROR;
|
||||
- goto out1;
|
||||
+ /*
|
||||
+ * If you are registering a non-zero key, mpp->reservation_key
|
||||
+ * must be set and must equal paramp->sa_key.
|
||||
+ * If you're not registering a key, mpp->reservation_key must be
|
||||
+ * set, and must equal paramp->key
|
||||
+ */
|
||||
+ if ((rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
+ rq_servact == MPATH_PROUT_REG_SA)) {
|
||||
+ if (!unregistering && !get_be64(mpp->reservation_key)) {
|
||||
+ condlog(0, "%s: no configured reservation key", alias);
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
+ if (!unregistering &&
|
||||
+ memcmp(paramp->sa_key, &mpp->reservation_key, 8)) {
|
||||
+ condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64,
|
||||
+ mpp->alias, get_be64(mpp->reservation_key));
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (!get_be64(mpp->reservation_key)) {
|
||||
+ condlog(0, "%s: no configured reservation key", alias);
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
+ if (memcmp(paramp->key, &mpp->reservation_key, 8)) {
|
||||
+ condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64,
|
||||
+ mpp->alias, get_be64(mpp->reservation_key));
|
||||
+ ret = MPATH_PR_SYNTAX_ERROR;
|
||||
+ goto out1;
|
||||
+ }
|
||||
}
|
||||
|
||||
switch(rq_servact)
|
||||
@@ -387,7 +414,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
{
|
||||
case MPATH_PROUT_REG_SA:
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
- if (prkey == 0) {
|
||||
+ if (unregistering) {
|
||||
update_prflag(alias, 0);
|
||||
update_prkey(alias, 0);
|
||||
} else
|
||||
@ -0,0 +1,137 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 17 Jul 2025 19:12:23 -0400
|
||||
Subject: [PATCH] libmpathpersist: change how reservation conflicts are handled
|
||||
|
||||
If registering a key on a path fails with a reservation conflict in
|
||||
mpath_prout_reg(), libmpathpersist currently tries to roll back the
|
||||
registration. This code doesn't always make much sense. First, it
|
||||
updates the configured key, but doesn't fix it if it does a rollback.
|
||||
Second, it always rolls the key back to 0x0, unregistering paths that
|
||||
may have been previously registered. These rollback only happen on the
|
||||
paths where the registration succeeded, meaning that they were in the
|
||||
expected state when the command was run. The paths where the command
|
||||
failed, that were in an unexpected state, remain in that state.
|
||||
|
||||
The code no longer attempts to rollback registrations that failed
|
||||
with a reservation conflict. Instead, it checks that at least one
|
||||
path was in the expected state and was successfully registered. If
|
||||
so, then it assumes that the registration command was a resonable one
|
||||
and retries it on the paths that failed with a reservation conflict.
|
||||
But instead of using MPATH_PROUT_REG_SA, it uses MPATH_PROUT_REG_IGN_SA
|
||||
so that it will ignore the current key. This will keep it from
|
||||
failing with a reservation conflict because the path doesn't have the
|
||||
expected key registered on it. If path reservations failed for reasons
|
||||
other than a reservation conflict, the command still returns failure.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 69 +++++++++++++++++++++------------
|
||||
1 file changed, 44 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 98b6997c..af1fdd61 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -598,13 +598,13 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int i, j, k;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
- int rollback = 0;
|
||||
+ bool can_retry = false;
|
||||
+ bool need_retry = false;
|
||||
int active_pathcount=0;
|
||||
int rc;
|
||||
int count=0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
int all_tg_pt;
|
||||
- uint64_t sa_key = 0;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -693,43 +693,62 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
|
||||
}
|
||||
}
|
||||
- if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
|
||||
- rollback = 1;
|
||||
- sa_key = get_unaligned_be64(¶mp->sa_key[0]);
|
||||
- status = MPATH_PR_RESERV_CONFLICT ;
|
||||
- }
|
||||
- if (!rollback && (status == MPATH_PR_SUCCESS)){
|
||||
+ /*
|
||||
+ * We only retry if there is at least one registration that
|
||||
+ * returned a reservation conflict (which we need to retry)
|
||||
+ * and at least one registration the return success, so we
|
||||
+ * know that the command worked on some of the paths. If
|
||||
+ * the registation fails on all paths, then it wasn't a
|
||||
+ * valid request, so there's no need to retry.
|
||||
+ */
|
||||
+ if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
+ need_retry = true;
|
||||
+ else if (thread[i].param.status == MPATH_PR_SUCCESS)
|
||||
+ can_retry = true;
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
- }
|
||||
}
|
||||
- if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
|
||||
- condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
|
||||
- memcpy(¶mp->key, ¶mp->sa_key, 8);
|
||||
- memset(¶mp->sa_key, 0, 8);
|
||||
- for( i=0 ; i < count ; i++){
|
||||
- if(thread[i].param.status == MPATH_PR_SUCCESS) {
|
||||
- rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
|
||||
- (void *)(&thread[i].param));
|
||||
- if (rc){
|
||||
- condlog (0, "%s: failed to create thread for rollback. %d", mpp->wwid, rc);
|
||||
- thread[i].param.status = MPATH_PR_THREAD_ERROR;
|
||||
- }
|
||||
- } else
|
||||
+ if (need_retry && can_retry && rq_servact == MPATH_PROUT_REG_SA &&
|
||||
+ status == MPATH_PR_SUCCESS) {
|
||||
+ condlog (3, "%s: ERROR: initiating pr out retry", mpp->wwid);
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT) {
|
||||
thread[i].param.status = MPATH_PR_SKIP;
|
||||
+ continue;
|
||||
+ }
|
||||
+ /*
|
||||
+ * retry using MPATH_PROUT_REG_IGN_SA to avoid
|
||||
+ * conflicts. We already know that some paths
|
||||
+ * succeeded using MPATH_PROUT_REG_SA.
|
||||
+ */
|
||||
+ thread[i].param.rq_servact = MPATH_PROUT_REG_IGN_SA;
|
||||
+ rc = pthread_create(&thread[i].id, &attr,
|
||||
+ mpath_prout_pthread_fn,
|
||||
+ (void *)(&thread[i].param));
|
||||
+ if (rc) {
|
||||
+ condlog(0, "%s: failed to create thread for retry. %d",
|
||||
+ mpp->wwid, rc);
|
||||
+ thread[i].param.status = MPATH_PR_THREAD_ERROR;
|
||||
+ }
|
||||
}
|
||||
- for(i=0; i < count ; i++){
|
||||
+ for (i = 0; i < count; i++) {
|
||||
if (thread[i].param.status != MPATH_PR_SKIP &&
|
||||
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 rolling back %d",
|
||||
+ if (rc) {
|
||||
+ condlog(3, "%s: failed to join thread while retrying %d",
|
||||
mpp->wwid, i);
|
||||
}
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ status = thread[i].param.status;
|
||||
}
|
||||
}
|
||||
+ need_retry = false;
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
+ if (need_retry)
|
||||
+ status = MPATH_PR_RESERV_CONFLICT;
|
||||
if (status == MPATH_PR_SUCCESS)
|
||||
preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
|
||||
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
@ -0,0 +1,50 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 21 Jul 2025 19:27:17 -0400
|
||||
Subject: [PATCH] libmpathpersist: Clear prkey in multipathd before
|
||||
unregistering
|
||||
|
||||
When you register or switch keys in libmpathpersist, it updates
|
||||
mpp->reservation_key in multipathd before doing the registration. This
|
||||
means that any paths that come online while you are doing the
|
||||
registration get the new key registered. libmpathpersist didn't do
|
||||
this when unregistering a key. This could cause the same problem. A
|
||||
path that got restored while unregistering the device could end up
|
||||
getting the old key registered on it. Fix this by unsetting the key
|
||||
before doing the unregister, instead of afterwards.
|
||||
|
||||
There is still a race condition associated with updating
|
||||
mpp->reservation_key before doing the registration (but not on
|
||||
unregistration). This will be dealt with by a future patch.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index af1fdd61..ee49c27b 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -333,7 +333,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
set_ignored_key(mpp, paramp->key);
|
||||
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
- if (mpp->prkey_source == PRKEY_SOURCE_FILE && !unregistering &&
|
||||
+ if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
(rq_servact == MPATH_PROUT_REG_SA &&
|
||||
(!get_be64(mpp->reservation_key) ||
|
||||
@@ -414,10 +414,9 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
{
|
||||
case MPATH_PROUT_REG_SA:
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
- if (unregistering) {
|
||||
+ if (unregistering)
|
||||
update_prflag(alias, 0);
|
||||
- update_prkey(alias, 0);
|
||||
- } else
|
||||
+ else
|
||||
update_prflag(alias, 1);
|
||||
break;
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 23 Jul 2025 16:52:53 -0400
|
||||
Subject: [PATCH] libmpathpersist: only clear the key if we are using the
|
||||
prkeys file
|
||||
|
||||
Otherwise this request will create a useless prkeys file.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index ee49c27b..f585d8e9 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -421,7 +421,8 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
break;
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
update_prflag(alias, 0);
|
||||
- update_prkey(alias, 0);
|
||||
+ if (mpp->prkey_source == PRKEY_SOURCE_FILE)
|
||||
+ update_prkey(alias, 0);
|
||||
break;
|
||||
case MPATH_PROUT_RES_SA:
|
||||
case MPATH_PROUT_REL_SA:
|
||||
@ -0,0 +1,50 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 23 Jul 2025 17:54:45 -0400
|
||||
Subject: [PATCH] libmpathpersist: Restore old reservation key on failure
|
||||
|
||||
If we updated the key and then failed, restore the old key.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index f585d8e9..5b81c67f 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -316,8 +316,10 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
char *alias;
|
||||
int ret;
|
||||
uint64_t zerokey = 0;
|
||||
+ struct be64 oldkey = {0};
|
||||
struct config *conf;
|
||||
bool unregistering, preempting_reservation = false;
|
||||
+ bool updated_prkey = false;
|
||||
|
||||
ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -339,6 +341,8 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
(!get_be64(mpp->reservation_key) ||
|
||||
memcmp(paramp->key, &zerokey, 8) == 0 ||
|
||||
memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
|
||||
+ updated_prkey = true;
|
||||
+ memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
|
||||
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
|
||||
paramp->sa_flags)) {
|
||||
@@ -407,8 +411,12 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
goto out1;
|
||||
}
|
||||
|
||||
- if (ret != MPATH_PR_SUCCESS)
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
+ if (updated_prkey)
|
||||
+ update_prkey_flags(alias, get_be64(oldkey),
|
||||
+ mpp->sa_flags);
|
||||
goto out1;
|
||||
+ }
|
||||
|
||||
switch(rq_servact)
|
||||
{
|
||||
@ -0,0 +1,169 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 23 Jul 2025 18:28:52 -0400
|
||||
Subject: [PATCH] libmpatpersist: update reservation key before checking paths
|
||||
|
||||
There is a race condition when changing reservation keys where a failed
|
||||
path could come back online after libmpathpersist checks the paths, but
|
||||
before it updates the reservation key. In this case, the path would come
|
||||
up and get reregistered with the old key by multipathd, and
|
||||
libmpathpersist would not update its key, because the path was down
|
||||
when it checked.
|
||||
|
||||
To fix this, check the paths after updating the key, so any path that
|
||||
comes up after getting checked will use the updated key.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 83 ++++++++++++++-------------------
|
||||
libmpathpersist/mpathpr.h | 1 -
|
||||
2 files changed, 36 insertions(+), 48 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 5b81c67f..3d4c0c2c 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -187,7 +187,19 @@ int mpath_persistent_reserve_init_vecs(int verbose)
|
||||
return __mpath_persistent_reserve_init_vecs(&curmp, &pathvec, verbose);
|
||||
}
|
||||
|
||||
-static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
|
||||
+static int
|
||||
+get_path_info(struct multipath *mpp, vector pathvec)
|
||||
+{
|
||||
+ if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
|
||||
+ update_mpp_paths(mpp, pathvec)) {
|
||||
+ condlog(0, "error parsing map %s", mpp->wwid);
|
||||
+ return MPATH_PR_DMMP_ERROR;
|
||||
+ }
|
||||
+ extract_hwe_from_path(mpp);
|
||||
+ return MPATH_PR_SUCCESS ;
|
||||
+}
|
||||
+
|
||||
+static int mpath_get_map(vector curmp, int fd, char **palias,
|
||||
struct multipath **pmpp)
|
||||
{
|
||||
int ret = MPATH_PR_DMMP_ERROR;
|
||||
@@ -223,12 +235,6 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /* get info of all paths from the dm device */
|
||||
- if (get_mpvec(curmp, pathvec, alias)){
|
||||
- condlog(0, "%s: failed to get device info.", alias);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
mpp = find_mp_by_alias(curmp, alias);
|
||||
|
||||
if (!mpp) {
|
||||
@@ -254,7 +260,11 @@ static int do_mpath_persistent_reserve_in (vector curmp, vector pathvec,
|
||||
struct multipath *mpp;
|
||||
int ret;
|
||||
|
||||
- ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp);
|
||||
+ ret = mpath_get_map(curmp, fd, NULL, &mpp);
|
||||
+ if (ret != MPATH_PR_SUCCESS)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = get_path_info(mpp, pathvec);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
return ret;
|
||||
|
||||
@@ -321,19 +331,15 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
bool unregistering, preempting_reservation = false;
|
||||
bool updated_prkey = false;
|
||||
|
||||
- ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
|
||||
+ ret = mpath_get_map(curmp, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
return ret;
|
||||
|
||||
conf = get_multipath_config();
|
||||
+ mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
|
||||
select_reservation_key(conf, mpp);
|
||||
- select_all_tg_pt(conf, mpp);
|
||||
- select_skip_kpartx(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
- if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
- set_ignored_key(mpp, paramp->key);
|
||||
-
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
@@ -387,6 +393,22 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
}
|
||||
}
|
||||
|
||||
+ ret = get_path_info(mpp, pathvec);
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
+ if (updated_prkey)
|
||||
+ update_prkey_flags(alias, get_be64(oldkey),
|
||||
+ mpp->sa_flags);
|
||||
+ goto out1;
|
||||
+ }
|
||||
+
|
||||
+ conf = get_multipath_config();
|
||||
+ select_all_tg_pt(conf, mpp);
|
||||
+ select_skip_kpartx(conf, mpp);
|
||||
+ put_multipath_config(conf);
|
||||
+
|
||||
+ if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
+ set_ignored_key(mpp, paramp->key);
|
||||
+
|
||||
switch(rq_servact)
|
||||
{
|
||||
case MPATH_PROUT_REG_SA:
|
||||
@@ -485,39 +507,6 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-int
|
||||
-get_mpvec (vector curmp, vector pathvec, char * refwwid)
|
||||
-{
|
||||
- int i;
|
||||
- struct multipath *mpp;
|
||||
-
|
||||
- vector_foreach_slot (curmp, mpp, i){
|
||||
- /*
|
||||
- * discard out of scope maps
|
||||
- */
|
||||
- if (!mpp->alias) {
|
||||
- condlog(0, "%s: map with empty alias!", __func__);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- if (mpp->pg != NULL)
|
||||
- /* Already seen this one */
|
||||
- continue;
|
||||
-
|
||||
- if (refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE - 1))
|
||||
- continue;
|
||||
-
|
||||
- if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
|
||||
- update_mpp_paths(mpp, pathvec)) {
|
||||
- condlog(1, "error parsing map %s", mpp->wwid);
|
||||
- remove_map(mpp, pathvec, curmp);
|
||||
- i--;
|
||||
- } else
|
||||
- extract_hwe_from_path(mpp);
|
||||
- }
|
||||
- return MPATH_PR_SUCCESS ;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* If you are changing the key registered to a device, and that device is
|
||||
* holding the reservation on a path that couldn't get its key updated,
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 052af85d..27df5fdd 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -31,7 +31,6 @@ int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int
|
||||
int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
|
||||
void * _mpath_pr_update (void *arg);
|
||||
-int get_mpvec (vector curmp, vector pathvec, char * refwwid);
|
||||
void * mpath_prout_pthread_fn(void *p);
|
||||
void dumpHex(const char* , int len, int no_ascii);
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 24 Jul 2025 14:05:38 -0400
|
||||
Subject: [PATCH] libmpathpersist: retry on conflicts in mpath_prout_common
|
||||
|
||||
mpath_prout_common() just needs to execute a prout command down one
|
||||
path. If it uses a path that was down when the key was changed and has
|
||||
since been restored, but multipathd hasn't noticed yet, that path will
|
||||
still be using the old key. This was causing mpath_prout_common() to
|
||||
fail with MPATH_PR_RESERV_CONFLICT, even if there were other paths that
|
||||
would work.
|
||||
|
||||
Now, if prout command fails with MPATH_PR_RESERV_CONFLICT,
|
||||
mpath_prout_common() checks if pp->dmstate is PSTATE_FAILED. If it is,
|
||||
mpath_prout_common() assumes that multipathd has not yet noticed that
|
||||
the path is back online and it might still have and old key, so it
|
||||
doesn't immediately return. If it can't successfully send the command
|
||||
down another path, it will still return MPATH_PR_RESERV_CONFLICT.
|
||||
|
||||
Also, make sure prout_do_scsi_ioctl() always returns a MPATH_PR_*
|
||||
type error.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 14 +++++++++++++-
|
||||
libmpathpersist/mpath_pr_ioctl.c | 2 +-
|
||||
2 files changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 3d4c0c2c..560c9ae7 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -771,6 +771,7 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
bool found = false;
|
||||
+ bool conflict = false;
|
||||
|
||||
vector_foreach_slot (mpp->pg, pgp, j){
|
||||
vector_foreach_slot (pgp->paths, pp, i){
|
||||
@@ -786,12 +787,23 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
rq_type, paramp, noisy);
|
||||
if (ret == MPATH_PR_SUCCESS && pptr)
|
||||
*pptr = pp;
|
||||
+ /*
|
||||
+ * If this path is considered down by the kernel,
|
||||
+ * it may have just come back up, and multipathd
|
||||
+ * may not have had time to update the key. Allow
|
||||
+ * reservation conflicts.
|
||||
+ */
|
||||
+ if (ret == MPATH_PR_RESERV_CONFLICT &&
|
||||
+ pp->dmstate == PSTATE_FAILED) {
|
||||
+ conflict = true;
|
||||
+ continue;
|
||||
+ }
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
- return MPATH_PR_OTHER;
|
||||
+ return conflict ? MPATH_PR_RESERV_CONFLICT : MPATH_PR_OTHER;
|
||||
condlog (0, "%s: no path available", mpp->wwid);
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c
|
||||
index e5b25692..689578ac 100644
|
||||
--- a/libmpathpersist/mpath_pr_ioctl.c
|
||||
+++ b/libmpathpersist/mpath_pr_ioctl.c
|
||||
@@ -105,7 +105,7 @@ retry :
|
||||
{
|
||||
condlog(0, "%s: ioctl failed %d", dev, ret);
|
||||
close(fd);
|
||||
- return ret;
|
||||
+ return MPATH_PR_OTHER;
|
||||
}
|
||||
|
||||
condlog(4, "%s: Duration=%u (ms)", dev, io_hdr.duration);
|
||||
@ -0,0 +1,151 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 25 Jul 2025 15:53:16 -0400
|
||||
Subject: [PATCH] libmpathpersist: Don't always fail registrations for
|
||||
retryable errors
|
||||
|
||||
When libmpathpersist registers a key, it's possible that a path fails
|
||||
between when it checks the path's status, and when it tries to do the
|
||||
registrations on the path. In this case, the registration will fail with
|
||||
a retryable error. If the registration was allowed to succeed,
|
||||
multipathd would update the now failed path's key when it came back
|
||||
online, and everything would work correctly. However it is possible for
|
||||
a registration to fail with a retryable error on a path that is still
|
||||
usable.
|
||||
|
||||
Libmpathpersist needs to avoid the case where it does not update the
|
||||
key of a usable path. Otherwise the path might be able to write to
|
||||
storage it shouldn't be allowed to. Or it could fail writing to storage
|
||||
that it should be allowed to write to. So if a registration would
|
||||
succeed except for retryable errors, libmpathpersist now rechecks all
|
||||
those paths to see if they are still usable. If they are, then it fails
|
||||
the registration as before. If they are not, then the registration
|
||||
succeeds.
|
||||
|
||||
Also, rename can_retry to had_success, since it is used for checking
|
||||
more than retries now.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 70 +++++++++++++++++++++++++++++----
|
||||
1 file changed, 63 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 560c9ae7..54408e91 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -588,6 +588,48 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
mpp->wwid);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * If libmpathpersist fails at updating the key on a path with a retryable
|
||||
+ * error, it has probably failed. But there is a chance that the path is
|
||||
+ * still usable. To make sure a path isn't active without a key, when it
|
||||
+ * should have one, or with a key, when it shouldn't have one, check if
|
||||
+ * the path is still usable. If it is, we must fail the registration.
|
||||
+ */
|
||||
+static int check_failed_paths(struct multipath *mpp,
|
||||
+ struct threadinfo *thread, int count)
|
||||
+{
|
||||
+ int i, j, k;
|
||||
+ int ret;
|
||||
+ struct pathgroup *pgp;
|
||||
+ struct path *pp;
|
||||
+ struct config *conf;
|
||||
+
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ if (thread[i].param.status != MPATH_PR_RETRYABLE_ERROR)
|
||||
+ continue;
|
||||
+ vector_foreach_slot (mpp->pg, pgp, j) {
|
||||
+ vector_foreach_slot (pgp->paths, pp, k) {
|
||||
+ if (strncmp(pp->dev, thread[i].param.dev,
|
||||
+ FILE_NAME_SIZE) == 0)
|
||||
+ goto match;
|
||||
+ }
|
||||
+ }
|
||||
+ /* no match. This shouldn't ever happen. */
|
||||
+ condlog(0, "%s: Error: can't find path %s", mpp->wwid,
|
||||
+ thread[i].param.dev);
|
||||
+ continue;
|
||||
+match:
|
||||
+ conf = get_multipath_config();
|
||||
+ ret = pathinfo(pp, conf, DI_CHECKER);
|
||||
+ put_multipath_config(conf);
|
||||
+ /* If pathinfo fails, or if the path is active, return error */
|
||||
+ if (ret != PATHINFO_OK || pp->state == PATH_UP ||
|
||||
+ pp->state == PATH_GHOST)
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ }
|
||||
+ return MPATH_PR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
@@ -595,8 +637,9 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int i, j, k;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
- bool can_retry = false;
|
||||
+ bool had_success = false;
|
||||
bool need_retry = false;
|
||||
+ bool retryable_error = false;
|
||||
int active_pathcount=0;
|
||||
int rc;
|
||||
int count=0;
|
||||
@@ -700,16 +743,20 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
*/
|
||||
if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
|
||||
need_retry = true;
|
||||
+ else if (thread[i].param.status == MPATH_PR_RETRYABLE_ERROR)
|
||||
+ retryable_error = true;
|
||||
else if (thread[i].param.status == MPATH_PR_SUCCESS)
|
||||
- can_retry = true;
|
||||
+ had_success = true;
|
||||
else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
}
|
||||
- if (need_retry && can_retry && rq_servact == MPATH_PROUT_REG_SA &&
|
||||
+ if (need_retry && had_success && rq_servact == MPATH_PROUT_REG_SA &&
|
||||
status == MPATH_PR_SUCCESS) {
|
||||
condlog (3, "%s: ERROR: initiating pr out retry", mpp->wwid);
|
||||
+ retryable_error = false;
|
||||
for (i = 0; i < count; i++) {
|
||||
- if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT) {
|
||||
+ /* retry retryable errors and conflicts */
|
||||
+ if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT && thread[i].param.status != MPATH_PR_RETRYABLE_ERROR) {
|
||||
thread[i].param.status = MPATH_PR_SKIP;
|
||||
continue;
|
||||
}
|
||||
@@ -736,7 +783,9 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
condlog(3, "%s: failed to join thread while retrying %d",
|
||||
mpp->wwid, i);
|
||||
}
|
||||
- if (status == MPATH_PR_SUCCESS)
|
||||
+ if (thread[i].param.status == MPATH_PR_RETRYABLE_ERROR)
|
||||
+ retryable_error = true;
|
||||
+ else if (status == MPATH_PR_SUCCESS)
|
||||
status = thread[i].param.status;
|
||||
}
|
||||
}
|
||||
@@ -745,10 +794,17 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
if (need_retry)
|
||||
- status = MPATH_PR_RESERV_CONFLICT;
|
||||
+ return MPATH_PR_RESERV_CONFLICT;
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ return status;
|
||||
+ /* If you had retryable errors on all paths, fail the registration */
|
||||
+ if (!had_success)
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ if (retryable_error)
|
||||
+ status = check_failed_paths(mpp, thread, count);
|
||||
if (status == MPATH_PR_SUCCESS)
|
||||
preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
|
||||
- return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
+ return status;
|
||||
}
|
||||
|
||||
void * mpath_prout_pthread_fn(void *p)
|
||||
@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 25 Aug 2025 14:09:29 -0400
|
||||
Subject: [PATCH] libmpathpersist: Don't try release workaround for invalid
|
||||
type
|
||||
|
||||
When trying to release a reservation, if the user specified the wrong
|
||||
reservation type, libmpathpersist would try to preempt the reservation,
|
||||
because the reservation key matched the device key, but it was not
|
||||
removed. In this case, the preemption would also fail because it also
|
||||
requires a matching type.
|
||||
|
||||
Check if the reservation type matches, to avoid attempting the
|
||||
workaround in this case.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 54408e91..ad2e0e80 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -880,6 +880,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
uint16_t udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
bool did_resume = false;
|
||||
bool all_threads_failed;
|
||||
+ unsigned int scope_type;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -975,6 +976,13 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
+ scope_type = resp.prin_descriptor.prin_readresv.scope_type;
|
||||
+ if ((scope_type & MPATH_PR_TYPE_MASK) != rq_type) {
|
||||
+ condlog(2, "%s: --prout_type %u doesn't match reservation %u",
|
||||
+ mpp->wwid, rq_type, scope_type & MPATH_PR_TYPE_MASK);
|
||||
+ return MPATH_PR_RESERV_CONFLICT;
|
||||
+ }
|
||||
+
|
||||
condlog (2, "%s: Path holding reservation is not available.", mpp->wwid);
|
||||
/*
|
||||
* Cannot free the reservation because the path that is holding it
|
||||
@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 4 Sep 2025 16:33:27 -0400
|
||||
Subject: [PATCH] libmpathpersist: Don't fail RESERVE commands unnecessarily
|
||||
|
||||
If you issue a RESERVE to a regular SCSI device that already holds the
|
||||
reservation, it succeeds (and does nothing). If you issue a RESERVE to a
|
||||
multipath device that already holds the reservation, it can fail with
|
||||
a reservation conflict error if you issue the RESERVE to a path that isn't
|
||||
holding the reservation. Instead, it should try all paths and
|
||||
succeed if the reservation command succeeds on any of them.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index ad2e0e80..52fbc0aa 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -848,9 +848,20 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
* it may have just come back up, and multipathd
|
||||
* may not have had time to update the key. Allow
|
||||
* reservation conflicts.
|
||||
+ *
|
||||
+ * If you issue a RESERVE to a regular scsi device
|
||||
+ * that already holds the reservation, it succeeds
|
||||
+ * (and does nothing). A multipath device that
|
||||
+ * holds the reservation should not return a
|
||||
+ * reservation conflict on a RESERVE command, just
|
||||
+ * because it issued the RESERVE to a path that
|
||||
+ * isn't holding the reservation. It should instead
|
||||
+ * keep trying to see if it succeeds on another
|
||||
+ * path.
|
||||
*/
|
||||
if (ret == MPATH_PR_RESERV_CONFLICT &&
|
||||
- pp->dmstate == PSTATE_FAILED) {
|
||||
+ (pp->dmstate == PSTATE_FAILED ||
|
||||
+ rq_servact == MPATH_PROUT_RES_SA)) {
|
||||
conflict = true;
|
||||
continue;
|
||||
}
|
||||
@ -0,0 +1,203 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 5 Sep 2025 14:04:58 -0400
|
||||
Subject: [PATCH] libmpathpersist: reregister keys when self preempting
|
||||
|
||||
When a SCSI device preempts its own reservation key, it will remove the
|
||||
registered keys from all other devices with that reservation key, but
|
||||
retain its registered key (and possibly acquire the reservation). If a
|
||||
multipath device preempts its own reservation key, it will also remove
|
||||
the registered keys from all its paths except the one issuing the
|
||||
reservation. This means that IO to the device can fail if it goes to one
|
||||
of these unregistered paths.
|
||||
|
||||
To avoid this, whenever a multipath device preempts itself, it must
|
||||
first suspend, then do the preemption and reregister the removed keys,
|
||||
and finally resume the device. This is already what libmpathpersist does
|
||||
if a release fails because the path holding the reservation is currently
|
||||
unavailable, with the addition of releasing the reservation after
|
||||
preempting it. This commit refactors that code into a separate function,
|
||||
makes the release optional, and calls the new function, preempt_self(),
|
||||
whenever a device preempts itself.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 136 +++++++++++++++++---------------
|
||||
1 file changed, 71 insertions(+), 65 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 52fbc0aa..3d3b62dd 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -37,6 +37,9 @@
|
||||
|
||||
extern struct udev *udev;
|
||||
|
||||
+static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy, bool do_release);
|
||||
+
|
||||
static void adapt_config(struct config *conf)
|
||||
{
|
||||
conf->force_sync = 1;
|
||||
@@ -419,6 +422,12 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES)
|
||||
preempting_reservation = true;
|
||||
+ /* if we are preempting ourself */
|
||||
+ if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
|
||||
+ ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
|
||||
+ noisy, false);
|
||||
+ break;
|
||||
+ }
|
||||
/* fallthrough */
|
||||
case MPATH_PROUT_RES_SA :
|
||||
case MPATH_PROUT_CLEAR_SA:
|
||||
@@ -875,6 +884,65 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Called to make a multipath device preempt its own reservation (and
|
||||
+ * optionally release the reservation). Doing this causes the reservation
|
||||
+ * keys to be removed from all the device paths except that path used to issue
|
||||
+ * the preempt, so they need to be restored. To avoid the chance that IO
|
||||
+ * goes to these paths when they don't have a registered key, the device
|
||||
+ * is suspended before issuing the preemption, and the keys are reregistered
|
||||
+ * before resuming it.
|
||||
+ */
|
||||
+static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy, bool do_release)
|
||||
+{
|
||||
+ int status, rel_status = MPATH_PR_SUCCESS;
|
||||
+ struct path *pp = NULL;
|
||||
+ struct prout_param_descriptor paramp = {.sa_flags = 0};
|
||||
+ uint16_t udev_flags = (mpp->skip_kpartx) ? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
+
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_SUSPEND, mpp->alias, 0)) {
|
||||
+ condlog(0, "%s: self preempt failed to suspend device.", mpp->wwid);
|
||||
+ return MPATH_PR_OTHER;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
+ memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
+ ¶mp, noisy, &pp);
|
||||
+ if (status != MPATH_PR_SUCCESS) {
|
||||
+ condlog(0, "%s: self preempt command failed.", mpp->wwid);
|
||||
+ goto fail_resume;
|
||||
+ }
|
||||
+
|
||||
+ if (do_release) {
|
||||
+ memset(¶mp, 0, sizeof(paramp));
|
||||
+ memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
+ rel_status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA,
|
||||
+ rq_scope, rq_type, ¶mp, noisy);
|
||||
+ if (rel_status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: release on alternate path failed.",
|
||||
+ mpp->wwid);
|
||||
+ }
|
||||
+
|
||||
+ memset(¶mp, 0, sizeof(paramp));
|
||||
+ memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
|
||||
+ rq_type, ¶mp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: self preempt failed to reregister paths.",
|
||||
+ mpp->wwid);
|
||||
+
|
||||
+fail_resume:
|
||||
+ if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
+ condlog(0, "%s: self preempt failed to resume device.", mpp->wwid);
|
||||
+ if (status == MPATH_PR_SUCCESS)
|
||||
+ status = MPATH_PR_OTHER;
|
||||
+ }
|
||||
+ /* return the first error we encountered */
|
||||
+ return (rel_status != MPATH_PR_SUCCESS) ? rel_status : status;
|
||||
+}
|
||||
+
|
||||
int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
@@ -888,8 +956,6 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
struct prin_resp resp = {0};
|
||||
- uint16_t udev_flags = (mpp->skip_kpartx)? MPATH_UDEV_NO_KPARTX_FLAG : 0;
|
||||
- bool did_resume = false;
|
||||
bool all_threads_failed;
|
||||
unsigned int scope_type;
|
||||
|
||||
@@ -1004,70 +1070,10 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
* preempting one. Since the device is suspended, no IO can
|
||||
* go to these unregistered paths and fail).
|
||||
* 3. Releasing the reservation on the path that now holds it.
|
||||
- * 4. Resuming the device (since it no longer matters that most of
|
||||
- * that paths no longer have a registered key)
|
||||
- * 5. Reregistering keys on all the paths
|
||||
+ * 4. Reregistering keys on all the paths
|
||||
+ * 5. Resuming the device
|
||||
*/
|
||||
-
|
||||
- if (!dm_simplecmd_noflush(DM_DEVICE_SUSPEND, mpp->alias, 0)) {
|
||||
- condlog(0, "%s: release: failed to suspend dm device.", mpp->wwid);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
-
|
||||
- memset(paramp, 0, sizeof(*paramp));
|
||||
- memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
- memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
- status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
|
||||
- paramp, noisy, &pp);
|
||||
- if (status != MPATH_PR_SUCCESS) {
|
||||
- condlog(0, "%s: release: pr preempt command failed.", mpp->wwid);
|
||||
- goto fail_resume;
|
||||
- }
|
||||
-
|
||||
- memset(paramp, 0, sizeof(*paramp));
|
||||
- memcpy(paramp->key, &mpp->reservation_key, 8);
|
||||
- status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA, rq_scope,
|
||||
- rq_type, paramp, noisy);
|
||||
- if (status != MPATH_PR_SUCCESS) {
|
||||
- condlog(0, "%s: release on alternate path failed.", mpp->wwid);
|
||||
- goto out_reregister;
|
||||
- }
|
||||
-
|
||||
- if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
- condlog(0, "%s release: failed to resume dm device.", mpp->wwid);
|
||||
- /*
|
||||
- * leave status set to MPATH_PR_SUCCESS, we will have another
|
||||
- * chance to resume the device.
|
||||
- */
|
||||
- goto out_reregister;
|
||||
- }
|
||||
- did_resume = true;
|
||||
-
|
||||
-out_reregister:
|
||||
- memset(paramp, 0, sizeof(*paramp));
|
||||
- memcpy(paramp->sa_key, &mpp->reservation_key, 8);
|
||||
- rc = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope, rq_type,
|
||||
- paramp, noisy);
|
||||
- if (rc != MPATH_PR_SUCCESS)
|
||||
- condlog(0, "%s: release: failed to reregister paths.", mpp->wwid);
|
||||
-
|
||||
- /*
|
||||
- * If we failed releasing the reservation or resuming earlier
|
||||
- * try resuming now. Otherwise, return with the reregistering status
|
||||
- * This means we will report failure, even though the resevation
|
||||
- * has been released, since the keys were not reregistered.
|
||||
- */
|
||||
- if (did_resume)
|
||||
- return rc;
|
||||
- else if (status == MPATH_PR_SUCCESS)
|
||||
- status = rc;
|
||||
-fail_resume:
|
||||
- if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
- condlog(0, "%s: release: failed to resume dm device.", mpp->wwid);
|
||||
- if (status == MPATH_PR_SUCCESS)
|
||||
- status = MPATH_PR_OTHER;
|
||||
- }
|
||||
- return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;
|
||||
+ return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
||||
}
|
||||
|
||||
void * mpath_alloc_prin_response(int prin_sa)
|
||||
@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 9 Sep 2025 18:55:49 -0400
|
||||
Subject: [PATCH] libmpathpersist: handle updating key race condition
|
||||
|
||||
If a multipath device's registered key is changed, mpathpersist needs
|
||||
to update the key in multipathd before it registers the new key on the
|
||||
paths. This means that there is a time when multipathd thinks the paths
|
||||
should be using the new key, but none of them are. If a path is
|
||||
restored after mpathpersist checks which paths are usable to set the
|
||||
key on, but before it sets the key on any path, multipathd will see
|
||||
that the new key is not registered on any paths, and think that the
|
||||
key has been preempted or cleared. This will leave the path without
|
||||
a key, and possibly make multipathd think the device does not hold
|
||||
the reservation, even if it does.
|
||||
|
||||
To avoid this, multipathd will now remember the old key when registering
|
||||
a new one. Once the registration is finished, and (un)setprstatus is
|
||||
called, multipathd will forget the old key. Until then, multipathd will
|
||||
check for either key when it looks to see if there is an existing key.
|
||||
If the registration fails and the key get reverted, multipathd will
|
||||
also forget the old key.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmultipath/prkey.c | 16 ++++++++++++++--
|
||||
libmultipath/structs.h | 1 +
|
||||
multipathd/main.c | 12 +++++++++++-
|
||||
3 files changed, 26 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/prkey.c b/libmultipath/prkey.c
|
||||
index d645f813..ab45f176 100644
|
||||
--- a/libmultipath/prkey.c
|
||||
+++ b/libmultipath/prkey.c
|
||||
@@ -176,10 +176,22 @@ int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey,
|
||||
}
|
||||
else
|
||||
ret = do_prkey(fd, mpp->wwid, NULL, PRKEY_WRITE);
|
||||
- if (ret == 0)
|
||||
+ if (ret == 0) {
|
||||
+ /*
|
||||
+ * If you are reverting back to the old key, because you
|
||||
+ * did not successfully set a new key, don't remember the
|
||||
+ * key you never successfully set.
|
||||
+ */
|
||||
+ if (get_be64(mpp->old_pr_key) == prkey)
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
+ else
|
||||
+ memcpy(&mpp->old_pr_key, &mpp->reservation_key, 8);
|
||||
select_reservation_key(conf, mpp);
|
||||
- if (get_be64(mpp->reservation_key) != prkey)
|
||||
+ }
|
||||
+ if (get_be64(mpp->reservation_key) != prkey) {
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
ret = 1;
|
||||
+ }
|
||||
out_file:
|
||||
close(fd);
|
||||
out:
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index a67e767d..2f69e831 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -468,6 +468,7 @@ struct multipath {
|
||||
bool fpin_must_reload;
|
||||
int prhold;
|
||||
bool ever_registered_pr;
|
||||
+ struct be64 old_pr_key;
|
||||
};
|
||||
|
||||
static inline int marginal_path_check_enabled(const struct multipath *mpp)
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 56d51c48..8a0d9edc 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3751,6 +3751,7 @@ void set_pr(struct multipath *mpp)
|
||||
{
|
||||
mpp->ever_registered_pr = true;
|
||||
mpp->prflag = PR_SET;
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
}
|
||||
|
||||
void unset_pr(struct multipath *mpp)
|
||||
@@ -3758,6 +3759,7 @@ void unset_pr(struct multipath *mpp)
|
||||
mpp->prflag = PR_UNSET;
|
||||
mpp->prhold = PR_UNSET;
|
||||
mpp->sa_flags = 0;
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3806,7 +3808,15 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
dumpHex((char *)keyp, 8, 1);
|
||||
}
|
||||
|
||||
- if (!memcmp(&mpp->reservation_key, keyp, 8))
|
||||
+ /*
|
||||
+ * If you are in the middle of updating a key (old_pr_key
|
||||
+ * is set) check for either the new key or the old key,
|
||||
+ * since you might be checking before any paths have
|
||||
+ * updated their keys.
|
||||
+ */
|
||||
+ if (!memcmp(&mpp->reservation_key, keyp, 8) ||
|
||||
+ (get_be64(mpp->old_pr_key) &&
|
||||
+ !memcmp(&mpp->old_pr_key, keyp, 8)))
|
||||
isFound = 1;
|
||||
}
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 10 Sep 2025 17:52:12 -0400
|
||||
Subject: [PATCH] libmpathpersist: handle preempting all registrants
|
||||
reservations
|
||||
|
||||
All Registrants reservations (types 7 and 8) are held by key 0x0. When
|
||||
preempting one, all registrations are cleared, except for the one on the
|
||||
path that issued the PREEMPT. libmpathpersist needs to handle this just
|
||||
like the other cases of self-preemption, so that all the paths of the
|
||||
preempting multipath device have their registrations restored while the
|
||||
device is suspended.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 36 +++++++++++++++++++++++++++------
|
||||
1 file changed, 30 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 3d3b62dd..92a0021d 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -37,8 +37,9 @@
|
||||
|
||||
extern struct udev *udev;
|
||||
|
||||
-static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, int noisy, bool do_release);
|
||||
+static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
+ int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
+ int noisy, bool do_release);
|
||||
|
||||
static void adapt_config(struct config *conf)
|
||||
{
|
||||
@@ -321,6 +322,21 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
memcpy(key, &mpp->reservation_key, 8);
|
||||
}
|
||||
|
||||
+static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy, bool do_release)
|
||||
+{
|
||||
+ return do_preempt_self(mpp, mpp->reservation_key, rq_servact, rq_scope,
|
||||
+ rq_type, noisy, do_release);
|
||||
+}
|
||||
+
|
||||
+static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, int noisy)
|
||||
+{
|
||||
+ struct be64 zerokey = {0};
|
||||
+ return do_preempt_self(mpp, zerokey, rq_servact, rq_scope, rq_type,
|
||||
+ noisy, false);
|
||||
+}
|
||||
+
|
||||
static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
struct prout_param_descriptor *paramp, int noisy)
|
||||
@@ -420,8 +436,15 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
break;
|
||||
case MPATH_PROUT_PREE_SA :
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
- if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES)
|
||||
+ if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES) {
|
||||
preempting_reservation = true;
|
||||
+ if (memcmp(paramp->sa_key, &zerokey, 8) == 0) {
|
||||
+ /* all registrants case */
|
||||
+ ret = preempt_all(mpp, rq_servact, rq_scope,
|
||||
+ rq_type, noisy);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
/* if we are preempting ourself */
|
||||
if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
|
||||
ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
|
||||
@@ -893,8 +916,9 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
* is suspended before issuing the preemption, and the keys are reregistered
|
||||
* before resuming it.
|
||||
*/
|
||||
-static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, int noisy, bool do_release)
|
||||
+static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
+ int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
+ int noisy, bool do_release)
|
||||
{
|
||||
int status, rel_status = MPATH_PR_SUCCESS;
|
||||
struct path *pp = NULL;
|
||||
@@ -907,7 +931,7 @@ static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
}
|
||||
|
||||
memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
- memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ memcpy(paramp.sa_key, &sa_key, 8);
|
||||
status = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
¶mp, noisy, &pp);
|
||||
if (status != MPATH_PR_SUCCESS) {
|
||||
@ -0,0 +1,74 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 18 Sep 2025 18:12:07 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix REGISTER AND IGNORE while holding a
|
||||
reservation
|
||||
|
||||
If a device that is holding a reservation changes its registered key,
|
||||
but the path holding the reservation is unavailable, libmpathpersist
|
||||
must preempt the old key to update the reservation. If the key is
|
||||
changed using REGISTER AND IGNORE, set_ignored_key() determines the old
|
||||
key to preempt. Unfortunately, commit 165427dda broke it, by comparing
|
||||
the wrong key against the actual reservation key. Then commit cf0eea85
|
||||
broke it more, by using mpp->reservation_key after it had been updated,
|
||||
so it was no longer the old key. Fix this by correctly comparing the old
|
||||
key against the actual reservation key.
|
||||
|
||||
Fixes: 165427dda ("libmpathpersist: Add safety check for preempting on key change")
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 14 +++++++-------
|
||||
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 92a0021d..6a254d2e 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -309,17 +309,17 @@ static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
* currently registered key for use in preempt_missing_path(), but only if
|
||||
* the key is holding the reservation.
|
||||
*/
|
||||
-static void set_ignored_key(struct multipath *mpp, uint8_t *key)
|
||||
+static void set_ignored_key(struct multipath *mpp, uint8_t *curr_key,
|
||||
+ uint8_t *key)
|
||||
{
|
||||
memset(key, 0, 8);
|
||||
- if (!get_be64(mpp->reservation_key))
|
||||
+ if (memcmp(curr_key, key, 8) == 0)
|
||||
return;
|
||||
if (get_prhold(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
- if (reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key,
|
||||
- 0) == YNU_NO)
|
||||
+ if (reservation_key_matches(mpp, curr_key, 0) == YNU_NO)
|
||||
return;
|
||||
- memcpy(key, &mpp->reservation_key, 8);
|
||||
+ memcpy(key, curr_key, 8);
|
||||
}
|
||||
|
||||
static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
@@ -359,6 +359,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
select_reservation_key(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
+ memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
@@ -367,7 +368,6 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
memcmp(paramp->key, &zerokey, 8) == 0 ||
|
||||
memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
|
||||
updated_prkey = true;
|
||||
- memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
memcpy(&mpp->reservation_key, paramp->sa_key, 8);
|
||||
if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
|
||||
paramp->sa_flags)) {
|
||||
@@ -426,7 +426,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
put_multipath_config(conf);
|
||||
|
||||
if (rq_servact == MPATH_PROUT_REG_IGN_SA)
|
||||
- set_ignored_key(mpp, paramp->key);
|
||||
+ set_ignored_key(mpp, (uint8_t *)&oldkey, paramp->key);
|
||||
|
||||
switch(rq_servact)
|
||||
{
|
||||
@ -0,0 +1,168 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 18 Sep 2025 19:29:08 -0400
|
||||
Subject: [PATCH] libmpathpersist: Handle RESERVE with reservation held by
|
||||
failed path
|
||||
|
||||
Issuing a RESERVE on a device that already holds the reservation should
|
||||
succeed, as long as the type is the same. But if the path that holds the
|
||||
reservation is unavailable, mpathpersist fails, since it gets a
|
||||
reservation conflict on all available paths. To deal with this, if the
|
||||
multipath device has failed paths, and the key holding the reservation
|
||||
matches the multipath device's key, and multipathd says that it is
|
||||
holding the reservation, assume the reservation is held by a failed path
|
||||
and claim the RESERVE succeeded, even though none of the actual scsi
|
||||
commands did
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 48 +++++++++++++++++++++++++--------
|
||||
1 file changed, 37 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 6a254d2e..fce28723 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -104,7 +104,7 @@ int libmpathpersist_exit(void)
|
||||
static int mpath_prout_common(struct multipath *mpp,int rq_servact,
|
||||
int rq_scope, unsigned int rq_type,
|
||||
struct prout_param_descriptor* paramp, int noisy,
|
||||
- struct path **pptr);
|
||||
+ struct path **pptr, bool *failed_paths);
|
||||
|
||||
int
|
||||
mpath_prin_activepath (struct multipath *mpp, int rq_servact,
|
||||
@@ -286,12 +286,12 @@ int __mpath_persistent_reserve_in (int fd, int rq_servact,
|
||||
}
|
||||
|
||||
static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
- int noisy)
|
||||
+ unsigned int *type)
|
||||
{
|
||||
struct prin_resp resp = {0};
|
||||
int status;
|
||||
|
||||
- status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
+ status = mpath_prin_activepath(mpp, MPATH_PRIN_RRES_SA, &resp, 0);
|
||||
if (status != MPATH_PR_SUCCESS) {
|
||||
condlog(0, "%s: pr in read reservation command failed.",
|
||||
mpp->wwid);
|
||||
@@ -299,8 +299,12 @@ static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
||||
}
|
||||
if (!resp.prin_descriptor.prin_readresv.additional_length)
|
||||
return YNU_NO;
|
||||
- if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0)
|
||||
+ if (memcmp(key, resp.prin_descriptor.prin_readresv.key, 8) == 0) {
|
||||
+ if (type)
|
||||
+ *type = resp.prin_descriptor.prin_readresv.scope_type &
|
||||
+ MPATH_PR_TYPE_MASK;
|
||||
return YNU_YES;
|
||||
+ }
|
||||
return YNU_NO;
|
||||
}
|
||||
|
||||
@@ -317,11 +321,20 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *curr_key,
|
||||
return;
|
||||
if (get_prhold(mpp->alias) == PR_UNSET)
|
||||
return;
|
||||
- if (reservation_key_matches(mpp, curr_key, 0) == YNU_NO)
|
||||
+ if (reservation_key_matches(mpp, curr_key, NULL) == YNU_NO)
|
||||
return;
|
||||
memcpy(key, curr_key, 8);
|
||||
}
|
||||
|
||||
+static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
|
||||
+{
|
||||
+ if (get_be64(mpp->reservation_key) &&
|
||||
+ get_prhold(mpp->alias) == PR_SET &&
|
||||
+ reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, int noisy, bool do_release)
|
||||
{
|
||||
@@ -349,6 +362,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
struct config *conf;
|
||||
bool unregistering, preempting_reservation = false;
|
||||
bool updated_prkey = false;
|
||||
+ bool failed_paths = false;
|
||||
|
||||
ret = mpath_get_map(curmp, fd, &alias, &mpp);
|
||||
if (ret != MPATH_PR_SUCCESS)
|
||||
@@ -436,7 +450,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
break;
|
||||
case MPATH_PROUT_PREE_SA :
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
- if (reservation_key_matches(mpp, paramp->sa_key, noisy) == YNU_YES) {
|
||||
+ if (reservation_key_matches(mpp, paramp->sa_key, NULL) == YNU_YES) {
|
||||
preempting_reservation = true;
|
||||
if (memcmp(paramp->sa_key, &zerokey, 8) == 0) {
|
||||
/* all registrants case */
|
||||
@@ -453,10 +467,18 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
}
|
||||
/* fallthrough */
|
||||
case MPATH_PROUT_RES_SA :
|
||||
- case MPATH_PROUT_CLEAR_SA:
|
||||
+ case MPATH_PROUT_CLEAR_SA: {
|
||||
+ unsigned int res_type;
|
||||
ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
- paramp, noisy, NULL);
|
||||
+ paramp, noisy, NULL, &failed_paths);
|
||||
+ if (rq_servact == MPATH_PROUT_RES_SA &&
|
||||
+ ret != MPATH_PR_SUCCESS && failed_paths &&
|
||||
+ check_holding_reservation(mpp, &res_type) &&
|
||||
+ res_type == rq_type)
|
||||
+ /* The reserve failed, but multipathd says we hold it */
|
||||
+ ret = MPATH_PR_SUCCESS;
|
||||
break;
|
||||
+ }
|
||||
case MPATH_PROUT_REL_SA:
|
||||
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
break;
|
||||
@@ -614,7 +636,7 @@ void preempt_missing_path(struct multipath *mpp, uint8_t *key, uint8_t *sa_key,
|
||||
memcpy(paramp.key, sa_key, 8);
|
||||
memcpy(paramp.sa_key, key, 8);
|
||||
status = mpath_prout_common(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
|
||||
- ¶mp, noisy, NULL);
|
||||
+ ¶mp, noisy, NULL, NULL);
|
||||
if (status != MPATH_PR_SUCCESS)
|
||||
condlog(0, "%s: register: pr preempt command failed.",
|
||||
mpp->wwid);
|
||||
@@ -853,7 +875,7 @@ void * mpath_prout_pthread_fn(void *p)
|
||||
static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type,
|
||||
struct prout_param_descriptor* paramp, int noisy,
|
||||
- struct path **pptr)
|
||||
+ struct path **pptr, bool *failed_paths)
|
||||
{
|
||||
int i,j, ret;
|
||||
struct pathgroup *pgp = NULL;
|
||||
@@ -866,6 +888,8 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
|
||||
condlog (1, "%s: %s path not up. Skip",
|
||||
mpp->wwid, pp->dev);
|
||||
+ if (failed_paths)
|
||||
+ *failed_paths = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -899,6 +923,8 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
}
|
||||
if (ret != MPATH_PR_RETRYABLE_ERROR)
|
||||
return ret;
|
||||
+ if (failed_paths)
|
||||
+ *failed_paths = true;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
@@ -933,7 +959,7 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
memcpy(paramp.sa_key, &sa_key, 8);
|
||||
status = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
|
||||
- ¶mp, noisy, &pp);
|
||||
+ ¶mp, noisy, &pp, NULL);
|
||||
if (status != MPATH_PR_SUCCESS) {
|
||||
condlog(0, "%s: self preempt command failed.", mpp->wwid);
|
||||
goto fail_resume;
|
||||
@ -0,0 +1,68 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 22 Sep 2025 17:40:00 -0400
|
||||
Subject: [PATCH] libmpathpersist: use check_holding_reservation in
|
||||
mpath_prout_rel
|
||||
|
||||
Instead of open-coding mostly the same work, just make mpath_prout_rel()
|
||||
call check_holding_reservation().
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 24 ++++--------------------
|
||||
1 file changed, 4 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index fce28723..15141be4 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -997,7 +997,6 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
{
|
||||
int i, j;
|
||||
- int num = 0;
|
||||
struct pathgroup *pgp = NULL;
|
||||
struct path *pp = NULL;
|
||||
int active_pathcount = 0;
|
||||
@@ -1005,9 +1004,8 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
int rc;
|
||||
int count = 0;
|
||||
int status = MPATH_PR_SUCCESS;
|
||||
- struct prin_resp resp = {0};
|
||||
bool all_threads_failed;
|
||||
- unsigned int scope_type;
|
||||
+ unsigned int res_type;
|
||||
|
||||
if (!mpp)
|
||||
return MPATH_PR_DMMP_ERROR;
|
||||
@@ -1086,27 +1084,13 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return status;
|
||||
}
|
||||
|
||||
- status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
|
||||
- if (status != MPATH_PR_SUCCESS){
|
||||
- condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
|
||||
- return MPATH_PR_OTHER;
|
||||
- }
|
||||
-
|
||||
- num = resp.prin_descriptor.prin_readresv.additional_length / 8;
|
||||
- if (num == 0){
|
||||
- condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
|
||||
- return MPATH_PR_SUCCESS;
|
||||
- }
|
||||
- if (!get_be64(mpp->reservation_key) ||
|
||||
- memcmp(&mpp->reservation_key, resp.prin_descriptor.prin_readresv.key, 8)) {
|
||||
+ if (!check_holding_reservation(mpp, &res_type)) {
|
||||
condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
-
|
||||
- scope_type = resp.prin_descriptor.prin_readresv.scope_type;
|
||||
- if ((scope_type & MPATH_PR_TYPE_MASK) != rq_type) {
|
||||
+ if (res_type != rq_type) {
|
||||
condlog(2, "%s: --prout_type %u doesn't match reservation %u",
|
||||
- mpp->wwid, rq_type, scope_type & MPATH_PR_TYPE_MASK);
|
||||
+ mpp->wwid, rq_type, res_type);
|
||||
return MPATH_PR_RESERV_CONFLICT;
|
||||
}
|
||||
|
||||
@ -0,0 +1,287 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 19 Sep 2025 18:17:20 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix unregistering while holding the
|
||||
reservation
|
||||
|
||||
There were two problems with how libmpathpersist handled unregistering
|
||||
a key while holding the reseravation (which should also release the
|
||||
reservation).
|
||||
1. If the path holding the reservation is not unregistered first, there
|
||||
will be unregistered paths, while a reservation is still held, which
|
||||
would cause IO to those paths to fail, when it shouldn't.
|
||||
2. If the path that holds the reservation is down, libmpathpersist was
|
||||
not clearing the reservation, since the there were no registered keys
|
||||
it could use for the PREEMPT command workaround
|
||||
|
||||
To fix these, libmpathpersist now releases the reservation first when
|
||||
trying to unregister a key that is holding the reservation.
|
||||
mpath_prout_rel() has a new option so that if it needs to self preempt
|
||||
to clear the reservation, it won't re-register the paths when called
|
||||
as part of unregistering a key. Also, instead of checking if the device
|
||||
is currently holding a reservation using mpp->reservation_key in
|
||||
check_holding_reservation() (which will already be set to 0 when called
|
||||
as part of unregistering a key), pass in the key to check.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.c | 111 +++++++++++++++++++++++---------
|
||||
libmpathpersist/mpath_persist.h | 3 +
|
||||
libmpathpersist/mpathpr.h | 3 +-
|
||||
3 files changed, 84 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c
|
||||
index 15141be4..72be48c1 100644
|
||||
--- a/libmpathpersist/mpath_persist.c
|
||||
+++ b/libmpathpersist/mpath_persist.c
|
||||
@@ -37,9 +37,15 @@
|
||||
|
||||
extern struct udev *udev;
|
||||
|
||||
+enum preempt_work {
|
||||
+ PREE_WORK_NONE,
|
||||
+ PREE_WORK_REL,
|
||||
+ PREE_WORK_REL_UNREG,
|
||||
+};
|
||||
+
|
||||
static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
- int noisy, bool do_release);
|
||||
+ int noisy, enum preempt_work work);
|
||||
|
||||
static void adapt_config(struct config *conf)
|
||||
{
|
||||
@@ -326,20 +332,22 @@ static void set_ignored_key(struct multipath *mpp, uint8_t *curr_key,
|
||||
memcpy(key, curr_key, 8);
|
||||
}
|
||||
|
||||
-static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
|
||||
+static bool check_holding_reservation(struct multipath *mpp, uint8_t *curr_key,
|
||||
+ unsigned int *type)
|
||||
{
|
||||
- if (get_be64(mpp->reservation_key) &&
|
||||
+ uint64_t zerokey = 0;
|
||||
+ if (memcmp(curr_key, &zerokey, 8) != 0 &&
|
||||
get_prhold(mpp->alias) == PR_SET &&
|
||||
- reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
|
||||
+ reservation_key_matches(mpp, curr_key, type) == YNU_YES)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, int noisy, bool do_release)
|
||||
+ unsigned int rq_type, int noisy, enum preempt_work work)
|
||||
{
|
||||
return do_preempt_self(mpp, mpp->reservation_key, rq_servact, rq_scope,
|
||||
- rq_type, noisy, do_release);
|
||||
+ rq_type, noisy, work);
|
||||
}
|
||||
|
||||
static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
@@ -347,7 +355,7 @@ static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
{
|
||||
struct be64 zerokey = {0};
|
||||
return do_preempt_self(mpp, zerokey, rq_servact, rq_scope, rq_type,
|
||||
- noisy, false);
|
||||
+ noisy, PREE_WORK_NONE);
|
||||
}
|
||||
|
||||
static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
@@ -373,7 +381,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
select_reservation_key(conf, mpp);
|
||||
put_multipath_config(conf);
|
||||
|
||||
- memcpy(&oldkey, &mpp->reservation_key, 8);
|
||||
+ oldkey = mpp->reservation_key;
|
||||
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
|
||||
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
|
||||
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
|
||||
@@ -446,7 +454,27 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
{
|
||||
case MPATH_PROUT_REG_SA:
|
||||
case MPATH_PROUT_REG_IGN_SA:
|
||||
- ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
+ if (unregistering && check_holding_reservation(mpp, (uint8_t *)&oldkey, &rq_type)) {
|
||||
+ struct be64 newkey = mpp->reservation_key;
|
||||
+ /* temporarily restore reservation key */
|
||||
+ mpp->reservation_key = oldkey;
|
||||
+ ret = mpath_prout_rel(mpp, MPATH_PROUT_REL_SA, rq_scope,
|
||||
+ rq_type, paramp, noisy, true);
|
||||
+ mpp->reservation_key = newkey;
|
||||
+ if (ret == MPATH_PR_SUCCESS)
|
||||
+ /*
|
||||
+ * Since unregistering it true, paramp->sa_key
|
||||
+ * must be zero here. So this command will
|
||||
+ * unregister the key.
|
||||
+ */
|
||||
+ ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
+ else if (ret == MPATH_PR_SUCCESS_UNREGISTER)
|
||||
+ /* We already unregistered the key */
|
||||
+ ret = MPATH_PR_SUCCESS;
|
||||
+ } else
|
||||
+ ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
|
||||
+ rq_type, paramp, noisy);
|
||||
break;
|
||||
case MPATH_PROUT_PREE_SA :
|
||||
case MPATH_PROUT_PREE_AB_SA :
|
||||
@@ -462,7 +490,7 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
/* if we are preempting ourself */
|
||||
if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
|
||||
ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
|
||||
- noisy, false);
|
||||
+ noisy, PREE_WORK_NONE);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
@@ -473,14 +501,14 @@ static int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
|
||||
paramp, noisy, NULL, &failed_paths);
|
||||
if (rq_servact == MPATH_PROUT_RES_SA &&
|
||||
ret != MPATH_PR_SUCCESS && failed_paths &&
|
||||
- check_holding_reservation(mpp, &res_type) &&
|
||||
+ check_holding_reservation(mpp, paramp->key, &res_type) &&
|
||||
res_type == rq_type)
|
||||
/* The reserve failed, but multipathd says we hold it */
|
||||
ret = MPATH_PR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
case MPATH_PROUT_REL_SA:
|
||||
- ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
|
||||
+ ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy, false);
|
||||
break;
|
||||
default:
|
||||
ret = MPATH_PR_OTHER;
|
||||
@@ -935,16 +963,16 @@ static int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope
|
||||
|
||||
/*
|
||||
* Called to make a multipath device preempt its own reservation (and
|
||||
- * optionally release the reservation). Doing this causes the reservation
|
||||
- * keys to be removed from all the device paths except that path used to issue
|
||||
- * the preempt, so they need to be restored. To avoid the chance that IO
|
||||
- * goes to these paths when they don't have a registered key, the device
|
||||
- * is suspended before issuing the preemption, and the keys are reregistered
|
||||
- * before resuming it.
|
||||
+ * optional extra work). Doing this causes the reservation keys to be removed
|
||||
+ * from all the device paths except that path used to issue the preempt, so
|
||||
+ * they may need to be restored. To avoid the chance that IO goes to these
|
||||
+ * paths when they don't have a registered key and a reservation exists, the
|
||||
+ * device is suspended before issuing the preemption, and the keys are
|
||||
+ * reregistered (or the reservation is released) before resuming it.
|
||||
*/
|
||||
static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
int rq_servact, int rq_scope, unsigned int rq_type,
|
||||
- int noisy, bool do_release)
|
||||
+ int noisy, enum preempt_work work)
|
||||
{
|
||||
int status, rel_status = MPATH_PR_SUCCESS;
|
||||
struct path *pp = NULL;
|
||||
@@ -965,7 +993,7 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
goto fail_resume;
|
||||
}
|
||||
|
||||
- if (do_release) {
|
||||
+ if (work != PREE_WORK_NONE) {
|
||||
memset(¶mp, 0, sizeof(paramp));
|
||||
memcpy(paramp.key, &mpp->reservation_key, 8);
|
||||
rel_status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA,
|
||||
@@ -973,15 +1001,26 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
|
||||
if (rel_status != MPATH_PR_SUCCESS)
|
||||
condlog(0, "%s: release on alternate path failed.",
|
||||
mpp->wwid);
|
||||
+ else if (work == PREE_WORK_REL_UNREG) {
|
||||
+ /* unregister the last path */
|
||||
+ rel_status = prout_do_scsi_ioctl(pp->dev,
|
||||
+ MPATH_PROUT_REG_IGN_SA,
|
||||
+ rq_scope, rq_type,
|
||||
+ ¶mp, noisy);
|
||||
+ if (rel_status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: final self preempt unregister failed,",
|
||||
+ mpp->wwid);
|
||||
+ }
|
||||
+ }
|
||||
+ if (work != PREE_WORK_REL_UNREG) {
|
||||
+ memset(¶mp, 0, sizeof(paramp));
|
||||
+ memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
+ status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
|
||||
+ rq_type, ¶mp, noisy);
|
||||
+ if (status != MPATH_PR_SUCCESS)
|
||||
+ condlog(0, "%s: self preempt failed to reregister paths.",
|
||||
+ mpp->wwid);
|
||||
}
|
||||
-
|
||||
- memset(¶mp, 0, sizeof(paramp));
|
||||
- memcpy(paramp.sa_key, &mpp->reservation_key, 8);
|
||||
- status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
|
||||
- rq_type, ¶mp, noisy);
|
||||
- if (status != MPATH_PR_SUCCESS)
|
||||
- condlog(0, "%s: self preempt failed to reregister paths.",
|
||||
- mpp->wwid);
|
||||
|
||||
fail_resume:
|
||||
if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
|
||||
@@ -993,8 +1032,9 @@ fail_resume:
|
||||
return (rel_status != MPATH_PR_SUCCESS) ? rel_status : status;
|
||||
}
|
||||
|
||||
-int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
|
||||
+int mpath_prout_rel(struct multipath *mpp, int rq_servact, int rq_scope,
|
||||
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy,
|
||||
+ bool unregister)
|
||||
{
|
||||
int i, j;
|
||||
struct pathgroup *pgp = NULL;
|
||||
@@ -1084,7 +1124,8 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
return status;
|
||||
}
|
||||
|
||||
- if (!check_holding_reservation(mpp, &res_type)) {
|
||||
+ if (!check_holding_reservation(mpp, (uint8_t *)&mpp->reservation_key,
|
||||
+ &res_type)) {
|
||||
condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
@@ -1107,7 +1148,13 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
* 4. Reregistering keys on all the paths
|
||||
* 5. Resuming the device
|
||||
*/
|
||||
- return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
||||
+ status = preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
|
||||
+ noisy,
|
||||
+ unregister ? PREE_WORK_REL_UNREG : PREE_WORK_REL);
|
||||
+ if (status == MPATH_PR_SUCCESS && unregister)
|
||||
+ return MPATH_PR_SUCCESS_UNREGISTER;
|
||||
+ return status;
|
||||
+
|
||||
}
|
||||
|
||||
void * mpath_alloc_prin_response(int prin_sa)
|
||||
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
|
||||
index 8d441d04..807787b5 100644
|
||||
--- a/libmpathpersist/mpath_persist.h
|
||||
+++ b/libmpathpersist/mpath_persist.h
|
||||
@@ -66,6 +66,9 @@ extern "C" {
|
||||
#define MPATH_PR_RETRYABLE_ERROR 16 /* error that might be succeed
|
||||
down another path. Internal
|
||||
only. */
|
||||
+#define MPATH_PR_SUCCESS_UNREGISTER 17 /* Success, and additionally, all
|
||||
+ paths were unregistered.
|
||||
+ Internal only. */
|
||||
|
||||
/* PR MASK */
|
||||
#define MPATH_F_APTPL_MASK 0x01 /* APTPL MASK*/
|
||||
diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h
|
||||
index 27df5fdd..69f402f2 100644
|
||||
--- a/libmpathpersist/mpathpr.h
|
||||
+++ b/libmpathpersist/mpathpr.h
|
||||
@@ -37,7 +37,8 @@ void dumpHex(const char* , int len, int no_ascii);
|
||||
int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
||||
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
|
||||
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy,
|
||||
+ bool unregister);
|
||||
|
||||
int update_prflag(char *mapname, int set);
|
||||
int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags);
|
||||
@ -0,0 +1,215 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 30 Sep 2025 19:36:36 -0400
|
||||
Subject: [PATCH] libmpathpersist: Fix race between restoring a path and
|
||||
preemption
|
||||
|
||||
If a multipath device gets preempted while a path is being restored, the
|
||||
path could end up getting the old key registered on it anyways. This
|
||||
happens by:
|
||||
1. multipathd calling update_map_pr() in mpath_pr_event_handle() and
|
||||
seeing that there are matching keys.
|
||||
2. Those matching keys get preempted.
|
||||
3. multipathd registering the preempted key on the path.
|
||||
|
||||
Since there is no way to guarantee that the key won't get preempted
|
||||
after multipathd checks for it, mpath_pr_event_handle() now calls
|
||||
update_map_pr() to check the registered keys again after registering the
|
||||
key. There must be at least as many keys registered after registering
|
||||
the key on the restored path (which may already have a key registered on
|
||||
it, so it's possible that the number of registered keys doesn't change).
|
||||
|
||||
pr_register_active_paths() calls mpath_pr_event_handle() for all working
|
||||
paths on a device. In order to avoid calling update_map_pr() twice for
|
||||
every path, mpath_pr_event_handle() now takes the number of keys to
|
||||
expect, and skips the initial call to update_map_pr() if it already
|
||||
knows how many keys are registered before trying to register the new
|
||||
path.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/main.c | 78 +++++++++++++++++++++++++++++++----------------
|
||||
1 file changed, 52 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 8a0d9edc..4b0935b5 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -91,7 +91,8 @@
|
||||
#define CMDSIZE 160
|
||||
#define MSG_SIZE 32
|
||||
|
||||
-static void mpath_pr_event_handle(struct path *pp);
|
||||
+static unsigned int
|
||||
+mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed);
|
||||
|
||||
#define LOG_MSG(lvl, pp) \
|
||||
do { \
|
||||
@@ -549,7 +550,7 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) {
|
||||
static void
|
||||
pr_register_active_paths(struct multipath *mpp)
|
||||
{
|
||||
- unsigned int i, j;
|
||||
+ unsigned int i, j, nr_keys = 0;
|
||||
struct path *pp;
|
||||
struct pathgroup *pgp;
|
||||
|
||||
@@ -558,7 +559,7 @@ pr_register_active_paths(struct multipath *mpp)
|
||||
if (mpp->prflag == PR_UNSET)
|
||||
return;
|
||||
if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))
|
||||
- mpath_pr_event_handle(pp);
|
||||
+ nr_keys = mpath_pr_event_handle(pp, nr_keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1184,7 +1185,7 @@ rescan:
|
||||
verify_paths(mpp);
|
||||
mpp->action = ACT_RELOAD;
|
||||
prflag = mpp->prflag;
|
||||
- mpath_pr_event_handle(pp);
|
||||
+ mpath_pr_event_handle(pp, 0);
|
||||
} else {
|
||||
if (!should_multipath(pp, vecs->pathvec, vecs->mpvec)) {
|
||||
orphan_path(pp, "only one path");
|
||||
@@ -2546,7 +2547,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
*/
|
||||
condlog(2, "%s: checking persistent "
|
||||
"reservation registration", pp->dev);
|
||||
- mpath_pr_event_handle(pp);
|
||||
+ mpath_pr_event_handle(pp, 0);
|
||||
if (pp->mpp->prflag == PR_SET &&
|
||||
prflag != PR_SET)
|
||||
pr_register_active_paths(pp->mpp);
|
||||
@@ -3766,12 +3767,16 @@ void unset_pr(struct multipath *mpp)
|
||||
* Returns MPATH_PR_SUCCESS unless if fails to read the PR keys. If
|
||||
* MPATH_PR_SUCCESS is returned, mpp->prflag will be either PR_SET or
|
||||
* PR_UNSET.
|
||||
+ *
|
||||
+ * 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.
|
||||
*/
|
||||
-static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
+static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *nr_keys)
|
||||
{
|
||||
struct prin_resp resp;
|
||||
- unsigned int i;
|
||||
- int ret, isFound;
|
||||
+ unsigned int i, nr_found = 0;
|
||||
+ int ret;
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
@@ -3798,7 +3803,6 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
condlog(4, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias,
|
||||
get_be64(mpp->reservation_key));
|
||||
|
||||
- isFound = 0;
|
||||
for (i = 0; i < resp.prin_descriptor.prin_readkeys.additional_length / 8; i++) {
|
||||
uint8_t *keyp = &resp.prin_descriptor.prin_readkeys.key_list[i * 8];
|
||||
|
||||
@@ -3817,42 +3821,57 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
||||
if (!memcmp(&mpp->reservation_key, keyp, 8) ||
|
||||
(get_be64(mpp->old_pr_key) &&
|
||||
!memcmp(&mpp->old_pr_key, keyp, 8)))
|
||||
- isFound = 1;
|
||||
+ nr_found++;
|
||||
}
|
||||
|
||||
- if (isFound) {
|
||||
+ if (nr_found >= *nr_keys) {
|
||||
set_pr(mpp);
|
||||
- condlog(was_set ? 3 : 2, "%s: key found. prflag set.",
|
||||
- mpp->alias);
|
||||
+ condlog(was_set ? 3 : 2, "%s: %u keys found. prflag set.",
|
||||
+ mpp->alias, nr_found);
|
||||
+ *nr_keys = nr_found;
|
||||
} else {
|
||||
unset_pr(mpp);
|
||||
- condlog(was_set ? 1 : 3, "%s: key not found. prflag unset.",
|
||||
- mpp->alias);
|
||||
+ condlog(was_set ? 1 : 3,
|
||||
+ "%s: %u keys found. needed %u. prflag unset.",
|
||||
+ mpp->alias, nr_found, *nr_keys);
|
||||
}
|
||||
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
-static void mpath_pr_event_handle(struct path *pp)
|
||||
+/*
|
||||
+ * This function is called with the number of registered keys that should be
|
||||
+ * seen for this device to know that the key has not been preempted while the
|
||||
+ * path was getting registered. If 0 is passed in, update_mpath_pr is called
|
||||
+ * before registering the key to figure out the number, assuming that at
|
||||
+ * least one key must exist.
|
||||
+ *
|
||||
+ * The function returns the number of keys that are registered or 0 if
|
||||
+ * it's unknown.
|
||||
+ */
|
||||
+static unsigned int mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
- struct prout_param_descriptor param;
|
||||
+ struct prout_param_descriptor param = {.sa_flags = 0};
|
||||
bool clear_reg = false;
|
||||
|
||||
if (pp->bus != SYSFS_BUS_SCSI) {
|
||||
unset_pr(mpp);
|
||||
- return;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
- if (update_map_pr(mpp, pp) != MPATH_PR_SUCCESS)
|
||||
- return;
|
||||
+ if (nr_keys_needed == 0) {
|
||||
+ nr_keys_needed = 1;
|
||||
+ if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS)
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
|
||||
if (mpp->prflag != PR_SET) {
|
||||
if (!mpp->ever_registered_pr)
|
||||
- return;
|
||||
+ return 0;
|
||||
/*
|
||||
* This path may have been unusable and either the
|
||||
* registration was cleared or the registered
|
||||
@@ -3865,21 +3884,28 @@ static void mpath_pr_event_handle(struct path *pp)
|
||||
clear_reg = true;
|
||||
}
|
||||
|
||||
- memset(¶m, 0, sizeof(param));
|
||||
-
|
||||
if (!clear_reg) {
|
||||
param.sa_flags = mpp->sa_flags;
|
||||
memcpy(param.sa_key, &mpp->reservation_key, 8);
|
||||
param.num_transportid = 0;
|
||||
}
|
||||
-
|
||||
+retry:
|
||||
condlog(3, "%s registration for device %s:%s",
|
||||
clear_reg ? "Clearing" : "Setting", pp->dev, pp->mpp->wwid);
|
||||
|
||||
ret = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REG_IGN_SA, 0, 0, ¶m, 0);
|
||||
- if (ret != MPATH_PR_SUCCESS )
|
||||
- {
|
||||
+ if (ret != MPATH_PR_SUCCESS) {
|
||||
condlog(0, "%s: %s reservation registration failed. Error: %d",
|
||||
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;
|
||||
+ if (mpp->prflag != PR_SET) {
|
||||
+ memset(¶m, 0, sizeof(param));
|
||||
+ clear_reg = true;
|
||||
+ goto retry;
|
||||
+ }
|
||||
+ return nr_keys_needed;
|
||||
}
|
||||
+ return 0;
|
||||
}
|
||||
49
SOURCES/0194-multipathd-Fix-tracking-of-old-PR-key.patch
Normal file
49
SOURCES/0194-multipathd-Fix-tracking-of-old-PR-key.patch
Normal file
@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Tue, 30 Sep 2025 23:32:11 -0400
|
||||
Subject: [PATCH] multipathd: Fix tracking of old PR key
|
||||
|
||||
When libmpathpersist is in the process of changing a registered key,
|
||||
multipathd needs to remember both the old and new values of the key to
|
||||
deal with a race between limpathpersist updating the key and multipathd
|
||||
restoring a failed path. It was supposed to stop remembering the old
|
||||
value when libmpathpersist was done changing the key and issued a
|
||||
"setprstatus" command. However, clearing the old key was done in
|
||||
set_pr(), which only gets called by cli_setprstatus() when registering a
|
||||
new device, not when changing the key on a registered device. Also,
|
||||
set_pr() is called by update_map_pr(). This means that multipathd was
|
||||
forgetting the key when it shouldn't and not when it should. Fix this
|
||||
to only forget the key when cli_setprstatus() is called, and always
|
||||
then.
|
||||
|
||||
Fixes: 1aeffa9e ("libmpathpersist: handle updating key race condition")
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
multipathd/cli_handlers.c | 1 +
|
||||
multipathd/main.c | 1 -
|
||||
2 files changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 93768ef3..541dd700 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1326,6 +1326,7 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data)
|
||||
set_pr(mpp);
|
||||
condlog(2, "%s: prflag set", param);
|
||||
}
|
||||
+ memset(&mpp->old_pr_key, 0, 8);
|
||||
|
||||
|
||||
return 0;
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 4b0935b5..1811747e 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -3752,7 +3752,6 @@ void set_pr(struct multipath *mpp)
|
||||
{
|
||||
mpp->ever_registered_pr = true;
|
||||
mpp->prflag = PR_SET;
|
||||
- memset(&mpp->old_pr_key, 0, 8);
|
||||
}
|
||||
|
||||
void unset_pr(struct multipath *mpp)
|
||||
246
SOURCES/0195-multipathd-Fix-race-while-registering-PR-key.patch
Normal file
246
SOURCES/0195-multipathd-Fix-race-while-registering-PR-key.patch
Normal file
@ -0,0 +1,246 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Thu, 6 Nov 2025 20:08:14 -0500
|
||||
Subject: [PATCH] multipathd: Fix race while registering PR key
|
||||
|
||||
When libmpathpersist registers a key, It first checks which paths are
|
||||
active, then registers the key on those paths, and then tells multipathd
|
||||
that the key has been registered, and it should start tracking it. If
|
||||
a path comes up after libmpathpersist checks for active paths, but before
|
||||
it tells multipathd that the key has been registered, multipathd will not
|
||||
register a key no that path (since it hasn't been told to that the device
|
||||
has a registered key yet). This can leave the device with a path that is
|
||||
missing a key.
|
||||
|
||||
To solve this, when multipathd is told that a key has been registered,
|
||||
it checks if there are the same number of registered keys as active
|
||||
paths. If there aren't, it registers keys on all the paths (at least
|
||||
until the number of registered keys and active paths are equal). To
|
||||
avoid doing a bunch of unnecessary PR work, pr_register_active_paths()
|
||||
has a new option to track the number of active paths, and
|
||||
mpath_pr_event_handle() now takes the number of keys to expect. The
|
||||
first time it's called, when there is an unknown number of keys, if the
|
||||
number of keys it finds matches the number of active_paths, it and
|
||||
pr_register_active_paths() exit early, since there is no registering
|
||||
work to do.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
multipathd/cli_handlers.c | 6 +++-
|
||||
multipathd/main.c | 67 ++++++++++++++++++++++++++++-----------
|
||||
multipathd/main.h | 1 +
|
||||
3 files changed, 54 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||||
index 541dd700..0c63ca9a 100644
|
||||
--- a/multipathd/cli_handlers.c
|
||||
+++ b/multipathd/cli_handlers.c
|
||||
@@ -1324,7 +1324,11 @@ cli_setprstatus(void * v, char ** reply, int * len, void * data)
|
||||
|
||||
if (mpp->prflag != PR_SET) {
|
||||
set_pr(mpp);
|
||||
- condlog(2, "%s: prflag set", param);
|
||||
+ pr_register_active_paths(mpp, true);
|
||||
+ if (mpp->prflag == PR_SET)
|
||||
+ condlog(2, "%s: prflag set", param);
|
||||
+ else
|
||||
+ condlog(0, "%s: Failed to set prflag", param);
|
||||
}
|
||||
memset(&mpp->old_pr_key, 0, 8);
|
||||
|
||||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||||
index 1811747e..a85c0db4 100644
|
||||
--- a/multipathd/main.c
|
||||
+++ b/multipathd/main.c
|
||||
@@ -92,7 +92,8 @@
|
||||
#define MSG_SIZE 32
|
||||
|
||||
static unsigned int
|
||||
-mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed);
|
||||
+mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed,
|
||||
+ unsigned int nr_keys_wanted);
|
||||
|
||||
#define LOG_MSG(lvl, pp) \
|
||||
do { \
|
||||
@@ -547,19 +548,28 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
-static void
|
||||
-pr_register_active_paths(struct multipath *mpp)
|
||||
+void pr_register_active_paths(struct multipath *mpp, bool check_nr_active)
|
||||
{
|
||||
unsigned int i, j, nr_keys = 0;
|
||||
+ unsigned int nr_active = 0;
|
||||
struct path *pp;
|
||||
struct pathgroup *pgp;
|
||||
|
||||
+ if (check_nr_active) {
|
||||
+ nr_active = count_active_paths(mpp);
|
||||
+ if (!nr_active)
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
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);
|
||||
+ 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;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -646,7 +656,7 @@ fail:
|
||||
|
||||
sync_map_state(mpp);
|
||||
|
||||
- pr_register_active_paths(mpp);
|
||||
+ pr_register_active_paths(mpp, false);
|
||||
|
||||
if (VECTOR_SIZE(offline_paths) != 0)
|
||||
handle_orphaned_offline_paths(offline_paths);
|
||||
@@ -1185,7 +1195,7 @@ rescan:
|
||||
verify_paths(mpp);
|
||||
mpp->action = ACT_RELOAD;
|
||||
prflag = mpp->prflag;
|
||||
- mpath_pr_event_handle(pp, 0);
|
||||
+ mpath_pr_event_handle(pp, 0, 0);
|
||||
} else {
|
||||
if (!should_multipath(pp, vecs->pathvec, vecs->mpvec)) {
|
||||
orphan_path(pp, "only one path");
|
||||
@@ -1268,9 +1278,8 @@ rescan:
|
||||
sync_map_state(mpp);
|
||||
|
||||
if (retries >= 0) {
|
||||
- if ((mpp->prflag == PR_SET && prflag != PR_SET) ||
|
||||
- start_waiter)
|
||||
- pr_register_active_paths(mpp);
|
||||
+ if ((mpp->prflag == PR_SET && prflag != PR_SET) || start_waiter)
|
||||
+ pr_register_active_paths(mpp, false);
|
||||
condlog(2, "%s [%s]: path added to devmap %s",
|
||||
pp->dev, pp->dev_t, mpp->alias);
|
||||
return 0;
|
||||
@@ -2547,10 +2556,10 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
|
||||
*/
|
||||
condlog(2, "%s: checking persistent "
|
||||
"reservation registration", pp->dev);
|
||||
- mpath_pr_event_handle(pp, 0);
|
||||
+ mpath_pr_event_handle(pp, 0, 0);
|
||||
if (pp->mpp->prflag == PR_SET &&
|
||||
prflag != PR_SET)
|
||||
- pr_register_active_paths(pp->mpp);
|
||||
+ pr_register_active_paths(pp->mpp, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2887,7 +2896,7 @@ configure (struct vectors * vecs)
|
||||
vector_foreach_slot(mpvec, mpp, i){
|
||||
if (remember_wwid(mpp->wwid) == 1)
|
||||
trigger_paths_udev_change(mpp, true);
|
||||
- pr_register_active_paths(mpp);
|
||||
+ pr_register_active_paths(mpp, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3769,7 +3778,8 @@ 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.
|
||||
+ * the call, *nr_keys will be set to the number of found keys. Otherwise
|
||||
+ * it will be set to 0.
|
||||
*/
|
||||
static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *nr_keys)
|
||||
{
|
||||
@@ -3779,13 +3789,18 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n
|
||||
bool was_set = (mpp->prflag == PR_SET);
|
||||
|
||||
/* If pr is explicitly unset, it must be manually set */
|
||||
- if (mpp->prflag == PR_UNSET)
|
||||
+ if (mpp->prflag == PR_UNSET) {
|
||||
+ *nr_keys = 0;
|
||||
return MPATH_PR_SUCCESS;
|
||||
+ }
|
||||
|
||||
if (!get_be64(mpp->reservation_key)) {
|
||||
/* Nothing to do. Assuming pr mgmt feature is disabled*/
|
||||
unset_pr(mpp);
|
||||
- condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias);
|
||||
+ condlog(was_set ? 2 : 4,
|
||||
+ "%s: reservation_key not set in multipath.conf",
|
||||
+ mpp->alias);
|
||||
+ *nr_keys = 0;
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -3795,7 +3810,9 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n
|
||||
if (ret != MPATH_PR_SUCCESS) {
|
||||
if (ret == MPATH_PR_ILLEGAL_REQ)
|
||||
unset_pr(mpp);
|
||||
- condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
|
||||
+ condlog(0, "%s : pr in read keys service action failed Error=%d",
|
||||
+ mpp->alias, ret);
|
||||
+ *nr_keys = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3833,22 +3850,32 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n
|
||||
condlog(was_set ? 1 : 3,
|
||||
"%s: %u keys found. needed %u. prflag unset.",
|
||||
mpp->alias, nr_found, *nr_keys);
|
||||
+ *nr_keys = 0;
|
||||
}
|
||||
|
||||
return MPATH_PR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
- * This function is called with the number of registered keys that should be
|
||||
+ * This function is called with two numbers
|
||||
+ *
|
||||
+ * nr_keys_needed: the number of registered keys that should be
|
||||
* seen for this device to know that the key has not been preempted while the
|
||||
* path was getting registered. If 0 is passed in, update_mpath_pr is called
|
||||
* before registering the key to figure out the number, assuming that at
|
||||
* least one key must exist.
|
||||
*
|
||||
+ * 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.
|
||||
+ *
|
||||
* The function returns the number of keys that are registered or 0 if
|
||||
* it's unknown.
|
||||
*/
|
||||
-static unsigned int mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed)
|
||||
+static unsigned int
|
||||
+mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed,
|
||||
+ unsigned int nr_keys_wanted)
|
||||
{
|
||||
struct multipath *mpp = pp->mpp;
|
||||
int ret;
|
||||
@@ -3864,6 +3891,8 @@ static unsigned int mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_
|
||||
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)
|
||||
+ return nr_keys_needed;
|
||||
}
|
||||
|
||||
check_prhold(mpp, pp);
|
||||
diff --git a/multipathd/main.h b/multipathd/main.h
|
||||
index 77603751..8a4c5f88 100644
|
||||
--- a/multipathd/main.h
|
||||
+++ b/multipathd/main.h
|
||||
@@ -60,4 +60,5 @@ 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);
|
||||
#endif /* MAIN_H */
|
||||
108
SOURCES/0196-mpathpersist-Fix-REPORT-CAPABILITIES-output.patch
Normal file
108
SOURCES/0196-mpathpersist-Fix-REPORT-CAPABILITIES-output.patch
Normal file
@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Mon, 10 Nov 2025 15:25:51 -0500
|
||||
Subject: [PATCH] mpathpersist: Fix REPORT CAPABILITIES output
|
||||
|
||||
mpathpersist was incorrectly parsing the REPORT CAPABILITES service
|
||||
action output. In reality, the type mask is two bytes where the type
|
||||
information is stored in bits 7, 6, 5, 3, & 1 (0xea) of the first byte
|
||||
and bit 0 (0x01) of the second byte. libmpathpersist was treating these
|
||||
two bytes as a big endian 16 bit number, but mpathpersist was looking
|
||||
for bits in that number as if it was little endian number.
|
||||
|
||||
Ideally, libmpathpersist would treat prin_capdescr.pr_type_mask as
|
||||
two bytes, like it does for the flags. But we already expose this
|
||||
as a 16 bit number, where we treated the input bytes as a big endian
|
||||
number. There's no great reason to mess with the libmpathpersist API,
|
||||
when we can just make mpathpersist treat this data like libmpathpersist
|
||||
provides it. So, fix mpathpersist to print the data out correctly.
|
||||
|
||||
Additionally, instead of printing a 1 or a 0 to indicate if a type was
|
||||
supported or not, it was printing the value of the type flag. Also,
|
||||
Persist Through Power Loss Capable (PTPL_C) was being reported if any
|
||||
bit in flags[0] was set. Fix these as well. Reformat all of the
|
||||
capability printing lines, since it is less confusing than only
|
||||
reformatting some of them.
|
||||
|
||||
Fixes: ae4e8a6 ("mpathpersist: Add new utility for managing persistent reservation on dm multipath device")
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
libmpathpersist/mpath_persist.h | 4 ++-
|
||||
mpathpersist/main.c | 43 +++++++++++++++++++++++----------
|
||||
2 files changed, 33 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h
|
||||
index 807787b5..3d6fa51d 100644
|
||||
--- a/libmpathpersist/mpath_persist.h
|
||||
+++ b/libmpathpersist/mpath_persist.h
|
||||
@@ -118,7 +118,9 @@ struct prin_capdescr
|
||||
{
|
||||
uint16_t length;
|
||||
uint8_t flags[2];
|
||||
- uint16_t pr_type_mask;
|
||||
+ uint16_t pr_type_mask; /* The two bytes of the type mask are treated
|
||||
+ as a single big-endian number. So the valid
|
||||
+ type bits are 0xea01 */
|
||||
uint16_t _reserved;
|
||||
};
|
||||
|
||||
diff --git a/mpathpersist/main.c b/mpathpersist/main.c
|
||||
index 26c69b01..a0646cde 100644
|
||||
--- a/mpathpersist/main.c
|
||||
+++ b/mpathpersist/main.c
|
||||
@@ -754,25 +754,42 @@ void mpath_print_buf_readcap( struct prin_resp *pr_buff)
|
||||
|
||||
printf("Report capabilities response:\n");
|
||||
|
||||
- printf(" Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
|
||||
- printf(" Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
|
||||
- printf(" All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 ));
|
||||
- printf(" Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0]));
|
||||
- printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
|
||||
- printf(" Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
|
||||
+ printf(" Compatible Reservation Handling(CRH): %d\n",
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
|
||||
+ printf(" Specify Initiator Ports Capable(SIP_C): %d\n",
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
|
||||
+ printf(" All Target Ports Capable(ATP_C): %d\n",
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4));
|
||||
+ printf(" Persist Through Power Loss Capable(PTPL_C): %d\n",
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x1));
|
||||
+ printf(" Type Mask Valid(TMV): %d\n",
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
|
||||
+ printf(" Allow Commands: %d\n",
|
||||
+ !!((pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
|
||||
printf(" Persist Through Power Loss Active(PTPL_A): %d\n",
|
||||
- !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
|
||||
|
||||
if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)
|
||||
{
|
||||
printf(" Support indicated in Type mask:\n");
|
||||
|
||||
- printf(" %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80);
|
||||
- printf(" %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40);
|
||||
- printf(" %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20);
|
||||
- printf(" %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8);
|
||||
- printf(" %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2);
|
||||
- printf(" %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100);
|
||||
+ printf(" %s: %d\n", pr_type_strs[7],
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask &
|
||||
+ 0x8000));
|
||||
+ printf(" %s: %d\n", pr_type_strs[6],
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask &
|
||||
+ 0x4000));
|
||||
+ printf(" %s: %d\n", pr_type_strs[5],
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask &
|
||||
+ 0x2000));
|
||||
+ printf(" %s: %d\n", pr_type_strs[3],
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask &
|
||||
+ 0x800));
|
||||
+ printf(" %s: %d\n", pr_type_strs[1],
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask &
|
||||
+ 0x200));
|
||||
+ printf(" %s: %d\n", pr_type_strs[8],
|
||||
+ !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
Name: device-mapper-multipath
|
||||
Version: 0.8.7
|
||||
Release: 39%{?dist}
|
||||
Release: 39%{?dist}.1
|
||||
Summary: Tools to manage multipath devices using device-mapper
|
||||
License: GPLv2
|
||||
URL: http://christophe.varoqui.free.fr/
|
||||
@ -159,6 +159,53 @@ Patch0146: 0146-multipath-tools-add-HPE-as-vendor-for-OPEN-XP8-array.patch
|
||||
Patch0147: 0147-multipath-tools-add-HP-HSVX740-to-hwtable.patch
|
||||
Patch0148: 0148-multipath-tools-add-DellEMC-ME5-PowerVault-ME5-to-ha.patch
|
||||
Patch0149: 0149-multipath-tools-add-HPE-MSA-Gen7-2070-2072-to-hwtabl.patch
|
||||
Patch0150: 0150-libmpathpersist-retry-commands-on-other-paths-in-mpa.patch
|
||||
Patch0151: 0151-libmpathpersist-check-released-key-against-the-reser.patch
|
||||
Patch0152: 0152-multipathd-remove-thread-from-mpath_pr_event_handle.patch
|
||||
Patch0153: 0153-libmpathpersist-remove-uneeded-wrapper-function.patch
|
||||
Patch0154: 0154-libmpathpersist-reduce-log-level-for-persistent-rese.patch
|
||||
Patch0155: 0155-libmpathpersist-remove-pointless-update_map_pr-ret-v.patch
|
||||
Patch0156: 0156-multipathd-use-update_map_pr-in-mpath_pr_event_handl.patch
|
||||
Patch0157: 0157-libmpathpersist-limit-changing-prflag-in-update_map_.patch
|
||||
Patch0158: 0158-multipathd-Don-t-call-update_map_pr-unnecessarily.patch
|
||||
Patch0159: 0159-libmpathpersist-remove-useless-function-send_prout_a.patch
|
||||
Patch0160: 0160-libmpathpersist-fix-memory-leak-in-mpath_prout_rel.patch
|
||||
Patch0161: 0161-limpathpersist-redesign-failed-release-workaround.patch
|
||||
Patch0162: 0162-libmpathpersist-fail-the-release-if-all-threads-fail.patch
|
||||
Patch0163: 0163-limpathpersist-Handle-changing-key-corner-case.patch
|
||||
Patch0164: 0164-libmpathpersist-fix-command-keyword-ordering.patch
|
||||
Patch0165: 0165-libmpathpersist-use-conf-timeout-for-updating-persis.patch
|
||||
Patch0166: 0166-libmapthpersist-Handle-REGISTER-AND-IGNORE-changing-.patch
|
||||
Patch0167: 0167-libmultipath-rename-prflag_value-enums.patch
|
||||
Patch0168: 0168-libmpathpersist-use-a-switch-statement-for-prout-com.patch
|
||||
Patch0169: 0169-libmpathpersist-Add-safety-check-for-preempting-on-k.patch
|
||||
Patch0170: 0170-limpathpersist-remove-update_map_pr-code-for-NULL-pp.patch
|
||||
Patch0171: 0171-libmpathpersist-move-update_map_pr-to-multipathd.patch
|
||||
Patch0172: 0172-multipathd-clean-up-update_map_pr-and-mpath_pr_event.patch
|
||||
Patch0173: 0173-libmpathpersist-clean-up-duplicate-function-declarat.patch
|
||||
Patch0174: 0174-multipathd-wrap-setting-and-unsetting-prflag.patch
|
||||
Patch0175: 0175-multipathd-unregister-PR-key-when-path-is-restored-i.patch
|
||||
Patch0176: 0176-libmpathpersist-Fix-up-reservation_key-checking.patch
|
||||
Patch0177: 0177-libmpathpersist-change-how-reservation-conflicts-are.patch
|
||||
Patch0178: 0178-libmpathpersist-Clear-prkey-in-multipathd-before-unr.patch
|
||||
Patch0179: 0179-libmpathpersist-only-clear-the-key-if-we-are-using-t.patch
|
||||
Patch0180: 0180-libmpathpersist-Restore-old-reservation-key-on-failu.patch
|
||||
Patch0181: 0181-libmpatpersist-update-reservation-key-before-checkin.patch
|
||||
Patch0182: 0182-libmpathpersist-retry-on-conflicts-in-mpath_prout_co.patch
|
||||
Patch0183: 0183-libmpathpersist-Don-t-always-fail-registrations-for-.patch
|
||||
Patch0184: 0184-libmpathpersist-Don-t-try-release-workaround-for-inv.patch
|
||||
Patch0185: 0185-libmpathpersist-Don-t-fail-RESERVE-commands-unnecess.patch
|
||||
Patch0186: 0186-libmpathpersist-reregister-keys-when-self-preempting.patch
|
||||
Patch0187: 0187-libmpathpersist-handle-updating-key-race-condition.patch
|
||||
Patch0188: 0188-libmpathpersist-handle-preempting-all-registrants-re.patch
|
||||
Patch0189: 0189-libmpathpersist-Fix-REGISTER-AND-IGNORE-while-holdin.patch
|
||||
Patch0190: 0190-libmpathpersist-Handle-RESERVE-with-reservation-held.patch
|
||||
Patch0191: 0191-libmpathpersist-use-check_holding_reservation-in-mpa.patch
|
||||
Patch0192: 0192-libmpathpersist-Fix-unregistering-while-holding-the-.patch
|
||||
Patch0193: 0193-libmpathpersist-Fix-race-between-restoring-a-path-an.patch
|
||||
Patch0194: 0194-multipathd-Fix-tracking-of-old-PR-key.patch
|
||||
Patch0195: 0195-multipathd-Fix-race-while-registering-PR-key.patch
|
||||
Patch0196: 0196-mpathpersist-Fix-REPORT-CAPABILITIES-output.patch
|
||||
|
||||
|
||||
# runtime
|
||||
@ -362,6 +409,58 @@ fi
|
||||
%{_pkgconfdir}/libdmmp.pc
|
||||
|
||||
%changelog
|
||||
* Tue Nov 11 2025 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-39.1
|
||||
- Add 0150-libmpathpersist-retry-commands-on-other-paths-in-mpa.patch
|
||||
- Add 0151-libmpathpersist-check-released-key-against-the-reser.patch
|
||||
- Add 0152-multipathd-remove-thread-from-mpath_pr_event_handle.patch
|
||||
- Add 0153-libmpathpersist-remove-uneeded-wrapper-function.patch
|
||||
- Add 0154-libmpathpersist-reduce-log-level-for-persistent-rese.patch
|
||||
- Add 0155-libmpathpersist-remove-pointless-update_map_pr-ret-v.patch
|
||||
- Add 0156-multipathd-use-update_map_pr-in-mpath_pr_event_handl.patch
|
||||
- Add 0157-libmpathpersist-limit-changing-prflag-in-update_map_.patch
|
||||
- Add 0158-multipathd-Don-t-call-update_map_pr-unnecessarily.patch
|
||||
- Add 0159-libmpathpersist-remove-useless-function-send_prout_a.patch
|
||||
- Add 0160-libmpathpersist-fix-memory-leak-in-mpath_prout_rel.patch
|
||||
- Add 0161-limpathpersist-redesign-failed-release-workaround.patch
|
||||
- Add 0162-libmpathpersist-fail-the-release-if-all-threads-fail.patch
|
||||
- Add 0163-limpathpersist-Handle-changing-key-corner-case.patch
|
||||
- Add 0164-libmpathpersist-fix-command-keyword-ordering.patch
|
||||
- Add 0165-libmpathpersist-use-conf-timeout-for-updating-persis.patch
|
||||
- Add 0166-libmapthpersist-Handle-REGISTER-AND-IGNORE-changing-.patch
|
||||
- Add 0167-libmultipath-rename-prflag_value-enums.patch
|
||||
- Add 0168-libmpathpersist-use-a-switch-statement-for-prout-com.patch
|
||||
- Add 0169-libmpathpersist-Add-safety-check-for-preempting-on-k.patch
|
||||
- Add 0170-limpathpersist-remove-update_map_pr-code-for-NULL-pp.patch
|
||||
- Add 0171-libmpathpersist-move-update_map_pr-to-multipathd.patch
|
||||
- Add 0172-multipathd-clean-up-update_map_pr-and-mpath_pr_event.patch
|
||||
- Add 0173-libmpathpersist-clean-up-duplicate-function-declarat.patch
|
||||
- Add 0174-multipathd-wrap-setting-and-unsetting-prflag.patch
|
||||
- Add 0175-multipathd-unregister-PR-key-when-path-is-restored-i.patch
|
||||
- Add 0176-libmpathpersist-Fix-up-reservation_key-checking.patch
|
||||
- Add 0177-libmpathpersist-change-how-reservation-conflicts-are.patch
|
||||
- Add 0178-libmpathpersist-Clear-prkey-in-multipathd-before-unr.patch
|
||||
- Add 0179-libmpathpersist-only-clear-the-key-if-we-are-using-t.patch
|
||||
- Add 0180-libmpathpersist-Restore-old-reservation-key-on-failu.patch
|
||||
- Add 0181-libmpatpersist-update-reservation-key-before-checkin.patch
|
||||
- Add 0182-libmpathpersist-retry-on-conflicts-in-mpath_prout_co.patch
|
||||
- Add 0183-libmpathpersist-Don-t-always-fail-registrations-for-.patch
|
||||
- Add 0184-libmpathpersist-Don-t-try-release-workaround-for-inv.patch
|
||||
- Add 0185-libmpathpersist-Don-t-fail-RESERVE-commands-unnecess.patch
|
||||
- Add 0186-libmpathpersist-reregister-keys-when-self-preempting.patch
|
||||
- Add 0187-libmpathpersist-handle-updating-key-race-condition.patch
|
||||
- Add 0188-libmpathpersist-handle-preempting-all-registrants-re.patch
|
||||
- Add 0189-libmpathpersist-Fix-REGISTER-AND-IGNORE-while-holdin.patch
|
||||
- Add 0190-libmpathpersist-Handle-RESERVE-with-reservation-held.patch
|
||||
- Add 0191-libmpathpersist-use-check_holding_reservation-in-mpa.patch
|
||||
- Add 0192-libmpathpersist-Fix-unregistering-while-holding-the-.patch
|
||||
- Add 0193-libmpathpersist-Fix-race-between-restoring-a-path-an.patch
|
||||
- Add 0194-multipathd-Fix-tracking-of-old-PR-key.patch
|
||||
- Add 0195-multipathd-Fix-race-while-registering-PR-key.patch
|
||||
- Add 0196-mpathpersist-Fix-REPORT-CAPABILITIES-output.patch
|
||||
* Fixes RHEL-118723 ("There are many bugs in multipath's persistent
|
||||
reservation handling [rhel-9.7.z]")
|
||||
- Resolves: RHEL-118723
|
||||
|
||||
* Mon Jul 14 2025 Benjamin Marzinski <bmarzins@redhat.com> - 0.8.7-39
|
||||
- Add 0145-multipath-tools-add-DellEMC-ME4-PowerVault-ME4-to-ha.patch
|
||||
- Add 0146-multipath-tools-add-HPE-as-vendor-for-OPEN-XP8-array.patch
|
||||
|
||||
Loading…
Reference in New Issue
Block a user