*
* 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
* 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 <stdio.h>
-#include <stdlib.h>
#include <unistd.h>
-#include <string.h>
+#include <ctype.h>
-#include <parser.h>
+#include <checkers.h>
+#include <prio.h>
#include <vector.h>
#include <memory.h>
#include <libdevmapper.h>
#include <devmapper.h>
-#include <checkers.h>
-#include <path_state.h>
-#include <blacklist.h>
-#include <hwtable.h>
#include <util.h>
#include <defaults.h>
#include <structs.h>
+#include <structs_vec.h>
#include <dmparser.h>
-#include <cache.h>
+#include <sysfs.h>
#include <config.h>
-#include <propsel.h>
+#include <blacklist.h>
#include <discovery.h>
#include <debug.h>
#include <switchgroup.h>
-#include <sysfs/libsysfs.h>
#include <print.h>
+#include <alias.h>
+#include <configure.h>
+#include <pgpolicies.h>
+#include <version.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/resource.h>
-#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;
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;
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);
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;
}