summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2015-06-01 13:48:01 +0200
committerKarel Zak <kzak@redhat.com>2015-09-14 09:12:31 +0200
commitd379d44255469f03994832ab5821bf1b9034f4dc (patch)
tree27194587d38c4ea1333e67caed64202ecca9ec20
parent5669ef3644e3044036eeaaf6bb4b1a6a7e63130c (diff)
mount: use libmount to monitor mountinfo & utab
The current implementation directly monitor /proc/self/mountinfo and /run/mount/utab files. It's really not optimal because utab file is private libmount stuff without any official guaranteed semantic. The libmount since v2.26 provides API to monitor mount kernel & userspace changes and since v2.27 the monitor is usable for non-root users too. This patch replaces the current implementation with libmount based solution. Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--Makefile.am33
-rw-r--r--README4
-rw-r--r--configure.ac2
-rw-r--r--src/core/manager.c4
-rw-r--r--src/core/manager.h5
-rw-r--r--src/core/mount.c106
6 files changed, 66 insertions, 88 deletions
diff --git a/Makefile.am b/Makefile.am
index c395840759..57dfee7cc8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1327,7 +1327,8 @@ systemd_SOURCES = \
systemd_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
systemd_LDADD = \
libcore.la
@@ -1532,7 +1533,8 @@ test_engine_SOURCES = \
test_engine_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_engine_LDADD = \
libcore.la
@@ -1542,7 +1544,8 @@ test_job_type_SOURCES = \
test_job_type_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_job_type_LDADD = \
libcore.la
@@ -1592,7 +1595,8 @@ test_unit_name_SOURCES = \
test_unit_name_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_unit_name_LDADD = \
libcore.la
@@ -1602,7 +1606,8 @@ test_unit_file_SOURCES = \
test_unit_file_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_unit_file_LDADD = \
libcore.la
@@ -1811,7 +1816,8 @@ test_tables_CPPFLAGS = \
test_tables_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_tables_LDADD = \
libjournal-core.la \
@@ -1937,7 +1943,8 @@ test_cgroup_mask_SOURCES = \
src/test/test-cgroup-mask.c
test_cgroup_mask_CPPFLAGS = \
- $(AM_CPPFLAGS)
+ $(AM_CPPFLAGS) \
+ $(MOUNT_CFLAGS)
test_cgroup_mask_CFLAGS = \
$(AM_CFLAGS) \
@@ -1980,7 +1987,8 @@ test_path_SOURCES = \
src/test/test-path.c
test_path_CFLAGS = \
- $(AM_CFLAGS)
+ $(AM_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_path_LDADD = \
libcore.la
@@ -1989,7 +1997,8 @@ test_execute_SOURCES = \
src/test/test-execute.c
test_execute_CFLAGS = \
- $(AM_CFLAGS)
+ $(AM_CFLAGS) \
+ $(MOUNT_CFLAGS)
test_execute_LDADD = \
libcore.la
@@ -2016,7 +2025,8 @@ test_sched_prio_SOURCES = \
src/test/test-sched-prio.c
test_sched_prio_CPPFLAGS = \
- $(AM_CPPFLAGS)
+ $(AM_CPPFLAGS) \
+ $(MOUNT_CFLAGS)
test_sched_prio_CFLAGS = \
$(AM_CFLAGS) \
@@ -2103,7 +2113,8 @@ systemd_analyze_SOURCES = \
systemd_analyze_CFLAGS = \
$(AM_CFLAGS) \
- $(SECCOMP_CFLAGS)
+ $(SECCOMP_CFLAGS) \
+ $(MOUNT_CFLAGS)
systemd_analyze_LDADD = \
libcore.la
diff --git a/README b/README
index b9a89f5cd1..f6fb966b26 100644
--- a/README
+++ b/README
@@ -122,7 +122,7 @@ REQUIREMENTS:
glibc >= 2.16
libcap
- libmount >= 2.20 (from util-linux)
+ libmount >= 2.27 (from util-linux)
libseccomp >= 1.0.0 (optional)
libblkid >= 2.24 (from util-linux) (optional)
libkmod >= 15 (optional)
@@ -144,7 +144,7 @@ REQUIREMENTS:
During runtime, you need the following additional
dependencies:
- util-linux >= v2.26 required
+ util-linux >= v2.27 required
dbus >= 1.4.0 (strictly speaking optional, but recommended)
dracut (optional)
PolicyKit (optional)
diff --git a/configure.ac b/configure.ac
index aad6782e08..d71cb07366 100644
--- a/configure.ac
+++ b/configure.ac
@@ -427,7 +427,7 @@ AM_CONDITIONAL(HAVE_BLKID, [test "$have_blkid" = "yes"])
# ------------------------------------------------------------------------------
have_libmount=no
-PKG_CHECK_MODULES(MOUNT, [ mount >= 2.20 ],
+PKG_CHECK_MODULES(MOUNT, [ mount >= 2.27 ],
[AC_DEFINE(HAVE_LIBMOUNT, 1, [Define if libmount is available]) have_libmount=yes], have_libmount=no)
if test "x$have_libmount" = xno; then
AC_MSG_ERROR([*** libmount support required but libraries not found])
diff --git a/src/core/manager.c b/src/core/manager.c
index 8e518fbaaf..bb1009081a 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -571,8 +571,8 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
- m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd =
- m->cgroup_inotify_fd = -1;
+ m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = -1;
+
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
m->ask_password_inotify_fd = -1;
diff --git a/src/core/manager.h b/src/core/manager.h
index 5cf0dbd508..7b896f9bc7 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdio.h>
+#include <libmount.h>
#include "sd-bus.h"
#include "sd-event.h"
@@ -176,10 +177,8 @@ struct Manager {
Hashmap *devices_by_sysfs;
/* Data specific to the mount subsystem */
- FILE *proc_self_mountinfo;
+ struct libmnt_monitor *mount_monitor;
sd_event_source *mount_event_source;
- int utab_inotify_fd;
- sd_event_source *mount_utab_event_source;
/* Data specific to the swap filesystem */
FILE *proc_swaps;
diff --git a/src/core/mount.c b/src/core/mount.c
index 1f02aa5566..e7aae6e19a 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -23,8 +23,6 @@
#include <stdio.h>
#include <sys/epoll.h>
#include <signal.h>
-#include <libmount.h>
-#include <sys/inotify.h>
#include "manager.h"
#include "unit.h"
@@ -1535,13 +1533,13 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
}
static void mount_shutdown(Manager *m) {
+
assert(m);
m->mount_event_source = sd_event_source_unref(m->mount_event_source);
- m->mount_utab_event_source = sd_event_source_unref(m->mount_utab_event_source);
- m->proc_self_mountinfo = safe_fclose(m->proc_self_mountinfo);
- m->utab_inotify_fd = safe_close(m->utab_inotify_fd);
+ mnt_unref_monitor(m->mount_monitor);
+ m->mount_monitor = NULL;
}
static int mount_get_timeout(Unit *u, uint64_t *timeout) {
@@ -1560,53 +1558,41 @@ static int mount_get_timeout(Unit *u, uint64_t *timeout) {
static int mount_enumerate(Manager *m) {
int r;
+
assert(m);
mnt_init_debug(0);
- if (!m->proc_self_mountinfo) {
- m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!m->proc_self_mountinfo)
- return -errno;
+ if (!m->mount_monitor) {
+ int fd;
- r = sd_event_add_io(m->event, &m->mount_event_source, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m);
- if (r < 0)
+ m->mount_monitor = mnt_new_monitor();
+ if (!m->mount_monitor) {
+ r = -ENOMEM;
goto fail;
+ }
- /* Dispatch this before we dispatch SIGCHLD, so that
- * we always get the events from /proc/self/mountinfo
- * before the SIGCHLD of /usr/bin/mount. */
- r = sd_event_source_set_priority(m->mount_event_source, -10);
+ r = mnt_monitor_enable_kernel(m->mount_monitor, 1);
if (r < 0)
goto fail;
-
- (void) sd_event_source_set_description(m->mount_event_source, "mount-mountinfo-dispatch");
- }
-
- if (m->utab_inotify_fd < 0) {
- m->utab_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->utab_inotify_fd < 0) {
- r = -errno;
+ r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL);
+ if (r < 0)
goto fail;
- }
-
- (void) mkdir_p_label("/run/mount", 0755);
- r = inotify_add_watch(m->utab_inotify_fd, "/run/mount", IN_MOVED_TO);
- if (r < 0) {
- r = -errno;
+ /* mnt_unref_monitor() will close the fd */
+ fd = r = mnt_monitor_get_fd(m->mount_monitor);
+ if (r < 0)
goto fail;
- }
- r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m);
+ r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m);
if (r < 0)
goto fail;
- r = sd_event_source_set_priority(m->mount_utab_event_source, -10);
+ r = sd_event_source_set_priority(m->mount_event_source, -10);
if (r < 0)
goto fail;
- (void) sd_event_source_set_description(m->mount_utab_event_source, "mount-utab-dispatch");
+ (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
}
r = mount_load_proc_self_mountinfo(m, false);
@@ -1629,45 +1615,27 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
int r;
assert(m);
- assert(revents & (EPOLLPRI | EPOLLIN));
-
- /* The manager calls this for every fd event happening on the
- * /proc/self/mountinfo file, which informs us about mounting
- * table changes, and for /run/mount events which we watch
- * for mount options. */
+ assert(revents & EPOLLIN);
- if (fd == m->utab_inotify_fd) {
+ if (fd == mnt_monitor_get_fd(m->mount_monitor)) {
bool rescan = false;
- /* FIXME: We *really* need to replace this with
- * libmount's own API for this, we should not hardcode
- * internal behaviour of libmount here. */
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- l = read(fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
-
- log_error_errno(errno, "Failed to read utab inotify: %m");
- break;
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- /* Only care about changes to utab,
- * but we have to monitor the
- * directory to reliably get
- * notifications about when utab is
- * replaced using rename(2) */
- if ((e->mask & IN_Q_OVERFLOW) || streq(e->name, "utab"))
- rescan = true;
- }
- }
-
+ /* Drain all events and verify that the event is valid.
+ *
+ * Note that libmount also monitors /run/mount mkdir if the
+ * directory does not exist yet. The mkdir may generate event
+ * which is irrelevant for us.
+ *
+ * error: r < 0; valid: r == 0, false positive: rc == 1 */
+ do {
+ r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL);
+ if (r == 0)
+ rescan = true;
+ else if (r < 0)
+ return log_error_errno(r, "Failed to drain libmount events");
+ } while (r == 0);
+
+ log_debug("libmount event [rescan: %s]", yes_no(rescan));
if (!rescan)
return 0;
}