summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-04-30 22:32:28 +0200
committerGitHub <noreply@github.com>2020-04-30 22:32:28 +0200
commita8332698d794522104f2131e294ab336d7726767 (patch)
tree977b025407c8b5dedca47b48a908030ec93f42e2
parentdb72aea4a952cdfdef51eda03408d7c4a11e7359 (diff)
parent30520492604bad0bb1e346b538119dcb37525d37 (diff)
downloadsystemd-a8332698d794522104f2131e294ab336d7726767.tar.gz
Merge pull request #15592 from kennylevinsen/fdpoll-standalone
Introduce FDPOLL=0
-rw-r--r--man/sd_notify.xml14
-rw-r--r--src/core/service.c67
-rw-r--r--src/core/service.h1
3 files changed, 51 insertions, 31 deletions
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index 3046ca88ee..0157ce864a 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -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
diff --git a/src/core/service.c b/src/core/service.c
index 7d5928e455..292df8d5e1 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -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;
@@ -453,19 +453,22 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
fs->fd = fd;
fs->service = s;
+ fs->do_poll = do_poll;
fs->fdname = strdup(name ?: "stored");
if (!fs->fdname) {
free(fs);
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 +476,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 +488,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.",
@@ -2715,7 +2718,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (!c)
return log_oom();
- (void) serialize_item_format(f, "fd-store-fd", "%i %s", copy, c);
+ (void) serialize_item_format(f, "fd-store-fd", "%i \"%s\" %i", copy, c, fs->do_poll);
}
if (s->main_exec_status.pid > 0) {
@@ -2944,30 +2947,36 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->socket_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "fd-store-fd")) {
- const char *fdv;
- size_t pf;
+ _cleanup_free_ char *fdv = NULL, *fdn = NULL, *fdp = NULL;
int fd;
+ int do_poll;
- pf = strcspn(value, WHITESPACE);
- fdv = strndupa(value, pf);
-
- if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ r = extract_first_word(&value, &fdv, NULL, 0);
+ if (r <= 0 || safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
- else {
- _cleanup_free_ char *t = NULL;
- const char *fdn;
+ return 0;
+ }
- fdn = value + pf;
- fdn += strspn(fdn, WHITESPACE);
- (void) cunescape(fdn, 0, &t);
+ r = extract_first_word(&value, &fdn, NULL, EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE);
+ if (r <= 0) {
+ log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
+ return 0;
+ }
- r = service_add_fd_store(s, fd, t);
- if (r < 0)
- log_unit_error_errno(u, r, "Failed to add fd to store: %m");
- else
- fdset_remove(fds, fd);
+ r = extract_first_word(&value, &fdp, NULL, 0);
+ if (r == 0) {
+ /* If the value is not present, we assume the default */
+ do_poll = 1;
+ } else if (r < 0 || safe_atoi(fdp, &do_poll) < 0) {
+ log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
+ return 0;
}
+ r = service_add_fd_store(s, fd, fdn, do_poll);
+ if (r < 0)
+ log_unit_error_errno(u, r, "Failed to add fd to store: %m");
+ else
+ fdset_remove(fds, fd);
} else if (streq(key, "main-exec-status-pid")) {
pid_t pid;
@@ -4068,7 +4077,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 */
diff --git a/src/core/service.h b/src/core/service.h
index 11e861a3d4..b9c8036f22 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -80,6 +80,7 @@ struct ServiceFDStore {
int fd;
char *fdname;
sd_event_source *event_source;
+ bool do_poll;
LIST_FIELDS(ServiceFDStore, fd_store);
};