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 <switchgroup.h>
43 #include <sysfs/libsysfs.h>
47 #include "pgpolicies.h"
50 /* for column aligned output */
51 struct path_layout pl;
54 get_refwwid (vector pathvec)
57 char buff[FILE_NAME_SIZE];
60 if (conf->dev_type == DEV_NONE)
63 if (conf->dev_type == DEV_DEVNODE) {
64 condlog(3, "limited scope = %s", conf->dev);
65 basename(conf->dev, buff);
66 pp = find_path_by_dev(pathvec, buff);
74 strncpy(pp->dev, buff, FILE_NAME_SIZE);
76 if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
79 if (store_path(pathvec, pp)) {
85 refwwid = MALLOC(WWID_SIZE);
90 memcpy(refwwid, pp->wwid, WWID_SIZE);
94 if (conf->dev_type == DEV_DEVT) {
95 condlog(3, "limited scope = %s", conf->dev);
96 pp = find_path_by_devt(pathvec, conf->dev);
104 devt2devname(conf->dev, buff);
106 if(safe_sprintf(pp->dev, "%s", buff)) {
107 fprintf(stderr, "pp->dev too small\n");
110 if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
113 if (store_path(pathvec, pp)) {
119 refwwid = MALLOC(WWID_SIZE);
124 memcpy(refwwid, pp->wwid, WWID_SIZE);
127 if (conf->dev_type == DEV_DEVMAP) {
128 condlog(3, "limited scope = %s", conf->dev);
132 refwwid = get_mpe_wwid(conf->dev);
140 refwwid = MALLOC(WWID_SIZE);
145 strncpy(refwwid, conf->dev, WWID_SIZE);
152 print_path (struct path * pp, char * style)
154 char buff[MAX_LINE_LEN];
156 snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
161 print_map (struct multipath * mpp)
163 if (mpp->size && mpp->params)
164 printf("0 %llu %s %s\n",
165 mpp->size, DEFAULT_TARGET, mpp->params);
170 print_all_paths (vector pathvec)
175 vector_foreach_slot (pathvec, pp, i)
176 print_path(pp, PRINT_PATH_LONG);
180 print_mp (struct multipath * mpp)
183 struct path * pp = NULL;
184 struct pathgroup * pgp = NULL;
186 if (mpp->action == ACT_NOTHING || conf->verbosity == 0)
189 if (conf->verbosity > 1) {
190 switch (mpp->action) {
192 printf("%s: ", ACT_RELOAD_STR);
196 printf("%s: ", ACT_CREATE_STR);
200 printf("%s: ", ACT_SWITCHPG_STR);
209 printf("%s", mpp->alias);
211 if (conf->verbosity == 1) {
215 if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
216 printf(" (%s)", mpp->wwid);
220 if (mpp->size < (1 << 11))
221 printf("[size=%llu kB]", mpp->size >> 1);
222 else if (mpp->size < (1 << 21))
223 printf("[size=%llu MB]", mpp->size >> 11);
224 else if (mpp->size < (1 << 31))
225 printf("[size=%llu GB]", mpp->size >> 21);
227 printf("[size=%llu TB]", mpp->size >> 31);
230 printf("[features=\"%s\"]", mpp->features);
233 printf("[hwhandler=\"%s\"]", mpp->hwhandler);
235 fprintf(stdout, "\n");
240 vector_foreach_slot (mpp->pg, pgp, j) {
244 printf("%s ", mpp->selector);
246 /* align to path status info */
247 for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
248 i > strlen(mpp->selector); i--)
253 switch (pgp->status) {
254 case PGSTATE_ENABLED:
257 case PGSTATE_DISABLED:
258 printf("[disabled]");
268 vector_foreach_slot (pgp->paths, pp, i)
269 print_path(pp, PRINT_PATH_INDENT);
275 filter_pathvec (vector pathvec, char * refwwid)
280 if (!refwwid || !strlen(refwwid))
283 vector_foreach_slot (pathvec, pp, i) {
284 if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
285 condlog(3, "skip path %s : out of scope", pp->dev);
287 vector_del_slot(pathvec, i);
295 * Transforms the path group vector into a proper device map string
298 assemble_map (struct multipath * mp)
303 struct pathgroup * pgp;
307 freechar = sizeof(mp->params);
309 shift = snprintf(p, freechar, "%s %s %i %i",
310 mp->features, mp->hwhandler,
311 VECTOR_SIZE(mp->pg), mp->nextpg);
313 if (shift >= freechar) {
314 fprintf(stderr, "mp->params too small\n");
320 vector_foreach_slot (mp->pg, pgp, i) {
321 pgp = VECTOR_SLOT(mp->pg, i);
322 shift = snprintf(p, freechar, " %s %i 1", mp->selector,
323 VECTOR_SIZE(pgp->paths));
324 if (shift >= freechar) {
325 fprintf(stderr, "mp->params too small\n");
331 vector_foreach_slot (pgp->paths, pp, j) {
332 shift = snprintf(p, freechar, " %s %d",
333 pp->dev_t, conf->minio);
334 if (shift >= freechar) {
335 fprintf(stderr, "mp->params too small\n");
343 fprintf(stderr, "mp->params too small\n");
346 snprintf(p, 1, "\n");
348 if (conf->verbosity > 2)
355 setup_map (struct multipath * mpp)
361 * don't bother if devmap size is unknown
363 if (mpp->size <= 0) {
364 condlog(3, "%s devmap size is unknown", mpp->alias);
369 * don't bother if a constituant path is claimed
370 * (not by the device mapper driver)
372 vector_foreach_slot (mpp->paths, pp, i) {
373 if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
374 condlog(3, "%s claimed", pp->dev);
380 * properties selectors
382 select_pgpolicy(mpp);
383 select_selector(mpp);
384 select_features(mpp);
385 select_hwhandler(mpp);
388 * apply selected grouping policy to valid paths
390 switch (mpp->pgpolicy) {
395 one_path_per_group(mpp);
397 case GROUP_BY_SERIAL:
398 group_by_serial(mpp);
403 case GROUP_BY_NODE_NAME:
404 group_by_node_name(mpp);
410 if (mpp->pg == NULL) {
411 condlog(3, "pgpolicy failed to produce a pg vector");
416 * ponders each path group and determine highest prio pg
417 * to switch over (default to first)
419 select_path_group(mpp);
422 * transform the mp->pg vector of vectors of paths
423 * into a mp->params strings to feed the device-mapper
425 if (assemble_map(mpp)) {
426 condlog(3, "problem assembing map");
433 pathcount (struct multipath * mpp, int state)
435 struct pathgroup *pgp;
440 vector_foreach_slot (mpp->pg, pgp, i)
441 vector_foreach_slot (pgp->paths, pp, j)
442 if (pp->state == state)
448 compute_pgid(struct pathgroup * pgp)
453 vector_foreach_slot (pgp->paths, pp, i)
458 pgcmp (struct multipath * mpp, struct multipath * cmpp)
461 struct pathgroup * pgp;
462 struct pathgroup * cpgp;
465 vector_foreach_slot (mpp->pg, pgp, i) {
468 vector_foreach_slot (cmpp->pg, cpgp, j) {
469 if (pgp->id == cpgp->id) {
482 select_action (struct multipath * mpp, vector curmp)
484 struct multipath * cmpp;
486 cmpp = find_mp(curmp, mpp->alias);
489 cmpp = find_mp_by_wwid(curmp, mpp->wwid);
491 if (cmpp && !conf->dry_run) {
492 condlog(2, "remove: %s (dup of %s)",
493 cmpp->alias, mpp->alias);
494 dm_flush_map(cmpp->alias, DEFAULT_TARGET);
496 mpp->action = ACT_CREATE;
499 if (pathcount(mpp, PATH_UP) == 0) {
500 condlog(3, "no good path");
501 mpp->action = ACT_NOTHING;
504 if (cmpp->size != mpp->size) {
505 condlog(3, "size different than current");
506 mpp->action = ACT_RELOAD;
509 if (strncmp(cmpp->features, mpp->features,
510 strlen(mpp->features))) {
511 condlog(3, "features different than current");
512 mpp->action = ACT_RELOAD;
515 if (strncmp(cmpp->hwhandler, mpp->hwhandler,
516 strlen(mpp->hwhandler))) {
517 condlog(3, "hwhandler different than current");
518 mpp->action = ACT_RELOAD;
521 if (strncmp(cmpp->selector, mpp->selector,
522 strlen(mpp->selector))) {
523 condlog(3, "selector different than current");
524 mpp->action = ACT_RELOAD;
527 if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
528 condlog(3, "different number of PG");
529 mpp->action = ACT_RELOAD;
532 if (pgcmp(mpp, cmpp)) {
533 condlog(3, "different path group topology");
534 mpp->action = ACT_RELOAD;
537 if (cmpp->nextpg != mpp->nextpg) {
538 condlog(3, "nextpg different than current");
539 mpp->action = ACT_SWITCHPG;
542 mpp->action = ACT_NOTHING;
547 reinstate_paths (struct multipath * mpp)
550 struct pathgroup * pgp;
553 vector_foreach_slot (mpp->pg, pgp, i) {
554 vector_foreach_slot (pgp->paths, pp, j) {
555 if (pp->state != PATH_UP &&
556 (pgp->status == PGSTATE_DISABLED ||
557 pgp->status == PGSTATE_ACTIVE))
560 if (pp->dmstate == PSTATE_FAILED) {
561 if (dm_reinstate(mpp->alias, pp->dev_t))
562 condlog(0, "error reinstating %s",
571 domap (struct multipath * mpp)
573 int op = ACT_NOTHING;
579 * last chance to quit before touching the devmaps
584 switch (mpp->action) {
589 dm_switchgroup(mpp->alias, mpp->nextpg);
591 * we may have avoided reinstating paths because there where in
592 * active or disabled PG. Now that the topology has changed,
595 reinstate_paths(mpp);
599 op = DM_DEVICE_CREATE;
603 op = DM_DEVICE_RELOAD;
612 * device mapper creation or updating
613 * here we know we'll have garbage on stderr from
614 * libdevmapper. so shut it down temporarily.
616 dm_log_init_verbose(0);
618 r = dm_addmap(op, mpp->alias, DEFAULT_TARGET, mpp->params, mpp->size);
621 dm_simplecmd(DM_DEVICE_REMOVE, mpp->alias);
622 else if (op == DM_DEVICE_RELOAD)
623 dm_simplecmd(DM_DEVICE_RESUME, mpp->alias);
626 * PG order is random, so we need to set the primary one
627 * upon create or reload
629 dm_switchgroup(mpp->alias, mpp->nextpg);
631 dm_log_init_verbose(1);
637 coalesce_paths (vector curmp, vector pathvec)
640 char empty_buff[WWID_SIZE];
641 struct multipath * mpp;
645 memset(empty_buff, 0, WWID_SIZE);
647 vector_foreach_slot (pathvec, pp1, k) {
648 /* skip this path for some reason */
650 /* 1. if path has no unique id or wwid blacklisted */
651 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
652 blacklist(conf->blist, pp1->wwid))
655 /* 2. if path already coalesced */
660 * at this point, we know we really got a new mp
662 mpp = alloc_multipath();
667 mpp->mpe = find_mpe(pp1->wwid);
672 strcpy(mpp->wwid, pp1->wwid);
673 mpp->size = pp1->size;
674 mpp->paths = vector_alloc();
676 if (pp1->priority < 0)
677 mpp->action = ACT_NOTHING;
682 if (store_path(mpp->paths, pp1))
685 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
686 pp2 = VECTOR_SLOT(pathvec, i);
688 if (strcmp(pp1->wwid, pp2->wwid))
693 if (pp2->size != mpp->size) {
695 * ouch, avoid feeding that to the DM
697 condlog(3, "path size mismatch : discard %s",
699 mpp->action = ACT_NOTHING;
701 if (pp2->priority < 0)
702 mpp->action = ACT_NOTHING;
704 if (store_path(mpp->paths, pp2))
707 if (setup_map(mpp)) {
708 free_multipath(mpp, KEEP_PATHS);
711 condlog(3, "action preset to %i", mpp->action);
713 if (mpp->action == ACT_UNDEF)
714 select_action(mpp, curmp);
716 condlog(3, "action set to %i", mpp->action);
719 free_multipath(mpp, KEEP_PATHS);
725 usage (char * progname)
727 fprintf (stderr, VERSION_STRING);
728 fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
731 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
734 "\t-v level\tverbosty level\n" \
735 "\t 0\t\t\tno output\n" \
736 "\t 1\t\t\tprint created devmap names only\n" \
737 "\t 2\t\t\tdefault verbosity\n" \
738 "\t 3\t\t\tprint debug information\n" \
739 "\t-d\t\tdry run, do not create or update devmaps\n" \
740 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
741 "\t-ll\t\tshow multipath topology (maximum info)\n" \
742 "\t-F\t\tflush a multipath device map\n" \
743 "\t-F\t\tflush all multipath device maps\n" \
744 "\t-p policy\tforce all maps to specified policy :\n" \
745 "\t failover\t\t1 path per priority group\n" \
746 "\t multibus\t\tall paths in 1 priority group\n" \
747 "\t group_by_serial\t1 priority group per serial\n" \
748 "\t group_by_prio\t1 priority group per priority lvl\n" \
749 "\t group_by_node_name\t1 priority group per target node\n" \
751 "\tdevice\t\tlimit scope to the device's multipath\n" \
752 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
753 "\t\t\tor major:minor or a device map name)\n" \
760 update_pathvec (vector pathvec)
765 vector_foreach_slot (pathvec, pp, i) {
766 if (pp->dev && pp->dev_t && strlen(pp->dev) == 0) {
767 devt2devname(pp->dev, pp->dev_t);
768 pathinfo(pp, conf->hwtable,
769 DI_SYSFS | DI_CHECKER | DI_SERIAL | DI_PRIO);
771 if (pp->checkfn && pp->state == PATH_UNCHECKED)
772 pp->state = pp->checkfn(pp->fd, NULL, NULL);
778 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
781 struct multipath * mpp;
784 if (dm_get_maps(curmp, DEFAULT_TARGET))
787 vector_foreach_slot (curmp, mpp, i) {
788 wwid = get_mpe_wwid(mpp->alias);
791 /* out of specified scope */
792 if (refwwid && strncmp(wwid, refwwid, WWID_SIZE))
797 condlog(3, "params = %s", mpp->params);
798 condlog(3, "status = %s", mpp->status);
800 /* will set mpp->wwid */
801 disassemble_map(pathvec, mpp->params, mpp);
804 * disassemble_map may have added new paths to pathvec.
805 * If not in "fast list mode", we need to fetch information
809 update_pathvec(pathvec);
811 disassemble_status(mpp->status, mpp);
817 reinstate_paths(mpp);
823 main (int argc, char *argv[])
826 vector pathvec = NULL;
832 char * refwwid = NULL;
835 fprintf(stderr, "need to be root\n");
839 if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
842 if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
843 condlog(0, "multipath tools need sysfs mounted");
846 if (load_config(DEFAULT_CONFIGFILE))
849 while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
851 case 1: printf("optarg : %s\n",optarg);
854 if (sizeof(optarg) > sizeof(char *) ||
858 conf->verbosity = atoi(optarg);
873 if (optarg && !strncmp(optarg, "l", 1))
879 debug = atoi(optarg);
883 conf->pgpolicy_flag = get_pgpolicy_id(optarg);
884 if (conf->pgpolicy_flag == -1) {
885 printf("'%s' is not a valid policy\n", optarg);
890 fprintf(stderr, "Missing option arguement\n");
893 fprintf(stderr, "Unknown switch: %s\n", optarg);
900 conf->dev = MALLOC(FILE_NAME_SIZE);
905 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
907 if (filepresent(conf->dev))
908 conf->dev_type = DEV_DEVNODE;
909 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
910 conf->dev_type = DEV_DEVT;
912 conf->dev_type = DEV_DEVMAP;
916 if (conf->remove == FLUSH_ONE) {
917 if (conf->dev_type == DEV_DEVMAP)
918 dm_flush_map(conf->dev, DEFAULT_TARGET);
920 condlog(0, "must provide a map name to remove");
924 else if (conf->remove == FLUSH_ALL) {
925 dm_flush_maps(DEFAULT_TARGET);
930 * allocate core vectors to store paths and multipaths
932 curmp = vector_alloc();
933 pathvec = vector_alloc();
935 if (!curmp || !pathvec) {
936 condlog(0, "can not allocate memory");
941 * if we have a blacklisted device parameter, exit early
943 if (conf->dev && blacklist(conf->blist, conf->dev))
946 condlog(3, "load path identifiers cache");
949 if (conf->verbosity > 2) {
950 fprintf(stdout, "#\n# all paths in cache :\n#\n");
951 print_all_paths(pathvec);
961 /* extended path info '-ll' */
962 di_flag |= DI_SYSFS | DI_CHECKER;
964 /* minimum path info '-l' */
970 if (path_discovery(pathvec, conf, di_flag) || VECTOR_SIZE(pathvec) == 0)
973 if (conf->verbosity > 2) {
974 fprintf(stdout, "#\n# all paths :\n#\n");
975 print_all_paths(pathvec);
978 refwwid = get_refwwid(pathvec);
979 get_path_layout(&pl, pathvec);
981 if (get_dm_mpvec(curmp, pathvec, refwwid))
984 filter_pathvec(pathvec, refwwid);
990 * core logic entry point
992 coalesce_paths(curmp, pathvec);
998 free_multipathvec(curmp, KEEP_PATHS);
999 free_pathvec(pathvec, FREE_PATHS);
1004 dbg_free_final(NULL);