LCOV - code coverage report
Current view: top level - core - slice.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 114 186 61.3 %
Date: 2019-08-22 15:41:25 Functions: 13 19 68.4 %

          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          19 : static void slice_init(Unit *u) {
      23          19 :         assert(u);
      24          19 :         assert(u->load_state == UNIT_STUB);
      25             : 
      26          19 :         u->ignore_on_isolate = true;
      27          19 : }
      28             : 
      29          11 : static void slice_set_state(Slice *t, SliceState state) {
      30             :         SliceState old_state;
      31          11 :         assert(t);
      32             : 
      33          11 :         if (t->state != state)
      34          11 :                 bus_unit_send_pending_change_signal(UNIT(t), false);
      35             : 
      36          11 :         old_state = t->state;
      37          11 :         t->state = state;
      38             : 
      39          11 :         if (state != old_state)
      40          11 :                 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          11 :         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
      46          11 : }
      47             : 
      48          18 : static int slice_add_parent_slice(Slice *s) {
      49          18 :         Unit *u = UNIT(s), *parent;
      50          18 :         _cleanup_free_ char *a = NULL;
      51             :         int r;
      52             : 
      53          18 :         assert(s);
      54             : 
      55          18 :         if (UNIT_ISSET(u->slice))
      56           0 :                 return 0;
      57             : 
      58          18 :         r = slice_build_parent_slice(u->id, &a);
      59          18 :         if (r <= 0) /* 0 means root slice */
      60          11 :                 return r;
      61             : 
      62           7 :         r = manager_load_unit(u->manager, a, NULL, NULL, &parent);
      63           7 :         if (r < 0)
      64           0 :                 return r;
      65             : 
      66           7 :         unit_ref_set(&u->slice, u, parent);
      67           7 :         return 0;
      68             : }
      69             : 
      70          18 : static int slice_add_default_dependencies(Slice *s) {
      71             :         int r;
      72             : 
      73          18 :         assert(s);
      74             : 
      75          18 :         if (!UNIT(s)->default_dependencies)
      76          11 :                 return 0;
      77             : 
      78             :         /* Make sure slices are unloaded on shutdown */
      79           7 :         r = unit_add_two_dependencies_by_name(
      80           7 :                         UNIT(s),
      81             :                         UNIT_BEFORE, UNIT_CONFLICTS,
      82             :                         SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
      83           7 :         if (r < 0)
      84           0 :                 return r;
      85             : 
      86           7 :         return 0;
      87             : }
      88             : 
      89          18 : static int slice_verify(Slice *s) {
      90          18 :         _cleanup_free_ char *parent = NULL;
      91             :         int r;
      92             : 
      93          18 :         assert(s);
      94             : 
      95          18 :         if (UNIT(s)->load_state != UNIT_LOADED)
      96           0 :                 return 0;
      97             : 
      98          18 :         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          18 :         r = slice_build_parent_slice(UNIT(s)->id, &parent);
     104          18 :         if (r < 0)
     105           0 :                 return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m");
     106             : 
     107          18 :         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          18 :         return 0;
     113             : }
     114             : 
     115          18 : static int slice_load_root_slice(Unit *u) {
     116          18 :         assert(u);
     117             : 
     118          18 :         if (!unit_has_name(u, SPECIAL_ROOT_SLICE))
     119           7 :                 return 0;
     120             : 
     121          11 :         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          11 :         u->default_dependencies = false;
     127             : 
     128          11 :         if (!u->description)
     129          11 :                 u->description = strdup("Root Slice");
     130          11 :         if (!u->documentation)
     131          11 :                 u->documentation = strv_new("man:systemd.special(7)");
     132             : 
     133          11 :         return 1;
     134             : }
     135             : 
     136          18 : static int slice_load_system_slice(Unit *u) {
     137          18 :         assert(u);
     138             : 
     139          18 :         if (!MANAGER_IS_SYSTEM(u->manager))
     140          18 :                 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          18 : static int slice_load(Unit *u) {
     160          18 :         Slice *s = SLICE(u);
     161             :         int r;
     162             : 
     163          18 :         assert(s);
     164          18 :         assert(u->load_state == UNIT_STUB);
     165             : 
     166          18 :         r = slice_load_root_slice(u);
     167          18 :         if (r < 0)
     168           0 :                 return r;
     169          18 :         r = slice_load_system_slice(u);
     170          18 :         if (r < 0)
     171           0 :                 return r;
     172             : 
     173          18 :         r = unit_load_fragment_and_dropin_optional(u);
     174          18 :         if (r < 0)
     175           0 :                 return r;
     176             : 
     177             :         /* This is a new unit? Then let's add in some extras */
     178          18 :         if (u->load_state == UNIT_LOADED) {
     179             : 
     180          18 :                 r = unit_patch_contexts(u);
     181          18 :                 if (r < 0)
     182           0 :                         return r;
     183             : 
     184          18 :                 r = slice_add_parent_slice(s);
     185          18 :                 if (r < 0)
     186           0 :                         return r;
     187             : 
     188          18 :                 r = slice_add_default_dependencies(s);
     189          18 :                 if (r < 0)
     190           0 :                         return r;
     191             :         }
     192             : 
     193          18 :         return slice_verify(s);
     194             : }
     195             : 
     196          11 : static int slice_coldplug(Unit *u) {
     197          11 :         Slice *t = SLICE(u);
     198             : 
     199          11 :         assert(t);
     200          11 :         assert(t->state == SLICE_DEAD);
     201             : 
     202          11 :         if (t->deserialized_state != t->state)
     203          11 :                 slice_set_state(t, t->deserialized_state);
     204             : 
     205          11 :         return 0;
     206             : }
     207             : 
     208           6 : static void slice_dump(Unit *u, FILE *f, const char *prefix) {
     209           6 :         Slice *t = SLICE(u);
     210             : 
     211           6 :         assert(t);
     212           6 :         assert(f);
     213             : 
     214           6 :         fprintf(f,
     215             :                 "%sSlice State: %s\n",
     216             :                 prefix, slice_state_to_string(t->state));
     217             : 
     218           6 :         cgroup_context_dump(&t->cgroup_context, f, prefix);
     219           6 : }
     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         880 : _pure_ static UnitActiveState slice_active_state(Unit *u) {
     292         880 :         assert(u);
     293             : 
     294         880 :         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          11 : static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) {
     304             :         Unit *u;
     305             :         int r;
     306             : 
     307          11 :         assert(m);
     308          11 :         assert(name);
     309             : 
     310          11 :         u = manager_get_unit(m, name);
     311          11 :         if (!u) {
     312          11 :                 r = unit_new_for_name(m, sizeof(Slice), name, &u);
     313          11 :                 if (r < 0)
     314           0 :                         return log_error_errno(r, "Failed to allocate the special %s unit: %m", name);
     315             :         }
     316             : 
     317          11 :         u->perpetual = true;
     318          11 :         SLICE(u)->deserialized_state = SLICE_ACTIVE;
     319             : 
     320          11 :         unit_add_to_load_queue(u);
     321          11 :         unit_add_to_dbus_queue(u);
     322             : 
     323          11 :         if (ret)
     324          11 :                 *ret = u;
     325             : 
     326          11 :         return 0;
     327             : }
     328             : 
     329          11 : static void slice_enumerate_perpetual(Manager *m) {
     330             :         Unit *u;
     331             :         int r;
     332             : 
     333          11 :         assert(m);
     334             : 
     335          11 :         r = slice_make_perpetual(m, SPECIAL_ROOT_SLICE, &u);
     336          11 :         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          11 :         if (MANAGER_IS_SYSTEM(m))
     349           0 :                 (void) slice_make_perpetual(m, SPECIAL_SYSTEM_SLICE, NULL);
     350          11 : }
     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