]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
service: allow freeing the fdstore via cleaning
authorLennart Poettering <lennart@poettering.net>
Wed, 29 Mar 2023 20:10:01 +0000 (22:10 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 13 Apr 2023 04:44:27 +0000 (06:44 +0200)
Now that we have a potentially pinned fdstore let's add a concept for
cleaning it explicitly on user requested. Let's expose this via
"systemctl clean", i.e. the same way as user directories are cleaned.

man/systemctl.xml
src/core/dbus-unit.c
src/core/execute.c
src/core/execute.h
src/core/service.c
src/core/timer.c
src/systemctl/systemctl-clean-or-freeze.c
src/systemctl/systemctl.c

index 1a881d10495317289c144a8cf5f3bc4b6c1c7ec3..705ed3e2386d71ce73988bffde7f48a3e589452d 100644 (file)
@@ -538,12 +538,16 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
             <varname>StateDirectory=</varname>, <varname>CacheDirectory=</varname>,
             <varname>LogsDirectory=</varname> and <varname>RuntimeDirectory=</varname>, see
             <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-            for details. For timer units this may be used to clear out the persistent timestamp data if
+            for details. It may also be used to clear the file decriptor store as enabled via
+            <varname>FileDescriptorStoreMax=</varname>, see
+            <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+            for details.  For timer units this may be used to clear out the persistent timestamp data if
             <varname>Persistent=</varname> is used and <option>--what=state</option> is selected, see
             <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
             command only applies to units that use either of these settings. If <option>--what=</option> is
-            not specified, both the cache and runtime data are removed (as these two types of data are
-            generally redundant and reproducible on the next invocation of the unit).</para>
+            not specified, the cache and runtime data as well as the file descriptor store are removed (as
+            these three types of resources are generally redundant and reproducible on the next invocation of
+            the unit). Note that the specified units must be stopped to invoke this operation.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
@@ -2193,13 +2197,17 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
 
         <listitem>
           <para>Select what type of per-unit resources to remove when the <command>clean</command> command is
-          invoked, see below. Takes one of <constant>configuration</constant>, <constant>state</constant>,
-          <constant>cache</constant>, <constant>logs</constant>, <constant>runtime</constant> to select the
-          type of resource. This option may be specified more than once, in which case all specified resource
-          types are removed. Also accepts the special value <constant>all</constant> as a shortcut for
-          specifying all five resource types. If this option is not specified defaults to the combination of
-          <constant>cache</constant> and <constant>runtime</constant>, i.e. the two kinds of resources that
-          are generally considered to be redundant and can be reconstructed on next invocation.</para>
+          invoked, see above. Takes one of <constant>configuration</constant>, <constant>state</constant>,
+          <constant>cache</constant>, <constant>logs</constant>, <constant>runtime</constant>,
+          <constant>fdstore</constant> to select the type of resource. This option may be specified more than
+          once, in which case all specified resource types are removed. Also accepts the special value
+          <constant>all</constant> as a shortcut for specifying all six resource types. If this option is not
+          specified defaults to the combination of <constant>cache</constant>, <constant>runtime</constant>
+          and <constant>fdstore</constant>, i.e. the three kinds of resources that are generally considered
+          to be redundant and can be reconstructed on next invocation. Note that the explicit removal of the
+          <constant>fdstore</constant> resource type is only useful if the
+          <varname>FileDescriptorStorePreserve=</varname> option is enabled, since the file descriptor store
+          is otherwise cleaned automatically when the unit is stopped.</para>
         </listitem>
       </varlistentry>
 
index 3f083a8174550bc98ffb4a495ee2a88a13dd6301..c01f41cb449766f6245a02ce2fa6bbdaeff248b4 100644 (file)
@@ -90,6 +90,12 @@ static int property_get_can_clean(
                         return r;
         }
 
+        if (FLAGS_SET(mask, EXEC_CLEAN_FDSTORE)) {
+                r = sd_bus_message_append(reply, "s", "fdstore");
+                if (r < 0)
+                        return r;
+        }
+
         return sd_bus_message_close_container(reply);
 }
 
@@ -696,6 +702,7 @@ int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error
                 return r;
 
         for (;;) {
+                ExecCleanMask m;
                 const char *i;
 
                 r = sd_bus_message_read(message, "s", &i);
@@ -704,17 +711,11 @@ int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error
                 if (r == 0)
                         break;
 
-                if (streq(i, "all"))
-                        mask |= EXEC_CLEAN_ALL;
-                else {
-                        ExecDirectoryType t;
-
-                        t = exec_resource_type_from_string(i);
-                        if (t < 0)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid resource type: %s", i);
+                m = exec_clean_mask_from_string(i);
+                if (m < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid resource type: %s", i);
 
-                        mask |= 1U << t;
-                }
+                mask |= m;
         }
 
         r = sd_bus_message_exit_container(message);
index 8b09794089ad9d10d597dff69b8203ef85bf1f7b..879f1345b0047b086e688c900b69f7c5845166f0 100644 (file)
@@ -7582,6 +7582,23 @@ void exec_directory_sort(ExecDirectory *d) {
                         }
 }
 
+ExecCleanMask exec_clean_mask_from_string(const char *s) {
+        ExecDirectoryType t;
+
+        assert(s);
+
+        if (streq(s, "all"))
+                return EXEC_CLEAN_ALL;
+        if (streq(s, "fdstore"))
+                return EXEC_CLEAN_FDSTORE;
+
+        t = exec_resource_type_from_string(s);
+        if (t < 0)
+                return (ExecCleanMask) t;
+
+        return 1U << t;
+}
+
 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_set_credential_hash_ops, char, string_hash_func, string_compare_func, ExecSetCredential, exec_set_credential_free);
 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_load_credential_hash_ops, char, string_hash_func, string_compare_func, ExecLoadCredential, exec_load_credential_free);
 
index 123fc1ec604dec47ff9943aa7ab9c3394545c704..d2f5507405818fcb430285a8adf29c45163ac6b3 100644 (file)
@@ -161,8 +161,9 @@ typedef enum ExecCleanMask {
         EXEC_CLEAN_CACHE         = 1U << EXEC_DIRECTORY_CACHE,
         EXEC_CLEAN_LOGS          = 1U << EXEC_DIRECTORY_LOGS,
         EXEC_CLEAN_CONFIGURATION = 1U << EXEC_DIRECTORY_CONFIGURATION,
+        EXEC_CLEAN_FDSTORE       = 1U << _EXEC_DIRECTORY_TYPE_MAX,
         EXEC_CLEAN_NONE          = 0,
-        EXEC_CLEAN_ALL           = (1U << _EXEC_DIRECTORY_TYPE_MAX) - 1,
+        EXEC_CLEAN_ALL           = (1U << (_EXEC_DIRECTORY_TYPE_MAX+1)) - 1,
         _EXEC_CLEAN_MASK_INVALID = -EINVAL,
 } ExecCleanMask;
 
@@ -520,6 +521,8 @@ void exec_directory_done(ExecDirectory *d);
 int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink);
 void exec_directory_sort(ExecDirectory *d);
 
+ExecCleanMask exec_clean_mask_from_string(const char *s);
+
 extern const struct hash_ops exec_set_credential_hash_ops;
 extern const struct hash_ops exec_load_credential_hash_ops;
 
index 7130cbf4e66edeea82b6e1b9417a7f618ff07581..dcd62fabdcd8d3737ce73c4e5efc04236f39826c 100644 (file)
@@ -4857,22 +4857,39 @@ static const char* service_status_text(Unit *u) {
 
 static int service_clean(Unit *u, ExecCleanMask mask) {
         _cleanup_strv_free_ char **l = NULL;
+        bool may_clean_fdstore = false;
         Service *s = SERVICE(u);
         int r;
 
         assert(s);
         assert(mask != 0);
 
-        if (s->state != SERVICE_DEAD)
+        if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_DEAD_RESOURCES_PINNED))
                 return -EBUSY;
 
+        /* Determine if there's anything we could potentially clean */
         r = exec_context_get_clean_directories(&s->exec_context, u->manager->prefix, mask, &l);
         if (r < 0)
                 return r;
 
-        if (strv_isempty(l))
-                return -EUNATCH;
+        if (mask & EXEC_CLEAN_FDSTORE)
+                may_clean_fdstore = s->n_fd_store > 0 || s->n_fd_store_max > 0;
+
+        if (strv_isempty(l) && !may_clean_fdstore)
+                return -EUNATCH; /* Nothing to potentially clean */
+
+        /* Let's clean the stuff we can clean quickly */
+        if (may_clean_fdstore)
+                service_release_fd_store(s);
+
+        /* If we are done, leave quickly */
+        if (strv_isempty(l)) {
+                if (s->state == SERVICE_DEAD_RESOURCES_PINNED && !s->fd_store)
+                        service_set_state(s, SERVICE_DEAD);
+                return 0;
+        }
 
+        /* We need to clean disk stuff. This is slow, hence do it out of process, and change state */
         service_unwatch_control_pid(s);
         s->clean_result = SERVICE_SUCCESS;
         s->control_command = NULL;
@@ -4899,10 +4916,21 @@ fail:
 
 static int service_can_clean(Unit *u, ExecCleanMask *ret) {
         Service *s = SERVICE(u);
+        ExecCleanMask mask = 0;
+        int r;
 
         assert(s);
+        assert(ret);
+
+        r = exec_context_get_clean_mask(&s->exec_context, &mask);
+        if (r < 0)
+                return r;
 
-        return exec_context_get_clean_mask(&s->exec_context, ret);
+        if (s->n_fd_store_max > 0)
+                mask |= EXEC_CLEAN_FDSTORE;
+
+        *ret = mask;
+        return 0;
 }
 
 static const char *service_finished_job(Unit *u, JobType t, JobResult result) {
index 371e42e0aa030014cdeaa6298032f9f49307ee6e..419416b3255af0847cd52de6030d6e23ec204c78 100644 (file)
@@ -884,6 +884,7 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
         Timer *t = TIMER(u);
 
         assert(t);
+        assert(ret);
 
         *ret = t->persistent ? EXEC_CLEAN_STATE : 0;
         return 0;
index 5c15a9fba0749b0b74c1de7c90fef07bc0730e86..40d5f6d557a7beb18ff7eaa78e786e14a907ba4f 100644 (file)
@@ -21,7 +21,7 @@ int verb_clean_or_freeze(int argc, char *argv[], void *userdata) {
         polkit_agent_open_maybe();
 
         if (!arg_clean_what) {
-                arg_clean_what = strv_new("cache", "runtime");
+                arg_clean_what = strv_new("cache", "runtime", "fdstore");
                 if (!arg_clean_what)
                         return log_oom();
         }
index df4cf684355d753e5ce2ecb6dc9dbcedbb211a14..21e09536a6b112f46daf3cb47c9056a7c41b1881 100644 (file)
@@ -937,7 +937,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                              "state\n"
                                              "cache\n"
                                              "logs\n"
-                                             "configuration");
+                                             "configuration\n"
+                                             "fdstore");
                                         return 0;
                                 }