core: add a new sd_notify() message for removing fds from the FD store again
authorLennart Poettering <lennart@poettering.net>
Mon, 13 Nov 2017 17:26:04 +0000 (18:26 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 27 Nov 2017 16:04:04 +0000 (17:04 +0100)
Currenly the only way to remove fds from the fdstore is to fully
stop the service, or to somehow trigger POLLERR/POLLHUP on the fd, in
which case systemd will remove the fd automatically.

Let's add another way: a new message that can be sent to remove fds
explicitly, given their name.

man/sd_notify.xml
src/core/service.c
src/systemd/sd-daemon.h

index 3ba242b..a53b1ab 100644 (file)
       </varlistentry>
 
       <varlistentry>
+        <term>FDSTOREREMOVE=1</term>
+
+        <listitem><para>Removes file descriptors from the file descriptor store. This field needs to be combined with
+        <varname>FDNAME=</varname> to specify the name of the file descriptors to remove.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term>FDNAME=…</term>
 
-        <listitem><para>When used in combination with
-        <varname>FDSTORE=1</varname>, specifies a name for the
-        submitted file descriptors. This name is passed to the service
-        during activation, and may be queried using
+        <listitem><para>When used in combination with <varname>FDSTORE=1</varname>, specifies a name for the submitted
+        file descriptors. When used with <varname>FDSTOREREMOVE=1</varname>, specifies the name for the file
+        descriptors to remove. This name is passed to the service during activation, and may be queried using
         <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>. File
-        descriptors submitted without this field set, will implicitly
-        get the name <literal>stored</literal> assigned. Note that, if
-        multiple file descriptors are submitted at once, the specified
-        name will be assigned to all of them. In order to assign
-        different names to submitted file descriptors, submit them in
-        separate invocations of
-        <function>sd_pid_notify_with_fds()</function>. The name may
-        consist of any ASCII character, but must not contain control
-        characters or <literal>:</literal>. It may not be longer than
-        255 characters. If a submitted name does not follow these
-        restrictions, it is ignored.</para></listitem>
+        descriptors submitted without this field set, will implicitly get the name <literal>stored</literal>
+        assigned. Note that, if multiple file descriptors are submitted at once, the specified name will be assigned to
+        all of them. In order to assign different names to submitted file descriptors, submit them in separate
+        invocations of <function>sd_pid_notify_with_fds()</function>. The name may consist of arbitrary ASCII
+        characters except control characters or <literal>:</literal>. It may not be longer than 255 characters. If a
+        submitted name does not follow these restrictions, it is ignored.</para></listitem>
       </varlistentry>
 
     </variablelist>
index b25ed49..bd187a2 100644 (file)
@@ -458,6 +458,21 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
         return 0;
 }
 
+static void service_remove_fd_store(Service *s, const char *name) {
+        ServiceFDStore *fs, *n;
+
+        assert(s);
+        assert(name);
+
+        LIST_FOREACH_SAFE(fd_store, fs, n, s->fd_store) {
+                if (!streq(fs->fdname, name))
+                        continue;
+
+                log_unit_debug(UNIT(s), "Got explicit request to remove fd %i (%s), closing.", fs->fd, name);
+                service_fd_store_unlink(fs);
+        }
+}
+
 static int service_arm_timer(Service *s, usec_t usec) {
         int r;
 
@@ -3466,7 +3481,19 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
                         service_reset_watchdog_timeout(s, watchdog_override_usec);
         }
 
-        if (strv_find(tags, "FDSTORE=1")) {
+        /* Process FD store messages. Either FDSTOREREMOVE=1 for removal, or FDSTORE=1 for addition. In both cases,
+         * process FDNAME= for picking the file descriptor name to use. Note that FDNAME= is required when removing
+         * fds, but optional when pushing in new fds, for compatibility reasons. */
+        if (strv_find(tags, "FDSTOREREMOVE=1")) {
+                const char *name;
+
+                name = strv_find_startswith(tags, "FDNAME=");
+                if (!name || !fdname_is_valid(name))
+                        log_unit_warning(u, "FDSTOREREMOVE=1 requested, but no valid file descriptor name passed, ignoring.");
+                else
+                        service_remove_fd_store(s, name);
+
+        } else if (strv_find(tags, "FDSTORE=1")) {
                 const char *name;
 
                 name = strv_find_startswith(tags, "FDNAME=");
@@ -3475,7 +3502,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
                         name = NULL;
                 }
 
-                service_add_fd_store_set(s, fds, name);
+                (void) service_add_fd_store_set(s, fds, name);
         }
 
         /* Notify clients about changed status or main pid */
index 3fd0cc6..9772a05 100644 (file)
@@ -222,6 +222,15 @@ int sd_is_mq(int fd, const char *path);
                   invocation. This variable is only supported with
                   sd_pid_notify_with_fds().
 
+     FDSTOREREMOVE=1
+                  Remove one or more file descriptors from the file
+                  descriptor store, identified by the name specified
+                  in FDNAME=, see below.
+
+     FDNAME=      A name to assign to new file descriptors stored in the
+                  file descriptor store, or the name of the file descriptors
+                  to remove in case of FDSTOREREMOVE=1.
+
   Daemons can choose to send additional variables. However, it is
   recommended to prefix variable names not listed above with X_.