From 810ef3180ead97e678cbf7b1107c6fdb424c95de Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 25 Aug 2019 17:57:08 +0900 Subject: [PATCH 1/5] core: introduce unit_fork_and_watch_rm_rf() --- src/core/service.c | 26 ++------------------------ src/core/unit.c | 34 ++++++++++++++++++++++++++++++++++ src/core/unit.h | 1 + 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/core/service.c b/src/core/service.c index 7e923c663d..0fffe11c49 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -30,7 +30,6 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" -#include "rm-rf.h" #include "serialize.h" #include "service.h" #include "signal-util.h" @@ -4252,7 +4251,6 @@ static int service_exit_status(Unit *u) { static int service_clean(Unit *u, ExecCleanMask mask) { _cleanup_strv_free_ char **l = NULL; Service *s = SERVICE(u); - pid_t pid; int r; assert(s); @@ -4277,36 +4275,16 @@ static int service_clean(Unit *u, ExecCleanMask mask) { if (r < 0) goto fail; - r = unit_fork_helper_process(UNIT(s), "(sd-rmrf)", &pid); + r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid); if (r < 0) goto fail; - if (r == 0) { - int ret = EXIT_SUCCESS; - char **i; - - STRV_FOREACH(i, l) { - r = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK); - if (r < 0) { - log_error_errno(r, "Failed to remove '%s': %m", *i); - ret = EXIT_FAILURE; - } - } - - _exit(ret); - } - - r = unit_watch_pid(u, pid, true); - if (r < 0) - goto fail; - - s->control_pid = pid; service_set_state(s, SERVICE_CLEANING); return 0; fail: - log_unit_warning_errno(UNIT(s), r, "Failed to initiate cleaning: %m"); + log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m"); s->clean_result = SERVICE_FAILURE_RESOURCES; s->timer_event_source = sd_event_source_unref(s->timer_event_source); return r; diff --git a/src/core/unit.c b/src/core/unit.c index 31ed473f91..5224015c70 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -38,6 +38,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "rm-rf.h" #include "serialize.h" #include "set.h" #include "signal-util.h" @@ -5303,6 +5304,39 @@ int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) { return 0; } +int unit_fork_and_watch_rm_rf(Unit *u, char **paths, pid_t *ret_pid) { + pid_t pid; + int r; + + assert(u); + assert(ret_pid); + + r = unit_fork_helper_process(u, "(sd-rmrf)", &pid); + if (r < 0) + return r; + if (r == 0) { + int ret = EXIT_SUCCESS; + char **i; + + STRV_FOREACH(i, paths) { + r = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK); + if (r < 0) { + log_error_errno(r, "Failed to remove '%s': %m", *i); + ret = EXIT_FAILURE; + } + } + + _exit(ret); + } + + r = unit_watch_pid(u, pid, true); + if (r < 0) + return r; + + *ret_pid = pid; + return 0; +} + static void unit_update_dependency_mask(Unit *u, UnitDependency d, Unit *other, UnitDependencyInfo di) { assert(u); assert(d >= 0); diff --git a/src/core/unit.h b/src/core/unit.h index 4732d72202..d5f4413cd8 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -824,6 +824,7 @@ bool unit_shall_confirm_spawn(Unit *u); int unit_set_exec_params(Unit *s, ExecParameters *p); int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret); +int unit_fork_and_watch_rm_rf(Unit *u, char **paths, pid_t *ret_pid); void unit_remove_dependencies(Unit *u, UnitDependencyMask mask); From c968d76a382f905b419cacd23a6b20aa31aca580 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 25 Aug 2019 18:20:56 +0900 Subject: [PATCH 2/5] core/socket: support "systemctl clean" for socket units --- src/basic/unit-def.c | 3 +- src/basic/unit-def.h | 1 + src/core/socket.c | 95 +++++++++++++++++++++++++++++++++++++++++--- src/core/socket.h | 1 + 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index cc7e953c10..e0928f9c02 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -204,7 +204,8 @@ static const char* const socket_state_table[_SOCKET_STATE_MAX] = { [SOCKET_STOP_POST] = "stop-post", [SOCKET_FINAL_SIGTERM] = "final-sigterm", [SOCKET_FINAL_SIGKILL] = "final-sigkill", - [SOCKET_FAILED] = "failed" + [SOCKET_FAILED] = "failed", + [SOCKET_CLEANING] = "cleaning", }; DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index c7b4235bea..9155c500a3 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -147,6 +147,7 @@ typedef enum SocketState { SOCKET_FINAL_SIGTERM, SOCKET_FINAL_SIGKILL, SOCKET_FAILED, + SOCKET_CLEANING, _SOCKET_STATE_MAX, _SOCKET_STATE_INVALID = -1 } SocketState; diff --git a/src/core/socket.c b/src/core/socket.c index 46fe405a17..e6ba60ffa6 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -67,7 +67,8 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_STOP_POST] = UNIT_DEACTIVATING, [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING, [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING, - [SOCKET_FAILED] = UNIT_FAILED + [SOCKET_FAILED] = UNIT_FAILED, + [SOCKET_CLEANING] = UNIT_MAINTENANCE, }; static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); @@ -624,6 +625,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sSocket State: %s\n" "%sResult: %s\n" + "%sClean Result: %s\n" "%sBindIPv6Only: %s\n" "%sBacklog: %u\n" "%sSocketMode: %04o\n" @@ -642,6 +644,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sSELinuxContextFromNet: %s\n", prefix, socket_state_to_string(s->state), prefix, socket_result_to_string(s->result), + prefix, socket_result_to_string(s->clean_result), prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), prefix, s->backlog, prefix, s->socket_mode, @@ -1802,7 +1805,8 @@ static void socket_set_state(Socket *s, SocketState state) { SOCKET_STOP_PRE_SIGKILL, SOCKET_STOP_POST, SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL)) { + SOCKET_FINAL_SIGKILL, + SOCKET_CLEANING)) { s->timer_event_source = sd_event_source_unref(s->timer_event_source); socket_unwatch_control_pid(s); @@ -1820,7 +1824,8 @@ static void socket_set_state(Socket *s, SocketState state) { SOCKET_RUNNING, SOCKET_STOP_PRE, SOCKET_STOP_PRE_SIGTERM, - SOCKET_STOP_PRE_SIGKILL)) + SOCKET_STOP_PRE_SIGKILL, + SOCKET_CLEANING)) socket_close_fds(s); if (state != old_state) @@ -1850,7 +1855,8 @@ static int socket_coldplug(Unit *u) { SOCKET_STOP_PRE_SIGKILL, SOCKET_STOP_POST, SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL)) { + SOCKET_FINAL_SIGKILL, + SOCKET_CLEANING)) { r = unit_watch_pid(UNIT(s), s->control_pid, false); if (r < 0) @@ -1891,7 +1897,7 @@ static int socket_coldplug(Unit *u) { return r; } - if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED)) { + if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED, SOCKET_CLEANING)) { (void) unit_setup_dynamic_creds(u); (void) unit_setup_exec_runtime(u); } @@ -2455,7 +2461,8 @@ static int socket_start(Unit *u) { SOCKET_STOP_PRE_SIGTERM, SOCKET_STOP_POST, SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL)) + SOCKET_FINAL_SIGKILL, + SOCKET_CLEANING)) return -EAGAIN; /* Already on it! */ @@ -2530,6 +2537,12 @@ static int socket_stop(Unit *u) { return -EAGAIN; } + /* If we are currently cleaning, then abort it, brutally. */ + if (s->state == SOCKET_CLEANING) { + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_SUCCESS); + return 0; + } + assert(IN_SET(s->state, SOCKET_LISTENING, SOCKET_RUNNING)); socket_enter_stop_pre(s, SOCKET_SUCCESS); @@ -3073,6 +3086,14 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { socket_enter_dead(s, f); break; + case SOCKET_CLEANING: + + if (s->clean_result == SOCKET_SUCCESS) + s->clean_result = f; + + socket_enter_dead(s, SOCKET_SUCCESS); + break; + default: assert_not_reached("Uh, control process died at wrong time."); } @@ -3141,6 +3162,15 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT); break; + case SOCKET_CLEANING: + log_unit_warning(UNIT(s), "Cleaning timed out. killing."); + + if (s->clean_result == SOCKET_SUCCESS) + s->clean_result = SOCKET_FAILURE_TIMEOUT; + + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, 0); + break; + default: assert_not_reached("Timeout at wrong time."); } @@ -3197,6 +3227,7 @@ static void socket_reset_failed(Unit *u) { socket_set_state(s, SOCKET_DEAD); s->result = SOCKET_SUCCESS; + s->clean_result = SOCKET_SUCCESS; } void socket_connection_unref(Socket *s) { @@ -3291,6 +3322,56 @@ static int socket_control_pid(Unit *u) { return s->control_pid; } +static int socket_clean(Unit *u, ExecCleanMask mask) { + _cleanup_strv_free_ char **l = NULL; + Socket *s = SOCKET(u); + int r; + + assert(s); + assert(mask != 0); + + if (s->state != SOCKET_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; + + socket_unwatch_control_pid(s); + s->clean_result = SOCKET_SUCCESS; + s->control_command = NULL; + s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; + + r = socket_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; + + socket_set_state(s, SOCKET_CLEANING); + + return 0; + +fail: + log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m"); + s->clean_result = SOCKET_FAILURE_RESOURCES; + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return r; +} + +static int socket_can_clean(Unit *u, ExecCleanMask *ret) { + Socket *s = SOCKET(u); + + assert(s); + + return exec_context_get_clean_mask(&s->exec_context, ret); +} + static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { [SOCKET_EXEC_START_PRE] = "ExecStartPre", [SOCKET_EXEC_START_CHOWN] = "ExecStartChown", @@ -3343,6 +3424,8 @@ const UnitVTable socket_vtable = { .stop = socket_stop, .kill = socket_kill, + .clean = socket_clean, + .can_clean = socket_can_clean, .get_timeout = socket_get_timeout, diff --git a/src/core/socket.h b/src/core/socket.h index c4e25db1fc..9e0be15ba8 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -103,6 +103,7 @@ struct Socket { mode_t socket_mode; SocketResult result; + SocketResult clean_result; char **symlinks; From 17e9d53d87245bff7191d6962fdc9eca42195ed2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 25 Aug 2019 22:08:47 +0900 Subject: [PATCH 3/5] core/mount: support "systemctl clean" for mount units --- src/basic/unit-def.c | 3 +- src/basic/unit-def.h | 1 + src/core/mount.c | 85 ++++++++++++++++++++++++++++++++++++++++++-- src/core/mount.h | 1 + 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index e0928f9c02..b0b2d917fa 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -136,7 +136,8 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = { [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", - [MOUNT_FAILED] = "failed" + [MOUNT_FAILED] = "failed", + [MOUNT_CLEANING] = "cleaning", }; DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index 9155c500a3..4ddaf34b5f 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -79,6 +79,7 @@ typedef enum MountState { MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILED, + MOUNT_CLEANING, _MOUNT_STATE_MAX, _MOUNT_STATE_INVALID = -1 } MountState; diff --git a/src/core/mount.c b/src/core/mount.c index 4f37d3e9a9..74da0f031b 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -45,7 +45,8 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING, [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING, [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING, - [MOUNT_FAILED] = UNIT_FAILED + [MOUNT_FAILED] = UNIT_FAILED, + [MOUNT_CLEANING] = UNIT_MAINTENANCE, }; static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); @@ -61,7 +62,8 @@ static bool MOUNT_STATE_WITH_PROCESS(MountState state) { MOUNT_REMOUNTING_SIGKILL, MOUNT_UNMOUNTING, MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL); + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_CLEANING); } static bool mount_is_network(const MountParameters *p) { @@ -731,6 +733,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sMount State: %s\n" "%sResult: %s\n" + "%sClean Result: %s\n" "%sWhere: %s\n" "%sWhat: %s\n" "%sFile System Type: %s\n" @@ -745,6 +748,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { "%sTimeoutSec: %s\n", prefix, mount_state_to_string(m->state), prefix, mount_result_to_string(m->result), + prefix, mount_result_to_string(m->clean_result), prefix, m->where, prefix, p ? strna(p->what) : "n/a", prefix, p ? strna(p->fstype) : "n/a", @@ -1090,7 +1094,8 @@ static int mount_start(Unit *u) { if (IN_SET(m->state, MOUNT_UNMOUNTING, MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL)) + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_CLEANING)) return -EAGAIN; /* Already on it! */ @@ -1149,6 +1154,11 @@ static int mount_stop(Unit *u) { mount_enter_unmounting(m); return 1; + case MOUNT_CLEANING: + /* If we are currently cleaning, then abort it, brutally. */ + mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS); + return 0; + default: assert_not_reached("Unexpected state."); } @@ -1382,6 +1392,13 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { mount_enter_dead_or_mounted(m, f); break; + case MOUNT_CLEANING: + if (m->clean_result == MOUNT_SUCCESS) + m->clean_result = f; + + mount_enter_dead(m, MOUNT_SUCCESS); + break; + default: assert_not_reached("Uh, control process died at wrong time."); } @@ -1449,6 +1466,15 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT); break; + case MOUNT_CLEANING: + log_unit_warning(UNIT(m), "Cleaning timed out. killing."); + + if (m->clean_result == MOUNT_SUCCESS) + m->clean_result = MOUNT_FAILURE_TIMEOUT; + + mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, 0); + break; + default: assert_not_reached("Timeout at wrong time."); } @@ -1923,6 +1949,7 @@ static void mount_reset_failed(Unit *u) { m->result = MOUNT_SUCCESS; m->reload_result = MOUNT_SUCCESS; + m->clean_result = MOUNT_SUCCESS; } static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { @@ -1941,6 +1968,56 @@ static int mount_control_pid(Unit *u) { return m->control_pid; } +static int mount_clean(Unit *u, ExecCleanMask mask) { + _cleanup_strv_free_ char **l = NULL; + Mount *m = MOUNT(u); + int r; + + assert(m); + assert(mask != 0); + + if (m->state != MOUNT_DEAD) + return -EBUSY; + + r = exec_context_get_clean_directories(&m->exec_context, u->manager->prefix, mask, &l); + if (r < 0) + return r; + + if (strv_isempty(l)) + return -EUNATCH; + + mount_unwatch_control_pid(m); + m->clean_result = MOUNT_SUCCESS; + m->control_command = NULL; + m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + + r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->exec_context.timeout_clean_usec)); + if (r < 0) + goto fail; + + r = unit_fork_and_watch_rm_rf(u, l, &m->control_pid); + if (r < 0) + goto fail; + + mount_set_state(m, MOUNT_CLEANING); + + return 0; + +fail: + log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m"); + m->clean_result = MOUNT_FAILURE_RESOURCES; + m->timer_event_source = sd_event_source_unref(m->timer_event_source); + return r; +} + +static int mount_can_clean(Unit *u, ExecCleanMask *ret) { + Mount *m = MOUNT(u); + + assert(m); + + return exec_context_get_clean_mask(&m->exec_context, ret); +} + static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", @@ -1989,6 +2066,8 @@ const UnitVTable mount_vtable = { .reload = mount_reload, .kill = mount_kill, + .clean = mount_clean, + .can_clean = mount_can_clean, .serialize = mount_serialize, .deserialize_item = mount_deserialize_item, diff --git a/src/core/mount.h b/src/core/mount.h index 2e59f1fe04..07fa05f3ca 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -61,6 +61,7 @@ struct Mount { MountResult result; MountResult reload_result; + MountResult clean_result; mode_t directory_mode; From a8b689b7d01a9b7c7a66a29b0ea79d883b38a279 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 25 Aug 2019 22:26:33 +0900 Subject: [PATCH 4/5] core/swap: support "systemctl clean" for swap units --- src/basic/unit-def.c | 3 +- src/basic/unit-def.h | 1 + src/core/swap.c | 86 ++++++++++++++++++++++++++++++++++++++++++-- src/core/swap.h | 1 + 4 files changed, 87 insertions(+), 4 deletions(-) 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; From a3f8e4d94ab388bb04e7b8ec65690d584b9e72fb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 31 Aug 2019 09:30:12 +0200 Subject: [PATCH 5/5] test: add more tests for "systemctl clean" --- test/TEST-33-CLEAN-UNIT/testsuite.sh | 145 +++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/test/TEST-33-CLEAN-UNIT/testsuite.sh b/test/TEST-33-CLEAN-UNIT/testsuite.sh index 26754f01ba..0272a2305b 100755 --- a/test/TEST-33-CLEAN-UNIT/testsuite.sh +++ b/test/TEST-33-CLEAN-UNIT/testsuite.sh @@ -169,6 +169,151 @@ systemctl clean testservice --what=all ! test -L /var/cache/testservice ! test -L /var/log/testservice +cat > /etc/systemd/system/tmp-hoge.mount < /etc/systemd/system/testservice.socket < /testok exit 0