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