|
|
8444ee |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
8444ee |
From: Benjamin Marzinski <bmarzins@redhat.com>
|
|
|
8444ee |
Date: Thu, 19 Sep 2019 13:46:03 -0500
|
|
|
8444ee |
Subject: [PATCH] multipathd: warn when configuration has been changed.
|
|
|
8444ee |
|
|
|
8444ee |
It would be helpful if multipathd could log a message when
|
|
|
8444ee |
multipath.conf or files in the config_dir have been written to, both so
|
|
|
8444ee |
that it can be used to send a notification to users, and to help with
|
|
|
8444ee |
determining after the fact if multipathd was running with an older
|
|
|
8444ee |
config, when the logs of multipathd's behaviour don't match with the
|
|
|
8444ee |
current multipath.conf.
|
|
|
8444ee |
|
|
|
8444ee |
To do this, the multipathd uxlsnr thread now sets up inotify watches on
|
|
|
8444ee |
both /etc/multipath.conf and the config_dir to watch if the files are
|
|
|
8444ee |
deleted or closed after being opened for writing. In order to keep
|
|
|
8444ee |
uxlsnr from polling repeatedly if the multipath.conf or the config_dir
|
|
|
8444ee |
aren't present, it will only set up the watches once per reconfigure.
|
|
|
8444ee |
However, since multipath.conf is far more likely to be replaced by a
|
|
|
8444ee |
text editor than modified in place, if it gets removed, multipathd will
|
|
|
8444ee |
immediately try to restart the watch on it (which will succeed if the
|
|
|
8444ee |
file was simply replaced by a new copy). This does mean that if
|
|
|
8444ee |
multipath.conf or the config_dir are actually removed and then later
|
|
|
8444ee |
re-added, multipathd won't log any more messages for changes until the
|
|
|
8444ee |
next reconfigure. But that seems like a fair trade-off to avoid
|
|
|
8444ee |
repeatedly polling for files that aren't likely to appear.
|
|
|
8444ee |
|
|
|
8444ee |
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
|
|
8444ee |
---
|
|
|
8444ee |
libmultipath/config.h | 1 +
|
|
|
8444ee |
multipathd/main.c | 1 +
|
|
|
8444ee |
multipathd/uxlsnr.c | 134 ++++++++++++++++++++++++++++++++++++++++--
|
|
|
8444ee |
3 files changed, 130 insertions(+), 6 deletions(-)
|
|
|
8444ee |
|
|
|
8444ee |
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
|
|
8444ee |
index ffec3103..e69aa07c 100644
|
|
|
8444ee |
--- a/libmultipath/config.h
|
|
|
8444ee |
+++ b/libmultipath/config.h
|
|
|
8444ee |
@@ -188,6 +188,7 @@ struct config {
|
|
|
8444ee |
int find_multipaths_timeout;
|
|
|
8444ee |
int marginal_pathgroups;
|
|
|
8444ee |
unsigned int version[3];
|
|
|
8444ee |
+ unsigned int sequence_nr;
|
|
|
8444ee |
|
|
|
8444ee |
char * multipath_dir;
|
|
|
8444ee |
char * selector;
|
|
|
8444ee |
diff --git a/multipathd/main.c b/multipathd/main.c
|
|
|
8444ee |
index 34a57689..7b364cfe 100644
|
|
|
8444ee |
--- a/multipathd/main.c
|
|
|
8444ee |
+++ b/multipathd/main.c
|
|
|
8444ee |
@@ -2618,6 +2618,7 @@ reconfigure (struct vectors * vecs)
|
|
|
8444ee |
uxsock_timeout = conf->uxsock_timeout;
|
|
|
8444ee |
|
|
|
8444ee |
old = rcu_dereference(multipath_conf);
|
|
|
8444ee |
+ conf->sequence_nr = old->sequence_nr + 1;
|
|
|
8444ee |
rcu_assign_pointer(multipath_conf, conf);
|
|
|
8444ee |
call_rcu(&old->rcu, rcu_free_config);
|
|
|
8444ee |
|
|
|
8444ee |
diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c
|
|
|
8444ee |
index bc71679e..92d9a79a 100644
|
|
|
8444ee |
--- a/multipathd/uxlsnr.c
|
|
|
8444ee |
+++ b/multipathd/uxlsnr.c
|
|
|
8444ee |
@@ -23,6 +23,7 @@
|
|
|
8444ee |
#include <sys/time.h>
|
|
|
8444ee |
#include <signal.h>
|
|
|
8444ee |
#include <stdbool.h>
|
|
|
8444ee |
+#include <sys/inotify.h>
|
|
|
8444ee |
#include "checkers.h"
|
|
|
8444ee |
#include "memory.h"
|
|
|
8444ee |
#include "debug.h"
|
|
|
8444ee |
@@ -51,6 +52,8 @@ struct client {
|
|
|
8444ee |
LIST_HEAD(clients);
|
|
|
8444ee |
pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
8444ee |
struct pollfd *polls;
|
|
|
8444ee |
+int notify_fd = -1;
|
|
|
8444ee |
+char *config_dir;
|
|
|
8444ee |
|
|
|
8444ee |
static bool _socket_client_is_root(int fd);
|
|
|
8444ee |
|
|
|
8444ee |
@@ -151,6 +154,8 @@ void uxsock_cleanup(void *arg)
|
|
|
8444ee |
long ux_sock = (long)arg;
|
|
|
8444ee |
|
|
|
8444ee |
close(ux_sock);
|
|
|
8444ee |
+ close(notify_fd);
|
|
|
8444ee |
+ free(config_dir);
|
|
|
8444ee |
|
|
|
8444ee |
pthread_mutex_lock(&client_lock);
|
|
|
8444ee |
list_for_each_entry_safe(client_loop, client_tmp, &clients, node) {
|
|
|
8444ee |
@@ -162,6 +167,106 @@ void uxsock_cleanup(void *arg)
|
|
|
8444ee |
free_polls();
|
|
|
8444ee |
}
|
|
|
8444ee |
|
|
|
8444ee |
+/* failing to set the watch descriptor is o.k. we just miss a warning
|
|
|
8444ee |
+ * message */
|
|
|
8444ee |
+void reset_watch(int notify_fd, int *wds, unsigned int *sequence_nr)
|
|
|
8444ee |
+{
|
|
|
8444ee |
+ struct config *conf;
|
|
|
8444ee |
+ int dir_reset = 0;
|
|
|
8444ee |
+ int conf_reset = 0;
|
|
|
8444ee |
+
|
|
|
8444ee |
+ if (notify_fd == -1)
|
|
|
8444ee |
+ return;
|
|
|
8444ee |
+
|
|
|
8444ee |
+ conf = get_multipath_config();
|
|
|
8444ee |
+ /* instead of repeatedly try to reset the inotify watch if
|
|
|
8444ee |
+ * the config directory or multipath.conf isn't there, just
|
|
|
8444ee |
+ * do it once per reconfigure */
|
|
|
8444ee |
+ if (*sequence_nr != conf->sequence_nr) {
|
|
|
8444ee |
+ *sequence_nr = conf->sequence_nr;
|
|
|
8444ee |
+ if (wds[0] == -1)
|
|
|
8444ee |
+ conf_reset = 1;
|
|
|
8444ee |
+ if (!config_dir || !conf->config_dir ||
|
|
|
8444ee |
+ strcmp(config_dir, conf->config_dir)) {
|
|
|
8444ee |
+ dir_reset = 1;
|
|
|
8444ee |
+ if (config_dir)
|
|
|
8444ee |
+ free(config_dir);
|
|
|
8444ee |
+ if (conf->config_dir)
|
|
|
8444ee |
+ config_dir = strdup(conf->config_dir);
|
|
|
8444ee |
+ else
|
|
|
8444ee |
+ config_dir = NULL;
|
|
|
8444ee |
+ } else if (wds[1] == -1)
|
|
|
8444ee |
+ dir_reset = 1;
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ put_multipath_config(conf);
|
|
|
8444ee |
+
|
|
|
8444ee |
+ if (dir_reset) {
|
|
|
8444ee |
+ if (wds[1] != -1) {
|
|
|
8444ee |
+ inotify_rm_watch(notify_fd, wds[1]);
|
|
|
8444ee |
+ wds[1] = -1;
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ if (config_dir) {
|
|
|
8444ee |
+ wds[1] = inotify_add_watch(notify_fd, config_dir,
|
|
|
8444ee |
+ IN_CLOSE_WRITE | IN_DELETE |
|
|
|
8444ee |
+ IN_ONLYDIR);
|
|
|
8444ee |
+ if (wds[1] == -1)
|
|
|
8444ee |
+ condlog(3, "didn't set up notifications on %s: %s", config_dir, strerror(errno));
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ if (conf_reset) {
|
|
|
8444ee |
+ wds[0] = inotify_add_watch(notify_fd, DEFAULT_CONFIGFILE,
|
|
|
8444ee |
+ IN_CLOSE_WRITE);
|
|
|
8444ee |
+ if (wds[0] == -1)
|
|
|
8444ee |
+ condlog(3, "didn't set up notifications on /etc/multipath.conf: %s", strerror(errno));
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ return;
|
|
|
8444ee |
+}
|
|
|
8444ee |
+
|
|
|
8444ee |
+void handle_inotify(int fd, int *wds)
|
|
|
8444ee |
+{
|
|
|
8444ee |
+ char buff[1024]
|
|
|
8444ee |
+ __attribute__ ((aligned(__alignof__(struct inotify_event))));
|
|
|
8444ee |
+ const struct inotify_event *event;
|
|
|
8444ee |
+ ssize_t len;
|
|
|
8444ee |
+ char *ptr;
|
|
|
8444ee |
+ int i, got_notify = 0;
|
|
|
8444ee |
+
|
|
|
8444ee |
+ for (;;) {
|
|
|
8444ee |
+ len = read(fd, buff, sizeof(buff));
|
|
|
8444ee |
+ if (len <= 0) {
|
|
|
8444ee |
+ if (len < 0 && errno != EAGAIN) {
|
|
|
8444ee |
+ condlog(3, "error reading from inotify_fd");
|
|
|
8444ee |
+ for (i = 0; i < 2; i++) {
|
|
|
8444ee |
+ if (wds[i] != -1) {
|
|
|
8444ee |
+ inotify_rm_watch(fd, wds[i]);
|
|
|
8444ee |
+ wds[i] = -1;
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ break;
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+
|
|
|
8444ee |
+ got_notify = 1;
|
|
|
8444ee |
+ for (ptr = buff; ptr < buff + len;
|
|
|
8444ee |
+ ptr += sizeof(struct inotify_event) + event->len) {
|
|
|
8444ee |
+ event = (const struct inotify_event *) ptr;
|
|
|
8444ee |
+
|
|
|
8444ee |
+ if (event->mask & IN_IGNORED) {
|
|
|
8444ee |
+ /* multipathd.conf may have been overwritten.
|
|
|
8444ee |
+ * Try once to reset the notification */
|
|
|
8444ee |
+ if (wds[0] == event->wd)
|
|
|
8444ee |
+ wds[0] = inotify_add_watch(notify_fd,
|
|
|
8444ee |
+ DEFAULT_CONFIGFILE,
|
|
|
8444ee |
+ IN_CLOSE_WRITE);
|
|
|
8444ee |
+ else if (wds[1] == event->wd)
|
|
|
8444ee |
+ wds[1] = -1;
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ }
|
|
|
8444ee |
+ if (got_notify)
|
|
|
8444ee |
+ condlog(1, "Multipath configuration updated.\nReload multipathd for changes to take effect");
|
|
|
8444ee |
+}
|
|
|
8444ee |
+
|
|
|
8444ee |
/*
|
|
|
8444ee |
* entry point
|
|
|
8444ee |
*/
|
|
|
8444ee |
@@ -173,13 +278,19 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
|
|
|
8444ee |
char *reply;
|
|
|
8444ee |
sigset_t mask;
|
|
|
8444ee |
int old_clients = MIN_POLLS;
|
|
|
8444ee |
+ /* conf->sequence_nr will be 1 when uxsock_listen is first called */
|
|
|
8444ee |
+ unsigned int sequence_nr = 0;
|
|
|
8444ee |
+ int wds[2] = { -1, -1 };
|
|
|
8444ee |
|
|
|
8444ee |
condlog(3, "uxsock: startup listener");
|
|
|
8444ee |
- polls = (struct pollfd *)MALLOC((MIN_POLLS + 1) * sizeof(struct pollfd));
|
|
|
8444ee |
+ polls = (struct pollfd *)MALLOC((MIN_POLLS + 2) * sizeof(struct pollfd));
|
|
|
8444ee |
if (!polls) {
|
|
|
8444ee |
condlog(0, "uxsock: failed to allocate poll fds");
|
|
|
8444ee |
exit_daemon();
|
|
|
8444ee |
}
|
|
|
8444ee |
+ notify_fd = inotify_init1(IN_NONBLOCK);
|
|
|
8444ee |
+ if (notify_fd == -1) /* it's fine if notifications fail */
|
|
|
8444ee |
+ condlog(3, "failed to start up configuration notifications");
|
|
|
8444ee |
sigfillset(&mask);
|
|
|
8444ee |
sigdelset(&mask, SIGINT);
|
|
|
8444ee |
sigdelset(&mask, SIGTERM);
|
|
|
8444ee |
@@ -198,18 +309,18 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
|
|
|
8444ee |
if (num_clients != old_clients) {
|
|
|
8444ee |
struct pollfd *new;
|
|
|
8444ee |
if (num_clients <= MIN_POLLS && old_clients > MIN_POLLS) {
|
|
|
8444ee |
- new = REALLOC(polls, (1 + MIN_POLLS) *
|
|
|
8444ee |
+ new = REALLOC(polls, (2 + MIN_POLLS) *
|
|
|
8444ee |
sizeof(struct pollfd));
|
|
|
8444ee |
} else if (num_clients <= MIN_POLLS && old_clients <= MIN_POLLS) {
|
|
|
8444ee |
new = polls;
|
|
|
8444ee |
} else {
|
|
|
8444ee |
- new = REALLOC(polls, (1+num_clients) *
|
|
|
8444ee |
+ new = REALLOC(polls, (2 + num_clients) *
|
|
|
8444ee |
sizeof(struct pollfd));
|
|
|
8444ee |
}
|
|
|
8444ee |
if (!new) {
|
|
|
8444ee |
pthread_mutex_unlock(&client_lock);
|
|
|
8444ee |
condlog(0, "%s: failed to realloc %d poll fds",
|
|
|
8444ee |
- "uxsock", 1 + num_clients);
|
|
|
8444ee |
+ "uxsock", 2 + num_clients);
|
|
|
8444ee |
sched_yield();
|
|
|
8444ee |
continue;
|
|
|
8444ee |
}
|
|
|
8444ee |
@@ -219,8 +330,15 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
|
|
|
8444ee |
polls[0].fd = ux_sock;
|
|
|
8444ee |
polls[0].events = POLLIN;
|
|
|
8444ee |
|
|
|
8444ee |
+ reset_watch(notify_fd, wds, &sequence_nr);
|
|
|
8444ee |
+ if (notify_fd == -1 || (wds[0] == -1 && wds[1] == -1))
|
|
|
8444ee |
+ polls[1].fd = -1;
|
|
|
8444ee |
+ else
|
|
|
8444ee |
+ polls[1].fd = notify_fd;
|
|
|
8444ee |
+ polls[1].events = POLLIN;
|
|
|
8444ee |
+
|
|
|
8444ee |
/* setup the clients */
|
|
|
8444ee |
- i = 1;
|
|
|
8444ee |
+ i = 2;
|
|
|
8444ee |
list_for_each_entry(c, &clients, node) {
|
|
|
8444ee |
polls[i].fd = c->fd;
|
|
|
8444ee |
polls[i].events = POLLIN;
|
|
|
8444ee |
@@ -262,7 +380,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
|
|
|
8444ee |
}
|
|
|
8444ee |
|
|
|
8444ee |
/* see if a client wants to speak to us */
|
|
|
8444ee |
- for (i = 1; i < num_clients + 1; i++) {
|
|
|
8444ee |
+ for (i = 2; i < num_clients + 2; i++) {
|
|
|
8444ee |
if (polls[i].revents & POLLIN) {
|
|
|
8444ee |
struct timespec start_time;
|
|
|
8444ee |
|
|
|
8444ee |
@@ -321,6 +439,10 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
|
|
|
8444ee |
if (polls[0].revents & POLLIN) {
|
|
|
8444ee |
new_client(ux_sock);
|
|
|
8444ee |
}
|
|
|
8444ee |
+
|
|
|
8444ee |
+ /* handle inotify events on config files */
|
|
|
8444ee |
+ if (polls[1].revents & POLLIN)
|
|
|
8444ee |
+ handle_inotify(notify_fd, wds);
|
|
|
8444ee |
}
|
|
|
8444ee |
|
|
|
8444ee |
return NULL;
|
|
|
8444ee |
--
|
|
|
8444ee |
2.17.2
|
|
|
8444ee |
|