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
146 lines
4.7 KiB
Diff
146 lines
4.7 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
|
Date: Fri, 25 Jul 2025 23:58:47 -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>
|
|
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
|
---
|
|
libmultipath/structs.h | 2 ++
|
|
multipathd/main.c | 46 ++++++++++++++++++++++++++++++++----------
|
|
2 files changed, 37 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
|
index 6d0cd867..90127641 100644
|
|
--- a/libmultipath/structs.h
|
|
+++ b/libmultipath/structs.h
|
|
@@ -491,6 +491,8 @@ struct multipath {
|
|
int prflag;
|
|
int prhold;
|
|
int all_tg_pt;
|
|
+ bool ever_registered_pr;
|
|
+
|
|
struct gen_multipath generic_mp;
|
|
bool fpin_must_reload;
|
|
};
|
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
|
index e29ab2b8..484c8ac1 100644
|
|
--- a/multipathd/main.c
|
|
+++ b/multipathd/main.c
|
|
@@ -2644,7 +2644,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.
|
|
@@ -3964,6 +3965,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;
|
|
}
|
|
|
|
@@ -3974,16 +3976,21 @@ 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*/
|
|
@@ -3991,7 +3998,7 @@ static int update_map_pr(struct multipath *mpp, struct path *pp)
|
|
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));
|
|
@@ -4040,6 +4047,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);
|
|
@@ -4051,20 +4059,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);
|
|
}
|
|
}
|