mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-27 14:03:43 +03:00
Merge pull request #6160 from poettering/non-pollable-fdstore
support for non-pollable fds in the service fdstore
This commit is contained in:
commit
82891136d7
@ -205,25 +205,24 @@
|
||||
<varlistentry>
|
||||
<term>FDSTORE=1</term>
|
||||
|
||||
<listitem><para>Stores additional file descriptors in the service manager. File
|
||||
descriptors sent this way will be maintained per-service by the service manager
|
||||
and will be passed again using the usual file descriptor passing logic on the next
|
||||
invocation of the service, see
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
This is useful for implementing service restart schemes where services serialize
|
||||
their state to <filename>/run</filename>, push their file descriptors to the
|
||||
system manager, and are then restarted, retrieving their state again via socket
|
||||
passing and <filename>/run</filename>. Note that the service manager will accept
|
||||
messages for a service only if <varname>FileDescriptorStoreMax=</varname> is set
|
||||
to non-zero for it (defaults to zero, see
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
|
||||
File descriptors must be pollable, see
|
||||
<citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
|
||||
Multiple arrays of file descriptors may be sent in separate messages, in which
|
||||
case the arrays are combined. Note that the service manager removes duplicate
|
||||
file descriptors before passing them to the service. Use
|
||||
<function>sd_pid_notify_with_fds()</function> to send messages with
|
||||
<literal>FDSTORE=1</literal>, see below.</para></listitem>
|
||||
<listitem><para>Stores additional file descriptors in the service manager. File descriptors sent this way will
|
||||
be maintained per-service by the service manager and will later be handed back using the usual file descriptor
|
||||
passing logic at the next invocation of the service, see
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>. 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 <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory
|
||||
file descriptor. Note that the service manager will accept messages for a service only if its
|
||||
<varname>FileDescriptorStoreMax=</varname> setting is non-zero (defaults to zero, see
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If file
|
||||
descriptors sent are pollable (see
|
||||
<citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), then any
|
||||
<constant>EPOLLHUP</constant> or <constant>EPOLLERR</constant> event seen on them will result in their
|
||||
automatic removal from the store. Multiple arrays of file descriptors may be sent in separate messages, in
|
||||
which case the arrays are combined. Note that the service manager removes duplicate (pointing to the same
|
||||
object) file descriptors before passing them to the service. Use <function>sd_pid_notify_with_fds()</function>
|
||||
to send messages with <literal>FDSTORE=1</literal>, see below.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -312,13 +311,14 @@
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>On failure, these calls return a negative errno-style error
|
||||
code. If <varname>$NOTIFY_SOCKET</varname> was not set and hence
|
||||
no status data could be sent, 0 is returned. If the status was
|
||||
sent, these functions return with a positive return value. In
|
||||
order to support both, init systems that implement this scheme and
|
||||
those which do not, it is generally recommended to ignore the
|
||||
return value of this call.</para>
|
||||
<para>On failure, these calls return a negative errno-style error code. If <varname>$NOTIFY_SOCKET</varname> was
|
||||
not set and hence no status message could be sent, 0 is returned. If the status was sent, these functions return a
|
||||
positive value. In order to support both service managers that implement this scheme and those which do not, it is
|
||||
generally recommended to ignore the return value of this call. Note that the return value simply indicates whether
|
||||
the notification message was enqueued properly, it does not reflect whether the message could be processed
|
||||
successfully. Specifically, no error is returned when a file descriptor is attempted to be stored using
|
||||
<varname>FDSTORE=1</varname> but the service is not actually configured to permit storing of file descriptors (see
|
||||
above).</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -853,21 +853,18 @@
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>FileDescriptorStoreMax=</varname></term>
|
||||
<listitem><para>Configure how many file descriptors may be
|
||||
stored in the service manager for the service using
|
||||
<listitem><para>Configure how many file descriptors may be stored in the service manager for the service using
|
||||
<citerefentry><refentrytitle>sd_pid_notify_with_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>'s
|
||||
<literal>FDSTORE=1</literal> messages. This is useful for
|
||||
implementing service restart schemes where the state is
|
||||
serialized to <filename>/run</filename> and the file
|
||||
descriptors passed to the service manager, to allow restarts
|
||||
without losing state. 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 to the service's main process on the
|
||||
next service restart. Any file descriptors passed to the
|
||||
service manager are automatically closed when POLLHUP or
|
||||
POLLERR is seen on them, or when the service is fully stopped
|
||||
and no job is queued or being executed for it.</para></listitem>
|
||||
<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
|
||||
<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 to the service's main process on the next
|
||||
service restart. 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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -1047,3 +1047,12 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
|
||||
|
||||
static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
|
||||
[NOTIFY_NONE] = "none",
|
||||
[NOTIFY_MAIN] = "main",
|
||||
[NOTIFY_EXEC] = "exec",
|
||||
[NOTIFY_ALL] = "all"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
|
||||
|
@ -257,6 +257,15 @@ typedef enum UnitDependency {
|
||||
_UNIT_DEPENDENCY_INVALID = -1
|
||||
} UnitDependency;
|
||||
|
||||
typedef enum NotifyAccess {
|
||||
NOTIFY_NONE,
|
||||
NOTIFY_ALL,
|
||||
NOTIFY_MAIN,
|
||||
NOTIFY_EXEC,
|
||||
_NOTIFY_ACCESS_MAX,
|
||||
_NOTIFY_ACCESS_INVALID = -1
|
||||
} NotifyAccess;
|
||||
|
||||
typedef enum UnitNameFlags {
|
||||
UNIT_NAME_PLAIN = 1, /* Allow foo.service */
|
||||
UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */
|
||||
@ -365,3 +374,6 @@ TimerState timer_state_from_string(const char *s) _pure_;
|
||||
|
||||
const char *unit_dependency_to_string(UnitDependency i) _const_;
|
||||
UnitDependency unit_dependency_from_string(const char *s) _pure_;
|
||||
|
||||
const char* notify_access_to_string(NotifyAccess i) _const_;
|
||||
NotifyAccess notify_access_from_string(const char *s) _pure_;
|
||||
|
@ -199,6 +199,39 @@ static int bus_service_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "FileDescriptorStoreMax")) {
|
||||
uint32_t u;
|
||||
|
||||
r = sd_bus_message_read(message, "u", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
s->n_fd_store_max = (unsigned) u;
|
||||
unit_write_drop_in_private_format(UNIT(s), mode, name, "FileDescriptorStoreMax=%" PRIu32, u);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "NotifyAccess")) {
|
||||
const char *t;
|
||||
NotifyAccess k;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
k = notify_access_from_string(t);
|
||||
if (k < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid notify access setting %s", t);
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
s->notify_access = k;
|
||||
unit_write_drop_in_private_format(UNIT(s), mode, name, "NotifyAccess=%s", notify_access_to_string(s->notify_access));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "ExecStart")) {
|
||||
unsigned n = 0;
|
||||
|
||||
|
@ -413,13 +413,12 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
|
||||
}
|
||||
|
||||
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
|
||||
if (r < 0) {
|
||||
if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
|
||||
free(fs->fdname);
|
||||
free(fs);
|
||||
return r;
|
||||
}
|
||||
|
||||
(void) sd_event_source_set_description(fs->event_source, "service-fd-store");
|
||||
} else if (r >= 0)
|
||||
(void) sd_event_source_set_description(fs->event_source, "service-fd-store");
|
||||
|
||||
LIST_PREPEND(fd_store, s->fd_store, fs);
|
||||
s->n_fd_store++;
|
||||
@ -3584,15 +3583,6 @@ static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] =
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
|
||||
|
||||
static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
|
||||
[NOTIFY_NONE] = "none",
|
||||
[NOTIFY_MAIN] = "main",
|
||||
[NOTIFY_EXEC] = "exec",
|
||||
[NOTIFY_ALL] = "all"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
|
||||
|
||||
static const char* const notify_state_table[_NOTIFY_STATE_MAX] = {
|
||||
[NOTIFY_UNKNOWN] = "unknown",
|
||||
[NOTIFY_READY] = "ready",
|
||||
|
@ -61,15 +61,6 @@ typedef enum ServiceExecCommand {
|
||||
_SERVICE_EXEC_COMMAND_INVALID = -1
|
||||
} ServiceExecCommand;
|
||||
|
||||
typedef enum NotifyAccess {
|
||||
NOTIFY_NONE,
|
||||
NOTIFY_ALL,
|
||||
NOTIFY_MAIN,
|
||||
NOTIFY_EXEC,
|
||||
_NOTIFY_ACCESS_MAX,
|
||||
_NOTIFY_ACCESS_INVALID = -1
|
||||
} NotifyAccess;
|
||||
|
||||
typedef enum NotifyState {
|
||||
NOTIFY_UNKNOWN,
|
||||
NOTIFY_READY,
|
||||
@ -218,9 +209,6 @@ ServiceType service_type_from_string(const char *s) _pure_;
|
||||
const char* service_exec_command_to_string(ServiceExecCommand i) _const_;
|
||||
ServiceExecCommand service_exec_command_from_string(const char *s) _pure_;
|
||||
|
||||
const char* notify_access_to_string(NotifyAccess i) _const_;
|
||||
NotifyAccess notify_access_from_string(const char *s) _pure_;
|
||||
|
||||
const char* notify_state_to_string(NotifyState i) _const_;
|
||||
NotifyState notify_state_from_string(const char *s) _pure_;
|
||||
|
||||
|
@ -266,7 +266,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
"StandardInput", "StandardOutput", "StandardError",
|
||||
"Description", "Slice", "Type", "WorkingDirectory",
|
||||
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
|
||||
"ProtectHome", "SELinuxContext", "Restart", "RootImage"))
|
||||
"ProtectHome", "SELinuxContext", "Restart", "RootImage",
|
||||
"NotifyAccess"))
|
||||
r = sd_bus_message_append(m, "v", "s", eq);
|
||||
|
||||
else if (streq(field, "SyslogLevel")) {
|
||||
@ -389,6 +390,15 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
|
||||
r = sd_bus_message_append(m, "v", "i", (int32_t) n);
|
||||
|
||||
} else if (streq(field, "FileDescriptorStoreMax")) {
|
||||
unsigned u;
|
||||
|
||||
r = safe_atou(eq, &u);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse file descriptor store limit: %s", eq);
|
||||
|
||||
r = sd_bus_message_append(m, "v", "u", (uint32_t) u);
|
||||
|
||||
} else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
|
||||
const char *p;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user