When you use REGISTER to change the reservation key of a registered multipath device, where the path holding the reservation is down, libmpathpersist will PREEMPT the failed path to move the reservation to a usable path, so the reservation key will be updated. However, when you use REGISTER AND IGNORE, you don't pass in the old key, so libmpathpersist can't use it to check against the key holding the reservation, which is necessary to know if it needs to PREEMPT.
Since the SCSI spec says that devices must ignore any passed-in key on REGISTER AND IGNORE, libmpathpersist can still use it to pass in the old key value. But unlike with REGISTER, the command won't fail if device isn't actually registered with the old key, so libmpathpersist needs to check that itself. To do this, it calls update_map_pr() just like multipathd does to check that the device is registered before registering new paths. However, libmpathpersist doesn't track the persistent reservation state like multipathd, so it needs to ask multipathd if it thinks the device is registered, using the "get prstatus map <map>" command. Signed-off-by: Benjamin Marzinski <bmarz...@redhat.com> --- libmpathpersist/mpath_persist_int.c | 20 ++++++++++ libmpathpersist/mpath_updatepr.c | 59 +++++++++++++++++++++-------- libmpathpersist/mpathpr.h | 1 + 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c index ca972c2b..ee9706c6 100644 --- a/libmpathpersist/mpath_persist_int.c +++ b/libmpathpersist/mpath_persist_int.c @@ -640,6 +640,23 @@ fail_resume: return (status == MPATH_PR_RETRYABLE_ERROR) ? MPATH_PR_OTHER : status; } +/* + * for MPATH_PROUT_REG_IGN_SA, we use the ignored paramp->key to store the + * currently registered key. + */ +static void set_ignored_key(struct multipath *mpp, uint8_t *key) +{ + memset(key, 0, 8); + if (!get_be64(mpp->reservation_key)) + return; + if (get_prflag(mpp->alias) == PRFLAG_UNSET) + return; + update_map_pr(mpp, NULL); + if (mpp->prflag != PRFLAG_SET) + return; + memcpy(key, &mpp->reservation_key, 8); +} + int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy) @@ -660,6 +677,9 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, select_skip_kpartx(conf, mpp); put_multipath_config(conf); + if (rq_servact == MPATH_PROUT_REG_IGN_SA) + set_ignored_key(mpp, paramp->key); + memcpy(&prkey, paramp->sa_key, 8); if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey && (rq_servact == MPATH_PROUT_REG_IGN_SA || diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c index 36bd777e..7cf82f50 100644 --- a/libmpathpersist/mpath_updatepr.c +++ b/libmpathpersist/mpath_updatepr.c @@ -19,14 +19,12 @@ #include "config.h" #include "uxsock.h" #include "mpathpr.h" +#include "structs.h" - -static int do_update_pr(char *alias, char *cmd, char *key) +static char *do_pr(char *alias, char *str) { int fd; - char str[256]; char *reply; - int ret = 0; int timeout; struct config *conf; @@ -37,24 +35,35 @@ static int do_update_pr(char *alias, char *cmd, char *key) fd = mpath_connect(); if (fd == -1) { condlog (0, "ux socket connect error"); - return -1; + return NULL; } - if (key) - snprintf(str,sizeof(str),"%s map %s key %s", cmd, alias, key); - else - snprintf(str,sizeof(str),"%s map %s", cmd, alias); condlog (2, "%s: pr message=%s", alias, str); if (send_packet(fd, str) != 0) { condlog(2, "%s: message=%s send error=%d", alias, str, errno); mpath_disconnect(fd); - return -1; + return NULL; } - ret = recv_packet(fd, &reply, timeout); - if (ret < 0) { + if (recv_packet(fd, &reply, timeout) < 0) condlog(2, "%s: message=%s recv error=%d", alias, str, errno); - ret = -1; - } else { + + mpath_disconnect(fd); + return reply; +} + +static int do_update_pr(char *alias, char *cmd, char *key) +{ + char str[256]; + char *reply = NULL; + int ret = -1; + + if (key) + snprintf(str, sizeof(str), "%s map %s key %s", cmd, alias, key); + else + snprintf(str, sizeof(str), "%s map %s", cmd, alias); + + reply = do_pr(alias, str); + if (reply) { condlog (2, "%s: message=%s reply=%s", alias, str, reply); if (reply && strncmp(reply,"ok", 2) == 0) ret = 0; @@ -63,10 +72,30 @@ static int do_update_pr(char *alias, char *cmd, char *key) } free(reply); - mpath_disconnect(fd); return ret; } +int get_prflag(char *mapname) +{ + char str[256]; + char *reply; + int prflag; + + snprintf(str, sizeof(str), "getprstatus map %s", mapname); + reply = do_pr(mapname, str); + if (!reply) + prflag = PRFLAG_UNKNOWN; + else if (strncmp(reply, "unset", 5) == 0) + prflag = PRFLAG_UNSET; + else if (strncmp(reply, "set", 3) == 0) + prflag = PRFLAG_SET; + else + prflag = PRFLAG_UNKNOWN; + + free(reply); + return prflag; +} + int update_prflag(char *mapname, int set) { return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus", NULL); diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h index cc1a5673..912957e5 100644 --- a/libmpathpersist/mpathpr.h +++ b/libmpathpersist/mpathpr.h @@ -8,6 +8,7 @@ int update_prflag(char *mapname, int set); int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags); +int get_prflag(char *mapname); #define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0) #endif -- 2.48.1