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
109 lines
3.7 KiB
Diff
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;
|
|
}
|
|
|