There is a race condition when changing reservation keys where a failed path could come back online after libmpathpersist checks the paths, but before it updates the reservation key. In this case, the path would come up and get reregistered with the old key by multipathd, and libmpathpersist would not update its key, because the path was down when it checked.
To fix this, check the paths after updating the key, so any path that comes up after getting checked will use the updated key. Signed-off-by: Benjamin Marzinski <[email protected]> --- libmpathpersist/mpath_persist_int.c | 80 ++++++++++++----------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c index c575e3b5..3419fde3 100644 --- a/libmpathpersist/mpath_persist_int.c +++ b/libmpathpersist/mpath_persist_int.c @@ -110,39 +110,18 @@ void *mpath_alloc_prin_response(int prin_sa) return ptr; } -static int get_mpvec(vector curmp, vector pathvec, char *refwwid) +static int get_path_info(struct multipath *mpp, vector pathvec) { - int i; - struct multipath *mpp; - - vector_foreach_slot (curmp, mpp, i){ - /* - * discard out of scope maps - */ - if (!mpp->alias) { - condlog(0, "%s: map with empty alias!", __func__); - continue; - } - - if (mpp->pg != NULL) - /* Already seen this one */ - continue; - - if (refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE - 1)) - continue; - - if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK || - update_mpp_paths(mpp, pathvec)) { - condlog(1, "error parsing map %s", mpp->wwid); - remove_map(mpp, pathvec, curmp); - i--; - } else - extract_hwe_from_path(mpp); + if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK || + update_mpp_paths(mpp, pathvec)) { + condlog(0, "error parsing map %s", mpp->wwid); + return MPATH_PR_DMMP_ERROR; } + extract_hwe_from_path(mpp); return MPATH_PR_SUCCESS ; } -static int mpath_get_map(vector curmp, vector pathvec, int fd, struct multipath **pmpp) +static int mpath_get_map(vector curmp, int fd, struct multipath **pmpp) { int rc; struct stat info; @@ -174,12 +153,6 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, struct multipath condlog(4, "alias = %s", alias); - /* get info of all paths from the dm device */ - if (get_mpvec(curmp, pathvec, alias)) { - condlog(0, "%s: failed to get device info.", alias); - return MPATH_PR_DMMP_ERROR; - } - mpp = find_mp_by_alias(curmp, alias); if (!mpp) { @@ -200,7 +173,11 @@ int do_mpath_persistent_reserve_in(vector curmp, vector pathvec, struct multipath *mpp; int ret; - ret = mpath_get_map(curmp, pathvec, fd, &mpp); + ret = mpath_get_map(curmp, fd, &mpp); + if (ret != MPATH_PR_SUCCESS) + return ret; + + ret = get_path_info(mpp, pathvec); if (ret != MPATH_PR_SUCCESS) return ret; @@ -736,25 +713,15 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, bool unregistering, preempting_reservation = false; bool updated_prkey = false; - ret = mpath_get_map(curmp, pathvec, fd, &mpp); + ret = mpath_get_map(curmp, fd, &mpp); if (ret != MPATH_PR_SUCCESS) return ret; conf = get_multipath_config(); mpp->mpe = find_mpe(conf->mptable, mpp->wwid); select_reservation_key(conf, mpp); - select_all_tg_pt(conf, mpp); - /* - * If a device preempts itself, it will need to suspend and resume. - * Set mpp->skip_kpartx to make sure we set the flags to skip kpartx - * if necessary, when doing this. - */ - select_skip_kpartx(conf, mpp); put_multipath_config(conf); - if (rq_servact == MPATH_PROUT_REG_IGN_SA) - set_ignored_key(mpp, paramp->key); - unregistering = (memcmp(&zerokey, paramp->sa_key, 8) == 0); if (mpp->prkey_source == PRKEY_SOURCE_FILE && (rq_servact == MPATH_PROUT_REG_IGN_SA || @@ -807,6 +774,27 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, } } + ret = get_path_info(mpp, pathvec); + if (ret != MPATH_PR_SUCCESS) { + if (updated_prkey) + update_prkey_flags(mpp->alias, get_be64(oldkey), + mpp->sa_flags); + return ret; + } + + conf = get_multipath_config(); + select_all_tg_pt(conf, mpp); + /* + * If a device preempts itself, it will need to suspend and resume. + * Set mpp->skip_kpartx to make sure we set the flags to skip kpartx + * if necessary, when doing this. + */ + select_skip_kpartx(conf, mpp); + put_multipath_config(conf); + + if (rq_servact == MPATH_PROUT_REG_IGN_SA) + set_ignored_key(mpp, paramp->key); + switch(rq_servact) { case MPATH_PROUT_REG_SA: -- 2.50.1
