LCOV - code coverage report
Current view: top level - core - slice.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 114 186 61.3 %
Date: 2019-08-23 13:36:53 Functions: 13 19 68.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 65 178 36.5 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : 
       5                 :            : #include "alloc-util.h"
       6                 :            : #include "dbus-slice.h"
       7                 :            : #include "dbus-unit.h"
       8                 :            : #include "log.h"
       9                 :            : #include "serialize.h"
      10                 :            : #include "slice.h"
      11                 :            : #include "special.h"
      12                 :            : #include "string-util.h"
      13                 :            : #include "strv.h"
      14                 :            : #include "unit-name.h"
      15                 :            : #include "unit.h"
      16                 :            : 
      17                 :            : static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
      18                 :            :         [SLICE_DEAD] = UNIT_INACTIVE,
      19                 :            :         [SLICE_ACTIVE] = UNIT_ACTIVE
      20                 :            : };
      21                 :            : 
      22                 :         76 : static void slice_init(Unit *u) {
      23         [ -  + ]:         76 :         assert(u);
      24         [ -  + ]:         76 :         assert(u->load_state == UNIT_STUB);
      25                 :            : 
      26                 :         76 :         u->ignore_on_isolate = true;
      27                 :         76 : }
      28                 :            : 
      29                 :         44 : static void slice_set_state(Slice *t, SliceState state) {
      30                 :            :         SliceState old_state;
      31         [ -  + ]:         44 :         assert(t);
      32                 :            : 
      33         [ +  - ]:         44 :         if (t->state != state)
      34         [ +  - ]:         44 :                 bus_unit_send_pending_change_signal(UNIT(t), false);
      35                 :            : 
      36                 :         44 :         old_state = t->state;
      37                 :         44 :         t->state = state;
      38                 :            : 
      39         [ +  - ]:         44 :         if (state != old_state)
      40   [ +  +  +  - ]:         44 :                 log_debug("%s changed %s -> %s",
      41                 :            :                           UNIT(t)->id,
      42                 :            :                           slice_state_to_string(old_state),
      43                 :            :                           slice_state_to_string(state));
      44                 :            : 
      45         [ +  - ]:         44 :         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
      46                 :         44 : }
      47                 :            : 
      48                 :         72 : static int slice_add_parent_slice(Slice *s) {
      49         [ +  - ]:         72 :         Unit *u = UNIT(s), *parent;
      50                 :         72 :         _cleanup_free_ char *a = NULL;
      51                 :            :         int r;
      52                 :            : 
      53         [ -  + ]:         72 :         assert(s);
      54                 :            : 
      55         [ -  + ]:         72 :         if (UNIT_ISSET(u->slice))
      56                 :          0 :                 return 0;
      57                 :            : 
      58                 :         72 :         r = slice_build_parent_slice(u->id, &a);
      59         [ +  + ]:         72 :         if (r <= 0) /* 0 means root slice */
      60                 :         44 :                 return r;
      61                 :            : 
      62                 :         28 :         r = manager_load_unit(u->manager, a, NULL, NULL, &parent);
      63         [ -  + ]:         28 :         if (r < 0)
      64                 :          0 :                 return r;
      65                 :            : 
      66                 :         28 :         unit_ref_set(&u->slice, u, parent);
      67                 :         28 :         return 0;
      68                 :            : }
      69                 :            : 
      70                 :         72 : static int slice_add_default_dependencies(Slice *s) {
      71                 :            :         int r;
      72                 :            : 
      73         [ -  + ]:         72 :         assert(s);
      74                 :            : 
      75   [ +  -  +  + ]:         72 :         if (!UNIT(s)->default_dependencies)
      76                 :         44 :                 return 0;
      77                 :            : 
      78                 :            :         /* Make sure slices are unloaded on shutdown */
      79                 :         28 :         r = unit_add_two_dependencies_by_name(
      80         [ +  - ]:         28 :                         UNIT(s),
      81                 :            :                         UNIT_BEFORE, UNIT_CONFLICTS,
      82                 :            :                         SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
      83         [ -  + ]:         28 :         if (r < 0)
      84                 :          0 :                 return r;
      85                 :            : 
      86                 :         28 :         return 0;
      87                 :            : }
      88                 :            : 
      89                 :         72 : static int slice_verify(Slice *s) {
      90                 :         72 :         _cleanup_free_ char *parent = NULL;
      91                 :            :         int r;
      92                 :            : 
      93         [ -  + ]:         72 :         assert(s);
      94                 :            : 
      95   [ +  -  -  + ]:         72 :         if (UNIT(s)->load_state != UNIT_LOADED)
      96                 :          0 :                 return 0;
      97                 :            : 
      98   [ +  -  -  + ]:         72 :         if (!slice_name_is_valid(UNIT(s)->id)) {
      99   [ #  #  #  #  :          0 :                 log_unit_error(UNIT(s), "Slice name %s is not valid. Refusing.", UNIT(s)->id);
             #  #  #  # ]
     100                 :          0 :                 return -ENOEXEC;
     101                 :            :         }
     102                 :            : 
     103         [ +  - ]:         72 :         r = slice_build_parent_slice(UNIT(s)->id, &parent);
     104         [ -  + ]:         72 :         if (r < 0)
     105   [ #  #  #  # ]:          0 :                 return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m");
     106                 :            : 
     107   [ +  +  +  -  :         72 :         if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) {
             +  -  -  + ]
     108   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(s), "Located outside of parent slice. Refusing.");
     109                 :          0 :                 return -ENOEXEC;
     110                 :            :         }
     111                 :            : 
     112                 :         72 :         return 0;
     113                 :            : }
     114                 :            : 
     115                 :         72 : static int slice_load_root_slice(Unit *u) {
     116         [ -  + ]:         72 :         assert(u);
     117                 :            : 
     118         [ +  + ]:         72 :         if (!unit_has_name(u, SPECIAL_ROOT_SLICE))
     119                 :         28 :                 return 0;
     120                 :            : 
     121                 :         44 :         u->perpetual = true;
     122                 :            : 
     123                 :            :         /* The root slice is a bit special. For example it is always running and cannot be terminated. Because of its
     124                 :            :          * special semantics we synthesize it here, instead of relying on the unit file on disk. */
     125                 :            : 
     126                 :         44 :         u->default_dependencies = false;
     127                 :            : 
     128         [ +  - ]:         44 :         if (!u->description)
     129                 :         44 :                 u->description = strdup("Root Slice");
     130         [ +  - ]:         44 :         if (!u->documentation)
     131                 :         44 :                 u->documentation = strv_new("man:systemd.special(7)");
     132                 :            : 
     133                 :         44 :         return 1;
     134                 :            : }
     135                 :            : 
     136                 :         72 : static int slice_load_system_slice(Unit *u) {
     137         [ -  + ]:         72 :         assert(u);
     138                 :            : 
     139         [ +  - ]:         72 :         if (!MANAGER_IS_SYSTEM(u->manager))
     140                 :         72 :                 return 0;
     141         [ #  # ]:          0 :         if (!unit_has_name(u, SPECIAL_SYSTEM_SLICE))
     142                 :          0 :                 return 0;
     143                 :            : 
     144                 :          0 :         u->perpetual = true;
     145                 :            : 
     146                 :            :         /* The system slice is a bit special. For example it is always running and cannot be terminated. Because of its
     147                 :            :          * special semantics we synthesize it here, instead of relying on the unit file on disk. */
     148                 :            : 
     149                 :          0 :         u->default_dependencies = false;
     150                 :            : 
     151         [ #  # ]:          0 :         if (!u->description)
     152                 :          0 :                 u->description = strdup("System Slice");
     153         [ #  # ]:          0 :         if (!u->documentation)
     154                 :          0 :                 u->documentation = strv_new("man:systemd.special(7)");
     155                 :            : 
     156                 :          0 :         return 1;
     157                 :            : }
     158                 :            : 
     159                 :         72 : static int slice_load(Unit *u) {
     160                 :         72 :         Slice *s = SLICE(u);
     161                 :            :         int r;
     162                 :            : 
     163         [ -  + ]:         72 :         assert(s);
     164         [ -  + ]:         72 :         assert(u->load_state == UNIT_STUB);
     165                 :            : 
     166                 :         72 :         r = slice_load_root_slice(u);
     167         [ -  + ]:         72 :         if (r < 0)
     168                 :          0 :                 return r;
     169                 :         72 :         r = slice_load_system_slice(u);
     170         [ -  + ]:         72 :         if (r < 0)
     171                 :          0 :                 return r;
     172                 :            : 
     173                 :         72 :         r = unit_load_fragment_and_dropin_optional(u);
     174         [ -  + ]:         72 :         if (r < 0)
     175                 :          0 :                 return r;
     176                 :            : 
     177                 :            :         /* This is a new unit? Then let's add in some extras */
     178         [ +  - ]:         72 :         if (u->load_state == UNIT_LOADED) {
     179                 :            : 
     180                 :         72 :                 r = unit_patch_contexts(u);
     181         [ -  + ]:         72 :                 if (r < 0)
     182                 :          0 :                         return r;
     183                 :            : 
     184                 :         72 :                 r = slice_add_parent_slice(s);
     185         [ -  + ]:         72 :                 if (r < 0)
     186                 :          0 :                         return r;
     187                 :            : 
     188                 :         72 :                 r = slice_add_default_dependencies(s);
     189         [ -  + ]:         72 :                 if (r < 0)
     190                 :          0 :                         return r;
     191                 :            :         }
     192                 :            : 
     193                 :         72 :         return slice_verify(s);
     194                 :            : }
     195                 :            : 
     196                 :         44 : static int slice_coldplug(Unit *u) {
     197                 :         44 :         Slice *t = SLICE(u);
     198                 :            : 
     199         [ -  + ]:         44 :         assert(t);
     200         [ -  + ]:         44 :         assert(t->state == SLICE_DEAD);
     201                 :            : 
     202         [ +  - ]:         44 :         if (t->deserialized_state != t->state)
     203                 :         44 :                 slice_set_state(t, t->deserialized_state);
     204                 :            : 
     205                 :         44 :         return 0;
     206                 :            : }
     207                 :            : 
     208                 :         24 : static void slice_dump(Unit *u, FILE *f, const char *prefix) {
     209                 :         24 :         Slice *t = SLICE(u);
     210                 :            : 
     211         [ -  + ]:         24 :         assert(t);
     212         [ -  + ]:         24 :         assert(f);
     213                 :            : 
     214                 :         24 :         fprintf(f,
     215                 :            :                 "%sSlice State: %s\n",
     216                 :            :                 prefix, slice_state_to_string(t->state));
     217                 :            : 
     218                 :         24 :         cgroup_context_dump(&t->cgroup_context, f, prefix);
     219                 :         24 : }
     220                 :            : 
     221                 :          0 : static int slice_start(Unit *u) {
     222                 :          0 :         Slice *t = SLICE(u);
     223                 :            :         int r;
     224                 :            : 
     225         [ #  # ]:          0 :         assert(t);
     226         [ #  # ]:          0 :         assert(t->state == SLICE_DEAD);
     227                 :            : 
     228                 :          0 :         r = unit_acquire_invocation_id(u);
     229         [ #  # ]:          0 :         if (r < 0)
     230                 :          0 :                 return r;
     231                 :            : 
     232                 :          0 :         (void) unit_realize_cgroup(u);
     233                 :          0 :         (void) unit_reset_accounting(u);
     234                 :            : 
     235                 :          0 :         slice_set_state(t, SLICE_ACTIVE);
     236                 :          0 :         return 1;
     237                 :            : }
     238                 :            : 
     239                 :          0 : static int slice_stop(Unit *u) {
     240                 :          0 :         Slice *t = SLICE(u);
     241                 :            : 
     242         [ #  # ]:          0 :         assert(t);
     243         [ #  # ]:          0 :         assert(t->state == SLICE_ACTIVE);
     244                 :            : 
     245                 :            :         /* We do not need to destroy the cgroup explicitly,
     246                 :            :          * unit_notify() will do that for us anyway. */
     247                 :            : 
     248                 :          0 :         slice_set_state(t, SLICE_DEAD);
     249                 :          0 :         return 1;
     250                 :            : }
     251                 :            : 
     252                 :          0 : static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
     253                 :          0 :         return unit_kill_common(u, who, signo, -1, -1, error);
     254                 :            : }
     255                 :            : 
     256                 :          0 : static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
     257                 :          0 :         Slice *s = SLICE(u);
     258                 :            : 
     259         [ #  # ]:          0 :         assert(s);
     260         [ #  # ]:          0 :         assert(f);
     261         [ #  # ]:          0 :         assert(fds);
     262                 :            : 
     263                 :          0 :         (void) serialize_item(f, "state", slice_state_to_string(s->state));
     264                 :            : 
     265                 :          0 :         return 0;
     266                 :            : }
     267                 :            : 
     268                 :          0 : static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
     269                 :          0 :         Slice *s = SLICE(u);
     270                 :            : 
     271         [ #  # ]:          0 :         assert(u);
     272         [ #  # ]:          0 :         assert(key);
     273         [ #  # ]:          0 :         assert(value);
     274         [ #  # ]:          0 :         assert(fds);
     275                 :            : 
     276         [ #  # ]:          0 :         if (streq(key, "state")) {
     277                 :            :                 SliceState state;
     278                 :            : 
     279                 :          0 :                 state = slice_state_from_string(value);
     280         [ #  # ]:          0 :                 if (state < 0)
     281         [ #  # ]:          0 :                         log_debug("Failed to parse state value %s", value);
     282                 :            :                 else
     283                 :          0 :                         s->deserialized_state = state;
     284                 :            : 
     285                 :            :         } else
     286         [ #  # ]:          0 :                 log_debug("Unknown serialization key '%s'", key);
     287                 :            : 
     288                 :          0 :         return 0;
     289                 :            : }
     290                 :            : 
     291                 :       2956 : _pure_ static UnitActiveState slice_active_state(Unit *u) {
     292         [ -  + ]:       2956 :         assert(u);
     293                 :            : 
     294                 :       2956 :         return state_translation_table[SLICE(u)->state];
     295                 :            : }
     296                 :            : 
     297                 :          0 : _pure_ static const char *slice_sub_state_to_string(Unit *u) {
     298         [ #  # ]:          0 :         assert(u);
     299                 :            : 
     300                 :          0 :         return slice_state_to_string(SLICE(u)->state);
     301                 :            : }
     302                 :            : 
     303                 :         44 : static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) {
     304                 :            :         Unit *u;
     305                 :            :         int r;
     306                 :            : 
     307         [ -  + ]:         44 :         assert(m);
     308         [ -  + ]:         44 :         assert(name);
     309                 :            : 
     310                 :         44 :         u = manager_get_unit(m, name);
     311         [ +  - ]:         44 :         if (!u) {
     312                 :         44 :                 r = unit_new_for_name(m, sizeof(Slice), name, &u);
     313         [ -  + ]:         44 :                 if (r < 0)
     314         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to allocate the special %s unit: %m", name);
     315                 :            :         }
     316                 :            : 
     317                 :         44 :         u->perpetual = true;
     318                 :         44 :         SLICE(u)->deserialized_state = SLICE_ACTIVE;
     319                 :            : 
     320                 :         44 :         unit_add_to_load_queue(u);
     321                 :         44 :         unit_add_to_dbus_queue(u);
     322                 :            : 
     323         [ +  - ]:         44 :         if (ret)
     324                 :         44 :                 *ret = u;
     325                 :            : 
     326                 :         44 :         return 0;
     327                 :            : }
     328                 :            : 
     329                 :         44 : static void slice_enumerate_perpetual(Manager *m) {
     330                 :            :         Unit *u;
     331                 :            :         int r;
     332                 :            : 
     333         [ -  + ]:         44 :         assert(m);
     334                 :            : 
     335                 :         44 :         r = slice_make_perpetual(m, SPECIAL_ROOT_SLICE, &u);
     336   [ +  -  -  + ]:         44 :         if (r >= 0 && manager_owns_host_root_cgroup(m)) {
     337                 :          0 :                 Slice *s = SLICE(u);
     338                 :            : 
     339                 :            :                 /* If we are managing the root cgroup then this means our root slice covers the whole system, which
     340                 :            :                  * means the kernel will track CPU/tasks/memory for us anyway, and it is all available in /proc. Let's
     341                 :            :                  * hence turn accounting on here, so that our APIs to query this data are available. */
     342                 :            : 
     343                 :          0 :                 s->cgroup_context.cpu_accounting = true;
     344                 :          0 :                 s->cgroup_context.tasks_accounting = true;
     345                 :          0 :                 s->cgroup_context.memory_accounting = true;
     346                 :            :         }
     347                 :            : 
     348         [ -  + ]:         44 :         if (MANAGER_IS_SYSTEM(m))
     349                 :          0 :                 (void) slice_make_perpetual(m, SPECIAL_SYSTEM_SLICE, NULL);
     350                 :         44 : }
     351                 :            : 
     352                 :            : const UnitVTable slice_vtable = {
     353                 :            :         .object_size = sizeof(Slice),
     354                 :            :         .cgroup_context_offset = offsetof(Slice, cgroup_context),
     355                 :            : 
     356                 :            :         .sections =
     357                 :            :                 "Unit\0"
     358                 :            :                 "Slice\0"
     359                 :            :                 "Install\0",
     360                 :            :         .private_section = "Slice",
     361                 :            : 
     362                 :            :         .can_transient = true,
     363                 :            : 
     364                 :            :         .init = slice_init,
     365                 :            :         .load = slice_load,
     366                 :            : 
     367                 :            :         .coldplug = slice_coldplug,
     368                 :            : 
     369                 :            :         .dump = slice_dump,
     370                 :            : 
     371                 :            :         .start = slice_start,
     372                 :            :         .stop = slice_stop,
     373                 :            : 
     374                 :            :         .kill = slice_kill,
     375                 :            : 
     376                 :            :         .serialize = slice_serialize,
     377                 :            :         .deserialize_item = slice_deserialize_item,
     378                 :            : 
     379                 :            :         .active_state = slice_active_state,
     380                 :            :         .sub_state_to_string = slice_sub_state_to_string,
     381                 :            : 
     382                 :            :         .bus_vtable = bus_slice_vtable,
     383                 :            :         .bus_set_property = bus_slice_set_property,
     384                 :            :         .bus_commit_properties = bus_slice_commit_properties,
     385                 :            : 
     386                 :            :         .enumerate_perpetual = slice_enumerate_perpetual,
     387                 :            : 
     388                 :            :         .status_message_formats = {
     389                 :            :                 .finished_start_job = {
     390                 :            :                         [JOB_DONE]       = "Created slice %s.",
     391                 :            :                 },
     392                 :            :                 .finished_stop_job = {
     393                 :            :                         [JOB_DONE]       = "Removed slice %s.",
     394                 :            :                 },
     395                 :            :         },
     396                 :            : };

Generated by: LCOV version 1.14