]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #16603 from benzea/benzea/special-app-slice
authorLennart Poettering <lennart@poettering.net>
Wed, 11 Nov 2020 13:11:02 +0000 (14:11 +0100)
committerGitHub <noreply@github.com>
Wed, 11 Nov 2020 13:11:02 +0000 (14:11 +0100)
Use app.slice by default in user manager (and define special user slices)

12 files changed:
man/systemd.special.xml
src/basic/special.h
src/core/mount.c
src/core/swap.c
src/core/unit.c
src/core/unit.h
units/user/app.slice [new file with mode: 0644]
units/user/background.slice [new file with mode: 0644]
units/user/meson.build
units/user/session.slice [new file with mode: 0644]
units/user/systemd-exit.service
units/user/systemd-tmpfiles-clean.service

index d9439c23dedae7ac7df14ea6c43ed730e69fc2cc..a70e9ee0cae83b5b88fa64b921bfc1d03b377a7c 100644 (file)
         </varlistentry>
       </variablelist>
     </refsect2>
+
+    <refsect2>
+      <title>Special User Slice Units</title>
+
+      <para>There are four <literal>.slice</literal> units which form the basis of the user hierarchy for
+      assignment of resources for user applications and services. See
+      <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+      for details about slice units and the documentation about
+      <ulink url="https://systemd.io/DESKTOP_ENVIRONMENTS">Desktop Environments</ulink>
+      for further information.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><filename>-.slice</filename></term>
+          <listitem>
+            <para>The root slice is the root of the user's slice hierarchy.
+            It usually does not contain units directly, but may be used to set defaults for the whole tree.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><filename>app.slice</filename></term>
+          <listitem>
+            <para>By default, all user services and applications managed by
+            <command>systemd</command> are found in this slice.
+            All interactively launched applications like web browsers and text editors
+            as well as non-critical services should be placed into this slice.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><filename>session.slice</filename></term>
+          <listitem>
+            <para>All essential services and applications required for the
+            session should use this slice.
+            These are services that either cannot be restarted easily
+            or where latency issues may affect the interactivity of the system and applications.
+            This includes the display server, screen readers and other services such as DBus or XDG portals.
+            Such services should be configured to be part of this slice by
+            adding <varname>Slice=session.slice</varname> to their unit files.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><filename>background.slice</filename></term>
+          <listitem>
+            <para>All services running low-priority background tasks should use this slice.
+            This permits resources to be preferentially assigned to the other slices.
+            Examples include non-interactive tasks like file indexing or backup operations
+            where latency is not important.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index b602bb097cb4ba1d07b1d841379c27c5fb166120..d55b3289dee184ae97f9e4002e826706c53f6fc3 100644 (file)
 
 /* The root directory. */
 #define SPECIAL_ROOT_MOUNT "-.mount"
+
+/* Special slices valid for the user instance */
+#define SPECIAL_SESSION_SLICE "session.slice"
+#define SPECIAL_APP_SLICE "app.slice"
+#define SPECIAL_BACKGROUND_SLICE "background.slice"
index c96c137d297b754db3100bd05206547f16cd8925..41dc7e9967464ffbed12c11777f6d0b0c9f60730 100644 (file)
@@ -412,8 +412,9 @@ static int mount_add_quota_dependencies(Mount *m) {
         return 0;
 }
 
-static bool mount_is_extrinsic(Mount *m) {
+static bool mount_is_extrinsic(Unit *u) {
         MountParameters *p;
+        Mount *m = MOUNT(u);
         assert(m);
 
         /* Returns true for all units that are "magic" and should be excluded from the usual
@@ -422,10 +423,7 @@ static bool mount_is_extrinsic(Mount *m) {
          * ourselves but it's fine if the user operates on them with us. */
 
         /* We only automatically manage mounts if we are in system mode */
-        if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
-                return true;
-
-        if (UNIT(m)->perpetual) /* All perpetual units never change state */
+        if (MANAGER_IS_USER(u->manager))
                 return true;
 
         p = get_mount_parameters(m);
@@ -493,7 +491,7 @@ static int mount_add_default_dependencies(Mount *m) {
          * guaranteed to stay mounted the whole time, since our system is on it.  Also, don't
          * bother with anything mounted below virtual file systems, it's also going to be virtual,
          * and hence not worth the effort. */
-        if (mount_is_extrinsic(m))
+        if (mount_is_extrinsic(UNIT(m)))
                 return 0;
 
         p = get_mount_parameters(m);
@@ -790,7 +788,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, p ? strna(p->options) : "n/a",
                 prefix, yes_no(m->from_proc_self_mountinfo),
                 prefix, yes_no(m->from_fragment),
-                prefix, yes_no(mount_is_extrinsic(m)),
+                prefix, yes_no(mount_is_extrinsic(u)),
                 prefix, m->directory_mode,
                 prefix, yes_no(m->sloppy_options),
                 prefix, yes_no(m->lazy_unmount),
@@ -2161,6 +2159,7 @@ const UnitVTable mount_vtable = {
         .will_restart = unit_will_restart_default,
 
         .may_gc = mount_may_gc,
+        .is_extrinsic = mount_is_extrinsic,
 
         .sigchld_event = mount_sigchld_event,
 
index d984ac0f2d0626927139b35f080691c5a3e0d379..76e491ad94fb23935b25c00ffa3c25efec358000 100644 (file)
@@ -56,6 +56,35 @@ static bool SWAP_STATE_WITH_PROCESS(SwapState state) {
                       SWAP_CLEANING);
 }
 
+_pure_ static UnitActiveState swap_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[SWAP(u)->state];
+}
+
+_pure_ static const char *swap_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return swap_state_to_string(SWAP(u)->state);
+}
+
+_pure_ static bool swap_may_gc(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        if (s->from_proc_swaps)
+                return false;
+
+        return true;
+}
+
+_pure_ static bool swap_is_extrinsic(Unit *u) {
+        assert(SWAP(u));
+
+        return MANAGER_IS_USER(u->manager);
+}
+
 static void swap_unset_proc_swaps(Swap *s) {
         assert(s);
 
@@ -610,13 +639,15 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sClean Result: %s\n"
                 "%sWhat: %s\n"
                 "%sFrom /proc/swaps: %s\n"
-                "%sFrom fragment: %s\n",
+                "%sFrom fragment: %s\n"
+                "%sExtrinsic: %s\n",
                 prefix, swap_state_to_string(s->state),
                 prefix, swap_result_to_string(s->result),
                 prefix, swap_result_to_string(s->clean_result),
                 prefix, s->what,
                 prefix, yes_no(s->from_proc_swaps),
-                prefix, yes_no(s->from_fragment));
+                prefix, yes_no(s->from_fragment),
+                prefix, yes_no(swap_is_extrinsic(u)));
 
         if (s->devnode)
                 fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
@@ -1028,29 +1059,6 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
         return 0;
 }
 
-_pure_ static UnitActiveState swap_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[SWAP(u)->state];
-}
-
-_pure_ static const char *swap_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return swap_state_to_string(SWAP(u)->state);
-}
-
-_pure_ static bool swap_may_gc(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        if (s->from_proc_swaps)
-                return false;
-
-        return true;
-}
-
 static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         Swap *s = SWAP(u);
         SwapResult f;
@@ -1649,6 +1657,7 @@ const UnitVTable swap_vtable = {
         .will_restart = unit_will_restart_default,
 
         .may_gc = swap_may_gc,
+        .is_extrinsic = swap_is_extrinsic,
 
         .sigchld_event = swap_sigchld_event,
 
index 1d9691fb57d264823901d537be706f706a71f4fb..45a417a090690f09d5f78d9b74ed660d9f0e3e66 100644 (file)
@@ -1988,6 +1988,10 @@ int unit_stop(Unit *u) {
 bool unit_can_stop(Unit *u) {
         assert(u);
 
+        /* Note: if we return true here, it does not mean that the unit may be successfully stopped.
+         * Extrinsic units follow external state and they may stop following external state changes
+         * (hence we return true here), but an attempt to do this through the manager will fail. */
+
         if (!unit_type_supported(u->type))
                 return false;
 
@@ -3345,12 +3349,17 @@ int unit_set_default_slice(Unit *u) {
                 if (MANAGER_IS_SYSTEM(u->manager))
                         slice_name = strjoina("system-", escaped, ".slice");
                 else
-                        slice_name = strjoina(escaped, ".slice");
-        } else
-                slice_name =
-                        MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE)
-                        ? SPECIAL_SYSTEM_SLICE
-                        : SPECIAL_ROOT_SLICE;
+                        slice_name = strjoina("app-", escaped, ".slice");
+
+        } else if (unit_is_extrinsic(u))
+                /* Keep all extrinsic units (e.g. perpetual units and swap and mount units in user mode) in
+                 * the root slice. They don't really belong in one of the subslices. */
+                slice_name = SPECIAL_ROOT_SLICE;
+
+        else if (MANAGER_IS_SYSTEM(u->manager))
+                slice_name = SPECIAL_SYSTEM_SLICE;
+        else
+                slice_name = SPECIAL_APP_SLICE;
 
         r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
         if (r < 0)
index 8cb713572310af426043e1d123c448d8966dbd03..02b2b24206f393bbcd476b958c301a487c7e856c 100644 (file)
@@ -531,6 +531,9 @@ typedef struct UnitVTable {
          * even though nothing references it and it isn't active in any way. */
         bool (*may_gc)(Unit *u);
 
+        /* Return true when the unit is not controlled by the manager (e.g. extrinsic mounts). */
+        bool (*is_extrinsic)(Unit *u);
+
         /* When the unit is not running and no job for it queued we shall release its runtime resources */
         void (*release_resources)(Unit *u);
 
@@ -684,6 +687,11 @@ int unit_set_description(Unit *u, const char *description);
 
 bool unit_may_gc(Unit *u);
 
+static inline bool unit_is_extrinsic(Unit *u) {
+        return u->perpetual ||
+                (UNIT_VTABLE(u)->is_extrinsic && UNIT_VTABLE(u)->is_extrinsic(u));
+}
+
 void unit_add_to_load_queue(Unit *u);
 void unit_add_to_dbus_queue(Unit *u);
 void unit_add_to_cleanup_queue(Unit *u);
diff --git a/units/user/app.slice b/units/user/app.slice
new file mode 100644 (file)
index 0000000..065ea77
--- /dev/null
@@ -0,0 +1,12 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=User Application Slice
+Documentation=man:systemd.special(7)
diff --git a/units/user/background.slice b/units/user/background.slice
new file mode 100644 (file)
index 0000000..03c89b6
--- /dev/null
@@ -0,0 +1,12 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=User Background Tasks Slice
+Documentation=man:systemd.special(7)
index b2a599b6d8aa76cea4b6775d360c99850bda0446..337a92092dbed68be398822feeef0abb31cc2594 100644 (file)
@@ -1,6 +1,8 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 units = [
+        'app.slice',
+        'background.slice',
         'basic.target',
         'bluetooth.target',
         'default.target',
@@ -9,6 +11,7 @@ units = [
         'graphical-session.target',
         'paths.target',
         'printer.target',
+        'session.slice',
         'shutdown.target',
         'smartcard.target',
         'sockets.target',
diff --git a/units/user/session.slice b/units/user/session.slice
new file mode 100644 (file)
index 0000000..e0b38c5
--- /dev/null
@@ -0,0 +1,12 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=User Core Session Slice
+Documentation=man:systemd.special(7)
index 91953e0524d2b97ec88fc26e95ede8ff0aed8b0e..18725253bb37a6b35b38b5988fb452cd59906a4b 100644 (file)
@@ -14,3 +14,7 @@ DefaultDependencies=no
 Requires=shutdown.target
 After=shutdown.target
 SuccessAction=exit-force
+
+[Service]
+# Place into the root slice to not keep another slice unit alive
+Slice=-.slice
index ff319d2b3a9b4c113bb89f27abe0f2b04eb0d1e5..6a937071f762dbc04bb0f57215aa6740fb9d500b 100644 (file)
@@ -19,3 +19,4 @@ Type=oneshot
 ExecStart=systemd-tmpfiles --user --clean
 SuccessExitStatus=DATAERR
 IOSchedulingClass=idle
+Slice=background.slice