From: Lennart Poettering Date: Wed, 29 Mar 2023 20:10:01 +0000 (+0200) Subject: service: allow freeing the fdstore via cleaning X-Git-Tag: v254-rc1~736^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4fb8f1e88322b94b0fa051d3c6fd19cac0227aaa;p=thirdparty%2Fsystemd.git service: allow freeing the fdstore via cleaning Now that we have a potentially pinned fdstore let's add a concept for cleaning it explicitly on user requested. Let's expose this via "systemctl clean", i.e. the same way as user directories are cleaned. --- diff --git a/man/systemctl.xml b/man/systemctl.xml index 1a881d10495..705ed3e2386 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -538,12 +538,16 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err StateDirectory=, CacheDirectory=, LogsDirectory= and RuntimeDirectory=, see systemd.exec5 - for details. For timer units this may be used to clear out the persistent timestamp data if + for details. It may also be used to clear the file decriptor store as enabled via + FileDescriptorStoreMax=, see + systemd.service5 + for details. For timer units this may be used to clear out the persistent timestamp data if Persistent= is used and is selected, see systemd.timer5. This command only applies to units that use either of these settings. If is - not specified, both the cache and runtime data are removed (as these two types of data are - generally redundant and reproducible on the next invocation of the unit). + not specified, the cache and runtime data as well as the file descriptor store are removed (as + these three types of resources are generally redundant and reproducible on the next invocation of + the unit). Note that the specified units must be stopped to invoke this operation. @@ -2193,13 +2197,17 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err Select what type of per-unit resources to remove when the clean command is - invoked, see below. Takes one of configuration, state, - cache, logs, runtime to select the - type of resource. This option may be specified more than once, in which case all specified resource - types are removed. Also accepts the special value all as a shortcut for - specifying all five resource types. If this option is not specified defaults to the combination of - cache and runtime, i.e. the two kinds of resources that - are generally considered to be redundant and can be reconstructed on next invocation. + invoked, see above. Takes one of configuration, state, + cache, logs, runtime, + fdstore to select the type of resource. This option may be specified more than + once, in which case all specified resource types are removed. Also accepts the special value + all as a shortcut for specifying all six resource types. If this option is not + specified defaults to the combination of cache, runtime + and fdstore, i.e. the three kinds of resources that are generally considered + to be redundant and can be reconstructed on next invocation. Note that the explicit removal of the + fdstore resource type is only useful if the + FileDescriptorStorePreserve= option is enabled, since the file descriptor store + is otherwise cleaned automatically when the unit is stopped. diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 3f083a81745..c01f41cb449 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -90,6 +90,12 @@ static int property_get_can_clean( return r; } + if (FLAGS_SET(mask, EXEC_CLEAN_FDSTORE)) { + r = sd_bus_message_append(reply, "s", "fdstore"); + if (r < 0) + return r; + } + return sd_bus_message_close_container(reply); } @@ -696,6 +702,7 @@ int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error return r; for (;;) { + ExecCleanMask m; const char *i; r = sd_bus_message_read(message, "s", &i); @@ -704,17 +711,11 @@ int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error if (r == 0) break; - if (streq(i, "all")) - mask |= EXEC_CLEAN_ALL; - else { - ExecDirectoryType t; - - t = exec_resource_type_from_string(i); - if (t < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid resource type: %s", i); + m = exec_clean_mask_from_string(i); + if (m < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid resource type: %s", i); - mask |= 1U << t; - } + mask |= m; } r = sd_bus_message_exit_container(message); diff --git a/src/core/execute.c b/src/core/execute.c index 8b09794089a..879f1345b00 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -7582,6 +7582,23 @@ void exec_directory_sort(ExecDirectory *d) { } } +ExecCleanMask exec_clean_mask_from_string(const char *s) { + ExecDirectoryType t; + + assert(s); + + if (streq(s, "all")) + return EXEC_CLEAN_ALL; + if (streq(s, "fdstore")) + return EXEC_CLEAN_FDSTORE; + + t = exec_resource_type_from_string(s); + if (t < 0) + return (ExecCleanMask) t; + + return 1U << t; +} + DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_set_credential_hash_ops, char, string_hash_func, string_compare_func, ExecSetCredential, exec_set_credential_free); DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_load_credential_hash_ops, char, string_hash_func, string_compare_func, ExecLoadCredential, exec_load_credential_free); diff --git a/src/core/execute.h b/src/core/execute.h index 123fc1ec604..d2f55074058 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -161,8 +161,9 @@ typedef enum ExecCleanMask { EXEC_CLEAN_CACHE = 1U << EXEC_DIRECTORY_CACHE, EXEC_CLEAN_LOGS = 1U << EXEC_DIRECTORY_LOGS, EXEC_CLEAN_CONFIGURATION = 1U << EXEC_DIRECTORY_CONFIGURATION, + EXEC_CLEAN_FDSTORE = 1U << _EXEC_DIRECTORY_TYPE_MAX, EXEC_CLEAN_NONE = 0, - EXEC_CLEAN_ALL = (1U << _EXEC_DIRECTORY_TYPE_MAX) - 1, + EXEC_CLEAN_ALL = (1U << (_EXEC_DIRECTORY_TYPE_MAX+1)) - 1, _EXEC_CLEAN_MASK_INVALID = -EINVAL, } ExecCleanMask; @@ -520,6 +521,8 @@ void exec_directory_done(ExecDirectory *d); int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink); void exec_directory_sort(ExecDirectory *d); +ExecCleanMask exec_clean_mask_from_string(const char *s); + extern const struct hash_ops exec_set_credential_hash_ops; extern const struct hash_ops exec_load_credential_hash_ops; diff --git a/src/core/service.c b/src/core/service.c index 7130cbf4e66..dcd62fabdcd 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -4857,22 +4857,39 @@ static const char* service_status_text(Unit *u) { static int service_clean(Unit *u, ExecCleanMask mask) { _cleanup_strv_free_ char **l = NULL; + bool may_clean_fdstore = false; Service *s = SERVICE(u); int r; assert(s); assert(mask != 0); - if (s->state != SERVICE_DEAD) + if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_DEAD_RESOURCES_PINNED)) return -EBUSY; + /* Determine if there's anything we could potentially clean */ 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; + if (mask & EXEC_CLEAN_FDSTORE) + may_clean_fdstore = s->n_fd_store > 0 || s->n_fd_store_max > 0; + + if (strv_isempty(l) && !may_clean_fdstore) + return -EUNATCH; /* Nothing to potentially clean */ + + /* Let's clean the stuff we can clean quickly */ + if (may_clean_fdstore) + service_release_fd_store(s); + + /* If we are done, leave quickly */ + if (strv_isempty(l)) { + if (s->state == SERVICE_DEAD_RESOURCES_PINNED && !s->fd_store) + service_set_state(s, SERVICE_DEAD); + return 0; + } + /* We need to clean disk stuff. This is slow, hence do it out of process, and change state */ service_unwatch_control_pid(s); s->clean_result = SERVICE_SUCCESS; s->control_command = NULL; @@ -4899,10 +4916,21 @@ fail: static int service_can_clean(Unit *u, ExecCleanMask *ret) { Service *s = SERVICE(u); + ExecCleanMask mask = 0; + int r; assert(s); + assert(ret); + + r = exec_context_get_clean_mask(&s->exec_context, &mask); + if (r < 0) + return r; - return exec_context_get_clean_mask(&s->exec_context, ret); + if (s->n_fd_store_max > 0) + mask |= EXEC_CLEAN_FDSTORE; + + *ret = mask; + return 0; } static const char *service_finished_job(Unit *u, JobType t, JobResult result) { diff --git a/src/core/timer.c b/src/core/timer.c index 371e42e0aa0..419416b3255 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -884,6 +884,7 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) { Timer *t = TIMER(u); assert(t); + assert(ret); *ret = t->persistent ? EXEC_CLEAN_STATE : 0; return 0; diff --git a/src/systemctl/systemctl-clean-or-freeze.c b/src/systemctl/systemctl-clean-or-freeze.c index 5c15a9fba07..40d5f6d557a 100644 --- a/src/systemctl/systemctl-clean-or-freeze.c +++ b/src/systemctl/systemctl-clean-or-freeze.c @@ -21,7 +21,7 @@ int verb_clean_or_freeze(int argc, char *argv[], void *userdata) { polkit_agent_open_maybe(); if (!arg_clean_what) { - arg_clean_what = strv_new("cache", "runtime"); + arg_clean_what = strv_new("cache", "runtime", "fdstore"); if (!arg_clean_what) return log_oom(); } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index df4cf684355..21e09536a6b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -937,7 +937,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { "state\n" "cache\n" "logs\n" - "configuration"); + "configuration\n" + "fdstore"); return 0; }