]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/cgroup.c
use "Out of memory." consistantly (or with "\n")
[thirdparty/systemd.git] / src / core / cgroup.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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
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 <assert.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <signal.h>
27 #include <sys/mount.h>
28 #include <fcntl.h>
29
30 #include "cgroup.h"
31 #include "cgroup-util.h"
32 #include "log.h"
33 #include "strv.h"
34 #include "path-util.h"
35
36 int cgroup_bonding_realize(CGroupBonding *b) {
37 int r;
38
39 assert(b);
40 assert(b->path);
41 assert(b->controller);
42
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));
46 return r;
47 }
48
49 b->realized = true;
50
51 return 0;
52 }
53
54 int cgroup_bonding_realize_list(CGroupBonding *first) {
55 CGroupBonding *b;
56 int r;
57
58 LIST_FOREACH(by_unit, b, first)
59 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
60 return r;
61
62 return 0;
63 }
64
65 void cgroup_bonding_free(CGroupBonding *b, bool trim) {
66 assert(b);
67
68 if (b->unit) {
69 CGroupBonding *f;
70
71 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
72
73 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
74 assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
75 LIST_REMOVE(CGroupBonding, by_path, f, b);
76
77 if (f)
78 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
79 else
80 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
81 }
82 }
83
84 if (b->realized && b->ours && trim)
85 cg_trim(b->controller, b->path, false);
86
87 free(b->controller);
88 free(b->path);
89 free(b);
90 }
91
92 void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
93 CGroupBonding *b, *n;
94
95 LIST_FOREACH_SAFE(by_unit, b, n, first)
96 cgroup_bonding_free(b, remove_or_trim);
97 }
98
99 void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
100 assert(b);
101
102 if (b->realized && b->ours)
103 cg_trim(b->controller, b->path, delete_root);
104 }
105
106 void 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
113
114 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
115 char *p = NULL;
116 const char *path;
117 int r;
118
119 assert(b);
120 assert(pid >= 0);
121
122 if (cgroup_suffix) {
123 p = strjoin(b->path, "/", cgroup_suffix, NULL);
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)
135 return r;
136
137 b->realized = true;
138 return 0;
139 }
140
141 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
142 CGroupBonding *b;
143 int r;
144
145 LIST_FOREACH(by_unit, b, first) {
146 r = cgroup_bonding_install(b, pid, cgroup_suffix);
147 if (r < 0 && b->essential)
148 return r;
149 }
150
151 return 0;
152 }
153
154 int 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
163 int 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
176 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
177 assert(b);
178
179 if (!b->realized)
180 return -EINVAL;
181
182 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
183 }
184
185 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
186 CGroupBonding *b;
187 int r;
188
189 LIST_FOREACH(by_unit, b, first) {
190 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
191 if (r < 0)
192 return r;
193 }
194
195 return 0;
196 }
197
198 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
199 char *p = NULL;
200 const char *path;
201 int r;
202
203 assert(b);
204 assert(sig >= 0);
205
206 /* Don't kill cgroups that aren't ours */
207 if (!b->ours)
208 return 0;
209
210 if (cgroup_suffix) {
211 p = strjoin(b->path, "/", cgroup_suffix, NULL);
212 if (!p)
213 return -ENOMEM;
214
215 path = p;
216 } else
217 path = b->path;
218
219 r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
220 free(p);
221
222 return r;
223 }
224
225 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
226 CGroupBonding *b;
227 Set *allocated_set = NULL;
228 int ret = -EAGAIN, r;
229
230 if (!first)
231 return 0;
232
233 if (!s)
234 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
235 return -ENOMEM;
236
237 LIST_FOREACH(by_unit, b, first) {
238 r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
239 if (r < 0) {
240 if (r == -EAGAIN || r == -ESRCH)
241 continue;
242
243 ret = r;
244 goto finish;
245 }
246
247 if (ret < 0 || r > 0)
248 ret = r;
249 }
250
251 finish:
252 if (allocated_set)
253 set_free(allocated_set);
254
255 return ret;
256 }
257
258 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
259 * cannot know */
260 int cgroup_bonding_is_empty(CGroupBonding *b) {
261 int r;
262
263 assert(b);
264
265 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
266 return r;
267
268 /* If it is empty it is empty */
269 if (r > 0)
270 return 1;
271
272 /* It's not only us using this cgroup, so we just don't know */
273 return b->ours ? 0 : -EAGAIN;
274 }
275
276 int 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
296 int manager_setup_cgroup(Manager *m) {
297 char *current = NULL, *path = NULL;
298 int r;
299 char suffix[32];
300
301 assert(m);
302
303 /* 0. Be nice to Ingo Molnar #628004 */
304 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
305 log_warning("No control group support available, not creating root group.");
306 return 0;
307 }
308
309 /* 1. Determine hierarchy */
310 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current);
311 if (r < 0) {
312 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
313 goto finish;
314 }
315
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 }
322
323 free(m->cgroup_hierarchy);
324 if (endswith(current, suffix)) {
325 /* We probably got reexecuted and can continue to use our root cgroup */
326 m->cgroup_hierarchy = current;
327 current = NULL;
328
329 } else {
330 /* We need a new root cgroup */
331 m->cgroup_hierarchy = NULL;
332 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
333 log_error("Out of memory.");
334 r = -ENOMEM;
335 goto finish;
336 }
337 }
338
339 /* 2. Show data */
340 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
341 if (r < 0) {
342 log_error("Cannot find cgroup mount point: %s", strerror(-r));
343 goto finish;
344 }
345
346 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
347
348 /* 3. Install agent */
349 r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
350 if (r < 0)
351 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
352 else if (r > 0)
353 log_debug("Installed release agent.");
354 else
355 log_debug("Release agent already installed.");
356
357 /* 4. Realize the group */
358 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
359 if (r < 0) {
360 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
361 goto finish;
362 }
363
364 /* 5. And pin it, so that it cannot be unmounted */
365 if (m->pin_cgroupfs_fd >= 0)
366 close_nointr_nofail(m->pin_cgroupfs_fd);
367
368 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
369 if (r < 0) {
370 log_error("Failed to open pin file: %m");
371 r = -errno;
372 goto finish;
373 }
374
375 log_debug("Created root group.");
376
377 cg_shorten_controllers(m->default_controllers);
378
379 finish:
380 free(current);
381 free(path);
382
383 return r;
384 }
385
386 void manager_shutdown_cgroup(Manager *m, bool delete) {
387 assert(m);
388
389 if (delete && m->cgroup_hierarchy)
390 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
391
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;
399 }
400
401 int 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);
410 if (b) {
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
440 int cgroup_notify_empty(Manager *m, const char *group) {
441 CGroupBonding *l, *b;
442 int r;
443
444 assert(m);
445 assert(group);
446
447 r = cgroup_bonding_get(m, group, &l);
448 if (r <= 0)
449 return r;
450
451 LIST_FOREACH(by_path, b, l) {
452 int t;
453
454 if (!b->unit)
455 continue;
456
457 t = cgroup_bonding_is_empty_list(b);
458 if (t < 0) {
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
467 if (t > 0) {
468 /* If it is empty, let's delete it */
469 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
470
471 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
472 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
473 }
474 }
475
476 return 0;
477 }
478
479 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
480 CGroupBonding *l, *b;
481 char *group = NULL;
482
483 assert(m);
484
485 if (pid <= 1)
486 return NULL;
487
488 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
489 return NULL;
490
491 l = hashmap_get(m->cgroup_bondings, group);
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
507 free(group);
508
509 LIST_FOREACH(by_path, b, l) {
510
511 if (!b->unit)
512 continue;
513
514 if (b->ours)
515 return b->unit;
516 }
517
518 return NULL;
519 }
520
521 CGroupBonding *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 }
532
533 char *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 }
543
544 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
545 FILE *f;
546 pid_t pid = 0, npid, mypid;
547
548 assert(b);
549
550 if (!b->ours)
551 return 0;
552
553 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
554 return 0;
555
556 mypid = getpid();
557
558 while (cg_read_pid(f, &npid) > 0) {
559 pid_t ppid;
560
561 if (npid == pid)
562 continue;
563
564 /* Ignore processes that aren't our kids */
565 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
566 continue;
567
568 if (pid != 0) {
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. */
572 pid = 0;
573 break;
574 }
575
576 pid = npid;
577 }
578
579 fclose(f);
580
581 return pid;
582 }
583
584 pid_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 }