From 8e4ddefdfdb87c15e9ba218c11098d8744c34920 Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Thu, 17 Nov 2005 16:50:43 +0100 Subject: [PATCH] [libmultipath] move coalesce_path() to libmultipath/configure.c and consequences ... - coalesce_paths() and all functions used only in this code path are folded into configure.c - move print_*() to libmultipath/print.c, although they are only needed for multipath(8) (in their current form) - declare {map,path}_layout as globals in print.c so we can now remove them from the parameter list in all print.c-exported functions Now we can use coalesce_path() from multipathd. --- libmultipath/Makefile | 2 +- libmultipath/configure.c | 481 +++++++++++++++++++++++++++++++++++++ libmultipath/configure.h | 21 ++ libmultipath/print.c | 266 ++++++++++++++++----- libmultipath/print.h | 17 +- multipath/main.c | 608 +---------------------------------------------- multipath/main.h | 19 -- multipathd/main.c | 14 +- 8 files changed, 730 insertions(+), 698 deletions(-) create mode 100644 libmultipath/configure.c create mode 100644 libmultipath/configure.h diff --git a/libmultipath/Makefile b/libmultipath/Makefile index 0e2bfa3..441aad1 100644 --- a/libmultipath/Makefile +++ b/libmultipath/Makefile @@ -11,7 +11,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \ structs.o cache.o discovery.o propsel.o dict.o \ pgpolicies.o debug.o regex.o defaults.o uevent.o \ switchgroup.o uxsock.o print.o alias.o log_pthread.o \ - log.o + log.o configure.o CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes diff --git a/libmultipath/configure.c b/libmultipath/configure.c new file mode 100644 index 0000000..16d6472 --- /dev/null +++ b/libmultipath/configure.c @@ -0,0 +1,481 @@ +/* + * 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 "../libcheckers/path_state.h" +#include "vector.h" +#include "memory.h" +#include "devmapper.h" +#include "blacklist.h" +#include "defaults.h" +#include "structs.h" +#include "dmparser.h" +#include "config.h" +#include "propsel.h" +#include "discovery.h" +#include "debug.h" +#include "switchgroup.h" +#include "print.h" +#include "configure.h" +#include "pgpolicies.h" +#include "dict.h" + +static int +setup_map (struct multipath * mpp) +{ + struct pathgroup * pgp; + int i; + + /* + * don't bother if devmap size is unknown + */ + if (mpp->size <= 0) { + condlog(3, "%s: devmap size is unknown", mpp->alias); + return 1; + } + + /* + * properties selectors + */ + select_pgfailback(mpp); + select_pgpolicy(mpp); + select_selector(mpp); + select_features(mpp); + select_hwhandler(mpp); + select_rr_weight(mpp); + select_minio(mpp); + select_no_path_retry(mpp); + + /* + * assign paths to path groups -- start with no groups and all paths + * in mpp->paths + */ + if (mpp->pg) { + vector_foreach_slot (mpp->pg, pgp, i) + free_pathgroup(pgp, KEEP_PATHS); + + vector_free(mpp->pg); + mpp->pg = NULL; + } + if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp)) + return 1; + + mpp->nr_active = pathcount(mpp, PATH_UP); + + /* + * ponders each path group and determine highest prio pg + * to switch over (default to first) + */ + mpp->bestpg = select_path_group(mpp); + + /* + * transform the mp->pg vector of vectors of paths + * into a mp->params strings to feed the device-mapper + */ + if (assemble_map(mpp)) { + condlog(0, "%s: problem assembing map", mpp->alias); + return 1; + } + return 0; +} + +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; +} + +static void +select_action (struct multipath * mpp, vector curmp) +{ + struct multipath * cmpp; + + cmpp = find_mp_by_alias(curmp, mpp->alias); + + if (!cmpp) { + cmpp = find_mp_by_wwid(curmp, mpp->wwid); + + 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; + condlog(3, "set ACT_CREATE: map does not exists"); + return; + } + + if (!find_mp_by_wwid(curmp, mpp->wwid)) { + condlog(2, "remove: %s (wwid changed)", cmpp->alias); + dm_flush_map(mpp->alias, NULL); + strncat(cmpp->wwid, mpp->wwid, WWID_SIZE); + drop_multipath(curmp, cmpp->wwid, KEEP_PATHS); + mpp->action = ACT_CREATE; + condlog(3, "set ACT_CREATE: map wwid change"); + return; + } + + if (pathcount(mpp, PATH_UP) == 0) { + mpp->action = ACT_NOTHING; + condlog(3, "set ACT_NOTHING: no usable path"); + return; + } + if (cmpp->size != mpp->size) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: size change"); + return; + } + if (!mpp->no_path_retry && /* let features be handled by the daemon */ + strncmp(cmpp->features, mpp->features, strlen(mpp->features))) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: features change"); + return; + } + if (strncmp(cmpp->hwhandler, mpp->hwhandler, + strlen(mpp->hwhandler))) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: hwhandler change"); + return; + } + if (strncmp(cmpp->selector, mpp->selector, + strlen(mpp->selector))) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: selector change"); + return; + } + if (cmpp->minio != mpp->minio) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: minio change (%u->%u)", + cmpp->minio, mpp->minio); + return; + } + if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: number of path group change"); + return; + } + if (pgcmp(mpp, cmpp)) { + mpp->action = ACT_RELOAD; + condlog(3, "set ACT_RELOAD: path group topology change"); + return; + } + if (cmpp->nextpg != mpp->bestpg) { + mpp->action = ACT_SWITCHPG; + condlog(3, "set ACT_SWITCHPG: next path group change"); + return; + } + mpp->action = ACT_NOTHING; + condlog(3, "set ACT_NOTHING: map unchanged"); + return; +} + +extern int +reinstate_paths (struct multipath * mpp) +{ + int i, j; + struct pathgroup * pgp; + struct path * pp; + + if (!mpp->pg) + return 0; + + vector_foreach_slot (mpp->pg, pgp, i) { + if (!pgp->paths) + continue; + + vector_foreach_slot (pgp->paths, pp, j) { + if (pp->state != PATH_UP && + (pgp->status == PGSTATE_DISABLED || + pgp->status == PGSTATE_ACTIVE)) + continue; + + if (pp->dmstate == PSTATE_FAILED) { + if (dm_reinstate_path(mpp->alias, pp->dev_t)) + condlog(0, "error reinstating %s", + pp->dev); + } + } + } + return 0; +} + +static int +lock_multipath (struct multipath * mpp, int lock) +{ + struct pathgroup * pgp; + struct path * pp; + int i, j; + + if (!mpp || !mpp->pg) + return 0; + + vector_foreach_slot (mpp->pg, pgp, i) { + if (!pgp->paths) + continue; + vector_foreach_slot(pgp->paths, pp, j) { + if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) && + errno == EWOULDBLOCK) + return 1; + else if (!lock) + flock(pp->fd, LOCK_UN); + } + } + return 0; +} + +/* + * Return value: + * -1: Retry + * 0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode. + * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded. + * 2: Map is already existing. + */ +static int +domap (struct multipath * mpp) +{ + int r = 0; + + /* + * last chance to quit before touching the devmaps + */ + if (conf->dry_run) { + print_mp(mpp, conf->verbosity); + return 0; + } + + switch (mpp->action) { + case ACT_NOTHING: + return 2; + + case ACT_SWITCHPG: + dm_switchgroup(mpp->alias, mpp->bestpg); + /* + * 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 2; + + case ACT_CREATE: + if (lock_multipath(mpp, 1)) { + condlog(3, "%s: in use", mpp->alias); + return -1; + } + dm_shut_log(); + + if (dm_map_present(mpp->alias)) + break; + + r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET, + mpp->params, mpp->size, mpp->wwid); + + /* + * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus + * DM_TABLE_LOAD. Failing the second part leaves an + * empty map. Clean it up. + */ + if (!r && dm_map_present(mpp->alias)) { + condlog(3, "%s: failed to load map " + "(a path might be in use)", + mpp->alias); + dm_flush_map(mpp->alias, NULL); + } + + lock_multipath(mpp, 0); + dm_restore_log(); + break; + + case ACT_RELOAD: + r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET, + mpp->params, mpp->size, NULL) && + dm_simplecmd(DM_DEVICE_RESUME, mpp->alias)); + break; + + default: + break; + } + + if (r) { + /* + * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded + */ + dm_switchgroup(mpp->alias, mpp->bestpg); + print_mp(mpp, conf->verbosity); + } + + return r; +} + +static int +deadmap (struct multipath * mpp) +{ + int i, j; + struct pathgroup * pgp; + struct path * pp; + + if (!mpp->pg) + return 1; + + vector_foreach_slot (mpp->pg, pgp, i) { + if (!pgp->paths) + continue; + + vector_foreach_slot (pgp->paths, pp, j) + if (strlen(pp->dev)) + return 0; /* alive */ + } + + return 1; /* dead */ +} + +extern int +coalesce_paths (vector curmp, vector pathvec) +{ + int r = 1; + int k, i; + char empty_buff[WWID_SIZE]; + struct multipath * mpp; + struct path * pp1; + struct path * pp2; + + memset(empty_buff, 0, WWID_SIZE); + + 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)) + continue; + + /* 2. if path already coalesced */ + if (pp1->mpp) + 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; + strcpy(mpp->wwid, pp1->wwid); + select_alias(mpp); + + pp1->mpp = mpp; + 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)) + goto next; + + if (mpp->action == ACT_UNDEF) + select_action(mpp, curmp); + + r = domap(mpp); + + if (r < 0) + return r; + + if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) { + if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) + dm_queue_if_no_path(mpp->alias, 0); + else + dm_queue_if_no_path(mpp->alias, 1); + } + +next: + drop_multipath(curmp, mpp->wwid, KEEP_PATHS); + free_multipath(mpp, KEEP_PATHS); + } + /* + * Flush maps with only dead paths (ie not in sysfs) + * Keep maps with only failed paths + */ + vector_foreach_slot (curmp, mpp, i) { + if (!deadmap(mpp)) + continue; + + if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) + condlog(2, "remove: %s (dead) failed!", + mpp->alias); + else + condlog(2, "remove: %s (dead)", mpp->alias); + } + return 0; +} diff --git a/libmultipath/configure.h b/libmultipath/configure.h new file mode 100644 index 0000000..26d125a --- /dev/null +++ b/libmultipath/configure.h @@ -0,0 +1,21 @@ +/* + * configurator actions + */ +#define ACT_NOTHING_STR "unchanged" +#define ACT_RELOAD_STR "reload" +#define ACT_SWITCHPG_STR "switchpg" +#define ACT_CREATE_STR "create" + +enum actions { + ACT_UNDEF, + ACT_NOTHING, + ACT_RELOAD, + ACT_SWITCHPG, + ACT_CREATE +}; + +#define FLUSH_ONE 1 +#define FLUSH_ALL 2 + +int reinstate_paths (struct multipath * mpp); +int coalesce_paths (vector curmp, vector pathvec); diff --git a/libmultipath/print.c b/libmultipath/print.c index 0b14eae..41f0005 100644 --- a/libmultipath/print.c +++ b/libmultipath/print.c @@ -10,6 +10,8 @@ #include "structs.h" #include "print.h" #include "dmparser.h" +#include "configure.h" +#include "defaults.h" #include "../libcheckers/path_state.h" @@ -17,8 +19,12 @@ #define MAX(x,y) (x > y) ? x : y +/* for column aligned output */ +struct path_layout pl; +struct map_layout ml; + void -get_path_layout (struct path_layout * pl, vector pathvec) +get_path_layout (vector pathvec) { int i; char buff[MAX_FIELD_LEN]; @@ -31,11 +37,11 @@ get_path_layout (struct path_layout * pl, vector pathvec) int prio_len; /* reset max col lengths */ - pl->uuid_len = 0; - pl->hbtl_len = 0; - pl->dev_len = 0; - pl->dev_t_len = 0; - pl->prio_len = 0; + pl.uuid_len = 0; + pl.hbtl_len = 0; + pl.dev_len = 0; + pl.dev_t_len = 0; + pl.prio_len = 0; vector_foreach_slot (pathvec, pp, i) { uuid_len = strlen(pp->wwid); @@ -48,17 +54,17 @@ get_path_layout (struct path_layout * pl, vector pathvec) dev_t_len = strlen(pp->dev_t); prio_len = 1 + (int)log10(pp->priority); - pl->uuid_len = MAX(uuid_len, pl->uuid_len); - pl->hbtl_len = MAX(hbtl_len, pl->hbtl_len); - pl->dev_len = MAX(dev_len, pl->dev_len); - pl->dev_t_len = MAX(dev_t_len, pl->dev_t_len); - pl->prio_len = MAX(prio_len, pl->prio_len); + pl.uuid_len = MAX(uuid_len, pl.uuid_len); + pl.hbtl_len = MAX(hbtl_len, pl.hbtl_len); + pl.dev_len = MAX(dev_len, pl.dev_len); + pl.dev_t_len = MAX(dev_t_len, pl.dev_t_len); + pl.prio_len = MAX(prio_len, pl.prio_len); } return; } void -get_map_layout (struct map_layout * ml, vector mpvec) +get_map_layout (vector mpvec) { int i; char buff[MAX_FIELD_LEN]; @@ -71,11 +77,11 @@ get_map_layout (struct map_layout * ml, vector mpvec) int nr_active_len; /* reset max col lengths */ - ml->mapname_len = 0; - ml->mapdev_len = 0; - ml->failback_progress_len = 0; - ml->queueing_progress_len = 0; - ml->nr_active_len = 0; + ml.mapname_len = 0; + ml.mapdev_len = 0; + ml.failback_progress_len = 0; + ml.queueing_progress_len = 0; + ml.nr_active_len = 0; vector_foreach_slot (mpvec, mpp, i) { mapname_len = (mpp->alias) ? @@ -91,13 +97,13 @@ get_map_layout (struct map_layout * ml, vector mpvec) queueing_progress_len = 5 + (int)log10(mpp->retry_tick); nr_active_len = (int)log10(mpp->nr_active); - ml->mapname_len = MAX(mapname_len, ml->mapname_len); - ml->mapdev_len = MAX(mapdev_len, ml->mapdev_len); - ml->failback_progress_len = MAX(failback_progress_len, - ml->failback_progress_len); - ml->queueing_progress_len = MAX(queueing_progress_len, - ml->queueing_progress_len); - ml->nr_active_len = MAX(nr_active_len, ml->nr_active_len); + ml.mapname_len = MAX(mapname_len, ml.mapname_len); + ml.mapdev_len = MAX(mapdev_len, ml.mapdev_len); + ml.failback_progress_len = MAX(failback_progress_len, + ml.failback_progress_len); + ml.queueing_progress_len = MAX(queueing_progress_len, + ml.queueing_progress_len); + ml.nr_active_len = MAX(nr_active_len, ml.nr_active_len); } return; } @@ -124,8 +130,7 @@ get_map_layout (struct map_layout * ml, vector mpvec) PRINT(c, TAIL, " %i/%i", cur, total) int -snprint_map_header (char * line, int len, char * format, - struct map_layout * ml) +snprint_map_header (char * line, int len, char * format) { char * c = line; /* line cursor */ char * s = line; /* for padding */ @@ -145,30 +150,30 @@ snprint_map_header (char * line, int len, char * format, switch (*f) { case 'w': PRINT(c, TAIL, "name"); - ml->mapname_len = MAX(ml->mapname_len, 4); - PAD(ml->mapname_len); + ml.mapname_len = MAX(ml.mapname_len, 4); + PAD(ml.mapname_len); break; case 'd': PRINT(c, TAIL, "sysfs"); - ml->mapdev_len = MAX(ml->mapdev_len, 5); - PAD(ml->mapdev_len); + ml.mapdev_len = MAX(ml.mapdev_len, 5); + PAD(ml.mapdev_len); break; case 'F': PRINT(c, TAIL, "failback"); - ml->failback_progress_len = - MAX(ml->failback_progress_len, 8); - PAD(ml->failback_progress_len); + ml.failback_progress_len = + MAX(ml.failback_progress_len, 8); + PAD(ml.failback_progress_len); break; case 'Q': PRINT(c, TAIL, "queueing"); - ml->queueing_progress_len = - MAX(ml->queueing_progress_len, 8); - PAD(ml->queueing_progress_len); + ml.queueing_progress_len = + MAX(ml.queueing_progress_len, 8); + PAD(ml.queueing_progress_len); break; case 'n': PRINT(c, TAIL, "paths"); - ml->nr_active_len = MAX(ml->nr_active_len, 5); - PAD(ml->nr_active_len); + ml.nr_active_len = MAX(ml.nr_active_len, 5); + PAD(ml.nr_active_len); break; case 't': PRINT(c, TAIL, "dm-st"); @@ -187,7 +192,7 @@ snprint_map_header (char * line, int len, char * format, int snprint_map (char * line, int len, char * format, - struct multipath * mpp, struct map_layout * ml) + struct multipath * mpp) { char * c = line; /* line cursor */ char * s = line; /* for padding */ @@ -211,18 +216,18 @@ snprint_map (char * line, int len, char * format, } else { PRINT(c, TAIL, "%s", mpp->wwid); } - PAD(ml->mapname_len); + PAD(ml.mapname_len); break; case 'd': if (mpp->dmi) { PRINT(c, TAIL, "dm-%i", mpp->dmi->minor); } - PAD(ml->mapdev_len); + PAD(ml.mapdev_len); break; case 'F': if (mpp->pgfailback == -FAILBACK_IMMEDIATE) { PRINT(c, TAIL, "immediate"); - PAD(ml->failback_progress_len); + PAD(ml.failback_progress_len); break; } if (!mpp->failback_tick) { @@ -231,7 +236,7 @@ snprint_map (char * line, int len, char * format, PRINT_PROGRESS(mpp->failback_tick, mpp->pgfailback); } - PAD(ml->failback_progress_len); + PAD(ml.failback_progress_len); break; case 'Q': if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) { @@ -249,11 +254,11 @@ snprint_map (char * line, int len, char * format, mpp->no_path_retry); } } - PAD(ml->queueing_progress_len); + PAD(ml.queueing_progress_len); break; case 'n': PRINT(c, TAIL, "%i", mpp->nr_active); - PAD(ml->nr_active_len); + PAD(ml.nr_active_len); break; case 't': if (mpp->dmi && mpp->dmi->suspended) { @@ -275,8 +280,7 @@ snprint_map (char * line, int len, char * format, } int -snprint_path_header (char * line, int len, char * format, - struct path_layout * pl) +snprint_path_header (char * line, int len, char * format) { char * c = line; /* line cursor */ char * s = line; /* for padding */ @@ -296,21 +300,21 @@ snprint_path_header (char * line, int len, char * format, switch (*f) { case 'w': PRINT(c, TAIL, "uuid"); - PAD(pl->uuid_len); + PAD(pl.uuid_len); break; case 'i': PRINT(c, TAIL, "hcil"); - PAD(pl->hbtl_len); + PAD(pl.hbtl_len); break; case 'd': PRINT(c, TAIL, "dev"); - pl->dev_len = MAX(pl->dev_len, 3); - PAD(pl->dev_len); + pl.dev_len = MAX(pl.dev_len, 3); + PAD(pl.dev_len); break; case 'D': PRINT(c, TAIL, "dev_t"); - pl->dev_t_len = MAX(pl->dev_t_len, 5); - PAD(pl->dev_t_len); + pl.dev_t_len = MAX(pl.dev_t_len, 5); + PAD(pl.dev_t_len); break; case 'T': PRINT(c, TAIL, "chk-st"); @@ -330,8 +334,8 @@ snprint_path_header (char * line, int len, char * format, break; case 'p': PRINT(c, TAIL, "pri"); - pl->prio_len = MAX(pl->prio_len, 3); - PAD(pl->prio_len); + pl.prio_len = MAX(pl.prio_len, 3); + PAD(pl.prio_len); break; default: break; @@ -345,8 +349,7 @@ snprint_path_header (char * line, int len, char * format, } int -snprint_path (char * line, int len, char * format, struct path * pp, - struct path_layout * pl) +snprint_path (char * line, int len, char * format, struct path * pp) { char * c = line; /* line cursor */ char * s = line; /* for padding */ @@ -366,7 +369,7 @@ snprint_path (char * line, int len, char * format, struct path * pp, switch (*f) { case 'w': PRINT(c, TAIL, "%s", pp->wwid); - PAD(pl->uuid_len); + PAD(pl.uuid_len); break; case 'i': if (pp->sg_id.host_no < 0) { @@ -378,7 +381,7 @@ snprint_path (char * line, int len, char * format, struct path * pp, pp->sg_id.scsi_id, pp->sg_id.lun); } - PAD(pl->hbtl_len); + PAD(pl.hbtl_len); break; case 'd': if (!strlen(pp->dev)) { @@ -386,11 +389,11 @@ snprint_path (char * line, int len, char * format, struct path * pp, } else { PRINT(c, TAIL, "%s", pp->dev); } - PAD(pl->dev_len); + PAD(pl.dev_len); break; case 'D': PRINT(c, TAIL, "%s", pp->dev_t); - PAD(pl->dev_t_len); + PAD(pl.dev_t_len); break; case 'T': switch (pp->state) { @@ -445,7 +448,7 @@ snprint_path (char * line, int len, char * format, struct path * pp, } else { PRINT(c, TAIL, "#"); } - PAD(pl->prio_len); + PAD(pl.prio_len); break; default: break; @@ -458,3 +461,142 @@ snprint_path (char * line, int len, char * format, struct path * pp, return (c - line); } +extern void +print_mp (struct multipath * mpp, int verbosity) +{ + int j, i; + struct path * pp = NULL; + struct pathgroup * pgp = NULL; + + if (mpp->action == ACT_NOTHING || !verbosity || !mpp->size) + return; + + if (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 (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); + + fprintf(stdout, "\n"); + + 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); + + switch (pgp->status) { + case PGSTATE_ENABLED: + printf("[enabled]"); + break; + case PGSTATE_DISABLED: + printf("[disabled]"); + break; + case PGSTATE_ACTIVE: + printf("[active]"); + break; + default: + break; + } + printf("\n"); + + vector_foreach_slot (pgp->paths, pp, i) + print_path(pp, PRINT_PATH_INDENT); + } + printf("\n"); +} + +extern void +print_path (struct path * pp, char * style) +{ + char line[MAX_LINE_LEN]; + + snprint_path(&line[0], MAX_LINE_LEN, style, pp); + printf("%s", line); +} + +extern void +print_map (struct multipath * mpp) +{ + if (mpp->size && mpp->params) + printf("0 %llu %s %s\n", + mpp->size, DEFAULT_TARGET, mpp->params); + return; +} + +extern void +print_all_paths (vector pathvec, int banner) +{ + int i; + struct path * pp; + char line[MAX_LINE_LEN]; + + if (!VECTOR_SIZE(pathvec)) { + if (banner) + fprintf(stdout, "===== no paths =====\n"); + return; + } + + if (banner) + fprintf(stdout, "===== paths list =====\n"); + + get_path_layout(pathvec); + snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG); + fprintf(stdout, "%s", line); + + vector_foreach_slot (pathvec, pp, i) + print_path(pp, PRINT_PATH_LONG); +} + diff --git a/libmultipath/print.h b/libmultipath/print.h index 5da4396..da69edc 100644 --- a/libmultipath/print.h +++ b/libmultipath/print.h @@ -45,9 +45,14 @@ struct map_layout { }; -void get_path_layout (struct path_layout * pl, vector pathvec); -void get_map_layout (struct map_layout * pl, vector mpvec); -int snprint_path_header (char *, int, char *, struct path_layout *); -int snprint_map_header (char *, int, char *, struct map_layout *); -int snprint_path (char *, int, char *, struct path *, struct path_layout *); -int snprint_map (char *, int, char *,struct multipath *, struct map_layout *); +void get_path_layout (vector pathvec); +void get_map_layout (vector mpvec); +int snprint_path_header (char *, int, char *); +int snprint_map_header (char *, int, char *); +int snprint_path (char *, int, char *, struct path *); +int snprint_map (char *, int, char *,struct multipath *); + +void print_mp (struct multipath * mpp, int verbosity); +void print_path (struct path * pp, char * style); +void print_map (struct multipath * mpp); +void print_all_paths (vector pathvec, int banner); diff --git a/multipath/main.c b/multipath/main.c index 9bd1063..3cd0fb2 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -23,41 +23,31 @@ */ #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; static char * get_refwwid (vector pathvec) @@ -146,145 +136,6 @@ out: return NULL; } -static void -print_path (struct path * pp, char * style) -{ - char line[MAX_LINE_LEN]; - - snprint_path(&line[0], MAX_LINE_LEN, style, pp, &pl); - printf("%s", line); -} - -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; -} - -static void -print_all_paths (vector pathvec, int banner) -{ - int i; - struct path * pp; - char line[MAX_LINE_LEN]; - - if (!VECTOR_SIZE(pathvec)) { - if (banner) - fprintf(stdout, "===== no paths =====\n"); - return; - } - - if (banner) - fprintf(stdout, "===== paths list =====\n"); - - get_path_layout(&pl, pathvec); - snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG, &pl); - fprintf(stdout, "%s", line); - - 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 || !mpp->size) - 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); - - fprintf(stdout, "\n"); - - 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); - - switch (pgp->status) { - case PGSTATE_ENABLED: - printf("[enabled]"); - break; - case PGSTATE_DISABLED: - printf("[disabled]"); - break; - case PGSTATE_ACTIVE: - printf("[active]"); - break; - default: - break; - } - printf("\n"); - - vector_foreach_slot (pgp->paths, pp, i) - print_path(pp, PRINT_PATH_INDENT); - } - printf("\n"); -} - static int filter_pathvec (vector pathvec, char * refwwid) { @@ -305,453 +156,6 @@ filter_pathvec (vector pathvec, char * refwwid) return 0; } -static int -setup_map (struct multipath * mpp) -{ - struct pathgroup * pgp; - int i; - - /* - * don't bother if devmap size is unknown - */ - if (mpp->size <= 0) { - condlog(3, "%s: devmap size is unknown", mpp->alias); - return 1; - } - - /* - * properties selectors - */ - select_pgfailback(mpp); - select_pgpolicy(mpp); - select_selector(mpp); - select_features(mpp); - select_hwhandler(mpp); - select_rr_weight(mpp); - select_minio(mpp); - select_no_path_retry(mpp); - - /* - * assign paths to path groups -- start with no groups and all paths - * in mpp->paths - */ - if (mpp->pg) { - vector_foreach_slot (mpp->pg, pgp, i) - free_pathgroup(pgp, KEEP_PATHS); - - vector_free(mpp->pg); - mpp->pg = NULL; - } - if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp)) - return 1; - - mpp->nr_active = pathcount(mpp, PATH_UP); - - /* - * ponders each path group and determine highest prio pg - * to switch over (default to first) - */ - mpp->bestpg = select_path_group(mpp); - - /* - * transform the mp->pg vector of vectors of paths - * into a mp->params strings to feed the device-mapper - */ - if (assemble_map(mpp)) { - condlog(0, "%s: problem assembing map", mpp->alias); - return 1; - } - return 0; -} - -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; -} - -static void -select_action (struct multipath * mpp, vector curmp) -{ - struct multipath * cmpp; - - cmpp = find_mp_by_alias(curmp, mpp->alias); - - if (!cmpp) { - cmpp = find_mp_by_wwid(curmp, mpp->wwid); - - 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; - condlog(3, "set ACT_CREATE: map does not exists"); - return; - } - - if (!find_mp_by_wwid(curmp, mpp->wwid)) { - condlog(2, "remove: %s (wwid changed)", cmpp->alias); - dm_flush_map(mpp->alias, NULL); - strncat(cmpp->wwid, mpp->wwid, WWID_SIZE); - drop_multipath(curmp, cmpp->wwid, KEEP_PATHS); - mpp->action = ACT_CREATE; - condlog(3, "set ACT_CREATE: map wwid change"); - return; - } - - if (pathcount(mpp, PATH_UP) == 0) { - mpp->action = ACT_NOTHING; - condlog(3, "set ACT_NOTHING: no usable path"); - return; - } - if (cmpp->size != mpp->size) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: size change"); - return; - } - if (!mpp->no_path_retry && /* let features be handled by the daemon */ - strncmp(cmpp->features, mpp->features, strlen(mpp->features))) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: features change"); - return; - } - if (strncmp(cmpp->hwhandler, mpp->hwhandler, - strlen(mpp->hwhandler))) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: hwhandler change"); - return; - } - if (strncmp(cmpp->selector, mpp->selector, - strlen(mpp->selector))) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: selector change"); - return; - } - if (cmpp->minio != mpp->minio) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: minio change (%u->%u)", - cmpp->minio, mpp->minio); - return; - } - if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: number of path group change"); - return; - } - if (pgcmp(mpp, cmpp)) { - mpp->action = ACT_RELOAD; - condlog(3, "set ACT_RELOAD: path group topology change"); - return; - } - if (cmpp->nextpg != mpp->bestpg) { - mpp->action = ACT_SWITCHPG; - condlog(3, "set ACT_SWITCHPG: next path group change"); - return; - } - mpp->action = ACT_NOTHING; - condlog(3, "set ACT_NOTHING: map unchanged"); - return; -} - -static int -reinstate_paths (struct multipath * mpp) -{ - int i, j; - struct pathgroup * pgp; - struct path * pp; - - if (!mpp->pg) - return 0; - - vector_foreach_slot (mpp->pg, pgp, i) { - if (!pgp->paths) - continue; - - vector_foreach_slot (pgp->paths, pp, j) { - if (pp->state != PATH_UP && - (pgp->status == PGSTATE_DISABLED || - pgp->status == PGSTATE_ACTIVE)) - continue; - - if (pp->dmstate == PSTATE_FAILED) { - if (dm_reinstate_path(mpp->alias, pp->dev_t)) - condlog(0, "error reinstating %s", - pp->dev); - } - } - } - return 0; -} - -int lock_multipath (struct multipath * mpp, int lock) -{ - struct pathgroup * pgp; - struct path * pp; - int i, j; - - if (!mpp || !mpp->pg) - return 0; - - vector_foreach_slot (mpp->pg, pgp, i) { - if (!pgp->paths) - continue; - vector_foreach_slot(pgp->paths, pp, j) { - if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) && - errno == EWOULDBLOCK) - return 1; - else if (!lock) - flock(pp->fd, LOCK_UN); - } - } - return 0; -} - -/* - * Return value: - * -1: Retry - * 0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode. - * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded. - * 2: Map is already existing. - */ -static int -domap (struct multipath * mpp) -{ - int r = 0; - - /* - * last chance to quit before touching the devmaps - */ - if (conf->dry_run) { - print_mp(mpp); - return 0; - } - - switch (mpp->action) { - case ACT_NOTHING: - return 2; - - case ACT_SWITCHPG: - dm_switchgroup(mpp->alias, mpp->bestpg); - /* - * 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 2; - - case ACT_CREATE: - if (lock_multipath(mpp, 1)) { - condlog(3, "%s: in use", mpp->alias); - return -1; - } - dm_shut_log(); - - if (dm_map_present(mpp->alias)) - break; - - r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET, - mpp->params, mpp->size, mpp->wwid); - - /* - * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus - * DM_TABLE_LOAD. Failing the second part leaves an - * empty map. Clean it up. - */ - if (!r && dm_map_present(mpp->alias)) { - condlog(3, "%s: failed to load map " - "(a path might be in use)", - mpp->alias); - dm_flush_map(mpp->alias, NULL); - } - - lock_multipath(mpp, 0); - dm_restore_log(); - break; - - case ACT_RELOAD: - r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET, - mpp->params, mpp->size, NULL) && - dm_simplecmd(DM_DEVICE_RESUME, mpp->alias)); - break; - - default: - break; - } - - if (r) { - /* - * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded - */ - dm_switchgroup(mpp->alias, mpp->bestpg); - print_mp(mpp); - } - - return r; -} - -static int -deadmap (struct multipath * mpp) -{ - int i, j; - struct pathgroup * pgp; - struct path * pp; - - if (!mpp->pg) - return 1; - - vector_foreach_slot (mpp->pg, pgp, i) { - if (!pgp->paths) - continue; - - vector_foreach_slot (pgp->paths, pp, j) - if (strlen(pp->dev)) - return 0; /* alive */ - } - - return 1; /* dead */ -} - -static int -coalesce_paths (vector curmp, vector pathvec) -{ - int r = 1; - int k, i; - char empty_buff[WWID_SIZE]; - struct multipath * mpp; - struct path * pp1; - struct path * pp2; - - memset(empty_buff, 0, WWID_SIZE); - - 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)) - continue; - - /* 2. if path already coalesced */ - if (pp1->mpp) - 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; - strcpy(mpp->wwid, pp1->wwid); - select_alias(mpp); - - pp1->mpp = mpp; - 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)) - goto next; - - if (mpp->action == ACT_UNDEF) - select_action(mpp, curmp); - - r = domap(mpp); - - if (r < 0) - return r; - - if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) { - if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) - dm_queue_if_no_path(mpp->alias, 0); - else - dm_queue_if_no_path(mpp->alias, 1); - } - -next: - drop_multipath(curmp, mpp->wwid, KEEP_PATHS); - free_multipath(mpp, KEEP_PATHS); - } - /* - * Flush maps with only dead paths (ie not in sysfs) - * Keep maps with only failed paths - */ - vector_foreach_slot (curmp, mpp, i) { - if (!deadmap(mpp)) - continue; - - if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) - condlog(2, "remove: %s (dead) failed!", - mpp->alias); - else - condlog(2, "remove: %s (dead)", mpp->alias); - } - return 0; -} - static void usage (char * progname) { @@ -865,7 +269,7 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid) disassemble_status(mpp->status, mpp); if (conf->list) - print_mp(mpp); + print_mp(mpp, conf->verbosity); if (!conf->dry_run) reinstate_paths(mpp); @@ -957,7 +361,7 @@ configure (void) if (conf->verbosity > 2) print_all_paths(pathvec, 1); - get_path_layout(&pl, pathvec); + get_path_layout(pathvec); if (get_dm_mpvec(curmp, pathvec, refwwid)) goto out; diff --git a/multipath/main.h b/multipath/main.h index b4d79c9..89d98fb 100644 --- a/multipath/main.h +++ b/multipath/main.h @@ -20,25 +20,6 @@ #define _MAIN_H /* - * configurator actions - */ -#define ACT_NOTHING_STR "unchanged" -#define ACT_RELOAD_STR "reload" -#define ACT_SWITCHPG_STR "switchpg" -#define ACT_CREATE_STR "create" - -enum actions { - ACT_UNDEF, - ACT_NOTHING, - ACT_RELOAD, - ACT_SWITCHPG, - ACT_CREATE -}; - -#define FLUSH_ONE 1 -#define FLUSH_ALL 2 - -/* * Build version */ #define PROG "multipath" diff --git a/multipathd/main.c b/multipathd/main.c index 30e2979..0f93039 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -780,11 +780,10 @@ show_paths (char ** r, int * len, struct vectors * vecs) struct path * pp; char * c; char * reply; - struct path_layout pl; int maxlen = INITIAL_REPLY_LEN; int again = 1; - get_path_layout(&pl, vecs->pathvec); + get_path_layout(vecs->pathvec); reply = MALLOC(maxlen); while (again) { @@ -795,11 +794,11 @@ show_paths (char ** r, int * len, struct vectors * vecs) if (VECTOR_SIZE(vecs->pathvec) > 0) c += snprint_path_header(c, reply + maxlen - c, - PRINT_PATH_CHECKER, &pl); + PRINT_PATH_CHECKER); vector_foreach_slot(vecs->pathvec, pp, i) c += snprint_path(c, reply + maxlen - c, - PRINT_PATH_CHECKER, pp, &pl); + PRINT_PATH_CHECKER, pp); again = ((c - reply) == (maxlen - 1)); @@ -819,11 +818,10 @@ show_maps (char ** r, int *len, struct vectors * vecs) struct multipath * mpp; char * c; char * reply; - struct map_layout ml; int maxlen = INITIAL_REPLY_LEN; int again = 1; - get_map_layout(&ml, vecs->mpvec); + get_map_layout(vecs->mpvec); reply = MALLOC(maxlen); while (again) { @@ -833,11 +831,11 @@ show_maps (char ** r, int *len, struct vectors * vecs) c = reply; if (VECTOR_SIZE(vecs->mpvec) > 0) c += snprint_map_header(c, reply + maxlen - c, - PRINT_MAP_FAILBACK, &ml); + PRINT_MAP_FAILBACK); vector_foreach_slot(vecs->mpvec, mpp, i) c += snprint_map(c, reply + maxlen - c, - PRINT_MAP_FAILBACK, mpp, &ml); + PRINT_MAP_FAILBACK, mpp); again = ((c - reply) == (maxlen - 1)); -- 2.7.4