diff --git a/src/core/mount.c b/src/core/mount.c index afdbaa1d9d..ead9bc1f44 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -68,20 +68,16 @@ static bool MOUNT_STATE_WITH_PROCESS(MountState state) { MOUNT_UNMOUNTING_SIGKILL); } -static bool mount_needs_network(const char *options, const char *fstype) { - if (fstab_test_option(options, "_netdev\0")) - return true; - - if (fstype && fstype_is_network(fstype)) - return true; - - return false; -} - static bool mount_is_network(const MountParameters *p) { assert(p); - return mount_needs_network(p->options, p->fstype); + if (fstab_test_option(p->options, "_netdev\0")) + return true; + + if (p->fstype && fstype_is_network(p->fstype)) + return true; + + return false; } static bool mount_is_loop(const MountParameters *p) { @@ -129,11 +125,11 @@ static bool mount_is_bound_to_device(const Mount *m) { return fstab_test_option(p->options, "x-systemd.device-bound\0"); } -static bool needs_quota(const MountParameters *p) { +static bool mount_needs_quota(const MountParameters *p) { assert(p); - /* Quotas are not enabled on network filesystems, - * but we want them, for example, on storage connected via iscsi */ + /* Quotas are not enabled on network filesystems, but we want them, for example, on storage connected via + * iscsi. We hence don't use mount_is_network() here, as that would also return true for _netdev devices. */ if (p->fstype && fstype_is_network(p->fstype)) return false; @@ -211,11 +207,9 @@ static void mount_unwatch_control_pid(Mount *m) { static void mount_parameters_done(MountParameters *p) { assert(p); - free(p->what); - free(p->options); - free(p->fstype); - - p->what = p->options = p->fstype = NULL; + p->what = mfree(p->what); + p->options = mfree(p->options); + p->fstype = mfree(p->fstype); } static void mount_done(Unit *u) { @@ -318,7 +312,7 @@ static int mount_add_mount_dependencies(Mount *m) { } static int mount_add_device_dependencies(Mount *m) { - bool device_wants_mount = false; + bool device_wants_mount; UnitDependencyMask mask; MountParameters *p; UnitDependency dep; @@ -348,8 +342,8 @@ static int mount_add_device_dependencies(Mount *m) { if (path_equal(m->where, "/")) return 0; - if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager)) - device_wants_mount = true; + 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 @@ -381,7 +375,7 @@ static int mount_add_quota_dependencies(Mount *m) { if (!p) return 0; - if (!needs_quota(p)) + if (!mount_needs_quota(p)) return 0; mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT; @@ -429,10 +423,10 @@ static bool mount_is_extrinsic(Mount *m) { } static int mount_add_default_dependencies(Mount *m) { + const char *after, *before; UnitDependencyMask mask; - int r; MountParameters *p; - const char *after; + int r; assert(m); @@ -474,8 +468,15 @@ static int mount_add_default_dependencies(Mount *m) { return r; after = SPECIAL_REMOTE_FS_PRE_TARGET; - } else + before = SPECIAL_REMOTE_FS_TARGET; + } else { after = SPECIAL_LOCAL_FS_PRE_TARGET; + before = SPECIAL_LOCAL_FS_TARGET; + } + + 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) @@ -542,6 +543,10 @@ static int mount_add_extras(Mount *m) { assert(m); + /* Note: this call might be called after we already have been loaded once (and even when it has already been + * activated), in case data from /proc/self/mountinfo has changed. This means all code here needs to be ready + * to run with an already set up unit. */ + if (u->fragment_path) m->from_fragment = true; @@ -611,28 +616,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 - r = unit_load_fragment_and_dropin(u); + 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 + 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); } @@ -944,7 +954,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; @@ -1048,6 +1057,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; @@ -1078,13 +1098,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; } @@ -1148,6 +1164,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); @@ -1160,6 +1177,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); @@ -1173,6 +1191,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; @@ -1191,13 +1210,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, "control-pid")) { - pid_t pid; + } else if (streq(key, "n-retry-umount")) { - if (parse_pid(value, &pid) < 0) + 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")) { + + 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; @@ -1405,59 +1428,77 @@ 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 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( - Unit *u, + Manager *m, + const char *name, const char *what, const char *where, const char *options, const char *fstype, - MountSetupFlags *flags) { + MountProcFlags *ret_flags, + Unit **ret) { - MountParameters *p; + _cleanup_(unit_freep) Unit *u = NULL; + int r; - assert(u); - assert(flags); + assert(m); + assert(name); + assert(ret_flags); + assert(ret); - u->source_path = strdup("/proc/self/mountinfo"); - MOUNT(u)->where = strdup(where); - if (!u->source_path || !MOUNT(u)->where) - return -ENOMEM; + r = unit_new_for_name(m, sizeof(Mount), name, &u); + if (r < 0) + return r; - /* Make sure to initialize those fields before mount_is_extrinsic(). */ + r = free_and_strdup(&u->source_path, "/proc/self/mountinfo"); + if (r < 0) + return r; + + r = free_and_strdup(&MOUNT(u)->where, where); + if (r < 0) + return r; + + r = update_parameters_proc_self_mount_info(MOUNT(u), what, options, fstype); + 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; - p = &MOUNT(u)->parameters_proc_self_mountinfo; - - p->what = strdup(what); - p->options = strdup(options); - p->fstype = strdup(fstype); - if (!p->what || !p->options || !p->fstype) - return -ENOMEM; - - if (!mount_is_extrinsic(MOUNT(u))) { - const char *target; - 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, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); - 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; - } + /* 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; } @@ -1467,11 +1508,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); @@ -1482,49 +1522,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; + 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; - 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; - - 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; - - 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 (!MOUNT(u)->from_proc_self_mountinfo) { + flags |= MOUNT_PROC_JUST_MOUNTED; + MOUNT(u)->from_proc_self_mountinfo = 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; } @@ -1537,7 +1566,7 @@ static int mount_setup_unit( bool set_flags) { _cleanup_free_ char *e = NULL; - MountSetupFlags flags; + MountProcFlags flags; Unit *u; int r; @@ -1561,44 +1590,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; + return log_warning_errno(r, "Failed to set up mount unit: %m"); - if (set_flags) { - MOUNT(u)->is_mounted = flags.is_mounted; - MOUNT(u)->just_mounted = flags.just_mounted; - MOUNT(u)->just_changed = flags.just_changed; - } - - 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); @@ -1611,7 +1628,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; @@ -1640,12 +1656,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) { @@ -1703,7 +1717,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) { @@ -1767,7 +1781,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; @@ -1803,11 +1817,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; } @@ -1828,7 +1839,7 @@ 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... */ } @@ -1837,10 +1848,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, 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; @@ -1848,7 +1856,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 */ @@ -1859,7 +1867,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; @@ -1881,14 +1890,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) { diff --git a/src/core/mount.h b/src/core/mount.h index 67ab8ecf93..2e59f1fe04 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -34,6 +34,13 @@ typedef struct MountParameters { char *fstype; } MountParameters; +/* Used while looking for mount points that vanished or got added from/to /proc/self/mountinfo */ +typedef enum MountProcFlags { + MOUNT_PROC_IS_MOUNTED = 1 << 0, + MOUNT_PROC_JUST_MOUNTED = 1 << 1, + MOUNT_PROC_JUST_CHANGED = 1 << 2, +} MountProcFlags; + struct Mount { Unit meta; @@ -45,11 +52,7 @@ struct Mount { bool from_proc_self_mountinfo:1; bool from_fragment:1; - /* Used while looking for mount points that vanished or got - * added from/to /proc/self/mountinfo */ - bool is_mounted:1; - bool just_mounted:1; - bool just_changed:1; + MountProcFlags proc_flags; bool sloppy_options; diff --git a/src/core/swap.c b/src/core/swap.c index 90207a48fa..2d8463b8b1 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -273,9 +273,71 @@ static int swap_load_devnode(Swap *s) { return swap_set_devnode(s, p); } -static int swap_load(Unit *u) { +static int swap_add_extras(Swap *s) { int r; + + assert(s); + + if (UNIT(s)->fragment_path) + s->from_fragment = true; + + if (!s->what) { + if (s->parameters_fragment.what) + s->what = strdup(s->parameters_fragment.what); + else if (s->parameters_proc_swaps.what) + s->what = strdup(s->parameters_proc_swaps.what); + else { + r = unit_name_to_path(UNIT(s)->id, &s->what); + if (r < 0) + return r; + } + + if (!s->what) + return -ENOMEM; + } + + path_simplify(s->what, false); + + if (!UNIT(s)->description) { + r = unit_set_description(UNIT(s), s->what); + if (r < 0) + return r; + } + + r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT); + if (r < 0) + return r; + + r = swap_add_device_dependencies(s); + if (r < 0) + return r; + + r = swap_load_devnode(s); + if (r < 0) + return r; + + r = unit_patch_contexts(UNIT(s)); + if (r < 0) + return r; + + r = unit_add_exec_dependencies(UNIT(s), &s->exec_context); + if (r < 0) + return r; + + r = unit_set_default_slice(UNIT(s)); + if (r < 0) + return r; + + r = swap_add_default_dependencies(s); + if (r < 0) + return r; + + return 0; +} + +static int swap_load(Unit *u) { Swap *s = SWAP(u); + int r, q; assert(s); assert(u->load_state == UNIT_STUB); @@ -285,65 +347,18 @@ static int swap_load(Unit *u) { r = unit_load_fragment_and_dropin_optional(u); else r = unit_load_fragment_and_dropin(u); + + /* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is already + * active. */ + if (u->load_state == UNIT_LOADED || s->from_proc_swaps) + q = swap_add_extras(s); + else + q = 0; + if (r < 0) return r; - - if (u->load_state == UNIT_LOADED) { - - if (UNIT(s)->fragment_path) - s->from_fragment = true; - - if (!s->what) { - if (s->parameters_fragment.what) - s->what = strdup(s->parameters_fragment.what); - else if (s->parameters_proc_swaps.what) - s->what = strdup(s->parameters_proc_swaps.what); - else { - r = unit_name_to_path(u->id, &s->what); - if (r < 0) - return r; - } - - if (!s->what) - return -ENOMEM; - } - - path_simplify(s->what, false); - - if (!UNIT(s)->description) { - r = unit_set_description(u, s->what); - if (r < 0) - return r; - } - - r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT); - if (r < 0) - return r; - - r = swap_add_device_dependencies(s); - if (r < 0) - return r; - - r = swap_load_devnode(s); - if (r < 0) - return r; - - r = unit_patch_contexts(u); - if (r < 0) - return r; - - r = unit_add_exec_dependencies(u, &s->exec_context); - if (r < 0) - return r; - - r = unit_set_default_slice(u); - if (r < 0) - return r; - - r = swap_add_default_dependencies(s); - if (r < 0) - return r; - } + if (q < 0) + return q; return swap_verify(s); } @@ -370,7 +385,6 @@ static int swap_setup_unit( return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m"); u = manager_get_unit(m, e); - if (u && SWAP(u)->from_proc_swaps && !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) @@ -405,6 +419,13 @@ static int swap_setup_unit( } } + /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be + * loaded. After all we can load it now, from the data in /proc/swaps. */ + if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) { + u->load_state = UNIT_LOADED; + u->load_error = 0; + } + if (set_flags) { SWAP(u)->is_active = true; SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps; @@ -472,7 +493,7 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f swap_setup_unit(m, devlink, device, prio, set_flags); } - return r; + return 0; } static void swap_set_state(Swap *s, SwapState state) { @@ -813,6 +834,14 @@ fail: swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES); } +static void swap_cycle_clear(Swap *s) { + assert(s); + + s->result = SWAP_SUCCESS; + exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); + UNIT(s)->reset_accounting = true; +} + static int swap_start(Unit *u) { Swap *s = SWAP(u), *other; int r; @@ -852,11 +881,7 @@ static int swap_start(Unit *u) { if (r < 0) return r; - s->result = SWAP_SUCCESS; - exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); - - u->reset_accounting = true; - + swap_cycle_clear(s); swap_enter_activating(s); return 1; } @@ -1088,7 +1113,6 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd static int swap_load_proc_swaps(Manager *m, bool set_flags) { unsigned i; - int r = 0; assert(m); @@ -1120,12 +1144,10 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) { device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP); - k = swap_process_new(m, d, prio, set_flags); - if (k < 0) - r = k; + (void) swap_process_new(m, d, prio, set_flags); } - return r; + return 0; } static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { @@ -1156,13 +1178,13 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v Swap *swap = SWAP(u); if (!swap->is_active) { - /* This has just been deactivated */ swap_unset_proc_swaps(swap); switch (swap->state) { case SWAP_ACTIVE: + /* This has just been deactivated */ swap_enter_dead(swap, SWAP_SUCCESS); break; @@ -1183,7 +1205,8 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v case SWAP_DEAD: case SWAP_FAILED: - (void) unit_acquire_invocation_id(UNIT(swap)); + (void) unit_acquire_invocation_id(u); + swap_cycle_clear(swap); swap_enter_active(swap, SWAP_SUCCESS); break;