|
|
84b277 |
From 3c567125dd6e3f0f3a460d79701554ea4198c07b Mon Sep 17 00:00:00 2001
|
|
|
84b277 |
From: Lukas Nykryn <lnykryn@redhat.com>
|
|
|
84b277 |
Date: Thu, 18 Dec 2014 14:13:26 +0100
|
|
|
84b277 |
Subject: [PATCH] mount: monitor for utab changes with inotify
|
|
|
84b277 |
|
|
|
84b277 |
Parsing the mount table with libmount races against the mount command,
|
|
|
84b277 |
which will handle the actual mounting before updating utab. This means
|
|
|
84b277 |
the poll event on /proc/self/mountinfo can kick of a reparse in systemd
|
|
|
84b277 |
before the utab information is available.
|
|
|
84b277 |
|
|
|
84b277 |
This change adds in an additional event source using inotify to watch
|
|
|
84b277 |
for changes to utab. It only watches for IN_MOVED_TO events, matching
|
|
|
84b277 |
libmount behavior of always overwriting this file using rename(2).
|
|
|
84b277 |
|
|
|
84b277 |
This does add a second pass through the mount table parsing when utab is
|
|
|
84b277 |
updated.
|
|
|
84b277 |
|
|
|
84b277 |
(based-on befb6d54948480f836d53d633bef27e3505818c1)
|
|
|
84b277 |
|
|
|
84b277 |
Related: #1161417
|
|
|
84b277 |
---
|
|
|
84b277 |
src/core/manager.c | 3 ++-
|
|
|
84b277 |
src/core/manager.h | 2 ++
|
|
|
84b277 |
src/core/mount.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
|
84b277 |
src/core/mount.h | 2 +-
|
|
|
84b277 |
src/shared/util.h | 7 +++++
|
|
|
84b277 |
5 files changed, 88 insertions(+), 5 deletions(-)
|
|
|
84b277 |
|
|
|
84b277 |
diff --git a/src/core/manager.c b/src/core/manager.c
|
|
|
84b277 |
index e48ea36..b0772ba 100644
|
|
|
84b277 |
--- a/src/core/manager.c
|
|
|
84b277 |
+++ b/src/core/manager.c
|
|
|
84b277 |
@@ -1732,8 +1732,9 @@ static int process_event(Manager *m, struct epoll_event *ev) {
|
|
|
84b277 |
}
|
|
|
84b277 |
|
|
|
84b277 |
case WATCH_MOUNT:
|
|
|
84b277 |
+ case WATCH_MOUNT_UTAB:
|
|
|
84b277 |
/* Some mount table change, intended for the mount subsystem */
|
|
|
84b277 |
- mount_fd_event(m, ev->events);
|
|
|
84b277 |
+ mount_fd_event(m, w, ev->events);
|
|
|
84b277 |
break;
|
|
|
84b277 |
|
|
|
84b277 |
case WATCH_SWAP:
|
|
|
84b277 |
diff --git a/src/core/manager.h b/src/core/manager.h
|
|
|
84b277 |
index 0133ea5..af66598 100644
|
|
|
84b277 |
--- a/src/core/manager.h
|
|
|
84b277 |
+++ b/src/core/manager.h
|
|
|
84b277 |
@@ -58,6 +58,7 @@ enum WatchType {
|
|
|
84b277 |
WATCH_UNIT_TIMER,
|
|
|
84b277 |
WATCH_JOB_TIMER,
|
|
|
84b277 |
WATCH_MOUNT,
|
|
|
84b277 |
+ WATCH_MOUNT_UTAB,
|
|
|
84b277 |
WATCH_SWAP,
|
|
|
84b277 |
WATCH_UDEV,
|
|
|
84b277 |
WATCH_DBUS_WATCH,
|
|
|
84b277 |
@@ -178,6 +179,7 @@ struct Manager {
|
|
|
84b277 |
/* Data specific to the mount subsystem */
|
|
|
84b277 |
FILE *proc_self_mountinfo;
|
|
|
84b277 |
Watch mount_watch;
|
|
|
84b277 |
+ Watch mount_watch_utab;
|
|
|
84b277 |
|
|
|
84b277 |
/* Data specific to the swap filesystem */
|
|
|
84b277 |
FILE *proc_swaps;
|
|
|
84b277 |
diff --git a/src/core/mount.c b/src/core/mount.c
|
|
|
84b277 |
index d78269c..efa46da 100644
|
|
|
84b277 |
--- a/src/core/mount.c
|
|
|
84b277 |
+++ b/src/core/mount.c
|
|
|
84b277 |
@@ -25,6 +25,7 @@
|
|
|
84b277 |
#include <sys/epoll.h>
|
|
|
84b277 |
#include <signal.h>
|
|
|
84b277 |
#include <libmount.h>
|
|
|
84b277 |
+#include <sys/inotify.h>
|
|
|
84b277 |
|
|
|
84b277 |
#include "manager.h"
|
|
|
84b277 |
#include "unit.h"
|
|
|
84b277 |
@@ -1619,6 +1620,11 @@ static void mount_shutdown(Manager *m) {
|
|
|
84b277 |
fclose(m->proc_self_mountinfo);
|
|
|
84b277 |
m->proc_self_mountinfo = NULL;
|
|
|
84b277 |
}
|
|
|
84b277 |
+
|
|
|
84b277 |
+ if (m->mount_watch_utab.fd) {
|
|
|
84b277 |
+ close_nointr(m->mount_watch_utab.fd);
|
|
|
84b277 |
+ m->mount_watch_utab.fd=0;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
}
|
|
|
84b277 |
|
|
|
84b277 |
static int mount_enumerate(Manager *m) {
|
|
|
84b277 |
@@ -1644,6 +1650,35 @@ static int mount_enumerate(Manager *m) {
|
|
|
84b277 |
return -errno;
|
|
|
84b277 |
}
|
|
|
84b277 |
|
|
|
84b277 |
+ if (!m->mount_watch_utab.fd) {
|
|
|
84b277 |
+
|
|
|
84b277 |
+ struct epoll_event ev = {
|
|
|
84b277 |
+ .events = EPOLLIN,
|
|
|
84b277 |
+ .data.ptr = &m->mount_watch_utab,
|
|
|
84b277 |
+ };
|
|
|
84b277 |
+
|
|
|
84b277 |
+ m->mount_watch_utab.fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
|
|
|
84b277 |
+ if (m->mount_watch_utab.fd < 0) {
|
|
|
84b277 |
+ r = -errno;
|
|
|
84b277 |
+ goto fail;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+
|
|
|
84b277 |
+ (void) mkdir_p_label("/run/mount", 0755);
|
|
|
84b277 |
+
|
|
|
84b277 |
+ r = inotify_add_watch(m->mount_watch_utab.fd, "/run/mount", IN_MOVED_TO);
|
|
|
84b277 |
+ if (r < 0) {
|
|
|
84b277 |
+ r = -errno;
|
|
|
84b277 |
+ goto fail;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+
|
|
|
84b277 |
+ m->mount_watch_utab.type = WATCH_MOUNT_UTAB;
|
|
|
84b277 |
+
|
|
|
84b277 |
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch_utab.fd, &ev) < 0) {
|
|
|
84b277 |
+ r = -errno;
|
|
|
84b277 |
+ goto fail;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+
|
|
|
84b277 |
r = mount_load_proc_self_mountinfo(m, false);
|
|
|
84b277 |
if (r < 0)
|
|
|
84b277 |
goto fail;
|
|
|
84b277 |
@@ -1655,16 +1690,54 @@ fail:
|
|
|
84b277 |
return r;
|
|
|
84b277 |
}
|
|
|
84b277 |
|
|
|
84b277 |
-void mount_fd_event(Manager *m, int events) {
|
|
|
84b277 |
+void mount_fd_event(Manager *m, Watch *w, int events) {
|
|
|
84b277 |
Unit *u;
|
|
|
84b277 |
int r;
|
|
|
84b277 |
|
|
|
84b277 |
assert(m);
|
|
|
84b277 |
- assert(events & EPOLLPRI);
|
|
|
84b277 |
+ assert(w);
|
|
|
84b277 |
+ assert(events & (EPOLLPRI|EPOLLIN));
|
|
|
84b277 |
|
|
|
84b277 |
/* The manager calls this for every fd event happening on the
|
|
|
84b277 |
* /proc/self/mountinfo file, which informs us about mounting
|
|
|
84b277 |
- * table changes */
|
|
|
84b277 |
+ * table changes
|
|
|
84b277 |
+ * This may also be called for /run/mount events */
|
|
|
84b277 |
+
|
|
|
84b277 |
+ if (w->type == WATCH_MOUNT_UTAB) {
|
|
|
84b277 |
+ bool rescan = false;
|
|
|
84b277 |
+
|
|
|
84b277 |
+ /* FIXME: We *really* need to replace this with
|
|
|
84b277 |
+ * libmount's own API for this, we should not hardcode
|
|
|
84b277 |
+ * internal behaviour of libmount here. */
|
|
|
84b277 |
+
|
|
|
84b277 |
+ for (;;) {
|
|
|
84b277 |
+ uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
|
|
|
84b277 |
+ struct inotify_event *e;
|
|
|
84b277 |
+ ssize_t l;
|
|
|
84b277 |
+
|
|
|
84b277 |
+ l = read(w->fd, buffer, sizeof(buffer));
|
|
|
84b277 |
+ if (l < 0) {
|
|
|
84b277 |
+ if (errno == EAGAIN || errno == EINTR)
|
|
|
84b277 |
+ break;
|
|
|
84b277 |
+
|
|
|
84b277 |
+ log_error("Failed to read utab inotify: %s", strerror(errno));
|
|
|
84b277 |
+ break;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+
|
|
|
84b277 |
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
|
|
|
84b277 |
+ /* Only care about changes to utab,
|
|
|
84b277 |
+ * but we have to monitor the
|
|
|
84b277 |
+ * directory to reliably get
|
|
|
84b277 |
+ * notifications about when utab is
|
|
|
84b277 |
+ * replaced using rename(2) */
|
|
|
84b277 |
+ if ((e->mask & IN_Q_OVERFLOW) || streq(e->name, "utab"))
|
|
|
84b277 |
+ rescan = true;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+ }
|
|
|
84b277 |
+
|
|
|
84b277 |
+ if (!rescan)
|
|
|
84b277 |
+ return;
|
|
|
84b277 |
+ }
|
|
|
84b277 |
|
|
|
84b277 |
r = mount_load_proc_self_mountinfo(m, true);
|
|
|
84b277 |
if (r < 0) {
|
|
|
84b277 |
diff --git a/src/core/mount.h b/src/core/mount.h
|
|
|
84b277 |
index 7cd4320..df0e541 100644
|
|
|
84b277 |
--- a/src/core/mount.h
|
|
|
84b277 |
+++ b/src/core/mount.h
|
|
|
84b277 |
@@ -113,7 +113,7 @@ struct Mount {
|
|
|
84b277 |
|
|
|
84b277 |
extern const UnitVTable mount_vtable;
|
|
|
84b277 |
|
|
|
84b277 |
-void mount_fd_event(Manager *m, int events);
|
|
|
84b277 |
+void mount_fd_event(Manager *m, Watch *w, int events);
|
|
|
84b277 |
|
|
|
84b277 |
const char* mount_state_to_string(MountState i) _const_;
|
|
|
84b277 |
MountState mount_state_from_string(const char *s) _pure_;
|
|
|
84b277 |
diff --git a/src/shared/util.h b/src/shared/util.h
|
|
|
84b277 |
index d68f385..c5ef8b6 100644
|
|
|
84b277 |
--- a/src/shared/util.h
|
|
|
84b277 |
+++ b/src/shared/util.h
|
|
|
84b277 |
@@ -791,3 +791,10 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size,
|
|
|
84b277 |
qsort(base, nmemb, size, compar);
|
|
|
84b277 |
}
|
|
|
84b277 |
}
|
|
|
84b277 |
+
|
|
|
84b277 |
+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
|
|
|
84b277 |
+
|
|
|
84b277 |
+#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
|
|
|
84b277 |
+ for ((e) = (struct inotify_event*) (buffer); \
|
|
|
84b277 |
+ (uint8_t*) (e) < (uint8_t*) (buffer) + (sz); \
|
|
|
84b277 |
+ (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
|