core/swap: support "systemctl clean" for swap units
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 25 Aug 2019 13:26:33 +0000 (22:26 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 28 Aug 2019 14:09:54 +0000 (23:09 +0900)
src/basic/unit-def.c
src/basic/unit-def.h
src/core/swap.c
src/core/swap.h

index b0b2d91..dba218b 100644 (file)
@@ -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);
index 4ddaf34..5979819 100644 (file)
@@ -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;
index 74381c0..0719d3e 100644 (file)
@@ -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,
 
index 1a4b60b..389faf5 100644 (file)
@@ -57,6 +57,7 @@ struct Swap {
         bool just_activated:1;
 
         SwapResult result;
+        SwapResult clean_result;
 
         usec_t timeout_usec;