summaryrefslogtreecommitdiff
path: root/libmultipath/configure.c
diff options
context:
space:
mode:
authorChristophe Varoqui <root@xa-s05.(none)>2005-11-17 16:50:43 +0100
committerChristophe Varoqui <root@xa-s05.(none)>2005-11-17 16:50:43 +0100
commit8e4ddefdfdb87c15e9ba218c11098d8744c34920 (patch)
tree0b2d4d2ad9ffa5f4df507410be1f30040422d218 /libmultipath/configure.c
parent6fb3a3e50e3f8460a61fddd69279b224c41f0dbb (diff)
downloadmultipath-tools-8e4ddefdfdb87c15e9ba218c11098d8744c34920.tar.gz
multipath-tools-8e4ddefdfdb87c15e9ba218c11098d8744c34920.tar.bz2
multipath-tools-8e4ddefdfdb87c15e9ba218c11098d8744c34920.zip
[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.
Diffstat (limited to 'libmultipath/configure.c')
-rw-r--r--libmultipath/configure.c481
1 files changed, 481 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <libdevmapper.h>
+
+#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;
+}