Skip to content

Commit 970f693

Browse files
bmarzinsmwilck
authored andcommitted
libmpathpersist: Fix unregistering while holding the reservation
There were two problems with how libmpathpersist handled unregistering a key while holding the reseravation (which should also release the reservation). 1. If the path holding the reservation is not unregistered first, there will be unregistered paths, while a reservation is still held, which would cause IO to those paths to fail, when it shouldn't. 2. If the path that holds the reservation is down, libmpathpersist was not clearing the reservation, since the there were no registered keys it could use for the PREEMPT command workaround To fix these, libmpathpersist now releases the reservation first when trying to unregister a key that is holding the reservation. mpath_prout_rel() has a new option so that if it needs to self preempt to clear the reservation, it won't re-register the paths when called as part of unregistering a key. Also, instead of checking if the device is currently holding a reservation using mpp->reservation_key in check_holding_reservation() (which will already be set to 0 when called as part of unregistering a key), pass in the key to check. Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
1 parent f23b015 commit 970f693

2 files changed

Lines changed: 80 additions & 31 deletions

File tree

libmpathpersist/mpath_persist.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ extern "C" {
6565
#define MPATH_PR_RETRYABLE_ERROR 16 /* error that might be succeed
6666
down another path. Internal
6767
only. */
68+
#define MPATH_PR_SUCCESS_UNREGISTER 17 /* Success, and additionally, all
69+
paths were unregistered.
70+
Internal only. */
6871

6972
/* PR MASK */
7073
#define MPATH_F_APTPL_MASK 0x01 /* APTPL MASK*/

libmpathpersist/mpath_persist_int.c

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -564,18 +564,23 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
564564
return status;
565565
}
566566

567+
enum preempt_work {
568+
PREE_WORK_NONE,
569+
PREE_WORK_REL,
570+
PREE_WORK_REL_UNREG,
571+
};
567572
/*
568573
* Called to make a multipath device preempt its own reservation (and
569-
* optionally release the reservation). Doing this causes the reservation
570-
* keys to be removed from all the device paths except that path used to issue
571-
* the preempt, so they need to be restored. To avoid the chance that IO
572-
* goes to these paths when they don't have a registered key, the device
573-
* is suspended before issuing the preemption, and the keys are reregistered
574-
* before resuming it.
574+
* optional extra work). Doing this causes the reservation keys to be removed
575+
* from all the device paths except that path used to issue the preempt, so
576+
* they may need to be restored. To avoid the chance that IO goes to these
577+
* paths when they don't have a registered key and a reservation exists, the
578+
* device is suspended before issuing the preemption, and the keys are
579+
* reregistered (or the reservation is released) before resuming it.
575580
*/
576581
static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
577582
int rq_servact, int rq_scope, unsigned int rq_type,
578-
int noisy, bool do_release)
583+
int noisy, enum preempt_work work)
579584
{
580585
int status, rel_status = MPATH_PR_SUCCESS;
581586
struct path *pp = NULL;
@@ -596,23 +601,34 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
596601
goto fail_resume;
597602
}
598603

599-
if (do_release) {
604+
if (work != PREE_WORK_NONE) {
600605
memset(&paramp, 0, sizeof(paramp));
601606
memcpy(paramp.key, &mpp->reservation_key, 8);
602607
rel_status = prout_do_scsi_ioctl(pp->dev, MPATH_PROUT_REL_SA,
603608
rq_scope, rq_type, &paramp, noisy);
604609
if (rel_status != MPATH_PR_SUCCESS)
605610
condlog(0, "%s: release on alternate path failed.",
606611
mpp->wwid);
612+
else if (work == PREE_WORK_REL_UNREG) {
613+
/* unregister the last path */
614+
rel_status = prout_do_scsi_ioctl(pp->dev,
615+
MPATH_PROUT_REG_IGN_SA,
616+
rq_scope, rq_type,
617+
&paramp, noisy);
618+
if (rel_status != MPATH_PR_SUCCESS)
619+
condlog(0, "%s: final self preempt unregister failed,",
620+
mpp->wwid);
621+
}
622+
}
623+
if (work != PREE_WORK_REL_UNREG) {
624+
memset(&paramp, 0, sizeof(paramp));
625+
memcpy(paramp.sa_key, &mpp->reservation_key, 8);
626+
status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
627+
rq_type, &paramp, noisy);
628+
if (status != MPATH_PR_SUCCESS)
629+
condlog(0, "%s: self preempt failed to reregister paths.",
630+
mpp->wwid);
607631
}
608-
609-
memset(&paramp, 0, sizeof(paramp));
610-
memcpy(paramp.sa_key, &mpp->reservation_key, 8);
611-
status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
612-
rq_type, &paramp, noisy);
613-
if (status != MPATH_PR_SUCCESS)
614-
condlog(0, "%s: self preempt failed to reregister paths.",
615-
mpp->wwid);
616632

617633
fail_resume:
618634
if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
@@ -625,18 +641,18 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
625641
}
626642

627643
static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
628-
unsigned int rq_type, int noisy, bool do_release)
644+
unsigned int rq_type, int noisy, enum preempt_work work)
629645
{
630646
return do_preempt_self(mpp, mpp->reservation_key, rq_servact, rq_scope,
631-
rq_type, noisy, do_release);
647+
rq_type, noisy, work);
632648
}
633649

634650
static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
635651
unsigned int rq_type, int noisy)
636652
{
637653
struct be64 zerokey = {0};
638654
return do_preempt_self(mpp, zerokey, rq_servact, rq_scope, rq_type,
639-
noisy, false);
655+
noisy, PREE_WORK_NONE);
640656
}
641657

642658
static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
@@ -661,18 +677,21 @@ static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
661677
return YNU_NO;
662678
}
663679

664-
static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
680+
static bool check_holding_reservation(struct multipath *mpp, uint8_t *curr_key,
681+
unsigned int *type)
665682
{
666-
if (get_be64(mpp->reservation_key) &&
683+
uint64_t zerokey = 0;
684+
if (memcmp(curr_key, &zerokey, 8) != 0 &&
667685
get_prhold(mpp->alias) == PR_SET &&
668-
reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) == YNU_YES)
686+
reservation_key_matches(mpp, curr_key, type) == YNU_YES)
669687
return true;
670688
return false;
671689
}
672690

673-
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
691+
static int mpath_prout_rel(struct multipath *mpp, int rq_servact, int rq_scope,
674692
unsigned int rq_type,
675-
struct prout_param_descriptor * paramp, int noisy)
693+
struct prout_param_descriptor *paramp, int noisy,
694+
bool unregister)
676695
{
677696
int i, j;
678697
struct pathgroup *pgp = NULL;
@@ -762,7 +781,8 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
762781
return status;
763782
}
764783

765-
if (!check_holding_reservation(mpp, &res_type)) {
784+
if (!check_holding_reservation(mpp, (uint8_t *)&mpp->reservation_key,
785+
&res_type)) {
766786
condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
767787
return MPATH_PR_SUCCESS;
768788
}
@@ -785,7 +805,13 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
785805
* 4. Reregistering keys on all the paths
786806
* 5. Resuming the device
787807
*/
788-
return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
808+
status = preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type,
809+
noisy,
810+
unregister ? PREE_WORK_REL_UNREG : PREE_WORK_REL);
811+
if (status == MPATH_PR_SUCCESS && unregister)
812+
return MPATH_PR_SUCCESS_UNREGISTER;
813+
return status;
814+
789815
}
790816

791817
/*
@@ -828,7 +854,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
828854
select_reservation_key(conf, mpp);
829855
put_multipath_config(conf);
830856

831-
memcpy(&oldkey, &mpp->reservation_key, 8);
857+
oldkey = mpp->reservation_key;
832858
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
833859
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
834860
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
@@ -905,7 +931,27 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
905931
{
906932
case MPATH_PROUT_REG_SA:
907933
case MPATH_PROUT_REG_IGN_SA:
908-
ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
934+
if (unregistering && check_holding_reservation(mpp, (uint8_t *)&oldkey, &rq_type)) {
935+
struct be64 newkey = mpp->reservation_key;
936+
/* temporarily restore reservation key */
937+
mpp->reservation_key = oldkey;
938+
ret = mpath_prout_rel(mpp, MPATH_PROUT_REL_SA, rq_scope,
939+
rq_type, paramp, noisy, true);
940+
mpp->reservation_key = newkey;
941+
if (ret == MPATH_PR_SUCCESS)
942+
/*
943+
* Since unregistering it true, paramp->sa_key
944+
* must be zero here. So this command will
945+
* unregister the key.
946+
*/
947+
ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
948+
rq_type, paramp, noisy);
949+
else if (ret == MPATH_PR_SUCCESS_UNREGISTER)
950+
/* We already unregistered the key */
951+
ret = MPATH_PR_SUCCESS;
952+
} else
953+
ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
954+
rq_type, paramp, noisy);
909955
break;
910956
case MPATH_PROUT_PREE_SA:
911957
case MPATH_PROUT_PREE_AB_SA:
@@ -921,7 +967,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
921967
/* if we are preempting ourself */
922968
if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
923969
ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
924-
noisy, false);
970+
noisy, PREE_WORK_NONE);
925971
break;
926972
}
927973
/* fallthrough */
@@ -932,14 +978,14 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
932978
paramp, noisy, NULL, &failed_paths);
933979
if (rq_servact == MPATH_PROUT_RES_SA &&
934980
ret != MPATH_PR_SUCCESS && failed_paths &&
935-
check_holding_reservation(mpp, &res_type) &&
981+
check_holding_reservation(mpp, paramp->key, &res_type) &&
936982
res_type == rq_type)
937983
/* The reserve failed, but multipathd says we hold it */
938984
ret = MPATH_PR_SUCCESS;
939985
break;
940986
}
941987
case MPATH_PROUT_REL_SA:
942-
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
988+
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy, false);
943989
break;
944990
default:
945991
return MPATH_PR_OTHER;

0 commit comments

Comments
 (0)