libmultipath: fixup string copy and comparison
[multipath-tools/.git] / libmpathpersist / mpath_persist.c
1 #include <libdevmapper.h>
2 #include <defaults.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include <vector.h>
7 #include <checkers.h>
8 #include <structs.h>
9 #include <structs_vec.h>
10 #include <libudev.h>
11
12 #include <prio.h>
13 #include <unistd.h>
14 #include <devmapper.h>
15 #include <debug.h>
16 #include <config.h>
17 #include <switchgroup.h>
18 #include <discovery.h>
19 #include <dmparser.h>
20 #include <ctype.h>
21 #include <propsel.h>
22 #include <util.h>
23
24 #include "mpath_persist.h"
25 #include "mpathpr.h"
26 #include "mpath_pr_ioctl.h"
27
28 #include <pthread.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/resource.h>
34
35 #define __STDC_FORMAT_MACROS 1
36
37
38 int
39 mpath_lib_init (struct udev *udev)
40 {
41         if (load_config(DEFAULT_CONFIGFILE, udev)){
42                 condlog(0, "Failed to initialize multipath config.");
43                 return 1;
44         }
45
46         if (conf->max_fds) {
47                 struct rlimit fd_limit;
48
49                 fd_limit.rlim_cur = conf->max_fds;
50                 fd_limit.rlim_max = conf->max_fds;
51                 if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
52                         condlog(0, "can't set open fds limit to %d : %s",
53                                    conf->max_fds, strerror(errno));
54         }
55
56         return 0;
57 }
58
59 int
60 mpath_lib_exit (void)
61 {
62         dm_lib_release();
63         dm_lib_exit();
64         cleanup_prio();
65         cleanup_checkers();
66         free_config(conf);
67         conf = NULL;
68         return 0;
69 }
70
71 static int
72 updatepaths (struct multipath * mpp)
73 {
74         int i, j;
75         struct pathgroup * pgp;
76         struct path * pp;
77
78         if (!mpp->pg)
79                 return 0;
80
81         vector_foreach_slot (mpp->pg, pgp, i){
82                 if (!pgp->paths)
83                         continue;
84
85                 vector_foreach_slot (pgp->paths, pp, j){
86                         if (!strlen(pp->dev)){
87                                 if (devt2devname(pp->dev, PATH_SIZE,
88                                                  pp->dev_t)){
89                                         /*
90                                          * path is not in sysfs anymore
91                                          */
92                                         pp->state = PATH_DOWN;
93                                         continue;
94                                 }
95                                 pp->mpp = mpp;
96                                 pathinfo(pp, conf->hwtable, DI_ALL);
97                                 continue;
98                         }
99                         pp->mpp = mpp;
100                         if (pp->state == PATH_UNCHECKED ||
101                                         pp->state == PATH_WILD)
102                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
103
104                         if (pp->priority == PRIO_UNDEF)
105                                 pathinfo(pp, conf->hwtable, DI_PRIO);
106                 }
107         }
108         return 0;
109 }
110
111 int
112 mpath_prin_activepath (struct multipath *mpp, int rq_servact,
113         struct prin_resp * resp, int noisy)
114 {
115         int i,j, ret = MPATH_PR_DMMP_ERROR;
116         struct pathgroup *pgp = NULL;
117         struct path *pp = NULL;
118
119         vector_foreach_slot (mpp->pg, pgp, j){
120                 vector_foreach_slot (pgp->paths, pp, i){
121                         if (!((pp->state == PATH_UP) ||
122                               (pp->state == PATH_GHOST))){
123                                 condlog(2, "%s: %s not available. Skip.",
124                                         mpp->wwid, pp->dev);
125                                 condlog(3, "%s: status = %d.",
126                                         mpp->wwid, pp->state);
127                                 continue;
128                         }
129
130                         condlog(3, "%s: sending pr in command to %s ",
131                                 mpp->wwid, pp->dev);
132                         ret = mpath_send_prin_activepath(pp->dev, rq_servact,
133                                                          resp, noisy);
134                         switch(ret)
135                         {
136                                 case MPATH_PR_SUCCESS:
137                                 case MPATH_PR_SENSE_INVALID_OP:
138                                         return ret;
139                                 default:
140                                         continue;
141                         }
142                 }
143         }
144         return ret;
145 }
146
147 int mpath_persistent_reserve_in (int fd, int rq_servact,
148         struct prin_resp *resp, int noisy, int verbose)
149 {
150         struct stat info;
151         vector curmp = NULL;
152         vector pathvec = NULL;
153         char * alias;
154         struct multipath * mpp;
155         int map_present;
156         int major, minor;
157         int ret;
158
159         conf->verbosity = verbose;
160
161         if (fstat( fd, &info) != 0){
162                 condlog(0, "stat error %d", fd);
163                 return MPATH_PR_FILE_ERROR;
164         }
165         if(!S_ISBLK(info.st_mode)){
166                 condlog(0, "Failed to get major:minor. fd = %d", fd);
167                 return MPATH_PR_FILE_ERROR;
168         }
169
170         major = major(info.st_rdev);
171         minor = minor(info.st_rdev);
172         condlog(4, "Device %d:%d:  ", major, minor);
173
174         /* get alias from major:minor*/
175         alias = dm_mapname(major, minor);
176         if (!alias){
177                 condlog(0, "%d:%d failed to get device alias.", major, minor);
178                 return MPATH_PR_DMMP_ERROR;
179         }
180
181         condlog(3, "alias = %s", alias);
182         map_present = dm_map_present(alias);
183         if (map_present && !dm_is_mpath(alias)){
184                 condlog( 0, "%s: not a multipath device.", alias);
185                 ret = MPATH_PR_DMMP_ERROR;
186                 goto out;
187         }
188
189         /*
190          * allocate core vectors to store paths and multipaths
191          */
192         curmp = vector_alloc ();
193         pathvec = vector_alloc ();
194
195         if (!curmp || !pathvec){
196                 condlog (0, "%s: vector allocation failed.", alias);
197                 ret = MPATH_PR_DMMP_ERROR;
198                 goto out;
199         }
200
201         if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) {
202                 ret = MPATH_PR_DMMP_ERROR;
203                 goto out1;
204         }
205
206         /* get info of all paths from the dm device     */
207         if (get_mpvec (curmp, pathvec, alias)){
208                 condlog(0, "%s: failed to get device info.", alias);
209                 ret = MPATH_PR_DMMP_ERROR;
210                 goto out1;
211         }
212
213         mpp = find_mp_by_alias(curmp, alias);
214         if (!mpp){
215                 condlog(0, "%s: devmap not registered.", alias);
216                 ret = MPATH_PR_DMMP_ERROR;
217                 goto out1;
218         }
219
220         ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy);
221
222 out1:
223         free_multipathvec(curmp, KEEP_PATHS);
224         free_pathvec(pathvec, FREE_PATHS);
225 out:
226         FREE(alias);
227         return ret;
228 }
229
230 int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
231         unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
232 {
233
234         struct stat info;
235
236         vector curmp = NULL;
237         vector pathvec = NULL;
238
239         char * alias;
240         struct multipath * mpp;
241         int map_present;
242         int major, minor;
243         int ret;
244         int j;
245         unsigned char *keyp;
246         uint64_t prkey;
247
248         conf->verbosity = verbose;
249
250         if (fstat( fd, &info) != 0){
251                 condlog(0, "stat error fd=%d", fd);
252                 return MPATH_PR_FILE_ERROR;
253         }
254
255         if(!S_ISBLK(info.st_mode)){
256                 condlog(3, "Failed to get major:minor. fd=%d", fd);
257                 return MPATH_PR_FILE_ERROR;
258         }
259
260         major = major(info.st_rdev);
261         minor = minor(info.st_rdev);
262         condlog(4, "Device  %d:%d", major, minor);
263
264         /* get WWN of the device from major:minor*/
265         alias = dm_mapname(major, minor);
266         if (!alias){
267                 return MPATH_PR_DMMP_ERROR;
268         }
269
270         condlog(3, "alias = %s", alias);
271         map_present = dm_map_present(alias);
272
273         if (map_present && !dm_is_mpath(alias)){
274                 condlog(3, "%s: not a multipath device.", alias);
275                 ret = MPATH_PR_DMMP_ERROR;
276                 goto out;
277         }
278
279         /*
280          * allocate core vectors to store paths and multipaths
281          */
282         curmp = vector_alloc ();
283         pathvec = vector_alloc ();
284
285         if (!curmp || !pathvec){
286                 condlog (0, "%s: vector allocation failed.", alias);
287                 ret = MPATH_PR_DMMP_ERROR;
288                 goto out;
289         }
290
291         if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) {
292                 ret = MPATH_PR_DMMP_ERROR;
293                 goto out1;
294         }
295
296         /* get info of all paths from the dm device     */
297         if (get_mpvec(curmp, pathvec, alias)){
298                 condlog(0, "%s: failed to get device info.", alias);
299                 ret = MPATH_PR_DMMP_ERROR;
300                 goto out1;
301         }
302
303         mpp = find_mp_by_alias(curmp, alias);
304
305         if (!mpp) {
306                 condlog(0, "%s: devmap not registered.", alias);
307                 ret = MPATH_PR_DMMP_ERROR;
308                 goto out1;
309         }
310
311         select_reservation_key(mpp);
312
313         switch(rq_servact)
314         {
315         case MPATH_PROUT_REG_SA:
316         case MPATH_PROUT_REG_IGN_SA:
317                 ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
318                 break;
319         case MPATH_PROUT_RES_SA :
320         case MPATH_PROUT_PREE_SA :
321         case MPATH_PROUT_PREE_AB_SA :
322         case MPATH_PROUT_CLEAR_SA:
323                 ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
324                 break;
325         case MPATH_PROUT_REL_SA:
326                 ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
327                 break;
328         default:
329                 ret = MPATH_PR_OTHER;
330                 goto out1;
331         }
332
333         if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
334                                 (rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
335         {
336                 keyp=paramp->sa_key;
337                 prkey = 0;
338                 for (j = 0; j < 8; ++j) {
339                         if (j > 0)
340                                 prkey <<= 8;
341                         prkey |= *keyp;
342                         ++keyp;
343                 }
344                 if (prkey == 0)
345                         update_prflag(alias, "unset", noisy);
346                 else
347                         update_prflag(alias, "set", noisy);
348         } else {
349                 if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_CLEAR_SA) ||
350                                         (rq_servact == MPATH_PROUT_PREE_AB_SA ))){
351                         update_prflag(alias, "unset", noisy);
352                 }
353         }
354 out1:
355         free_multipathvec(curmp, KEEP_PATHS);
356         free_pathvec(pathvec, FREE_PATHS);
357
358 out:
359         FREE(alias);
360         return ret;
361 }
362
363 int
364 get_mpvec (vector curmp, vector pathvec, char * refwwid)
365 {
366         int i;
367         struct multipath *mpp;
368         char params[PARAMS_SIZE], status[PARAMS_SIZE];
369
370         if (dm_get_maps (curmp)){
371                 return 1;
372         }
373
374         vector_foreach_slot (curmp, mpp, i){
375                 /*
376                  * discard out of scope maps
377                  */
378                 if (mpp->alias && refwwid &&
379                     strncmp (mpp->alias, refwwid, WWID_SIZE - 1)){
380                         free_multipath (mpp, KEEP_PATHS);
381                         vector_del_slot (curmp, i);
382                         i--;
383                         continue;
384                 }
385
386                 dm_get_map(mpp->alias, &mpp->size, params);
387                 condlog(3, "params = %s", params);
388                 dm_get_status(mpp->alias, status);
389                 condlog(3, "status = %s", status);
390                 disassemble_map (pathvec, params, mpp);
391
392                 /*
393                  * disassemble_map() can add new paths to pathvec.
394                  * If not in "fast list mode", we need to fetch information
395                  * about them
396                  */
397                 updatepaths(mpp);
398                 mpp->bestpg = select_path_group (mpp);
399                 disassemble_status (status, mpp);
400
401         }
402         return MPATH_PR_SUCCESS ;
403 }
404
405 void * mpath_prin_pthread_fn (void *p)
406 {
407         int ret;
408         struct prin_param * pparam = (struct prin_param *)p;
409
410         ret = prin_do_scsi_ioctl(pparam->dev, pparam->rq_servact,
411                                  pparam->resp,  pparam->noisy);
412         pparam->status = ret;
413         pthread_exit(NULL);
414 }
415
416 int mpath_send_prin_activepath (char * dev, int rq_servact,
417                                 struct prin_resp * resp, int noisy)
418 {
419
420         int rc;
421
422         rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
423
424         return (rc);
425 }
426
427 int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
428         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
429 {
430
431         int i, j;
432         struct pathgroup *pgp = NULL;
433         struct path *pp = NULL;
434         int rollback = 0;
435         int active_pathcount=0;
436         int rc;
437         int count=0;
438         int status = MPATH_PR_SUCCESS;
439         uint64_t sa_key = 0;
440
441         if (!mpp)
442                 return MPATH_PR_DMMP_ERROR;
443
444         active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
445
446         if (active_pathcount == 0) {
447                 condlog (0, "%s: no path available", mpp->wwid);
448                 return MPATH_PR_DMMP_ERROR;
449         }
450
451         if ( paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK ) {
452                 condlog (1, "Warning: ALL_TG_PT is set. Configuration not supported");
453         }
454
455         struct threadinfo thread[active_pathcount];
456
457         memset(thread, 0, sizeof(thread));
458
459         /* init thread parameter */
460         for (i =0; i< active_pathcount; i++){
461                 thread[i].param.rq_servact = rq_servact;
462                 thread[i].param.rq_scope = rq_scope;
463                 thread[i].param.rq_type = rq_type;
464                 thread[i].param.paramp = paramp;
465                 thread[i].param.noisy = noisy;
466                 thread[i].param.status = -1;
467
468                 condlog (3, "THRED ID [%d] INFO]", i);
469                 condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
470                 condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
471                 condlog (3, "rq_type=%d ", thread[i].param.rq_type);
472                 condlog (3, "rkey=");
473                 condlog (3, "paramp->sa_flags =%02x ",
474                          thread[i].param.paramp->sa_flags);
475                 condlog (3, "noisy=%d ", thread[i].param.noisy);
476                 condlog (3, "status=%d ", thread[i].param.status);
477         }
478
479         pthread_attr_t attr;
480         pthread_attr_init(&attr);
481         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
482
483         vector_foreach_slot (mpp->pg, pgp, j){
484                 vector_foreach_slot (pgp->paths, pp, i){
485                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
486                                 condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
487                                 continue;
488                         }
489                         strncpy(thread[count].param.dev, pp->dev,
490                                 FILE_NAME_SIZE - 1);
491
492                         if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
493                                 /*
494                                  * Clearing SPEC_I_PT as transportids are already registered by now.
495                                  */
496                                 thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK);
497                         }
498
499                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
500
501                         rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param));
502                         if (rc){
503                                 condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
504                         }
505                         count = count +1;
506                 }
507         }
508         for( i=0; i < active_pathcount ; i++){
509                 rc = pthread_join(thread[i].id, NULL);
510                 if (rc){
511                         condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
512                 }
513                 if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
514                         rollback = 1;
515                         sa_key = 0;
516                         for (i = 0; i < 8; ++i){
517                                 if (i > 0)
518                                         sa_key <<= 8;
519                                 sa_key |= paramp->sa_key[i];
520                         }
521                         status = MPATH_PR_RESERV_CONFLICT ;
522                 }
523                 if (!rollback && (status == MPATH_PR_SUCCESS)){
524                         status = thread[i].param.status;
525                 }
526         }
527         if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
528                 condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
529                 for( i=0 ; i < active_pathcount ; i++){
530                         if((thread[i].param.status == MPATH_PR_SUCCESS) &&
531                                         ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
532                                 memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8);
533                                 memset(&thread[i].param.paramp->sa_key, 0, 8);
534                                 thread[i].param.status = MPATH_PR_SUCCESS;
535                                 rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn, 
536                                                 (void *)(&thread[i].param));
537                                 if (rc){
538                                         condlog (0, "%s: failed to create thread for rollback. %d",  mpp->wwid, rc);
539                                 }
540                         }
541                 }
542                 for(i=0; i < active_pathcount ; i++){
543                         rc = pthread_join(thread[i].id, NULL);
544                         if (rc){
545                                 condlog (3, "%s: failed to join thread while rolling back %d",
546                                                 mpp->wwid, i);
547                         }
548                 }
549         }
550
551         pthread_attr_destroy(&attr);
552         return (status);
553 }
554
555 void * mpath_prout_pthread_fn(void *p)
556 {
557         int ret;
558         struct prout_param * param = (struct prout_param *)p;
559
560         ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope,
561                         param->rq_type, param->paramp, param->noisy);
562         param->status = ret;
563         pthread_exit(NULL);
564 }
565
566 int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
567         unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
568 {
569         int i,j, ret;
570         struct pathgroup *pgp = NULL;
571         struct path *pp = NULL;
572
573         vector_foreach_slot (mpp->pg, pgp, j){
574                 vector_foreach_slot (pgp->paths, pp, i){
575                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
576                                 condlog (1, "%s: %s path not up. Skip",
577                                          mpp->wwid, pp->dev);
578                                 continue;
579                         }
580
581                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
582                         ret = send_prout_activepath(pp->dev, rq_servact,
583                                                     rq_scope, rq_type,
584                                                     paramp, noisy);
585                         return ret ;
586                 }
587         }
588         return MPATH_PR_SUCCESS;
589 }
590
591 int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
592         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
593 {
594         struct prout_param param;
595         param.rq_servact = rq_servact;
596         param.rq_scope  = rq_scope;
597         param.rq_type   = rq_type;
598         param.paramp    = paramp;
599         param.noisy = noisy;
600         param.status = -1;
601
602         pthread_t thread;
603         pthread_attr_t attr;
604         int rc;
605
606         memset(&thread, 0, sizeof(thread));
607         strncpy(param.dev, dev, FILE_NAME_SIZE - 1);
608         /* Initialize and set thread joinable attribute */
609         pthread_attr_init(&attr);
610         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
611
612         rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
613         if (rc){
614                 condlog (3, "%s: failed to create thread %d", dev, rc);
615                 return MPATH_PR_OTHER;
616         }
617         /* Free attribute and wait for the other threads */
618         pthread_attr_destroy(&attr);
619         rc = pthread_join(thread, NULL);
620
621         return (param.status);
622 }
623
624 int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
625         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
626 {
627         int i, j;
628         int num = 0;
629         struct pathgroup *pgp = NULL;
630         struct path *pp = NULL;
631         int active_pathcount = 0;
632         pthread_attr_t attr;
633         int rc, found = 0;;
634         int count = 0;
635         int status = MPATH_PR_SUCCESS;
636         struct prin_resp resp;
637         struct prout_param_descriptor *pamp;
638         struct prin_resp *pr_buff;
639         int length;
640         struct transportid *pptr;
641
642         if (!mpp)
643                 return MPATH_PR_DMMP_ERROR;
644
645         active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST);
646
647         struct threadinfo thread[active_pathcount];
648         memset(thread, 0, sizeof(thread));
649         for (i = 0; i < active_pathcount; i++){
650                 thread[i].param.rq_servact = rq_servact;
651                 thread[i].param.rq_scope = rq_scope;
652                 thread[i].param.rq_type = rq_type;
653                 thread[i].param.paramp = paramp;
654                 thread[i].param.noisy = noisy;
655                 thread[i].param.status = -1;
656
657                 condlog (3, " path count = %d", i);
658                 condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
659                 condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
660                 condlog (3, "rq_type=%d ", thread[i].param.rq_type);
661                 condlog (3, "noisy=%d ", thread[i].param.noisy);
662                 condlog (3, "status=%d ", thread[i].param.status);
663         }
664
665         pthread_attr_init (&attr);
666         pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
667
668         vector_foreach_slot (mpp->pg, pgp, j){
669                 vector_foreach_slot (pgp->paths, pp, i){
670                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
671                                 condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev);
672                                 continue;
673                         }
674
675                         strncpy(thread[count].param.dev, pp->dev,
676                                 FILE_NAME_SIZE - 1);
677                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
678                         rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
679                                         (void *) (&thread[count].param));
680                         if (rc)
681                                 condlog (0, "%s: failed to create thread. %d",  mpp->wwid, rc);
682                         count = count + 1;
683                 }
684         }
685         pthread_attr_destroy (&attr);
686         for (i = 0; i < active_pathcount; i++){
687                 rc = pthread_join (thread[i].id, NULL);
688                 if (rc){
689                         condlog (1, "%s: failed to join thread.  %d",  mpp->wwid,  rc);
690                 }
691         }
692
693         for (i = 0; i < active_pathcount; i++){
694                 /*  check thread status here and return the status */
695
696                 if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
697                         status = MPATH_PR_RESERV_CONFLICT;
698                 else if (status == MPATH_PR_SUCCESS
699                                 && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
700                         status = thread[i].param.status;
701         }
702
703         status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
704         if (status != MPATH_PR_SUCCESS){
705                 condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
706                 return MPATH_PR_OTHER;
707         }
708
709         num = resp.prin_descriptor.prin_readresv.additional_length / 8;
710         if (num == 0){
711                 condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
712                 return MPATH_PR_SUCCESS;
713         }
714         condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid);
715
716         pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
717         if (!pr_buff){
718                 condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);
719                 return MPATH_PR_OTHER;
720         }
721
722         status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
723
724         if (status != MPATH_PR_SUCCESS){
725                 condlog (0,  "%s: pr in read full status command failed.",  mpp->wwid);
726                 goto out;
727         }
728
729         num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
730         if (0 == num){
731                 goto out;
732         }
733         length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
734
735         pamp = (struct prout_param_descriptor *)malloc (length);
736         if (!pamp){
737                 condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
738                 goto out1;
739         }
740
741         memset(pamp, 0, length);
742
743         pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
744         if (!pamp->trnptid_list[0]){
745                 condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
746                 goto out1;
747         }
748
749         if (mpp->reservation_key ){
750                 memcpy (pamp->key, mpp->reservation_key, 8);
751                 condlog (3, "%s: reservation key set.", mpp->wwid);
752         }
753
754         status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
755                                      rq_scope, rq_type, pamp, noisy);
756
757         if (status) {
758                 condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
759                 goto out1;
760         }
761
762         pamp->num_transportid = 1;
763         pptr=pamp->trnptid_list[0];
764
765         for (i = 0; i < num; i++){
766                 if (mpp->reservation_key &&
767                         memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
768                                mpp->reservation_key, 8)){
769                         /*register with tarnsport id*/
770                         memset(pamp, 0, length);
771                         pamp->trnptid_list[0] = pptr;
772                         memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
773                         memcpy (pamp->sa_key,
774                                         pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
775                         pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
776                         pamp->num_transportid = 1;
777
778                         memcpy (pamp->trnptid_list[0],
779                                         &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
780                                         sizeof (struct transportid));
781                         status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
782                                         pamp, noisy);
783
784                         pamp->sa_flags = 0;
785                         memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
786                         memset (pamp->sa_key, 0, 8);
787                         pamp->num_transportid = 0;
788                         status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
789                                         pamp, noisy);
790                 }
791                 else
792                 {
793                         if (mpp->reservation_key)
794                                 found = 1;
795                 }
796
797
798         }
799
800         if (found){
801                 memset (pamp, 0, length);
802                 memcpy (pamp->sa_key, mpp->reservation_key, 8);
803                 memset (pamp->key, 0, 8);
804                 status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
805         }
806
807
808         free(pptr);
809 out1:
810         free (pamp);
811 out:
812         free (pr_buff);
813         return (status);
814 }
815
816 void * mpath_alloc_prin_response(int prin_sa)
817 {
818         void * ptr = NULL;
819         int size=0;
820         switch (prin_sa)
821         {
822                 case MPATH_PRIN_RKEY_SA:
823                         size = sizeof(struct prin_readdescr);
824                         ptr = malloc(size);
825                         memset(ptr, 0, size);
826                         break;
827                 case MPATH_PRIN_RRES_SA:
828                         size = sizeof(struct prin_resvdescr);
829                         ptr = malloc(size);
830                         memset(ptr, 0, size);
831                         break;
832                 case MPATH_PRIN_RCAP_SA:
833                         size=sizeof(struct prin_capdescr);
834                         ptr = malloc(size);
835                         memset(ptr, 0, size);
836                         break;
837                 case MPATH_PRIN_RFSTAT_SA:
838                         size = sizeof(struct print_fulldescr_list) +
839                                 sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
840                         ptr = malloc(size);
841                         memset(ptr, 0, size);
842                         break;
843         }
844         return ptr;
845 }
846
847 int update_map_pr(struct multipath *mpp)
848 {
849         int noisy=0;
850         struct prin_resp *resp;
851         int i,j, ret, isFound;
852         unsigned char *keyp;
853         uint64_t prkey;
854
855         if (!mpp->reservation_key)
856         {
857                 /* Nothing to do. Assuming pr mgmt feature is disabled*/
858                 condlog(3, "%s: reservation_key not set in multipath.conf", mpp->alias);
859                 return MPATH_PR_SUCCESS;
860         }
861
862         resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
863         if (!resp)
864         {
865                 condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
866                 return MPATH_PR_OTHER;
867         }
868         ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
869
870         if (ret != MPATH_PR_SUCCESS )
871         {
872                 condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
873                 free(resp);
874                 return  ret;
875         }
876
877         if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
878         {
879                 condlog(0,"%s: No key found. Device may not be registered. ", mpp->alias);
880                 free(resp);
881                 return MPATH_PR_SUCCESS;
882         }
883
884         prkey = 0;
885         keyp = mpp->reservation_key;
886         for (j = 0; j < 8; ++j) {
887                 if (j > 0)
888                         prkey <<= 8;
889                 prkey |= *keyp;
890                 ++keyp;
891         }
892         condlog(2, "%s: Multipath  reservation_key: 0x%" PRIx64 " ", mpp->alias, prkey);
893
894         isFound =0;
895         for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
896         {
897                 condlog(2, "%s: PR IN READKEYS[%d]  reservation key:", mpp->alias, i);
898                 dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
899
900                 if (!memcmp(mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
901                 {
902                         condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
903                         isFound =1;
904                 }
905         }
906
907         if (isFound)
908         {
909                 mpp->prflag = 1;
910                 condlog(2, "%s: prflag flag set.", mpp->alias );
911         }
912
913         free(resp);
914         return MPATH_PR_SUCCESS;
915 }
916
917
918