]> sourceware.org Git - lvm2.git/commitdiff
Implement dmeventd -R, allowing dmeventd to be restarted without losing
authorPetr Rockai <prokai@redhat.com>
Wed, 20 Oct 2010 15:12:12 +0000 (15:12 +0000)
committerPetr Rockai <prokai@redhat.com>
Wed, 20 Oct 2010 15:12:12 +0000 (15:12 +0000)
monitoring state.

daemons/dmeventd/.exported_symbols
daemons/dmeventd/dmeventd.c
daemons/dmeventd/dmeventd.h
daemons/dmeventd/libdevmapper-event.c
libdm/libdm-file.c

index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..25690c8d1b7d574a225415e9aa1748f1d60a7040 100644 (file)
@@ -0,0 +1,3 @@
+init_fifos
+fini_fifos
+daemon_talk
index 4889b7cf2bc896dc1731512887e7460bb9ca1e84..639f200ad59cf93abd18462de13885d65f15fdb9 100644 (file)
@@ -99,6 +99,8 @@ static pthread_mutex_t _global_mutex;
 
 int dmeventd_debug = 0;
 static int _foreground = 0;
+static int _restart = 0;
+static char **_initial_registrations = 0;
 
 /* Data kept about a DSO. */
 struct dso_data {
@@ -444,6 +446,61 @@ static struct thread_status *_lookup_thread_status(struct message_data *data)
        return NULL;
 }
 
+static int _get_status(struct message_data *message_data)
+{
+       struct dm_event_daemon_message *msg = message_data->msg;
+       struct thread_status *thread;
+       int i = 0, j = 0;
+       int ret = -1;
+       int count = dm_list_size(&_thread_registry);
+       int size = 0, current = 0;
+       char *buffers[count];
+       char *message;
+
+       dm_free(msg->data);
+
+       for (i = 0; i < count; ++i)
+               buffers[i] = NULL;
+
+       i = 0;
+       _lock_mutex();
+       dm_list_iterate_items(thread, &_thread_registry) {
+               if ((current = dm_asprintf(buffers + i, "0:%d %s %s %u %" PRIu32 ";",
+                                          i, thread->dso_data->dso_name,
+                                          thread->device.uuid, thread->events,
+                                          thread->timeout)) < 0) {
+                       _unlock_mutex();
+                       goto out;
+               }
+               ++ i;
+               size += current;
+       }
+       _unlock_mutex();
+
+       msg->size = size + strlen(message_data->id) + 1;
+       msg->data = dm_malloc(msg->size);
+       if (!msg->data)
+               goto out;
+       *msg->data = 0;
+
+       message = msg->data;
+       strcpy(message, message_data->id);
+       message += strlen(message_data->id);
+       *message = ' ';
+       message ++;
+       for (j = 0; j < i; ++j) {
+               strcpy(message, buffers[j]);
+               message += strlen(buffers[j]);
+       }
+
+       ret = 0;
+ out:
+       for (j = 0; j < i; ++j)
+               dm_free(buffers[j]);
+       return ret;
+
+}
+
 /* Cleanup at exit. */
 static void _exit_dm_lib(void)
 {
@@ -1343,6 +1400,7 @@ static int _handle_request(struct dm_event_daemon_message *msg,
                { DM_EVENT_CMD_SET_TIMEOUT, _set_timeout},
                { DM_EVENT_CMD_GET_TIMEOUT, _get_timeout},
                { DM_EVENT_CMD_ACTIVE, _active},
+               { DM_EVENT_CMD_GET_STATUS, _get_status},
        }, *req;
 
        for (req = requests; req < requests + sizeof(requests); req++)
@@ -1362,11 +1420,12 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
        /* Parse the message. */
        memset(&message_data, 0, sizeof(message_data));
        message_data.msg = msg;
-       if (msg->cmd == DM_EVENT_CMD_HELLO)  {
+       if (msg->cmd == DM_EVENT_CMD_HELLO || msg->cmd == DM_EVENT_CMD_DIE)  {
                ret = 0;
                answer = msg->data;
                if (answer) {
-                       msg->size = dm_asprintf(&(msg->data), "%s HELLO", answer);
+                       msg->size = dm_asprintf(&(msg->data), "%s %s", answer,
+                                               msg->cmd == DM_EVENT_CMD_DIE ? "DYING" : "HELLO");
                        dm_free(answer);
                } else {
                        msg->size = 0;
@@ -1390,6 +1449,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
 /* Only one caller at a time. */
 static void _process_request(struct dm_event_fifos *fifos)
 {
+       int die = 0;
        struct dm_event_daemon_message msg;
 
        memset(&msg, 0, sizeof(msg));
@@ -1401,6 +1461,9 @@ static void _process_request(struct dm_event_fifos *fifos)
        if (!_client_read(fifos, &msg))
                return;
 
+       if (msg.cmd == DM_EVENT_CMD_DIE)
+               die = 1;
+
        /* _do_process_request fills in msg (if memory allows for
           data, otherwise just cmd and size = 0) */
        _do_process_request(&msg);
@@ -1408,9 +1471,26 @@ static void _process_request(struct dm_event_fifos *fifos)
        if (!_client_write(fifos, &msg))
                stack;
 
+       if (die) raise(9);
+
        dm_free(msg.data);
 }
 
+static void _process_initial_registrations()
+{
+       int i = 0;
+       char *reg;
+       struct dm_event_daemon_message msg = { 0, 0, NULL };
+
+       while ((reg = _initial_registrations[i])) {
+               msg.cmd = DM_EVENT_CMD_REGISTER_FOR_EVENT;
+               msg.size = strlen(reg);
+               msg.data = reg;
+               _do_process_request(&msg);
+               ++ i;
+       }
+}
+
 static void _cleanup_unused_threads(void)
 {
        int ret;
@@ -1616,6 +1696,56 @@ static void _daemonize(void)
        setsid();
 }
 
+static void restart()
+{
+       struct dm_event_fifos fifos;
+       struct dm_event_daemon_message msg = { 0, 0, NULL };
+       int i, count = 0;
+       char *message;
+       int length;
+
+       /* Get the list of registrations from the running daemon. */
+
+       if (!init_fifos(&fifos)) {
+               fprintf(stderr, "Could not initiate communication with existing dmeventd.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)) {
+               fprintf(stderr, "Could not communicate with existing dmeventd.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) {
+               exit(EXIT_FAILURE);
+       }
+
+       message = msg.data;
+       message = strchr(message, ' ');
+       ++ message;
+       length = strlen(msg.data);
+       for (i = 0; i < length; ++i) {
+               if (msg.data[i] == ';') {
+                       msg.data[i] = 0;
+                       ++count;
+               }
+       }
+
+       _initial_registrations = dm_malloc(sizeof(char*) * (count + 1));
+       for (i = 0; i < count; ++i) {
+               _initial_registrations[i] = dm_strdup(message);
+               message += strlen(message) + 1;
+       }
+       _initial_registrations[count] = 0;
+
+       if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) {
+               fprintf(stderr, "Old dmeventd refused to die.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       fini_fifos(&fifos);
+}
+
 static void usage(char *prog, FILE *file)
 {
        fprintf(file, "Usage:\n");
@@ -1638,7 +1768,7 @@ int main(int argc, char *argv[])
        opterr = 0;
        optind = 0;
 
-       while ((opt = getopt(argc, argv, "?fhVd")) != EOF) {
+       while ((opt = getopt(argc, argv, "?fhVdR")) != EOF) {
                switch (opt) {
                case 'h':
                        usage(argv[0], stdout);
@@ -1646,6 +1776,9 @@ int main(int argc, char *argv[])
                case '?':
                        usage(argv[0], stderr);
                        exit(0);
+               case 'R':
+                       _restart++;
+                       break;
                case 'f':
                        _foreground++;
                        break;
@@ -1667,6 +1800,9 @@ int main(int argc, char *argv[])
        if (setenv("LANG", "C", 1))
                perror("Cannot set LANG to C");
 
+       if (_restart)
+               restart();
+
        if (!_foreground)
                _daemonize();
 
@@ -1706,6 +1842,9 @@ int main(int argc, char *argv[])
                kill(getppid(), SIGTERM);
        syslog(LOG_NOTICE, "dmeventd ready for processing.");
 
+       if (_initial_registrations)
+               _process_initial_registrations();
+
        while (!_exit_now) {
                _process_request(&fifos);
                _cleanup_unused_threads();
index 0bf8082d0acd977813727e9e8734c30211b0ece6..254758e16fb5e4950f8e91a6edfdbd7e58f1e3d1 100644 (file)
@@ -35,6 +35,8 @@ enum dm_event_command {
        DM_EVENT_CMD_SET_TIMEOUT,
        DM_EVENT_CMD_GET_TIMEOUT,
        DM_EVENT_CMD_HELLO,
+       DM_EVENT_CMD_DIE,
+       DM_EVENT_CMD_GET_STATUS,
 };
 
 /* Message passed between client and daemon. */
@@ -63,4 +65,12 @@ struct dm_event_fifos {
 #define EXIT_FIFO_FAILURE        6
 #define EXIT_CHDIR_FAILURE       7
 
+/* Implemented in libdevmapper-event.c, but not part of public API. */
+int daemon_talk(struct dm_event_fifos *fifos,
+               struct dm_event_daemon_message *msg, int cmd,
+               const char *dso_name, const char *dev_name,
+               enum dm_event_mask evmask, uint32_t timeout);
+int init_fifos(struct dm_event_fifos *fifos);
+void fini_fifos(struct dm_event_fifos *fifos);
+
 #endif /* __DMEVENTD_DOT_H__ */
index 61ca340c000d51379415785e0dcafa4102cc46ff..abbb968a178f0b9407c7be2a2b2fdea783df8be3 100644 (file)
@@ -276,7 +276,6 @@ static int _daemon_read(struct dm_event_fifos *fifos,
                dm_free(msg->data);
                msg->data = NULL;
        }
-
        return bytes == size;
 }
 
@@ -341,13 +340,13 @@ static int _daemon_write(struct dm_event_fifos *fifos,
        return bytes == size;
 }
 
-static int _daemon_talk(struct dm_event_fifos *fifos,
-                       struct dm_event_daemon_message *msg, int cmd,
-                       const char *dso_name, const char *dev_name,
-                       enum dm_event_mask evmask, uint32_t timeout)
+int daemon_talk(struct dm_event_fifos *fifos,
+               struct dm_event_daemon_message *msg, int cmd,
+               const char *dso_name, const char *dev_name,
+               enum dm_event_mask evmask, uint32_t timeout)
 {
-       const char *dso = dso_name ? dso_name : "";
-       const char *dev = dev_name ? dev_name : "";
+       const char *dso = dso_name ? dso_name : "-";
+       const char *dev = dev_name ? dev_name : "-";
        const char *fmt = "%d:%d %s %s %u %" PRIu32;
        int msg_size;
        memset(msg, 0, sizeof(*msg));
@@ -452,6 +451,7 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 
        else if (!pid) {
                execvp(args[0], args);
+               log_error("Unable to exec dmeventd: %s", strerror(errno));
                _exit(EXIT_FAILURE);
        } else {
                if (waitpid(pid, &status, 0) < 0)
@@ -466,24 +466,15 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
        return ret;
 }
 
-/* Initialize client. */
-static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos)
+int init_fifos(struct dm_event_fifos *fifos)
 {
        /* FIXME? Is fifo the most suitable method? Why not share
           comms/daemon code with something else e.g. multipath? */
 
-       /* init fifos */
-       memset(fifos, 0, sizeof(*fifos));
-
        /* FIXME Make these either configurable or depend directly on dmeventd_path */
        fifos->client_path = DM_EVENT_FIFO_CLIENT;
        fifos->server_path = DM_EVENT_FIFO_SERVER;
 
-       if (!_start_daemon(dmeventd_path, fifos)) {
-               stack;
-               return 0;
-       }
-
        /* Open the fifo used to read from the daemon. */
        if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
                log_error("%s: open server fifo %s",
@@ -511,7 +502,23 @@ static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos)
        return 1;
 }
 
-static void _dtr_client(struct dm_event_fifos *fifos)
+/* Initialize client. */
+static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos)
+{
+       /* init fifos */
+       memset(fifos, 0, sizeof(*fifos));
+
+       /* FIXME Make these either configurable or depend directly on dmeventd_path */
+       fifos->client_path = DM_EVENT_FIFO_CLIENT;
+       fifos->server_path = DM_EVENT_FIFO_SERVER;
+
+       if (!_start_daemon(dmeventd_path, fifos))
+               return_0;
+
+       return init_fifos(fifos);
+}
+
+void fini_fifos(struct dm_event_fifos *fifos)
 {
        if (flock(fifos->server, LOCK_UN))
                log_error("flock unlock %s", fifos->server_path);
@@ -576,16 +583,16 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
                return -ESRCH;
        }
 
-       ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
+       ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 
        dm_free(msg->data);
        msg->data = 0;
 
        if (!ret)
-               ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
+               ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
 
        /* what is the opposite of init? */
-       _dtr_client(&fifos);
+       fini_fifos(&fifos);
 
        return ret;
 }
index b72b2abe0eed0adf79ea67b47eae1619e6431ff3..82fae342859ec97a1de014e53a4882667212b071 100644 (file)
@@ -92,6 +92,7 @@ int dm_create_lockfile(const char *lockfile)
        ssize_t write_out;
        struct flock lock;
        char buffer[50];
+       int retries = 0;
 
        if((fd = open(lockfile, O_CREAT | O_WRONLY,
                      (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
@@ -112,9 +113,15 @@ retry_fcntl:
                        break;
                case EACCES:
                case EAGAIN:
-                       log_error("Cannot lock lockfile [%s], error was [%s]",
-                                  lockfile, strerror(errno));
-                       break;
+                       if (retries == 20) {
+                               log_error("Cannot lock lockfile [%s], error was [%s]",
+                                         lockfile, strerror(errno));
+                               break;
+                       } else {
+                               ++ retries;
+                               usleep(1000);
+                               goto retry_fcntl;
+                       }
                default:
                        log_error("process is already running");
                }
This page took 0.053938 seconds and 5 git commands to generate.