diff options
Diffstat (limited to 'src/core/swap.c')
-rw-r--r-- | src/core/swap.c | 237 |
1 files changed, 135 insertions, 102 deletions
diff --git a/src/core/swap.c b/src/core/swap.c index 193c8c3767..b592abb9fb 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,22 +18,30 @@ ***/ #include <errno.h> -#include <unistd.h> #include <sys/epoll.h> #include <sys/stat.h> -#include <libudev.h> +#include <unistd.h> -#include "unit.h" -#include "swap.h" -#include "unit-name.h" +#include "libudev.h" + +#include "alloc-util.h" #include "dbus-swap.h" -#include "special.h" +#include "escape.h" #include "exit-status.h" +#include "fd-util.h" +#include "formats-util.h" +#include "fstab-util.h" +#include "parse-util.h" #include "path-util.h" -#include "virt.h" +#include "process-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "swap.h" #include "udev-util.h" -#include "fstab-util.h" -#include "formats-util.h" +#include "unit-name.h" +#include "unit.h" +#include "virt.h" static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { [SWAP_DEAD] = UNIT_INACTIVE, @@ -59,8 +65,7 @@ static void swap_unset_proc_swaps(Swap *s) { if (!s->from_proc_swaps) return; - free(s->parameters_proc_swaps.what); - s->parameters_proc_swaps.what = NULL; + s->parameters_proc_swaps.what = mfree(s->parameters_proc_swaps.what); s->from_proc_swaps = false; } @@ -87,8 +92,7 @@ static int swap_set_devnode(Swap *s, const char *devnode) { else hashmap_remove(swaps, s->devnode); - free(s->devnode); - s->devnode = NULL; + s->devnode = mfree(s->devnode); } if (devnode) { @@ -141,47 +145,42 @@ static void swap_done(Unit *u) { swap_unset_proc_swaps(s); swap_set_devnode(s, NULL); - free(s->what); - s->what = NULL; - - free(s->parameters_fragment.what); - s->parameters_fragment.what = NULL; - - free(s->parameters_fragment.options); - s->parameters_fragment.options = NULL; + s->what = mfree(s->what); + s->parameters_fragment.what = mfree(s->parameters_fragment.what); + s->parameters_fragment.options = mfree(s->parameters_fragment.options); s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); s->control_command = NULL; + dynamic_creds_unref(&s->dynamic_creds); + swap_unwatch_control_pid(s); s->timer_event_source = sd_event_source_unref(s->timer_event_source); } -static int swap_arm_timer(Swap *s) { +static int swap_arm_timer(Swap *s, usec_t usec) { int r; assert(s); - if (s->timeout_usec <= 0) { - s->timer_event_source = sd_event_source_unref(s->timer_event_source); - return 0; - } - if (s->timer_event_source) { - r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + r = sd_event_source_set_time(s->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(s)->manager->event, &s->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + s->timeout_usec, 0, + usec, 0, swap_dispatch_timer, s); if (r < 0) return r; @@ -201,7 +200,7 @@ static int swap_add_device_links(Swap *s) { return 0; if (is_device_path(s->what)) - return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM); + return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO); else /* File based swap devices need to be ordered after * systemd-remount-fs.service, since they might need a @@ -210,14 +209,25 @@ static int swap_add_device_links(Swap *s) { } static int swap_add_default_dependencies(Swap *s) { + int r; + assert(s); - if (UNIT(s)->manager->running_as != MANAGER_SYSTEM) + if (!UNIT(s)->default_dependencies) return 0; - if (detect_container(NULL) > 0) + if (!MANAGER_IS_SYSTEM(UNIT(s)->manager)) return 0; + if (detect_container() > 0) + return 0; + + /* swap units generated for the swap dev links are missing the + * ordering dep against the swap target. */ + r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true); + if (r < 0) + return r; + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); } @@ -326,15 +336,13 @@ static int swap_load(Unit *u) { if (r < 0) return r; - r = unit_add_default_slice(u, &s->cgroup_context); + r = unit_set_default_slice(u); if (r < 0) return r; - if (UNIT(s)->default_dependencies) { - r = swap_add_default_dependencies(s); - if (r < 0) - return r; - } + r = swap_add_default_dependencies(s); + if (r < 0) + return r; } return swap_verify(s); @@ -527,26 +535,29 @@ static int swap_coldplug(Unit *u) { if (new_state == s->state) return 0; - if (new_state == SWAP_ACTIVATING || - new_state == SWAP_ACTIVATING_SIGTERM || - new_state == SWAP_ACTIVATING_SIGKILL || - new_state == SWAP_ACTIVATING_DONE || - new_state == SWAP_DEACTIVATING || - new_state == SWAP_DEACTIVATING_SIGTERM || - new_state == SWAP_DEACTIVATING_SIGKILL) { - - if (s->control_pid <= 0) - return -EBADMSG; + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(new_state, + SWAP_ACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_ACTIVATING_DONE, + SWAP_DEACTIVATING, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL)) { r = unit_watch_pid(UNIT(s), s->control_pid); if (r < 0) return r; - r = swap_arm_timer(s); + r = swap_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec)); if (r < 0) return r; } + if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED)) + (void) unit_setup_dynamic_creds(u); + swap_set_state(s, new_state); return 0; } @@ -600,10 +611,10 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { pid_t pid; int r; ExecParameters exec_params = { - .apply_permissions = true, - .apply_chroot = true, - .apply_tty_stdin = true, - .bus_endpoint_fd = -1, + .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN, + .stdin_fd = -1, + .stdout_fd = -1, + .stderr_fd = -1, }; assert(s); @@ -620,12 +631,16 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { if (r < 0) goto fail; - r = swap_arm_timer(s); + r = unit_setup_dynamic_creds(UNIT(s)); + if (r < 0) + return r; + + r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; exec_params.environment = UNIT(s)->manager->environment; - exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; + exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0; exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; exec_params.cgroup_path = UNIT(s)->cgroup_path; exec_params.cgroup_delegate = s->cgroup_context.delegate; @@ -636,6 +651,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { &s->exec_context, &exec_params, s->exec_runtime, + &s->dynamic_creds, &pid); if (r < 0) goto fail; @@ -657,21 +673,25 @@ fail: static void swap_enter_dead(Swap *s, SwapResult f) { assert(s); - if (f != SWAP_SUCCESS) + if (s->result == SWAP_SUCCESS) s->result = f; + swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD); + exec_runtime_destroy(s->exec_runtime); s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager)); - swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD); + unit_unref_uid_gid(UNIT(s), true); + + dynamic_creds_destroy(&s->dynamic_creds); } static void swap_enter_active(Swap *s, SwapResult f) { assert(s); - if (f != SWAP_SUCCESS) + if (s->result == SWAP_SUCCESS) s->result = f; swap_set_state(s, SWAP_ACTIVE); @@ -682,7 +702,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { assert(s); - if (f != SWAP_SUCCESS) + if (s->result == SWAP_SUCCESS) s->result = f; r = unit_kill_context( @@ -697,7 +717,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { goto fail; if (r > 0) { - r = swap_arm_timer(s); + r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; @@ -806,6 +826,7 @@ fail: static int swap_start(Unit *u) { Swap *s = SWAP(u), *other; + int r; assert(s); @@ -824,7 +845,7 @@ static int swap_start(Unit *u) { assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED); - if (detect_container(NULL) > 0) + if (detect_container() > 0) return -EPERM; /* If there's a job for another swap unit for the same node @@ -834,6 +855,16 @@ static int swap_start(Unit *u) { if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING) return -EAGAIN; + r = unit_start_limit_test(u); + if (r < 0) { + swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT); + return r; + } + + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + s->result = SWAP_SUCCESS; s->reset_cpu_usage = true; @@ -857,7 +888,7 @@ static int swap_stop(Unit *u) { s->state == SWAP_ACTIVATING_DONE || s->state == SWAP_ACTIVE); - if (detect_container(NULL) > 0) + if (detect_container() > 0) return -EPERM; swap_enter_deactivating(s); @@ -961,7 +992,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_pid = 0; - if (is_clean_exit(code, status, NULL)) + if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL)) f = SWAP_SUCCESS; else if (code == CLD_EXITED) f = SWAP_FAILURE_EXIT_CODE; @@ -972,7 +1003,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { else assert_not_reached("Unknown code"); - if (f != SWAP_SUCCESS) + if (s->result == SWAP_SUCCESS) s->result = f; if (s->control_command) { @@ -1162,6 +1193,7 @@ 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)); swap_enter_active(swap, SWAP_SUCCESS); break; @@ -1202,7 +1234,7 @@ static Unit *swap_following(Unit *u) { if (other->from_fragment) return UNIT(other); - /* Otherwise make everybody follow the unit that's named after + /* Otherwise, make everybody follow the unit that's named after * the swap device in the kernel */ if (streq_ptr(s->what, s->devnode)) @@ -1259,35 +1291,41 @@ static void swap_shutdown(Manager *m) { m->swap_event_source = sd_event_source_unref(m->swap_event_source); - if (m->proc_swaps) { - fclose(m->proc_swaps); - m->proc_swaps = NULL; - } + m->proc_swaps = safe_fclose(m->proc_swaps); - hashmap_free(m->swaps_by_devnode); - m->swaps_by_devnode = NULL; + m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode); } -static int swap_enumerate(Manager *m) { +static void swap_enumerate(Manager *m) { int r; assert(m); if (!m->proc_swaps) { m->proc_swaps = fopen("/proc/swaps", "re"); - if (!m->proc_swaps) - return errno == ENOENT ? 0 : -errno; + if (!m->proc_swaps) { + if (errno == ENOENT) + log_debug("Not swap enabled, skipping enumeration"); + else + log_error_errno(errno, "Failed to open /proc/swaps: %m"); + + return; + } r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to watch /proc/swaps: %m"); goto fail; + } /* Dispatch this before we dispatch SIGCHLD, so that * we always get the events from /proc/swaps before * the SIGCHLD of /sbin/swapon. */ r = sd_event_source_set_priority(m->swap_event_source, -10); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to change /proc/swaps priority: %m"); goto fail; + } (void) sd_event_source_set_description(m->swap_event_source, "swap-proc"); } @@ -1296,11 +1334,10 @@ static int swap_enumerate(Manager *m) { if (r < 0) goto fail; - return 0; + return; fail: swap_shutdown(m); - return r; } int swap_process_device_new(Manager *m, struct udev_device *dev) { @@ -1380,17 +1417,21 @@ static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error); } -static int swap_get_timeout(Unit *u, uint64_t *timeout) { +static int swap_get_timeout(Unit *u, usec_t *timeout) { Swap *s = SWAP(u); + usec_t t; int r; if (!s->timer_event_source) return 0; - r = sd_event_source_get_time(s->timer_event_source, timeout); + r = sd_event_source_get_time(s->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } @@ -1404,25 +1445,18 @@ static bool swap_supported(void) { if (supported < 0) supported = access("/proc/swaps", F_OK) >= 0 && - detect_container(NULL) <= 0; + detect_container() <= 0; return supported; } -static const char* const swap_state_table[_SWAP_STATE_MAX] = { - [SWAP_DEAD] = "dead", - [SWAP_ACTIVATING] = "activating", - [SWAP_ACTIVATING_DONE] = "activating-done", - [SWAP_ACTIVE] = "active", - [SWAP_DEACTIVATING] = "deactivating", - [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", - [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", - [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", - [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", - [SWAP_FAILED] = "failed" -}; +static int swap_control_pid(Unit *u) { + Swap *s = SWAP(u); -DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + assert(s); + + return s->control_pid; +} static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", @@ -1437,7 +1471,8 @@ static const char* const swap_result_table[_SWAP_RESULT_MAX] = { [SWAP_FAILURE_TIMEOUT] = "timeout", [SWAP_FAILURE_EXIT_CODE] = "exit-code", [SWAP_FAILURE_SIGNAL] = "signal", - [SWAP_FAILURE_CORE_DUMP] = "core-dump" + [SWAP_FAILURE_CORE_DUMP] = "core-dump", + [SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult); @@ -1448,6 +1483,7 @@ const UnitVTable swap_vtable = { .cgroup_context_offset = offsetof(Swap, cgroup_context), .kill_context_offset = offsetof(Swap, kill_context), .exec_runtime_offset = offsetof(Swap, exec_runtime), + .dynamic_creds_offset = offsetof(Swap, dynamic_creds), .sections = "Unit\0" @@ -1455,9 +1491,6 @@ const UnitVTable swap_vtable = { "Install\0", .private_section = "Swap", - .no_alias = true, - .no_instances = true, - .init = swap_init, .load = swap_load, .done = swap_done, @@ -1485,7 +1518,8 @@ const UnitVTable swap_vtable = { .reset_failed = swap_reset_failed, - .bus_interface = "org.freedesktop.systemd1.Swap", + .control_pid = swap_control_pid, + .bus_vtable = bus_swap_vtable, .bus_set_property = bus_swap_set_property, .bus_commit_properties = bus_swap_commit_properties, @@ -1505,7 +1539,6 @@ const UnitVTable swap_vtable = { .finished_start_job = { [JOB_DONE] = "Activated swap %s.", [JOB_FAILED] = "Failed to activate swap %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", [JOB_TIMEOUT] = "Timed out activating swap %s.", }, .finished_stop_job = { |