From 45eb3167d5fd0543425f56ad0f0b79eb9ac2fe5e Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Mon, 21 Nov 2005 18:00:03 +0100 Subject: [PATCH] [multipathd] DM configuration final cut This one adds the multipath maintenance through uevents {add,remove} path handlers. Edward Goggin, EMC. --- libmultipath/configure.c | 4 +- libmultipath/configure.h | 2 + multipathd/main.c | 259 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 238 insertions(+), 27 deletions(-) diff --git a/libmultipath/configure.c b/libmultipath/configure.c index 882367d..59cfbab 100644 --- a/libmultipath/configure.c +++ b/libmultipath/configure.c @@ -33,7 +33,7 @@ #include "pgpolicies.h" #include "dict.h" -static int +extern int setup_map (struct multipath * mpp) { struct pathgroup * pgp; @@ -271,7 +271,7 @@ lock_multipath (struct multipath * mpp, int lock) * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded. * 2: Map is already existing. */ -static int +extern int domap (struct multipath * mpp) { int r = 0; diff --git a/libmultipath/configure.h b/libmultipath/configure.h index b74d350..24c022d 100644 --- a/libmultipath/configure.h +++ b/libmultipath/configure.h @@ -18,5 +18,7 @@ enum actions { #define FLUSH_ONE 1 #define FLUSH_ALL 2 +int setup_map (struct multipath * mpp); +int domap (struct multipath * mpp); int reinstate_paths (struct multipath *mpp); int coalesce_paths (struct vectors *vecs, vector curmp); diff --git a/multipathd/main.c b/multipathd/main.c index d3e71be..329b46b 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -466,6 +466,30 @@ out: return 1; } +static int +flush_map(struct multipath * mpp, char * devname, struct vectors * vecs) +{ + /* + * clear references to this map before flushing so we can ignore + * the spurious uevent we may generate with the dm_flush_map call below + */ + if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) { + /* + * May not really be an error -- if the map was already flushed + * from the device mapper by dmsetup(8) for instance. + */ + condlog(0, "%s: can't flush", devname); + return 1; + } + else + condlog(3, "%s: devmap %s removed", devname, mpp->alias); + + orphan_paths(vecs->pathvec, mpp); + remove_map(mpp, vecs, stop_waiter_thread, 1); + + return 0; +} + int uev_add_map (char * devname, struct vectors * vecs) { @@ -543,58 +567,242 @@ uev_remove_map (char * devname, struct vectors * vecs) int uev_add_path (char * devname, struct vectors * vecs) { + struct multipath * mpp; struct path * pp; + char empty_buff[WWID_SIZE] = {0}; - pp = find_path_by_dev(vecs->pathvec, devname); + condlog(3, "%s: uev_add_path", devname); + pp = find_path_by_dev(vecs->pathvec, devname); if (pp) { - condlog(3, "%s: already in pathvec", devname); - return 1; + condlog(0, "%s: spurious uevent, path already in pathvec, %p", + devname, pp->mpp); + /* + * allow reconfig of orphaned path here + */ + if (pp->mpp) return 1; + } + else { + /* + * get path vital state + */ + if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable, + devname, DI_ALL))) { + condlog(0, "%s: failed to store path info", devname); + return 1; + } + pp->checkint = conf->checkint; } - pp = store_pathinfo(vecs->pathvec, conf->hwtable, - devname, DI_SYSFS | DI_WWID); - if (!pp) { - condlog(0, "%s: failed to store path info", devname); - return 1; + /* + * need path UID to go any further + */ + if (memcmp(empty_buff, pp->wwid, WWID_SIZE) == 0) { + condlog(0, "%s: failed to get path uid", devname); + return 1; /* leave path added to pathvec */ } - condlog(2, "%s: path checker registered", devname); - pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); + mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); +rescan: + if (mpp) { + if (adopt_paths(vecs->pathvec, mpp)) + return 1; /* leave path added to pathvec */ + + verify_paths(mpp, vecs, NULL); + condlog(0, "%s: ownership set to %s", pp->dev_t, mpp->alias); + mpp->action = ACT_RELOAD; + } + else { + if ((mpp = add_map_with_path(vecs, pp, 1))) + mpp->action = ACT_CREATE; + else + return 1; /* leave path added to pathvec */ + } - if (pp->mpp) { - condlog(4, "%s: ownership set to %s", - pp->dev_t, pp->mpp->alias); - } else { - condlog(4, "%s: orphaned", pp->dev_t); - orphan_path(pp); + /* + * push the map to the device-mapper + */ + if (setup_map(mpp)) { + condlog(0, "%s: failed to setup map for addition of new " + "path %s", mpp->alias, devname); + goto out; + } + /* + * reload the map for the multipath mapped device + */ + if (domap(mpp) <= 0) { + condlog(0, "%s: failed in domap for addition of new " + "path %s", mpp->alias, devname); + /* + * deal with asynchronous uevents :(( + */ + if (mpp->action == ACT_RELOAD) { + condlog(0, "%s: uev_add_path sleep", mpp->alias); + sleep(1); + update_mpp_paths(mpp); + goto rescan; + } + else + goto out; } + /* + * update our state from kernel regardless of create or reload + */ + if (setup_multipath(vecs, mpp)) + goto out; + + if (mpp->action == ACT_CREATE && + start_waiter_thread(mpp, vecs)) + goto out; + + condlog(3, "%s path added to devmap %s", devname, mpp->alias); return 0; + +out: + remove_map(mpp, vecs, NULL, 1); + return 1; } int uev_remove_path (char * devname, struct vectors * vecs) { - int i; + struct multipath * mpp; struct path * pp; + int redo, i; + int rm_path = 1; - pp = find_path_by_dev(vecs->pathvec, devname); + condlog(3, "%s: uev_remove_path", devname); + pp = find_path_by_dev(vecs->pathvec, devname); if (!pp) { - condlog(3, "%s: not in pathvec", devname); + condlog(0, "%s: spurious uevent, path not in pathvec", devname); return 1; } - if (pp->mpp && pp->state == PATH_UP) - update_queue_mode_del_path(pp->mpp); + /* + * avoid referring to the map of an orphanned path + */ + if ((mpp = pp->mpp)) { - condlog(2, "remove %s path checker", devname); - i = find_slot(vecs->pathvec, (void *)pp); - vector_del_slot(vecs->pathvec, i); - free_path(pp); + /* + * remove the map IFF removing the last path + */ + if (pathcount(mpp, PATH_WILD) > 1) { + vector rpvec = vector_alloc(); + struct path * mypp; + int j; + + /* + * transform the mp->pg vector of vectors of paths + * into a mp->params string to feed the device-mapper + */ + update_mpp_paths(mpp); + if ((i = find_slot(mpp->paths, (void *)pp)) != -1) + vector_del_slot(mpp->paths, i); + +rescan: + redo = verify_paths(mpp, vecs, rpvec); + if (VECTOR_SIZE(mpp->paths) == 0) { + char alias[WWID_SIZE]; + + /* + * flush_map will fail if the device is open + */ + strncpy(alias, mpp->alias, WWID_SIZE); + if (flush_map(mpp, devname, vecs)) { + rm_path = 0; + vector_foreach_slot(rpvec, mypp, i) + if (store_path(mpp->paths, mypp)) + goto out; + } + else { + vector_foreach_slot(rpvec, mypp, i) { + if ((j = find_slot(vecs->pathvec, + (void *)mypp)) != -1) { + vector_del_slot(vecs->pathvec, j); + free_path(mypp); + } + } + condlog(3, "%s: removed map after removing" + " multiple paths", alias); + } + } + else { + vector_foreach_slot(rpvec, mypp, i) { + if ((j = find_slot(vecs->pathvec, + (void *)mypp)) != -1) { + vector_del_slot(vecs->pathvec, j); + free_path(mypp); + } + } + + if (setup_map(mpp)) { + condlog(0, "%s: failed to setup map for" + " removal of path %s", mpp->alias, devname); + free_pathvec(rpvec, KEEP_PATHS); + goto out; + } + /* + * reload the map + */ + mpp->action = ACT_RELOAD; + if (domap(mpp) <= 0) { + condlog(0, "%s: failed in domap for " + "removal of path %s", + mpp->alias, devname); + /* + * deal with asynchronous uevents :(( + */ + if (!redo) { + condlog(3, "%s: uev_remove_path sleep", + mpp->alias); + sleep(1); + } + update_mpp_paths(mpp); + free_pathvec(rpvec, KEEP_PATHS); + rpvec = vector_alloc(); + goto rescan; + } + /* + * update our state from kernel + */ + if (setup_multipath(vecs, mpp)) { + free_pathvec(rpvec, KEEP_PATHS); + goto out; + } + + condlog(3, "%s path removed from devmap %s", + devname, mpp->alias); + } + free_pathvec(rpvec, KEEP_PATHS); + } + else { + char alias[WWID_SIZE]; + + /* + * flush_map will fail if the device is open + */ + strncpy(alias, mpp->alias, WWID_SIZE); + if (flush_map(mpp, devname, vecs)) { + rm_path = 0; + } + else + condlog(3, "%s: removed map", alias); + } + } + + if (rm_path) { + if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1) + vector_del_slot(vecs->pathvec, i); + free_path(pp); + } return 0; + +out: + remove_map(mpp, vecs, stop_waiter_thread, 1); + return 1; } int @@ -1570,3 +1778,4 @@ main (int argc, char *argv[]) /* child lives */ return (child(NULL)); } + -- 2.7.4