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,
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;
assert(m);
- if (!IN_SET(m->state, MOUNT_DEAD, MOUNT_MOUNTED, MOUNT_FAILED)) {
- /* This was pending, so need to udpate the count */
- assert(u->manager->mount_pending_count > 0);
- u->manager->mount_pending_count--;
- }
-
m->where = mfree(m->where);
mount_parameters_done(&m->parameters_proc_self_mountinfo);
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;
}
static int mount_add_device_dependencies(Mount *m) {
- bool device_wants_mount;
UnitDependencyMask mask;
MountParameters *p;
UnitDependency dep;
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
* 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;
const char *after, *before;
UnitDependencyMask mask;
MountParameters *p;
+ bool nofail;
int r;
assert(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
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)
static void mount_set_state(Mount *m, MountState state) {
MountState old_state;
- int was_pending, is_pending;
assert(m);
if (m->state != state)
old_state = m->state;
m->state = state;
- was_pending = !IN_SET(old_state, MOUNT_DEAD, MOUNT_MOUNTED, MOUNT_FAILED);
- is_pending = !IN_SET(state, MOUNT_DEAD, MOUNT_MOUNTED, MOUNT_FAILED);
-
- if (was_pending && !is_pending) {
- assert(UNIT(m)->manager->mount_pending_count > 0);
- UNIT(m)->manager->mount_pending_count--;
- }
-
- if (is_pending && !was_pending)
- UNIT(m)->manager->mount_pending_count++;
-
if (!MOUNT_STATE_WITH_PROCESS(state)) {
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
mount_unwatch_control_pid(m);
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;
"%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,
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;
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) {
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;
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,
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
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);
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 there are pending mounts initiated by systemd, then
- * we need to process changes promptly, otherwise we
- * rate limit re-reading the file.
- */
- if (m->mount_pending_count == 0 &&
- 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);
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);
}
mount->from_proc_self_mountinfo = false;
+ assert_se(update_parameters_proc_self_mount_info(mount, NULL, NULL, NULL) >= 0);
switch (mount->state) {
/* 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) {