diff options
-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) { |