chiark / gitweb /
service: place control command in subcgroup control/
[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         if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
338                 log_error("Cannot find cgroup mount point: %s", strerror(-r));
339                 goto finish;
340         }
341
342         log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
343
344         /* 3. Install agent */
345         if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
346                 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
347         else if (r > 0)
348                 log_debug("Installed release agent.");
349         else
350                 log_debug("Release agent already installed.");
351
352         /* 4. Realize the group */
353         if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
354                 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
355                 goto finish;
356         }
357
358         /* 5. And pin it, so that it cannot be unmounted */
359         if (m->pin_cgroupfs_fd >= 0)
360                 close_nointr_nofail(m->pin_cgroupfs_fd);
361
362         if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
363                 log_error("Failed to open pin file: %m");
364                 r = -errno;
365                 goto finish;
366         }
367
368         log_debug("Created root group.");
369
370 finish:
371         free(current);
372         free(path);
373
374         return r;
375 }
376
377 void manager_shutdown_cgroup(Manager *m, bool delete) {
378         assert(m);
379
380         if (delete && m->cgroup_hierarchy)
381                 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
382
383         if (m->pin_cgroupfs_fd >= 0) {
384                 close_nointr_nofail(m->pin_cgroupfs_fd);
385                 m->pin_cgroupfs_fd = -1;
386         }
387
388         free(m->cgroup_hierarchy);
389         m->cgroup_hierarchy = NULL;
390 }
391
392 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
393         CGroupBonding *b;
394         char *p;
395
396         assert(m);
397         assert(cgroup);
398         assert(bonding);
399
400         b = hashmap_get(m->cgroup_bondings, cgroup);
401         if (b) {
402                 *bonding = b;
403                 return 1;
404         }
405
406         p = strdup(cgroup);
407         if (!p)
408                 return -ENOMEM;
409
410         for (;;) {
411                 char *e;
412
413                 e = strrchr(p, '/');
414                 if (!e || e == p) {
415                         free(p);
416                         *bonding = NULL;
417                         return 0;
418                 }
419
420                 *e = 0;
421
422                 b = hashmap_get(m->cgroup_bondings, p);
423                 if (b) {
424                         free(p);
425                         *bonding = b;
426                         return 1;
427                 }
428         }
429 }
430
431 int cgroup_notify_empty(Manager *m, const char *group) {
432         CGroupBonding *l, *b;
433         int r;
434
435         assert(m);
436         assert(group);
437
438         r = cgroup_bonding_get(m, group, &l);
439         if (r <= 0)
440                 return r;
441
442         LIST_FOREACH(by_path, b, l) {
443                 int t;
444
445                 if (!b->unit)
446                         continue;
447
448                 t = cgroup_bonding_is_empty_list(b);
449                 if (t < 0) {
450
451                         /* If we don't know, we don't know */
452                         if (t != -EAGAIN)
453                                 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
454
455                         continue;
456                 }
457
458                 if (t > 0) {
459                         /* If it is empty, let's delete it */
460                         cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
461
462                         if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
463                                 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
464                 }
465         }
466
467         return 0;
468 }
469
470 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
471         CGroupBonding *l, *b;
472         char *group = NULL;
473
474         assert(m);
475
476         if (pid <= 1)
477                 return NULL;
478
479         if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
480                 return NULL;
481
482         l = hashmap_get(m->cgroup_bondings, group);
483
484         if (!l) {
485                 char *slash;
486
487                 while ((slash = strrchr(group, '/'))) {
488                         if (slash == group)
489                                 break;
490
491                         *slash = 0;
492
493                         if ((l = hashmap_get(m->cgroup_bondings, group)))
494                                 break;
495                 }
496         }
497
498         free(group);
499
500         LIST_FOREACH(by_path, b, l) {
501
502                 if (!b->unit)
503                         continue;
504
505                 if (b->ours)
506                         return b->unit;
507         }
508
509         return NULL;
510 }
511
512 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
513         CGroupBonding *b;
514
515         assert(controller);
516
517         LIST_FOREACH(by_unit, b, first)
518                 if (streq(b->controller, controller))
519                         return b;
520
521         return NULL;
522 }
523
524 char *cgroup_bonding_to_string(CGroupBonding *b) {
525         char *r;
526
527         assert(b);
528
529         if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
530                 return NULL;
531
532         return r;
533 }
534
535 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
536         FILE *f;
537         pid_t pid = 0, npid, mypid;
538
539         assert(b);
540
541         if (!b->ours)
542                 return 0;
543
544         if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
545                 return 0;
546
547         mypid = getpid();
548
549         while (cg_read_pid(f, &npid) > 0)  {
550                 pid_t ppid;
551
552                 if (npid == pid)
553                         continue;
554
555                 /* Ignore processes that aren't our kids */
556                 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
557                         continue;
558
559                 if (pid != 0) {
560                         /* Dang, there's more than one daemonized PID
561                         in this group, so we don't know what process
562                         is the main process. */
563                         pid = 0;
564                         break;
565                 }
566
567                 pid = npid;
568         }
569
570         fclose(f);
571
572         return pid;
573 }
574
575 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
576         CGroupBonding *b;
577         pid_t pid;
578
579         /* Try to find a main pid from this cgroup, but checking if
580          * there's only one PID in the cgroup and returning it. Later
581          * on we might want to add additional, smarter heuristics
582          * here. */
583
584         LIST_FOREACH(by_unit, b, first)
585                 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
586                         return pid;
587
588         return 0;
589
590 }