chiark / gitweb /
cgroup: drop inherit flag, this mus be fixed in the kernel
[elogind.git] / src / cgroup.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU 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
29 #include "cgroup.h"
30 #include "log.h"
31
32 static int translate_error(int error, int _errno) {
33
34         switch (error) {
35
36         case ECGROUPNOTCOMPILED:
37         case ECGROUPNOTMOUNTED:
38         case ECGROUPNOTEXIST:
39         case ECGROUPNOTCREATED:
40                 return -ENOENT;
41
42         case ECGINVAL:
43                 return -EINVAL;
44
45         case ECGROUPNOTALLOWED:
46                 return -EPERM;
47
48         case ECGOTHER:
49                 return -_errno;
50         }
51
52         return -EIO;
53 }
54
55 int cgroup_bonding_realize(CGroupBonding *b) {
56         int r;
57
58         assert(b);
59         assert(b->path);
60         assert(b->controller);
61
62         if (b->cgroup)
63                 return 0;
64
65         if (!(b->cgroup = cgroup_new_cgroup(b->path)))
66                 return -ENOMEM;
67
68         if (!cgroup_add_controller(b->cgroup, b->controller)) {
69                 r = -ENOMEM;
70                 goto fail;
71         }
72
73         if ((r = cgroup_create_cgroup(b->cgroup, true)) != 0) {
74                 r = translate_error(r, errno);
75                 goto fail;
76         }
77
78         return 0;
79
80 fail:
81         cgroup_free(&b->cgroup);
82         b->cgroup = NULL;
83         return r;
84 }
85
86 int cgroup_bonding_realize_list(CGroupBonding *first) {
87         CGroupBonding *b;
88
89         LIST_FOREACH(by_unit, b, first) {
90                 int r;
91
92                 if ((r = cgroup_bonding_realize(b)) < 0)
93                         return r;
94         }
95
96         return 0;
97 }
98
99 void cgroup_bonding_free(CGroupBonding *b) {
100         assert(b);
101
102         if (b->unit) {
103                 CGroupBonding *f;
104
105                 LIST_REMOVE(CGroupBonding, by_unit, b->unit->meta.cgroup_bondings, b);
106
107                 assert_se(f = hashmap_get(b->unit->meta.manager->cgroup_bondings, b->path));
108                 LIST_REMOVE(CGroupBonding, by_path, f, b);
109
110                 if (f)
111                         hashmap_replace(b->unit->meta.manager->cgroup_bondings, b->path, f);
112                 else
113                         hashmap_remove(b->unit->meta.manager->cgroup_bondings, b->path);
114         }
115
116         if (b->cgroup) {
117                 if (b->only_us && b->clean_up && cgroup_bonding_is_empty(b) > 0)
118                         cgroup_delete_cgroup_ext(b->cgroup, true);
119
120                 cgroup_free(&b->cgroup);
121         }
122
123         free(b->controller);
124         free(b->path);
125         free(b);
126 }
127
128 void cgroup_bonding_free_list(CGroupBonding *first) {
129         CGroupBonding *b, *n;
130
131         LIST_FOREACH_SAFE(by_unit, b, n, first)
132                 cgroup_bonding_free(b);
133 }
134
135 int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
136         int r;
137
138         assert(b);
139         assert(pid >= 0);
140
141         if (pid == 0)
142                 pid = getpid();
143
144         if (!b->cgroup)
145                 return -ENOENT;
146
147         if ((r = cgroup_attach_task_pid(b->cgroup, pid)))
148                 return translate_error(r, errno);
149
150         return 0;
151 }
152
153 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
154         CGroupBonding *b;
155
156         LIST_FOREACH(by_unit, b, first) {
157                 int r;
158
159                 if ((r = cgroup_bonding_install(b, pid)) < 0)
160                         return r;
161         }
162
163         return 0;
164 }
165
166 int cgroup_bonding_kill(CGroupBonding *b, int sig) {
167         int r;
168         Set *s;
169         bool done;
170         bool killed = false;
171
172         assert(b);
173         assert(sig > 0);
174
175         if (!b->only_us)
176                 return -EAGAIN;
177
178         if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
179                 return -ENOMEM;
180
181         do {
182                 void *iterator;
183                 pid_t pid;
184
185                 done = true;
186
187                 if ((r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid)) != 0) {
188                         if (r == ECGEOF) {
189                                 r = 0;
190                                 goto kill_done;
191                         } else {
192                                 if (r == ECGOTHER && errno == ENOENT)
193                                         r = ESRCH;
194                                 else
195                                         r = translate_error(r, errno);
196                                 break;
197                         }
198                 }
199
200                 for (;;) {
201                         if (set_get(s, INT_TO_PTR(pid)) != INT_TO_PTR(pid)) {
202
203                                 /* If we haven't killed this process
204                                  * yet, kill it */
205
206                                 if (kill(pid, sig) < 0 && errno != ESRCH) {
207                                         r = -errno;
208                                         break;
209                                 }
210
211                                 killed = true;
212                                 done = false;
213
214                                 if ((r = set_put(s, INT_TO_PTR(pid))) < 0)
215                                     break;
216                         }
217
218                         if ((r = cgroup_get_task_next(&iterator, &pid)) != 0) {
219
220                                 if (r == ECGEOF)
221                                         r = 0;
222                                 else
223                                         r = translate_error(r, errno);
224
225                                 break;
226                         }
227                 }
228
229         kill_done:
230                 assert_se(cgroup_get_task_end(&iterator) == 0);
231
232                 /* To avoid racing against processes which fork
233                  * quicker than we can kill them we repeat this until
234                  * no new pids need to be killed. */
235
236         } while (!done && r >= 0);
237
238         set_free(s);
239
240         if (r < 0)
241                 return r;
242
243         return killed ? 0 : -ESRCH;
244 }
245
246 int cgroup_bonding_kill_list(CGroupBonding *first, int sig) {
247         CGroupBonding *b;
248         int r = -EAGAIN;
249
250         LIST_FOREACH(by_unit, b, first) {
251                 if ((r = cgroup_bonding_kill(b, sig)) < 0) {
252                         if (r == -EAGAIN || -ESRCH)
253                                 continue;
254
255                         return r;
256                 }
257
258                 return 0;
259         }
260
261         return r;
262 }
263
264 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
265  * cannot know */
266 int cgroup_bonding_is_empty(CGroupBonding *b) {
267         void *iterator;
268         pid_t pid;
269         int r;
270
271         assert(b);
272
273         r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid);
274
275         if (r == 0 || r == ECGEOF)
276                 cgroup_get_task_end(&iterator);
277
278         /* Hmm, no PID in this group? Then it is definitely empty */
279         if (r == ECGEOF)
280                 return 1;
281
282         /* Some error? Let's return it */
283         if (r != 0)
284                 return translate_error(r, errno);
285
286         /* It's not empty, and we are the only user, then it is
287          * definitely not empty */
288         if (b->only_us)
289                 return 0;
290
291         /* There are PIDs in the group but we aren't the only users,
292          * hence we cannot say */
293         return -EAGAIN;
294 }
295
296 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
297         CGroupBonding *b;
298
299         LIST_FOREACH(by_unit, b, first) {
300                 int r;
301
302                 if ((r = cgroup_bonding_is_empty(b)) < 0) {
303                         /* If this returned -EAGAIN, then we don't know if the
304                          * group is empty, so let's see if another group can
305                          * tell us */
306
307                         if (r != -EAGAIN)
308                                 return r;
309                 } else
310                         return r;
311         }
312
313         return -EAGAIN;
314 }
315
316 static int install_release_agent(Manager *m, const char *mount_point) {
317         char *p, *c, *sc;
318         int r;
319
320         assert(m);
321         assert(mount_point);
322
323         if (asprintf(&p, "%s/release_agent", mount_point) < 0)
324                 return -ENOMEM;
325
326         if ((r = read_one_line_file(p, &c)) < 0) {
327                 free(p);
328                 return r;
329         }
330
331         sc = strstrip(c);
332
333         if (sc[0] == 0) {
334                 if ((r = write_one_line_file(p, CGROUP_AGENT_PATH "\n" )) < 0) {
335                         free(p);
336                         free(c);
337                         return r;
338                 }
339         } else if (!streq(sc, CGROUP_AGENT_PATH)) {
340                 free(p);
341                 free(c);
342                 return -EEXIST;
343         }
344
345         free(c);
346         free(p);
347
348         if (asprintf(&p, "%s/notify_on_release", mount_point) < 0)
349                 return -ENOMEM;
350
351         if ((r = read_one_line_file(p, &c)) < 0) {
352                 free(p);
353                 return r;
354         }
355
356         sc = strstrip(c);
357
358         if (streq(sc, "0")) {
359                 if ((r = write_one_line_file(p, "1\n")) < 0) {
360                         free(p);
361                         free(c);
362                         return r;
363                 }
364         } else if (!streq(sc, "1")) {
365                 free(p);
366                 free(c);
367                 return -EIO;
368         }
369
370         free(p);
371         free(c);
372
373         return 0;
374 }
375
376 static int create_hierarchy_cgroup(Manager *m) {
377         struct cgroup *cg;
378         int r;
379
380         assert(m);
381
382         if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy)))
383                 return -ENOMEM;
384
385         if (!(cgroup_add_controller(cg, m->cgroup_controller))) {
386                 r = -ENOMEM;
387                 goto finish;
388         }
389
390         if ((r = cgroup_create_cgroup(cg, true)) != 0) {
391                 log_error("Failed to create cgroup hierarchy group: %s", cgroup_strerror(r));
392                 r = translate_error(r, errno);
393                 goto finish;
394         }
395
396         if ((r = cgroup_attach_task(cg)) != 0) {
397                 log_error("Failed to add ourselves to hierarchy group: %s", cgroup_strerror(r));
398                 r = translate_error(r, errno);
399                 goto finish;
400         }
401
402         r = 0;
403
404 finish:
405         cgroup_free(&cg);
406         return r;
407 }
408
409 int manager_setup_cgroup(Manager *m) {
410         char *mp, *cp;
411         int r;
412         pid_t pid;
413         char suffix[32];
414
415         assert(m);
416
417         if ((r = cgroup_init()) != 0) {
418                 log_error("Failed to initialize libcg: %s", cgroup_strerror(r));
419                 return translate_error(r, errno);
420         }
421
422         free(m->cgroup_controller);
423         if (!(m->cgroup_controller = strdup("name=systemd")))
424                 return -ENOMEM;
425
426         if ((r = cgroup_get_subsys_mount_point(m->cgroup_controller, &mp)))
427                 return translate_error(r, errno);
428
429         pid = getpid();
430
431         if ((r = cgroup_get_current_controller_path(pid, m->cgroup_controller, &cp))) {
432                 free(mp);
433                 return translate_error(r, errno);
434         }
435
436         snprintf(suffix, sizeof(suffix), "/systemd-%u", (unsigned) pid);
437         char_array_0(suffix);
438
439         free(m->cgroup_hierarchy);
440
441         if (endswith(cp, suffix))
442                 /* We probably got reexecuted and can continue to use our root cgroup */
443                 m->cgroup_hierarchy = cp;
444         else {
445                 /* We need a new root cgroup */
446
447                 m->cgroup_hierarchy = NULL;
448                 r = asprintf(&m->cgroup_hierarchy, "%s%s", streq(cp, "/") ? "" : cp, suffix);
449                 free(cp);
450
451                 if (r < 0) {
452                         free(mp);
453                         return -ENOMEM;
454                 }
455         }
456
457         log_debug("Using cgroup controller <%s>, hierarchy mounted at <%s>, using root group <%s>.",
458                   m->cgroup_controller,
459                   mp,
460                   m->cgroup_hierarchy);
461
462         if ((r = install_release_agent(m, mp)) < 0)
463                 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
464         else
465                 log_debug("Installed release agent, or already installed.");
466
467         free(mp);
468
469         if ((r = create_hierarchy_cgroup(m)) < 0)
470                 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
471         else
472                 log_debug("Created root group.");
473
474         return r;
475 }
476
477 int manager_shutdown_cgroup(Manager *m, bool delete) {
478         struct cgroup *cg;
479         int r;
480
481         assert(m);
482
483         if (!m->cgroup_hierarchy)
484                 return 0;
485
486         if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy)))
487                 return -ENOMEM;
488
489         if (!(cgroup_add_controller(cg, m->cgroup_controller))) {
490                 r = -ENOMEM;
491                 goto finish;
492         }
493
494         /* Often enough we won't be able to delete the cgroup we
495          * ourselves are in, hence ignore all errors here */
496         if (delete)
497                 cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_IGNORE_MIGRATION|CGFLAG_DELETE_RECURSIVE);
498         r = 0;
499
500 finish:
501         cgroup_free(&cg);
502         return r;
503
504 }
505
506 int cgroup_notify_empty(Manager *m, const char *group) {
507         CGroupBonding *l, *b;
508
509         assert(m);
510         assert(group);
511
512         if (!(l = hashmap_get(m->cgroup_bondings, group)))
513                 return 0;
514
515         LIST_FOREACH(by_path, b, l) {
516                 int t;
517
518                 if (!b->unit)
519                         continue;
520
521                 if ((t = cgroup_bonding_is_empty_list(b)) < 0) {
522
523                         /* If we don't know, we don't know */
524                         if (t != -EAGAIN)
525                                 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
526
527                         continue;
528                 }
529
530                 if (t > 0)
531                         if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
532                                 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
533         }
534
535         return 0;
536 }
537
538 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
539         CGroupBonding *b;
540
541         assert(controller);
542
543         LIST_FOREACH(by_unit, b, first)
544                 if (streq(b->controller, controller))
545                         return b;
546
547         return NULL;
548 }
549
550 char *cgroup_bonding_to_string(CGroupBonding *b) {
551         char *r;
552
553         assert(b);
554
555         if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
556                 return NULL;
557
558         return r;
559 }