chiark / gitweb /
core: set some event source priorities to enforce dispatching order
[elogind.git] / src / core / mount.c
index 0c15b99f945e85a83aa42ee86acfb0062d9ed6b3..634dff19a978a28ccf554eaae940ec4517ad4b54 100644 (file)
@@ -59,6 +59,9 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
         [MOUNT_FAILED] = UNIT_FAILED
 };
 
+static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
+static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+
 static char* mount_test_option(const char *haystack, const char *needle) {
         struct mntent me = { .mnt_opts = (char*) haystack };
 
@@ -138,8 +141,8 @@ static void mount_init(Unit *u) {
 
         if (unit_has_name(u, "-.mount")) {
                 /* Don't allow start/stop for root directory */
-                UNIT(m)->refuse_manual_start = true;
-                UNIT(m)->refuse_manual_stop = true;
+                u->refuse_manual_start = true;
+                u->refuse_manual_stop = true;
         } else {
                 /* The stdio/kmsg bridge socket is on /, in order to avoid a
                  * dep loop, don't use kmsg logging for -.mount */
@@ -156,11 +159,30 @@ static void mount_init(Unit *u) {
          * already trying to comply its last one. */
         m->exec_context.same_pgrp = true;
 
-        m->timer_watch.type = WATCH_INVALID;
-
         m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
 
-        UNIT(m)->ignore_on_isolate = true;
+        u->ignore_on_isolate = true;
+}
+
+static int mount_arm_timer(Mount *m) {
+        int r;
+
+        assert(m);
+
+        if (m->timeout_usec <= 0) {
+                m->timer_event_source = sd_event_source_unref(m->timer_event_source);
+                return 0;
+        }
+
+        if (m->timer_event_source) {
+                r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec);
+                if (r < 0)
+                        return r;
+
+                return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT);
+        }
+
+        return sd_event_add_monotonic(UNIT(m)->manager->event, now(CLOCK_MONOTONIC) + m->timeout_usec, 0, mount_dispatch_timer, m, &m->timer_event_source);
 }
 
 static void mount_unwatch_control_pid(Mount *m) {
@@ -201,7 +223,7 @@ static void mount_done(Unit *u) {
 
         mount_unwatch_control_pid(m);
 
-        unit_unwatch_timer(u, &m->timer_watch);
+        m->timer_event_source = sd_event_source_unref(m->timer_event_source);
 }
 
 _pure_ static MountParameters* get_mount_parameters_fragment(Mount *m) {
@@ -626,7 +648,7 @@ static void mount_set_state(Mount *m, MountState state) {
             state != MOUNT_UNMOUNTING_SIGKILL &&
             state != MOUNT_REMOUNTING_SIGTERM &&
             state != MOUNT_REMOUNTING_SIGKILL) {
-                unit_unwatch_timer(UNIT(m), &m->timer_watch);
+                m->timer_event_source = sd_event_source_unref(m->timer_event_source);
                 mount_unwatch_control_pid(m);
                 m->control_command = NULL;
                 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
@@ -672,34 +694,33 @@ static int mount_coldplug(Unit *u) {
         else if (m->from_proc_self_mountinfo)
                 new_state = MOUNT_MOUNTED;
 
-        if (new_state != m->state) {
-
-                if (new_state == MOUNT_MOUNTING ||
-                    new_state == MOUNT_MOUNTING_DONE ||
-                    new_state == MOUNT_REMOUNTING ||
-                    new_state == MOUNT_UNMOUNTING ||
-                    new_state == MOUNT_MOUNTING_SIGTERM ||
-                    new_state == MOUNT_MOUNTING_SIGKILL ||
-                    new_state == MOUNT_UNMOUNTING_SIGTERM ||
-                    new_state == MOUNT_UNMOUNTING_SIGKILL ||
-                    new_state == MOUNT_REMOUNTING_SIGTERM ||
-                    new_state == MOUNT_REMOUNTING_SIGKILL) {
-
-                        if (m->control_pid <= 0)
-                                return -EBADMSG;
-
-                        r = unit_watch_pid(UNIT(m), m->control_pid);
-                        if (r < 0)
-                                return r;
+        if (new_state == m->state)
+                return 0;
 
-                        r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
-                        if (r < 0)
-                                return r;
-                }
+        if (new_state == MOUNT_MOUNTING ||
+            new_state == MOUNT_MOUNTING_DONE ||
+            new_state == MOUNT_REMOUNTING ||
+            new_state == MOUNT_UNMOUNTING ||
+            new_state == MOUNT_MOUNTING_SIGTERM ||
+            new_state == MOUNT_MOUNTING_SIGKILL ||
+            new_state == MOUNT_UNMOUNTING_SIGTERM ||
+            new_state == MOUNT_UNMOUNTING_SIGKILL ||
+            new_state == MOUNT_REMOUNTING_SIGTERM ||
+            new_state == MOUNT_REMOUNTING_SIGKILL) {
+
+                if (m->control_pid <= 0)
+                        return -EBADMSG;
+
+                r = unit_watch_pid(UNIT(m), m->control_pid);
+                if (r < 0)
+                        return r;
 
-                mount_set_state(m, new_state);
+                r = mount_arm_timer(m);
+                if (r < 0)
+                        return r;
         }
 
+        mount_set_state(m, new_state);
         return 0;
 }
 
@@ -751,7 +772,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
 
         unit_realize_cgroup(UNIT(m));
 
-        r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
+        r = mount_arm_timer(m);
         if (r < 0)
                 goto fail;
 
@@ -782,7 +803,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
         return 0;
 
 fail:
-        unit_unwatch_timer(UNIT(m), &m->timer_watch);
+        m->timer_event_source = sd_event_source_unref(m->timer_event_source);
 
         return r;
 }
@@ -825,7 +846,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
                 goto fail;
 
         if (r > 0) {
-                r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
+                r = mount_arm_timer(m);
                 if (r < 0)
                         goto fail;
 
@@ -944,12 +965,6 @@ fail:
         mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
 }
 
-static void mount_enter_mounting_done(Mount *m) {
-        assert(m);
-
-        mount_set_state(m, MOUNT_MOUNTING_DONE);
-}
-
 static void mount_enter_remounting(Mount *m) {
         int r;
 
@@ -959,17 +974,11 @@ static void mount_enter_remounting(Mount *m) {
         m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
 
         if (m->from_fragment) {
-                char *buf = NULL;
                 const char *o;
 
-                if (m->parameters_fragment.options) {
-                        if (!(buf = strappend("remount,", m->parameters_fragment.options))) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        o = buf;
-                } else
+                if (m->parameters_fragment.options)
+                        o = strappenda("remount,", m->parameters_fragment.options);
+                else
                         o = "remount";
 
                 r = exec_command_set(
@@ -980,8 +989,6 @@ static void mount_enter_remounting(Mount *m) {
                                 "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
                                 "-o", o,
                                 NULL);
-
-                free(buf);
         } else
                 r = -ENOENT;
 
@@ -990,7 +997,8 @@ static void mount_enter_remounting(Mount *m) {
 
         mount_unwatch_control_pid(m);
 
-        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
+        r = mount_spawn(m, m->control_command, &m->control_pid);
+        if (r < 0)
                 goto fail;
 
         mount_set_state(m, MOUNT_REMOUNTING);
@@ -1279,44 +1287,43 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         unit_add_to_dbus_queue(u);
 }
 
-static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
-        Mount *m = MOUNT(u);
+static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
+        Mount *m = MOUNT(userdata);
 
         assert(m);
-        assert(elapsed == 1);
-        assert(w == &m->timer_watch);
+        assert(m->timer_event_source == source);
 
         switch (m->state) {
 
         case MOUNT_MOUNTING:
         case MOUNT_MOUNTING_DONE:
-                log_warning_unit(u->id,
-                                 "%s mounting timed out. Stopping.", u->id);
+                log_warning_unit(UNIT(m)->id,
+                                 "%s mounting timed out. Stopping.", UNIT(m)->id);
                 mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
                 break;
 
         case MOUNT_REMOUNTING:
-                log_warning_unit(u->id,
-                                 "%s remounting timed out. Stopping.", u->id);
+                log_warning_unit(UNIT(m)->id,
+                                 "%s remounting timed out. Stopping.", UNIT(m)->id);
                 m->reload_result = MOUNT_FAILURE_TIMEOUT;
                 mount_enter_mounted(m, MOUNT_SUCCESS);
                 break;
 
         case MOUNT_UNMOUNTING:
-                log_warning_unit(u->id,
-                                 "%s unmounting timed out. Stopping.", u->id);
+                log_warning_unit(UNIT(m)->id,
+                                 "%s unmounting timed out. Stopping.", UNIT(m)->id);
                 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
                 break;
 
         case MOUNT_MOUNTING_SIGTERM:
                 if (m->kill_context.send_sigkill) {
-                        log_warning_unit(u->id,
-                                         "%s mounting timed out. Killing.", u->id);
+                        log_warning_unit(UNIT(m)->id,
+                                         "%s mounting timed out. Killing.", UNIT(m)->id);
                         mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
                 } else {
-                        log_warning_unit(u->id,
+                        log_warning_unit(UNIT(m)->id,
                                          "%s mounting timed out. Skipping SIGKILL. Ignoring.",
-                                         u->id);
+                                         UNIT(m)->id);
 
                         if (m->from_proc_self_mountinfo)
                                 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1327,13 +1334,13 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
 
         case MOUNT_REMOUNTING_SIGTERM:
                 if (m->kill_context.send_sigkill) {
-                        log_warning_unit(u->id,
-                                         "%s remounting timed out. Killing.", u->id);
+                        log_warning_unit(UNIT(m)->id,
+                                         "%s remounting timed out. Killing.", UNIT(m)->id);
                         mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
                 } else {
-                        log_warning_unit(u->id,
+                        log_warning_unit(UNIT(m)->id,
                                          "%s remounting timed out. Skipping SIGKILL. Ignoring.",
-                                         u->id);
+                                         UNIT(m)->id);
 
                         if (m->from_proc_self_mountinfo)
                                 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1344,13 +1351,13 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
 
         case MOUNT_UNMOUNTING_SIGTERM:
                 if (m->kill_context.send_sigkill) {
-                        log_warning_unit(u->id,
-                                         "%s unmounting timed out. Killing.", u->id);
+                        log_warning_unit(UNIT(m)->id,
+                                         "%s unmounting timed out. Killing.", UNIT(m)->id);
                         mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
                 } else {
-                        log_warning_unit(u->id,
+                        log_warning_unit(UNIT(m)->id,
                                          "%s unmounting timed out. Skipping SIGKILL. Ignoring.",
-                                         u->id);
+                                         UNIT(m)->id);
 
                         if (m->from_proc_self_mountinfo)
                                 mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1362,9 +1369,9 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
         case MOUNT_MOUNTING_SIGKILL:
         case MOUNT_REMOUNTING_SIGKILL:
         case MOUNT_UNMOUNTING_SIGKILL:
-                log_warning_unit(u->id,
+                log_warning_unit(UNIT(m)->id,
                                  "%s mount process still around after SIGKILL. Ignoring.",
-                                 u->id);
+                                 UNIT(m)->id);
 
                 if (m->from_proc_self_mountinfo)
                         mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1375,6 +1382,8 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
         default:
                 assert_not_reached("Timeout at wrong time.");
         }
+
+        return 0;
 }
 
 static int mount_add_one(
@@ -1582,6 +1591,8 @@ 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);
+
         if (m->proc_self_mountinfo) {
                 fclose(m->proc_self_mountinfo);
                 m->proc_self_mountinfo = NULL;
@@ -1593,20 +1604,20 @@ static int mount_enumerate(Manager *m) {
         assert(m);
 
         if (!m->proc_self_mountinfo) {
-                struct epoll_event ev = {
-                        .events = EPOLLPRI,
-                        .data.ptr = &m->mount_watch,
-                };
-
                 m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
                 if (!m->proc_self_mountinfo)
                         return -errno;
 
-                m->mount_watch.type = WATCH_MOUNT;
-                m->mount_watch.fd = fileno(m->proc_self_mountinfo);
+                r = sd_event_add_io(m->event, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m, &m->mount_event_source);
+                if (r < 0)
+                        goto fail;
 
-                if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0)
-                        return -errno;
+                /* Dispatch this before we dispatch SIGCHLD, so that
+                 * we always get the events from /proc/self/mountinfo
+                 * before the SIGCHLD of /bin/mount. */
+                r = sd_event_source_set_priority(m->mount_event_source, -10);
+                if (r < 0)
+                        goto fail;
         }
 
         r = mount_load_proc_self_mountinfo(m, false);
@@ -1620,12 +1631,13 @@ fail:
         return r;
 }
 
-void mount_fd_event(Manager *m, int events) {
+static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+        Manager *m = userdata;
         Unit *u;
         int r;
 
         assert(m);
-        assert(events & EPOLLPRI);
+        assert(revents & EPOLLPRI);
 
         /* The manager calls this for every fd event happening on the
          * /proc/self/mountinfo file, which informs us about mounting
@@ -1642,7 +1654,7 @@ void mount_fd_event(Manager *m, int events) {
                         mount->is_mounted = mount->just_mounted = mount->just_changed = false;
                 }
 
-                return;
+                return 0;
         }
 
         manager_dispatch_load_queue(m);
@@ -1679,7 +1691,7 @@ void mount_fd_event(Manager *m, int events) {
                                 break;
 
                         case MOUNT_MOUNTING:
-                                mount_enter_mounting_done(mount);
+                                mount_set_state(mount, MOUNT_MOUNTING_DONE);
                                 break;
 
                         default:
@@ -1696,6 +1708,8 @@ void mount_fd_event(Manager *m, int events) {
                 /* Reset the flags for later calls */
                 mount->is_mounted = mount->just_mounted = mount->just_changed = false;
         }
+
+        return 0;
 }
 
 static void mount_reset_failed(Unit *u) {
@@ -1710,7 +1724,7 @@ static void mount_reset_failed(Unit *u) {
         m->reload_result = MOUNT_SUCCESS;
 }
 
-static int mount_kill(Unit *u, KillWho who, int signo, DBusError *error) {
+static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
         return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
 }
 
@@ -1753,15 +1767,15 @@ DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
 
 const UnitVTable mount_vtable = {
         .object_size = sizeof(Mount),
+        .exec_context_offset = offsetof(Mount, exec_context),
+        .cgroup_context_offset = offsetof(Mount, cgroup_context),
+        .kill_context_offset = offsetof(Mount, kill_context),
 
         .sections =
                 "Unit\0"
                 "Mount\0"
                 "Install\0",
-
         .private_section = "Mount",
-        .exec_context_offset = offsetof(Mount, exec_context),
-        .cgroup_context_offset = offsetof(Mount, cgroup_context),
 
         .no_alias = true,
         .no_instances = true,
@@ -1789,13 +1803,12 @@ const UnitVTable mount_vtable = {
         .check_gc = mount_check_gc,
 
         .sigchld_event = mount_sigchld_event,
-        .timer_event = mount_timer_event,
 
         .reset_failed = mount_reset_failed,
 
         .bus_interface = "org.freedesktop.systemd1.Mount",
-        .bus_message_handler = bus_mount_message_handler,
-        .bus_invalidating_properties =  bus_mount_invalidating_properties,
+        .bus_vtable = bus_mount_vtable,
+        .bus_changing_properties = bus_mount_changing_properties,
         .bus_set_property = bus_mount_set_property,
         .bus_commit_properties = bus_mount_commit_properties,