+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
[MOUNT_MOUNTED] = UNIT_ACTIVE,
[MOUNT_REMOUNTING] = UNIT_RELOADING,
[MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
- [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
- [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
[MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
[MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
[MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
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 bool MOUNT_STATE_WITH_PROCESS(MountState state) {
+ return IN_SET(state,
+ MOUNT_MOUNTING,
+ MOUNT_MOUNTING_DONE,
+ MOUNT_REMOUNTING,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL);
+}
+
static bool mount_needs_network(const char *options, const char *fstype) {
if (fstab_test_option(options, "_netdev\0"))
return true;
"x-systemd.automount\0");
}
-static bool mount_state_active(MountState state) {
- return IN_SET(state,
- MOUNT_MOUNTING,
- MOUNT_MOUNTING_DONE,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL);
-}
-
static bool mount_is_bound_to_device(const Mount *m) {
const MountParameters *p;
return get_mount_parameters_fragment(m);
}
-static int mount_add_mount_links(Mount *m) {
- _cleanup_free_ char *parent = NULL;
+static int mount_add_mount_dependencies(Mount *m) {
MountParameters *pm;
Unit *other;
Iterator i;
assert(m);
if (!path_equal(m->where, "/")) {
- /* Adds in links to other mount points that might lie further
- * up in the hierarchy */
+ _cleanup_free_ char *parent = NULL;
+
+ /* Adds in links to other mount points that might lie further up in the hierarchy */
parent = dirname_malloc(m->where);
if (!parent)
return -ENOMEM;
- r = unit_require_mounts_for(UNIT(m), parent);
+ r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
}
- /* Adds in links to other mount points that might be needed
- * for the source path (if this is a bind mount or a loop mount) to be
- * available. */
+ /* Adds in dependencies to other mount points that might be needed for the source path (if this is a bind mount
+ * or a loop mount) to be available. */
pm = get_mount_parameters_fragment(m);
if (pm && pm->what &&
path_is_absolute(pm->what) &&
(mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) {
- r = unit_require_mounts_for(UNIT(m), pm->what);
+ r = unit_require_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
- /* Adds in links to other units that use this path or paths
- * further down in the hierarchy */
+ /* Adds in dependencies to other units that use this path or paths further down in the hierarchy */
s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where);
SET_FOREACH(other, s, i) {
if (other == UNIT(m))
continue;
- r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true);
+ r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0)
return r;
if (UNIT(m)->fragment_path) {
/* If we have fragment configuration, then make this dependency required */
- r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true);
+ r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0)
return r;
}
return 0;
}
-static int mount_add_device_links(Mount *m) {
- MountParameters *p;
+static int mount_add_device_dependencies(Mount *m) {
bool device_wants_mount = false;
+ UnitDependencyMask mask;
+ MountParameters *p;
UnitDependency dep;
int r;
* automatically stopped when the device disappears suddenly. */
dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
- r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, dep);
+ mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
+
+ r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask);
if (r < 0)
return r;
return 0;
}
-static int mount_add_quota_links(Mount *m) {
- int r;
+static int mount_add_quota_dependencies(Mount *m) {
+ UnitDependencyMask mask;
MountParameters *p;
+ int r;
assert(m);
if (!needs_quota(p))
return 0;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
+ mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
+
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true, mask);
if (r < 0)
return r;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true, mask);
if (r < 0)
return r;
}
static int mount_add_default_dependencies(Mount *m) {
+ UnitDependencyMask mask;
+ int r;
MountParameters *p;
const char *after;
- int r;
assert(m);
if (!p)
return 0;
+ mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
+
if (mount_is_network(p)) {
/* We order ourselves after network.target. This is
* primarily useful at shutdown: services that take
* network.target, so that they are shut down only
* after this mount unit is stopped. */
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true, mask);
if (r < 0)
return r;
* whose purpose it is to delay this until the network
* is "up". */
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true, mask);
if (r < 0)
return r;
} else
after = SPECIAL_LOCAL_FS_PRE_TARGET;
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true, mask);
if (r < 0)
return r;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, mask);
if (r < 0)
return r;
+ /* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
+ if (streq_ptr(p->fstype, "tmpfs")) {
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true, mask);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
if (UNIT(m)->load_state != UNIT_LOADED)
return 0;
- if (!m->from_fragment && !m->from_proc_self_mountinfo)
+ if (!m->from_fragment && !m->from_proc_self_mountinfo && !UNIT(m)->perpetual)
return -ENOENT;
r = unit_name_from_path(m->where, ".mount", &e);
return r;
}
- r = mount_add_device_links(m);
+ r = mount_add_device_dependencies(m);
if (r < 0)
return r;
- r = mount_add_mount_links(m);
+ r = mount_add_mount_dependencies(m);
if (r < 0)
return r;
- r = mount_add_quota_links(m);
+ r = mount_add_quota_dependencies(m);
if (r < 0)
return r;
old_state = m->state;
m->state = state;
- if (!mount_state_active(state)) {
+ if (!MOUNT_STATE_WITH_PROCESS(state)) {
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
mount_unwatch_control_pid(m);
m->control_command = NULL;
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
- m->reload_result = MOUNT_SUCCESS;
}
static int mount_coldplug(Unit *u) {
if (m->control_pid > 0 &&
pid_is_unwaited(m->control_pid) &&
- mount_state_active(new_state)) {
+ MOUNT_STATE_WITH_PROCESS(new_state)) {
r = unit_watch_pid(UNIT(m), m->control_pid);
if (r < 0)
exec_context_dump(&m->exec_context, f, prefix);
kill_context_dump(&m->kill_context, f, prefix);
+ cgroup_context_dump(&m->cgroup_context, f, prefix);
}
static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
assert(_pid);
(void) unit_realize_cgroup(UNIT(m));
- if (m->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(m));
- m->reset_cpu_usage = false;
+ if (m->reset_accounting) {
+ (void) unit_reset_cpu_accounting(UNIT(m));
+ (void) unit_reset_ip_accounting(UNIT(m));
+ m->reset_accounting = false;
}
+ unit_export_state_files(UNIT(m));
+
r = unit_setup_exec_runtime(UNIT(m));
if (r < 0)
return r;
if (r < 0)
return r;
- exec_params.environment = UNIT(m)->manager->environment;
- exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(m)->manager);
- exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(m)->cgroup_path;
- exec_params.cgroup_delegate = m->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager);
+ manager_set_exec_params(UNIT(m)->manager, &exec_params);
+ unit_set_exec_params(UNIT(m), &exec_params);
r = exec_spawn(UNIT(m),
c,
if (m->result == MOUNT_SUCCESS)
m->result = f;
+ if (m->result != MOUNT_SUCCESS)
+ log_unit_warning(UNIT(m), "Failed with result '%s'.", mount_result_to_string(m->result));
+
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
exec_runtime_destroy(m->exec_runtime);
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
- exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager));
+ exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
unit_unref_uid_gid(UNIT(m), true);
mount_set_state(m, MOUNT_MOUNTED);
}
+static void mount_enter_dead_or_mounted(Mount *m, MountResult f) {
+ assert(m);
+
+ /* Enter DEAD or MOUNTED state, depending on what the kernel currently says about the mount point. We use this
+ * whenever we executed an operation, so that our internal state reflects what the kernel says again, after all
+ * ultimately we just mirror the kernel's internal state on this. */
+
+ if (m->from_proc_self_mountinfo)
+ mount_enter_mounted(m, f);
+ else
+ mount_enter_dead(m, f);
+}
+
+static int state_to_kill_operation(MountState state) {
+ switch (state) {
+
+ case MOUNT_REMOUNTING_SIGTERM:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ return KILL_TERMINATE;
+
+ case MOUNT_REMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGKILL:
+ return KILL_KILL;
+
+ default:
+ return _KILL_OPERATION_INVALID;
+ }
+}
+
static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
int r;
r = unit_kill_context(
UNIT(m),
&m->kill_context,
- (state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM) ?
- KILL_KILL : KILL_TERMINATE,
+ state_to_kill_operation(state),
-1,
m->control_pid,
false);
goto fail;
mount_set_state(m, state);
- } else if (state == MOUNT_REMOUNTING_SIGTERM)
+ } else if (state == MOUNT_REMOUNTING_SIGTERM && m->kill_context.send_sigkill)
mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS);
- else if (state == MOUNT_REMOUNTING_SIGKILL)
+ else if (IN_SET(state, MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL))
mount_enter_mounted(m, MOUNT_SUCCESS);
- else if (state == MOUNT_MOUNTING_SIGTERM)
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_SUCCESS);
- else if (state == MOUNT_UNMOUNTING_SIGTERM)
+ else if (state == MOUNT_UNMOUNTING_SIGTERM && m->kill_context.send_sigkill)
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS);
else
- mount_enter_dead(m, MOUNT_SUCCESS);
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
return;
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to kill processes: %m");
-
- if (IN_SET(state, MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL))
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
- else
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES);
}
static void mount_enter_unmounting(Mount *m) {
m->control_command_id = MOUNT_EXEC_UNMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
- r = exec_command_set(m->control_command, UMOUNT_PATH, m->where, NULL);
+ r = exec_command_set(m->control_command, UMOUNT_PATH, m->where, "-c", NULL);
if (r >= 0 && m->lazy_unmount)
r = exec_command_append(m->control_command, "-l", NULL);
if (r >= 0 && m->force_unmount)
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to run 'umount' task: %m");
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES);
}
static void mount_enter_mounting(Mount *m) {
r = exec_command_append(m->control_command, "-o", opts, NULL);
} else
r = -ENOENT;
-
if (r < 0)
goto fail;
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to run 'mount' task: %m");
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES);
+}
+
+static void mount_set_reload_result(Mount *m, MountResult result) {
+ assert(m);
+
+ /* Only store the first error we encounter */
+ if (m->reload_result != MOUNT_SUCCESS)
+ return;
+
+ m->reload_result = result;
}
static void mount_enter_remounting(Mount *m) {
assert(m);
+ /* Reset reload result when we are about to start a new remount operation */
+ m->reload_result = MOUNT_SUCCESS;
+
m->control_command_id = MOUNT_EXEC_REMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
} else
r = -ENOENT;
-
if (r < 0)
goto fail;
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to run 'remount' task: %m");
- m->reload_result = MOUNT_FAILURE_RESOURCES;
- mount_enter_mounted(m, MOUNT_SUCCESS);
+ mount_set_reload_result(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
}
static int mount_start(Unit *u) {
if (IN_SET(m->state,
MOUNT_UNMOUNTING,
MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL))
+ MOUNT_UNMOUNTING_SIGKILL))
return -EAGAIN;
/* Already on it! */
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
- m->reset_cpu_usage = true;
+ m->reset_accounting = true;
mount_enter_mounting(m);
return 1;
assert(m);
- /* Already on it */
- if (IN_SET(m->state,
- MOUNT_UNMOUNTING,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL))
+ switch (m->state) {
+
+ case MOUNT_UNMOUNTING:
+ case MOUNT_UNMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ /* Already on it */
return 0;
- assert(IN_SET(m->state,
- MOUNT_MOUNTING,
- MOUNT_MOUNTING_DONE,
- MOUNT_MOUNTED,
- MOUNT_REMOUNTING,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL));
+ case MOUNT_MOUNTING:
+ case MOUNT_MOUNTING_DONE:
+ case MOUNT_REMOUNTING:
+ /* If we are still waiting for /bin/mount, we go directly into kill mode. */
+ mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_SUCCESS);
+ return 0;
- mount_enter_unmounting(m);
- return 1;
+ case MOUNT_REMOUNTING_SIGTERM:
+ /* If we are already waiting for a hung remount, convert this to the matching unmounting state */
+ mount_set_state(m, MOUNT_UNMOUNTING_SIGTERM);
+ return 0;
+
+ case MOUNT_REMOUNTING_SIGKILL:
+ /* as above */
+ mount_set_state(m, MOUNT_UNMOUNTING_SIGKILL);
+ return 0;
+
+ case MOUNT_MOUNTED:
+ mount_enter_unmounting(m);
+ return 1;
+
+ default:
+ assert_not_reached("Unexpected state.");
+ }
}
static int mount_reload(Unit *u) {
assert(m);
- if (m->state == MOUNT_MOUNTING_DONE)
+ if (m->state == MOUNT_MOUNTING_DONE) /* not yet ready to reload, try again */
return -EAGAIN;
assert(m->state == MOUNT_MOUNTED);
mount_enter_remounting(m);
+
return 1;
}
else
assert_not_reached("Unknown code");
- if (m->result == MOUNT_SUCCESS)
+ if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM))
+ mount_set_reload_result(m, f);
+ else if (m->result == MOUNT_SUCCESS)
m->result = f;
if (m->control_command) {
log_unit_full(u, f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
"Mount process exited, code=%s status=%i", sigchld_code_to_string(code), status);
- /* Note that mount(8) returning and the kernel sending us a
- * mount table change event might happen out-of-order. If an
- * operation succeed we assume the kernel will follow soon too
- * and already change into the resulting state. If it fails
- * we check if the kernel still knows about the mount. and
- * change state accordingly. */
+ /* Note that mount(8) returning and the kernel sending us a mount table change event might happen
+ * out-of-order. If an operation succeed we assume the kernel will follow soon too and already change into the
+ * resulting state. If it fails we check if the kernel still knows about the mount. and change state
+ * accordingly. */
switch (m->state) {
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_MOUNTING_SIGTERM:
if (f == MOUNT_SUCCESS || m->from_proc_self_mountinfo)
/* If /bin/mount returned success, or if we see the mount point in /proc/self/mountinfo we are
break;
case MOUNT_REMOUNTING:
- case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGTERM:
-
- m->reload_result = f;
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_SUCCESS);
- else
- mount_enter_dead(m, MOUNT_SUCCESS);
-
+ case MOUNT_REMOUNTING_SIGKILL:
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
break;
case MOUNT_UNMOUNTING:
case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
- if (f == MOUNT_SUCCESS) {
-
- if (m->from_proc_self_mountinfo) {
-
- /* Still a mount point? If so, let's
- * try again. Most likely there were
- * multiple mount points stacked on
- * top of each other. Note that due to
- * the io event priority logic we can
- * be sure the new mountinfo is loaded
- * before we process the SIGCHLD for
- * the mount command. */
-
- if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
- log_unit_debug(u, "Mount still present, trying again.");
- m->n_retry_umount++;
- mount_enter_unmounting(m);
- } else {
- log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
- mount_enter_mounted(m, f);
- }
- } else
- mount_enter_dead(m, f);
-
- } else if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, f);
- else
+ if (m->from_proc_self_mountinfo) {
+
+ /* Still a mount point? If so, let's try again. Most likely there were multiple mount points
+ * stacked on top of each other. Note that due to the io event priority logic we can be sure
+ * the new mountinfo is loaded before we process the SIGCHLD for the mount command. */
+
+ if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
+ log_unit_debug(u, "Mount still present, trying again.");
+ m->n_retry_umount++;
+ mount_enter_unmounting(m);
+ } else {
+ log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
+ mount_enter_mounted(m, f);
+ }
+ } else
mount_enter_dead(m, f);
+
break;
default:
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
- log_unit_warning(UNIT(m), "Mounting timed out. Stopping.");
- mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Mounting timed out. Terminating.");
+ mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_REMOUNTING:
- log_unit_warning(UNIT(m), "Remounting timed out. Stopping.");
- m->reload_result = MOUNT_FAILURE_TIMEOUT;
- mount_enter_mounted(m, MOUNT_SUCCESS);
+ log_unit_warning(UNIT(m), "Remounting timed out. Terminating remount process.");
+ mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT);
+ mount_enter_signal(m, MOUNT_REMOUNTING_SIGTERM, MOUNT_SUCCESS);
break;
- case MOUNT_UNMOUNTING:
- log_unit_warning(UNIT(m), "Unmounting timed out. Stopping.");
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
+ case MOUNT_REMOUNTING_SIGTERM:
+ mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT);
- case MOUNT_MOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m), "Mounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Remounting timed out. Killing.");
+ mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS);
} else {
- log_unit_warning(UNIT(m), "Mounting timed out. Skipping SIGKILL. Ignoring.");
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
}
break;
- case MOUNT_REMOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m), "Remounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring.");
+ case MOUNT_REMOUNTING_SIGKILL:
+ mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT);
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
+ log_unit_warning(UNIT(m), "Mount process still around after SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
+ break;
+
+ case MOUNT_UNMOUNTING:
+ log_unit_warning(UNIT(m), "Unmounting timed out. Terminating.");
+ mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_UNMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m), "Unmounting timed out. Killing.");
+ log_unit_warning(UNIT(m), "Mount process timed out. Killing.");
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(m), "Unmounting timed out. Skipping SIGKILL. Ignoring.");
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Mount process timed out. Skipping SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT);
}
break;
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGKILL:
- log_unit_warning(UNIT(m),"Mount process still around after SIGKILL. Ignoring.");
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Mount process still around after SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT);
break;
default:
int r;
target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
- r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
}
* in the dependency "Set*" objects who created a
* dependency), we can only add deps, never lose them,
* until the next full daemon-reload. */
- unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true);
+ unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
load_extras = true;
}
}
static void mount_shutdown(Manager *m) {
-
assert(m);
m->mount_event_source = sd_event_source_unref(m->mount_event_source);
}
static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
+ Mount *m = MOUNT(u);
+
+ assert(m);
+
return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
}