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.
29 #include <libdevmapper.h>
30 #include <devmapper.h>
32 #include <path_state.h>
33 #include <blacklist.h>
42 #include <discovery.h>
44 #include <switchgroup.h>
45 #include <sysfs/libsysfs.h>
49 #include "pgpolicies.h"
52 /* for column aligned output */
53 struct path_layout pl;
56 get_refwwid (vector pathvec)
59 char buff[FILE_NAME_SIZE];
62 if (conf->dev_type == DEV_NONE)
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);
76 strncpy(pp->dev, buff, FILE_NAME_SIZE);
78 if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
81 if (store_path(pathvec, pp)) {
87 refwwid = MALLOC(WWID_SIZE);
92 memcpy(refwwid, pp->wwid, WWID_SIZE);
96 if (conf->dev_type == DEV_DEVT) {
97 condlog(3, "limited scope = %s", conf->dev);
98 pp = find_path_by_devt(pathvec, conf->dev);
101 if (devt2devname(conf->dev, buff))
109 if(safe_sprintf(pp->dev, "%s", buff)) {
110 fprintf(stderr, "pp->dev too small\n");
113 if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
116 if (store_path(pathvec, pp)) {
122 refwwid = MALLOC(WWID_SIZE);
127 memcpy(refwwid, pp->wwid, WWID_SIZE);
130 if (conf->dev_type == DEV_DEVMAP) {
131 condlog(3, "limited scope = %s", conf->dev);
135 refwwid = get_mpe_wwid(conf->dev);
138 return STRDUP(refwwid);
143 refwwid = MALLOC(WWID_SIZE);
148 strncpy(refwwid, conf->dev, WWID_SIZE);
155 print_path (struct path * pp, char * style)
157 char buff[MAX_LINE_LEN];
159 snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
164 print_map (struct multipath * mpp)
166 if (mpp->size && mpp->params)
167 printf("0 %llu %s %s\n",
168 mpp->size, DEFAULT_TARGET, mpp->params);
173 print_all_paths (vector pathvec)
178 vector_foreach_slot (pathvec, pp, i)
179 print_path(pp, PRINT_PATH_LONG);
183 print_mp (struct multipath * mpp)
186 struct path * pp = NULL;
187 struct pathgroup * pgp = NULL;
189 if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
192 if (conf->verbosity > 1) {
193 switch (mpp->action) {
195 printf("%s: ", ACT_RELOAD_STR);
199 printf("%s: ", ACT_CREATE_STR);
203 printf("%s: ", ACT_SWITCHPG_STR);
212 printf("%s", mpp->alias);
214 if (conf->verbosity == 1) {
218 if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
219 printf(" (%s)", mpp->wwid);
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);
230 printf("[size=%llu TB]", mpp->size >> 31);
233 printf("[features=\"%s\"]", mpp->features);
236 printf("[hwhandler=\"%s\"]", mpp->hwhandler);
238 fprintf(stdout, "\n");
243 vector_foreach_slot (mpp->pg, pgp, j) {
247 printf("%s ", mpp->selector);
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--)
256 printf("[prio=%i]", pgp->priority);
258 switch (pgp->status) {
259 case PGSTATE_ENABLED:
262 case PGSTATE_DISABLED:
263 printf("[disabled]");
273 vector_foreach_slot (pgp->paths, pp, i)
274 print_path(pp, PRINT_PATH_INDENT);
280 filter_pathvec (vector pathvec, char * refwwid)
285 if (!refwwid || !strlen(refwwid))
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);
292 vector_del_slot(pathvec, i);
300 * Transforms the path group vector into a proper device map string
303 assemble_map (struct multipath * mp)
309 struct pathgroup * pgp;
313 freechar = sizeof(mp->params);
315 shift = snprintf(p, freechar, "%s %s %i %i",
316 mp->features, mp->hwhandler,
317 VECTOR_SIZE(mp->pg), mp->nextpg);
319 if (shift >= freechar) {
320 fprintf(stderr, "mp->params too small\n");
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");
337 vector_foreach_slot (pgp->paths, pp, j) {
340 if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
341 minio *= pp->priority;
343 shift = snprintf(p, freechar, " %s %d",
345 if (shift >= freechar) {
346 fprintf(stderr, "mp->params too small\n");
354 fprintf(stderr, "mp->params too small\n");
357 snprintf(p, 1, "\n");
359 if (conf->verbosity > 2)
366 setup_map (struct multipath * mpp)
369 * don't bother if devmap size is unknown
371 if (mpp->size <= 0) {
372 condlog(3, "%s devmap size is unknown", mpp->alias);
377 * properties selectors
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);
387 * apply selected grouping policy to valid paths
389 switch (mpp->pgpolicy) {
394 one_path_per_group(mpp);
396 case GROUP_BY_SERIAL:
397 group_by_serial(mpp);
402 case GROUP_BY_NODE_NAME:
403 group_by_node_name(mpp);
409 if (mpp->pg == NULL) {
410 condlog(3, "pgpolicy failed to produce a pg vector");
415 * ponders each path group and determine highest prio pg
416 * to switch over (default to first)
418 select_path_group(mpp);
421 * transform the mp->pg vector of vectors of paths
422 * into a mp->params strings to feed the device-mapper
424 if (assemble_map(mpp)) {
425 condlog(3, "problem assembing map");
432 pathcount (struct multipath * mpp, int state)
434 struct pathgroup *pgp;
439 vector_foreach_slot (mpp->pg, pgp, i)
440 vector_foreach_slot (pgp->paths, pp, j)
441 if (pp->state == state)
447 compute_pgid(struct pathgroup * pgp)
452 vector_foreach_slot (pgp->paths, pp, i)
457 pgcmp (struct multipath * mpp, struct multipath * cmpp)
460 struct pathgroup * pgp;
461 struct pathgroup * cpgp;
464 vector_foreach_slot (mpp->pg, pgp, i) {
467 vector_foreach_slot (cmpp->pg, cpgp, j) {
468 if (pgp->id == cpgp->id) {
481 select_action (struct multipath * mpp, vector curmp)
483 struct multipath * cmpp;
485 cmpp = find_mp(curmp, mpp->alias);
488 cmpp = find_mp_by_wwid(curmp, mpp->wwid);
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);
495 mpp->action = ACT_CREATE;
496 condlog(3, "set ACT_CREATE: map does not exists");
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");
510 if (pathcount(mpp, PATH_UP) == 0) {
511 mpp->action = ACT_NOTHING;
512 condlog(3, "set ACT_NOTHING: no usable path");
515 if (cmpp->size != mpp->size) {
516 mpp->action = ACT_RELOAD;
517 condlog(3, "set ACT_RELOAD: size change");
520 if (strncmp(cmpp->features, mpp->features,
521 strlen(mpp->features))) {
522 mpp->action = ACT_RELOAD;
523 condlog(3, "set ACT_RELOAD: features change");
526 if (strncmp(cmpp->hwhandler, mpp->hwhandler,
527 strlen(mpp->hwhandler))) {
528 mpp->action = ACT_RELOAD;
529 condlog(3, "set ACT_RELOAD: hwhandler change");
532 if (strncmp(cmpp->selector, mpp->selector,
533 strlen(mpp->selector))) {
534 mpp->action = ACT_RELOAD;
535 condlog(3, "set ACT_RELOAD: selector change");
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");
543 if (pgcmp(mpp, cmpp)) {
544 mpp->action = ACT_RELOAD;
545 condlog(3, "set ACT_RELOAD: path group topology change");
548 if (cmpp->nextpg != mpp->nextpg) {
549 mpp->action = ACT_SWITCHPG;
550 condlog(3, "set ACT_SWITCHPG: next path group change");
553 mpp->action = ACT_NOTHING;
554 condlog(3, "set ACT_NOTHING: map unchanged");
559 reinstate_paths (struct multipath * mpp)
562 struct pathgroup * pgp;
568 vector_foreach_slot (mpp->pg, pgp, i) {
572 vector_foreach_slot (pgp->paths, pp, j) {
573 if (pp->state != PATH_UP &&
574 (pgp->status == PGSTATE_DISABLED ||
575 pgp->status == PGSTATE_ACTIVE))
578 if (pp->dmstate == PSTATE_FAILED) {
579 if (dm_reinstate(mpp->alias, pp->dev_t))
580 condlog(0, "error reinstating %s",
588 int lock_multipath (struct multipath * mpp, int lock)
590 struct pathgroup * pgp;
594 if (!mpp || !mpp->pg)
597 vector_foreach_slot (mpp->pg, pgp, i) {
600 vector_foreach_slot(pgp->paths, pp, j) {
601 if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
602 errno == EWOULDBLOCK)
605 flock(pp->fd, LOCK_UN);
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.
619 domap (struct multipath * mpp)
624 * last chance to quit before touching the devmaps
629 switch (mpp->action) {
634 dm_switchgroup(mpp->alias, mpp->nextpg);
636 * we may have avoided reinstating paths because there where in
637 * active or disabled PG. Now that the topology has changed,
640 reinstate_paths(mpp);
644 if (lock_multipath(mpp, 1)) {
645 condlog(3, "%s: in use", mpp->alias);
650 if (dm_map_present(mpp->alias))
653 r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
654 mpp->params, mpp->size, mpp->wwid);
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.
661 if (!r && dm_map_present(mpp->alias)) {
662 condlog(3, "%s: failed to load map "
663 "(a path might be in use)",
665 dm_flush_map(mpp->alias, NULL);
668 lock_multipath(mpp, 0);
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));
684 * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
686 dm_switchgroup(mpp->alias, mpp->nextpg);
694 deadmap (struct multipath * mpp)
697 struct pathgroup * pgp;
703 vector_foreach_slot (mpp->pg, pgp, i) {
707 vector_foreach_slot (pgp->paths, pp, j)
709 return 0; /* alive */
716 coalesce_paths (vector curmp, vector pathvec)
720 char empty_buff[WWID_SIZE];
721 struct multipath * mpp;
725 memset(empty_buff, 0, WWID_SIZE);
727 vector_foreach_slot (pathvec, pp1, k) {
728 /* skip this path for some reason */
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))
735 /* 2. if path already coalesced */
740 * at this point, we know we really got a new mp
742 mpp = alloc_multipath();
747 mpp->mpe = find_mpe(pp1->wwid);
752 strcpy(mpp->wwid, pp1->wwid);
753 mpp->size = pp1->size;
754 mpp->paths = vector_alloc();
756 if (pp1->priority < 0)
757 mpp->action = ACT_NOTHING;
762 if (store_path(mpp->paths, pp1))
765 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
766 pp2 = VECTOR_SLOT(pathvec, i);
768 if (strcmp(pp1->wwid, pp2->wwid))
773 if (pp2->size != mpp->size) {
775 * ouch, avoid feeding that to the DM
777 condlog(3, "path size mismatch : discard %s",
779 mpp->action = ACT_NOTHING;
781 if (pp2->priority < 0)
782 mpp->action = ACT_NOTHING;
784 if (store_path(mpp->paths, pp2))
790 if (mpp->action == ACT_UNDEF)
791 select_action(mpp, curmp);
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);
802 dm_queue_if_no_path(mpp->alias, 1);
806 drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
807 free_multipath(mpp, KEEP_PATHS);
810 * Flush maps with only dead paths (ie not in sysfs)
811 * Keep maps with only failed paths
813 vector_foreach_slot (curmp, mpp, i) {
817 if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
818 condlog(2, "remove: %s (dead) failed!",
821 condlog(2, "remove: %s (dead)", mpp->alias);
827 usage (char * progname)
829 fprintf (stderr, VERSION_STRING);
830 fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
833 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\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" \
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" \
862 update_paths (struct multipath * mpp)
865 struct pathgroup * pgp;
871 vector_foreach_slot (mpp->pg, pgp, i) {
875 vector_foreach_slot (pgp->paths, pp, j) {
876 if (!strlen(pp->dev)) {
877 if (devt2devname(pp->dev_t, pp->dev)) {
879 * path is not in sysfs anymore
881 pp->state = PATH_DOWN;
884 pathinfo(pp, conf->hwtable,
885 DI_SYSFS | DI_CHECKER | \
886 DI_SERIAL | DI_PRIO);
889 if (pp->state == PATH_UNCHECKED)
890 pathinfo(pp, conf->hwtable, DI_CHECKER);
893 pathinfo(pp, conf->hwtable, DI_PRIO);
900 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
903 struct multipath * mpp;
905 if (dm_get_maps(curmp, DEFAULT_TARGET))
908 vector_foreach_slot (curmp, mpp, i) {
910 * discard out of scope maps
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);
921 condlog(3, "params = %s", mpp->params);
922 condlog(3, "status = %s", mpp->status);
924 disassemble_map(pathvec, mpp->params, mpp);
927 * disassemble_map() can add new paths to pathvec.
928 * If not in "fast list mode", we need to fetch information
935 select_path_group(mpp);
937 disassemble_status(mpp->status, mpp);
943 reinstate_paths(mpp);
959 vector pathvec = NULL;
962 char * refwwid = NULL;
965 * allocate core vectors to store paths and multipaths
967 curmp = vector_alloc();
968 pathvec = vector_alloc();
970 if (!curmp || !pathvec) {
971 condlog(0, "can not allocate memory");
976 * if we have a blacklisted device parameter, exit early
978 if (conf->dev && blacklist(conf->blist, conf->dev))
981 condlog(3, "load path identifiers cache");
984 if (conf->verbosity > 2) {
985 fprintf(stdout, "#\n# all paths in cache :\n#\n");
986 print_all_paths(pathvec);
996 /* extended path info '-ll' */
997 di_flag |= DI_SYSFS | DI_CHECKER;
999 /* minimum path info '-l' */
1000 di_flag |= DI_SYSFS;
1005 if (path_discovery(pathvec, conf, di_flag))
1008 if (conf->verbosity > 2) {
1009 fprintf(stdout, "#\n# all paths :\n#\n");
1010 print_all_paths(pathvec);
1014 * scope limiting must be translated into a wwid
1015 * failing the translation is fatal (by policy)
1018 refwwid = get_refwwid(pathvec);
1021 condlog(3, "scope is nul");
1026 get_path_layout(&pl, pathvec);
1028 if (get_dm_mpvec(curmp, pathvec, refwwid))
1031 filter_pathvec(pathvec, refwwid);
1037 * core logic entry point
1039 r = coalesce_paths(curmp, pathvec);
1045 free_multipathvec(curmp, KEEP_PATHS);
1046 free_pathvec(pathvec, FREE_PATHS);
1052 main (int argc, char *argv[])
1055 extern char *optarg;
1059 if (getuid() != 0) {
1060 fprintf(stderr, "need to be root\n");
1064 if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
1067 if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
1068 condlog(0, "multipath tools need sysfs mounted");
1071 if (load_config(DEFAULT_CONFIGFILE))
1074 while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
1076 case 1: printf("optarg : %s\n",optarg);
1079 if (sizeof(optarg) > sizeof(char *) ||
1080 !isdigit(optarg[0]))
1083 conf->verbosity = atoi(optarg);
1089 conf->remove = FLUSH_ONE;
1092 conf->remove = FLUSH_ALL;
1098 if (optarg && !strncmp(optarg, "l", 1))
1104 debug = atoi(optarg);
1108 conf->pgpolicy_flag = get_pgpolicy_id(optarg);
1109 if (conf->pgpolicy_flag == -1) {
1110 printf("'%s' is not a valid policy\n", optarg);
1115 fprintf(stderr, "Missing option arguement\n");
1118 fprintf(stderr, "Unknown switch: %s\n", optarg);
1124 if (optind < argc) {
1125 conf->dev = MALLOC(FILE_NAME_SIZE);
1130 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
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;
1137 conf->dev_type = DEV_DEVMAP;
1141 if (conf->remove == FLUSH_ONE) {
1142 if (conf->dev_type == DEV_DEVMAP)
1143 dm_flush_map(conf->dev, DEFAULT_TARGET);
1145 condlog(0, "must provide a map name to remove");
1149 else if (conf->remove == FLUSH_ALL) {
1150 dm_flush_maps(DEFAULT_TARGET);
1153 while ((r = configure()) < 0)
1154 condlog(3, "restart multipath configuration process");
1161 dbg_free_final(NULL);