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