]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/cgroup.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / core / cgroup.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8e274523
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
8e274523
LP
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
5430f7f2 16 Lesser General Public License for more details.
8e274523 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
8e274523
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <assert.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <signal.h>
27#include <sys/mount.h>
c6c18be3 28#include <fcntl.h>
8c6db833 29
8e274523 30#include "cgroup.h"
8c6db833 31#include "cgroup-util.h"
8e274523
LP
32#include "log.h"
33
8e274523
LP
34int cgroup_bonding_realize(CGroupBonding *b) {
35 int r;
36
37 assert(b);
38 assert(b->path);
39 assert(b->controller);
40
ab1f0633
LP
41 r = cg_create(b->controller, b->path);
42 if (r < 0) {
43 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
8c6db833 44 return r;
ab1f0633 45 }
8e274523 46
8c6db833 47 b->realized = true;
8e274523 48
8e274523 49 return 0;
8e274523
LP
50}
51
52int cgroup_bonding_realize_list(CGroupBonding *first) {
53 CGroupBonding *b;
8c6db833 54 int r;
8e274523 55
8c6db833 56 LIST_FOREACH(by_unit, b, first)
d686d8a9 57 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
8e274523 58 return r;
8e274523
LP
59
60 return 0;
61}
62
8d53b453 63void cgroup_bonding_free(CGroupBonding *b, bool trim) {
8e274523
LP
64 assert(b);
65
66 if (b->unit) {
67 CGroupBonding *f;
68
ac155bb8 69 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
8e274523 70
d686d8a9 71 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
ac155bb8 72 assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
d686d8a9 73 LIST_REMOVE(CGroupBonding, by_path, f, b);
8e274523 74
d686d8a9 75 if (f)
ac155bb8 76 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
d686d8a9 77 else
ac155bb8 78 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
d686d8a9 79 }
8e274523
LP
80 }
81
8d53b453
LP
82 if (b->realized && b->ours && trim)
83 cg_trim(b->controller, b->path, false);
8e274523 84
c9106f61
LP
85 free(b->controller);
86 free(b->path);
8e274523
LP
87 free(b);
88}
89
38c52d46 90void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
8e274523
LP
91 CGroupBonding *b, *n;
92
93 LIST_FOREACH_SAFE(by_unit, b, n, first)
38c52d46 94 cgroup_bonding_free(b, remove_or_trim);
8e274523
LP
95}
96
fb385181
LP
97void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
98 assert(b);
99
d686d8a9 100 if (b->realized && b->ours)
fb385181
LP
101 cg_trim(b->controller, b->path, delete_root);
102}
103
104void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
105 CGroupBonding *b;
106
107 LIST_FOREACH(by_unit, b, first)
108 cgroup_bonding_trim(b, delete_root);
109}
110
8e274523
LP
111int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
112 int r;
113
114 assert(b);
115 assert(pid >= 0);
116
8c6db833
LP
117 if ((r = cg_create_and_attach(b->controller, b->path, pid)) < 0)
118 return r;
8e274523 119
8c6db833 120 b->realized = true;
8e274523
LP
121 return 0;
122}
123
124int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
125 CGroupBonding *b;
8c6db833 126 int r;
8e274523 127
8c6db833 128 LIST_FOREACH(by_unit, b, first)
d686d8a9 129 if ((r = cgroup_bonding_install(b, pid)) < 0 && b->essential)
8e274523 130 return r;
8e274523
LP
131
132 return 0;
133}
134
64747e2d
LP
135int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
136 assert(b);
137
138 if (!b->realized)
139 return -EINVAL;
140
141 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
142}
143
144int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
145 CGroupBonding *b;
146 int r;
147
148 LIST_FOREACH(by_unit, b, first) {
149 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
150 if (r < 0)
151 return r;
152 }
153
154 return 0;
155}
156
8d53b453 157int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
64747e2d
LP
158 assert(b);
159
160 if (!b->realized)
161 return -EINVAL;
162
8d53b453 163 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
64747e2d
LP
164}
165
8d53b453 166int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
64747e2d
LP
167 CGroupBonding *b;
168 int r;
169
170 LIST_FOREACH(by_unit, b, first) {
8d53b453 171 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
64747e2d
LP
172 if (r < 0)
173 return r;
174 }
175
176 return 0;
177}
178
430c18ed 179int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s) {
8e274523 180 assert(b);
8c6db833 181 assert(sig >= 0);
8e274523 182
d686d8a9 183 /* Don't kill cgroups that aren't ours */
31e54cc8 184 if (!b->ours)
d686d8a9 185 return 0;
8c6db833 186
430c18ed 187 return cg_kill_recursive(b->controller, b->path, sig, sigcont, true, false, s);
8e274523
LP
188}
189
430c18ed 190int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s) {
8e274523 191 CGroupBonding *b;
ca949c9d
LP
192 Set *allocated_set = NULL;
193 int ret = -EAGAIN, r;
194
8f53a7b8
LP
195 if (!first)
196 return 0;
197
ca949c9d
LP
198 if (!s)
199 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
200 return -ENOMEM;
8e274523
LP
201
202 LIST_FOREACH(by_unit, b, first) {
430c18ed 203 if ((r = cgroup_bonding_kill(b, sig, sigcont, s)) < 0) {
8c6db833 204 if (r == -EAGAIN || r == -ESRCH)
50159e6a 205 continue;
8e274523 206
ca949c9d
LP
207 ret = r;
208 goto finish;
50159e6a
LP
209 }
210
ca949c9d
LP
211 if (ret < 0 || r > 0)
212 ret = r;
8e274523
LP
213 }
214
ca949c9d
LP
215finish:
216 if (allocated_set)
217 set_free(allocated_set);
218
219 return ret;
8e274523
LP
220}
221
222/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
223 * cannot know */
224int cgroup_bonding_is_empty(CGroupBonding *b) {
8e274523
LP
225 int r;
226
227 assert(b);
228
8c6db833
LP
229 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
230 return r;
8e274523 231
8c6db833
LP
232 /* If it is empty it is empty */
233 if (r > 0)
8e274523
LP
234 return 1;
235
8c6db833 236 /* It's not only us using this cgroup, so we just don't know */
d686d8a9 237 return b->ours ? 0 : -EAGAIN;
8e274523
LP
238}
239
240int cgroup_bonding_is_empty_list(CGroupBonding *first) {
241 CGroupBonding *b;
242
243 LIST_FOREACH(by_unit, b, first) {
244 int r;
245
246 if ((r = cgroup_bonding_is_empty(b)) < 0) {
247 /* If this returned -EAGAIN, then we don't know if the
248 * group is empty, so let's see if another group can
249 * tell us */
250
251 if (r != -EAGAIN)
252 return r;
253 } else
254 return r;
255 }
256
257 return -EAGAIN;
258}
259
8e274523 260int manager_setup_cgroup(Manager *m) {
c6c18be3 261 char *current = NULL, *path = NULL;
8e274523 262 int r;
7ccfb64a 263 char suffix[32];
8e274523
LP
264
265 assert(m);
266
e5a53dc7 267 /* 0. Be nice to Ingo Molnar #628004 */
0c85a4f3 268 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
e5a53dc7
LP
269 log_warning("No control group support available, not creating root group.");
270 return 0;
271 }
272
35d2e7ec 273 /* 1. Determine hierarchy */
12235040
LP
274 if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current)) < 0) {
275 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
c6c18be3 276 goto finish;
12235040 277 }
8e274523 278
0baf24dd
LP
279 if (m->running_as == MANAGER_SYSTEM)
280 strcpy(suffix, "/system");
281 else {
282 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
283 char_array_0(suffix);
284 }
7ccfb64a 285
8e274523 286 free(m->cgroup_hierarchy);
c6c18be3 287 if (endswith(current, suffix)) {
7ccfb64a 288 /* We probably got reexecuted and can continue to use our root cgroup */
c6c18be3
LP
289 m->cgroup_hierarchy = current;
290 current = NULL;
7ccfb64a 291
c6c18be3
LP
292 } else {
293 /* We need a new root cgroup */
7ccfb64a 294 m->cgroup_hierarchy = NULL;
e364ad06 295 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
12235040 296 log_error("Out of memory");
c6c18be3
LP
297 r = -ENOMEM;
298 goto finish;
299 }
8e274523
LP
300 }
301
35d2e7ec 302 /* 2. Show data */
12235040
LP
303 if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
304 log_error("Cannot find cgroup mount point: %s", strerror(-r));
c6c18be3 305 goto finish;
12235040 306 }
8e274523 307
c6c18be3
LP
308 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
309
35d2e7ec 310 /* 3. Install agent */
91901329 311 if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
8e274523 312 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
c6c18be3
LP
313 else if (r > 0)
314 log_debug("Installed release agent.");
8e274523 315 else
c6c18be3 316 log_debug("Release agent already installed.");
8e274523 317
35d2e7ec 318 /* 4. Realize the group */
c6c18be3 319 if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
8e274523 320 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
c6c18be3
LP
321 goto finish;
322 }
323
35d2e7ec 324 /* 5. And pin it, so that it cannot be unmounted */
c6c18be3
LP
325 if (m->pin_cgroupfs_fd >= 0)
326 close_nointr_nofail(m->pin_cgroupfs_fd);
327
328 if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
12235040 329 log_error("Failed to open pin file: %m");
c6c18be3
LP
330 r = -errno;
331 goto finish;
332 }
333
334 log_debug("Created root group.");
335
336finish:
337 free(current);
338 free(path);
8e274523
LP
339
340 return r;
341}
342
c6c18be3 343void manager_shutdown_cgroup(Manager *m, bool delete) {
8e274523
LP
344 assert(m);
345
c6c18be3
LP
346 if (delete && m->cgroup_hierarchy)
347 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
8e274523 348
c6c18be3
LP
349 if (m->pin_cgroupfs_fd >= 0) {
350 close_nointr_nofail(m->pin_cgroupfs_fd);
351 m->pin_cgroupfs_fd = -1;
352 }
353
354 free(m->cgroup_hierarchy);
355 m->cgroup_hierarchy = NULL;
8e274523
LP
356}
357
acb14d31
LP
358int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
359 CGroupBonding *b;
360 char *p;
361
362 assert(m);
363 assert(cgroup);
364 assert(bonding);
365
366 b = hashmap_get(m->cgroup_bondings, cgroup);
5c72face 367 if (b) {
acb14d31
LP
368 *bonding = b;
369 return 1;
370 }
371
372 p = strdup(cgroup);
373 if (!p)
374 return -ENOMEM;
375
376 for (;;) {
377 char *e;
378
379 e = strrchr(p, '/');
380 if (!e || e == p) {
381 free(p);
382 *bonding = NULL;
383 return 0;
384 }
385
386 *e = 0;
387
388 b = hashmap_get(m->cgroup_bondings, p);
389 if (b) {
390 free(p);
391 *bonding = b;
392 return 1;
393 }
394 }
395}
396
8e274523
LP
397int cgroup_notify_empty(Manager *m, const char *group) {
398 CGroupBonding *l, *b;
acb14d31 399 int r;
8e274523
LP
400
401 assert(m);
402 assert(group);
403
acb14d31
LP
404 r = cgroup_bonding_get(m, group, &l);
405 if (r <= 0)
406 return r;
8e274523
LP
407
408 LIST_FOREACH(by_path, b, l) {
409 int t;
410
411 if (!b->unit)
412 continue;
413
353fa6a2
LP
414 t = cgroup_bonding_is_empty_list(b);
415 if (t < 0) {
8e274523
LP
416
417 /* If we don't know, we don't know */
418 if (t != -EAGAIN)
419 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
420
421 continue;
422 }
423
353fa6a2
LP
424 if (t > 0) {
425 /* If it is empty, let's delete it */
ac155bb8 426 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
353fa6a2 427
8e274523
LP
428 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
429 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
353fa6a2 430 }
8e274523
LP
431 }
432
433 return 0;
434}
435
8c47c732
LP
436Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
437 CGroupBonding *l, *b;
438 char *group = NULL;
8c47c732
LP
439
440 assert(m);
441
442 if (pid <= 1)
443 return NULL;
444
e364ad06 445 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
8c47c732
LP
446 return NULL;
447
448 l = hashmap_get(m->cgroup_bondings, group);
4455bcd0
LP
449
450 if (!l) {
451 char *slash;
452
453 while ((slash = strrchr(group, '/'))) {
454 if (slash == group)
455 break;
456
457 *slash = 0;
458
459 if ((l = hashmap_get(m->cgroup_bondings, group)))
460 break;
461 }
462 }
463
8c47c732
LP
464 free(group);
465
8c47c732
LP
466 LIST_FOREACH(by_path, b, l) {
467
468 if (!b->unit)
469 continue;
470
d686d8a9 471 if (b->ours)
8c47c732
LP
472 return b->unit;
473 }
474
475 return NULL;
476}
477
8e274523
LP
478CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
479 CGroupBonding *b;
480
481 assert(controller);
482
483 LIST_FOREACH(by_unit, b, first)
484 if (streq(b->controller, controller))
485 return b;
486
487 return NULL;
488}
6dde1f33
LP
489
490char *cgroup_bonding_to_string(CGroupBonding *b) {
491 char *r;
492
493 assert(b);
494
495 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
496 return NULL;
497
498 return r;
499}
4fbf50b3
LP
500
501pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
502 FILE *f;
2633eb83 503 pid_t pid = 0, npid, mypid;
4fbf50b3
LP
504
505 assert(b);
506
d686d8a9 507 if (!b->ours)
4fbf50b3
LP
508 return 0;
509
bd40a2d8 510 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
4fbf50b3
LP
511 return 0;
512
2633eb83
LP
513 mypid = getpid();
514
bd40a2d8 515 while (cg_read_pid(f, &npid) > 0) {
2633eb83 516 pid_t ppid;
4fbf50b3
LP
517
518 if (npid == pid)
519 continue;
520
2633eb83
LP
521 /* Ignore processes that aren't our kids */
522 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
523 continue;
524
4fbf50b3 525 if (pid != 0) {
2633eb83
LP
526 /* Dang, there's more than one daemonized PID
527 in this group, so we don't know what process
528 is the main process. */
4fbf50b3
LP
529 pid = 0;
530 break;
531 }
532
533 pid = npid;
534 }
535
536 fclose(f);
537
538 return pid;
539}
540
541pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
542 CGroupBonding *b;
543 pid_t pid;
544
545 /* Try to find a main pid from this cgroup, but checking if
546 * there's only one PID in the cgroup and returning it. Later
547 * on we might want to add additional, smarter heuristics
548 * here. */
549
550 LIST_FOREACH(by_unit, b, first)
551 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
552 return pid;
553
554 return 0;
555
556}