2 * Soft: multipath device mapper target autoconfig
4 * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
6 * Author: Copyright (C) 2003 Christophe Varoqui
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.
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.
27 #include <libdevmapper.h>
28 #include <devmapper.h>
30 #include <path_state.h>
31 #include <blacklist.h>
40 #include <discovery.h>
42 #include <sysfs/libsysfs.h>
45 #include "pgpolicies.h"
49 get_refwwid (vector pathvec)
52 char buff[FILE_NAME_SIZE];
55 if (conf->dev_type == DEV_NONE)
58 if (conf->dev_type == DEV_DEVNODE) {
59 condlog(3, "limited scope = %s", conf->dev);
60 basename(conf->dev, buff);
61 pp = find_path_by_dev(pathvec, buff);
69 if (store_path(pathvec, pp)) {
73 strncpy(pp->dev, buff, FILE_NAME_SIZE);
74 if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
78 refwwid = MALLOC(WWID_SIZE);
83 memcpy(refwwid, pp->wwid, WWID_SIZE);
87 if (conf->dev_type == DEV_DEVT) {
88 condlog(3, "limited scope = %s", conf->dev);
89 pp = find_path_by_devt(pathvec, conf->dev);
97 if (store_path(pathvec, pp)) {
101 devt2devname(conf->dev, buff);
103 if(safe_sprintf(pp->dev, "%s", buff)) {
104 fprintf(stderr, "pp->dev too small\n");
107 if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
111 refwwid = MALLOC(WWID_SIZE);
116 memcpy(refwwid, pp->wwid, WWID_SIZE);
119 if (conf->dev_type == DEV_DEVMAP) {
120 condlog(3, "limited scope = %s", conf->dev);
124 refwwid = get_mpe_wwid(conf->dev);
132 refwwid = MALLOC(WWID_SIZE);
137 strncpy(refwwid, conf->dev, WWID_SIZE);
146 #define PRINT_PATH_ALL 0
147 #define PRINT_PATH_SHORT 1
150 print_path (struct path * pp, int style)
152 if (style != PRINT_PATH_SHORT && pp->wwid)
153 printf ("%s ", pp->wwid);
157 if (pp->sg_id.host_no < 0)
160 printf("%i:%i:%i:%i ",
167 printf("%-4s ", pp->dev);
170 printf("%-7s ", pp->dev_t);
185 switch (pp->dmstate) {
198 if (style != PRINT_PATH_SHORT && pp->product_id)
199 printf("[%.16s]", pp->product_id);
201 fprintf(stdout, "\n");
205 print_map (struct multipath * mpp)
207 if (mpp->size && mpp->params)
208 printf("0 %lu %s %s\n",
209 mpp->size, DEFAULT_TARGET, mpp->params);
214 print_all_paths (vector pathvec)
219 vector_foreach_slot (pathvec, pp, i)
220 print_path(pp, PRINT_PATH_ALL);
224 print_mp (struct multipath * mpp)
227 struct path * pp = NULL;
228 struct pathgroup * pgp = NULL;
230 if (mpp->action == ACT_NOTHING || conf->verbosity == 0)
233 if (conf->verbosity > 1) {
234 switch (mpp->action) {
236 printf("%s: ", ACT_RELOAD_STR);
240 printf("%s: ", ACT_CREATE_STR);
244 printf("%s: ", ACT_SWITCHPG_STR);
253 printf("%s", mpp->alias);
255 if (conf->verbosity == 1) {
259 if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
260 printf(" (%s)", mpp->wwid);
264 if (mpp->size < 2000)
265 printf("[size=%lu kB]", mpp->size / 2);
266 else if (mpp->size < (2000 * 1024))
267 printf("[size=%lu MB]", mpp->size / 2 / 1024);
268 else if (mpp->size < (2000 * 1024 * 1024))
269 printf("[size=%lu GB]", mpp->size / 2 / 1024 / 1024);
271 printf("[size=%lu TB]", mpp->size / 2 / 1024 / 1024 / 1024);
274 printf("[features=\"%s\"]", mpp->features);
277 printf("[hwhandler=\"%s\"]", mpp->hwhandler);
279 fprintf(stdout, "\n");
284 vector_foreach_slot (mpp->pg, pgp, j) {
288 printf("%s ", mpp->selector);
290 switch (pgp->status) {
291 case PGSTATE_ENABLED:
294 case PGSTATE_DISABLED:
295 printf("[disabled]");
303 if (mpp->nextpg && mpp->nextpg == j + 1)
308 vector_foreach_slot (pgp->paths, pp, i)
309 print_path(pp, PRINT_PATH_SHORT);
315 filter_pathvec (vector pathvec, char * refwwid)
320 if (!refwwid || !strlen(refwwid))
323 vector_foreach_slot (pathvec, pp, i) {
324 if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
325 condlog(3, "skip path %s : out of scope", pp->dev);
327 vector_del_slot(pathvec, i);
335 * Transforms the path group vector into a proper device map string
338 assemble_map (struct multipath * mp)
343 struct pathgroup * pgp;
347 freechar = sizeof(mp->params);
349 shift = snprintf(p, freechar, "%s %s %i %i",
350 mp->features, mp->hwhandler,
351 VECTOR_SIZE(mp->pg), mp->nextpg);
353 if (shift >= freechar) {
354 fprintf(stderr, "mp->params too small\n");
360 vector_foreach_slot (mp->pg, pgp, i) {
361 pgp = VECTOR_SLOT(mp->pg, i);
362 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
363 VECTOR_SIZE(pgp->paths));
364 if (shift >= freechar) {
365 fprintf(stderr, "mp->params too small\n");
371 vector_foreach_slot (pgp->paths, pp, j) {
372 shift = snprintf(p, freechar, " %s %d",
373 pp->dev_t, conf->minio);
374 if (shift >= freechar) {
375 fprintf(stderr, "mp->params too small\n");
383 fprintf(stderr, "mp->params too small\n");
386 snprintf(p, 1, "\n");
388 if (conf->verbosity > 2)
395 setup_map (struct multipath * mpp)
398 struct pathgroup * pgp;
403 * don't bother if devmap size is unknown
405 if (mpp->size <= 0) {
406 condlog(3, "%s devmap size is unknown", mpp->alias);
411 * don't bother if a constituant path is claimed
412 * FIXME : claimed detection broken, always unclaimed for now
414 vector_foreach_slot (mpp->paths, pp, i) {
416 condlog(3, "%s claimed", pp->dev);
422 * properties selectors
424 select_pgpolicy(mpp);
425 select_selector(mpp);
426 select_features(mpp);
427 select_hwhandler(mpp);
430 * apply selected grouping policy to valid paths
432 switch (mpp->pgpolicy) {
437 one_path_per_group(mpp);
439 case GROUP_BY_SERIAL:
440 group_by_serial(mpp);
445 case GROUP_BY_NODE_NAME:
446 group_by_node_name(mpp);
452 if (mpp->pg == NULL) {
453 condlog(3, "pgpolicy failed to produce a pg vector");
458 * ponders each path group and determine highest prio pg
461 vector_foreach_slot (mpp->pg, pgp, i) {
462 vector_foreach_slot (pgp->paths, pp, j) {
464 if (pp->state != PATH_DOWN)
465 pgp->priority += pp->priority;
467 if (pgp->priority > highest) {
468 highest = pgp->priority;
474 * transform the mp->pg vector of vectors of paths
475 * into a mp->params strings to feed the device-mapper
477 if (assemble_map(mpp)) {
478 condlog(3, "problem assembing map");
485 pathcount (struct multipath * mpp, int state)
487 struct pathgroup *pgp;
492 vector_foreach_slot (mpp->pg, pgp, i)
493 vector_foreach_slot (pgp->paths, pp, j)
494 if (pp->state == state)
500 * detect if a path is in the map we are about to create but not in the
501 * current one (triggers a valid reload)
502 * if a path is in the current map but not in the one we are about to create,
503 * don't reload : it may come back latter so save the reload burden
506 pgcmp2 (struct multipath * mpp, struct multipath * cmpp)
509 struct pathgroup * pgp;
510 struct pathgroup * cpgp;
515 vector_foreach_slot (mpp->pg, pgp, i) {
516 vector_foreach_slot (pgp->paths, pp, j) {
517 vector_foreach_slot (cmpp->pg, cpgp, k) {
518 vector_foreach_slot (cpgp->paths, cpp, l) {
537 select_action (struct multipath * mpp, vector curmp)
539 struct multipath * cmpp;
541 cmpp = find_mp(curmp, mpp->alias);
544 mpp->action = ACT_CREATE;
547 if (pathcount(mpp, PATH_UP) == 0) {
548 condlog(3, "no good path");
549 mpp->action = ACT_NOTHING;
552 if (cmpp->size != mpp->size) {
553 condlog(3, "size different than current");
554 mpp->action = ACT_RELOAD;
557 if (strncmp(cmpp->features, mpp->features,
558 strlen(mpp->features))) {
559 condlog(3, "features different than current");
560 mpp->action = ACT_RELOAD;
563 if (strncmp(cmpp->hwhandler, mpp->hwhandler,
564 strlen(mpp->hwhandler))) {
565 condlog(3, "hwhandler different than current");
566 mpp->action = ACT_RELOAD;
569 if (strncmp(cmpp->selector, mpp->selector,
570 strlen(mpp->selector))) {
571 condlog(3, "selector different than current");
572 mpp->action = ACT_RELOAD;
575 if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
576 condlog(3, "different number of PG");
577 mpp->action = ACT_RELOAD;
580 if (pgcmp2(mpp, cmpp)) {
581 condlog(3, "different path group topology");
582 mpp->action = ACT_RELOAD;
585 if (cmpp->nextpg != mpp->nextpg) {
586 condlog(3, "nextpg different than current");
587 mpp->action = ACT_SWITCHPG;
590 mpp->action = ACT_NOTHING;
595 reinstate_paths (struct multipath * mpp)
598 struct pathgroup * pgp;
601 vector_foreach_slot (mpp->pg, pgp, i) {
602 vector_foreach_slot (pgp->paths, pp, j) {
603 if (pp->state != PATH_UP &&
604 (pgp->status == PGSTATE_DISABLED ||
605 pgp->status == PGSTATE_ACTIVE))
608 if (pp->dmstate == PSTATE_FAILED) {
609 if (dm_reinstate(mpp->alias, pp->dev_t))
610 condlog(0, "error reinstating %s",
619 domap (struct multipath * mpp)
621 int op = ACT_NOTHING;
627 * last chance to quit before touching the devmaps
629 if (conf->dry_run || mpp->action == ACT_NOTHING)
632 if (mpp->action == ACT_SWITCHPG) {
633 dm_switchgroup(mpp->alias, mpp->nextpg);
635 * we may have avoided reinstating paths because there where in
636 * active or disabled PG. Now that the topology has changed,
639 reinstate_paths(mpp);
642 if (mpp->action == ACT_CREATE)
643 op = DM_DEVICE_CREATE;
645 if (mpp->action == ACT_RELOAD)
646 op = DM_DEVICE_RELOAD;
650 * device mapper creation or updating
651 * here we know we'll have garbage on stderr from
652 * libdevmapper. so shut it down temporarily.
654 dm_log_init_verbose(0);
656 r = dm_addmap(op, mpp->alias, DEFAULT_TARGET, mpp->params, mpp->size);
659 dm_simplecmd(DM_DEVICE_REMOVE, mpp->alias);
660 else if (op == DM_DEVICE_RELOAD)
661 dm_simplecmd(DM_DEVICE_RESUME, mpp->alias);
664 * PG order is random, so we need to set the primary one
665 * upon create or reload
667 dm_switchgroup(mpp->alias, mpp->nextpg);
669 dm_log_init_verbose(1);
675 coalesce_paths (vector curmp, vector pathvec)
678 char empty_buff[WWID_SIZE];
679 struct multipath * mpp;
683 memset(empty_buff, 0, WWID_SIZE);
685 vector_foreach_slot (pathvec, pp1, k) {
686 /* skip this path for some reason */
688 /* 1. if path has no unique id or wwid blacklisted */
689 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
690 blacklist(conf->blist, pp1->wwid))
693 /* 2. if path already coalesced */
698 * at this point, we know we really got a new mp
700 mpp = alloc_multipath();
705 mpp->mpe = find_mpe(pp1->wwid);
710 strcpy(mpp->wwid, pp1->wwid);
711 mpp->size = pp1->size;
712 mpp->paths = vector_alloc();
714 if (pp1->priority < 0)
715 mpp->action = ACT_NOTHING;
720 if (store_path(mpp->paths, pp1))
723 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
724 pp2 = VECTOR_SLOT(pathvec, i);
726 if (strcmp(pp1->wwid, pp2->wwid))
731 if (pp2->size != mpp->size) {
733 * ouch, avoid feeding that to the DM
735 condlog(3, "path size mismatch : discard %s",
737 mpp->action = ACT_NOTHING;
739 if (pp2->priority < 0)
740 mpp->action = ACT_NOTHING;
742 if (store_path(mpp->paths, pp2))
745 if (setup_map(mpp)) {
746 free_multipath(mpp, KEEP_PATHS);
749 condlog(3, "action preset to %i", mpp->action);
751 if (mpp->action == ACT_UNDEF)
752 select_action(mpp, curmp);
754 condlog(3, "action set to %i", mpp->action);
757 free_multipath(mpp, KEEP_PATHS);
763 usage (char * progname)
765 fprintf (stderr, VERSION_STRING);
766 fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll]\n",
769 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
772 "\t-v level\tverbosty level\n" \
773 "\t 0\t\t\tno output\n" \
774 "\t 1\t\t\tprint created devmap names only\n" \
775 "\t 2\t\t\tdefault verbosity\n" \
776 "\t 3\t\t\tprint debug information\n" \
777 "\t-d\t\tdry run, do not create or update devmaps\n" \
778 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
779 "\t-ll\t\tshow multipath topology (maximum info)\n" \
780 "\t-F\t\tflush all multipath device maps\n" \
781 "\t-p policy\tforce all maps to specified policy :\n" \
782 "\t failover\t\t1 path per priority group\n" \
783 "\t multibus\t\tall paths in 1 priority group\n" \
784 "\t group_by_serial\t1 priority group per serial\n" \
785 "\t group_by_prio\t1 priority group per priority lvl\n" \
786 "\t group_by_node_name\t1 priority group per target node\n" \
788 "\tdevice\t\tlimit scope to the device's multipath\n" \
789 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
790 "\t\t\tor major:minor or a device map name)\n" \
797 update_pathvec (vector pathvec)
802 vector_foreach_slot (pathvec, pp, i) {
803 if (pp->dev && pp->dev_t && strlen(pp->dev) == 0) {
804 devt2devname(pp->dev, pp->dev_t);
805 pathinfo(pp, conf->hwtable,
806 DI_SYSFS | DI_CHECKER | DI_SERIAL | DI_PRIO);
808 if (pp->checkfn && pp->state == PATH_UNCHECKED)
809 pp->state = pp->checkfn(pp->fd, NULL, NULL);
815 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
818 struct multipath * mpp;
821 if (dm_get_maps(curmp, DEFAULT_TARGET))
824 vector_foreach_slot (curmp, mpp, i) {
825 wwid = get_mpe_wwid(mpp->alias);
828 strncpy(mpp->wwid, wwid, WWID_SIZE);
831 strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
833 if (refwwid && strncmp(mpp->wwid, refwwid, WWID_SIZE))
836 condlog(3, "params = %s", mpp->params);
837 condlog(3, "status = %s", mpp->status);
838 disassemble_map(pathvec, mpp->params, mpp);
841 * disassemble_map may have added new paths to pathvec.
842 * If not in "fast list mode", we need to fetch information
846 update_pathvec(pathvec);
848 disassemble_status(mpp->status, mpp);
854 reinstate_paths(mpp);
860 main (int argc, char *argv[])
863 vector pathvec = NULL;
869 char * refwwid = NULL;
872 fprintf(stderr, "need to be root\n");
876 if (dm_prereq(DEFAULT_TARGET, 1, 0, 3)) {
877 condlog(0, "device mapper prerequisites not met");
880 if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
881 condlog(0, "multipath tools need sysfs mounted");
884 if (load_config(DEFAULT_CONFIGFILE))
887 while ((arg = getopt(argc, argv, ":qdl::Fi:M:v:p:")) != EOF ) {
889 case 1: printf("optarg : %s\n",optarg);
892 if (sizeof(optarg) > sizeof(char *) ||
896 conf->verbosity = atoi(optarg);
902 dm_flush_maps(DEFAULT_TARGET);
909 if (optarg && !strncmp(optarg, "l", 1))
915 debug = atoi(optarg);
919 conf->pgpolicy_flag = get_pgpolicy_id(optarg);
920 if (conf->pgpolicy_flag == -1) {
921 printf("'%s' is not a valid policy\n", optarg);
926 fprintf(stderr, "Missing option arguement\n");
929 fprintf(stderr, "Unknown switch: %s\n", optarg);
936 conf->dev = MALLOC(FILE_NAME_SIZE);
941 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
943 if (filepresent(conf->dev))
944 conf->dev_type = DEV_DEVNODE;
945 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
946 conf->dev_type = DEV_DEVT;
948 conf->dev_type = DEV_DEVMAP;
953 * allocate core vectors to store paths and multipaths
955 curmp = vector_alloc();
956 pathvec = vector_alloc();
958 if (!curmp || !pathvec) {
959 condlog(0, "can not allocate memory");
964 * if we have a blacklisted device parameter, exit early
966 if (conf->dev && blacklist(conf->blist, conf->dev))
969 if (!cache_cold(CACHE_EXPIRE)) {
970 condlog(3, "load path identifiers cache");
978 /* extended path info '-ll' */
979 di_flag = DI_SYSFS | DI_CHECKER;
981 /* minimum path info '-l' */
987 if (path_discovery(pathvec, conf, di_flag) || VECTOR_SIZE(pathvec) == 0)
990 if (conf->verbosity > 2) {
991 fprintf(stdout, "#\n# all paths :\n#\n");
992 print_all_paths(pathvec);
995 refwwid = get_refwwid(pathvec);
997 if (get_dm_mpvec(curmp, pathvec, refwwid))
1000 cache_dump(pathvec);
1001 filter_pathvec(pathvec, refwwid);
1007 * core logic entry point
1009 coalesce_paths(curmp, pathvec);
1015 free_multipathvec(curmp, KEEP_PATHS);
1016 free_pathvec(pathvec, FREE_PATHS);
1019 dbg_free_final(NULL);