]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/mount.c
core: reduce the number of stalled PIDs from the watched processes list when possible
[thirdparty/systemd.git] / src / core / mount.c
index cfdcc6e6f541b09dd1eccf1765f0acfb2ec9e6f7..4fb4b0f81e389bdb34cb317dcc94ba69ecf4eabd 100644 (file)
@@ -55,7 +55,6 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
 
 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 int mount_dispatch_proc_self_mountinfo_timer(sd_event_source *source, usec_t usec, void *userdata);
 
 static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
         return IN_SET(state,
@@ -102,20 +101,6 @@ static bool mount_is_bind(const MountParameters *p) {
         return false;
 }
 
-static bool mount_is_auto(const MountParameters *p) {
-        assert(p);
-
-        return !fstab_test_option(p->options, "noauto\0");
-}
-
-static bool mount_is_automount(const MountParameters *p) {
-        assert(p);
-
-        return fstab_test_option(p->options,
-                                 "comment=systemd.automount\0"
-                                 "x-systemd.automount\0");
-}
-
 static bool mount_is_bound_to_device(const Mount *m) {
         const MountParameters *p;
 
@@ -252,6 +237,32 @@ _pure_ static MountParameters* get_mount_parameters(Mount *m) {
         return get_mount_parameters_fragment(m);
 }
 
+static int update_parameters_proc_self_mount_info(
+                Mount *m,
+                const char *what,
+                const char *options,
+                const char *fstype) {
+
+        MountParameters *p;
+        int r, q, w;
+
+        p = &m->parameters_proc_self_mountinfo;
+
+        r = free_and_strdup(&p->what, what);
+        if (r < 0)
+                return r;
+
+        q = free_and_strdup(&p->options, options);
+        if (q < 0)
+                return q;
+
+        w = free_and_strdup(&p->fstype, fstype);
+        if (w < 0)
+                return w;
+
+        return r > 0 || q > 0 || w > 0;
+}
+
 static int mount_add_mount_dependencies(Mount *m) {
         MountParameters *pm;
         Unit *other;
@@ -313,7 +324,6 @@ static int mount_add_mount_dependencies(Mount *m) {
 }
 
 static int mount_add_device_dependencies(Mount *m) {
-        bool device_wants_mount;
         UnitDependencyMask mask;
         MountParameters *p;
         UnitDependency dep;
@@ -343,9 +353,6 @@ static int mount_add_device_dependencies(Mount *m) {
         if (path_equal(m->where, "/"))
                 return 0;
 
-        device_wants_mount =
-                mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager);
-
         /* Mount units from /proc/self/mountinfo are not bound to devices
          * by default since they're subject to races when devices are
          * unplugged. But the user can still force this dep with an
@@ -353,9 +360,10 @@ static int mount_add_device_dependencies(Mount *m) {
          * automatically stopped when the device disappears suddenly. */
         dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
 
-        mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
+        /* We always use 'what' from /proc/self/mountinfo if mounted */
+        mask = m->from_proc_self_mountinfo ? UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT : UNIT_DEPENDENCY_FILE;
 
-        r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask);
+        r = unit_add_node_dependency(UNIT(m), p->what, false, dep, mask);
         if (r < 0)
                 return r;
 
@@ -427,6 +435,7 @@ static int mount_add_default_dependencies(Mount *m) {
         const char *after, *before;
         UnitDependencyMask mask;
         MountParameters *p;
+        bool nofail;
         int r;
 
         assert(m);
@@ -445,6 +454,7 @@ static int mount_add_default_dependencies(Mount *m) {
                 return 0;
 
         mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
+        nofail = m->from_fragment ? fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0") : false;
 
         if (mount_is_network(p)) {
                 /* We order ourselves after network.target. This is
@@ -475,9 +485,11 @@ static int mount_add_default_dependencies(Mount *m) {
                 before = SPECIAL_LOCAL_FS_TARGET;
         }
 
-        r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
-        if (r < 0)
-                return r;
+        if (!nofail) {
+                r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
+                if (r < 0)
+                        return r;
+        }
 
         r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
         if (r < 0)
@@ -692,7 +704,7 @@ static int mount_coldplug(Unit *u) {
             pid_is_unwaited(m->control_pid) &&
             MOUNT_STATE_WITH_PROCESS(new_state)) {
 
-                r = unit_watch_pid(UNIT(m), m->control_pid);
+                r = unit_watch_pid(UNIT(m), m->control_pid, false);
                 if (r < 0)
                         return r;
 
@@ -734,7 +746,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sSloppyOptions: %s\n"
                 "%sLazyUnmount: %s\n"
                 "%sForceUnmount: %s\n"
-                "%sTimoutSec: %s\n",
+                "%sTimeoutSec: %s\n",
                 prefix, mount_state_to_string(m->state),
                 prefix, mount_result_to_string(m->result),
                 prefix, m->where,
@@ -798,9 +810,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(m), pid);
+        r = unit_watch_pid(UNIT(m), pid, true);
         if (r < 0)
-                /* FIXME: we need to do something here */
                 return r;
 
         *_pid = pid;
@@ -824,6 +835,9 @@ static void mount_enter_dead(Mount *m, MountResult f) {
         unit_unref_uid_gid(UNIT(m), true);
 
         dynamic_creds_destroy(&m->dynamic_creds);
+
+        /* Any dependencies based on /proc/self/mountinfo are now stale */
+        unit_remove_dependencies(UNIT(m), UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
 }
 
 static void mount_enter_mounted(Mount *m, MountResult f) {
@@ -1089,7 +1103,7 @@ static int mount_start(Unit *u) {
 
         assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED));
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
                 return r;
@@ -1429,32 +1443,6 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
         return 0;
 }
 
-static int update_parameters_proc_self_mount_info(
-                Mount *m,
-                const char *what,
-                const char *options,
-                const char *fstype) {
-
-        MountParameters *p;
-        int r, q, w;
-
-        p = &m->parameters_proc_self_mountinfo;
-
-        r = free_and_strdup(&p->what, what);
-        if (r < 0)
-                return r;
-
-        q = free_and_strdup(&p->options, options);
-        if (q < 0)
-                return q;
-
-        w = free_and_strdup(&p->fstype, fstype);
-        if (w < 0)
-                return w;
-
-        return r > 0 || q > 0 || w > 0;
-}
-
 static int mount_setup_new_unit(
                 Manager *m,
                 const char *name,
@@ -1529,10 +1517,10 @@ static int mount_setup_existing_unit(
         if (r > 0)
                 flags |= MOUNT_PROC_JUST_CHANGED;
 
-        if (!MOUNT(u)->from_proc_self_mountinfo) {
+        if (!MOUNT(u)->from_proc_self_mountinfo || FLAGS_SET(MOUNT(u)->proc_flags, MOUNT_PROC_JUST_MOUNTED))
                 flags |= MOUNT_PROC_JUST_MOUNTED;
-                MOUNT(u)->from_proc_self_mountinfo = true;
-        }
+
+        MOUNT(u)->from_proc_self_mountinfo = true;
 
         if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
                 /* The unit was previously not found or otherwise not loaded. Now that the unit shows up in
@@ -1666,7 +1654,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
 static void mount_shutdown(Manager *m) {
         assert(m);
 
-        m->mount_timeout_source = sd_event_source_unref(m->mount_timeout_source);
         m->mount_event_source = sd_event_source_unref(m->mount_event_source);
 
         mnt_unref_monitor(m->mount_monitor);
@@ -1782,50 +1769,13 @@ fail:
         mount_shutdown(m);
 }
 
-static void mount_process_proc_self_mountinfo(Manager *m);
-
 static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+        _cleanup_set_free_free_ Set *around = NULL, *gone = NULL;
         Manager *m = userdata;
+        const char *what;
+        Iterator i;
+        Unit *u;
         int r;
-        usec_t next_read = usec_add(m->mount_last_read_usec,
-                                    m->mount_last_duration_usec * 10);
-
-        if (now(CLOCK_MONOTONIC) < next_read) {
-                /* The (current) API for getting mount events from the Linux kernel
-                 * involves getting a "something changed" notification, and then having
-                 * to re-read the entire /proc/self/mountinfo file.  When there are lots
-                 * of mountpoints, this file is large and parsing it can take noticeable
-                 * time.  As most of the file won't have changed, this can be seen as wasted time.
-                 * If there is a "mount storm" such as 1000 mount points being created
-                 * in quick succession, this will result in 1000 successive notification.
-                 * If we respond to every notification, we will do quadratically more work
-                 * than if we respond just once after all the notifications have arrived.
-                 * In this (pathological) case, a delay in scheduling would actually
-                 * improve throughput as we would combine notifications and parse
-                 * the file less often.  We cannot expect the scheduler to notice
-                 * this pathology without help.
-                 * So when the rate of notifications means we are spending more than
-                 * 10% of real time handling them, we set a timer and stop listening
-                 * to notifications for a while.
-                 * If/when Linux provides an API which provides only details of what
-                 * has changed, this rate-limiting can be removed.
-                 */
-
-                r = sd_event_source_set_enabled(source, SD_EVENT_OFF);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to disable monitoring of /proc/self/mounting, ignoring: %m");
-                if (!m->mount_timeout_source) {
-                        r = sd_event_add_time(m->event, &m->mount_timeout_source,
-                                              CLOCK_MONOTONIC,
-                                              next_read,
-                                              0,
-                                              mount_dispatch_proc_self_mountinfo_timer,
-                                              m);
-                        if (r < 0)
-                                log_warning_errno(r, "Failed to set timeout to reread /proc/self/mounting, ignoring: %m");
-                }
-                return 0;
-        }
 
         assert(m);
         assert(revents & EPOLLIN);
@@ -1853,40 +1803,13 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                         return 0;
         }
 
-        mount_process_proc_self_mountinfo(m);
-        return 0;
-}
-
-static int mount_dispatch_proc_self_mountinfo_timer(sd_event_source *source, usec_t usec, void *userdata) {
-        Manager *m = userdata;
-        int r;
-
-        r = sd_event_source_set_enabled(m->mount_event_source, SD_EVENT_ON);
-        if (r < 0)
-                log_warning_errno(r, "Failed to reenable /proc/self/mountinfo monitor, ignoring: %m");
-        m->mount_timeout_source = sd_event_source_unref(source);
-        mount_process_proc_self_mountinfo(m);
-        return 0;
-}
-
-static void mount_process_proc_self_mountinfo(Manager *m) {
-        _cleanup_set_free_free_ Set *around = NULL, *gone = NULL;
-        const char *what;
-        Iterator i;
-        Unit *u;
-        int r;
-
-        m->mount_last_read_usec = now(CLOCK_MONOTONIC);
-        /* If an error occurs, assume 10ms */
-        m->mount_last_duration_usec = 10 * USEC_PER_MSEC;
-
         r = mount_load_proc_self_mountinfo(m, true);
         if (r < 0) {
                 /* Reset flags, just in case, for later calls */
                 LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT])
                         MOUNT(u)->proc_flags = 0;
 
-                return;
+                return 0;
         }
 
         manager_dispatch_load_queue(m);
@@ -1910,6 +1833,7 @@ static void mount_process_proc_self_mountinfo(Manager *m) {
                         }
 
                         mount->from_proc_self_mountinfo = false;
+                        assert_se(update_parameters_proc_self_mount_info(mount, NULL, NULL, NULL) >= 0);
 
                         switch (mount->state) {
 
@@ -1974,8 +1898,8 @@ static void mount_process_proc_self_mountinfo(Manager *m) {
                 /* Let the device units know that the device is no longer mounted */
                 device_found_node(m, what, 0, DEVICE_FOUND_MOUNT);
         }
-        m->mount_last_duration_usec = usec_sub_unsigned(now(CLOCK_MONOTONIC),
-                                                        m->mount_last_read_usec);
+
+        return 0;
 }
 
 static void mount_reset_failed(Unit *u) {