diff options
-rw-r--r-- | daemons/lvmetad/Makefile.in | 2 | ||||
-rw-r--r-- | daemons/lvmetad/lvmetad-core.c | 14 | ||||
-rw-r--r-- | daemons/lvmetad/lvmetad-helper.c | 168 | ||||
-rw-r--r-- | daemons/lvmetad/lvmetad-internal.h | 6 | ||||
-rw-r--r-- | libdaemon/server/daemon-server.c | 10 | ||||
-rw-r--r-- | libdaemon/server/daemon-server.h | 6 |
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; |