X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fmount.c;h=e46c72a644fcc088a41c88e7a6c3792f6ca30c39;hp=93bfa99f3fe123525b6c290fb9985a1100ef3681;hb=99f37ad86e114b2d1c9eaedf2bc1a0004a265d26;hpb=77009452cfd25208509b14ea985e81fdf9f7d40e diff --git a/src/core/mount.c b/src/core/mount.c index 93bfa99f3..e46c72a64 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -59,21 +59,90 @@ 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 }; + + assert(needle); + + /* Like glibc's hasmntopt(), but works on a string, not a + * struct mntent */ + + if (!haystack) + return NULL; + + return hasmntopt(&me, needle); +} + +static bool mount_is_network(MountParameters *p) { + assert(p); + + if (mount_test_option(p->options, "_netdev")) + return true; + + if (p->fstype && fstype_is_network(p->fstype)) + return true; + + return false; +} + +static bool mount_is_bind(MountParameters *p) { + assert(p); + + if (mount_test_option(p->options, "bind")) + return true; + + 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; +} + +static bool mount_is_auto(MountParameters *p) { + assert(p); + + return !mount_test_option(p->options, "noauto"); +} + +static bool needs_quota(MountParameters *p) { + assert(p); + + if (mount_is_network(p)) + return false; + + if (mount_is_bind(p)) + return false; + + return mount_test_option(p->options, "usrquota") || + mount_test_option(p->options, "grpquota") || + mount_test_option(p->options, "quota") || + mount_test_option(p->options, "usrjquota") || + mount_test_option(p->options, "grpjquota"); +} + static void mount_init(Unit *u) { Mount *m = MOUNT(u); assert(u); assert(u->load_state == UNIT_STUB); - m->timeout_usec = DEFAULT_TIMEOUT_USEC; + m->timeout_usec = u->manager->default_timeout_start_usec; m->directory_mode = 0755; exec_context_init(&m->exec_context); 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 */ @@ -90,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) { @@ -129,13 +217,14 @@ static void mount_done(Unit *u) { mount_parameters_done(&m->parameters_fragment); cgroup_context_done(&m->cgroup_context); - exec_context_done(&m->exec_context, manager_is_reloading_or_reexecuting(u->manager)); + exec_context_done(&m->exec_context); + m->exec_runtime = exec_runtime_unref(m->exec_runtime); exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX); m->control_command = NULL; 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) { @@ -182,7 +271,10 @@ static int mount_add_mount_links(Mount *m) { * for the source path (if this is a bind mount) to be * available. */ pm = get_mount_parameters_fragment(m); - if (pm && path_is_absolute(pm->what)) { + if (pm && pm->what && + path_is_absolute(pm->what) && + !mount_is_network(pm)) { + r = unit_require_mounts_for(UNIT(m), pm->what); if (r < 0) return r; @@ -214,72 +306,6 @@ static int mount_add_mount_links(Mount *m) { return 0; } -static char* mount_test_option(const char *haystack, const char *needle) { - struct mntent me = { .mnt_opts = (char*) haystack }; - - assert(needle); - - /* Like glibc's hasmntopt(), but works on a string, not a - * struct mntent */ - - if (!haystack) - return NULL; - - return hasmntopt(&me, needle); -} - -static bool mount_is_network(MountParameters *p) { - assert(p); - - if (mount_test_option(p->options, "_netdev")) - return true; - - if (p->fstype && fstype_is_network(p->fstype)) - return true; - - return false; -} - -static bool mount_is_bind(MountParameters *p) { - assert(p); - - if (mount_test_option(p->options, "bind")) - return true; - - 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; -} - -static bool mount_is_auto(MountParameters *p) { - assert(p); - - return !mount_test_option(p->options, "noauto"); -} - -static bool needs_quota(MountParameters *p) { - assert(p); - - if (mount_is_network(p)) - return false; - - if (mount_is_bind(p)) - return false; - - return mount_test_option(p->options, "usrquota") || - mount_test_option(p->options, "grpquota") || - mount_test_option(p->options, "quota") || - mount_test_option(p->options, "usrjquota") || - mount_test_option(p->options, "grpjquota"); -} - static int mount_add_device_links(Mount *m) { MountParameters *p; bool device_wants_mount = false; @@ -310,33 +336,6 @@ static int mount_add_device_links(Mount *m) { if (r < 0) return r; - if (p->passno > 0 && - UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) { - char *name; - Unit *fsck; - /* Let's add in the fsck service */ - - /* aka SPECIAL_FSCK_SERVICE */ - name = unit_name_from_path_instance("systemd-fsck", p->what, ".service"); - if (!name) - return -ENOMEM; - - r = manager_load_unit_prepare(UNIT(m)->manager, name, NULL, NULL, &fsck); - if (r < 0) { - log_warning_unit(name, - "Failed to prepare unit %s: %s", name, strerror(-r)); - free(name); - return r; - } - free(name); - - SERVICE(fsck)->fsck_passno = p->passno; - - r = unit_add_two_dependencies(UNIT(m), UNIT_AFTER, UNIT_REQUIRES, fsck, true); - if (r < 0) - return r; - } - return 0; } @@ -650,7 +649,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; @@ -696,34 +695,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; } @@ -775,7 +773,11 @@ 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 = unit_setup_exec_runtime(UNIT(m)); + if (r < 0) + goto fail; + + r = mount_arm_timer(m); if (r < 0) goto fail; @@ -792,6 +794,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { UNIT(m)->cgroup_path, UNIT(m)->id, NULL, + m->exec_runtime, &pid); if (r < 0) goto fail; @@ -806,7 +809,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; } @@ -817,7 +820,9 @@ static void mount_enter_dead(Mount *m, MountResult f) { if (f != MOUNT_SUCCESS) m->result = f; - exec_context_tmp_dirs_done(&m->exec_context); + exec_runtime_destroy(m->exec_runtime); + m->exec_runtime = exec_runtime_unref(m->exec_runtime); + mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD); } @@ -849,7 +854,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; @@ -968,12 +973,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; @@ -983,17 +982,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( @@ -1004,8 +997,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; @@ -1014,7 +1005,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); @@ -1111,8 +1103,6 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { if (m->control_command_id >= 0) unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id)); - exec_context_serialize(&m->exec_context, UNIT(m), f); - return 0; } @@ -1169,22 +1159,6 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F m->control_command_id = id; m->control_command = m->exec_command + id; } - } else if (streq(key, "tmp-dir")) { - char *t; - - t = strdup(value); - if (!t) - return log_oom(); - - m->exec_context.tmp_dir = t; - } else if (streq(key, "var-tmp-dir")) { - char *t; - - t = strdup(value); - if (!t) - return log_oom(); - - m->exec_context.var_tmp_dir = t; } else log_debug_unit(UNIT(m)->id, "Unknown serialization key '%s'", key); @@ -1303,44 +1277,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); @@ -1351,13 +1324,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); @@ -1368,13 +1341,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); @@ -1386,9 +1359,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); @@ -1399,6 +1372,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( @@ -1407,7 +1382,6 @@ static int mount_add_one( const char *where, const char *options, const char *fstype, - int passno, bool set_flags) { int r; Unit *u; @@ -1527,8 +1501,6 @@ static int mount_add_one( free(p->fstype); p->fstype = f; - p->passno = passno; - if (load_extras) { r = mount_add_extras(MOUNT(u)); if (r < 0) @@ -1598,7 +1570,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { if (!d || !p) return log_oom(); - k = mount_add_one(m, d, p, o, fstype, 0, set_flags); + k = mount_add_one(m, d, p, o, fstype, set_flags); if (k < 0) r = k; } @@ -1609,6 +1581,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; @@ -1620,20 +1594,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); @@ -1647,12 +1621,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 @@ -1669,7 +1644,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); @@ -1706,7 +1681,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: @@ -1723,6 +1698,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) { @@ -1737,7 +1714,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); } @@ -1780,15 +1757,16 @@ 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), + .exec_runtime_offset = offsetof(Mount, exec_runtime), .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, @@ -1816,13 +1794,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,