Serialize startup on large machines
authorHannes Reinecke <hare@suse.de>
Tue, 4 May 2010 09:02:37 +0000 (11:02 +0200)
committerHannes Reinecke <hare@suse.de>
Wed, 18 May 2011 11:21:17 +0000 (13:21 +0200)
On large installations the startup can take quite long.
So to better integration with the init scripts I've added
the CLI command 'show daemon' which returns the internal
running state of the daemon.
With this the init scripts can wait until the daemon
is properly started.

Signed-off-by: Hannes Reinecke <hare@suse.de>
multipathd/cli.c
multipathd/cli.h
multipathd/cli_handlers.c
multipathd/cli_handlers.h
multipathd/main.c
multipathd/main.h
multipathd/multipathd.init.suse

index 782d8868a060eb634a144134e72a34ca2fea6fb7..4c90ef9ed6801380d98435bbcfb63ab44faa3683 100644 (file)
@@ -170,6 +170,7 @@ load_keys (void)
        r += add_key(keys, "multipath", MAP, 1);
        r += add_key(keys, "group", GROUP, 1);
        r += add_key(keys, "reconfigure", RECONFIGURE, 0);
+       r += add_key(keys, "daemon", DAEMON, 0);
        r += add_key(keys, "status", STATUS, 0);
        r += add_key(keys, "stats", STATS, 0);
        r += add_key(keys, "topology", TOPOLOGY, 0);
@@ -419,6 +420,7 @@ cli_init (void) {
        add_handler(LIST+PATHS, NULL);
        add_handler(LIST+PATHS+FMT, NULL);
        add_handler(LIST+STATUS, NULL);
+       add_handler(LIST+DAEMON, NULL);
        add_handler(LIST+MAPS, NULL);
        add_handler(LIST+MAPS+STATUS, NULL);
        add_handler(LIST+MAPS+STATS, NULL);
index 8971ff6d2401d0a44ace883ded1627b1b8932c74..7f03bf3fda4602b97fa2559d290f1b84d9dddd24 100644 (file)
@@ -16,6 +16,7 @@ enum {
        __MAP,
        __GROUP,
        __RECONFIGURE,
+       __DAEMON,
        __STATUS,
        __STATS,
        __TOPOLOGY,
@@ -45,6 +46,7 @@ enum {
 #define MAP            (1 << __MAP)
 #define GROUP          (1 << __GROUP)
 #define RECONFIGURE    (1 << __RECONFIGURE)
+#define DAEMON         (1 << __DAEMON)
 #define STATUS         (1 << __STATUS)
 #define STATS          (1 << __STATS)
 #define TOPOLOGY       (1 << __TOPOLOGY)
index 3c4d838bb8ee8b0f3a94a848b7373fd8e7b4b1bd..39ca6fe11c14eae35c4f1b928a564708876f19bd 100644 (file)
@@ -281,6 +281,26 @@ show_status (char ** r, int *len, struct vectors * vecs)
        return 0;
 }
 
+int
+show_daemon (char ** r, int *len)
+{
+       char * c;
+       char * reply;
+
+       unsigned int maxlen = INITIAL_REPLY_LEN;
+       reply = MALLOC(maxlen);
+
+       if (!reply)
+               return 1;
+
+       c = reply;
+       c += snprintf(c, INITIAL_REPLY_LEN, "%s\n", daemon_status());
+
+       *r = reply;
+       *len = (int)(c - reply + 1);
+       return 0;
+}
+
 int
 show_maps (char ** r, int *len, struct vectors * vecs, char * style)
 {
@@ -367,6 +387,14 @@ cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
        return show_maps(reply, len, vecs, PRINT_MAP_STATS);
 }
 
+int
+cli_list_daemon (void * v, char ** reply, int * len, void * data)
+{
+       condlog(3, "list daemon (operator)");
+
+       return show_daemon(reply, len);
+}
+
 int
 cli_add_path (void * v, char ** reply, int * len, void * data)
 {
index 8fe9e06dcf7ed23120d10c2492110ec569f3170b..eae308d51cb8d271344b5a0c268cc685f744c68c 100644 (file)
@@ -1,6 +1,7 @@
 int cli_list_paths (void * v, char ** reply, int * len, void * data);
 int cli_list_paths_fmt (void * v, char ** reply, int * len, void * data);
 int cli_list_status (void * v, char ** reply, int * len, void * data);
+int cli_list_daemon (void * v, char ** reply, int * len, void * data);
 int cli_list_maps (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_fmt (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
index d11ecdcdbfc88224a43e788de9967c9987123d9f..9eb534f9fd40d19b303f63f7c18acbeb314209d7 100644 (file)
@@ -69,6 +69,7 @@ pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
 pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 int logsink;
+enum daemon_status running_state;
 
 /*
  * global copy of vecs for use in sig handlers
@@ -780,6 +781,7 @@ uxlsnrloop (void * ap)
        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+DAEMON, cli_list_daemon);
        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+FMT, cli_list_maps_fmt);
@@ -830,6 +832,24 @@ exit_daemon (int status)
        return status;
 }
 
+const char *
+daemon_status(void)
+{
+       switch (running_state) {
+       case DAEMON_INIT:
+               return "init";
+       case DAEMON_START:
+               return "startup";
+       case DAEMON_CONFIGURE:
+               return "configure";
+       case DAEMON_RUNNING:
+               return "running";
+       case DAEMON_SHUTDOWN:
+               return "shutdown";
+       }
+       return NULL;
+}
+
 static void
 fail_path (struct path * pp, int del_active)
 {
@@ -1336,6 +1356,9 @@ sighup (int sig)
 {
        condlog(2, "reconfigure (SIGHUP)");
 
+       if (running_state != DAEMON_RUNNING)
+               return;
+
        reconfigure(gvecs);
 
 #ifdef _DEBUG_
@@ -1415,6 +1438,8 @@ child (void * param)
                pthread_attr_destroy(&log_attr);
        }
 
+       running_state = DAEMON_START;
+
        condlog(2, "--------start up--------");
        condlog(2, "read " DEFAULT_CONFIGFILE);
 
@@ -1493,10 +1518,16 @@ child (void * param)
                condlog(0, "failed to create uevent thread: %d", rc);
                exit(1);
        }
+       if ((rc = pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs))) {
+               condlog(0, "failed to create cli listener: %d", rc);
+               exit(1);
+       }
        /*
         * fetch and configure both paths and multipaths
         */
        lock(vecs->lock);
+       running_state = DAEMON_CONFIGURE;
+
        if (configure(vecs, 1)) {
                unlock(vecs->lock);
                condlog(0, "failure during configuration");
@@ -1511,10 +1542,6 @@ child (void * param)
                condlog(0,"failed to create checker loop thread: %d", rc);
                exit(1);
        }
-       if ((rc = pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs))) {
-               condlog(0, "failed to create cli listener: %d", rc);
-               exit(1);
-       }
        if ((rc = pthread_create(&uevq_thr, &misc_attr, uevqloop, vecs))) {
                condlog(0, "failed to create uevent dispatcher: %d", rc);
                exit(1);
@@ -1522,11 +1549,20 @@ child (void * param)
        pthread_attr_destroy(&misc_attr);
 
        pthread_mutex_lock(&exit_mutex);
+       /* Startup complete, create logfile */
+       if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
+               if (logsink)
+                       log_thread_stop();
+
+               exit(1);
+       }
+       running_state = DAEMON_RUNNING;
        pthread_cond_wait(&exit_cond, &exit_mutex);
 
        /*
         * exit path
         */
+       running_state = DAEMON_SHUTDOWN;
        block_signal(SIGHUP, NULL);
        lock(vecs->lock);
        if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
@@ -1643,6 +1679,7 @@ main (int argc, char *argv[])
        int err;
 
        logsink = 1;
+       running_state = DAEMON_INIT;
        dm_init();
 
        if (getuid() != 0) {
index f8487c064c03e8a9b7e8115552d0af738323c51c..87f24c72146f38d4d5fcc473df609cab3c9dbf01 100644 (file)
@@ -3,7 +3,16 @@
 
 #define MAPGCINT 5
 
+enum daemon_status {
+    DAEMON_INIT,
+    DAEMON_START,
+    DAEMON_CONFIGURE,
+    DAEMON_RUNNING,
+    DAEMON_SHUTDOWN,
+};
+
 int exit_daemon(int);
+const char * daemon_status(void);
 int reconfigure (struct vectors *);
 int ev_add_path (char *, struct vectors *);
 int ev_remove_path (char *, struct vectors *);
index d8513546cb5f6dc47cb2a00ba3884aabc73d13c9..9059faa85a9031afa5b8a37da323ca31dfd291a4 100644 (file)
@@ -25,6 +25,9 @@ PIDFILE=/var/run/multipathd.pid
 # Set the maximum number of open files
 MAX_OPEN_FDS=4096
 
+# Set to enable asynchronous daemon startup
+DAEMON_ASYNC_STARTUP=
+
 test -x $DAEMON || exit 5
 
 . /etc/rc.status
@@ -43,13 +46,29 @@ case "$1" in
            ulimit -n $MAX_OPEN_FDS
        fi
 
-       if [ -f $PIDFILE ]; then
-               PID="$(cat $PIDFILE)"
-               PROCNAME="$(ps -o cmd --no-headers $PID)"
-       fi
+       $DAEMON $ARGS
 
-       if [ "$PROCNAME" != "$DAEMON" ]; then
-               $DAEMON
+       if [ -n "$DAEMON_ASYNC_STARTUP" ] ; then
+           rc_status -v
+           rc_exit
+       fi
+       # Wait for the daemon to start up
+       timeout=$MPATH_INIT_TIMEOUT
+       while [ ! -f $PIDFILE ] ; do
+           sleep 1
+           status=$(multipathd -k'show daemon' 2> /dev/null)
+           if [ "$status" == "configure" ] ; then
+               # Daemon is still configuring, do not increase
+               # the timeout
+               continue
+           fi
+           timeout=$(( $timeout - 1 ))
+           [ $timeout -eq 0 ] && break
+       done
+       if [ $timeout -eq 0 ] ; then
+           echo -n " (no pidfile)"
+           rc_failed 1
+t.suse
        fi
        
        # Remember status and be verbose
@@ -66,7 +85,18 @@ case "$1" in
                PROCNAME="$(ps -o cmd --no-headers $PID)"
        fi
 
-       if [ "$PROCNAME" == "$DAEMON" ]; then
+       timeout=$MPATH_INIT_TIMEOUT
+       while [ $timeout -gt 0 ] ; do
+           status=$($DAEMON -k'show daemon' 2> /dev/null)
+           [ "$status" == "configure" ] && continue
+           [ "$status" == "running" ] && break
+           sleep 1
+           timeout=$(( $timeout - 1 ))
+       done
+
+       status=$($DAEMON -k'shutdown' 2> /dev/null)
+       if [ "$status" != "ok" ] ; then
+           if [ "$PROCNAME" == `basename $DAEMON` ]; then
                kill -TERM $PID
        fi