]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/slice.c
core: add global settings for enabling CPUAccounting=, MemoryAccounting=, BlockIOAcco...
[thirdparty/systemd.git] / src / core / slice.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <signal.h>
24 #include <unistd.h>
25
26 #include "unit.h"
27 #include "slice.h"
28 #include "load-fragment.h"
29 #include "log.h"
30 #include "dbus-slice.h"
31 #include "special.h"
32 #include "unit-name.h"
33
34 static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
35 [SLICE_DEAD] = UNIT_INACTIVE,
36 [SLICE_ACTIVE] = UNIT_ACTIVE
37 };
38
39 static void slice_init(Unit *u) {
40 Slice *s = SLICE(u);
41
42 assert(u);
43 assert(u->load_state == UNIT_STUB);
44
45 cgroup_context_init(&s->cgroup_context);
46 unit_cgroup_context_init_defaults(u, &s->cgroup_context);
47 }
48
49 static void slice_done(Unit *u) {
50 Slice *s = SLICE(u);
51
52 assert(u);
53
54 cgroup_context_done(&s->cgroup_context);
55 }
56
57 static void slice_set_state(Slice *t, SliceState state) {
58 SliceState old_state;
59 assert(t);
60
61 old_state = t->state;
62 t->state = state;
63
64 if (state != old_state)
65 log_debug("%s changed %s -> %s",
66 UNIT(t)->id,
67 slice_state_to_string(old_state),
68 slice_state_to_string(state));
69
70 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
71 }
72
73 static int slice_add_parent_slice(Slice *s) {
74 char *a, *dash;
75 Unit *parent;
76 int r;
77
78 assert(s);
79
80 if (UNIT_ISSET(UNIT(s)->slice))
81 return 0;
82
83 if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE))
84 return 0;
85
86 a = strdupa(UNIT(s)->id);
87 dash = strrchr(a, '-');
88 if (dash)
89 strcpy(dash, ".slice");
90 else
91 a = (char*) SPECIAL_ROOT_SLICE;
92
93 r = manager_load_unit(UNIT(s)->manager, a, NULL, NULL, &parent);
94 if (r < 0)
95 return r;
96
97 unit_ref_set(&UNIT(s)->slice, parent);
98 return 0;
99 }
100
101 static int slice_add_default_dependencies(Slice *s) {
102 int r;
103
104 assert(s);
105
106 /* Make sure slices are unloaded on shutdown */
107 r = unit_add_two_dependencies_by_name(
108 UNIT(s),
109 UNIT_BEFORE, UNIT_CONFLICTS,
110 SPECIAL_SHUTDOWN_TARGET, NULL, true);
111 if (r < 0)
112 return r;
113
114 return 0;
115 }
116
117 static int slice_verify(Slice *s) {
118 assert(s);
119
120 if (UNIT(s)->load_state != UNIT_LOADED)
121 return 0;
122
123 if (UNIT_DEREF(UNIT(s)->slice)) {
124 char *a, *dash;
125
126 a = strdupa(UNIT(s)->id);
127 dash = strrchr(a, '-');
128 if (dash)
129 strcpy(dash, ".slice");
130 else
131 a = (char*) SPECIAL_ROOT_SLICE;
132
133 if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
134 log_error_unit(UNIT(s)->id,
135 "%s located outside its parent slice. Refusing.", UNIT(s)->id);
136 return -EINVAL;
137 }
138 }
139
140 return 0;
141 }
142
143 static int slice_load(Unit *u) {
144 Slice *s = SLICE(u);
145 int r;
146
147 assert(s);
148
149 r = unit_load_fragment_and_dropin_optional(u);
150 if (r < 0)
151 return r;
152
153 /* This is a new unit? Then let's add in some extras */
154 if (u->load_state == UNIT_LOADED) {
155
156 r = slice_add_parent_slice(s);
157 if (r < 0)
158 return r;
159
160 if (u->default_dependencies) {
161 r = slice_add_default_dependencies(s);
162 if (r < 0)
163 return r;
164 }
165 }
166
167 return slice_verify(s);
168 }
169
170 static int slice_coldplug(Unit *u) {
171 Slice *t = SLICE(u);
172
173 assert(t);
174 assert(t->state == SLICE_DEAD);
175
176 if (t->deserialized_state != t->state)
177 slice_set_state(t, t->deserialized_state);
178
179 return 0;
180 }
181
182 static void slice_dump(Unit *u, FILE *f, const char *prefix) {
183 Slice *t = SLICE(u);
184
185 assert(t);
186 assert(f);
187
188 fprintf(f,
189 "%sSlice State: %s\n",
190 prefix, slice_state_to_string(t->state));
191
192 cgroup_context_dump(&t->cgroup_context, f, prefix);
193 }
194
195 static int slice_start(Unit *u) {
196 Slice *t = SLICE(u);
197
198 assert(t);
199 assert(t->state == SLICE_DEAD);
200
201 unit_realize_cgroup(u);
202
203 slice_set_state(t, SLICE_ACTIVE);
204 return 0;
205 }
206
207 static int slice_stop(Unit *u) {
208 Slice *t = SLICE(u);
209
210 assert(t);
211 assert(t->state == SLICE_ACTIVE);
212
213 /* We do not need to destroy the cgroup explicitly,
214 * unit_notify() will do that for us anyway. */
215
216 slice_set_state(t, SLICE_DEAD);
217 return 0;
218 }
219
220 static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
221 return unit_kill_common(u, who, signo, -1, -1, error);
222 }
223
224 static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
225 Slice *s = SLICE(u);
226
227 assert(s);
228 assert(f);
229 assert(fds);
230
231 unit_serialize_item(u, f, "state", slice_state_to_string(s->state));
232 return 0;
233 }
234
235 static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
236 Slice *s = SLICE(u);
237
238 assert(u);
239 assert(key);
240 assert(value);
241 assert(fds);
242
243 if (streq(key, "state")) {
244 SliceState state;
245
246 state = slice_state_from_string(value);
247 if (state < 0)
248 log_debug("Failed to parse state value %s", value);
249 else
250 s->deserialized_state = state;
251
252 } else
253 log_debug("Unknown serialization key '%s'", key);
254
255 return 0;
256 }
257
258 _pure_ static UnitActiveState slice_active_state(Unit *u) {
259 assert(u);
260
261 return state_translation_table[SLICE(u)->state];
262 }
263
264 _pure_ static const char *slice_sub_state_to_string(Unit *u) {
265 assert(u);
266
267 return slice_state_to_string(SLICE(u)->state);
268 }
269
270 static const char* const slice_state_table[_SLICE_STATE_MAX] = {
271 [SLICE_DEAD] = "dead",
272 [SLICE_ACTIVE] = "active"
273 };
274
275 DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
276
277 const UnitVTable slice_vtable = {
278 .object_size = sizeof(Slice),
279 .cgroup_context_offset = offsetof(Slice, cgroup_context),
280
281 .sections =
282 "Unit\0"
283 "Slice\0"
284 "Install\0",
285 .private_section = "Slice",
286
287 .no_alias = true,
288 .no_instances = true,
289
290 .init = slice_init,
291 .load = slice_load,
292 .done = slice_done,
293
294 .coldplug = slice_coldplug,
295
296 .dump = slice_dump,
297
298 .start = slice_start,
299 .stop = slice_stop,
300
301 .kill = slice_kill,
302
303 .serialize = slice_serialize,
304 .deserialize_item = slice_deserialize_item,
305
306 .active_state = slice_active_state,
307 .sub_state_to_string = slice_sub_state_to_string,
308
309 .bus_interface = "org.freedesktop.systemd1.Slice",
310 .bus_vtable = bus_slice_vtable,
311 .bus_set_property = bus_slice_set_property,
312 .bus_commit_properties = bus_slice_commit_properties,
313
314 .status_message_formats = {
315 .finished_start_job = {
316 [JOB_DONE] = "Created slice %s.",
317 [JOB_DEPENDENCY] = "Dependency failed for %s.",
318 },
319 .finished_stop_job = {
320 [JOB_DONE] = "Removed slice %s.",
321 },
322 },
323 };