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