device-mapper-multipath/0070-libmpathpersist-handle-updating-key-race-condition.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

109 lines
3.7 KiB
Diff

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 c66d293b..4fbde5ad 100644
--- a/libmultipath/prkey.c
+++ b/libmultipath/prkey.c
@@ -222,10 +222,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 90127641..2ff195f3 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -487,6 +487,7 @@ struct multipath {
/* persistent management data*/
int prkey_source;
struct be64 reservation_key;
+ struct be64 old_pr_key;
uint8_t sa_flags;
int prflag;
int prhold;
diff --git a/multipathd/main.c b/multipathd/main.c
index 484c8ac1..3b53d140 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -3967,6 +3967,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)
@@ -3974,6 +3975,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);
}
/*
@@ -4026,7 +4028,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;
}