X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fcore%2Fmount.c;h=4fb4b0f81e389bdb34cb317dcc94ba69ecf4eabd;hb=f75f613d259e9332be8e9657fa37e73f7aabcb8a;hp=cfce01417e1f506dbe80f788a0fab390e3afafa8;hpb=1f736476474dcf371bfa0660aa71a7708f2ed217;p=thirdparty%2Fsystemd.git diff --git a/src/core/mount.c b/src/core/mount.c index cfce01417e1..4fb4b0f81e3 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -101,20 +101,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; @@ -251,6 +237,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; @@ -312,7 +324,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; @@ -342,9 +353,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 @@ -352,9 +360,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; @@ -426,6 +435,7 @@ static int mount_add_default_dependencies(Mount *m) { const char *after, *before; UnitDependencyMask mask; MountParameters *p; + bool nofail; int r; assert(m); @@ -444,6 +454,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 @@ -474,9 +485,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) @@ -616,28 +629,33 @@ static int mount_load_root_mount(Unit *u) { static int mount_load(Unit *u) { Mount *m = MOUNT(u); - int r; + int r, q, w; assert(u); assert(u->load_state == UNIT_STUB); r = mount_load_root_mount(u); - if (r < 0) - return r; if (m->from_proc_self_mountinfo || u->perpetual) - r = unit_load_fragment_and_dropin_optional(u); + q = unit_load_fragment_and_dropin_optional(u); + else + q = unit_load_fragment_and_dropin(u); + + /* Add in some extras. Note we do this in all cases (even if we failed to load the unit) when announced by the + * kernel, because we need some things to be set up no matter what when the kernel establishes a mount and thus + * we need to update the state in our unit to track it. After all, consider that we don't allow changing the + * 'slice' field for a unit once it is active. */ + if (u->load_state == UNIT_LOADED || m->from_proc_self_mountinfo || u->perpetual) + w = mount_add_extras(m); else - r = unit_load_fragment_and_dropin(u); + w = 0; + if (r < 0) return r; - - /* This is a new unit? Then let's add in some extras */ - if (u->load_state == UNIT_LOADED) { - r = mount_add_extras(m); - if (r < 0) - return r; - } + if (q < 0) + return q; + if (w < 0) + return w; return mount_verify(m); } @@ -686,7 +704,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; @@ -728,7 +746,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, @@ -792,9 +810,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; @@ -818,6 +835,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) { @@ -949,7 +969,6 @@ static void mount_enter_mounting(Mount *m) { (void) mkdir_p_label(m->where, m->directory_mode); unit_warn_if_dir_nonempty(UNIT(m), m->where); - unit_warn_leftover_processes(UNIT(m)); m->control_command_id = MOUNT_EXEC_MOUNT; @@ -1053,6 +1072,17 @@ fail: mount_enter_dead_or_mounted(m, MOUNT_SUCCESS); } +static void mount_cycle_clear(Mount *m) { + assert(m); + + /* Clear all state we shall forget for this new cycle */ + + m->result = MOUNT_SUCCESS; + m->reload_result = MOUNT_SUCCESS; + exec_command_reset_status_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX); + UNIT(m)->reset_accounting = true; +} + static int mount_start(Unit *u) { Mount *m = MOUNT(u); int r; @@ -1073,7 +1103,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; @@ -1083,13 +1113,9 @@ static int mount_start(Unit *u) { if (r < 0) return r; - m->result = MOUNT_SUCCESS; - m->reload_result = MOUNT_SUCCESS; - exec_command_reset_status_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX); - - u->reset_accounting = true; - + mount_cycle_clear(m); mount_enter_mounting(m); + return 1; } @@ -1153,6 +1179,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item(f, "state", mount_state_to_string(m->state)); (void) serialize_item(f, "result", mount_result_to_string(m->result)); (void) serialize_item(f, "reload-result", mount_result_to_string(m->reload_result)); + (void) serialize_item_format(f, "n-retry-umount", "%u", m->n_retry_umount); if (m->control_pid > 0) (void) serialize_item_format(f, "control-pid", PID_FMT, m->control_pid); @@ -1165,6 +1192,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { Mount *m = MOUNT(u); + int r; assert(u); assert(key); @@ -1178,6 +1206,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F log_unit_debug(u, "Failed to parse state value: %s", value); else m->deserialized_state = state; + } else if (streq(key, "result")) { MountResult f; @@ -1196,13 +1225,17 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F else if (f != MOUNT_SUCCESS) m->reload_result = f; + } else if (streq(key, "n-retry-umount")) { + + r = safe_atou(value, &m->n_retry_umount); + if (r < 0) + log_unit_debug(u, "Failed to parse n-retry-umount value: %s", value); + } else if (streq(key, "control-pid")) { - pid_t pid; - if (parse_pid(value, &pid) < 0) + if (parse_pid(value, &m->control_pid) < 0) log_unit_debug(u, "Failed to parse control-pid value: %s", value); - else - m->control_pid = pid; + } else if (streq(key, "control-command")) { MountExecCommand id; @@ -1410,59 +1443,51 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user return 0; } -typedef struct { - bool is_mounted; - bool just_mounted; - bool just_changed; -} MountSetupFlags; - static int mount_setup_new_unit( - Unit *u, + Manager *m, + const char *name, const char *what, const char *where, const char *options, const char *fstype, - MountSetupFlags *flags) { - - MountParameters *p; + MountProcFlags *ret_flags, + Unit **ret) { - assert(u); - assert(flags); + _cleanup_(unit_freep) Unit *u = NULL; + int r; - u->source_path = strdup("/proc/self/mountinfo"); - MOUNT(u)->where = strdup(where); - if (!u->source_path || !MOUNT(u)->where) - return -ENOMEM; + assert(m); + assert(name); + assert(ret_flags); + assert(ret); - /* Make sure to initialize those fields before mount_is_extrinsic(). */ - MOUNT(u)->from_proc_self_mountinfo = true; - p = &MOUNT(u)->parameters_proc_self_mountinfo; + r = unit_new_for_name(m, sizeof(Mount), name, &u); + if (r < 0) + return r; - p->what = strdup(what); - p->options = strdup(options); - p->fstype = strdup(fstype); - if (!p->what || !p->options || !p->fstype) - return -ENOMEM; + r = free_and_strdup(&u->source_path, "/proc/self/mountinfo"); + if (r < 0) + return r; - if (!mount_is_extrinsic(MOUNT(u))) { - const char *target; - int r; + r = free_and_strdup(&MOUNT(u)->where, where); + if (r < 0) + return r; - target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET; - r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); - if (r < 0) - return r; + r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype); + if (r < 0) + return r; - r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); - if (r < 0) - return r; - } + /* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load + * the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps + * to.*/ + MOUNT(u)->from_proc_self_mountinfo = true; + /* We have only allocated the stub now, let's enqueue this unit for loading now, so that everything else is + * loaded in now. */ unit_add_to_load_queue(u); - flags->is_mounted = true; - flags->just_mounted = true; - flags->just_changed = true; + *ret_flags = MOUNT_PROC_IS_MOUNTED | MOUNT_PROC_JUST_MOUNTED | MOUNT_PROC_JUST_CHANGED; + *ret = TAKE_PTR(u); return 0; } @@ -1472,11 +1497,10 @@ static int mount_setup_existing_unit( const char *where, const char *options, const char *fstype, - MountSetupFlags *flags) { + MountProcFlags *ret_flags) { - MountParameters *p; - bool load_extras = false; - int r1, r2, r3; + MountProcFlags flags = MOUNT_PROC_IS_MOUNTED; + int r; assert(u); assert(flags); @@ -1487,49 +1511,38 @@ static int mount_setup_existing_unit( return -ENOMEM; } - /* Make sure to initialize those fields before mount_is_extrinsic(). */ - p = &MOUNT(u)->parameters_proc_self_mountinfo; - - r1 = free_and_strdup(&p->what, what); - r2 = free_and_strdup(&p->options, options); - r3 = free_and_strdup(&p->fstype, fstype); - if (r1 < 0 || r2 < 0 || r3 < 0) - return -ENOMEM; + r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype); + if (r < 0) + return r; + if (r > 0) + flags |= MOUNT_PROC_JUST_CHANGED; - flags->just_changed = r1 > 0 || r2 > 0 || r3 > 0; - flags->is_mounted = true; - flags->just_mounted = !MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->just_mounted; + 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; - if (!mount_is_extrinsic(MOUNT(u)) && mount_is_network(p)) { - /* _netdev option may have shown up late, or on a - * remount. Add remote-fs dependencies, even though - * local-fs ones may already be there. - * - * Note: due to a current limitation (we don't track - * 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, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); - load_extras = true; - } - - if (u->load_state == UNIT_NOT_FOUND) { + 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 + * /proc/self/mountinfo we should reconsider it this, hence set it to UNIT_LOADED. */ u->load_state = UNIT_LOADED; u->load_error = 0; - /* Load in the extras later on, after we - * finished initialization of the unit */ - - /* FIXME: since we're going to load the unit later on, why setting load_extras=true ? */ - load_extras = true; - flags->just_changed = true; + flags |= MOUNT_PROC_JUST_CHANGED; } - if (load_extras) - return mount_add_extras(MOUNT(u)); + if (FLAGS_SET(flags, MOUNT_PROC_JUST_CHANGED)) { + /* If things changed, then make sure that all deps are regenerated. Let's + * first remove all automatic deps, and then add in the new ones. */ + unit_remove_dependencies(u, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); + + r = mount_add_extras(MOUNT(u)); + if (r < 0) + return r; + } + + *ret_flags = flags; return 0; } @@ -1542,7 +1555,7 @@ static int mount_setup_unit( bool set_flags) { _cleanup_free_ char *e = NULL; - MountSetupFlags flags; + MountProcFlags flags; Unit *u; int r; @@ -1566,44 +1579,32 @@ static int mount_setup_unit( r = unit_name_from_path(where, ".mount", &e); if (r < 0) - return r; + return log_error_errno(r, "Failed to generate unit name from path '%s': %m", where); u = manager_get_unit(m, e); - if (!u) { - /* First time we see this mount point meaning that it's - * not been initiated by a mount unit but rather by the - * sysadmin having called mount(8) directly. */ - r = unit_new_for_name(m, sizeof(Mount), e, &u); - if (r < 0) - goto fail; - - r = mount_setup_new_unit(u, what, where, options, fstype, &flags); - if (r < 0) - unit_free(u); - } else + if (u) r = mount_setup_existing_unit(u, what, where, options, fstype, &flags); - + else + /* First time we see this mount point meaning that it's not been initiated by a mount unit but rather + * by the sysadmin having called mount(8) directly. */ + r = mount_setup_new_unit(m, e, what, where, options, fstype, &flags, &u); if (r < 0) - goto fail; - - if (set_flags) { - MOUNT(u)->is_mounted = flags.is_mounted; - MOUNT(u)->just_mounted = flags.just_mounted; - MOUNT(u)->just_changed = flags.just_changed; - } + return log_warning_errno(r, "Failed to set up mount unit: %m"); - if (flags.just_changed) + /* If the mount changed properties or state, let's notify our clients */ + if (flags & (MOUNT_PROC_JUST_CHANGED|MOUNT_PROC_JUST_MOUNTED)) unit_add_to_dbus_queue(u); + if (set_flags) + MOUNT(u)->proc_flags = flags; + return 0; -fail: - return log_warning_errno(r, "Failed to set up mount unit: %m"); } static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; - int r = 0; + int r; assert(m); @@ -1616,7 +1617,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { if (r < 0) return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m"); - r = 0; for (;;) { struct libmnt_fs *fs; const char *device, *path, *options, *fstype; @@ -1645,12 +1645,10 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT); - k = mount_setup_unit(m, d, p, options, fstype, set_flags); - if (r == 0 && k < 0) - r = k; + (void) mount_setup_unit(m, d, p, options, fstype, set_flags); } - return r; + return 0; } static void mount_shutdown(Manager *m) { @@ -1708,7 +1706,7 @@ static void mount_enumerate_perpetual(Manager *m) { static bool mount_is_mounted(Mount *m) { assert(m); - return UNIT(m)->perpetual || m->is_mounted; + return UNIT(m)->perpetual || FLAGS_SET(m->proc_flags, MOUNT_PROC_IS_MOUNTED); } static void mount_enumerate(Manager *m) { @@ -1772,7 +1770,7 @@ fail: } static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { - _cleanup_set_free_ Set *around = NULL, *gone = NULL; + _cleanup_set_free_free_ Set *around = NULL, *gone = NULL; Manager *m = userdata; const char *what; Iterator i; @@ -1808,11 +1806,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, 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 *mount = MOUNT(u); - - mount->is_mounted = mount->just_mounted = mount->just_changed = false; - } + LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) + MOUNT(u)->proc_flags = 0; return 0; } @@ -1833,19 +1828,17 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, /* Remember that this device might just have disappeared */ if (set_ensure_allocated(&gone, &path_hash_ops) < 0 || - set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0) + set_put_strdup(gone, mount->parameters_proc_self_mountinfo.what) < 0) log_oom(); /* we don't care too much about OOM here... */ } mount->from_proc_self_mountinfo = false; + assert_se(update_parameters_proc_self_mount_info(mount, NULL, NULL, NULL) >= 0); switch (mount->state) { case MOUNT_MOUNTED: - /* This has just been unmounted by - * somebody else, follow the state - * change. */ - mount->result = MOUNT_SUCCESS; /* make sure we forget any earlier umount failures */ + /* This has just been unmounted by somebody else, follow the state change. */ mount_enter_dead(mount, MOUNT_SUCCESS); break; @@ -1853,7 +1846,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, break; } - } else if (mount->just_mounted || mount->just_changed) { + } else if (mount->proc_flags & (MOUNT_PROC_JUST_MOUNTED|MOUNT_PROC_JUST_CHANGED)) { /* A mount point was added or changed */ @@ -1864,7 +1857,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, /* This has just been mounted by somebody else, follow the state change, but let's * generate a new invocation ID for this implicitly and automatically. */ - (void) unit_acquire_invocation_id(UNIT(mount)); + (void) unit_acquire_invocation_id(u); + mount_cycle_clear(mount); mount_enter_mounted(mount, MOUNT_SUCCESS); break; @@ -1886,14 +1880,15 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, if (mount_is_mounted(mount) && mount->from_proc_self_mountinfo && mount->parameters_proc_self_mountinfo.what) { + /* Track devices currently used */ if (set_ensure_allocated(&around, &path_hash_ops) < 0 || - set_put(around, mount->parameters_proc_self_mountinfo.what) < 0) + set_put_strdup(around, mount->parameters_proc_self_mountinfo.what) < 0) log_oom(); } /* Reset the flags for later calls */ - mount->is_mounted = mount->just_mounted = mount->just_changed = false; + mount->proc_flags = 0; } SET_FOREACH(what, gone, i) {