[multipath] proper execution serializing
[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         struct path * pp;
369         int i;
370
371         /*
372          * don't bother if devmap size is unknown
373          */
374         if (mpp->size <= 0) {
375                 condlog(3, "%s devmap size is unknown", mpp->alias);
376                 return 1;
377         }
378
379         /*
380          * don't bother if a constituant path is claimed
381          * (not by the device mapper driver)
382          */
383         vector_foreach_slot (mpp->paths, pp, i) {
384                 if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
385                         condlog(3, "%s claimed", pp->dev);
386                         return 1;
387                 }
388         }
389
390         /*
391          * properties selectors
392          */
393         select_pgpolicy(mpp);
394         select_selector(mpp);
395         select_features(mpp);
396         select_hwhandler(mpp);
397         select_rr_weight(mpp);
398         select_no_path_retry(mpp);
399
400         /*
401          * apply selected grouping policy to valid paths
402          */
403         switch (mpp->pgpolicy) {
404         case MULTIBUS:
405                 one_group(mpp);
406                 break;
407         case FAILOVER:
408                 one_path_per_group(mpp);
409                 break;
410         case GROUP_BY_SERIAL:
411                 group_by_serial(mpp);
412                 break;
413         case GROUP_BY_PRIO:
414                 group_by_prio(mpp);
415                 break;
416         case GROUP_BY_NODE_NAME:
417                 group_by_node_name(mpp);
418                 break;
419         default:
420                 break;
421         }
422
423         if (mpp->pg == NULL) {
424                 condlog(3, "pgpolicy failed to produce a pg vector");
425                 return 1;
426         }
427
428         /*
429          * ponders each path group and determine highest prio pg
430          * to switch over (default to first)
431          */
432         select_path_group(mpp);
433
434         /*
435          * transform the mp->pg vector of vectors of paths
436          * into a mp->params strings to feed the device-mapper
437          */
438         if (assemble_map(mpp)) {
439                 condlog(3, "problem assembing map");
440                 return 1;
441         }
442         return 0;
443 }
444
445 static int
446 pathcount (struct multipath * mpp, int state)
447 {
448         struct pathgroup *pgp;
449         struct path *pp;
450         int i, j;
451         int count = 0;
452
453         vector_foreach_slot (mpp->pg, pgp, i)
454                 vector_foreach_slot (pgp->paths, pp, j)
455                         if (pp->state == state)
456                                 count++;
457         return count;
458 }
459
460 static void
461 compute_pgid(struct pathgroup * pgp)
462 {
463         struct path * pp;
464         int i;
465
466         vector_foreach_slot (pgp->paths, pp, i)
467                 pgp->id ^= (long)pp;
468 }
469
470 static int
471 pgcmp (struct multipath * mpp, struct multipath * cmpp)
472 {
473         int i, j;
474         struct pathgroup * pgp;
475         struct pathgroup * cpgp;
476         int r = 0;
477
478         vector_foreach_slot (mpp->pg, pgp, i) {
479                 compute_pgid(pgp);
480
481                 vector_foreach_slot (cmpp->pg, cpgp, j) {
482                         if (pgp->id == cpgp->id) {
483                                 r = 0;
484                                 break;
485                         }
486                         r++;
487                 }
488                 if (r)
489                         return r;
490         }
491         return r;
492 }
493
494 static void
495 select_action (struct multipath * mpp, vector curmp)
496 {
497         struct multipath * cmpp;
498
499         cmpp = find_mp(curmp, mpp->alias);
500
501         if (!cmpp) {
502                 cmpp = find_mp_by_wwid(curmp, mpp->wwid);
503
504                 if (cmpp && !conf->dry_run) {
505                         condlog(2, "remove: %s (dup of %s)",
506                                 cmpp->alias, mpp->alias);
507                         dm_flush_map(cmpp->alias, DEFAULT_TARGET);
508                 }
509                 mpp->action = ACT_CREATE;
510                 condlog(3, "set ACT_CREATE: map does not exists");
511                 return;
512         }
513
514         if (!find_mp_by_wwid(curmp, mpp->wwid)) {
515                 condlog(2, "remove: %s (wwid changed)", cmpp->alias);
516                 dm_flush_map(mpp->alias, NULL);
517                 strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
518                 drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
519                 mpp->action = ACT_CREATE;
520                 condlog(3, "set ACT_CREATE: map wwid change");
521                 return;
522         }
523                 
524         if (pathcount(mpp, PATH_UP) == 0) {
525                 mpp->action = ACT_NOTHING;
526                 condlog(3, "set ACT_NOTHING: no usable path");
527                 return;
528         }
529         if (cmpp->size != mpp->size) {
530                 mpp->action = ACT_RELOAD;
531                 condlog(3, "set ACT_RELOAD: size change");
532                 return;
533         }
534         if (strncmp(cmpp->features, mpp->features,
535                     strlen(mpp->features))) {
536                 mpp->action =  ACT_RELOAD;
537                 condlog(3, "set ACT_RELOAD: features change");
538                 return;
539         }
540         if (strncmp(cmpp->hwhandler, mpp->hwhandler,
541                     strlen(mpp->hwhandler))) {
542                 mpp->action = ACT_RELOAD;
543                 condlog(3, "set ACT_RELOAD: hwhandler change");
544                 return;
545         }
546         if (strncmp(cmpp->selector, mpp->selector,
547                     strlen(mpp->selector))) {
548                 mpp->action = ACT_RELOAD;
549                 condlog(3, "set ACT_RELOAD: selector change");
550                 return;
551         }
552         if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
553                 mpp->action = ACT_RELOAD;
554                 condlog(3, "set ACT_RELOAD: number of path group change");
555                 return;
556         }
557         if (pgcmp(mpp, cmpp)) {
558                 mpp->action = ACT_RELOAD;
559                 condlog(3, "set ACT_RELOAD: path group topology change");
560                 return;
561         }
562         if (cmpp->nextpg != mpp->nextpg) {
563                 mpp->action = ACT_SWITCHPG;
564                 condlog(3, "set ACT_SWITCHPG: next path group change");
565                 return;
566         }
567         mpp->action = ACT_NOTHING;
568         condlog(3, "set ACT_NOTHING: map unchanged");
569         return;
570 }
571
572 static int
573 reinstate_paths (struct multipath * mpp)
574 {
575         int i, j;
576         struct pathgroup * pgp;
577         struct path * pp;
578
579         if (!mpp->pg)
580                 return 0;
581
582         vector_foreach_slot (mpp->pg, pgp, i) {
583                 if (!pgp->paths)
584                         continue;
585
586                 vector_foreach_slot (pgp->paths, pp, j) {
587                         if (pp->state != PATH_UP &&
588                             (pgp->status == PGSTATE_DISABLED ||
589                              pgp->status == PGSTATE_ACTIVE))
590                                 continue;
591
592                         if (pp->dmstate == PSTATE_FAILED) {
593                                 if (dm_reinstate(mpp->alias, pp->dev_t))
594                                         condlog(0, "error reinstating %s",
595                                                 pp->dev);
596                         }
597                 }
598         }
599         return 0;
600 }
601
602 int lock_multipath (struct multipath * mpp, int lock)
603 {
604         struct pathgroup * pgp;
605         struct path * pp;
606         int i, j;
607
608         if (!mpp || !mpp->pg)
609                 return 0;
610         
611         vector_foreach_slot (mpp->pg, pgp, i) {
612                 if (!pgp->paths)
613                         continue;
614                 vector_foreach_slot(pgp->paths, pp, j) {
615                         if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
616                             errno == EWOULDBLOCK)
617                                 return 1;
618                         else if (!lock)
619                                 flock(pp->fd, LOCK_UN);
620                 }
621         }
622         return 0;
623 }
624
625 /*
626  * Return value:
627  *  -1: Retry
628  *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
629  *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
630  *   2: Map is already existing.
631  */
632 static int
633 domap (struct multipath * mpp)
634 {
635         int r = 0;
636
637         /*
638          * last chance to quit before touching the devmaps
639          */
640         if (conf->dry_run)
641                 return 0;
642
643         switch (mpp->action) {
644         case ACT_NOTHING:
645                 return 2;
646
647         case ACT_SWITCHPG:
648                 dm_switchgroup(mpp->alias, mpp->nextpg);
649                 /*
650                  * we may have avoided reinstating paths because there where in
651                  * active or disabled PG. Now that the topology has changed,
652                  * retry.
653                  */
654                 reinstate_paths(mpp);
655                 return 2;
656
657         case ACT_CREATE:
658                 if (lock_multipath(mpp, 1)) {
659                         condlog(3, "%s: in use", mpp->alias);
660                         return -1;
661                 }
662
663                 if (dm_map_present(mpp->alias))
664                         break;
665
666                 r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
667                               mpp->params, mpp->size, mpp->wwid);
668                 break;
669
670         case ACT_RELOAD:
671                 r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
672                               mpp->params, mpp->size, NULL) &&
673                      dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
674                 break;
675
676         default:
677                 break;
678         }
679
680         if (r) {
681                 /*
682                  * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
683                  */
684                 dm_switchgroup(mpp->alias, mpp->nextpg);
685                 print_mp(mpp);
686         }
687
688         return r;
689 }
690
691 static int
692 deadmap (struct multipath * mpp)
693 {
694         int i, j;
695         struct pathgroup * pgp;
696         struct path * pp;
697
698         if (!mpp->pg)
699                 return 1;
700
701         vector_foreach_slot (mpp->pg, pgp, i) {
702                 if (!pgp->paths)
703                         continue;
704
705                 vector_foreach_slot (pgp->paths, pp, j)
706                         if (strlen(pp->dev))
707                                 return 0; /* alive */
708         }
709         
710         return 1; /* dead */
711 }
712
713 static int
714 coalesce_paths (vector curmp, vector pathvec)
715 {
716         int r = 1;
717         int k, i;
718         char empty_buff[WWID_SIZE];
719         struct multipath * mpp;
720         struct path * pp1;
721         struct path * pp2;
722
723         memset(empty_buff, 0, WWID_SIZE);
724
725         vector_foreach_slot (pathvec, pp1, k) {
726                 /* skip this path for some reason */
727
728                 /* 1. if path has no unique id or wwid blacklisted */
729                 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
730                     blacklist(conf->blist, pp1->wwid))
731                         continue;
732
733                 /* 2. if path already coalesced */
734                 if (pp1->mpp)
735                         continue;
736
737                 /*
738                  * at this point, we know we really got a new mp
739                  */
740                 mpp = alloc_multipath();
741
742                 if (!mpp)
743                         return 1;
744
745                 mpp->mpe = find_mpe(pp1->wwid);
746                 mpp->hwe = pp1->hwe;
747                 select_alias(mpp);
748
749                 pp1->mpp = mpp;
750                 strcpy(mpp->wwid, pp1->wwid);
751                 mpp->size = pp1->size;
752                 mpp->paths = vector_alloc();
753
754                 if (pp1->priority < 0)
755                         mpp->action = ACT_NOTHING;
756
757                 if (!mpp->paths)
758                         return 1;
759                 
760                 if (store_path(mpp->paths, pp1))
761                         return 1;
762
763                 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
764                         pp2 = VECTOR_SLOT(pathvec, i);
765
766                         if (strcmp(pp1->wwid, pp2->wwid))
767                                 continue;
768                         
769                         pp2->mpp = mpp;
770
771                         if (pp2->size != mpp->size) {
772                                 /*
773                                  * ouch, avoid feeding that to the DM
774                                  */
775                                 condlog(3, "path size mismatch : discard %s",
776                                      mpp->wwid);
777                                 mpp->action = ACT_NOTHING;
778                         }
779                         if (pp2->priority < 0)
780                                 mpp->action = ACT_NOTHING;
781
782                         if (store_path(mpp->paths, pp2))
783                                 return 1;
784                 }
785                 if (setup_map(mpp))
786                         goto next;
787
788                 if (mpp->action == ACT_UNDEF)
789                         select_action(mpp, curmp);
790
791                 r = domap(mpp);
792
793                 if (r < 0)
794                         return r;
795
796                 if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
797                         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
798                                 dm_queue_if_no_path(mpp->alias, 0);
799                         else
800                                 dm_queue_if_no_path(mpp->alias, 1);
801                 }
802
803 next:
804                 drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
805                 free_multipath(mpp, KEEP_PATHS);
806         }
807         /*
808          * Flush maps with only dead paths (ie not in sysfs)
809          * Keep maps with only failed paths
810          */
811         vector_foreach_slot (curmp, mpp, i) {
812                 if (!deadmap(mpp))
813                         continue;
814
815                 if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
816                         condlog(2, "remove: %s (dead) failed!",
817                                 mpp->alias);
818                 else
819                         condlog(2, "remove: %s (dead)", mpp->alias);
820         }
821         return 0;
822 }
823
824 static void
825 usage (char * progname)
826 {
827         fprintf (stderr, VERSION_STRING);
828         fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
829                 progname);
830         fprintf (stderr,
831                 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
832                 "\t\t\t[device]\n" \
833                 "\n" \
834                 "\t-v level\tverbosty level\n" \
835                 "\t   0\t\t\tno output\n" \
836                 "\t   1\t\t\tprint created devmap names only\n" \
837                 "\t   2\t\t\tdefault verbosity\n" \
838                 "\t   3\t\t\tprint debug information\n" \
839                 "\t-d\t\tdry run, do not create or update devmaps\n" \
840                 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
841                 "\t-ll\t\tshow multipath topology (maximum info)\n" \
842                 "\t-F\t\tflush a multipath device map\n" \
843                 "\t-F\t\tflush all multipath device maps\n" \
844                 "\t-p policy\tforce all maps to specified policy :\n" \
845                 "\t   failover\t\t1 path per priority group\n" \
846                 "\t   multibus\t\tall paths in 1 priority group\n" \
847                 "\t   group_by_serial\t1 priority group per serial\n" \
848                 "\t   group_by_prio\t1 priority group per priority lvl\n" \
849                 "\t   group_by_node_name\t1 priority group per target node\n" \
850                 "\n" \
851                 "\tdevice\t\tlimit scope to the device's multipath\n" \
852                 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
853                 "\t\t\tor major:minor or a device map name)\n" \
854                 );
855
856         exit(1);
857 }
858
859 static int
860 update_paths (struct multipath * mpp)
861 {
862         int i, j;
863         struct pathgroup * pgp;
864         struct path * pp;
865
866         if (!mpp->pg)
867                 return 0;
868
869         vector_foreach_slot (mpp->pg, pgp, i) {
870                 if (!pgp->paths)
871                         continue;
872
873                 vector_foreach_slot (pgp->paths, pp, j) {
874                         if (!strlen(pp->dev)) {
875                                 if (devt2devname(pp->dev_t, pp->dev)) {
876                                         /*
877                                          * path is not in sysfs anymore
878                                          */
879                                         pp->state = PATH_DOWN;
880                                         continue;
881                                 }
882                                 pathinfo(pp, conf->hwtable,
883                                          DI_SYSFS | DI_CHECKER | \
884                                          DI_SERIAL | DI_PRIO);
885                                 continue;
886                         }
887                         if (pp->state == PATH_UNCHECKED)
888                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
889
890                         if (!pp->priority)
891                                 pathinfo(pp, conf->hwtable, DI_PRIO);
892                 }
893         }
894         return 0;
895 }
896
897 static int
898 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
899 {
900         int i;
901         struct multipath * mpp;
902
903         if (dm_get_maps(curmp, DEFAULT_TARGET))
904                 return 1;
905
906         vector_foreach_slot (curmp, mpp, i) {
907                 /*
908                  * discard out of scope maps
909                  */
910                 if (mpp->wwid && refwwid &&
911                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
912                         condlog(3, "skip map %s: out of scope", mpp->alias);
913                         free_multipath(mpp, KEEP_PATHS);
914                         vector_del_slot(curmp, i);
915                         i--;
916                         continue;
917                 }
918
919                 condlog(3, "params = %s", mpp->params);
920                 condlog(3, "status = %s", mpp->status);
921
922                 disassemble_map(pathvec, mpp->params, mpp);
923
924                 /*
925                  * disassemble_map() can add new paths to pathvec.
926                  * If not in "fast list mode", we need to fetch information
927                  * about them
928                  */
929                 if (conf->list != 1)
930                         update_paths(mpp);
931
932                 if (conf->list > 1)
933                         select_path_group(mpp);
934
935                 disassemble_status(mpp->status, mpp);
936
937                 if (conf->list)
938                         print_mp(mpp);
939
940                 if (!conf->dry_run)
941                         reinstate_paths(mpp);
942         }
943         return 0;
944 }
945
946
947 /*
948  * Return value:
949  *  -1: Retry
950  *   0: Success
951  *   1: Failure
952  */
953 static int
954 configure (void)
955 {
956         vector curmp = NULL;
957         vector pathvec = NULL;
958         int r = 1;
959         int di_flag = 0;
960         char * refwwid = NULL;
961
962         /*
963          * allocate core vectors to store paths and multipaths
964          */
965         curmp = vector_alloc();
966         pathvec = vector_alloc();
967
968         if (!curmp || !pathvec) {
969                 condlog(0, "can not allocate memory");
970                 goto out;
971         }
972
973         /*
974          * if we have a blacklisted device parameter, exit early
975          */
976         if (conf->dev && blacklist(conf->blist, conf->dev))
977                 goto out;
978         
979         condlog(3, "load path identifiers cache");
980         cache_load(pathvec);
981
982         if (conf->verbosity > 2) {
983                 fprintf(stdout, "#\n# all paths in cache :\n#\n");
984                 print_all_paths(pathvec);
985         }
986
987         /*
988          * get a path list
989          */
990         if (conf->dev)
991                 di_flag = DI_WWID;
992
993         if (conf->list > 1)
994                 /* extended path info '-ll' */
995                 di_flag |= DI_SYSFS | DI_CHECKER;
996         else if (conf->list)
997                 /* minimum path info '-l' */
998                 di_flag |= DI_SYSFS;
999         else
1000                 /* maximum info */
1001                 di_flag = DI_ALL;
1002
1003         if (path_discovery(pathvec, conf, di_flag))
1004                 goto out;
1005
1006         if (conf->verbosity > 2) {
1007                 fprintf(stdout, "#\n# all paths :\n#\n");
1008                 print_all_paths(pathvec);
1009         }
1010
1011         /*
1012          * scope limiting must be translated into a wwid
1013          * failing the translation is fatal (by policy)
1014          */
1015         if (conf->dev) {
1016                 refwwid = get_refwwid(pathvec);
1017
1018                 if (!refwwid) {
1019                         condlog(3, "scope is nul");
1020                         goto out;
1021                 }
1022         }
1023
1024         get_path_layout(&pl, pathvec);
1025
1026         if (get_dm_mpvec(curmp, pathvec, refwwid))
1027                 goto out;
1028
1029         filter_pathvec(pathvec, refwwid);
1030
1031         if (conf->list)
1032                 goto out;
1033
1034         /*
1035          * core logic entry point
1036          */
1037         r = coalesce_paths(curmp, pathvec);
1038
1039 out:
1040         if (refwwid)
1041                 FREE(refwwid);
1042
1043         free_multipathvec(curmp, KEEP_PATHS);
1044         free_pathvec(pathvec, FREE_PATHS);
1045
1046         return r;
1047 }
1048
1049 int
1050 main (int argc, char *argv[])
1051 {
1052         int arg;
1053         extern char *optarg;
1054         extern int optind;
1055         int i, r;
1056
1057         if (getuid() != 0) {
1058                 fprintf(stderr, "need to be root\n");
1059                 exit(1);
1060         }
1061
1062         if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
1063                 exit(1);
1064
1065         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
1066                 condlog(0, "multipath tools need sysfs mounted");
1067                 exit(1);
1068         }
1069         if (load_config(DEFAULT_CONFIGFILE))
1070                 exit(1);
1071
1072         while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
1073                 switch(arg) {
1074                 case 1: printf("optarg : %s\n",optarg);
1075                         break;
1076                 case 'v':
1077                         if (sizeof(optarg) > sizeof(char *) ||
1078                             !isdigit(optarg[0]))
1079                                 usage (argv[0]);
1080
1081                         conf->verbosity = atoi(optarg);
1082                         break;
1083                 case 'd':
1084                         conf->dry_run = 1;
1085                         break;
1086                 case 'f':
1087                         conf->remove = 1;
1088                         break;
1089                 case 'F':
1090                         conf->remove = 2;
1091                         break;
1092                 case 'l':
1093                         conf->list = 1;
1094                         conf->dry_run = 1;
1095
1096                         if (optarg && !strncmp(optarg, "l", 1))
1097                                 conf->list++;
1098
1099                         break;
1100                 case 'M':
1101 #if _DEBUG_
1102                         debug = atoi(optarg);
1103 #endif
1104                         break;
1105                 case 'p':
1106                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
1107                         if (conf->pgpolicy_flag == -1) {
1108                                 printf("'%s' is not a valid policy\n", optarg);
1109                                 usage(argv[0]);
1110                         }                
1111                         break;
1112                 case ':':
1113                         fprintf(stderr, "Missing option arguement\n");
1114                         usage(argv[0]);        
1115                 case '?':
1116                         fprintf(stderr, "Unknown switch: %s\n", optarg);
1117                         usage(argv[0]);
1118                 default:
1119                         usage(argv[0]);
1120                 }
1121         }        
1122         if (optind < argc) {
1123                 conf->dev = MALLOC(FILE_NAME_SIZE);
1124
1125                 if (!conf->dev)
1126                         goto out;
1127
1128                 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
1129
1130                 if (filepresent(conf->dev))
1131                         conf->dev_type = DEV_DEVNODE;
1132                 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
1133                         conf->dev_type = DEV_DEVT;
1134                 else
1135                         conf->dev_type = DEV_DEVMAP;
1136
1137         }
1138
1139         if (conf->remove == FLUSH_ONE) {
1140                 if (conf->dev_type == DEV_DEVMAP)
1141                         dm_flush_map(conf->dev, DEFAULT_TARGET);
1142                 else
1143                         condlog(0, "must provide a map name to remove");
1144
1145                 goto out;
1146         }
1147         else if (conf->remove == FLUSH_ALL) {
1148                 dm_flush_maps(DEFAULT_TARGET);
1149                 goto out;
1150         }
1151         while ((r = configure()) < 0)
1152                 condlog(3, "restart multipath configuration process");
1153         
1154 out:
1155         free_config(conf);
1156         dm_lib_release();
1157         dm_lib_exit();
1158 #ifdef _DEBUG_
1159         dbg_free_final(NULL);
1160 #endif
1161         return r;
1162 }