Add 0035-libmpathpersist-fix-memory-leak-in-mpath_prout_rel.patch Add 0036-libmpathpersist-retry-commands-on-other-paths-in-mpa.patch Add 0037-libmpathpersist-check-released-key-against-the-reser.patch Add 0038-multipathd-remove-thread-from-mpath_pr_event_handle.patch Add 0039-libmpathpersist-remove-uneeded-wrapper-function.patch Add 0040-libmpathpersist-reduce-log-level-for-persistent-rese.patch Add 0041-libmpathpersist-remove-pointless-update_map_pr-ret-v.patch Add 0042-multipathd-use-update_map_pr-in-mpath_pr_event_handl.patch Add 0043-libmpathpersist-limit-changing-prflag-in-update_map_.patch Add 0044-multipathd-Don-t-call-update_map_pr-unnecessarily.patch Add 0045-libmpathpersist-remove-useless-function-send_prout_a.patch Add 0046-libmpathpersist-redesign-failed-release-workaround.patch Add 0047-libmpathpersist-fail-the-release-if-all-threads-fail.patch Add 0048-libmpathpersist-Handle-changing-key-corner-case.patch Add 0049-libmpathpersist-Handle-REGISTER-AND-IGNORE-changing-.patch Add 0050-libmultipath-rename-prflag_value-enums.patch Add 0051-libmpathpersist-use-a-switch-statement-for-prout-com.patch Add 0052-libmpathpersist-Add-safety-check-for-preempting-on-k.patch Add 0053-libmpathpersist-remove-update_map_pr-code-for-NULL-p.patch Add 0054-libmpathpersist-move-update_map_pr-to-multipathd.patch Add 0055-multipathd-clean-up-update_map_pr-and-mpath_pr_event.patch Add 0056-libmpathpersist-clean-up-duplicate-function-declarat.patch Add 0057-multipathd-wrap-setting-and-unsetting-prflag.patch Add 0058-multipathd-unregister-PR-key-when-path-is-restored-i.patch Add 0059-libmpathpersist-Fix-up-reservation_key-checking.patch Add 0060-libmpathpersist-change-how-reservation-conflicts-are.patch Add 0061-libmpathpersist-Clear-prkey-in-multipathd-before-unr.patch Add 0062-libmpathpersist-only-clear-the-key-if-we-are-using-t.patch Add 0063-libmpathpersist-Restore-old-reservation-key-on-failu.patch Add 0064-libmpathpersist-update-reservation-key-before-checki.patch Add 0065-libmpathpersist-retry-on-conflicts-in-mpath_prout_co.patch Add 0066-libmpathpersist-Don-t-always-fail-registrations-for-.patch Add 0067-libmpathpersist-Don-t-try-release-workaround-for-inv.patch Add 0068-libmpathpersist-Don-t-fail-RESERVE-commands-unnecess.patch Add 0069-libmpathpersist-reregister-keys-when-self-preempting.patch Add 0070-libmpathpersist-handle-updating-key-race-condition.patch Add 0071-libmpathpersist-handle-preempting-all-registrants-re.patch Add 0072-libmpathpersist-Fix-REGISTER-AND-IGNORE-while-holdin.patch Add 0073-libmpathpersist-Handle-RESERVE-with-reservation-held.patch Add 0074-libmpathpersist-use-check_holding_reservation-in-mpa.patch Add 0075-libmpathpersist-Fix-unregistering-while-holding-the-.patch Add 0076-libmpathpersist-Fix-race-between-restoring-a-path-an.patch Add 0077-multipathd-Fix-tracking-of-old-PR-key.patch * Fixes RHEL-118720 ("There are many bugs in multipath's persistent reservation handling [rhel-10]") Resolves: RHEL-118720
160 lines
6.2 KiB
Diff
160 lines
6.2 KiB
Diff
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_int.c | 47 +++++++++++++++++++++++------
|
|
1 file changed, 37 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
|
|
index e3514137..0cb08f88 100644
|
|
--- a/libmpathpersist/mpath_persist_int.c
|
|
+++ b/libmpathpersist/mpath_persist_int.c
|
|
@@ -210,7 +210,7 @@ static 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)
|
|
+ int noisy, struct path **pptr, bool *failed_paths)
|
|
{
|
|
int i, j, ret;
|
|
struct pathgroup *pgp = NULL;
|
|
@@ -223,6 +223,8 @@ 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;
|
|
}
|
|
|
|
@@ -257,6 +259,8 @@ 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)
|
|
@@ -343,7 +347,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);
|
|
+ rq_type, ¶mp, noisy, NULL, NULL);
|
|
if (status != MPATH_PR_SUCCESS)
|
|
condlog(0, "%s: register: pr preempt command failed.", mpp->wwid);
|
|
}
|
|
@@ -596,7 +600,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;
|
|
@@ -779,20 +783,25 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
|
|
return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
|
|
}
|
|
|
|
-static int reservation_key_matches(struct multipath *mpp, uint8_t *key, int noisy)
|
|
+static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
|
|
+ unsigned int *type)
|
|
{
|
|
struct prin_resp resp = {{{.prgeneration = 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);
|
|
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)
|
|
+ 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;
|
|
}
|
|
|
|
@@ -809,11 +818,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;
|
|
+}
|
|
+
|
|
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)
|
|
@@ -826,6 +844,7 @@ 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)
|
|
@@ -921,7 +940,7 @@ 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 */
|
|
@@ -938,10 +957,18 @@ 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;
|