summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2016-08-05 13:08:38 -0500
committerDavid Teigland <teigland@redhat.com>2016-08-09 13:39:50 -0500
commit82a740be3041b29c9bd1e147857ad447916a1072 (patch)
tree5bac0cb70d7a8bd4a08674b730081eaf5ae791d2
parentfc93085c7a7716671c3567d367dd2c75544a058b (diff)
downloadlvm2-dev-dct-lvmetad-helper2.tar.gz
lvmetad: add helper process and uevent monitordev-dct-lvmetad-helper2
so that lvmetad can keep its cache updated by itself without the assistance of externally generated pvscan commands. When lvmetad sees a uevent, it asks its helper process to run pvscan --cache on the device. TODO: error and failure handling -- if anything fails related to the helper or uevents, lvmetad should simply exit.
-rw-r--r--daemons/lvmetad/Makefile.in4
-rw-r--r--daemons/lvmetad/lvmetactl.c34
-rw-r--r--daemons/lvmetad/lvmetad-core.c54
-rw-r--r--daemons/lvmetad/lvmetad-helper.c553
-rw-r--r--daemons/lvmetad/lvmetad-internal.h88
-rw-r--r--libdaemon/server/daemon-server.c14
-rw-r--r--libdaemon/server/daemon-server.h5
7 files changed, 718 insertions, 34 deletions
diff --git a/daemons/lvmetad/Makefile.in b/daemons/lvmetad/Makefile.in
index fa3bdf1da..9e039c93e 100644
--- a/daemons/lvmetad/Makefile.in
+++ b/daemons/lvmetad/Makefile.in
@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
-SOURCES = lvmetad-core.c
+SOURCES = lvmetad-core.c lvmetad-helper.c
SOURCES2 = testclient.c
TARGETS = lvmetad lvmetactl
@@ -31,7 +31,7 @@ include $(top_builddir)/make.tmpl
INCLUDES += -I$(top_srcdir)/libdaemon/server
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
-LIBS += $(PTHREAD_LIBS)
+LIBS += $(PTHREAD_LIBS) -ludev
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS)
CLDFLAGS += -L$(top_builddir)/libdaemon/server
diff --git a/daemons/lvmetad/lvmetactl.c b/daemons/lvmetad/lvmetactl.c
index dd2ee1e6d..1e42335cc 100644
--- a/daemons/lvmetad/lvmetactl.c
+++ b/daemons/lvmetad/lvmetactl.c
@@ -12,6 +12,8 @@
#include "lvmetad-client.h"
+#define ARGS_SIZE 128 /* FIXME: get from header */
+
daemon_handle h;
static void print_reply(daemon_reply reply)
@@ -45,6 +47,7 @@ int main(int argc, char **argv)
printf("lvmetactl set_global_disable 0|1\n");
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
printf("lvmetactl vg_lock_type <uuid>\n");
+ printf("lvmetactl helper_run <path> <args>\n");
return -1;
}
@@ -237,6 +240,37 @@ int main(int argc, char **argv)
NULL);
printf("%s\n", reply.buffer.mem);
+ } else if (!strcmp(cmd, "helper_run")) {
+ char args[ARGS_SIZE];
+ int i;
+
+ memset(args, 0, ARGS_SIZE);
+
+ if (argc < 3) {
+ printf("helper_run <path> [<args>]\n");
+ return -1;
+ }
+
+ if (argc > 3) {
+ for (i = 3; i < argc; i++) {
+ if (strlen(argv[i]) + strlen(args) + 2 > ARGS_SIZE) {
+ printf("args too long\n");
+ return -1;
+ }
+ strcat(args, argv[i]);
+ strcat(args, " ");
+ }
+ }
+
+ reply = daemon_send_simple(h, "helper_run",
+ "token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
+ "runpath = %s", argv[2],
+ "runargs = %s", args[0] ? args : "",
+ NULL);
+ printf("%s\n", reply.buffer.mem);
+
} else {
printf("unknown command\n");
goto out_close;
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index ebaca7872..b9ae10868 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -22,6 +22,7 @@
#include "daemon-server.h"
#include "daemon-log.h"
#include "lvm-version.h"
+#include "lvmetad-internal.h"
#include "lvmetad-client.h"
#include <assert.h>
@@ -203,38 +204,10 @@ struct vg_info {
#define GLFL_DISABLE_REASON_LVM1 0x00000008
#define GLFL_DISABLE_REASON_DUPLICATES 0x00000010
#define GLFL_DISABLE_REASON_VGRESTORE 0x00000020
-
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
#define VGFL_INVALID 0x00000001
-#define CMD_NAME_SIZE 32
-
-typedef struct {
- daemon_idle *idle;
- log_state *log; /* convenience */
- const char *log_config;
-
- struct dm_hash_table *pvid_to_pvmeta;
- struct dm_hash_table *device_to_pvid; /* shares locks with above */
-
- struct dm_hash_table *vgid_to_metadata;
- struct dm_hash_table *vgid_to_vgname;
- struct dm_hash_table *vgid_to_outdated_pvs;
- struct dm_hash_table *vgid_to_info;
- struct dm_hash_table *vgname_to_vgid;
- struct dm_hash_table *pvid_to_vgid;
- char token[128];
- char update_cmd[CMD_NAME_SIZE];
- int update_pid;
- int update_timeout;
- uint64_t update_begin;
- uint32_t flags; /* GLFL_ */
- pthread_mutex_t token_lock;
- pthread_mutex_t info_lock;
- pthread_rwlock_t cache_lock;
-} lvmetad_state;
-
static uint64_t _monotonic_seconds(void)
{
struct timespec ts;
@@ -2655,7 +2628,9 @@ static response dump(lvmetad_state *s)
return res;
}
-static response handler(daemon_state s, client_handle h, request r)
+/* called in context of a per-connection thread */
+
+static response client_handler(daemon_state s, client_handle h, request r)
{
response res;
lvmetad_state *state = s.private;
@@ -2822,7 +2797,8 @@ static response handler(daemon_state s, client_handle h, request r)
}
if (!strcmp(rq, "set_global_info") ||
- !strcmp(rq, "get_global_info")) {
+ !strcmp(rq, "get_global_info") ||
+ !strcmp(rq, "helper_run")) {
pthread_mutex_lock(&state->info_lock);
info_lock = 1;
goto do_rq;
@@ -2872,6 +2848,11 @@ static response handler(daemon_state s, client_handle h, request r)
else if (!strcmp(rq, "dump"))
res = dump(state);
+ else if (!strcmp(rq, "helper_run")) {
+ send_helper_request(&s, r);
+ res = daemon_reply_simple("OK", NULL );
+ }
+
else
res = reply_fail("request not implemented");
@@ -2909,6 +2890,9 @@ static int init(daemon_state *s)
if (ls->idle)
ls->idle->is_idle = 1;
+ if (ls->enable_udev_monitor)
+ setup_udev_monitor(s);
+
return 1;
}
@@ -2958,7 +2942,7 @@ int main(int argc, char *argv[])
daemon_state s = {
.daemon_fini = fini,
.daemon_init = init,
- .handler = handler,
+ .handler = client_handler,
.name = "lvmetad",
.pidfile = getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE,
.private = &ls,
@@ -2968,7 +2952,7 @@ int main(int argc, char *argv[])
};
// use getopt_long
- while ((opt = getopt(argc, argv, "?fhVl:p:s:t:")) != EOF) {
+ while ((opt = getopt(argc, argv, "?fhVl:p:s:t:u:")) != EOF) {
switch (opt) {
case 'h':
usage(argv[0], stdout);
@@ -2997,13 +2981,19 @@ int main(int argc, char *argv[])
if (di.max_timeouts)
s.idle = ls.idle = &di;
break;
+ case 'u':
+ ls.enable_udev_monitor = atoi(optarg);
+ break;
case 'V':
printf("lvmetad version: " LVM_VERSION "\n");
exit(1);
}
}
+ setup_helper(&s);
+
daemon_start(s);
return 0;
}
+
diff --git a/daemons/lvmetad/lvmetad-helper.c b/daemons/lvmetad/lvmetad-helper.c
new file mode 100644
index 000000000..3922cd71a
--- /dev/null
+++ b/daemons/lvmetad/lvmetad-helper.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _XOPEN_SOURCE 500 /* pthread */
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <grp.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "libudev.h"
+
+#include "tool.h"
+
+#include "daemon-io.h"
+#include "daemon-server.h"
+#include "daemon-log.h"
+#include "lvm-version.h"
+#include "lvmetad-internal.h"
+#include "lvmetad-client.h"
+
+/*
+ * lvmetad_main is the main process that:
+ * . forks threads to handle client (command) connections
+ * . receives client requests from socket
+ * . reads/writes cache state
+ * . receives uevent messages
+ * . sends lvmetad_helper pvscan requests for uevents
+ * . sends lvmetad_helper client requests from lvmetactl
+ *
+ * lvmetad_helper is the helper process that:
+ * . receives pvscan requests from lvmetad_main
+ * . forks/execs pvscan commands for each request
+ */
+
+#define MAX_AV_COUNT 8
+
+static int _log_debug_stderr;
+
+#define log_debug(fmt, args...) \
+do { \
+ if (_log_debug_stderr) \
+ fprintf(stderr, fmt "\n", ##args); \
+} while (0)
+
+static void run_path(struct helper_msg *hm)
+{
+ char arg[HELPER_ARGS_LEN];
+ char *args = hm->args;
+ char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
+ int av_count = 0;
+ int i, arg_len, args_len;
+
+ for (i = 0; i < MAX_AV_COUNT + 1; i++)
+ av[i] = NULL;
+
+ av[av_count++] = strdup(hm->path);
+
+ if (!args[0])
+ goto run;
+
+ /* this should already be done, but make sure */
+ args[HELPER_ARGS_LEN - 1] = '\0';
+
+ memset(&arg, 0, sizeof(arg));
+ arg_len = 0;
+ args_len = strlen(args);
+
+ for (i = 0; i < args_len; i++) {
+ if (!args[i])
+ break;
+
+ if (av_count == MAX_AV_COUNT)
+ break;
+
+ if (args[i] == '\\') {
+ if (i == (args_len - 1))
+ break;
+ i++;
+
+ if (args[i] == '\\') {
+ arg[arg_len++] = args[i];
+ continue;
+ }
+ if (isspace(args[i])) {
+ arg[arg_len++] = args[i];
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (isalnum(args[i]) || ispunct(args[i])) {
+ arg[arg_len++] = args[i];
+ } else if (isspace(args[i])) {
+ if (arg_len)
+ av[av_count++] = strdup(arg);
+
+ memset(arg, 0, sizeof(arg));
+ arg_len = 0;
+ } else {
+ break;
+ }
+ }
+
+ if ((av_count < MAX_AV_COUNT) && arg_len) {
+ av[av_count++] = strdup(arg);
+ }
+run:
+ execvp(av[0], av);
+}
+
+static int read_from_main(int fd, struct helper_msg *hm)
+{
+ int rv;
+ retry:
+ rv = read(fd, hm, sizeof(struct helper_msg));
+ if (rv == -1 && errno == EINTR)
+ goto retry;
+
+ if (rv != sizeof(struct helper_msg))
+ return -1;
+ return 0;
+}
+
+static int send_to_main(int fd, int type)
+{
+ struct helper_status hs;
+ int rv;
+
+ memset(&hs, 0, sizeof(hs));
+
+ hs.type = type;
+
+ rv = write(fd, &hs, sizeof(hs));
+
+ if (rv == sizeof(hs))
+ return 0;
+ return -1;
+}
+
+#define INACTIVE_TIMEOUT_MS 10000
+#define ACTIVE_TIMEOUT_MS 1000
+
+int run_helper(int in_fd, int out_fd, int debug_stderr)
+{
+ char name[16];
+ struct pollfd pollfd;
+ struct helper_msg hm;
+ unsigned int fork_count = 0;
+ unsigned int wait_count = 0;
+ int timeout = INACTIVE_TIMEOUT_MS;
+ int rv, pid, status;
+
+ _log_debug_stderr = debug_stderr;
+
+ memset(name, 0, sizeof(name));
+ sprintf(name, "%s", "lvmetad_helper");
+ prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
+
+ memset(&pollfd, 0, sizeof(pollfd));
+ pollfd.fd = in_fd;
+ pollfd.events = POLLIN;
+
+ /* Tell the main process we've started. */
+ send_to_main(out_fd, HELPER_STARTED);
+
+ while (1) {
+ rv = poll(&pollfd, 1, timeout);
+ if (rv == -1 && errno == EINTR)
+ continue;
+
+ if (rv < 0)
+ exit(0);
+
+ memset(&hm, 0, sizeof(hm));
+
+ if (pollfd.revents & POLLIN) {
+ rv = read_from_main(in_fd, &hm);
+ if (rv)
+ continue;
+
+ if (hm.type == HELPER_MSG_RUNPATH) {
+ pid = fork();
+ if (!pid) {
+ run_path(&hm);
+ exit(-1);
+ }
+
+ fork_count++;
+
+ /*
+ log_debug("helper fork %d count %d %d %s %s",
+ pid, fork_count, wait_count,
+ hm.path, hm.args);
+ */
+ }
+ }
+
+ if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL))
+ exit(0);
+
+ /* collect child exits until no more children exist (ECHILD)
+ or none are ready (WNOHANG) */
+
+ while (1) {
+ rv = waitpid(-1, &status, WNOHANG);
+ if (rv > 0) {
+ wait_count++;
+
+ /*
+ log_debug("helper wait %d count %d %d",
+ rv, fork_count, wait_count);
+ */
+ continue;
+ }
+
+ /* no more children to wait for or no children
+ have exited */
+
+ if (rv < 0 && errno == ECHILD)
+ timeout = INACTIVE_TIMEOUT_MS;
+ else
+ timeout = ACTIVE_TIMEOUT_MS;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void close_helper(daemon_state *s)
+{
+ lvmetad_state *ls = s->private;
+
+ close(ls->helper_pr_fd);
+ close(ls->helper_pw_fd);
+ ls->helper_pr_fd = -1;
+ ls->helper_pw_fd = -1;
+ s->helper_fd = -1;
+ s->helper_handler = NULL;
+}
+
+static void _send_helper_msg(daemon_state *s, struct helper_msg *hm)
+{
+ lvmetad_state *ls = s->private;
+ int rv;
+
+ retry:
+ rv = write(ls->helper_pw_fd, hm, sizeof(struct helper_msg));
+ if (rv == -1 && errno == EINTR)
+ goto retry;
+
+ if (rv == -1 && errno == EAGAIN) {
+ return;
+ }
+
+ /* helper exited or closed fd, quit using helper */
+ if (rv == -1 && errno == EPIPE) {
+ ERROR(s, "send_helper EPIPE");
+ close_helper(s);
+ return;
+ }
+
+ if (rv != sizeof(struct helper_msg)) {
+ /* this shouldn't happen */
+ ERROR(s, "send_helper error %d %d", rv, errno);
+ close_helper(s);
+ return;
+ }
+}
+
+/* send a request to helper process */
+
+void send_helper_request(daemon_state *s, request r)
+{
+ struct helper_msg hm = { 0 };
+ char *runpath = daemon_request_str(r, "runpath", NULL);
+ char *runargs = daemon_request_str(r, "runargs", NULL);
+
+ hm.type = HELPER_MSG_RUNPATH;
+ memcpy(hm.path, runpath, HELPER_PATH_LEN);
+ if (runargs)
+ memcpy(hm.args, runargs, HELPER_ARGS_LEN);
+
+ _send_helper_msg(s, &hm);
+}
+
+static void send_helper_pvscan_cache_name(daemon_state *s, const char *name)
+{
+ struct helper_msg hm = { 0 };
+
+ hm.type = HELPER_MSG_RUNPATH;
+ sprintf(hm.path, "pvscan");
+ snprintf(hm.args, HELPER_ARGS_LEN-1, "--cache %s", name);
+
+ _send_helper_msg(s, &hm);
+}
+
+static void send_helper_pvscan_cache_num(daemon_state *s, dev_t devt)
+{
+ struct helper_msg hm = { 0 };
+
+ hm.type = HELPER_MSG_RUNPATH;
+ sprintf(hm.path, "pvscan");
+ snprintf(hm.args, HELPER_ARGS_LEN-1, "--cache --major %d --minor %d",
+ major(devt), minor(devt));
+
+ _send_helper_msg(s, &hm);
+}
+
+static void send_helper_pvscan_cache_all(daemon_state *s)
+{
+ struct helper_msg hm = { 0 };
+
+ hm.type = HELPER_MSG_RUNPATH;
+ sprintf(hm.path, "pvscan");
+ sprintf(hm.args, "--cache");
+
+ _send_helper_msg(s, &hm);
+}
+
+/*
+ * called in context of main lvmetad process
+ * handles a message from helper process
+ */
+
+static int helper_handler(daemon_state *s)
+{
+ lvmetad_state *ls = s->private;
+ struct helper_status hs;
+ int rv;
+
+ memset(&hs, 0, sizeof(hs));
+
+ rv = read(ls->helper_pr_fd, &hs, sizeof(hs));
+ if (!rv || rv == -EAGAIN)
+ return -1;
+ if (rv < 0) {
+ ERROR(s, "handle_helper rv %d errno %d", rv, errno);
+ goto fail;
+ }
+ if (rv != sizeof(hs)) {
+ ERROR(s, "handle_helper recv size %d", rv);
+ goto fail;
+ }
+
+ DEBUGLOG(s, "helper message type %d status %d", hs.type, hs.status);
+
+ /*
+ * Run initial pvscan --cache to populate lvmetad cache.
+ *
+ * (Upon receiving HELPER_STARTED we know that the helper
+ * is ready to handle to running commands.)
+ *
+ * The udev monitor is enabled before this, so there should
+ * be no gap where new devs could be missed. It's possible
+ * that new devs added during lvmetad startup could be scanned
+ * by this initial pvscan --cache, and then scanned again
+ * individually because of the monitor. This possible repetition
+ * is harmless.
+ */
+ if (hs.type == HELPER_STARTED)
+ send_helper_pvscan_cache_all(s);
+
+ return 0;
+
+ fail:
+ ERROR(s, "close helper connection");
+ close_helper(s);
+ return -1;
+}
+
+/* create helper process */
+
+int setup_helper(daemon_state *s)
+{
+ lvmetad_state *ls = s->private;
+ int pid;
+ int pw_fd = -1; /* parent write */
+ int cr_fd = -1; /* child read */
+ int pr_fd = -1; /* parent read */
+ int cw_fd = -1; /* child write */
+ int pfd[2];
+
+ /* don't allow the main daemon thread to block */
+ if (pipe2(pfd, O_NONBLOCK | O_CLOEXEC))
+ return -errno;
+
+ /* only available on rhel7 */
+ /* fcntl(pfd[1], F_SETPIPE_SZ, 1024*1024); */
+
+ cr_fd = pfd[0];
+ pw_fd = pfd[1];
+
+ if (pipe2(pfd, O_NONBLOCK | O_CLOEXEC)) {
+ close(cr_fd);
+ close(pw_fd);
+ return -errno;
+ }
+
+ pr_fd = pfd[0];
+ cw_fd = pfd[1];
+
+ pid = fork();
+ if (pid < 0) {
+ close(cr_fd);
+ close(pw_fd);
+ close(pr_fd);
+ close(cw_fd);
+ return -errno;
+ }
+
+ if (pid) {
+ close(cr_fd);
+ close(cw_fd);
+ ls->helper_pw_fd = pw_fd;
+ ls->helper_pr_fd = pr_fd;
+ ls->helper_pid = pid;
+ s->helper_fd = pr_fd; /* libdaemon uses helper_fd in select */
+ s->helper_handler = helper_handler;
+ return 0;
+ } else {
+ close(pr_fd);
+ close(pw_fd);
+ run_helper(cr_fd, cw_fd, (s->foreground && strstr(ls->log_config, "debug")));
+ exit(0);
+ }
+}
+
+/*
+ * called in context of main lvmetad process
+ * handles a message from udev monitor
+ * sends a message to lvmetad helper to scan a device
+ */
+
+static int monitor_handler(daemon_state *s)
+{
+ lvmetad_state *ls = s->private;
+ struct udev_device *dev;
+ dev_t devt;
+ const char *name;
+ const char *action;
+
+ dev = udev_monitor_receive_device(ls->udev_mon);
+ if (!dev)
+ return 0;
+
+ name = udev_device_get_devnode(dev);
+ if (!name)
+ goto out;
+
+ devt = udev_device_get_devnum(dev);
+ action = udev_device_get_action(dev);
+
+ /*
+ * FIXME: there's a lot of magic in 69-dm-lvm-metad.rules.in
+ * some of which is probably needed here (especially related
+ * to scanning MD/DM/loop devs.)
+ */
+
+ if (!strcmp(action, "add")) {
+ DEBUGLOG(s, "monitor add %s", name);
+ send_helper_pvscan_cache_name(s, name);
+
+ } else if (!strcmp(action, "remove")) {
+ DEBUGLOG(s, "monitor remove %s", name);
+ send_helper_pvscan_cache_num(s, devt);
+ }
+out:
+ udev_device_unref(dev);
+ return 0;
+}
+
+/* create udev monitor */
+
+void setup_udev_monitor(daemon_state *s)
+{
+ lvmetad_state *ls = s->private;
+ int fd;
+ int ret;
+
+ /* FIXME: cleanup all libudev stuff */
+
+ ls->udevh = udev_new();
+ if (!ls->udevh) {
+ ERROR(s, "Failed to monitor udev new.");
+ return;
+ }
+
+ ls->udev_mon = udev_monitor_new_from_netlink(ls->udevh, "udev");
+ if (!ls->udev_mon) {
+ ERROR(s, "Failed to monitor udev netlink.");
+ return;
+ }
+
+ ret = udev_monitor_filter_add_match_subsystem_devtype(ls->udev_mon, "block", "disk");
+ if (ret < 0) {
+ ERROR(s, "Failed to monitor udev filter.");
+ return;
+ }
+
+ ret = udev_monitor_enable_receiving(ls->udev_mon);
+ if (ret < 0) {
+ ERROR(s, "Failed to monitor udev receive.");
+ return;
+ }
+
+ /* udev_monitor_set_receive_buffer_size? */
+
+ fd = udev_monitor_get_fd(ls->udev_mon);
+ if (fd < 0) {
+ ERROR(s, "Failed to monitor udev fd.");
+ return;
+ }
+
+ ls->udev_fd = fd;
+ s->monitor_fd = fd;
+ s->monitor_handler = monitor_handler;
+}
+
diff --git a/daemons/lvmetad/lvmetad-internal.h b/daemons/lvmetad/lvmetad-internal.h
new file mode 100644
index 000000000..40fa5dbd8
--- /dev/null
+++ b/daemons/lvmetad/lvmetad-internal.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ */
+
+#ifndef _LVM_LVMETAD_INTERNAL_H
+#define _LVM_LVMETAD_INTERNAL_H
+
+#define CMD_NAME_SIZE 32
+
+typedef struct {
+ daemon_idle *idle;
+ log_state *log; /* convenience */
+ const char *log_config;
+ int enable_udev_monitor;
+
+ struct dm_hash_table *pvid_to_pvmeta;
+ struct dm_hash_table *device_to_pvid; /* shares locks with above */
+
+ struct dm_hash_table *vgid_to_metadata;
+ struct dm_hash_table *vgid_to_vgname;
+ struct dm_hash_table *vgid_to_outdated_pvs;
+ struct dm_hash_table *vgid_to_info;
+ struct dm_hash_table *vgname_to_vgid;
+ struct dm_hash_table *pvid_to_vgid;
+ char token[128];
+ char update_cmd[CMD_NAME_SIZE];
+ int update_pid;
+ int update_timeout;
+ uint64_t update_begin;
+ uint32_t flags; /* GLFL_ */
+ pthread_mutex_t token_lock;
+ pthread_mutex_t info_lock;
+ pthread_rwlock_t cache_lock;
+
+ int helper_pid;
+ int helper_pw_fd; /* parent write to send message to helper */
+ int helper_pr_fd; /* parent read to recv message from helper */
+
+ struct udev *udevh;
+ struct udev_monitor *udev_mon;
+ int udev_fd;
+} lvmetad_state;
+
+/*
+ * helper process
+ * recvs 512 byte helper_msg on in_fd
+ * sends 4 byte helper_status on out_fd
+ */
+
+/* max length of path and args, includes terminate \0 byte */
+
+#define HELPER_PATH_LEN 128
+#define HELPER_ARGS_LEN 128
+#define HELPER_MSG_LEN 512
+#define HELPER_MSG_RUNPATH 1
+
+struct helper_msg {
+ uint8_t type;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t flags;
+ int pid;
+ int unused;
+ char path[HELPER_PATH_LEN]; /* 128 */
+ char args[HELPER_ARGS_LEN]; /* 128 */
+ char pad[240];
+};
+
+#define HELPER_STARTED 1
+
+struct helper_status {
+ uint8_t type;
+ uint8_t status;
+ uint16_t len;
+};
+
+void close_helper(daemon_state *s);
+void send_helper_request(daemon_state *s, request r);
+int setup_helper(daemon_state *s);
+void setup_udev_monitor(daemon_state *s);
+
+#endif
diff --git a/libdaemon/server/daemon-server.c b/libdaemon/server/daemon-server.c
index 4d6546633..00c23f5f6 100644
--- a/libdaemon/server/daemon-server.c
+++ b/libdaemon/server/daemon-server.c
@@ -630,12 +630,26 @@ void daemon_start(daemon_state s)
_reset_timeout(s);
FD_ZERO(&in);
FD_SET(s.socket_fd, &in);
+
+ if (s.helper_handler)
+ FD_SET(s.helper_fd, &in);
+ if (s.monitor_handler)
+ FD_SET(s.monitor_fd, &in);
+
if (select(FD_SETSIZE, &in, NULL, NULL, _get_timeout(s)) < 0 && errno != EINTR)
perror("select error");
if (FD_ISSET(s.socket_fd, &in)) {
timeout_count = 0;
handle_connect(s);
}
+ if (FD_ISSET(s.helper_fd, &in)) {
+ timeout_count = 0;
+ s.helper_handler(&s);
+ }
+ if (FD_ISSET(s.monitor_fd, &in)) {
+ timeout_count = 0;
+ s.monitor_handler(&s);
+ }
_reap(s, 0);
diff --git a/libdaemon/server/daemon-server.h b/libdaemon/server/daemon-server.h
index 2b9ceac36..ee8ca9c79 100644
--- a/libdaemon/server/daemon-server.h
+++ b/libdaemon/server/daemon-server.h
@@ -108,10 +108,15 @@ typedef struct daemon_state {
int (*daemon_init)(struct daemon_state *st);
int (*daemon_fini)(struct daemon_state *st);
int (*daemon_main)(struct daemon_state *st);
+ int (*helper_handler)(struct daemon_state *st);
+ int (*monitor_handler)(struct daemon_state *st);
/* Global runtime info maintained by the framework. */
int socket_fd;
+ int helper_fd; /* used in select if helper_handler is set */
+ int monitor_fd; /* used in select if monitor_handler is set */
+
log_state *log;
struct thread_state *threads;