diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index b0b2d917fa..dba218b388 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -219,7 +219,8 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = { [SWAP_DEACTIVATING] = "deactivating", [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", - [SWAP_FAILED] = "failed" + [SWAP_FAILED] = "failed", + [SWAP_CLEANING] = "cleaning", }; DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index 4ddaf34b5f..5979819dc0 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -162,6 +162,7 @@ typedef enum SwapState { SWAP_DEACTIVATING_SIGTERM, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILED, + SWAP_CLEANING, _SWAP_STATE_MAX, _SWAP_STATE_INVALID = -1 } SwapState; diff --git a/src/core/swap.c b/src/core/swap.c index 74381c0c95..0719d3efcc 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -38,7 +38,8 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { [SWAP_DEACTIVATING] = UNIT_DEACTIVATING, [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING, [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING, - [SWAP_FAILED] = UNIT_FAILED + [SWAP_FAILED] = UNIT_FAILED, + [SWAP_CLEANING] = UNIT_MAINTENANCE, }; static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); @@ -51,7 +52,8 @@ static bool SWAP_STATE_WITH_PROCESS(SwapState state) { SWAP_ACTIVATING_DONE, SWAP_DEACTIVATING, SWAP_DEACTIVATING_SIGTERM, - SWAP_DEACTIVATING_SIGKILL); + SWAP_DEACTIVATING_SIGKILL, + SWAP_CLEANING); } static void swap_unset_proc_swaps(Swap *s) { @@ -587,11 +589,13 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sSwap State: %s\n" "%sResult: %s\n" + "%sClean Result: %s\n" "%sWhat: %s\n" "%sFrom /proc/swaps: %s\n" "%sFrom fragment: %s\n", prefix, swap_state_to_string(s->state), prefix, swap_result_to_string(s->result), + prefix, swap_result_to_string(s->clean_result), prefix, s->what, prefix, yes_no(s->from_proc_swaps), prefix, yes_no(s->from_fragment)); @@ -852,7 +856,8 @@ static int swap_start(Unit *u) { if (IN_SET(s->state, SWAP_DEACTIVATING, SWAP_DEACTIVATING_SIGTERM, - SWAP_DEACTIVATING_SIGKILL)) + SWAP_DEACTIVATING_SIGKILL, + SWAP_CLEANING)) return -EAGAIN; /* Already on it! */ @@ -912,6 +917,12 @@ static int swap_stop(Unit *u) { swap_enter_deactivating(s); return 1; + case SWAP_CLEANING: + /* If we are currently cleaning, then abort it, brutally. */ + swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS); + return 0; + + default: assert_not_reached("Unexpected state."); } @@ -1067,6 +1078,13 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { swap_enter_dead_or_active(s, f); break; + case SWAP_CLEANING: + if (s->clean_result == SWAP_SUCCESS) + s->clean_result = f; + + swap_enter_dead(s, SWAP_SUCCESS); + break; + default: assert_not_reached("Uh, control process died at wrong time."); } @@ -1109,6 +1127,15 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT); break; + case SWAP_CLEANING: + log_unit_warning(UNIT(s), "Cleaning timed out. killing."); + + if (s->clean_result == SWAP_SUCCESS) + s->clean_result = SWAP_FAILURE_TIMEOUT; + + swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, 0); + break; + default: assert_not_reached("Timeout at wrong time."); } @@ -1428,6 +1455,7 @@ static void swap_reset_failed(Unit *u) { swap_set_state(s, SWAP_DEAD); s->result = SWAP_SUCCESS; + s->clean_result = SWAP_SUCCESS; } static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { @@ -1475,6 +1503,56 @@ static int swap_control_pid(Unit *u) { return s->control_pid; } +static int swap_clean(Unit *u, ExecCleanMask mask) { + _cleanup_strv_free_ char **l = NULL; + Swap *s = SWAP(u); + int r; + + assert(s); + assert(mask != 0); + + if (s->state != SWAP_DEAD) + return -EBUSY; + + r = exec_context_get_clean_directories(&s->exec_context, u->manager->prefix, mask, &l); + if (r < 0) + return r; + + if (strv_isempty(l)) + return -EUNATCH; + + swap_unwatch_control_pid(s); + s->clean_result = SWAP_SUCCESS; + s->control_command = NULL; + s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; + + r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->exec_context.timeout_clean_usec)); + if (r < 0) + goto fail; + + r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid); + if (r < 0) + goto fail; + + swap_set_state(s, SWAP_CLEANING); + + return 0; + +fail: + log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m"); + s->clean_result = SWAP_FAILURE_RESOURCES; + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return r; +} + +static int swap_can_clean(Unit *u, ExecCleanMask *ret) { + Swap *s = SWAP(u); + + assert(s); + + return exec_context_get_clean_mask(&s->exec_context, ret); +} + static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", @@ -1520,6 +1598,8 @@ const UnitVTable swap_vtable = { .stop = swap_stop, .kill = swap_kill, + .clean = swap_clean, + .can_clean = swap_can_clean, .get_timeout = swap_get_timeout, diff --git a/src/core/swap.h b/src/core/swap.h index 1a4b60b957..389faf584d 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -57,6 +57,7 @@ struct Swap { bool just_activated:1; SwapResult result; + SwapResult clean_result; usec_t timeout_usec;