X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fmount.c;h=419cf27a889ea884b062b912e121ff4f5d53793e;hp=78740a8b2d6ab170008d72e9c5ac9049bdd9d342;hb=fea7838e7e0b2724f5e0bc028121a08b42995045;hpb=257f1d8ec49046c7b481801acfdd5bf57c9efa5c diff --git a/src/core/mount.c b/src/core/mount.c index 78740a8b2..419cf27a8 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -30,6 +30,7 @@ #include "load-fragment.h" #include "load-dropin.h" #include "log.h" +#include "sd-messages.h" #include "strv.h" #include "mkdir.h" #include "path-util.h" @@ -221,9 +222,11 @@ static int mount_add_swap_links(Mount *m) { assert(m); - LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP]) - if ((r = swap_add_one_mount_link(SWAP(other), m)) < 0) + LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP]) { + r = swap_add_one_mount_link(SWAP(other), m); + if (r < 0) return r; + } return 0; } @@ -234,9 +237,11 @@ static int mount_add_path_links(Mount *m) { assert(m); - LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH]) - if ((r = path_add_one_mount_link(PATH(other), m)) < 0) + LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH]) { + r = path_add_one_mount_link(PATH(other), m); + if (r < 0) return r; + } return 0; } @@ -247,9 +252,11 @@ static int mount_add_automount_links(Mount *m) { assert(m); - LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_AUTOMOUNT]) - if ((r = automount_add_one_mount_link(AUTOMOUNT(other), m)) < 0) + LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_AUTOMOUNT]) { + r = automount_add_one_mount_link(AUTOMOUNT(other), m); + if (r < 0) return r; + } return 0; } @@ -260,9 +267,11 @@ static int mount_add_socket_links(Mount *m) { assert(m); - LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SOCKET]) - if ((r = socket_add_one_mount_link(SOCKET(other), m)) < 0) + LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SOCKET]) { + r = socket_add_one_mount_link(SOCKET(other), m); + if (r < 0) return r; + } return 0; } @@ -320,6 +329,12 @@ static bool mount_is_bind(MountParameters *p) { if (p->fstype && streq(p->fstype, "bind")) return true; + if (mount_test_option(p->options, "rbind")) + return true; + + if (p->fstype && streq(p->fstype, "rbind")) + return true; + return false; } @@ -352,17 +367,21 @@ static int mount_add_device_links(Mount *m) { if (!p->what) return 0; - if (!mount_is_bind(p) && - !path_equal(m->where, "/")) { - r = unit_add_node_link(UNIT(m), p->what, false); - if (r < 0) - return r; - } + if (mount_is_bind(p)) + return 0; + + if (!is_device_path(p->what)) + return 0; + + if (path_equal(m->where, "/")) + return 0; + + r = unit_add_node_link(UNIT(m), p->what, false); + if (r < 0) + return r; if (p->passno > 0 && - !mount_is_bind(p) && - !path_equal(m->where, "/") && - UNIT(m)->manager->running_as == MANAGER_SYSTEM) { + UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) { char *name; Unit *fsck; /* Let's add in the fsck service */ @@ -374,7 +393,8 @@ static int mount_add_device_links(Mount *m) { r = manager_load_unit_prepare(UNIT(m)->manager, name, NULL, NULL, &fsck); if (r < 0) { - log_warning("Failed to prepare unit %s: %s", name, strerror(-r)); + log_warning_unit(name, + "Failed to prepare unit %s: %s", name, strerror(-r)); free(name); return r; } @@ -396,7 +416,7 @@ static int mount_add_quota_links(Mount *m) { assert(m); - if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) + if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM) return 0; p = get_mount_parameters_fragment(m); @@ -424,7 +444,7 @@ static int mount_add_default_dependencies(Mount *m) { assert(m); - if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) + if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM) return 0; p = get_mount_parameters_fragment(m); @@ -485,7 +505,9 @@ static int mount_fix_timeouts(Mount *m) { free(t); if (r < 0) { - log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout); + log_warning_unit(UNIT(m)->id, + "Failed to parse timeout for %s, ignoring: %s", + m->where, timeout); return r; } @@ -517,22 +539,29 @@ static int mount_verify(Mount *m) { free(e); if (!b) { - log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->id); + log_error_unit(UNIT(m)->id, + "%s's Where setting doesn't match unit name. Refusing.", + UNIT(m)->id); return -EINVAL; } if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) { - log_error("Cannot create mount unit for API file system %s. Refusing.", m->where); + log_error_unit(UNIT(m)->id, + "Cannot create mount unit for API file system %s. Refusing.", + m->where); return -EINVAL; } if (UNIT(m)->fragment_path && !m->parameters_fragment.what) { - log_error("%s's What setting is missing. Refusing.", UNIT(m)->id); + log_error_unit(UNIT(m)->id, + "%s's What setting is missing. Refusing.", UNIT(m)->id); return -EBADMSG; } if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) { - log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id); + log_error_unit(UNIT(m)->id, + "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.", + UNIT(m)->id); return -EINVAL; } @@ -543,10 +572,6 @@ static int mount_add_extras(Mount *m) { Unit *u = UNIT(m); int r; - r = unit_add_exec_dependencies(u, &m->exec_context); - if (r < 0) - return r; - if (UNIT(m)->fragment_path) m->from_fragment = true; @@ -558,6 +583,10 @@ static int mount_add_extras(Mount *m) { path_kill_slashes(m->where); + r = unit_add_exec_dependencies(u, &m->exec_context); + if (r < 0) + return r; + if (!UNIT(m)->description) { r = unit_set_description(u, m->where); if (r < 0) @@ -694,15 +723,16 @@ static void mount_set_state(Mount *m, MountState state) { state == MOUNT_UNMOUNTING_SIGTERM || state == MOUNT_UNMOUNTING_SIGKILL || state == MOUNT_FAILED) { - if (state != old_state) - mount_notify_automount(m, -ENODEV); - } + if (state != old_state) + mount_notify_automount(m, -ENODEV); + } if (state != old_state) - log_debug("%s changed %s -> %s", - UNIT(m)->id, - mount_state_to_string(old_state), - mount_state_to_string(state)); + log_debug_unit(UNIT(m)->id, + "%s changed %s -> %s", + UNIT(m)->id, + 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; @@ -737,10 +767,12 @@ static int mount_coldplug(Unit *u) { if (m->control_pid <= 0) return -EBADMSG; - if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0) + r = unit_watch_pid(UNIT(m), m->control_pid); + if (r < 0) return r; - if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0) + r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch); + if (r < 0) return r; } @@ -796,7 +828,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { assert(c); assert(_pid); - if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0) + r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch); + if (r < 0) goto fail; if ((r = exec_spawn(c, @@ -850,53 +883,25 @@ static void mount_enter_mounted(Mount *m, MountResult f) { static void mount_enter_signal(Mount *m, MountState state, MountResult f) { int r; - Set *pid_set = NULL; - bool wait_for_exit = false; assert(m); if (f != MOUNT_SUCCESS) m->result = f; - if (m->kill_context.kill_mode != KILL_NONE) { - int sig = (state == MOUNT_MOUNTING_SIGTERM || - state == MOUNT_UNMOUNTING_SIGTERM || - state == MOUNT_REMOUNTING_SIGTERM) ? m->kill_context.kill_signal : SIGKILL; - - if (m->control_pid > 0) { - if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH) - - log_warning("Failed to kill control process %li: %m", (long) m->control_pid); - else - wait_for_exit = true; - } - - if (m->kill_context.kill_mode == KILL_CONTROL_GROUP) { - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { - r = -ENOMEM; - goto fail; - } - - /* Exclude the control pid from being killed via the cgroup */ - if (m->control_pid > 0) - if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) - goto fail; - - r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, false, pid_set, NULL); - if (r < 0) { - if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) - log_warning("Failed to kill control group: %s", strerror(-r)); - } else if (r > 0) - wait_for_exit = true; - - set_free(pid_set); - pid_set = NULL; - } - } + r = unit_kill_context( + UNIT(m), + &m->kill_context, + state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM, + -1, + m->control_pid, + false); + if (r < 0) + goto fail; - if (wait_for_exit) { - if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0) + if (r > 0) { + r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch); + if (r < 0) goto fail; mount_set_state(m, state); @@ -908,15 +913,29 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) { return; fail: - log_warning("%s failed to kill processes: %s", UNIT(m)->id, strerror(-r)); + log_warning_unit(UNIT(m)->id, + "%s failed to kill processes: %s", UNIT(m)->id, strerror(-r)); if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL) mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES); else mount_enter_dead(m, MOUNT_FAILURE_RESOURCES); +} - if (pid_set) - set_free(pid_set); +void warn_if_dir_nonempty(const char *unit, const char* where) { + assert(unit); + assert(where); + + if (dir_is_empty(where) > 0) + return; + + log_struct_unit(LOG_NOTICE, + unit, + "MESSAGE=%s: Directory %s to mount over is not empty, mounting anyway.", + unit, where, + "WHERE=%s", where, + MESSAGE_ID(SD_MESSAGE_OVERMOUNTING), + NULL); } static void mount_enter_unmounting(Mount *m) { @@ -944,7 +963,9 @@ static void mount_enter_unmounting(Mount *m) { return; fail: - log_warning("%s failed to run 'umount' task: %s", UNIT(m)->id, strerror(-r)); + log_warning_unit(UNIT(m)->id, + "%s failed to run 'umount' task: %s", + UNIT(m)->id, strerror(-r)); mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES); } @@ -959,8 +980,7 @@ static void mount_enter_mounting(Mount *m) { mkdir_p_label(m->where, m->directory_mode); - if (dir_is_empty(m->where) <= 0) - log_notice("%s: Directory %s to mount over is not empty, ignoring. (To see the over-mounted files, please manually mount the underlying file system to a secondary location.)", m->meta.id, m->where); + warn_if_dir_nonempty(m->meta.id, m->where); /* Create the source directory for bind-mounts if needed */ p = get_mount_parameters_fragment(m); @@ -993,7 +1013,9 @@ static void mount_enter_mounting(Mount *m) { return; fail: - log_warning("%s failed to run 'mount' task: %s", UNIT(m)->id, strerror(-r)); + log_warning_unit(UNIT(m)->id, + "%s failed to run 'mount' task: %s", + UNIT(m)->id, strerror(-r)); mount_enter_dead(m, MOUNT_FAILURE_RESOURCES); } @@ -1051,7 +1073,9 @@ static void mount_enter_remounting(Mount *m) { return; fail: - log_warning("%s failed to run 'remount' task: %s", UNIT(m)->id, strerror(-r)); + log_warning_unit(UNIT(m)->id, + "%s failed to run 'remount' task: %s", + UNIT(m)->id, strerror(-r)); m->reload_result = MOUNT_FAILURE_RESOURCES; mount_enter_mounted(m, MOUNT_SUCCESS); } @@ -1153,7 +1177,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F MountState state; if ((state = mount_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); + log_debug_unit(u->id, "Failed to parse state value %s", value); else m->deserialized_state = state; } else if (streq(key, "result")) { @@ -1161,7 +1185,8 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F f = mount_result_from_string(value); if (f < 0) - log_debug("Failed to parse result value %s", value); + log_debug_unit(UNIT(m)->id, + "Failed to parse result value %s", value); else if (f != MOUNT_SUCCESS) m->result = f; @@ -1170,7 +1195,8 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F f = mount_result_from_string(value); if (f < 0) - log_debug("Failed to parse reload result value %s", value); + log_debug_unit(UNIT(m)->id, + "Failed to parse reload result value %s", value); else if (f != MOUNT_SUCCESS) m->reload_result = f; @@ -1178,21 +1204,24 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F pid_t pid; if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse control-pid value %s", value); + log_debug_unit(UNIT(m)->id, + "Failed to parse control-pid value %s", value); else m->control_pid = pid; } else if (streq(key, "control-command")) { MountExecCommand id; if ((id = mount_exec_command_from_string(value)) < 0) - log_debug("Failed to parse exec-command value %s", value); + log_debug_unit(UNIT(m)->id, + "Failed to parse exec-command value %s", value); else { m->control_command_id = id; m->control_command = m->exec_command + id; } } else - log_debug("Unknown serialization key '%s'", key); + log_debug_unit(UNIT(m)->id, + "Unknown serialization key '%s'", key); return 0; } @@ -1250,8 +1279,9 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; } - log_full(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, - "%s mount process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status); + log_full_unit(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, u->id, + "%s mount process exited, code=%s status=%i", + u->id, 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 @@ -1318,27 +1348,33 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { case MOUNT_MOUNTING: case MOUNT_MOUNTING_DONE: - log_warning("%s mounting timed out. Stopping.", u->id); + log_warning_unit(u->id, + "%s mounting timed out. Stopping.", u->id); mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT); break; case MOUNT_REMOUNTING: - log_warning("%s remounting timed out. Stopping.", u->id); + log_warning_unit(u->id, + "%s remounting timed out. Stopping.", u->id); m->reload_result = MOUNT_FAILURE_TIMEOUT; mount_enter_mounted(m, MOUNT_SUCCESS); break; case MOUNT_UNMOUNTING: - log_warning("%s unmounting timed out. Stopping.", u->id); + log_warning_unit(u->id, + "%s unmounting timed out. Stopping.", u->id); mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT); break; case MOUNT_MOUNTING_SIGTERM: if (m->kill_context.send_sigkill) { - log_warning("%s mounting timed out. Killing.", u->id); + log_warning_unit(u->id, + "%s mounting timed out. Killing.", u->id); mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { - log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->id); + log_warning_unit(u->id, + "%s mounting timed out. Skipping SIGKILL. Ignoring.", + u->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1349,10 +1385,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("%s remounting timed out. Killing.", u->id); + log_warning_unit(u->id, + "%s remounting timed out. Killing.", u->id); mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { - log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->id); + log_warning_unit(u->id, + "%s remounting timed out. Skipping SIGKILL. Ignoring.", + u->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1363,10 +1402,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("%s unmounting timed out. Killing.", u->id); + log_warning_unit(u->id, + "%s unmounting timed out. Killing.", u->id); mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { - log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->id); + log_warning_unit(u->id, + "%s unmounting timed out. Skipping SIGKILL. Ignoring.", + u->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1378,7 +1420,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("%s mount process still around after SIGKILL. Ignoring.", u->id); + log_warning_unit(u->id, + "%s mount process still around after SIGKILL. Ignoring.", + u->id); if (m->from_proc_self_mountinfo) mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); @@ -1404,6 +1448,7 @@ static int mount_add_one( bool delete; char *e, *w = NULL, *o = NULL, *f = NULL; MountParameters *p; + bool load_extras = false; assert(m); assert(what); @@ -1449,17 +1494,32 @@ static int mount_add_one( goto fail; } + u->source_path = strdup("/proc/self/mountinfo"); + if (!u->source_path) { + r = -ENOMEM; + goto fail; + } + unit_add_to_load_queue(u); } else { delete = false; free(e); + if (!MOUNT(u)->where) { + MOUNT(u)->where = strdup(where); + if (!MOUNT(u)->where) { + r = -ENOMEM; + goto fail; + } + } + if (u->load_state == UNIT_ERROR) { u->load_state = UNIT_LOADED; u->load_error = 0; - r = mount_add_extras(MOUNT(u)); - if (r < 0) - goto fail; + + /* Load in the extras later on, after we + * finished initialization of the unit */ + load_extras = true; } } @@ -1490,6 +1550,12 @@ static int mount_add_one( p->passno = passno; + if (load_extras) { + r = mount_add_extras(MOUNT(u)); + if (r < 0) + goto fail; + } + unit_add_to_dbus_queue(u); return 0; @@ -1634,7 +1700,8 @@ void mount_fd_event(Manager *m, int events) { * /proc/self/mountinfo file, which informs us about mounting * table changes */ - if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) { + r = mount_load_proc_self_mountinfo(m, true); + if (r < 0) { log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r)); /* Reset flags, just in case, for later calls */ @@ -1801,13 +1868,15 @@ DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult); const UnitVTable mount_vtable = { .object_size = sizeof(Mount), - .exec_context_offset = offsetof(Mount, exec_context), .sections = "Unit\0" "Mount\0" "Install\0", + .exec_context_offset = offsetof(Mount, exec_context), + .exec_section = "Mount", + .no_alias = true, .no_instances = true,