[multipath] claimed path handling overall
[platform/upstream/multipath-tools.git] / multipath / main.c
1 /*
2  * Soft:        multipath device mapper target autoconfig
3  *
4  * Version:     $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
5  *
6  * Author:      Copyright (C) 2003 Christophe Varoqui
7  *
8  *              This program is distributed in the hope that it will be useful,
9  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *              See the GNU General Public License for more details.
12  *
13  *              This program is free software; you can redistribute it and/or
14  *              modify it under the terms of the GNU General Public License
15  *              as published by the Free Software Foundation; either version
16  *              2 of the License, or (at your option) any later version.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <sys/file.h>
24 #include <errno.h>
25
26 #include <parser.h>
27 #include <vector.h>
28 #include <memory.h>
29 #include <libdevmapper.h>
30 #include <devmapper.h>
31 #include <checkers.h>
32 #include <path_state.h>
33 #include <blacklist.h>
34 #include <hwtable.h>
35 #include <util.h>
36 #include <defaults.h>
37 #include <structs.h>
38 #include <dmparser.h>
39 #include <cache.h>
40 #include <config.h>
41 #include <propsel.h>
42 #include <discovery.h>
43 #include <debug.h>
44 #include <switchgroup.h>
45 #include <sysfs/libsysfs.h>
46 #include <print.h>
47
48 #include "main.h"
49 #include "pgpolicies.h"
50 #include "dict.h"
51
52 /* for column aligned output */
53 struct path_layout pl;
54
55 static char *
56 get_refwwid (vector pathvec)
57 {
58         struct path * pp;
59         char buff[FILE_NAME_SIZE];
60         char * refwwid;
61
62         if (conf->dev_type == DEV_NONE)
63                 return NULL;
64
65         if (conf->dev_type == DEV_DEVNODE) {
66                 condlog(3, "limited scope = %s", conf->dev);
67                 basename(conf->dev, buff);
68                 pp = find_path_by_dev(pathvec, buff);
69                 
70                 if (!pp) {
71                         pp = alloc_path();
72
73                         if (!pp)
74                                 return NULL;
75
76                         strncpy(pp->dev, buff, FILE_NAME_SIZE);
77
78                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
79                                 return NULL;
80
81                         if (store_path(pathvec, pp)) {
82                                 free_path(pp);
83                                 return NULL;
84                         }
85                 }
86
87                 refwwid = MALLOC(WWID_SIZE);
88
89                 if (!refwwid)
90                         return NULL;
91
92                 memcpy(refwwid, pp->wwid, WWID_SIZE);
93                 return refwwid;
94         }
95
96         if (conf->dev_type == DEV_DEVT) {
97                 condlog(3, "limited scope = %s", conf->dev);
98                 pp = find_path_by_devt(pathvec, conf->dev);
99                 
100                 if (!pp) {
101                         if (devt2devname(conf->dev, buff))
102                                 return NULL;
103
104                         pp = alloc_path();
105
106                         if (!pp)
107                                 return NULL;
108
109                         if(safe_sprintf(pp->dev, "%s", buff)) {
110                                 fprintf(stderr, "pp->dev too small\n");
111                                 exit(1);
112                         }
113                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
114                                 return NULL;
115                         
116                         if (store_path(pathvec, pp)) {
117                                 free_path(pp);
118                                 return NULL;
119                         }
120                 }
121
122                 refwwid = MALLOC(WWID_SIZE);
123
124                 if (!refwwid)
125                         return NULL;
126                 
127                 memcpy(refwwid, pp->wwid, WWID_SIZE);
128                 return refwwid;
129         }
130         if (conf->dev_type == DEV_DEVMAP) {
131                 condlog(3, "limited scope = %s", conf->dev);
132                 /*
133                  * may be an alias
134                  */
135                 refwwid = get_mpe_wwid(conf->dev);
136
137                 if (refwwid)
138                         return STRDUP(refwwid);
139                 
140                 /*
141                  * or directly a wwid
142                  */
143                 refwwid = MALLOC(WWID_SIZE);
144
145                 if (!refwwid)
146                         return NULL;
147
148                 strncpy(refwwid, conf->dev, WWID_SIZE);
149                 return refwwid;
150         }
151         return NULL;
152 }
153
154 static void
155 print_path (struct path * pp, char * style)
156 {
157         char buff[MAX_LINE_LEN];
158
159         snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
160         printf("%s", buff);
161 }
162
163 static void
164 print_map (struct multipath * mpp)
165 {
166         if (mpp->size && mpp->params)
167                 printf("0 %llu %s %s\n",
168                          mpp->size, DEFAULT_TARGET, mpp->params);
169         return;
170 }
171
172 static void
173 print_all_paths (vector pathvec)
174 {
175         int i;
176         struct path * pp;
177
178         vector_foreach_slot (pathvec, pp, i)
179                 print_path(pp, PRINT_PATH_LONG);
180 }
181
182 static void
183 print_mp (struct multipath * mpp)
184 {
185         int j, i;
186         struct path * pp = NULL;
187         struct pathgroup * pgp = NULL;
188
189         if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
190                 return;
191
192         if (conf->verbosity > 1) {
193                 switch (mpp->action) {
194                 case ACT_RELOAD:
195                         printf("%s: ", ACT_RELOAD_STR);
196                         break;
197
198                 case ACT_CREATE:
199                         printf("%s: ", ACT_CREATE_STR);
200                         break;
201
202                 case ACT_SWITCHPG:
203                         printf("%s: ", ACT_SWITCHPG_STR);
204                         break;
205
206                 default:
207                         break;
208                 }
209         }
210
211         if (mpp->alias)
212                 printf("%s", mpp->alias);
213
214         if (conf->verbosity == 1) {
215                 printf("\n");
216                 return;
217         }
218         if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
219                 printf(" (%s)", mpp->wwid);
220
221         printf("\n");
222
223         if (mpp->size < (1 << 11))
224                 printf("[size=%llu kB]", mpp->size >> 1);
225         else if (mpp->size < (1 << 21))
226                 printf("[size=%llu MB]", mpp->size >> 11);
227         else if (mpp->size < (1 << 31))
228                 printf("[size=%llu GB]", mpp->size >> 21);
229         else
230                 printf("[size=%llu TB]", mpp->size >> 31);
231
232         if (mpp->features)
233                 printf("[features=\"%s\"]", mpp->features);
234
235         if (mpp->hwhandler)
236                 printf("[hwhandler=\"%s\"]", mpp->hwhandler);
237
238         fprintf(stdout, "\n");
239
240         if (!mpp->pg)
241                 return;
242
243         vector_foreach_slot (mpp->pg, pgp, j) {
244                 printf("\\_ ");
245
246                 if (mpp->selector) {
247                         printf("%s ", mpp->selector);
248 #if 0
249                         /* align to path status info */
250                         for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
251                              i > strlen(mpp->selector); i--)
252                                 printf(" ");
253 #endif
254                 }
255                 if (pgp->priority)
256                         printf("[prio=%i]", pgp->priority);
257
258                 switch (pgp->status) {
259                 case PGSTATE_ENABLED:
260                         printf("[enabled]");
261                         break;
262                 case PGSTATE_DISABLED:
263                         printf("[disabled]");
264                         break;
265                 case PGSTATE_ACTIVE:
266                         printf("[active]");
267                         break;
268                 default:
269                         break;
270                 }
271                 printf("\n");
272
273                 vector_foreach_slot (pgp->paths, pp, i)
274                         print_path(pp, PRINT_PATH_INDENT);
275         }
276         printf("\n");
277 }
278
279 static int
280 filter_pathvec (vector pathvec, char * refwwid)
281 {
282         int i;
283         struct path * pp;
284
285         if (!refwwid || !strlen(refwwid))
286                 return 0;
287
288         vector_foreach_slot (pathvec, pp, i) {
289                 if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
290                         condlog(3, "skip path %s : out of scope", pp->dev);
291                         free_path(pp);
292                         vector_del_slot(pathvec, i);
293                         i--;
294                 }
295         }
296         return 0;
297 }
298
299 /*
300  * Transforms the path group vector into a proper device map string
301  */
302 int
303 assemble_map (struct multipath * mp)
304 {
305         int i, j;
306         int shift, freechar;
307         int minio;
308         char * p;
309         struct pathgroup * pgp;
310         struct path * pp;
311
312         p = mp->params;
313         freechar = sizeof(mp->params);
314         
315         shift = snprintf(p, freechar, "%s %s %i %i",
316                          mp->features, mp->hwhandler,
317                          VECTOR_SIZE(mp->pg), mp->nextpg);
318
319         if (shift >= freechar) {
320                 fprintf(stderr, "mp->params too small\n");
321                 return 1;
322         }
323         p += shift;
324         freechar -= shift;
325         
326         vector_foreach_slot (mp->pg, pgp, i) {
327                 pgp = VECTOR_SLOT(mp->pg, i);
328                 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
329                                  VECTOR_SIZE(pgp->paths));
330                 if (shift >= freechar) {
331                         fprintf(stderr, "mp->params too small\n");
332                         return 1;
333                 }
334                 p += shift;
335                 freechar -= shift;
336
337                 vector_foreach_slot (pgp->paths, pp, j) {
338                         minio = conf->minio;
339                         
340                         if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
341                                 minio *= pp->priority;
342
343                         shift = snprintf(p, freechar, " %s %d",
344                                          pp->dev_t, minio);
345                         if (shift >= freechar) {
346                                 fprintf(stderr, "mp->params too small\n");
347                                 return 1;
348                         }
349                         p += shift;
350                         freechar -= shift;
351                 }
352         }
353         if (freechar < 1) {
354                 fprintf(stderr, "mp->params too small\n");
355                 return 1;
356         }
357         snprintf(p, 1, "\n");
358
359         if (conf->verbosity > 2)
360                 print_map(mp);
361
362         return 0;
363 }
364
365 static int
366 setup_map (struct multipath * mpp)
367 {
368         /*
369          * don't bother if devmap size is unknown
370          */
371         if (mpp->size <= 0) {
372                 condlog(3, "%s devmap size is unknown", mpp->alias);
373                 return 1;
374         }
375
376         /*
377          * properties selectors
378          */
379         select_pgpolicy(mpp);
380         select_selector(mpp);
381         select_features(mpp);
382         select_hwhandler(mpp);
383         select_rr_weight(mpp);
384         select_no_path_retry(mpp);
385
386         /*
387          * apply selected grouping policy to valid paths
388          */
389         switch (mpp->pgpolicy) {
390         case MULTIBUS:
391                 one_group(mpp);
392                 break;
393         case FAILOVER:
394                 one_path_per_group(mpp);
395                 break;
396         case GROUP_BY_SERIAL:
397                 group_by_serial(mpp);
398                 break;
399         case GROUP_BY_PRIO:
400                 group_by_prio(mpp);
401                 break;
402         case GROUP_BY_NODE_NAME:
403                 group_by_node_name(mpp);
404                 break;
405         default:
406                 break;
407         }
408
409         if (mpp->pg == NULL) {
410                 condlog(3, "pgpolicy failed to produce a pg vector");
411                 return 1;
412         }
413
414         /*
415          * ponders each path group and determine highest prio pg
416          * to switch over (default to first)
417          */
418         select_path_group(mpp);
419
420         /*
421          * transform the mp->pg vector of vectors of paths
422          * into a mp->params strings to feed the device-mapper
423          */
424         if (assemble_map(mpp)) {
425                 condlog(3, "problem assembing map");
426                 return 1;
427         }
428         return 0;
429 }
430
431 static int
432 pathcount (struct multipath * mpp, int state)
433 {
434         struct pathgroup *pgp;
435         struct path *pp;
436         int i, j;
437         int count = 0;
438
439         vector_foreach_slot (mpp->pg, pgp, i)
440                 vector_foreach_slot (pgp->paths, pp, j)
441                         if (pp->state == state)
442                                 count++;
443         return count;
444 }
445
446 static void
447 compute_pgid(struct pathgroup * pgp)
448 {
449         struct path * pp;
450         int i;
451
452         vector_foreach_slot (pgp->paths, pp, i)
453                 pgp->id ^= (long)pp;
454 }
455
456 static int
457 pgcmp (struct multipath * mpp, struct multipath * cmpp)
458 {
459         int i, j;
460         struct pathgroup * pgp;
461         struct pathgroup * cpgp;
462         int r = 0;
463
464         vector_foreach_slot (mpp->pg, pgp, i) {
465                 compute_pgid(pgp);
466
467                 vector_foreach_slot (cmpp->pg, cpgp, j) {
468                         if (pgp->id == cpgp->id) {
469                                 r = 0;
470                                 break;
471                         }
472                         r++;
473                 }
474                 if (r)
475                         return r;
476         }
477         return r;
478 }
479
480 static void
481 select_action (struct multipath * mpp, vector curmp)
482 {
483         struct multipath * cmpp;
484
485         cmpp = find_mp(curmp, mpp->alias);
486
487         if (!cmpp) {
488                 cmpp = find_mp_by_wwid(curmp, mpp->wwid);
489
490                 if (cmpp && !conf->dry_run) {
491                         condlog(2, "remove: %s (dup of %s)",
492                                 cmpp->alias, mpp->alias);
493                         dm_flush_map(cmpp->alias, DEFAULT_TARGET);
494                 }
495                 mpp->action = ACT_CREATE;
496                 condlog(3, "set ACT_CREATE: map does not exists");
497                 return;
498         }
499
500         if (!find_mp_by_wwid(curmp, mpp->wwid)) {
501                 condlog(2, "remove: %s (wwid changed)", cmpp->alias);
502                 dm_flush_map(mpp->alias, NULL);
503                 strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
504                 drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
505                 mpp->action = ACT_CREATE;
506                 condlog(3, "set ACT_CREATE: map wwid change");
507                 return;
508         }
509                 
510         if (pathcount(mpp, PATH_UP) == 0) {
511                 mpp->action = ACT_NOTHING;
512                 condlog(3, "set ACT_NOTHING: no usable path");
513                 return;
514         }
515         if (cmpp->size != mpp->size) {
516                 mpp->action = ACT_RELOAD;
517                 condlog(3, "set ACT_RELOAD: size change");
518                 return;
519         }
520         if (strncmp(cmpp->features, mpp->features,
521                     strlen(mpp->features))) {
522                 mpp->action =  ACT_RELOAD;
523                 condlog(3, "set ACT_RELOAD: features change");
524                 return;
525         }
526         if (strncmp(cmpp->hwhandler, mpp->hwhandler,
527                     strlen(mpp->hwhandler))) {
528                 mpp->action = ACT_RELOAD;
529                 condlog(3, "set ACT_RELOAD: hwhandler change");
530                 return;
531         }
532         if (strncmp(cmpp->selector, mpp->selector,
533                     strlen(mpp->selector))) {
534                 mpp->action = ACT_RELOAD;
535                 condlog(3, "set ACT_RELOAD: selector change");
536                 return;
537         }
538         if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
539                 mpp->action = ACT_RELOAD;
540                 condlog(3, "set ACT_RELOAD: number of path group change");
541                 return;
542         }
543         if (pgcmp(mpp, cmpp)) {
544                 mpp->action = ACT_RELOAD;
545                 condlog(3, "set ACT_RELOAD: path group topology change");
546                 return;
547         }
548         if (cmpp->nextpg != mpp->nextpg) {
549                 mpp->action = ACT_SWITCHPG;
550                 condlog(3, "set ACT_SWITCHPG: next path group change");
551                 return;
552         }
553         mpp->action = ACT_NOTHING;
554         condlog(3, "set ACT_NOTHING: map unchanged");
555         return;
556 }
557
558 static int
559 reinstate_paths (struct multipath * mpp)
560 {
561         int i, j;
562         struct pathgroup * pgp;
563         struct path * pp;
564
565         if (!mpp->pg)
566                 return 0;
567
568         vector_foreach_slot (mpp->pg, pgp, i) {
569                 if (!pgp->paths)
570                         continue;
571
572                 vector_foreach_slot (pgp->paths, pp, j) {
573                         if (pp->state != PATH_UP &&
574                             (pgp->status == PGSTATE_DISABLED ||
575                              pgp->status == PGSTATE_ACTIVE))
576                                 continue;
577
578                         if (pp->dmstate == PSTATE_FAILED) {
579                                 if (dm_reinstate(mpp->alias, pp->dev_t))
580                                         condlog(0, "error reinstating %s",
581                                                 pp->dev);
582                         }
583                 }
584         }
585         return 0;
586 }
587
588 int lock_multipath (struct multipath * mpp, int lock)
589 {
590         struct pathgroup * pgp;
591         struct path * pp;
592         int i, j;
593
594         if (!mpp || !mpp->pg)
595                 return 0;
596         
597         vector_foreach_slot (mpp->pg, pgp, i) {
598                 if (!pgp->paths)
599                         continue;
600                 vector_foreach_slot(pgp->paths, pp, j) {
601                         if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
602                             errno == EWOULDBLOCK)
603                                 return 1;
604                         else if (!lock)
605                                 flock(pp->fd, LOCK_UN);
606                 }
607         }
608         return 0;
609 }
610
611 /*
612  * Return value:
613  *  -1: Retry
614  *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
615  *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
616  *   2: Map is already existing.
617  */
618 static int
619 domap (struct multipath * mpp)
620 {
621         int r = 0;
622
623         /*
624          * last chance to quit before touching the devmaps
625          */
626         if (conf->dry_run)
627                 return 0;
628
629         switch (mpp->action) {
630         case ACT_NOTHING:
631                 return 2;
632
633         case ACT_SWITCHPG:
634                 dm_switchgroup(mpp->alias, mpp->nextpg);
635                 /*
636                  * we may have avoided reinstating paths because there where in
637                  * active or disabled PG. Now that the topology has changed,
638                  * retry.
639                  */
640                 reinstate_paths(mpp);
641                 return 2;
642
643         case ACT_CREATE:
644                 if (lock_multipath(mpp, 1)) {
645                         condlog(3, "%s: in use", mpp->alias);
646                         return -1;
647                 }
648                 dm_shut_log();
649
650                 if (dm_map_present(mpp->alias))
651                         break;
652
653                 r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
654                               mpp->params, mpp->size, mpp->wwid);
655
656                 /*
657                  * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
658                  * DM_TABLE_LOAD. Failing the second part leaves an
659                  * empty map. Clean it up.
660                  */
661                 if (!r && dm_map_present(mpp->alias)) {
662                         condlog(3, "%s: failed to load map "
663                                    "(a path might be in use)",
664                                    mpp->alias);
665                         dm_flush_map(mpp->alias, NULL);
666                 }
667
668                 lock_multipath(mpp, 0);
669                 dm_restore_log();
670                 break;
671
672         case ACT_RELOAD:
673                 r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
674                               mpp->params, mpp->size, NULL) &&
675                      dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
676                 break;
677
678         default:
679                 break;
680         }
681
682         if (r) {
683                 /*
684                  * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
685                  */
686                 dm_switchgroup(mpp->alias, mpp->nextpg);
687                 print_mp(mpp);
688         }
689
690         return r;
691 }
692
693 static int
694 deadmap (struct multipath * mpp)
695 {
696         int i, j;
697         struct pathgroup * pgp;
698         struct path * pp;
699
700         if (!mpp->pg)
701                 return 1;
702
703         vector_foreach_slot (mpp->pg, pgp, i) {
704                 if (!pgp->paths)
705                         continue;
706
707                 vector_foreach_slot (pgp->paths, pp, j)
708                         if (strlen(pp->dev))
709                                 return 0; /* alive */
710         }
711         
712         return 1; /* dead */
713 }
714
715 static int
716 coalesce_paths (vector curmp, vector pathvec)
717 {
718         int r = 1;
719         int k, i;
720         char empty_buff[WWID_SIZE];
721         struct multipath * mpp;
722         struct path * pp1;
723         struct path * pp2;
724
725         memset(empty_buff, 0, WWID_SIZE);
726
727         vector_foreach_slot (pathvec, pp1, k) {
728                 /* skip this path for some reason */
729
730                 /* 1. if path has no unique id or wwid blacklisted */
731                 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
732                     blacklist(conf->blist, pp1->wwid))
733                         continue;
734
735                 /* 2. if path already coalesced */
736                 if (pp1->mpp)
737                         continue;
738
739                 /*
740                  * at this point, we know we really got a new mp
741                  */
742                 mpp = alloc_multipath();
743
744                 if (!mpp)
745                         return 1;
746
747                 mpp->mpe = find_mpe(pp1->wwid);
748                 mpp->hwe = pp1->hwe;
749                 select_alias(mpp);
750
751                 pp1->mpp = mpp;
752                 strcpy(mpp->wwid, pp1->wwid);
753                 mpp->size = pp1->size;
754                 mpp->paths = vector_alloc();
755
756                 if (pp1->priority < 0)
757                         mpp->action = ACT_NOTHING;
758
759                 if (!mpp->paths)
760                         return 1;
761                 
762                 if (store_path(mpp->paths, pp1))
763                         return 1;
764
765                 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
766                         pp2 = VECTOR_SLOT(pathvec, i);
767
768                         if (strcmp(pp1->wwid, pp2->wwid))
769                                 continue;
770                         
771                         pp2->mpp = mpp;
772
773                         if (pp2->size != mpp->size) {
774                                 /*
775                                  * ouch, avoid feeding that to the DM
776                                  */
777                                 condlog(3, "path size mismatch : discard %s",
778                                      mpp->wwid);
779                                 mpp->action = ACT_NOTHING;
780                         }
781                         if (pp2->priority < 0)
782                                 mpp->action = ACT_NOTHING;
783
784                         if (store_path(mpp->paths, pp2))
785                                 return 1;
786                 }
787                 if (setup_map(mpp))
788                         goto next;
789
790                 if (mpp->action == ACT_UNDEF)
791                         select_action(mpp, curmp);
792
793                 r = domap(mpp);
794
795                 if (r < 0)
796                         return r;
797
798                 if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
799                         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
800                                 dm_queue_if_no_path(mpp->alias, 0);
801                         else
802                                 dm_queue_if_no_path(mpp->alias, 1);
803                 }
804
805 next:
806                 drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
807                 free_multipath(mpp, KEEP_PATHS);
808         }
809         /*
810          * Flush maps with only dead paths (ie not in sysfs)
811          * Keep maps with only failed paths
812          */
813         vector_foreach_slot (curmp, mpp, i) {
814                 if (!deadmap(mpp))
815                         continue;
816
817                 if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
818                         condlog(2, "remove: %s (dead) failed!",
819                                 mpp->alias);
820                 else
821                         condlog(2, "remove: %s (dead)", mpp->alias);
822         }
823         return 0;
824 }
825
826 static void
827 usage (char * progname)
828 {
829         fprintf (stderr, VERSION_STRING);
830         fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
831                 progname);
832         fprintf (stderr,
833                 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
834                 "\t\t\t[device]\n" \
835                 "\n" \
836                 "\t-v level\tverbosty level\n" \
837                 "\t   0\t\t\tno output\n" \
838                 "\t   1\t\t\tprint created devmap names only\n" \
839                 "\t   2\t\t\tdefault verbosity\n" \
840                 "\t   3\t\t\tprint debug information\n" \
841                 "\t-d\t\tdry run, do not create or update devmaps\n" \
842                 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
843                 "\t-ll\t\tshow multipath topology (maximum info)\n" \
844                 "\t-f\t\tflush a multipath device map\n" \
845                 "\t-F\t\tflush all multipath device maps\n" \
846                 "\t-p policy\tforce all maps to specified policy :\n" \
847                 "\t   failover\t\t1 path per priority group\n" \
848                 "\t   multibus\t\tall paths in 1 priority group\n" \
849                 "\t   group_by_serial\t1 priority group per serial\n" \
850                 "\t   group_by_prio\t1 priority group per priority lvl\n" \
851                 "\t   group_by_node_name\t1 priority group per target node\n" \
852                 "\n" \
853                 "\tdevice\t\tlimit scope to the device's multipath\n" \
854                 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
855                 "\t\t\tor major:minor or a device map name)\n" \
856                 );
857
858         exit(1);
859 }
860
861 static int
862 update_paths (struct multipath * mpp)
863 {
864         int i, j;
865         struct pathgroup * pgp;
866         struct path * pp;
867
868         if (!mpp->pg)
869                 return 0;
870
871         vector_foreach_slot (mpp->pg, pgp, i) {
872                 if (!pgp->paths)
873                         continue;
874
875                 vector_foreach_slot (pgp->paths, pp, j) {
876                         if (!strlen(pp->dev)) {
877                                 if (devt2devname(pp->dev_t, pp->dev)) {
878                                         /*
879                                          * path is not in sysfs anymore
880                                          */
881                                         pp->state = PATH_DOWN;
882                                         continue;
883                                 }
884                                 pathinfo(pp, conf->hwtable,
885                                          DI_SYSFS | DI_CHECKER | \
886                                          DI_SERIAL | DI_PRIO);
887                                 continue;
888                         }
889                         if (pp->state == PATH_UNCHECKED)
890                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
891
892                         if (!pp->priority)
893                                 pathinfo(pp, conf->hwtable, DI_PRIO);
894                 }
895         }
896         return 0;
897 }
898
899 static int
900 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
901 {
902         int i;
903         struct multipath * mpp;
904
905         if (dm_get_maps(curmp, DEFAULT_TARGET))
906                 return 1;
907
908         vector_foreach_slot (curmp, mpp, i) {
909                 /*
910                  * discard out of scope maps
911                  */
912                 if (mpp->wwid && refwwid &&
913                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
914                         condlog(3, "skip map %s: out of scope", mpp->alias);
915                         free_multipath(mpp, KEEP_PATHS);
916                         vector_del_slot(curmp, i);
917                         i--;
918                         continue;
919                 }
920
921                 condlog(3, "params = %s", mpp->params);
922                 condlog(3, "status = %s", mpp->status);
923
924                 disassemble_map(pathvec, mpp->params, mpp);
925
926                 /*
927                  * disassemble_map() can add new paths to pathvec.
928                  * If not in "fast list mode", we need to fetch information
929                  * about them
930                  */
931                 if (conf->list != 1)
932                         update_paths(mpp);
933
934                 if (conf->list > 1)
935                         select_path_group(mpp);
936
937                 disassemble_status(mpp->status, mpp);
938
939                 if (conf->list)
940                         print_mp(mpp);
941
942                 if (!conf->dry_run)
943                         reinstate_paths(mpp);
944         }
945         return 0;
946 }
947
948
949 /*
950  * Return value:
951  *  -1: Retry
952  *   0: Success
953  *   1: Failure
954  */
955 static int
956 configure (void)
957 {
958         vector curmp = NULL;
959         vector pathvec = NULL;
960         int r = 1;
961         int di_flag = 0;
962         char * refwwid = NULL;
963
964         /*
965          * allocate core vectors to store paths and multipaths
966          */
967         curmp = vector_alloc();
968         pathvec = vector_alloc();
969
970         if (!curmp || !pathvec) {
971                 condlog(0, "can not allocate memory");
972                 goto out;
973         }
974
975         /*
976          * if we have a blacklisted device parameter, exit early
977          */
978         if (conf->dev && blacklist(conf->blist, conf->dev))
979                 goto out;
980         
981         condlog(3, "load path identifiers cache");
982         cache_load(pathvec);
983
984         if (conf->verbosity > 2) {
985                 fprintf(stdout, "#\n# all paths in cache :\n#\n");
986                 print_all_paths(pathvec);
987         }
988
989         /*
990          * get a path list
991          */
992         if (conf->dev)
993                 di_flag = DI_WWID;
994
995         if (conf->list > 1)
996                 /* extended path info '-ll' */
997                 di_flag |= DI_SYSFS | DI_CHECKER;
998         else if (conf->list)
999                 /* minimum path info '-l' */
1000                 di_flag |= DI_SYSFS;
1001         else
1002                 /* maximum info */
1003                 di_flag = DI_ALL;
1004
1005         if (path_discovery(pathvec, conf, di_flag))
1006                 goto out;
1007
1008         if (conf->verbosity > 2) {
1009                 fprintf(stdout, "#\n# all paths :\n#\n");
1010                 print_all_paths(pathvec);
1011         }
1012
1013         /*
1014          * scope limiting must be translated into a wwid
1015          * failing the translation is fatal (by policy)
1016          */
1017         if (conf->dev) {
1018                 refwwid = get_refwwid(pathvec);
1019
1020                 if (!refwwid) {
1021                         condlog(3, "scope is nul");
1022                         goto out;
1023                 }
1024         }
1025
1026         get_path_layout(&pl, pathvec);
1027
1028         if (get_dm_mpvec(curmp, pathvec, refwwid))
1029                 goto out;
1030
1031         filter_pathvec(pathvec, refwwid);
1032
1033         if (conf->list)
1034                 goto out;
1035
1036         /*
1037          * core logic entry point
1038          */
1039         r = coalesce_paths(curmp, pathvec);
1040
1041 out:
1042         if (refwwid)
1043                 FREE(refwwid);
1044
1045         free_multipathvec(curmp, KEEP_PATHS);
1046         free_pathvec(pathvec, FREE_PATHS);
1047
1048         return r;
1049 }
1050
1051 int
1052 main (int argc, char *argv[])
1053 {
1054         int arg;
1055         extern char *optarg;
1056         extern int optind;
1057         int i, r;
1058
1059         if (getuid() != 0) {
1060                 fprintf(stderr, "need to be root\n");
1061                 exit(1);
1062         }
1063
1064         if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
1065                 exit(1);
1066
1067         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
1068                 condlog(0, "multipath tools need sysfs mounted");
1069                 exit(1);
1070         }
1071         if (load_config(DEFAULT_CONFIGFILE))
1072                 exit(1);
1073
1074         while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
1075                 switch(arg) {
1076                 case 1: printf("optarg : %s\n",optarg);
1077                         break;
1078                 case 'v':
1079                         if (sizeof(optarg) > sizeof(char *) ||
1080                             !isdigit(optarg[0]))
1081                                 usage (argv[0]);
1082
1083                         conf->verbosity = atoi(optarg);
1084                         break;
1085                 case 'd':
1086                         conf->dry_run = 1;
1087                         break;
1088                 case 'f':
1089                         conf->remove = FLUSH_ONE;
1090                         break;
1091                 case 'F':
1092                         conf->remove = FLUSH_ALL;
1093                         break;
1094                 case 'l':
1095                         conf->list = 1;
1096                         conf->dry_run = 1;
1097
1098                         if (optarg && !strncmp(optarg, "l", 1))
1099                                 conf->list++;
1100
1101                         break;
1102                 case 'M':
1103 #if _DEBUG_
1104                         debug = atoi(optarg);
1105 #endif
1106                         break;
1107                 case 'p':
1108                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
1109                         if (conf->pgpolicy_flag == -1) {
1110                                 printf("'%s' is not a valid policy\n", optarg);
1111                                 usage(argv[0]);
1112                         }                
1113                         break;
1114                 case ':':
1115                         fprintf(stderr, "Missing option arguement\n");
1116                         usage(argv[0]);        
1117                 case '?':
1118                         fprintf(stderr, "Unknown switch: %s\n", optarg);
1119                         usage(argv[0]);
1120                 default:
1121                         usage(argv[0]);
1122                 }
1123         }        
1124         if (optind < argc) {
1125                 conf->dev = MALLOC(FILE_NAME_SIZE);
1126
1127                 if (!conf->dev)
1128                         goto out;
1129
1130                 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
1131
1132                 if (filepresent(conf->dev))
1133                         conf->dev_type = DEV_DEVNODE;
1134                 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
1135                         conf->dev_type = DEV_DEVT;
1136                 else
1137                         conf->dev_type = DEV_DEVMAP;
1138
1139         }
1140
1141         if (conf->remove == FLUSH_ONE) {
1142                 if (conf->dev_type == DEV_DEVMAP)
1143                         dm_flush_map(conf->dev, DEFAULT_TARGET);
1144                 else
1145                         condlog(0, "must provide a map name to remove");
1146
1147                 goto out;
1148         }
1149         else if (conf->remove == FLUSH_ALL) {
1150                 dm_flush_maps(DEFAULT_TARGET);
1151                 goto out;
1152         }
1153         while ((r = configure()) < 0)
1154                 condlog(3, "restart multipath configuration process");
1155         
1156 out:
1157         free_config(conf);
1158         dm_lib_release();
1159         dm_lib_exit();
1160 #ifdef _DEBUG_
1161         dbg_free_final(NULL);
1162 #endif
1163         return r;
1164 }