core: Add optional FDPOLL=0 argument to fdstore

A service can specify FDSTORE=1 FDPOLL=0 to request that PID1 does not
poll the fd to remove them on error. If set, fds will only be removed on
FDSTOREREMOVE=1 or when the service is done.

Fixes: #12086
This commit is contained in:
Kenny Levinsen 2020-04-08 20:19:30 +02:00
parent 9dcd43b149
commit cb5a46b845
2 changed files with 26 additions and 14 deletions

View file

@ -219,8 +219,8 @@
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>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If
<varname>FDPOLL=0</varname> is not set and the 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
@ -251,6 +251,16 @@
submitted name does not follow these restrictions, it is ignored.</para></listitem>
</varlistentry>
<varlistentry>
<term>FDPOLL=0</term>
<listitem><para>When used in combination with <varname>FDSTORE=1</varname>, disables polling of the stored
file descriptors regardless of whether or not they are pollable. As this option disables automatic cleanup
of the stored file descriptors on EPOLLERR and EPOLLHUP, care must be taken to ensure proper manual cleanup.
Use of this option is not generally recommended except for when automatic cleanup has unwanted behavior such
as prematurely discarding file descriptors from the store.</para></listitem>
</varlistentry>
</variablelist>
<para>It is recommended to prefix variable names that are not

View file

@ -423,7 +423,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
return 0;
}
static int service_add_fd_store(Service *s, int fd, const char *name) {
static int service_add_fd_store(Service *s, int fd, const char *name, bool do_poll) {
ServiceFDStore *fs;
int r;
@ -459,13 +459,15 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
return -ENOMEM;
}
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
free(fs->fdname);
free(fs);
return r;
} else if (r >= 0)
(void) sd_event_source_set_description(fs->event_source, "service-fd-store");
if (do_poll) {
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
free(fs->fdname);
free(fs);
return r;
} 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++;
@ -473,7 +475,7 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
return 1; /* fd newly stored */
}
static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name, bool do_poll) {
int r;
assert(s);
@ -485,7 +487,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
if (fd < 0)
break;
r = service_add_fd_store(s, fd, name);
r = service_add_fd_store(s, fd, name, do_poll);
if (r == -EXFULL)
return log_unit_warning_errno(UNIT(s), r,
"Cannot store more fds than FileDescriptorStoreMax=%u, closing remaining.",
@ -2961,7 +2963,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
fdn += strspn(fdn, WHITESPACE);
(void) cunescape(fdn, 0, &t);
r = service_add_fd_store(s, fd, t);
r = service_add_fd_store(s, fd, t, true);
if (r < 0)
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else
@ -4068,7 +4070,7 @@ static void service_notify_message(
name = NULL;
}
(void) service_add_fd_store_set(s, fds, name);
(void) service_add_fd_store_set(s, fds, name, !strv_contains(tags, "FDPOLL=0"));
}
/* Notify clients about changed status or main pid */