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