#include #include "defaults.h" #include #include #include #include "vector.h" #include "checkers.h" #include "structs.h" #include "structs_vec.h" #include #include "prio.h" #include #include "devmapper.h" #include "debug.h" #include "config.h" #include "switchgroup.h" #include "discovery.h" #include "configure.h" #include "dmparser.h" #include #include "propsel.h" #include "util.h" #include "unaligned.h" #include "mpath_persist.h" #include "mpathpr.h" #include "mpath_pr_ioctl.h" #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 extern struct udev *udev; struct config * mpath_lib_init (void) { struct config *conf; conf = load_config(DEFAULT_CONFIGFILE); if (!conf) { condlog(0, "Failed to initialize multipath config."); return NULL; } conf->force_sync = 1; set_max_fds(conf->max_fds); return conf; } int mpath_lib_exit (struct config *conf) { dm_lib_release(); dm_lib_exit(); cleanup_prio(); cleanup_checkers(); free_config(conf); conf = NULL; return 0; } static int updatepaths (struct multipath * mpp) { int i, j; struct pathgroup * pgp; struct path * pp; struct config *conf; if (!mpp->pg) return 0; vector_foreach_slot (mpp->pg, pgp, i){ if (!pgp->paths) continue; vector_foreach_slot (pgp->paths, pp, j){ if (!strlen(pp->dev)){ /* * path is not in sysfs anymore */ pp->state = PATH_DOWN; continue; } pp->mpp = mpp; if (pp->udev == NULL) { pp->udev = get_udev_device(pp->dev_t, DEV_DEVT); if (pp->udev == NULL) { pp->state = PATH_DOWN; continue; } conf = get_multipath_config(); pathinfo(pp, conf, DI_SYSFS|DI_CHECKER); put_multipath_config(conf); continue; } if (pp->state == PATH_UNCHECKED || pp->state == PATH_WILD) { conf = get_multipath_config(); pathinfo(pp, conf, DI_CHECKER); put_multipath_config(conf); } } } return 0; } int mpath_prin_activepath (struct multipath *mpp, int rq_servact, struct prin_resp * resp, int noisy) { int i,j, ret = MPATH_PR_DMMP_ERROR; struct pathgroup *pgp = NULL; struct path *pp = NULL; vector_foreach_slot (mpp->pg, pgp, j){ vector_foreach_slot (pgp->paths, pp, i){ if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){ condlog(2, "%s: %s not available. Skip.", mpp->wwid, pp->dev); condlog(3, "%s: status = %d.", mpp->wwid, pp->state); continue; } condlog(3, "%s: sending pr in command to %s ", mpp->wwid, pp->dev); ret = mpath_send_prin_activepath(pp->dev, rq_servact, resp, noisy); switch(ret) { case MPATH_PR_SUCCESS: case MPATH_PR_SENSE_INVALID_OP: return ret; default: continue; } } } return ret; } int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose) { int ret = mpath_persistent_reserve_init_vecs(verbose); if (ret != MPATH_PR_SUCCESS) return ret; ret = __mpath_persistent_reserve_in(fd, rq_servact, resp, noisy); mpath_persistent_reserve_free_vecs(); return ret; } int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose) { int ret = mpath_persistent_reserve_init_vecs(verbose); if (ret != MPATH_PR_SUCCESS) return ret; ret = __mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, paramp, noisy); mpath_persistent_reserve_free_vecs(); return ret; } static vector curmp; static vector pathvec; void mpath_persistent_reserve_free_vecs(void) { free_multipathvec(curmp, KEEP_PATHS); free_pathvec(pathvec, FREE_PATHS); curmp = pathvec = NULL; } int mpath_persistent_reserve_init_vecs(int verbose) { struct config *conf = get_multipath_config(); conf->verbosity = verbose; put_multipath_config(conf); if (curmp) return MPATH_PR_SUCCESS; /* * allocate core vectors to store paths and multipaths */ curmp = vector_alloc (); pathvec = vector_alloc (); if (!curmp || !pathvec){ condlog (0, "vector allocation failed."); goto err; } if (dm_get_maps(curmp)) goto err; return MPATH_PR_SUCCESS; err: mpath_persistent_reserve_free_vecs(); return MPATH_PR_DMMP_ERROR; } static int mpath_get_map(int fd, char **palias, struct multipath **pmpp) { int ret = MPATH_PR_DMMP_ERROR; struct stat info; int major, minor; char *alias; struct multipath *mpp; if (fstat(fd, &info) != 0){ condlog(0, "stat error fd=%d", fd); return MPATH_PR_FILE_ERROR; } if(!S_ISBLK(info.st_mode)){ condlog(3, "Failed to get major:minor. fd=%d", fd); return MPATH_PR_FILE_ERROR; } major = major(info.st_rdev); minor = minor(info.st_rdev); condlog(4, "Device %d:%d", major, minor); /* get alias from major:minor*/ alias = dm_mapname(major, minor); if (!alias){ condlog(0, "%d:%d failed to get device alias.", major, minor); return MPATH_PR_DMMP_ERROR; } condlog(3, "alias = %s", alias); if (dm_map_present(alias) && dm_is_mpath(alias) != 1){ condlog(3, "%s: not a multipath device.", alias); goto out; } /* get info of all paths from the dm device */ if (get_mpvec(curmp, pathvec, alias)){ condlog(0, "%s: failed to get device info.", alias); goto out; } mpp = find_mp_by_alias(curmp, alias); if (!mpp) { condlog(0, "%s: devmap not registered.", alias); goto out; } ret = MPATH_PR_SUCCESS; if (pmpp) *pmpp = mpp; if (palias) { *palias = alias; alias = NULL; } out: FREE(alias); return ret; } int __mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy) { struct multipath *mpp; int ret; ret = mpath_get_map(fd, NULL, &mpp); if (ret != MPATH_PR_SUCCESS) return ret; ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy); return ret; } int __mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy) { struct multipath *mpp; char *alias; int ret; uint64_t prkey; struct config *conf; ret = mpath_get_map(fd, &alias, &mpp); if (ret != MPATH_PR_SUCCESS) return ret; conf = get_multipath_config(); select_reservation_key(conf, mpp); select_all_tg_pt(conf, mpp); put_multipath_config(conf); memcpy(&prkey, paramp->sa_key, 8); if (mpp->prkey_source == PRKEY_SOURCE_FILE && prkey && ((!get_be64(mpp->reservation_key) && rq_servact == MPATH_PROUT_REG_SA) || rq_servact == MPATH_PROUT_REG_IGN_SA)) { memcpy(&mpp->reservation_key, paramp->sa_key, 8); if (update_prkey_flags(alias, get_be64(mpp->reservation_key), paramp->sa_flags)) { condlog(0, "%s: failed to set prkey for multipathd.", alias); ret = MPATH_PR_DMMP_ERROR; goto out1; } } if (memcmp(paramp->key, &mpp->reservation_key, 8) && memcmp(paramp->sa_key, &mpp->reservation_key, 8)) { condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key)); ret = MPATH_PR_SYNTAX_ERROR; goto out1; } switch(rq_servact) { case MPATH_PROUT_REG_SA: case MPATH_PROUT_REG_IGN_SA: ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy); break; case MPATH_PROUT_RES_SA : case MPATH_PROUT_PREE_SA : case MPATH_PROUT_PREE_AB_SA : case MPATH_PROUT_CLEAR_SA: ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy); break; case MPATH_PROUT_REL_SA: ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy); break; default: ret = MPATH_PR_OTHER; goto out1; } if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) || (rq_servact == MPATH_PROUT_REG_IGN_SA))) { if (prkey == 0) { update_prflag(alias, 0); update_prkey(alias, 0); } else update_prflag(alias, 1); } else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) { update_prflag(alias, 0); update_prkey(alias, 0); } out1: FREE(alias); return ret; } int get_mpvec (vector curmp, vector pathvec, char * refwwid) { int i; struct multipath *mpp; char params[PARAMS_SIZE], status[PARAMS_SIZE]; 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; dm_get_map(mpp->alias, &mpp->size, params); condlog(3, "params = %s", params); dm_get_status(mpp->alias, status); condlog(3, "status = %s", status); disassemble_map (pathvec, params, mpp, 0); /* * disassemble_map() can add new paths to pathvec. * If not in "fast list mode", we need to fetch information * about them */ updatepaths(mpp); disassemble_status (status, mpp); } return MPATH_PR_SUCCESS ; } int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy) { int rc; rc = prin_do_scsi_ioctl(dev, rq_servact, resp, noisy); return (rc); } int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy) { int i, j, k; struct pathgroup *pgp = NULL; struct path *pp = NULL; int rollback = 0; 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; all_tg_pt = (mpp->all_tg_pt == ALL_TG_PT_ON || paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK); active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST); if (active_pathcount == 0) { condlog (0, "%s: no path available", mpp->wwid); return MPATH_PR_DMMP_ERROR; } struct threadinfo thread[active_pathcount]; int hosts[active_pathcount]; memset(thread, 0, sizeof(thread)); /* init thread parameter */ for (i =0; i< active_pathcount; i++){ hosts[i] = -1; thread[i].param.rq_servact = rq_servact; thread[i].param.rq_scope = rq_scope; thread[i].param.rq_type = rq_type; thread[i].param.paramp = paramp; thread[i].param.noisy = noisy; thread[i].param.status = MPATH_PR_SKIP; condlog (3, "THREAD ID [%d] INFO]", i); condlog (3, "rq_servact=%d ", thread[i].param.rq_servact); condlog (3, "rq_scope=%d ", thread[i].param.rq_scope); condlog (3, "rq_type=%d ", thread[i].param.rq_type); condlog (3, "rkey="); condlog (3, "paramp->sa_flags =%02x ", thread[i].param.paramp->sa_flags); condlog (3, "noisy=%d ", thread[i].param.noisy); condlog (3, "status=%d ", thread[i].param.status); } pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); vector_foreach_slot (mpp->pg, pgp, j){ vector_foreach_slot (pgp->paths, pp, i){ if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){ condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev); continue; } if (all_tg_pt && pp->sg_id.host_no != -1) { for (k = 0; k < count; k++) { if (pp->sg_id.host_no == hosts[k]) { condlog(3, "%s: %s host %d matches skip.", pp->wwid, pp->dev, pp->sg_id.host_no); break; } } if (k < count) continue; } strlcpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE); if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){ /* * Clearing SPEC_I_PT as transportids are already registered by now. */ thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK); } condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev); rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param)); if (rc){ condlog (0, "%s: failed to create thread %d", mpp->wwid, rc); thread[count].param.status = MPATH_PR_THREAD_ERROR; } else hosts[count] = pp->sg_id.host_no; count = count + 1; } } for( i=0; i < count ; i++){ if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { rc = pthread_join(thread[i].id, NULL); if (rc){ 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(¶mp->sa_key[0]); status = MPATH_PR_RESERV_CONFLICT ; } if (!rollback && (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(¶mp->key, ¶mp->sa_key, 8); memset(¶mp->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 thread[i].param.status = MPATH_PR_SKIP; } 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); } } } } pthread_attr_destroy(&attr); return (status); } void * mpath_prout_pthread_fn(void *p) { int ret; struct prout_param * param = (struct prout_param *)p; ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope, param->rq_type, param->paramp, param->noisy); param->status = ret; pthread_exit(NULL); } int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy) { int i,j, ret; struct pathgroup *pgp = NULL; struct path *pp = NULL; vector_foreach_slot (mpp->pg, pgp, j){ vector_foreach_slot (pgp->paths, pp, i){ if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){ condlog (1, "%s: %s path not up. Skip", mpp->wwid, pp->dev); continue; } condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev); ret = send_prout_activepath(pp->dev, rq_servact, rq_scope, rq_type, paramp, noisy); return ret ; } } return MPATH_PR_SUCCESS; } int send_prout_activepath(char * dev, int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy) { struct prout_param param; param.rq_servact = rq_servact; param.rq_scope = rq_scope; param.rq_type = rq_type; param.paramp = paramp; param.noisy = noisy; param.status = -1; pthread_t thread; pthread_attr_t attr; int rc; memset(&thread, 0, sizeof(thread)); strlcpy(param.dev, dev, FILE_NAME_SIZE); /* Initialize and set thread joinable attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(¶m)); if (rc){ condlog (3, "%s: failed to create thread %d", dev, rc); return MPATH_PR_THREAD_ERROR; } /* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr); rc = pthread_join(thread, NULL); return (param.status); } int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope, unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy) { int i, j; int num = 0; struct pathgroup *pgp = NULL; struct path *pp = NULL; int active_pathcount = 0; pthread_attr_t attr; int rc, found = 0; int count = 0; int status = MPATH_PR_SUCCESS; struct prin_resp resp; struct prout_param_descriptor *pamp; struct prin_resp *pr_buff; int length; struct transportid *pptr; if (!mpp) return MPATH_PR_DMMP_ERROR; active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST); struct threadinfo thread[active_pathcount]; memset(thread, 0, sizeof(thread)); for (i = 0; i < active_pathcount; i++){ thread[i].param.rq_servact = rq_servact; thread[i].param.rq_scope = rq_scope; thread[i].param.rq_type = rq_type; thread[i].param.paramp = paramp; thread[i].param.noisy = noisy; thread[i].param.status = MPATH_PR_SKIP; condlog (3, " path count = %d", i); condlog (3, "rq_servact=%d ", thread[i].param.rq_servact); condlog (3, "rq_scope=%d ", thread[i].param.rq_scope); condlog (3, "rq_type=%d ", thread[i].param.rq_type); condlog (3, "noisy=%d ", thread[i].param.noisy); condlog (3, "status=%d ", thread[i].param.status); } pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); vector_foreach_slot (mpp->pg, pgp, j){ vector_foreach_slot (pgp->paths, pp, i){ if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){ condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev); continue; } strlcpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE); condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev); rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn, (void *) (&thread[count].param)); if (rc) { condlog (0, "%s: failed to create thread. %d", mpp->wwid, rc); thread[count].param.status = MPATH_PR_THREAD_ERROR; } count = count + 1; } } pthread_attr_destroy (&attr); for (i = 0; i < count; i++){ if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { rc = pthread_join (thread[i].id, NULL); if (rc){ condlog (1, "%s: failed to join thread. %d", mpp->wwid, rc); } } } for (i = 0; i < count; i++){ /* check thread status here and return the status */ if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT) status = MPATH_PR_RESERV_CONFLICT; else if (status == MPATH_PR_SUCCESS && thread[i].param.status != MPATH_PR_RESERV_CONFLICT) status = thread[i].param.status; } status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy); if (status != MPATH_PR_SUCCESS){ condlog (0, "%s: pr in read reservation command failed.", mpp->wwid); return MPATH_PR_OTHER; } num = resp.prin_descriptor.prin_readresv.additional_length / 8; if (num == 0){ condlog (2, "%s: Path holding reservation is released.", mpp->wwid); return MPATH_PR_SUCCESS; } condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid); pr_buff = mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA); if (!pr_buff){ condlog (0, "%s: failed to alloc pr in response buffer.", mpp->wwid); return MPATH_PR_OTHER; } status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy); if (status != MPATH_PR_SUCCESS){ condlog (0, "%s: pr in read full status command failed.", mpp->wwid); goto out; } num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor; if (0 == num){ goto out; } length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *)); pamp = (struct prout_param_descriptor *)malloc (length); if (!pamp){ condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid); goto out1; } memset(pamp, 0, length); pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid)); if (!pamp->trnptid_list[0]){ condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid); goto out1; } if (get_be64(mpp->reservation_key)){ memcpy (pamp->key, &mpp->reservation_key, 8); condlog (3, "%s: reservation key set.", mpp->wwid); } status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA, rq_scope, rq_type, pamp, noisy); if (status) { condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid); goto out1; } pamp->num_transportid = 1; pptr=pamp->trnptid_list[0]; for (i = 0; i < num; i++){ if (get_be64(mpp->reservation_key) && memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, &mpp->reservation_key, 8)){ /*register with tarnsport id*/ memset(pamp, 0, length); pamp->trnptid_list[0] = pptr; memset (pamp->trnptid_list[0], 0, sizeof (struct transportid)); memcpy (pamp->sa_key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8); pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK; pamp->num_transportid = 1; memcpy (pamp->trnptid_list[0], &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid, sizeof (struct transportid)); status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type, pamp, noisy); pamp->sa_flags = 0; memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8); memset (pamp->sa_key, 0, 8); pamp->num_transportid = 0; status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type, pamp, noisy); } else { if (get_be64(mpp->reservation_key)) found = 1; } } if (found){ memset (pamp, 0, length); memcpy (pamp->sa_key, &mpp->reservation_key, 8); memset (pamp->key, 0, 8); status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy); } free(pptr); out1: free (pamp); out: free (pr_buff); return (status); } void * mpath_alloc_prin_response(int prin_sa) { void * ptr = NULL; int size=0; switch (prin_sa) { case MPATH_PRIN_RKEY_SA: size = sizeof(struct prin_readdescr); break; case MPATH_PRIN_RRES_SA: size = sizeof(struct prin_resvdescr); break; case MPATH_PRIN_RCAP_SA: size=sizeof(struct prin_capdescr); break; case MPATH_PRIN_RFSTAT_SA: size = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS; break; } if (size > 0) { ptr = calloc(size, 1); } return ptr; } int update_map_pr(struct multipath *mpp) { int noisy=0; struct prin_resp *resp; unsigned int i; int ret, isFound; if (!get_be64(mpp->reservation_key)) { /* Nothing to do. Assuming pr mgmt feature is disabled*/ condlog(4, "%s: reservation_key not set in multipath.conf", mpp->alias); return MPATH_PR_SUCCESS; } resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA); if (!resp) { condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias); return MPATH_PR_OTHER; } ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy); if (ret != MPATH_PR_SUCCESS ) { condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret); free(resp); return ret; } if (resp->prin_descriptor.prin_readkeys.additional_length == 0 ) { condlog(3,"%s: No key found. Device may not be registered. ", mpp->alias); free(resp); return MPATH_PR_SUCCESS; } condlog(2, "%s: Multipath reservation_key: 0x%" PRIx64 " ", mpp->alias, get_be64(mpp->reservation_key)); isFound =0; for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ ) { condlog(2, "%s: PR IN READKEYS[%d] reservation key:", mpp->alias, i); dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1); if (!memcmp(&mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8)) { condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias); isFound =1; } } if (isFound) { mpp->prflag = 1; condlog(2, "%s: prflag flag set.", mpp->alias ); } free(resp); return MPATH_PR_SUCCESS; }