X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fcore%2Fmount.c;h=b7fd35fc678ca206fe46e07d48602fc60f6078e7;hb=74b45889e4ea1d7e0ae551419fccbb5bf4489f05;hp=cfdcc6e6f541b09dd1eccf1765f0acfb2ec9e6f7;hpb=0e89eb474d9a467df23965e77679e26a4d26ffca;p=thirdparty%2Fsystemd.git diff --git a/src/core/mount.c b/src/core/mount.c index cfdcc6e6f54..b7fd35fc678 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -5,18 +5,16 @@ #include #include -#include - #include "sd-messages.h" #include "alloc-util.h" #include "dbus-mount.h" #include "dbus-unit.h" #include "device.h" -#include "escape.h" #include "exit-status.h" #include "format-util.h" #include "fstab-util.h" +#include "libmount-util.h" #include "log.h" #include "manager.h" #include "mkdir.h" @@ -36,9 +34,6 @@ #define RETRY_UMOUNT_MAX 32 -DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter); - static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { [MOUNT_DEAD] = UNIT_INACTIVE, [MOUNT_MOUNTING] = UNIT_ACTIVATING, @@ -55,7 +50,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 +96,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 +232,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 +319,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 +348,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 +355,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 +430,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 +449,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 +480,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 +699,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 +741,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 +805,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 +830,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 +1098,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 +1438,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 +1512,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 @@ -1632,7 +1615,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { for (;;) { struct libmnt_fs *fs; const char *device, *path, *options, *fstype; - _cleanup_free_ char *d = NULL, *p = NULL; int k; k = mnt_table_next_fs(t, i, &fs); @@ -1649,15 +1631,9 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { if (!device || !path) continue; - if (cunescape(device, UNESCAPE_RELAX, &d) < 0) - return log_oom(); - - if (cunescape(path, UNESCAPE_RELAX, &p) < 0) - return log_oom(); + device_found_node(m, device, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT); - device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT); - - (void) mount_setup_unit(m, d, p, options, fstype, set_flags); + (void) mount_setup_unit(m, device, path, options, fstype, set_flags); } return 0; @@ -1666,7 +1642,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 +1757,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 +1791,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 +1821,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 +1886,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) { @@ -1995,7 +1907,7 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { assert(m); - return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error); + return unit_kill_common(u, who, signo, -1, m->control_pid, error); } static int mount_control_pid(Unit *u) {