Allow specific CLI commands to run unlocked
authorHannes Reinecke <hare@suse.de>
Thu, 24 Jul 2014 12:03:56 +0000 (14:03 +0200)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Tue, 3 May 2016 07:13:45 +0000 (09:13 +0200)
When multipath is busy with checking paths or processing udev
events it'll take the vector lock, causing the CLI
to become unresponsive.
This patch allows certain CLI commands to not wait for the vector
lock, so that those commands will always succeed.

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

index 3c9cdbf..d991cd0 100644 (file)
@@ -1,9 +1,13 @@
 /*
  * Copyright (c) 2005 Christophe Varoqui
  */
+#include <sys/time.h>
 #include <errno.h>
+#include <pthread.h>
 #include <memory.h>
 #include <vector.h>
+#include <structs.h>
+#include <structs_vec.h>
 #include <parser.h>
 #include <util.h>
 #include <version.h>
@@ -100,6 +104,19 @@ set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *))
        if (!h)
                return 1;
        h->fn = fn;
+       h->locked = 1;
+       return 0;
+}
+
+int
+set_unlocked_handler_callback (unsigned long fp,int (*fn)(void *, char **, int *, void *))
+{
+       struct handler * h = find_handler(fp);
+
+       if (!h)
+               return 1;
+       h->fn = fn;
+       h->locked = 0;
        return 0;
 }
 
@@ -430,11 +447,13 @@ genhelp_handler (const char *cmd, int error)
 }
 
 int
-parse_cmd (char * cmd, char ** reply, int * len, void * data)
+parse_cmd (char * cmd, char ** reply, int * len, void * data, int timeout )
 {
        int r;
        struct handler * h;
        vector cmdvec = NULL;
+       struct timespec tmo;
+       struct timeval now;
 
        r = get_cmdvec(cmd, &cmdvec);
 
@@ -456,7 +475,30 @@ parse_cmd (char * cmd, char ** reply, int * len, void * data)
        /*
         * execute handler
         */
-       r = h->fn(cmdvec, reply, len, data);
+       if (gettimeofday(&now, NULL) == 0) {
+               tmo.tv_sec = now.tv_sec + timeout;
+               tmo.tv_nsec = now.tv_usec * 1000;
+       } else {
+               tmo.tv_sec = 0;
+       }
+       if (h->locked) {
+               struct vectors * vecs = (struct vectors *)data;
+
+               pthread_cleanup_push(cleanup_lock, &vecs->lock);
+               if (tmo.tv_sec) {
+                       vecs->lock.depth++;
+                       r = pthread_mutex_timedlock(vecs->lock.mutex, &tmo);
+               } else {
+                       lock(vecs->lock);
+                       r = 0;
+               }
+               if (r == 0) {
+                       pthread_testcancel();
+                       r = h->fn(cmdvec, reply, len, data);
+               }
+               lock_cleanup_pop(vecs->lock);
+       } else
+               r = h->fn(cmdvec, reply, len, data);
        free_keys(cmdvec);
 
        return r;
index 2aa19d5..84ca40f 100644 (file)
@@ -100,13 +100,15 @@ struct key {
 
 struct handler {
        uint64_t fingerprint;
+       int locked;
        int (*fn)(void *, char **, int *, void *);
 };
 
 int alloc_handlers (void);
 int add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *));
 int set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *));
-int parse_cmd (char * cmd, char ** reply, int * len, void *);
+int set_unlocked_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *));
+int parse_cmd (char * cmd, char ** reply, int * len, void *, int);
 int load_keys (void);
 char * get_keyparam (vector v, uint64_t code);
 void free_keys (vector vec);
index edcbc51..58e8854 100644 (file)
@@ -976,14 +976,13 @@ uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
        *len = 0;
        vecs = (struct vectors *)trigger_data;
 
-       pthread_cleanup_push(cleanup_lock, &vecs->lock);
-       lock(vecs->lock);
-       pthread_testcancel();
-
-       r = parse_cmd(str, reply, len, vecs);
+       r = parse_cmd(str, reply, len, vecs, uxsock_timeout / 1000);
 
        if (r > 0) {
-               *reply = STRDUP("fail\n");
+               if (r == ETIMEDOUT)
+                       *reply = STRDUP("timeout\n");
+               else
+                       *reply = STRDUP("fail\n");
                *len = strlen(*reply) + 1;
                r = 1;
        }
@@ -994,7 +993,6 @@ uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
        }
        /* else if (r < 0) leave *reply alone */
 
-       lock_cleanup_pop(vecs->lock);
        return r;
 }
 
@@ -1114,8 +1112,8 @@ uxlsnrloop (void * ap)
        set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
        set_handler_callback(LIST+PATH, cli_list_path);
        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_unlocked_handler_callback(LIST+STATUS, cli_list_status);
+       set_unlocked_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);
@@ -1125,8 +1123,8 @@ uxlsnrloop (void * ap)
        set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
        set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt);
        set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt);
-       set_handler_callback(LIST+CONFIG, cli_list_config);
-       set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
+       set_unlocked_handler_callback(LIST+CONFIG, cli_list_config);
+       set_unlocked_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);
@@ -1134,7 +1132,7 @@ uxlsnrloop (void * ap)
        set_handler_callback(ADD+MAP, cli_add_map);
        set_handler_callback(DEL+MAP, cli_del_map);
        set_handler_callback(SWITCH+MAP+GROUP, cli_switch_group);
-       set_handler_callback(RECONFIGURE, cli_reconfigure);
+       set_unlocked_handler_callback(RECONFIGURE, cli_reconfigure);
        set_handler_callback(SUSPEND+MAP, cli_suspend);
        set_handler_callback(RESUME+MAP, cli_resume);
        set_handler_callback(RESIZE+MAP, cli_resize);
@@ -1146,8 +1144,8 @@ uxlsnrloop (void * ap)
        set_handler_callback(RESTOREQ+MAP, cli_restore_queueing);
        set_handler_callback(DISABLEQ+MAPS, cli_disable_all_queueing);
        set_handler_callback(RESTOREQ+MAPS, cli_restore_all_queueing);
-       set_handler_callback(QUIT, cli_quit);
-       set_handler_callback(SHUTDOWN, cli_shutdown);
+       set_unlocked_handler_callback(QUIT, cli_quit);
+       set_unlocked_handler_callback(SHUTDOWN, cli_shutdown);
        set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus);
        set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus);
        set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus);