diff options
-rw-r--r-- | man/org.freedesktop.systemd1.xml | 6 | ||||
-rw-r--r-- | man/systemd.service.xml | 21 | ||||
-rw-r--r-- | src/basic/unit-def.c | 1 | ||||
-rw-r--r-- | src/basic/unit-def.h | 1 | ||||
-rw-r--r-- | src/core/dbus-execute.c | 8 | ||||
-rw-r--r-- | src/core/dbus-execute.h | 2 | ||||
-rw-r--r-- | src/core/dbus-service.c | 4 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.in | 3 | ||||
-rw-r--r-- | src/core/load-fragment.c | 2 | ||||
-rw-r--r-- | src/core/load-fragment.h | 2 | ||||
-rw-r--r-- | src/core/service.c | 47 | ||||
-rw-r--r-- | src/core/service.h | 1 | ||||
-rw-r--r-- | src/shared/bus-unit-util.c | 3 |
13 files changed, 80 insertions, 21 deletions
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index f39893f647..e462c60636 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -2619,6 +2619,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { readonly u FileDescriptorStoreMax = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly u NFileDescriptorStore = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s FileDescriptorStorePreserve = '...'; readonly s StatusText = '...'; readonly i StatusErrno = ...; readonly s Result = '...'; @@ -3244,6 +3246,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { <!--property NFileDescriptorStore is not documented!--> + <!--property FileDescriptorStorePreserve is not documented!--> + <!--property StatusErrno is not documented!--> <!--property ReloadResult is not documented!--> @@ -3830,6 +3834,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { <variablelist class="dbus-property" generated="True" extra-ref="NFileDescriptorStore"/> + <variablelist class="dbus-property" generated="True" extra-ref="FileDescriptorStorePreserve"/> + <variablelist class="dbus-property" generated="True" extra-ref="StatusText"/> <variablelist class="dbus-property" generated="True" extra-ref="StatusErrno"/> diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 1b116b8372..7de1350a59 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -1066,7 +1066,7 @@ <literal>FDSTORE=1</literal> messages. This is useful for implementing services that can restart after an explicit request or a crash without losing state. Any open sockets and other file descriptors which should not be closed during the restart may be stored this way. Application state - can either be serialized to a file in <filename>/run/</filename>, or better, stored in a + can either be serialized to a file in <varname>RuntimeDirectory=</varname>, or stored in a <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory file descriptor. Defaults to 0, i.e. no file descriptors may be stored in the service manager. All file descriptors passed to the service manager from a specific service are passed back @@ -1075,7 +1075,8 @@ details about the precise protocol used and the order in which the file descriptors are passed). Any file descriptors passed to the service manager are automatically closed when <constant>POLLHUP</constant> or <constant>POLLERR</constant> is seen on them, or when the service is - fully stopped and no job is queued or being executed for it. If this option is used, + fully stopped and no job is queued or being executed for it (the latter can be tweaked with + <varname>FileDescriptorStorePreserve=</varname>, see below). If this option is used, <varname>NotifyAccess=</varname> (see above) should be set to open access to the notification socket provided by systemd. If <varname>NotifyAccess=</varname> is not set, it will be implicitly set to <option>main</option>.</para> @@ -1098,6 +1099,22 @@ </varlistentry> <varlistentry> + <term><varname>FileDescriptorStorePreserve=</varname></term> + <listitem><para>Takes one of <constant>no</constant>, <constant>yes</constant>, + <constant>restart</constant> and controls when to release the service's file descriptor store + (i.e. when to close the contained file descriptors, if any). If set to <constant>no</constant> the + file descriptor store is automatically released when the service is stopped; if + <constant>restart</constant> (the default) it is kept around as long as the unit is neither inactive + nor failed, or a job is queued for the service, or the service is expected to be restarted. If + <constant>yes</constant> the file descriptor store is kept around until the unit is removed from + memory (i.e. is not referenced anymore and inactive). The latter is useful to keep entries in the + file descriptor store pinned until the service manage exits.</para> + + <para>Use <command>systemctl clean --what=fdstore …</command> to release the file descriptor store + explicitly.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>USBFunctionDescriptors=</varname></term> <listitem><para>Configure the location of a file containing <ulink diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index a0fab46a19..86b66e2be0 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -201,6 +201,7 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { [SERVICE_FAILED] = "failed", [SERVICE_DEAD_BEFORE_AUTO_RESTART] = "dead-before-auto-restart", [SERVICE_FAILED_BEFORE_AUTO_RESTART] = "failed-before-auto-restart", + [SERVICE_DEAD_RESOURCES_PINNED] = "dead-resources-pinned", [SERVICE_AUTO_RESTART] = "auto-restart", [SERVICE_CLEANING] = "cleaning", }; diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index 2fab42e9c7..169e1f719e 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -146,6 +146,7 @@ typedef enum ServiceState { SERVICE_FAILED, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, + SERVICE_DEAD_RESOURCES_PINNED, /* Like SERVICE_DEAD, but with pinned resources */ SERVICE_AUTO_RESTART, SERVICE_CLEANING, _SERVICE_STATE_MAX, diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index d77842bdab..ce20183a70 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -49,7 +49,7 @@ BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode); -static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode); +BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_proc, protect_proc, ProtectProc); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_proc_subset, proc_subset, ProcSubset); @@ -1318,7 +1318,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectorySymlink", "a(sst)", bus_property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", bus_property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectory", "as", bus_property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StateDirectorySymlink", "a(sst)", bus_property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1695,7 +1695,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, protect_home_fr static BUS_DEFINE_SET_TRANSIENT_PARSE(keyring_mode, ExecKeyringMode, exec_keyring_mode_from_string); static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_proc, ProtectProc, protect_proc_from_string); static BUS_DEFINE_SET_TRANSIENT_PARSE(proc_subset, ProcSubset, proc_subset_from_string); -static BUS_DEFINE_SET_TRANSIENT_PARSE(preserve_mode, ExecPreserveMode, exec_preserve_mode_from_string); +BUS_DEFINE_SET_TRANSIENT_PARSE(exec_preserve_mode, ExecPreserveMode, exec_preserve_mode_from_string); static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(personality, unsigned long, parse_personality); static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(secure_bits, "i", int32_t, int, "%" PRIi32, secure_bits_to_string_alloc_with_check); static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint64_t, "%" PRIu64, capability_set_to_string); @@ -2047,7 +2047,7 @@ int bus_exec_context_set_transient_property( return bus_set_transient_proc_subset(u, name, &c->proc_subset, message, flags, error); if (streq(name, "RuntimeDirectoryPreserve")) - return bus_set_transient_preserve_mode(u, name, &c->runtime_directory_preserve_mode, message, flags, error); + return bus_set_transient_exec_preserve_mode(u, name, &c->runtime_directory_preserve_mode, message, flags, error); if (streq(name, "UMask")) return bus_set_transient_mode_t(u, name, &c->umask, message, flags, error); diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index c53834140e..5926bdb4b1 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -28,6 +28,8 @@ int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *inte int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); int bus_property_get_exec_command_list(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); int bus_property_get_exec_ex_command_list(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); +int bus_property_get_exec_preserve_mode(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); int bus_exec_context_set_transient_property(Unit *u, ExecContext *c, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_exec_command(Unit *u, const char *name, ExecCommand **exec_command, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); +int bus_set_transient_exec_preserve_mode(Unit *u, const char *name, ExecPreserveMode *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index a563624fce..ecab3f479d 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -349,6 +349,7 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NFileDescriptorStore", "u", property_get_size_as_uint32, offsetof(Service, n_fd_store), 0), + SD_BUS_PROPERTY("FileDescriptorStorePreserve", "s", bus_property_get_exec_preserve_mode, offsetof(Service, fd_store_preserve_mode), 0), SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StatusErrno", "i", bus_property_get_int, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -599,6 +600,9 @@ static int bus_service_set_transient_property( if (streq(name, "FileDescriptorStoreMax")) return bus_set_transient_unsigned(u, name, &s->n_fd_store_max, message, flags, error); + if (streq(name, "FileDescriptorStorePreserve")) + return bus_set_transient_exec_preserve_mode(u, name, &s->fd_store_preserve_mode, message, flags, error); + if (streq(name, "NotifyAccess")) return bus_set_transient_notify_access(u, name, &s->notify_access, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index f35c743655..ce0e2f0c5c 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -136,7 +136,7 @@ {{type}}.MountFlags, config_parse_exec_mount_propagation_flag, 0, offsetof({{type}}, exec_context.mount_propagation_flag) {{type}}.MountAPIVFS, config_parse_exec_mount_apivfs, 0, offsetof({{type}}, exec_context) {{type}}.Personality, config_parse_personality, 0, offsetof({{type}}, exec_context.personality) -{{type}}.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof({{type}}, exec_context.runtime_directory_preserve_mode) +{{type}}.RuntimeDirectoryPreserve, config_parse_exec_preserve_mode, 0, offsetof({{type}}, exec_context.runtime_directory_preserve_mode) {{type}}.RuntimeDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode) {{type}}.RuntimeDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME]) {{type}}.StateDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE].mode) @@ -433,6 +433,7 @@ Service.SysVStartPriority, config_parse_warn_compat, Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking) Service.BusName, config_parse_bus_name, 0, offsetof(Service, bus_name) Service.FileDescriptorStoreMax, config_parse_unsigned, 0, offsetof(Service, n_fd_store_max) +Service.FileDescriptorStorePreserve, config_parse_exec_preserve_mode, 0, offsetof(Service, fd_store_preserve_mode) Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) Service.Sockets, config_parse_service_sockets, 0, 0 Service.BusPolicy, config_parse_warn_compat, DISABLED_LEGACY, 0 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 686a72402d..cf0096263a 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -138,7 +138,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to pa DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "Failed to parse protect home value"); DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value"); -DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse resource preserve mode"); DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type"); DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier"); diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index ab682ee23e..98adf5ae05 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -101,7 +101,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_selinux_context); CONFIG_PARSER_PROTOTYPE(config_parse_exec_apparmor_profile); CONFIG_PARSER_PROTOTYPE(config_parse_exec_smack_process_label); CONFIG_PARSER_PROTOTYPE(config_parse_address_families); -CONFIG_PARSER_PROTOTYPE(config_parse_runtime_preserve_mode); +CONFIG_PARSER_PROTOTYPE(config_parse_exec_preserve_mode); CONFIG_PARSER_PROTOTYPE(config_parse_exec_directories); CONFIG_PARSER_PROTOTYPE(config_parse_set_credential); CONFIG_PARSER_PROTOTYPE(config_parse_load_credential); diff --git a/src/core/service.c b/src/core/service.c index 934500abd6..7130cbf4e6 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -69,6 +69,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_FAILED] = UNIT_FAILED, [SERVICE_DEAD_BEFORE_AUTO_RESTART] = UNIT_INACTIVE, [SERVICE_FAILED_BEFORE_AUTO_RESTART] = UNIT_FAILED, + [SERVICE_DEAD_RESOURCES_PINNED] = UNIT_INACTIVE, [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING, [SERVICE_CLEANING] = UNIT_MAINTENANCE, }; @@ -97,6 +98,7 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = [SERVICE_FAILED] = UNIT_FAILED, [SERVICE_DEAD_BEFORE_AUTO_RESTART] = UNIT_INACTIVE, [SERVICE_FAILED_BEFORE_AUTO_RESTART] = UNIT_FAILED, + [SERVICE_DEAD_RESOURCES_PINNED] = UNIT_INACTIVE, [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING, [SERVICE_CLEANING] = UNIT_MAINTENANCE, }; @@ -139,6 +141,8 @@ static void service_init(Unit *u) { s->oom_policy = _OOM_POLICY_INVALID; s->reload_begin_usec = USEC_INFINITY; s->reload_signal = SIGHUP; + + s->fd_store_preserve_mode = EXEC_PRESERVE_RESTART; } static void service_unwatch_control_pid(Service *s) { @@ -1031,8 +1035,10 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { if (s->n_fd_store_max > 0) fprintf(f, "%sFile Descriptor Store Max: %u\n" + "%sFile Descriptor Store Pin: %s\n" "%sFile Descriptor Store Current: %zu\n", prefix, s->n_fd_store_max, + prefix, exec_preserve_mode_to_string(s->fd_store_preserve_mode), prefix, s->n_fd_store); service_dump_fdstore(s, f, prefix); @@ -1244,7 +1250,8 @@ static void service_set_state(Service *s, ServiceState state) { if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, - SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART)) { + SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART, + SERVICE_DEAD_RESOURCES_PINNED)) { unit_unwatch_all_pids(UNIT(s)); unit_dequeue_rewatch_pids(UNIT(s)); } @@ -1351,7 +1358,8 @@ static int service_coldplug(Unit *u) { if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART, - SERVICE_CLEANING)) { + SERVICE_CLEANING, + SERVICE_DEAD_RESOURCES_PINNED)) { (void) unit_enqueue_rewatch_pids(u); (void) unit_setup_exec_runtime(u); } @@ -1939,6 +1947,12 @@ static bool service_will_restart(Unit *u) { return unit_will_restart_default(u); } +static ServiceState service_determine_dead_state(Service *s) { + assert(s); + + return s->fd_store && s->fd_store_preserve_mode == EXEC_PRESERVE_YES ? SERVICE_DEAD_RESOURCES_PINNED : SERVICE_DEAD; +} + static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) { ServiceState end_state, restart_state; int r; @@ -1955,11 +1969,11 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) if (s->result == SERVICE_SUCCESS) { unit_log_success(UNIT(s)); - end_state = SERVICE_DEAD; + end_state = service_determine_dead_state(s); restart_state = SERVICE_DEAD_BEFORE_AUTO_RESTART; } else if (s->result == SERVICE_SKIP_CONDITION) { unit_log_skip(UNIT(s), service_result_to_string(s->result)); - end_state = SERVICE_DEAD; + end_state = service_determine_dead_state(s); restart_state = SERVICE_DEAD_BEFORE_AUTO_RESTART; } else { unit_log_failure(UNIT(s), service_result_to_string(s->result)); @@ -2023,6 +2037,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) /* Also, remove the runtime directory */ unit_destroy_runtime_data(UNIT(s), &s->exec_context); + /* Also get rid of the fd store, if that's configured. */ + if (s->fd_store_preserve_mode == EXEC_PRESERVE_NO) + service_release_fd_store(s); + /* Get rid of the IPC bits of the user */ unit_unref_uid_gid(UNIT(s), true); @@ -2701,7 +2719,7 @@ static int service_start(Unit *u) { if (IN_SET(s->state, SERVICE_AUTO_RESTART, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART)) return -EAGAIN; - assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)); + assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_RESOURCES_PINNED)); r = unit_acquire_invocation_id(u); if (r < 0) @@ -2760,7 +2778,7 @@ static int service_stop(Unit *u) { case SERVICE_AUTO_RESTART: /* A restart will be scheduled or is in progress. */ - service_set_state(s, SERVICE_DEAD); + service_set_state(s, service_determine_dead_state(s)); return 0; case SERVICE_CONDITION: @@ -2789,6 +2807,7 @@ static int service_stop(Unit *u) { case SERVICE_FAILED_BEFORE_AUTO_RESTART: case SERVICE_DEAD: case SERVICE_FAILED: + case SERVICE_DEAD_RESOURCES_PINNED: default: /* Unknown state, or unit_stop() should already have handled these */ assert_not_reached(); @@ -3397,7 +3416,7 @@ static bool service_may_gc(Unit *u) { /* Only allow collection of actually dead services, i.e. not those that are in the transitionary * SERVICE_DEAD_BEFORE_AUTO_RESTART/SERVICE_FAILED_BEFORE_AUTO_RESTART states. */ - if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)) + if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_RESOURCES_PINNED)) return false; return true; @@ -3624,6 +3643,7 @@ static void service_notify_cgroup_empty_event(Unit *u) { case SERVICE_DEAD_BEFORE_AUTO_RESTART: case SERVICE_FAILED_BEFORE_AUTO_RESTART: case SERVICE_AUTO_RESTART: + case SERVICE_DEAD_RESOURCES_PINNED: unit_prune_cgroup(u); break; @@ -4712,7 +4732,7 @@ int service_set_socket_fd( assert(!s->socket_peer); - if (s->state != SERVICE_DEAD) + if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_DEAD_RESOURCES_PINNED)) return -EAGAIN; if (getpeername_pretty(fd, true, &peer_text) >= 0) { @@ -4749,7 +4769,7 @@ static void service_reset_failed(Unit *u) { assert(s); if (s->state == SERVICE_FAILED) - service_set_state(s, SERVICE_DEAD); + service_set_state(s, service_determine_dead_state(s)); s->result = SERVICE_SUCCESS; s->reload_result = SERVICE_SUCCESS; @@ -4920,14 +4940,19 @@ static void service_release_resources(Unit *u) { /* Don't release resources if this is a transitionary failed/dead state * (i.e. SERVICE_DEAD_BEFORE_AUTO_RESTART/SERVICE_FAILED_BEFORE_AUTO_RESTART), insist on a permanent * failure state. */ - if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)) + if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_RESOURCES_PINNED)) return; log_unit_debug(u, "Releasing resources..."); service_close_socket_fd(s); service_release_stdio_fd(s); - service_release_fd_store(s); + + if (s->fd_store_preserve_mode != EXEC_PRESERVE_YES) + service_release_fd_store(s); + + if (s->state == SERVICE_DEAD_RESOURCES_PINNED && !s->fd_store) + service_set_state(s, SERVICE_DEAD); } static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { diff --git a/src/core/service.h b/src/core/service.h index 03edb18e31..1d1aa91fc6 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -206,6 +206,7 @@ struct Service { ServiceFDStore *fd_store; size_t n_fd_store; unsigned n_fd_store_max; + ExecPreserveMode fd_store_preserve_mode; char *usb_function_descriptors; char *usb_function_strings; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1c991ae54f..ebbd1f7f28 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2198,7 +2198,8 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con "USBFunctionStrings", "OOMPolicy", "TimeoutStartFailureMode", - "TimeoutStopFailureMode")) + "TimeoutStopFailureMode", + "FileDescriptorStorePreserve")) return bus_append_string(m, field, eq); if (STR_IN_SET(field, "PermissionsStartOnly", |