diff options
author | Chris Leech <cleech@redhat.com> | 2014-11-23 20:33:39 -0800 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2014-11-28 14:30:50 -0500 |
commit | befb6d54948480f836d53d633bef27e3505818c1 (patch) | |
tree | af77c29722d934c06ac261d2e74472058bc08d0c | |
parent | 8d3ae2bd4c9bf9fc2e57f7b3776325a1c750ca30 (diff) |
mount: monitor for utab changes with inotify
Parsing the mount table with libmount races against the mount command,
which will handle the actual mounting before updating utab. This means
the poll event on /proc/self/mountinfo can kick of a reparse in systemd
before the utab information is available.
This change adds in an additional event source using inotify to watch
for changes to utab. It only watches for IN_MOVED_TO events, matching
libmount behavior of always overwriting this file using rename(2).
This does add a second pass through the mount table parsing when utab is
updated.
-rw-r--r-- | src/core/manager.c | 2 | ||||
-rw-r--r-- | src/core/manager.h | 2 | ||||
-rw-r--r-- | src/core/mount.c | 50 |
3 files changed, 51 insertions, 3 deletions
diff --git a/src/core/manager.c b/src/core/manager.c index 3e1728f925..7b2550065d 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -540,7 +540,7 @@ int manager_new(SystemdRunningAs 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 = -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 = -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 02535023a3..ab75f902e5 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -182,6 +182,8 @@ struct Manager { /* Data specific to the mount subsystem */ FILE *proc_self_mountinfo; 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 d257925fa7..c961677ff9 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -25,6 +25,7 @@ #include <sys/epoll.h> #include <signal.h> #include <libmount.h> +#include <sys/inotify.h> #include "manager.h" #include "unit.h" @@ -1553,11 +1554,13 @@ 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); if (m->proc_self_mountinfo) { fclose(m->proc_self_mountinfo); m->proc_self_mountinfo = NULL; } + m->utab_inotify_fd = safe_close(m->utab_inotify_fd); } static int mount_get_timeout(Unit *u, uint64_t *timeout) { @@ -1597,12 +1600,32 @@ static int mount_enumerate(Manager *m) { goto fail; } + if (m->utab_inotify_fd < 0) { + m->utab_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (m->utab_inotify_fd < 0) + goto fail_with_errno; + + r = inotify_add_watch(m->utab_inotify_fd, "/run/mount", IN_MOVED_TO); + if (r < 0) + goto fail_with_errno; + + r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(m->mount_utab_event_source, -10); + if (r < 0) + goto fail; + } + r = mount_load_proc_self_mountinfo(m, false); if (r < 0) goto fail; return 0; +fail_with_errno: + r = -errno; fail: mount_shutdown(m); return r; @@ -1614,11 +1637,34 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, int r; assert(m); - assert(revents & EPOLLPRI); + 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 */ + * table changes + * This may also be called for /run/mount events */ + + if (fd == m->utab_inotify_fd) { + char inotify_buffer[sizeof(struct inotify_event) + NAME_MAX + 1]; + struct inotify_event *event; + char *p; + int rescan = 0; + + while ((r = read(fd, inotify_buffer, sizeof(inotify_buffer))) > 0) { + for (p = inotify_buffer; p < inotify_buffer + r; ) { + event = (struct inotify_event *) p; + /* 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 (strcmp(event->name, "utab") == 0) + rescan = 1; + p += sizeof(struct inotify_event) + event->len; + } + } + if (!rescan) + return 0; + } r = mount_load_proc_self_mountinfo(m, true); if (r < 0) { |