X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=multipath%2Fmain.c;h=f4559855bbd54d1fea01847876aa04822d15bbee;hb=ace982abd6cfe76fab3f89067db52e9f103972f5;hp=a20aad6425a11ee0ae097721275e224119cbb759;hpb=cd520f7a35e0c946d758b6c54c78f6081484d5c0;p=platform%2Fupstream%2Fmultipath-tools.git diff --git a/multipath/main.c b/multipath/main.c index a20aad6..f455985 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -3,7 +3,7 @@ * * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $ * - * Author: Copyright (C) 2003 Christophe Varoqui + * Author: Christophe Varoqui * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,852 +14,390 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * Copyright (c) 2003, 2004, 2005 Christophe Varoqui + * Copyright (c) 2005 Benjamin Marzinski, Redhat + * Copyright (c) 2005 Kiyoshi Ueda, NEC + * Copyright (c) 2005 Patrick Caulfield, Redhat + * Copyright (c) 2005 Edward Goggin, EMC */ #include -#include #include -#include +#include -#include +#include +#include #include #include #include #include -#include -#include -#include -#include #include #include #include +#include #include -#include +#include #include -#include +#include #include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include -#include "main.h" -#include "pgpolicies.h" -#include "dict.h" - -/* for column aligned output */ -struct path_layout pl; +int logsink; -static char * -get_refwwid (vector pathvec) +static int +filter_pathvec (vector pathvec, char * refwwid) { + int i; struct path * pp; - char buff[FILE_NAME_SIZE]; - char * refwwid; - - if (conf->dev_type == DEV_NONE) - return NULL; - - if (conf->dev_type == DEV_DEVNODE) { - condlog(3, "limited scope = %s", conf->dev); - basename(conf->dev, buff); - pp = find_path_by_dev(pathvec, buff); - - if (!pp) { - pp = alloc_path(); - - if (!pp) - return NULL; - strncpy(pp->dev, buff, FILE_NAME_SIZE); - - if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID)) - return NULL; - - if (store_path(pathvec, pp)) { - free_path(pp); - return NULL; - } - } - - refwwid = MALLOC(WWID_SIZE); - - if (!refwwid) - return NULL; - - memcpy(refwwid, pp->wwid, WWID_SIZE); - return refwwid; - } - - if (conf->dev_type == DEV_DEVT) { - condlog(3, "limited scope = %s", conf->dev); - pp = find_path_by_devt(pathvec, conf->dev); - - if (!pp) { - if (devt2devname(conf->dev, buff)) - return NULL; - - pp = alloc_path(); - - if (!pp) - return NULL; + if (!refwwid || !strlen(refwwid)) + return 0; - if(safe_sprintf(pp->dev, "%s", buff)) { - fprintf(stderr, "pp->dev too small\n"); - exit(1); - } - if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID)) - return NULL; - - if (store_path(pathvec, pp)) { - free_path(pp); - return NULL; - } + vector_foreach_slot (pathvec, pp, i) { + if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) { + condlog(3, "skip path %s : out of scope", pp->dev); + free_path(pp); + vector_del_slot(pathvec, i); + i--; } - - refwwid = MALLOC(WWID_SIZE); - - if (!refwwid) - return NULL; - - memcpy(refwwid, pp->wwid, WWID_SIZE); - return refwwid; } - if (conf->dev_type == DEV_DEVMAP) { - condlog(3, "limited scope = %s", conf->dev); - /* - * may be an alias - */ - refwwid = get_mpe_wwid(conf->dev); - - if (refwwid) - return refwwid; - - /* - * or directly a wwid - */ - refwwid = MALLOC(WWID_SIZE); - - if (!refwwid) - return NULL; - - strncpy(refwwid, conf->dev, WWID_SIZE); - return refwwid; - } - return NULL; + return 0; } static void -print_path (struct path * pp, char * style) +usage (char * progname) { - char buff[MAX_LINE_LEN]; - - snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl); - printf("%s", buff); -} + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); + fprintf (stderr, " %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -t\n", progname); + fprintf (stderr, " %s -h\n", progname); + fprintf (stderr, + "\n" + "Where:\n" + " -h print this usage text\n" \ + " -l show multipath topology (sysfs and DM info)\n" \ + " -ll show multipath topology (maximum info)\n" \ + " -f flush a multipath device map\n" \ + " -F flush all multipath device maps\n" \ + " -d dry run, do not create or update devmaps\n" \ + " -t dump internal hardware table\n" \ + " -r force devmap reload\n" \ + " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ + " -b fil bindings file location\n" \ + " -p pol force all maps to specified path grouping policy :\n" \ + " . failover one path per priority group\n" \ + " . multibus all paths in one priority group\n" \ + " . group_by_serial one priority group per serial\n" \ + " . group_by_prio one priority group per priority lvl\n" \ + " . group_by_node_name one priority group per target node\n" \ + " -v lvl verbosity level\n" \ + " . 0 no output\n" \ + " . 1 print created devmap names only\n" \ + " . 2 default verbosity\n" \ + " . 3 print debug information\n" \ + " dev action limited to:\n" \ + " . multipath named 'dev' (ex: mpath0) or\n" \ + " . multipath whose wwid is 'dev' (ex: 60051..)\n" \ + " . multipath including the path named 'dev' (ex: /dev/sda)\n" \ + " . multipath including the path with maj:min 'dev' (ex: 8:0)\n" \ + ); -static void -print_map (struct multipath * mpp) -{ - if (mpp->size && mpp->params) - printf("0 %llu %s %s\n", - mpp->size, DEFAULT_TARGET, mpp->params); - return; + exit(1); } -static void -print_all_paths (vector pathvec) +static int +update_paths (struct multipath * mpp) { - int i; + int i, j; + struct pathgroup * pgp; struct path * pp; - vector_foreach_slot (pathvec, pp, i) - print_path(pp, PRINT_PATH_LONG); -} - -static void -print_mp (struct multipath * mpp) -{ - int j, i; - struct path * pp = NULL; - struct pathgroup * pgp = NULL; - - if (mpp->action == ACT_NOTHING || conf->verbosity == 0) - return; - - if (conf->verbosity > 1) { - switch (mpp->action) { - case ACT_RELOAD: - printf("%s: ", ACT_RELOAD_STR); - break; - - case ACT_CREATE: - printf("%s: ", ACT_CREATE_STR); - break; - - case ACT_SWITCHPG: - printf("%s: ", ACT_SWITCHPG_STR); - break; - - default: - break; - } - } - - if (mpp->alias) - printf("%s", mpp->alias); - - if (conf->verbosity == 1) { - printf("\n"); - return; - } - if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE)) - printf(" (%s)", mpp->wwid); - - printf("\n"); - - if (mpp->size < (1 << 11)) - printf("[size=%llu kB]", mpp->size >> 1); - else if (mpp->size < (1 << 21)) - printf("[size=%llu MB]", mpp->size >> 11); - else if (mpp->size < (1 << 31)) - printf("[size=%llu GB]", mpp->size >> 21); - else - printf("[size=%llu TB]", mpp->size >> 31); - - if (mpp->features) - printf("[features=\"%s\"]", mpp->features); - - if (mpp->hwhandler) - printf("[hwhandler=\"%s\"]", mpp->hwhandler); + if (!mpp->pg) + return 0; - fprintf(stdout, "\n"); + vector_foreach_slot (mpp->pg, pgp, i) { + if (!pgp->paths) + continue; - if (!mpp->pg) - return; - - vector_foreach_slot (mpp->pg, pgp, j) { - printf("\\_ "); - - if (mpp->selector) { - printf("%s ", mpp->selector); -#if 0 - /* align to path status info */ - for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4; - i > strlen(mpp->selector); i--) - printf(" "); -#endif - } - if (pgp->priority) - printf("[prio=%i]", pgp->priority); + vector_foreach_slot (pgp->paths, pp, j) { + if (!strlen(pp->dev)) { + if (devt2devname(pp->dev, FILE_NAME_SIZE, + pp->dev_t)) { + /* + * path is not in sysfs anymore + */ + pp->state = PATH_DOWN; + continue; + } + pp->mpp = mpp; + pathinfo(pp, conf->hwtable, DI_ALL); + continue; + } + pp->mpp = mpp; + if (pp->state == PATH_UNCHECKED || + pp->state == PATH_WILD) + pathinfo(pp, conf->hwtable, DI_CHECKER); - switch (pgp->status) { - case PGSTATE_ENABLED: - printf("[enabled]"); - break; - case PGSTATE_DISABLED: - printf("[disabled]"); - break; - case PGSTATE_ACTIVE: - printf("[active]"); - break; - default: - break; + if (pp->priority == PRIO_UNDEF) + pathinfo(pp, conf->hwtable, DI_PRIO); } - printf("\n"); - - vector_foreach_slot (pgp->paths, pp, i) - print_path(pp, PRINT_PATH_INDENT); } - printf("\n"); + return 0; } static int -filter_pathvec (vector pathvec, char * refwwid) +get_dm_mpvec (vector curmp, vector pathvec, char * refwwid) { int i; - struct path * pp; + struct multipath * mpp; + char params[PARAMS_SIZE], status[PARAMS_SIZE]; - if (!refwwid || !strlen(refwwid)) - return 0; + if (dm_get_maps(curmp)) + return 1; - vector_foreach_slot (pathvec, pp, i) { - if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) { - condlog(3, "skip path %s : out of scope", pp->dev); - free_path(pp); - vector_del_slot(pathvec, i); + vector_foreach_slot (curmp, mpp, i) { + /* + * discard out of scope maps + */ + if (mpp->wwid && refwwid && + strncmp(mpp->wwid, refwwid, WWID_SIZE)) { + condlog(3, "skip map %s: out of scope", mpp->alias); + free_multipath(mpp, KEEP_PATHS); + vector_del_slot(curmp, i); i--; + continue; } - } - return 0; -} -/* - * Transforms the path group vector into a proper device map string - */ -int -assemble_map (struct multipath * mp) -{ - int i, j; - int shift, freechar; - int minio; - char * p; - struct pathgroup * pgp; - struct path * pp; + dm_get_map(mpp->alias, &mpp->size, params); + condlog(3, "params = %s", params); + dm_get_status(mpp->alias, status); + condlog(3, "status = %s", status); - p = mp->params; - freechar = sizeof(mp->params); - - shift = snprintf(p, freechar, "%s %s %i %i", - mp->features, mp->hwhandler, - VECTOR_SIZE(mp->pg), mp->nextpg); + disassemble_map(pathvec, params, mpp); - if (shift >= freechar) { - fprintf(stderr, "mp->params too small\n"); - return 1; - } - p += shift; - freechar -= shift; - - vector_foreach_slot (mp->pg, pgp, i) { - pgp = VECTOR_SLOT(mp->pg, i); - shift = snprintf(p, freechar, " %s %i 1", mp->selector, - VECTOR_SIZE(pgp->paths)); - if (shift >= freechar) { - fprintf(stderr, "mp->params too small\n"); - return 1; - } - p += shift; - freechar -= shift; + /* + * disassemble_map() can add new paths to pathvec. + * If not in "fast list mode", we need to fetch information + * about them + */ + if (conf->list != 1) + update_paths(mpp); - vector_foreach_slot (pgp->paths, pp, j) { - minio = conf->minio; - - if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority) - minio *= pp->priority; - - shift = snprintf(p, freechar, " %s %d", - pp->dev_t, minio); - if (shift >= freechar) { - fprintf(stderr, "mp->params too small\n"); - return 1; - } - p += shift; - freechar -= shift; - } - } - if (freechar < 1) { - fprintf(stderr, "mp->params too small\n"); - return 1; - } - snprintf(p, 1, "\n"); + if (conf->list > 1) + mpp->bestpg = select_path_group(mpp); - if (conf->verbosity > 2) - print_map(mp); + disassemble_status(status, mpp); + + if (conf->list) + print_multipath_topology(mpp, conf->verbosity); + if (!conf->dry_run) + reinstate_paths(mpp); + } return 0; } + +/* + * Return value: + * -1: Retry + * 0: Success + * 1: Failure + */ static int -setup_map (struct multipath * mpp) +configure (void) { - struct path * pp; - int i; + vector curmp = NULL; + vector pathvec = NULL; + struct vectors vecs; + int r = 1; + int di_flag = 0; + char * refwwid = NULL; + char * dev = NULL; /* - * don't bother if devmap size is unknown + * allocate core vectors to store paths and multipaths */ - if (mpp->size <= 0) { - condlog(3, "%s devmap size is unknown", mpp->alias); - return 1; + curmp = vector_alloc(); + pathvec = vector_alloc(); + + if (!curmp || !pathvec) { + condlog(0, "can not allocate memory"); + goto out; } + vecs.pathvec = pathvec; + vecs.mpvec = curmp; /* - * don't bother if a constituant path is claimed - * (not by the device mapper driver) + * dev is "/dev/" . "sysfs block dev" */ - vector_foreach_slot (mpp->paths, pp, i) { - if (pp->claimed && pp->dmstate == PSTATE_UNDEF) { - condlog(3, "%s claimed", pp->dev); - return 1; - } + if (conf->dev) { + if (!strncmp(conf->dev, "/dev/", 5) && + strlen(conf->dev) > 5) + dev = conf->dev + 5; + else + dev = conf->dev; } /* - * properties selectors + * if we have a blacklisted device parameter, exit early */ - select_pgpolicy(mpp); - select_selector(mpp); - select_features(mpp); - select_hwhandler(mpp); - select_rr_weight(mpp); + if (dev && + (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0)) + goto out; /* - * apply selected grouping policy to valid paths + * scope limiting must be translated into a wwid + * failing the translation is fatal (by policy) */ - switch (mpp->pgpolicy) { - case MULTIBUS: - one_group(mpp); - break; - case FAILOVER: - one_path_per_group(mpp); - break; - case GROUP_BY_SERIAL: - group_by_serial(mpp); - break; - case GROUP_BY_PRIO: - group_by_prio(mpp); - break; - case GROUP_BY_NODE_NAME: - group_by_node_name(mpp); - break; - default: - break; - } + if (conf->dev) { + refwwid = get_refwwid(conf->dev, conf->dev_type, pathvec); - if (mpp->pg == NULL) { - condlog(3, "pgpolicy failed to produce a pg vector"); - return 1; + if (!refwwid) { + condlog(3, "scope is nul"); + goto out; + } + condlog(3, "scope limited to %s", refwwid); + if (filter_wwid(conf->blist_wwid, conf->elist_wwid, + refwwid) > 0) + goto out; } /* - * ponders each path group and determine highest prio pg - * to switch over (default to first) - */ - select_path_group(mpp); - - /* - * transform the mp->pg vector of vectors of paths - * into a mp->params strings to feed the device-mapper + * get a path list */ - if (assemble_map(mpp)) { - condlog(3, "problem assembing map"); - return 1; - } - return 0; -} - -static int -pathcount (struct multipath * mpp, int state) -{ - struct pathgroup *pgp; - struct path *pp; - int i, j; - int count = 0; - - vector_foreach_slot (mpp->pg, pgp, i) - vector_foreach_slot (pgp->paths, pp, j) - if (pp->state == state) - count++; - return count; -} - -static void -compute_pgid(struct pathgroup * pgp) -{ - struct path * pp; - int i; - - vector_foreach_slot (pgp->paths, pp, i) - pgp->id ^= (long)pp; -} - -static int -pgcmp (struct multipath * mpp, struct multipath * cmpp) -{ - int i, j; - struct pathgroup * pgp; - struct pathgroup * cpgp; - int r = 0; - - vector_foreach_slot (mpp->pg, pgp, i) { - compute_pgid(pgp); - - vector_foreach_slot (cmpp->pg, cpgp, j) { - if (pgp->id == cpgp->id) { - r = 0; - break; - } - r++; - } - if (r) - return r; - } - return r; -} + if (conf->dev) + di_flag = DI_WWID; -static void -select_action (struct multipath * mpp, vector curmp) -{ - struct multipath * cmpp; + if (conf->list > 1) + /* extended path info '-ll' */ + di_flag |= DI_SYSFS | DI_CHECKER; + else if (conf->list) + /* minimum path info '-l' */ + di_flag |= DI_SYSFS; + else + /* maximum info */ + di_flag = DI_ALL; - cmpp = find_mp(curmp, mpp->alias); + if (path_discovery(pathvec, conf, di_flag)) + goto out; - if (!cmpp) { - cmpp = find_mp_by_wwid(curmp, mpp->wwid); + if (conf->verbosity > 2) + print_all_paths(pathvec, 1); - if (cmpp && !conf->dry_run) { - condlog(2, "remove: %s (dup of %s)", - cmpp->alias, mpp->alias); - dm_flush_map(cmpp->alias, DEFAULT_TARGET); - } - mpp->action = ACT_CREATE; - return; - } - if (pathcount(mpp, PATH_UP) == 0) { - condlog(3, "no good path"); - mpp->action = ACT_NOTHING; - return; - } - if (cmpp->size != mpp->size) { - condlog(3, "size different than current"); - mpp->action = ACT_RELOAD; - return; - } - if (strncmp(cmpp->features, mpp->features, - strlen(mpp->features))) { - condlog(3, "features different than current"); - mpp->action = ACT_RELOAD; - return; - } - if (strncmp(cmpp->hwhandler, mpp->hwhandler, - strlen(mpp->hwhandler))) { - condlog(3, "hwhandler different than current"); - mpp->action = ACT_RELOAD; - return; - } - if (strncmp(cmpp->selector, mpp->selector, - strlen(mpp->selector))) { - condlog(3, "selector different than current"); - mpp->action = ACT_RELOAD; - return; - } - if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) { - condlog(3, "different number of PG"); - mpp->action = ACT_RELOAD; - return; - } - if (pgcmp(mpp, cmpp)) { - condlog(3, "different path group topology"); - mpp->action = ACT_RELOAD; - return; - } - if (cmpp->nextpg != mpp->nextpg) { - condlog(3, "nextpg different than current"); - mpp->action = ACT_SWITCHPG; - return; - } - mpp->action = ACT_NOTHING; - return; -} + get_path_layout(pathvec, 0); -static int -reinstate_paths (struct multipath * mpp) -{ - int i, j; - struct pathgroup * pgp; - struct path * pp; + if (get_dm_mpvec(curmp, pathvec, refwwid)) + goto out; - vector_foreach_slot (mpp->pg, pgp, i) { - vector_foreach_slot (pgp->paths, pp, j) { - if (pp->state != PATH_UP && - (pgp->status == PGSTATE_DISABLED || - pgp->status == PGSTATE_ACTIVE)) - continue; + filter_pathvec(pathvec, refwwid); - if (pp->dmstate == PSTATE_FAILED) { - if (dm_reinstate(mpp->alias, pp->dev_t)) - condlog(0, "error reinstating %s", - pp->dev); - } - } + if (conf->list) { + r = 0; + goto out; } - return 0; -} - -static int -domap (struct multipath * mpp) -{ - int r = 0; - - print_mp(mpp); /* - * last chance to quit before touching the devmaps + * core logic entry point */ - if (conf->dry_run) - return 0; - - switch (mpp->action) { - case ACT_NOTHING: - return 0; - - case ACT_SWITCHPG: - dm_switchgroup(mpp->alias, mpp->nextpg); - /* - * we may have avoided reinstating paths because there where in - * active or disabled PG. Now that the topology has changed, - * retry. - */ - reinstate_paths(mpp); - return 0; - - case ACT_CREATE: - r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET, - mpp->params, mpp->size, mpp->wwid); - break; + r = coalesce_paths(&vecs, NULL, NULL, conf->force_reload); - case ACT_RELOAD: - r = dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET, - mpp->params, mpp->size, NULL); - break; - - default: - break; - } +out: + if (refwwid) + FREE(refwwid); - if (r) { - /* - * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded - */ - dm_simplecmd(DM_DEVICE_RESUME, mpp->alias); - dm_switchgroup(mpp->alias, mpp->nextpg); - } + free_multipathvec(curmp, KEEP_PATHS); + free_pathvec(pathvec, FREE_PATHS); return r; } static int -coalesce_paths (vector curmp, vector pathvec) +dump_config (void) { - int k, i; - char empty_buff[WWID_SIZE]; - struct multipath * mpp; - struct path * pp1; - struct path * pp2; + char * c; + char * reply; + unsigned int maxlen = 256; + int again = 1; - memset(empty_buff, 0, WWID_SIZE); + reply = MALLOC(maxlen); - vector_foreach_slot (pathvec, pp1, k) { - /* skip this path for some reason */ - - /* 1. if path has no unique id or wwid blacklisted */ - if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 || - blacklist(conf->blist, pp1->wwid)) + while (again) { + if (!reply) + return 1; + c = reply; + c += snprint_defaults(c, reply + maxlen - c); + again = ((c - reply) == maxlen); + if (again) { + reply = REALLOC(reply, maxlen *= 2); continue; - - /* 2. if path already coalesced */ - if (pp1->mpp) + } + c += snprint_blacklist(c, reply + maxlen - c); + again = ((c - reply) == maxlen); + if (again) { + reply = REALLOC(reply, maxlen *= 2); continue; - - /* - * at this point, we know we really got a new mp - */ - mpp = alloc_multipath(); - - if (!mpp) - return 1; - - mpp->mpe = find_mpe(pp1->wwid); - mpp->hwe = pp1->hwe; - select_alias(mpp); - - pp1->mpp = mpp; - strcpy(mpp->wwid, pp1->wwid); - mpp->size = pp1->size; - mpp->paths = vector_alloc(); - - if (pp1->priority < 0) - mpp->action = ACT_NOTHING; - - if (!mpp->paths) - return 1; - - if (store_path(mpp->paths, pp1)) - return 1; - - for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) { - pp2 = VECTOR_SLOT(pathvec, i); - - if (strcmp(pp1->wwid, pp2->wwid)) - continue; - - pp2->mpp = mpp; - - if (pp2->size != mpp->size) { - /* - * ouch, avoid feeding that to the DM - */ - condlog(3, "path size mismatch : discard %s", - mpp->wwid); - mpp->action = ACT_NOTHING; - } - if (pp2->priority < 0) - mpp->action = ACT_NOTHING; - - if (store_path(mpp->paths, pp2)) - return 1; } - if (setup_map(mpp)) { - free_multipath(mpp, KEEP_PATHS); + c += snprint_blacklist_except(c, reply + maxlen - c); + again = ((c - reply) == maxlen); + if (again) { + reply = REALLOC(reply, maxlen *= 2); continue; } - condlog(3, "action preset to %i", mpp->action); - - if (mpp->action == ACT_UNDEF) - select_action(mpp, curmp); - - condlog(3, "action set to %i", mpp->action); - - domap(mpp); - free_multipath(mpp, KEEP_PATHS); - } - return 0; -} - -static void -usage (char * progname) -{ - fprintf (stderr, VERSION_STRING); - fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n", - progname); - fprintf (stderr, - "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \ - "\t\t\t[device]\n" \ - "\n" \ - "\t-v level\tverbosty level\n" \ - "\t 0\t\t\tno output\n" \ - "\t 1\t\t\tprint created devmap names only\n" \ - "\t 2\t\t\tdefault verbosity\n" \ - "\t 3\t\t\tprint debug information\n" \ - "\t-d\t\tdry run, do not create or update devmaps\n" \ - "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \ - "\t-ll\t\tshow multipath topology (maximum info)\n" \ - "\t-F\t\tflush a multipath device map\n" \ - "\t-F\t\tflush all multipath device maps\n" \ - "\t-p policy\tforce all maps to specified policy :\n" \ - "\t failover\t\t1 path per priority group\n" \ - "\t multibus\t\tall paths in 1 priority group\n" \ - "\t group_by_serial\t1 priority group per serial\n" \ - "\t group_by_prio\t1 priority group per priority lvl\n" \ - "\t group_by_node_name\t1 priority group per target node\n" \ - "\n" \ - "\tdevice\t\tlimit scope to the device's multipath\n" \ - "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \ - "\t\t\tor major:minor or a device map name)\n" \ - ); - - exit(1); -} - -static int -update_paths (struct multipath * mpp) -{ - int i, j; - struct pathgroup * pgp; - struct path * pp; - - vector_foreach_slot (mpp->pg, pgp, i) { - vector_foreach_slot (pgp->paths, pp, j) { - if (!strlen(pp->dev)) { - if (devt2devname(pp->dev_t, pp->dev)) { - /* - * path is not in sysfs anymore - */ - pp->state = PATH_DOWN; - continue; - } - pathinfo(pp, conf->hwtable, - DI_SYSFS | DI_CHECKER | \ - DI_SERIAL | DI_PRIO); - continue; - } - if (pp->state == PATH_UNCHECKED) - pathinfo(pp, conf->hwtable, DI_CHECKER); - - if (!pp->priority) - pathinfo(pp, conf->hwtable, DI_PRIO); + c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable); + again = ((c - reply) == maxlen); + if (again) { + reply = REALLOC(reply, maxlen *= 2); + continue; } + c += snprint_mptable(c, reply + maxlen - c, conf->mptable); + again = ((c - reply) == maxlen); + if (again) + reply = REALLOC(reply, maxlen *= 2); } - return 0; -} -static int -get_dm_mpvec (vector curmp, vector pathvec, char * refwwid) -{ - int i; - struct multipath * mpp; - char * wwid; - - if (dm_get_maps(curmp, DEFAULT_TARGET)) - return 1; - - vector_foreach_slot (curmp, mpp, i) { - wwid = get_mpe_wwid(mpp->alias); - - if (wwid) { - /* out of specified scope */ - if (refwwid && strncmp(wwid, refwwid, WWID_SIZE)) - continue; - wwid = NULL; - } - - condlog(3, "params = %s", mpp->params); - condlog(3, "status = %s", mpp->status); - - /* will set mpp->wwid */ - disassemble_map(pathvec, mpp->params, mpp); - - /* - * disassemble_map may have added new paths to pathvec. - * If not in "fast list mode", we need to fetch information - * about them - */ - if (conf->list != 1) - update_paths(mpp); - - if (conf->list > 1) - select_path_group(mpp); - - disassemble_status(mpp->status, mpp); - - if (conf->list) - print_mp(mpp); - - if (!conf->dry_run) - reinstate_paths(mpp); - } + printf("%s", reply); + FREE(reply); return 0; } int main (int argc, char *argv[]) { - vector curmp = NULL; - vector pathvec = NULL; - int i; - int di_flag = 0; int arg; extern char *optarg; extern int optind; - char * refwwid = NULL; + int i, r = 1; if (getuid() != 0) { fprintf(stderr, "need to be root\n"); exit(1); } - if (dm_prereq(DEFAULT_TARGET, 1, 0, 3)) + if (dm_prereq()) exit(1); - if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) { - condlog(0, "multipath tools need sysfs mounted"); - exit(1); - } if (load_config(DEFAULT_CONFIGFILE)) exit(1); - while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) { + if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) { + condlog(0, "multipath tools need sysfs mounted"); + exit(1); + } + while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:Brt")) != EOF ) { switch(arg) { case 1: printf("optarg : %s\n",optarg); break; @@ -870,14 +408,20 @@ main (int argc, char *argv[]) conf->verbosity = atoi(optarg); break; + case 'b': + conf->bindings_file = strdup(optarg); + break; + case 'B': + conf->bindings_read_only = 1; + break; case 'd': conf->dry_run = 1; break; case 'f': - conf->remove = 1; + conf->remove = FLUSH_ONE; break; case 'F': - conf->remove = 2; + conf->remove = FLUSH_ALL; break; case 'l': conf->list = 1; @@ -897,18 +441,26 @@ main (int argc, char *argv[]) if (conf->pgpolicy_flag == -1) { printf("'%s' is not a valid policy\n", optarg); usage(argv[0]); - } + } + break; + case 'r': + conf->force_reload = 1; break; + case 't': + dump_config(); + goto out; + case 'h': + usage(argv[0]); case ':': fprintf(stderr, "Missing option arguement\n"); - usage(argv[0]); + usage(argv[0]); case '?': fprintf(stderr, "Unknown switch: %s\n", optarg); usage(argv[0]); default: usage(argv[0]); } - } + } if (optind < argc) { conf->dev = MALLOC(FILE_NAME_SIZE); @@ -925,108 +477,62 @@ main (int argc, char *argv[]) conf->dev_type = DEV_DEVMAP; } + conf->daemon = 0; - if (conf->remove == FLUSH_ONE) { - if (conf->dev_type == DEV_DEVMAP) - dm_flush_map(conf->dev, DEFAULT_TARGET); - else - condlog(0, "must provide a map name to remove"); + if (conf->max_fds) { + struct rlimit fd_limit; - goto out; - } - else if (conf->remove == FLUSH_ALL) { - dm_flush_maps(DEFAULT_TARGET); - goto out; + fd_limit.rlim_cur = conf->max_fds; + fd_limit.rlim_max = conf->max_fds; + if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0) + condlog(0, "can't set open fds limit to %d : %s\n", + conf->max_fds, strerror(errno)); } - /* - * allocate core vectors to store paths and multipaths - */ - curmp = vector_alloc(); - pathvec = vector_alloc(); - - if (!curmp || !pathvec) { - condlog(0, "can not allocate memory"); - goto out; + if (init_checkers()) { + condlog(0, "failed to initialize checkers"); + exit(1); } - - /* - * if we have a blacklisted device parameter, exit early - */ - if (conf->dev && blacklist(conf->blist, conf->dev)) - goto out; - - condlog(3, "load path identifiers cache"); - cache_load(pathvec); - - if (conf->verbosity > 2) { - fprintf(stdout, "#\n# all paths in cache :\n#\n"); - print_all_paths(pathvec); + if (init_prio()) { + condlog(0, "failed to initialize prioritizers"); + exit(1); } + dm_init(); - /* - * get a path list - */ - if (conf->dev) - di_flag = DI_WWID; - - if (conf->list > 1) - /* extended path info '-ll' */ - di_flag |= DI_SYSFS | DI_CHECKER; - else if (conf->list) - /* minimum path info '-l' */ - di_flag |= DI_SYSFS; - else - /* maximum info */ - di_flag = DI_ALL; + if (conf->remove == FLUSH_ONE) { + if (conf->dev_type == DEV_DEVMAP) + r = dm_flush_map(conf->dev); + else + condlog(0, "must provide a map name to remove"); - if (path_discovery(pathvec, conf, di_flag)) goto out; - - if (conf->verbosity > 2) { - fprintf(stdout, "#\n# all paths :\n#\n"); - print_all_paths(pathvec); - } - - /* - * scope limiting must be translated into a wwid - * failing the translation is fatal (by policy) - */ - if (conf->dev) { - refwwid = get_refwwid(pathvec); - - if (!refwwid) { - condlog(3, "scope is nul"); - goto out; - } } - - get_path_layout(&pl, pathvec); - - if (get_dm_mpvec(curmp, pathvec, refwwid)) + else if (conf->remove == FLUSH_ALL) { + r = dm_flush_maps(); goto out; + } + while ((r = configure()) < 0) + condlog(3, "restart multipath configuration process"); - filter_pathvec(pathvec, refwwid); +out: + udev_wait(conf->cookie); - if (conf->list) - goto out; + sysfs_cleanup(); + dm_lib_release(); + dm_lib_exit(); + cleanup_prio(); + cleanup_checkers(); /* - * core logic entry point + * Freeing config must be done after dm_lib_exit(), because + * the logging function (dm_write_log()), which is called there, + * references the config. */ - coalesce_paths(curmp, pathvec); - -out: - if (refwwid) - FREE(refwwid); - - free_multipathvec(curmp, KEEP_PATHS); - free_pathvec(pathvec, FREE_PATHS); free_config(conf); - dm_lib_release(); - dm_lib_exit(); + conf = NULL; + #ifdef _DEBUG_ dbg_free_final(NULL); #endif - exit(0); + return r; }