device-mapper-multipath/0060-libmpathpersist-change-how-reservation-conflicts-are.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

140 lines
5.5 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Fri, 25 Jul 2025 23:58:49 -0400
Subject: [PATCH] libmpathpersist: change how reservation conflicts are handled
If registering a key on a path fails with a reservation conflict in
mpath_prout_reg(), libmpathpersist currently tries to roll back the
registration. This code doesn't always make much sense. First, it
updates the configured key, but doesn't fix it if it does a rollback.
Second, it always rolls the key back to 0x0, unregistering paths that
may have been previously registered. These rollback only happen on the
paths where the registration succeeded, meaning that they were in the
expected state when the command was run. The paths where the command
failed, that were in an unexpected state, remain in that state.
The code no longer attempts to rollback registrations that failed
with a reservation conflict. Instead, it checks that at least one
path was in the expected state and was successfully registered. If
so, then it assumes that the registration command was a resonable one
and retries it on the paths that failed with a reservation conflict.
But instead of using MPATH_PROUT_REG_SA, it uses MPATH_PROUT_REG_IGN_SA
so that it will ignore the current key. This will keep it from
failing with a reservation conflict because the path doesn't have the
expected key registered on it. If path reservations failed for reasons
other than a reservation conflict, the command still returns failure.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmpathpersist/mpath_persist_int.c | 71 ++++++++++++++++++-----------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
index ded1af38..e2dc5773 100644
--- a/libmpathpersist/mpath_persist_int.c
+++ b/libmpathpersist/mpath_persist_int.c
@@ -356,13 +356,13 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
int i, j, k;
struct pathgroup *pgp = NULL;
struct path *pp = NULL;
- int rollback = 0;
+ bool can_retry = false;
+ bool need_retry = false;
int active_pathcount=0;
int rc;
int count=0;
int status = MPATH_PR_SUCCESS;
int all_tg_pt;
- uint64_t sa_key = 0;
if (!mpp)
return MPATH_PR_DMMP_ERROR;
@@ -451,43 +451,62 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
}
}
- if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
- rollback = 1;
- sa_key = get_unaligned_be64(&paramp->sa_key[0]);
- status = MPATH_PR_RESERV_CONFLICT ;
- }
- if (!rollback && (status == MPATH_PR_SUCCESS)){
+ /*
+ * We only retry if there is at least one registration that
+ * returned a reservation conflict (which we need to retry)
+ * and at least one registration the return success, so we
+ * know that the command worked on some of the paths. If
+ * the registation fails on all paths, then it wasn't a
+ * valid request, so there's no need to retry.
+ */
+ if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
+ need_retry = true;
+ else if (thread[i].param.status == MPATH_PR_SUCCESS)
+ can_retry = true;
+ else if (status == MPATH_PR_SUCCESS)
status = thread[i].param.status;
- }
}
- if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
- condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
- memcpy(&paramp->key, &paramp->sa_key, 8);
- memset(&paramp->sa_key, 0, 8);
- for( i=0 ; i < count ; i++){
- if(thread[i].param.status == MPATH_PR_SUCCESS) {
- rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
- (void *)(&thread[i].param));
- if (rc){
- condlog (0, "%s: failed to create thread for rollback. %d", mpp->wwid, rc);
- thread[i].param.status = MPATH_PR_THREAD_ERROR;
- }
- } else
+ if (need_retry && can_retry && rq_servact == MPATH_PROUT_REG_SA &&
+ status == MPATH_PR_SUCCESS) {
+ condlog(3, "%s: ERROR: initiating pr out retry", mpp->wwid);
+ for (i = 0; i < count; i++) {
+ if (thread[i].param.status != MPATH_PR_RESERV_CONFLICT) {
thread[i].param.status = MPATH_PR_SKIP;
+ continue;
+ }
+ /*
+ * retry using MPATH_PROUT_REG_IGN_SA to avoid
+ * conflicts. We already know that some paths
+ * succeeded using MPATH_PROUT_REG_SA.
+ */
+ thread[i].param.rq_servact = MPATH_PROUT_REG_IGN_SA;
+ rc = pthread_create(&thread[i].id, &attr,
+ mpath_prout_pthread_fn,
+ (void *)(&thread[i].param));
+ if (rc) {
+ condlog(0, "%s: failed to create thread for retry. %d",
+ mpp->wwid, rc);
+ thread[i].param.status = MPATH_PR_THREAD_ERROR;
+ }
}
- for(i=0; i < count ; i++){
+ for (i = 0; i < count; i++) {
if (thread[i].param.status != MPATH_PR_SKIP &&
thread[i].param.status != MPATH_PR_THREAD_ERROR) {
rc = pthread_join(thread[i].id, NULL);
- if (rc){
- condlog (3, "%s: failed to join thread while rolling back %d",
- mpp->wwid, i);
+ if (rc) {
+ condlog(3, "%s: failed to join thread while retrying %d",
+ mpp->wwid, i);
}
+ if (status == MPATH_PR_SUCCESS)
+ status = thread[i].param.status;
}
}
+ need_retry = false;
}
pthread_attr_destroy(&attr);
+ if (need_retry)
+ status = MPATH_PR_RESERV_CONFLICT;
if (status == MPATH_PR_SUCCESS)
preempt_missing_path(mpp, paramp->key, paramp->sa_key, noisy);
return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status;