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