device-mapper-multipath/0058-multipathd-unregister-PR-key-when-path-is-restored-i.patch
Benjamin Marzinski 695f9436f4 device-mapper-multipath-0.9.9-13
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
2025-10-01 16:53:32 -04:00

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(&param, 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, &param, 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);
}
}