Skip to content

Commit 137041f

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> Reviewed-by: Martin Wilck <mwilck@suse.com>
1 parent e150ef5 commit 137041f

2 files changed

Lines changed: 82 additions & 34 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: 79 additions & 34 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,33 @@ 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, MPATH_PROUT_REG_IGN_SA,
615+
rq_scope, rq_type,
616+
&paramp, noisy);
617+
if (rel_status != MPATH_PR_SUCCESS)
618+
condlog(0, "%s: final self preempt unregister failed,",
619+
mpp->wwid);
620+
}
621+
}
622+
if (work != PREE_WORK_REL_UNREG) {
623+
memset(&paramp, 0, sizeof(paramp));
624+
memcpy(paramp.sa_key, &mpp->reservation_key, 8);
625+
status = mpath_prout_reg(mpp, MPATH_PROUT_REG_IGN_SA, rq_scope,
626+
rq_type, &paramp, noisy);
627+
if (status != MPATH_PR_SUCCESS)
628+
condlog(0, "%s: self preempt failed to reregister paths.",
629+
mpp->wwid);
607630
}
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);
616631

617632
fail_resume:
618633
if (!dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, udev_flags)) {
@@ -625,18 +640,18 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
625640
}
626641

627642
static int preempt_self(struct multipath *mpp, int rq_servact, int rq_scope,
628-
unsigned int rq_type, int noisy, bool do_release)
643+
unsigned int rq_type, int noisy, enum preempt_work work)
629644
{
630645
return do_preempt_self(mpp, mpp->reservation_key, rq_servact, rq_scope,
631-
rq_type, noisy, do_release);
646+
rq_type, noisy, work);
632647
}
633648

634649
static int preempt_all(struct multipath *mpp, int rq_servact, int rq_scope,
635650
unsigned int rq_type, int noisy)
636651
{
637652
struct be64 zerokey = {0};
638653
return do_preempt_self(mpp, zerokey, rq_servact, rq_scope, rq_type,
639-
noisy, false);
654+
noisy, PREE_WORK_NONE);
640655
}
641656

642657
static int
@@ -661,18 +676,20 @@ reservation_key_matches(struct multipath *mpp, uint8_t *key, unsigned int *type)
661676
return YNU_NO;
662677
}
663678

664-
static bool check_holding_reservation(struct multipath *mpp, unsigned int *type)
679+
static bool check_holding_reservation(struct multipath *mpp, uint8_t *curr_key,
680+
unsigned int *type)
665681
{
666-
if (get_be64(mpp->reservation_key) && get_prhold(mpp->alias) == PR_SET &&
667-
reservation_key_matches(mpp, (uint8_t *)&mpp->reservation_key, type) ==
668-
YNU_YES)
682+
uint64_t zerokey = 0;
683+
if (memcmp(curr_key, &zerokey, 8) != 0 && get_prhold(mpp->alias) == PR_SET &&
684+
reservation_key_matches(mpp, curr_key, type) == YNU_YES)
669685
return true;
670686
return false;
671687
}
672688

673-
static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
674-
unsigned int rq_type,
675-
struct prout_param_descriptor * paramp, int noisy)
689+
static int
690+
mpath_prout_rel(struct multipath *mpp, int rq_servact, int rq_scope,
691+
unsigned int rq_type, struct prout_param_descriptor *paramp,
692+
int noisy, bool unregister)
676693
{
677694
int i, j;
678695
struct pathgroup *pgp = NULL;
@@ -762,7 +779,8 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
762779
return status;
763780
}
764781

765-
if (!check_holding_reservation(mpp, &res_type)) {
782+
if (!check_holding_reservation(mpp, (uint8_t *)&mpp->reservation_key,
783+
&res_type)) {
766784
condlog(2, "%s: Releasing key not holding reservation.", mpp->wwid);
767785
return MPATH_PR_SUCCESS;
768786
}
@@ -785,7 +803,11 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
785803
* 4. Reregistering keys on all the paths
786804
* 5. Resuming the device
787805
*/
788-
return preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy, true);
806+
status = preempt_self(mpp, MPATH_PROUT_PREE_SA, rq_scope, rq_type, noisy,
807+
unregister ? PREE_WORK_REL_UNREG : PREE_WORK_REL);
808+
if (status == MPATH_PR_SUCCESS && unregister)
809+
return MPATH_PR_SUCCESS_UNREGISTER;
810+
return status;
789811
}
790812

791813
/*
@@ -827,7 +849,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
827849
select_reservation_key(conf, mpp);
828850
put_multipath_config(conf);
829851

830-
memcpy(&oldkey, &mpp->reservation_key, 8);
852+
oldkey = mpp->reservation_key;
831853
unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0);
832854
if (mpp->prkey_source == PRKEY_SOURCE_FILE &&
833855
(rq_servact == MPATH_PROUT_REG_IGN_SA ||
@@ -904,7 +926,28 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
904926
{
905927
case MPATH_PROUT_REG_SA:
906928
case MPATH_PROUT_REG_IGN_SA:
907-
ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
929+
if (unregistering &&
930+
check_holding_reservation(mpp, (uint8_t *)&oldkey, &rq_type)) {
931+
struct be64 newkey = mpp->reservation_key;
932+
/* temporarily restore reservation key */
933+
mpp->reservation_key = oldkey;
934+
ret = mpath_prout_rel(mpp, MPATH_PROUT_REL_SA, rq_scope,
935+
rq_type, paramp, noisy, true);
936+
mpp->reservation_key = newkey;
937+
if (ret == MPATH_PR_SUCCESS)
938+
/*
939+
* Since unregistering it true, paramp->sa_key
940+
* must be zero here. So this command will
941+
* unregister the key.
942+
*/
943+
ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
944+
rq_type, paramp, noisy);
945+
else if (ret == MPATH_PR_SUCCESS_UNREGISTER)
946+
/* We already unregistered the key */
947+
ret = MPATH_PR_SUCCESS;
948+
} else
949+
ret = mpath_prout_reg(mpp, rq_servact, rq_scope,
950+
rq_type, paramp, noisy);
908951
break;
909952
case MPATH_PROUT_PREE_SA:
910953
case MPATH_PROUT_PREE_AB_SA:
@@ -920,7 +963,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
920963
/* if we are preempting ourself */
921964
if (memcmp(paramp->sa_key, paramp->key, 8) == 0) {
922965
ret = preempt_self(mpp, rq_servact, rq_scope, rq_type,
923-
noisy, false);
966+
noisy, PREE_WORK_NONE);
924967
break;
925968
}
926969
/* fallthrough */
@@ -929,15 +972,17 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
929972
unsigned int res_type;
930973
ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type,
931974
paramp, noisy, NULL, &failed_paths);
932-
if (rq_servact == MPATH_PROUT_RES_SA && ret != MPATH_PR_SUCCESS &&
933-
failed_paths && check_holding_reservation(mpp, &res_type) &&
975+
if (rq_servact == MPATH_PROUT_RES_SA &&
976+
ret != MPATH_PR_SUCCESS && failed_paths &&
977+
check_holding_reservation(mpp, paramp->key, &res_type) &&
934978
res_type == rq_type)
935979
/* The reserve failed, but multipathd says we hold it */
936980
ret = MPATH_PR_SUCCESS;
937981
break;
938982
}
939983
case MPATH_PROUT_REL_SA:
940-
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
984+
ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type,
985+
paramp, noisy, false);
941986
break;
942987
default:
943988
return MPATH_PR_OTHER;

0 commit comments

Comments
 (0)