[multipathd]
authorroot <root@xa-s05.(none)>
Mon, 16 May 2005 13:08:19 +0000 (15:08 +0200)
committerroot <root@xa-s05.(none)>
Mon, 16 May 2005 13:08:19 +0000 (15:08 +0200)
Jumbo patch :

o get rid of the last multipath configurator call
o introduce the native path group switching logic.
  For now only two behaviours :
  o FAILBACK_MANUAL
  o FAILBACK_IMMEDIATE
o get rid of path group ids unused bits
o paths and multipaths full scan is only done once now.
  Moved one step earlier, in child(). Lists housekeeping done
  through uevents (well, the mpvec part is yet to come)

libmultipath/Makefile
libmultipath/devmapper.c
libmultipath/dmparser.c
libmultipath/structs.c
libmultipath/structs.h
libmultipath/switchgroup.c [new file with mode: 0644]
libmultipath/switchgroup.h [new file with mode: 0644]
multipath/main.c
multipathd/Makefile
multipathd/log_pthread.c
multipathd/main.c

index 778297d..1dc3c51 100644 (file)
@@ -9,7 +9,8 @@ include ../Makefile.inc
 OBJS = memory.o parser.o vector.o devmapper.o callout.o \
        hwtable.o blacklist.o util.o dmparser.o config.o \
        structs.o cache.o discovery.o propsel.o dict.o \
-       pgpolicies.o debug.o regex.o defaults.o uevent.o
+       pgpolicies.o debug.o regex.o defaults.o uevent.o \
+       switchgroup.o
 
 CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
 
index 98739ac..b286cae 100644 (file)
@@ -413,8 +413,7 @@ dm_get_maps (vector mp, char * type)
 
        do {
                if (dm_type(names->name, type)) {
-                       mpp = (struct multipath *)
-                               MALLOC(sizeof(struct multipath));
+                       mpp = alloc_multipath();
 
                        if (!mpp)
                                goto out;
index de37790..a801a0a 100644 (file)
@@ -255,8 +255,6 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
                        if (store_path(pgp->paths, pp))
                                goto out;
 
-                       pgp->id ^= (long)pp;
-
                        if (!strlen(mpp->wwid))
                                strncpy(mpp->wwid, pp->wwid, WWID_SIZE);
 
index 3a1d55b..01fc542 100644 (file)
@@ -101,7 +101,15 @@ free_pgvec (vector pgvec, int free_paths)
 struct multipath *
 alloc_multipath (void)
 {
-       return (struct multipath *)MALLOC(sizeof(struct multipath));
+       struct multipath * mpp;
+
+       mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
+
+       if (mpp) {
+               mpp->pgfailback = FAILBACK_IMMEDIATE;
+               mpp->nextpg = 1;
+       }
+       return mpp;
 }
 
 void
index 9ae2a44..f368e18 100644 (file)
@@ -17,6 +17,9 @@
 #define KEEP_PATHS             0
 #define FREE_PATHS             1
 
+#define FAILBACK_MANUAL                -1
+#define FAILBACK_IMMEDIATE     0
+
 enum pathstates {
        PSTATE_RESERVED,
        PSTATE_FAILED,
@@ -89,6 +92,7 @@ struct multipath {
        int nextpg;
        int queuedio;
        int action;
+       int pgfailback;
        unsigned long size;
        vector paths;
        vector pg;
@@ -105,7 +109,6 @@ struct multipath {
 };
 
 struct pathgroup {
-       long id;
        int status;
        int priority;
        vector paths;
diff --git a/libmultipath/switchgroup.c b/libmultipath/switchgroup.c
new file mode 100644 (file)
index 0000000..346c2f2
--- /dev/null
@@ -0,0 +1,24 @@
+#include "vector.h"
+#include "structs.h"
+#include "switchgroup.h"
+#include "../libcheckers/path_state.h"
+
+extern void
+select_path_group (struct multipath * mpp)
+{
+       int i, j;
+       int highest = 0;
+       struct pathgroup * pgp;
+       struct path * pp;
+       
+       vector_foreach_slot (mpp->pg, pgp, i) {
+               vector_foreach_slot (pgp->paths, pp, j) {
+                       if (pp->state != PATH_DOWN)
+                               pgp->priority += pp->priority;
+               }
+               if (pgp->priority > highest) {
+                       highest = pgp->priority;
+                       mpp->nextpg = i + 1;
+               }
+       }
+}
diff --git a/libmultipath/switchgroup.h b/libmultipath/switchgroup.h
new file mode 100644 (file)
index 0000000..cc98210
--- /dev/null
@@ -0,0 +1 @@
+void select_path_group (struct multipath * mpp);
index 60cce73..5900cb6 100644 (file)
@@ -39,6 +39,7 @@
 #include <propsel.h>
 #include <discovery.h>
 #include <debug.h>
+#include <switchgroup.h>
 #include <sysfs/libsysfs.h>
 
 #include "main.h"
@@ -395,9 +396,7 @@ static int
 setup_map (struct multipath * mpp)
 {
        struct path * pp;
-       struct pathgroup * pgp;
-       int i, j;
-       int highest = 0;
+       int i;
 
        /*
         * don't bother if devmap size is unknown
@@ -456,19 +455,9 @@ setup_map (struct multipath * mpp)
 
        /*
         * ponders each path group and determine highest prio pg
+        * to switch over (default to first)
         */
-       mpp->nextpg = 1;
-       vector_foreach_slot (mpp->pg, pgp, i) {
-               vector_foreach_slot (pgp->paths, pp, j) {
-                       pgp->id ^= (long)pp;
-                       if (pp->state != PATH_DOWN)
-                               pgp->priority += pp->priority;
-               }
-               if (pgp->priority > highest) {
-                       highest = pgp->priority;
-                       mpp->nextpg = i + 1;
-               }
-       }
+       select_path_group(mpp);
 
        /*
         * transform the mp->pg vector of vectors of paths
index 9d656af..4432b81 100644 (file)
@@ -17,6 +17,13 @@ CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
         -DDAEMON -I$(multipathdir) -I$(checkersdir)
 LDFLAGS = -lpthread -ldevmapper -lsysfs
 
+#
+# debuging stuff
+#
+#CFLAGS += -DLOG_THREAD_DISABLE
+#CFLAGS += -DLCKDBG
+#CFLAGS += -D_DEBUG_
+
 #
 # object files
 #
index 278d173..2b62a73 100644 (file)
@@ -11,6 +11,12 @@ void log_safe (int prio, char * fmt, ...)
 {
        va_list ap;
 
+#ifdef LOG_THREAD_DISABLE
+       va_start(ap, fmt);
+       vfprintf(stdout, fmt, ap);
+       fprintf(stdout, "\n");
+       va_end(ap);
+#else
        pthread_mutex_lock(logq_lock);
        va_start(ap, fmt);
        log_enqueue(prio, fmt, ap);
@@ -20,6 +26,7 @@ void log_safe (int prio, char * fmt, ...)
        pthread_mutex_lock(logev_lock);
        pthread_cond_signal(logev_cond);
        pthread_mutex_unlock(logev_lock);
+#endif
 }
 
 static void flush_logqueue (void)
index f6e1910..ab7f20a 100644 (file)
@@ -47,6 +47,7 @@
 #include <debug.h>
 #include <propsel.h>
 #include <uevent.h>
+#include <switchgroup.h>
 
 #include "main.h"
 #include "copy.h"
@@ -89,6 +90,7 @@ pthread_cond_t *event;
 struct paths {
        pthread_mutex_t *lock;
        vector pathvec;
+       vector mpvec;
 };
 
 struct event_thread {
@@ -208,118 +210,113 @@ set_paths_owner (struct paths * allpaths, struct multipath * mpp)
        int i;
        struct path * pp;
 
-       vector_foreach_slot (allpaths->pathvec, pp, i)
-               if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE))
+       vector_foreach_slot (allpaths->pathvec, pp, i) {
+               if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
+                       log_safe(LOG_DEBUG, "%s ownership set",
+                                pp->dev_t);
                        pp->mpp = mpp;
-
+               }
+       }
 }
 
-/*
- * caller must have locked the path list before calling that function
- */
 static int
-get_dm_mpvec (vector mpvec, struct paths * allpaths)
+setup_multipath (struct paths * allpaths, struct multipath * mpp)
 {
-       int i;
-       struct multipath * mpp;
        char * wwid;
 
-       if (dm_get_maps(mpvec, "multipath"))
-               return 1;
+       wwid = get_mpe_wwid(mpp->alias);
 
-       vector_foreach_slot (mpvec, mpp, i) {
-               wwid = get_mpe_wwid(mpp->alias);
+       if (wwid) {
+               strncpy(mpp->wwid, wwid, WWID_SIZE);
+               wwid = NULL;
+       } else
+               strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
 
-               if (wwid) {
-                       strncpy(mpp->wwid, wwid, WWID_SIZE);
-                       wwid = NULL;
-               } else
-                       strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
+       log_safe(LOG_DEBUG, "discovered map %s", mpp->alias);
+
+       if(disassemble_map(allpaths->pathvec, mpp->params, mpp))
+               goto out;
 
-               set_paths_owner(allpaths, mpp);
-        }
-        return 0;
+       if(disassemble_status(mpp->status, mpp))
+               goto out;
+
+       set_paths_owner(allpaths, mpp);
+       return 0;
+out:
+       free_multipath(mpp, KEEP_PATHS);
+       return 1;
 }
 
+/*
+ * caller must have locked the path list before calling that function
+ */
 static int
-path_discovery_locked (struct paths *allpaths)
+get_dm_mpvec (struct paths * allpaths)
 {
-       lock(allpaths->lock);
-       path_discovery(allpaths->pathvec, conf, DI_SYSFS | DI_WWID);
-       unlock(allpaths->lock);
+       int i;
+       struct multipath * mpp;
+
+       if (dm_get_maps(allpaths->mpvec, "multipath"))
+               return 1;
+
+       vector_foreach_slot (allpaths->mpvec, mpp, i)
+               setup_multipath(allpaths, mpp);
 
        return 0;
 }
 
 static int
-mark_failed_path (struct paths *allpaths, char *mapname)
+update_multipath (struct paths *allpaths, char *mapname)
 {
        struct multipath *mpp;
        struct pathgroup  *pgp;
        struct path *pp;
-       struct path *app;
        int i, j;
        int r = 1;
 
-       if (!dm_map_present(mapname))
-               return 0;
-
-       mpp = alloc_multipath();
+       lock(allpaths->lock);
+       mpp = find_mp(allpaths->mpvec, mapname);
 
        if (!mpp)
-               return 1;
-
-       if (dm_get_map(mapname, &mpp->size, (char *)mpp->params))
-               goto out;
-
-       if (dm_get_status(mapname, mpp->status))
-               goto out;
-       
-       lock(allpaths->lock);
-       r = disassemble_map(allpaths->pathvec, mpp->params, mpp);
-       unlock(allpaths->lock);
-       
-       if (r)
                goto out;
 
-       r = disassemble_status(mpp->status, mpp);
+       free_pgvec(mpp->pg, KEEP_PATHS);
+       mpp->pg = NULL;
 
-       if (r)
-               goto out;
-
-       r = 0; /* can't fail from here on */
-       lock(allpaths->lock);
+       dm_get_map(mapname, &mpp->size, mpp->params);
+       dm_get_status(mapname, mpp->status);
+       setup_multipath(allpaths, mpp);
 
+       /*
+        * compare checkers states with DM states
+        */
        vector_foreach_slot (mpp->pg, pgp, i) {
                vector_foreach_slot (pgp->paths, pp, j) {
                        if (pp->dmstate != PSTATE_FAILED)
                                continue;
 
-                       app = find_path_by_devt(allpaths->pathvec, pp->dev_t);
-
-                       if (app && app->state != PATH_DOWN) {
+                       if (pp->state != PATH_DOWN) {
                                log_safe(LOG_NOTICE, "%s: mark as failed",
                                        pp->dev_t);
-                               app->state = PATH_DOWN;
+                               pp->state = PATH_DOWN;
 
                                /*
                                 * if opportune,
                                 * schedule the next check earlier
                                 */
-                               if (app->tick > conf->checkint)
-                                       app->tick = conf->checkint;
+                               if (pp->tick > conf->checkint)
+                                       pp->tick = conf->checkint;
                        }
                }
        }
-       unlock(allpaths->lock);
+       r = 0;
 out:
-       free_multipath(mpp, KEEP_PATHS);
-
+       unlock(allpaths->lock);
        return r;
 }
 
 static void *
-waiteventloop (struct event_thread * waiter, char * cmd)
+waiteventloop (struct event_thread * waiter)
 {
        struct dm_task *dmt;
        int event_nr;
@@ -346,11 +343,14 @@ waiteventloop (struct event_thread * waiter, char * cmd)
         * upon event ...
         */
        while (1) {
-               log_safe(LOG_DEBUG, "%s", cmd);
                log_safe(LOG_NOTICE, "devmap event (%i) on %s",
                                waiter->event_nr, waiter->mapname);
 
-               mark_failed_path(waiter->allpaths, waiter->mapname);
+               /*
+                * event might be a table reload, which means our mpp
+                * structure is obsolete. Refresh it.
+                */
+               update_multipath(waiter->allpaths, waiter->mapname);
 
                event_nr = dm_geteventnr(waiter->mapname);
 
@@ -375,7 +375,6 @@ static void *
 waitevent (void * et)
 {
        struct event_thread *waiter;
-       char cmd[CMDSIZE];
 
        mlockall(MCL_CURRENT | MCL_FUTURE);
 
@@ -383,15 +382,9 @@ waitevent (void * et)
        lock(waiter->waiter_lock);
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 
-       if (safe_snprintf(cmd, CMDSIZE, "%s %s",
-                         conf->multipath, waiter->mapname)) {
-               log_safe(LOG_ERR, "command too long, abord reconfigure");
-               goto out;
-       }
        while (1)
-               waiteventloop(waiter, cmd);
+               waiteventloop(waiter);
 
-out:
        /*
         * release waiter_lock so that waiterloop knows we are gone
         */
@@ -457,7 +450,6 @@ waiterloop (void *ap)
 {
        struct paths *allpaths;
        struct multipath *mpp;
-       vector mpvec = NULL;
        vector waiters;
        struct event_thread *wp;
        pthread_attr_t attr;
@@ -467,11 +459,6 @@ waiterloop (void *ap)
        mlockall(MCL_CURRENT | MCL_FUTURE);
        log_safe(LOG_NOTICE, "start DM events thread");
 
-       if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
-               log_safe(LOG_ERR, "can not find sysfs mount point");
-               return NULL;
-       }
-
        /*
         * inits
         */
@@ -486,20 +473,6 @@ waiterloop (void *ap)
 
        pthread_attr_setstacksize(&attr, 32 * 1024);
 
-       /*
-        * update paths list
-        */
-       while(path_discovery_locked(allpaths)) {
-               if (r) {
-                       /* log only once */
-                       log_safe(LOG_ERR, "can't update path list ... retry");
-                       r = 0;
-               }
-               sleep(5);
-       }
-       log_safe(LOG_INFO, "path list updated");
-
-
        while (1) {
                /*
                 * revoke the leases
@@ -507,45 +480,14 @@ waiterloop (void *ap)
                vector_foreach_slot(waiters, wp, i)
                        wp->lease = 0;
 
-               /*
-                * abuse the path list lock to protect against
-                * pp->mpp use while pointing nowhere
-                */
                lock(allpaths->lock);
 
-               /*
-                * update multipaths list
-                */
-               while (1) {
-                       if (mpvec) {
-                               free_multipathvec(mpvec, KEEP_PATHS);
-                               mpvec = NULL;
-                       }
-
-                       /*
-                        * we're not allowed to fail here
-                        */
-                       mpvec = vector_alloc();
-
-                       if (mpvec && !get_dm_mpvec(mpvec, allpaths))
-                               break;
-
-                       if (!r) {
-                               /* log only once */
-                               log_safe(LOG_ERR, "can't get mpvec ... retry");
-                               r = 1;
-                       }
-                       sleep(5);
-               }
-               log_safe(LOG_INFO, "multipath list updated");
-               unlock(allpaths->lock);
-
                /*
                 * start waiters on all mpvec
                 */
                log_safe(LOG_INFO, "start up event loops");
 
-               vector_foreach_slot (mpvec, mpp, i) {
+               vector_foreach_slot (allpaths->mpvec, mpp, i) {
                        /*
                         * find out if devmap already has
                         * a running waiter thread
@@ -608,6 +550,8 @@ waiterloop (void *ap)
                        log_safe(LOG_NOTICE, "event checker started : %s",
                                        wp->mapname);
                }
+               unlock(allpaths->lock);
+
                vector_foreach_slot (waiters, wp, i) {
                        if (wp->lease == 0) {
                                log_safe(LOG_NOTICE, "reap event checker : %s",
@@ -636,6 +580,32 @@ waiterloop (void *ap)
        return NULL;
 }
 
+/*
+ * caller must have locked the path list before calling that function
+ */
+static void
+switch_pathgroup (struct multipath * mpp)
+{
+       struct pathgroup * pgp;
+       struct path * pp;
+       int i, j;
+       
+       if (!mpp || mpp->pgfailback == FAILBACK_MANUAL)
+               return;
+
+       /*
+        * Refresh path priority values
+        */
+       vector_foreach_slot (mpp->pg, pgp, i)
+               vector_foreach_slot (pgp->paths, pp, j)
+                       pathinfo(pp, conf->hwtable, DI_PRIO);
+
+       select_path_group(mpp);
+       dm_switchgroup(mpp->alias, mpp->nextpg);
+       log_safe(LOG_NOTICE, "%s: switch to path group #%i",
+                mpp->alias, mpp->nextpg);
+}
+
 /*
  * caller must have locked the path list before calling that function
  */
@@ -657,8 +627,6 @@ checkerloop (void *ap)
        struct path *pp;
        int i;
        int newstate;
-       char buff[1];
-       char cmd[CMDSIZE];
        char checker_msg[MAX_CHECKER_MSG_SIZE];
 
        mlockall(MCL_CURRENT | MCL_FUTURE);
@@ -725,19 +693,9 @@ checkerloop (void *ap)
                                reinstate_path(pp);
 
                                /*
-                                * only for switchgroup now
+                                * need to switch group ?
                                 */
-                               if (safe_snprintf(cmd, CMDSIZE, "%s %s",
-                                                 conf->multipath, pp->dev_t)) {
-                                       log_safe(LOG_ERR, "command too long,"
-                                                       " abord reconfigure");
-                               } else {
-                                       log_safe(LOG_DEBUG, "%s", cmd);
-                                       log_safe(LOG_INFO,
-                                               "%s: reconfigure multipath",
-                                               pp->dev_t);
-                                       execute_program(cmd, buff, 1);
-                               }
+                               switch_pathgroup(pp->mpp);
 
                                /*
                                 * tell waiterloop we have an event
@@ -788,9 +746,17 @@ init_paths (void)
        if (!allpaths->pathvec)
                goto out1;
                
-       pthread_mutex_init (allpaths->lock, NULL);
+       allpaths->mpvec = vector_alloc();
+
+       if (!allpaths->mpvec)
+               goto out2;
+       
+       pthread_mutex_init(allpaths->lock, NULL);
+
+       return allpaths;
 
-       return (allpaths);
+out2:
+       vector_free(allpaths->pathvec);
 out1:
        FREE(allpaths->lock);
 out:
@@ -1038,6 +1004,11 @@ child (void * param)
        if (!allpaths || init_event())
                exit(1);
 
+       if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
+               log_safe(LOG_ERR, "can not find sysfs mount point");
+               exit(1);
+       }
+
 #ifdef CLONE_NEWNS
        if (prepare_namespace() < 0) {
                log_safe(LOG_ERR, "cannot prepare namespace");
@@ -1045,6 +1016,14 @@ child (void * param)
        }
 #endif
 
+       /*
+        * fetch paths and multipaths lists
+        * no paths and/or no multipaths are valid scenarii
+        * vectors maintenance will be driven by events
+        */
+       path_discovery(allpaths->pathvec, conf, DI_SYSFS | DI_WWID);
+       get_dm_mpvec(allpaths);
+
        /*
         * start threads
         */