From 3ceb72e5582948cd81fa7018716c67ac7f17905e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Jun 2017 23:30:30 +0200 Subject: [PATCH] core: permit FDSTORE=1 messages with non-pollable fds This also alters the documentation to recommend memfds rather than /run for serializing state across reboots. That's because /run doesn't actually have the same lifecycle as the fd store, as it is cleared out on restarts. Fixes: #5606 --- man/sd_notify.xml | 52 ++++++++++++++++++++--------------------- man/systemd.service.xml | 25 +++++++++----------- src/core/service.c | 7 +++--- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/man/sd_notify.xml b/man/sd_notify.xml index 4dcefc4baf..e8ddea2f5f 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -205,25 +205,24 @@ FDSTORE=1 - 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 - sd_listen_fds3. - This is useful for implementing service restart schemes where services serialize - their state to /run, push their file descriptors to the - system manager, and are then restarted, retrieving their state again via socket - passing and /run. Note that the service manager will accept - messages for a service only if FileDescriptorStoreMax= is set - to non-zero for it (defaults to zero, see - systemd.service5). - File descriptors must be pollable, see - epoll_ctl2. - 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 - sd_pid_notify_with_fds() to send messages with - FDSTORE=1, see below. + 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 + sd_listen_fds3. 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 /run, or better, stored + in a memfd_create2 memory + file descriptor. Note that the service manager will accept messages for a service only if its + FileDescriptorStoreMax= setting is non-zero (defaults to zero, see + systemd.service5). If file + descriptors sent are pollable (see + epoll_ctl2), then any + EPOLLHUP or EPOLLERR 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 sd_pid_notify_with_fds() + to send messages with FDSTORE=1, see below. @@ -312,13 +311,14 @@ Return Value - On failure, these calls return a negative errno-style error - code. If $NOTIFY_SOCKET 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. + On failure, these calls return a negative errno-style error code. If $NOTIFY_SOCKET 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 + FDSTORE=1 but the service is not actually configured to permit storing of file descriptors (see + above). diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 95c16fded7..1faac0f762 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -853,21 +853,18 @@ FileDescriptorStoreMax= - Configure how many file descriptors may be - stored in the service manager for the service using + Configure how many file descriptors may be stored in the service manager for the service using sd_pid_notify_with_fds3's - FDSTORE=1 messages. This is useful for - implementing service restart schemes where the state is - serialized to /run 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. + FDSTORE=1 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 + /run, or better, stored in a + memfd_create2 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 + POLLHUP or POLLERR is seen on them, or when the service is fully + stopped and no job is queued or being executed for it. diff --git a/src/core/service.c b/src/core/service.c index df7f1f3053..e1f02ccde1 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -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++;