[multipathd] add "show wildcards" cli command
[platform/upstream/multipath-tools.git] / multipathd / main.c
index f887ad0..84fb5c4 100644 (file)
@@ -12,6 +12,8 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 /*
  * libcheckers
@@ -43,6 +45,7 @@
 #include <switchgroup.h>
 #include <print.h>
 #include <configure.h>
+#include <prio.h>
 
 #include "main.h"
 #include "pidfile.h"
@@ -62,6 +65,8 @@
 pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
 pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+int logsink;
+
 /*
  * global copy of vecs for use in sig handlers
  */
@@ -116,7 +121,7 @@ coalesce_maps(struct vectors *vecs, vector nmpv)
                         * remove all current maps not allowed by the
                         * current configuration
                         */
-                       if (dm_flush_map(ompp->alias, DEFAULT_TARGET)) {
+                       if (dm_flush_map(ompp->alias)) {
                                condlog(0, "%s: unable to flush devmap",
                                        ompp->alias);
                                /*
@@ -135,7 +140,7 @@ coalesce_maps(struct vectors *vecs, vector nmpv)
                        }
                        else {
                                dm_lib_release();
-                               condlog(3, "%s devmap removed", ompp->alias);
+                               condlog(2, "%s devmap removed", ompp->alias);
                        }
                }
        }
@@ -149,9 +154,13 @@ sync_map_state(struct multipath *mpp)
        struct path *pp;
        unsigned int i, j;
 
+       if (!mpp->pg)
+               return;
+
        vector_foreach_slot (mpp->pg, pgp, i){
                vector_foreach_slot (pgp->paths, pp, j){
-                       if (pp->state <= PATH_UNCHECKED)
+                       if (pp->state == PATH_UNCHECKED || 
+                           pp->state == PATH_WILD)
                                continue;
                        if ((pp->dmstate == PSTATE_FAILED ||
                             pp->dmstate == PSTATE_UNDEF) &&
@@ -183,7 +192,7 @@ flush_map(struct multipath * mpp, 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)) {
+       if (dm_flush_map(mpp->alias)) {
                /*
                 * May not really be an error -- if the map was already flushed
                 * from the device mapper by dmsetup(8) for instance.
@@ -193,11 +202,11 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
        }
        else {
                dm_lib_release();
-               condlog(3, "%s: devmap removed", mpp->alias);
+               condlog(2, "%s: devmap removed", mpp->alias);
        }
 
        orphan_paths(vecs->pathvec, mpp);
-       remove_map(mpp, vecs, stop_waiter_thread, 1);
+       remove_map_and_stop_waiter(mpp, vecs, 1);
 
        return 0;
 }
@@ -232,7 +241,7 @@ ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
 
        map_present = dm_map_present(alias);
 
-       if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
+       if (map_present && dm_type(alias, TGT_MPATH) <= 0) {
                condlog(4, "%s: not a multipath map", alias);
                return 0;
        }
@@ -253,21 +262,20 @@ ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
        /*
         * now we can register the map
         */
-       if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
-                                       start_waiter_thread))) {
+       if (map_present && (mpp = add_map_without_path(vecs, minor, alias))) {
                sync_map_state(mpp);
-               condlog(3, "%s: devmap %s added", alias, dev->kernel);
+               condlog(2, "%s: devmap %s added", alias, dev->kernel);
                return 0;
        }
        refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec);
 
        if (refwwid) {
-               r = coalesce_paths(vecs, NULL, refwwid);
+               r = coalesce_paths(vecs, NULL, refwwid, 0);
                dm_lib_release();
        }
 
        if (!r)
-               condlog(3, "%s: devmap %s added", alias, dev->kernel);
+               condlog(2, "%s: devmap %s added", alias, dev->kernel);
        else
                condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel);
 
@@ -290,7 +298,7 @@ ev_remove_map (char * devname, struct vectors * vecs)
        mpp = find_mp_by_str(vecs->mpvec, devname);
 
        if (!mpp) {
-               condlog(3, "%s: devmap not registered, can't remove",
+               condlog(2, "%s: devmap not registered, can't remove",
                        devname);
                return 0;
        }
@@ -368,7 +376,7 @@ ev_add_path (char * devname, struct vectors * vecs)
                condlog(0, "%s: failed to get path uid", devname);
                return 1; /* leave path added to pathvec */
        }
-       if (filter_path(conf, pp)){
+       if (filter_path(conf, pp) > 0){
                int i = find_slot(vecs->pathvec, (void *)pp);
                if (i != -1)
                        vector_del_slot(vecs->pathvec, i);
@@ -431,11 +439,11 @@ rescan:
            start_waiter_thread(mpp, vecs))
                        goto out;
 
-       condlog(3, "%s path added to devmap %s", devname, mpp->alias);
+       condlog(2, "%s path added to devmap %s", devname, mpp->alias);
        return 0;
 
 out:
-       remove_map(mpp, vecs, NULL, 1);
+       remove_map(mpp, vecs, 1);
        return 1;
 }
 
@@ -457,8 +465,7 @@ ev_remove_path (char * devname, struct vectors * vecs)
 {
        struct multipath * mpp;
        struct path * pp;
-       int i;
-       int rm_path = 1;
+       int i, retval = 0;
 
        pp = find_path_by_dev(vecs->pathvec, devname);
 
@@ -468,100 +475,81 @@ ev_remove_path (char * devname, struct vectors * vecs)
        }
 
        /*
-        * avoid referring to the map of an orphanned path
+        * avoid referring to the map of an orphaned path
         */
        if ((mpp = pp->mpp)) {
+               /*
+                * transform the mp->pg vector of vectors of paths
+                * into a mp->params string to feed the device-mapper
+                */
+               if (update_mpp_paths(mpp, vecs->pathvec)) {
+                       condlog(0, "%s: failed to update paths",
+                               mpp->alias);
+                       goto out;
+               }
+               if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
+                       vector_del_slot(mpp->paths, i);
 
                /*
                 * remove the map IFF removing the last path
                 */
-               if (pathcount(mpp, PATH_WILD) > 1) {
-                       vector rpvec = vector_alloc();
+               if (VECTOR_SIZE(mpp->paths) == 0) {
+                       char alias[WWID_SIZE];
 
                        /*
-                        * transform the mp->pg vector of vectors of paths
-                        * into a mp->params string to feed the device-mapper
+                        * flush_map will fail if the device is open
                         */
-                       update_mpp_paths(mpp, vecs->pathvec);
-                       if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
-                               vector_del_slot(mpp->paths, i);
-
-                       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, vecs))
-                                       rm_path = 0;
-                               else
-                                       condlog(3, "%s: removed map after removing"
-                                               " multiple paths", alias);
-                       }
-                       else {
-                               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);
-                                       /*
-                                        * Delete path from pathvec so that
-                                        * update_mpp_paths wont find it later
-                                        * when/if another path is removed.
-                                        */
-                                       if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
-                                               vector_del_slot(vecs->pathvec, i);
-                                       free_path(pp);
-                                       return 1;
-                               }
-                               /*
-                                * update our state from kernel
-                                */
-                               if (setup_multipath(vecs, mpp)) {
-                                       free_pathvec(rpvec, KEEP_PATHS);
-                                       goto out;
-                               }
-                               sync_map_state(mpp);
-
-                               condlog(3, "%s: path removed from map %s",
-                                       devname, mpp->alias);
+                       strncpy(alias, mpp->alias, WWID_SIZE);
+                       if (!flush_map(mpp, vecs)) {
+                               condlog(2, "%s: removed map after"
+                                       " removing all paths",
+                                       alias);
+                               free_path(pp);
+                               return 0;
                        }
-                       free_pathvec(rpvec, KEEP_PATHS);
+                       /*
+                        * Not an error, continue
+                        */
                }
-               else {
-                       char alias[WWID_SIZE];
 
+               if (setup_map(mpp)) {
+                       condlog(0, "%s: failed to setup map for"
+                               " removal of path %s", mpp->alias,
+                               devname);
+                       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);
+                       retval = 1;
+               } else {
                        /*
-                        * flush_map will fail if the device is open
+                        * update our state from kernel
                         */
-                       strncpy(alias, mpp->alias, WWID_SIZE);
-                       if (flush_map(mpp, vecs))
-                               rm_path = 0;
-                       else
-                               condlog(3, "%s: removed map", alias);
+                       if (setup_multipath(vecs, mpp)) {
+                               goto out;
+                       }
+                       sync_map_state(mpp);
+
+                       condlog(2, "%s: path removed from map %s",
+                               devname, mpp->alias);
                }
        }
 
-       if (rm_path) {
-               if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
-                       vector_del_slot(vecs->pathvec, i);
-               free_path(pp);
-       }
+       if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
+               vector_del_slot(vecs->pathvec, i);
 
-       return 0;
+       free_path(pp);
+
+       return retval;
 
 out:
-       remove_map(mpp, vecs, stop_waiter_thread, 1);
+       remove_map_and_stop_waiter(mpp, vecs, 1);
        return 1;
 }
 
@@ -571,7 +559,7 @@ map_discovery (struct vectors * vecs)
        struct multipath * mpp;
        unsigned int i;
 
-       if (dm_get_maps(vecs->mpvec, "multipath"))
+       if (dm_get_maps(vecs->mpvec))
                return 1;
 
        vector_foreach_slot (vecs->mpvec, mpp, i)
@@ -704,7 +692,9 @@ uxlsnrloop (void * ap)
                return NULL;
 
        set_handler_callback(LIST+PATHS, cli_list_paths);
+       set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
        set_handler_callback(LIST+MAPS, cli_list_maps);
+       set_handler_callback(LIST+STATUS, cli_list_status);
        set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
        set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
        set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
@@ -713,6 +703,7 @@ uxlsnrloop (void * ap)
        set_handler_callback(LIST+CONFIG, cli_list_config);
        set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
        set_handler_callback(LIST+DEVICES, cli_list_devices);
+       set_handler_callback(LIST+WILDCARDS, cli_list_wildcards);
        set_handler_callback(ADD+PATH, cli_add_path);
        set_handler_callback(DEL+PATH, cli_del_path);
        set_handler_callback(ADD+MAP, cli_add_map);
@@ -809,7 +800,7 @@ mpvec_garbage_collector (struct vectors * vecs)
        vector_foreach_slot (vecs->mpvec, mpp, i) {
                if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
                        condlog(2, "%s: remove dead map", mpp->alias);
-                       remove_map(mpp, vecs, stop_waiter_thread, 1);
+                       remove_map_and_stop_waiter(mpp, vecs, 1);
                        i--;
                }
        }
@@ -1019,12 +1010,15 @@ checkerloop (void *ap)
                lock(vecs->lock);
                condlog(4, "tick");
 
-               vector_foreach_slot (vecs->pathvec, pp, i) {
-                       check_path(vecs, pp);
+               if (vecs->pathvec) {
+                       vector_foreach_slot (vecs->pathvec, pp, i) {
+                               check_path(vecs, pp);
+                       }
+               }
+               if (vecs->mpvec) {
+                       defered_failback_tick(vecs->mpvec);
+                       retry_count_tick(vecs->mpvec);
                }
-               defered_failback_tick(vecs->mpvec);
-               retry_count_tick(vecs->mpvec);
-
                if (count)
                        count--;
                else {
@@ -1062,7 +1056,7 @@ configure (struct vectors * vecs, int start_waiters)
        path_discovery(vecs->pathvec, conf, DI_ALL);
 
        vector_foreach_slot (vecs->pathvec, pp, i){
-               if (filter_path(conf, pp)){
+               if (filter_path(conf, pp) > 0){
                        vector_del_slot(vecs->pathvec, i);
                        free_path(pp);
                        i--;
@@ -1076,7 +1070,7 @@ configure (struct vectors * vecs, int start_waiters)
        /*
         * create new set of maps & push changed ones into dm
         */
-       if (coalesce_paths(vecs, mpvec, NULL))
+       if (coalesce_paths(vecs, mpvec, NULL, 0))
                return 1;
 
        /*
@@ -1093,7 +1087,7 @@ configure (struct vectors * vecs, int start_waiters)
        /*
         * purge dm of old maps
         */
-       remove_maps(vecs, NULL);
+       remove_maps(vecs);
 
        /*
         * save new set of maps formed by considering current path state
@@ -1123,7 +1117,7 @@ reconfigure (struct vectors * vecs)
         * free old map and path vectors ... they use old conf state
         */
        if (VECTOR_SIZE(vecs->mpvec))
-               remove_maps(vecs, stop_waiter_thread);
+               remove_maps_and_stop_waiters(vecs);
 
        if (VECTOR_SIZE(vecs->pathvec))
                free_pathvec(vecs->pathvec, FREE_PATHS);
@@ -1273,6 +1267,15 @@ child (void * param)
        if (load_config(DEFAULT_CONFIGFILE))
                exit(1);
 
+       if (init_checkers()) {
+               condlog(0, "failed to initialize checkers");
+               exit(1);
+       }
+       if (init_prio()) {
+               condlog(0, "failed to initialize prioritizers");
+               exit(1);
+       }
+
        setlogmask(LOG_UPTO(conf->verbosity + 3));
 
        /*
@@ -1283,6 +1286,21 @@ child (void * param)
                conf->max_checkint = MAX_CHECKINT(conf->checkint);
        }
 
+       if (conf->max_fds) {
+               struct rlimit fd_limit;
+               if (conf->max_fds > 0) {
+                       fd_limit.rlim_cur = conf->max_fds;
+                       fd_limit.rlim_max = conf->max_fds;
+               }
+               else {
+                       fd_limit.rlim_cur = RLIM_INFINITY;
+                       fd_limit.rlim_max = RLIM_INFINITY;
+               }
+               if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
+                       condlog(0, "can't set open fds limit to %d : %s\n",
+                               conf->max_fds, strerror(errno));
+       }
+
        if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
                if (logsink)
                        log_thread_stop();
@@ -1327,7 +1345,7 @@ child (void * param)
         * exit path
         */
        lock(vecs->lock);
-       remove_maps(vecs, stop_waiter_thread);
+       remove_maps_and_stop_waiters(vecs);
        free_pathvec(vecs->pathvec, FREE_PATHS);
 
        pthread_cancel(check_thr);
@@ -1348,8 +1366,6 @@ child (void * param)
        vecs->lock = NULL;
        FREE(vecs);
        vecs = NULL;
-       free_config(conf);
-       conf = NULL;
 
        condlog(2, "--------shut down-------");
 
@@ -1359,6 +1375,14 @@ child (void * param)
        dm_lib_release();
        dm_lib_exit();
 
+       /*
+        * Freeing config must be done after condlog() and dm_lib_exit(),
+        * because logging functions like dlog() and dm_write_log()
+        * reference the config.
+        */
+       free_config(conf);
+       conf = NULL;
+
 #ifdef _DEBUG_
        dbg_free_final(NULL);
 #endif