summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--daemons/lvmetad/Makefile.in2
-rw-r--r--daemons/lvmetad/lvmetad-core.c14
-rw-r--r--daemons/lvmetad/lvmetad-helper.c168
-rw-r--r--daemons/lvmetad/lvmetad-internal.h6
-rw-r--r--libdaemon/server/daemon-server.c10
-rw-r--r--libdaemon/server/daemon-server.h6
6 files changed, 181 insertions, 25 deletions
diff --git a/daemons/lvmetad/Makefile.in b/daemons/lvmetad/Makefile.in
index 82fb8ceff..9e039c93e 100644
--- a/daemons/lvmetad/Makefile.in
+++ b/daemons/lvmetad/Makefile.in
@@ -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/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index 369d75d3d..b9ae10868 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -2628,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;
@@ -2888,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;
}
@@ -2937,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,
@@ -2947,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);
@@ -2976,6 +2981,9 @@ 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);
diff --git a/daemons/lvmetad/lvmetad-helper.c b/daemons/lvmetad/lvmetad-helper.c
index d94773362..fe9030f63 100644
--- a/daemons/lvmetad/lvmetad-helper.c
+++ b/daemons/lvmetad/lvmetad-helper.c
@@ -37,7 +37,10 @@
#include <sys/wait.h>
#include <sys/prctl.h>
#include <grp.h>
+#include <assert.h>
+#include <errno.h>
+#include "libudev.h"
#include "tool.h"
@@ -48,11 +51,16 @@
#include "lvmetad-internal.h"
#include "lvmetad-client.h"
-#include <assert.h>
-#include <errno.h>
-
#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];
@@ -149,14 +157,6 @@ static int send_to_main(int fd, int type)
return -1;
}
-static int _log_debug_stderr;
-
-#define log_debug(fmt, args...) \
-do { \
- if (_log_debug_stderr) \
- fprintf(stderr, fmt "\n", ##args); \
-} while (0)
-
#define INACTIVE_TIMEOUT_MS 10000
#define ACTIVE_TIMEOUT_MS 1000
@@ -246,6 +246,7 @@ int run_helper(int in_fd, int out_fd, int debug_stderr)
return 0;
}
+
void close_helper(daemon_state *s)
{
lvmetad_state *ls = s->private;
@@ -255,7 +256,7 @@ void close_helper(daemon_state *s)
ls->helper_pr_fd = -1;
ls->helper_pw_fd = -1;
s->helper_fd = -1;
- s->daemon_helper = NULL;
+ s->helper_handler = NULL;
}
/* send a request to helper process */
@@ -299,7 +300,43 @@ void send_helper_request(daemon_state *s, request r)
}
}
-static void send_helper_pvscan_cache(daemon_state *s)
+static void send_helper_pvscan_cache_path(daemon_state *s, const char *path)
+{
+ lvmetad_state *ls = s->private;
+ struct helper_msg hm;
+ int rv;
+
+ memset(&hm, 0, sizeof(hm));
+
+ hm.type = HELPER_MSG_RUNPATH;
+ sprintf(hm.path, "pvscan");
+ snprintf(hm.args, HELPER_ARGS_LEN-1, "--cache %s", path);
+
+ retry:
+ rv = write(ls->helper_pw_fd, &hm, sizeof(hm));
+ 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(hm)) {
+ /* this shouldn't happen */
+ ERROR(s, "send_helper error %d %d", rv, errno);
+ close_helper(s);
+ return;
+ }
+}
+
+static void send_helper_pvscan_cache_all(daemon_state *s)
{
lvmetad_state *ls = s->private;
struct helper_msg hm;
@@ -335,9 +372,12 @@ static void send_helper_pvscan_cache(daemon_state *s)
}
}
-/* handle message from helper process */
+/*
+ * called in context of main lvmetad process
+ * handles a message from helper process
+ */
-static int handle_helper(daemon_state *s)
+static int helper_handler(daemon_state *s)
{
lvmetad_state *ls = s->private;
struct helper_status hs;
@@ -359,8 +399,21 @@ static int handle_helper(daemon_state *s)
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(s);
+ send_helper_pvscan_cache_all(s);
return 0;
@@ -417,7 +470,7 @@ int setup_helper(daemon_state *s)
ls->helper_pr_fd = pr_fd;
ls->helper_pid = pid;
s->helper_fd = pr_fd; /* libdaemon uses helper_fd in select */
- s->daemon_helper = handle_helper;
+ s->helper_handler = helper_handler;
return 0;
} else {
close(pr_fd);
@@ -427,3 +480,84 @@ int setup_helper(daemon_state *s)
}
}
+/*
+ * 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;
+ const char *path;
+
+ dev = udev_monitor_receive_device(ls->udev_mon);
+ if (!dev)
+ return 0;
+
+ /*
+ * FIXME: check something to see if the dev is
+ * being added or removed. When removed, pass
+ * the dev num instead of path.
+ */
+
+ path = udev_device_get_devpath(dev);
+ if (!path)
+ goto out;
+
+ DEBUGLOG(s, "monitor pvscan %s", path);
+
+ send_helper_pvscan_cache_path(s, path);
+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", NULL);
+ 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
index e06c01b05..40fa5dbd8 100644
--- a/daemons/lvmetad/lvmetad-internal.h
+++ b/daemons/lvmetad/lvmetad-internal.h
@@ -17,6 +17,7 @@ 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 */
@@ -40,6 +41,10 @@ typedef struct {
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;
/*
@@ -78,5 +83,6 @@ struct helper_status {
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 e6ddadf20..00c23f5f6 100644
--- a/libdaemon/server/daemon-server.c
+++ b/libdaemon/server/daemon-server.c
@@ -631,8 +631,10 @@ void daemon_start(daemon_state s)
FD_ZERO(&in);
FD_SET(s.socket_fd, &in);
- if (s.daemon_helper)
+ 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");
@@ -642,7 +644,11 @@ void daemon_start(daemon_state s)
}
if (FD_ISSET(s.helper_fd, &in)) {
timeout_count = 0;
- s.daemon_helper(&s);
+ 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 b26d882be..ee8ca9c79 100644
--- a/libdaemon/server/daemon-server.h
+++ b/libdaemon/server/daemon-server.h
@@ -108,12 +108,14 @@ 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 (*daemon_helper)(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;
+ 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;