]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-cgroup.c
core: make sure we always write changed cgroup attributes to the cgroupfs
[thirdparty/systemd.git] / src / core / dbus-cgroup.c
CommitLineData
4ad49000
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 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
718db961 22#include "bus-util.h"
7041efe9 23#include "path-util.h"
718db961
LP
24#include "cgroup-util.h"
25#include "cgroup.h"
4ad49000
LP
26#include "dbus-cgroup.h"
27
718db961
LP
28static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
29
30static int property_get_blockio_device_weight(
31 sd_bus *bus,
32 const char *path,
33 const char *interface,
34 const char *property,
35 sd_bus_message *reply,
ebcf1f97
LP
36 void *userdata,
37 sd_bus_error *error) {
4ad49000 38
718db961 39 CGroupContext *c = userdata;
4ad49000 40 CGroupBlockIODeviceWeight *w;
718db961 41 int r;
4ad49000 42
718db961
LP
43 assert(bus);
44 assert(reply);
4ad49000
LP
45 assert(c);
46
718db961
LP
47 r = sd_bus_message_open_container(reply, 'a', "(st)");
48 if (r < 0)
49 return r;
4ad49000
LP
50
51 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
718db961
LP
52 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
53 if (r < 0)
54 return r;
4ad49000
LP
55 }
56
718db961 57 return sd_bus_message_close_container(reply);
4ad49000
LP
58}
59
718db961
LP
60static int property_get_blockio_device_bandwidths(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
ebcf1f97
LP
66 void *userdata,
67 sd_bus_error *error) {
718db961
LP
68
69 CGroupContext *c = userdata;
4ad49000 70 CGroupBlockIODeviceBandwidth *b;
718db961 71 int r;
4ad49000 72
718db961
LP
73 assert(bus);
74 assert(reply);
4ad49000
LP
75 assert(c);
76
718db961
LP
77 r = sd_bus_message_open_container(reply, 'a', "(st)");
78 if (r < 0)
79 return r;
4ad49000
LP
80
81 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
82
83 if (streq(property, "BlockIOReadBandwidth") != b->read)
84 continue;
85
718db961
LP
86 r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
87 if (r < 0)
88 return r;
4ad49000
LP
89 }
90
718db961 91 return sd_bus_message_close_container(reply);
4ad49000
LP
92}
93
718db961
LP
94static int property_get_device_allow(
95 sd_bus *bus,
96 const char *path,
97 const char *interface,
98 const char *property,
99 sd_bus_message *reply,
ebcf1f97
LP
100 void *userdata,
101 sd_bus_error *error) {
718db961
LP
102
103 CGroupContext *c = userdata;
4ad49000 104 CGroupDeviceAllow *a;
718db961 105 int r;
4ad49000 106
718db961
LP
107 assert(bus);
108 assert(reply);
4ad49000
LP
109 assert(c);
110
718db961
LP
111 r = sd_bus_message_open_container(reply, 'a', "(ss)");
112 if (r < 0)
113 return r;
4ad49000
LP
114
115 LIST_FOREACH(device_allow, a, c->device_allow) {
4ad49000 116 unsigned k = 0;
718db961 117 char rwm[4];
4ad49000
LP
118
119 if (a->r)
718db961 120 rwm[k++] = 'r';
4ad49000 121 if (a->w)
718db961 122 rwm[k++] = 'w';
4ad49000 123 if (a->m)
718db961 124 rwm[k++] = 'm';
4ad49000 125
718db961 126 rwm[k] = 0;
4ad49000 127
718db961
LP
128 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
129 if (r < 0)
130 return r;
4ad49000
LP
131 }
132
718db961 133 return sd_bus_message_close_container(reply);
4ad49000
LP
134}
135
718db961
LP
136const sd_bus_vtable bus_cgroup_vtable[] = {
137 SD_BUS_VTABLE_START(0),
610f780c
LP
138 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
139 SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
140 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
141 SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0),
142 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
143 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
144 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
145 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
146 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
147 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
148 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
718db961 149 SD_BUS_VTABLE_END
4ad49000 150};
8e2af478
LP
151
152int bus_cgroup_set_property(
153 Unit *u,
154 CGroupContext *c,
155 const char *name,
718db961 156 sd_bus_message *message,
8e2af478 157 UnitSetPropertiesMode mode,
718db961
LP
158 sd_bus_error *error) {
159
160 int r;
8e2af478 161
8e2af478
LP
162 assert(u);
163 assert(c);
718db961
LP
164 assert(name);
165 assert(message);
8e2af478
LP
166
167 if (streq(name, "CPUAccounting")) {
718db961 168 int b;
8e2af478 169
718db961
LP
170 r = sd_bus_message_read(message, "b", &b);
171 if (r < 0)
172 return r;
8e2af478
LP
173
174 if (mode != UNIT_CHECK) {
8e2af478 175 c->cpu_accounting = b;
3051f187 176 u->cgroup_realized_mask &= ~CGROUP_CPUACCT;
b9ec9359 177 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
b42defe3
LP
178 }
179
180 return 1;
181
182 } else if (streq(name, "CPUShares")) {
183 uint64_t u64;
184 unsigned long ul;
185
718db961
LP
186 r = sd_bus_message_read(message, "t", &u64);
187 if (r < 0)
188 return r;
b42defe3 189
b42defe3 190 ul = (unsigned long) u64;
718db961
LP
191 if (ul <= 0 || (uint64_t) ul != u64)
192 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
b42defe3
LP
193
194 if (mode != UNIT_CHECK) {
b42defe3 195 c->cpu_shares = ul;
3051f187 196 u->cgroup_realized_mask &= ~CGROUP_CPU;
b9ec9359 197 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
8e2af478
LP
198 }
199
200 return 1;
201
202 } else if (streq(name, "BlockIOAccounting")) {
718db961 203 int b;
8e2af478 204
718db961
LP
205 r = sd_bus_message_read(message, "b", &b);
206 if (r < 0)
207 return r;
8e2af478
LP
208
209 if (mode != UNIT_CHECK) {
8e2af478 210 c->blockio_accounting = b;
3051f187 211 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
b9ec9359 212 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
8e2af478
LP
213 }
214
215 return 1;
b42defe3
LP
216
217 } else if (streq(name, "BlockIOWeight")) {
218 uint64_t u64;
219 unsigned long ul;
220
718db961
LP
221 r = sd_bus_message_read(message, "t", &u64);
222 if (r < 0)
223 return r;
b42defe3 224
b42defe3 225 ul = (unsigned long) u64;
718db961
LP
226 if (ul < 10 || ul > 1000)
227 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
b42defe3
LP
228
229 if (mode != UNIT_CHECK) {
f2369103 230 c->blockio_weight = ul;
3051f187 231 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
b9ec9359 232 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
b42defe3
LP
233 }
234
235 return 1;
236
f004c2ca 237 } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
718db961 238 const char *path;
f004c2ca 239 bool read = true;
718db961
LP
240 unsigned n = 0;
241 uint64_t u64;
f004c2ca
G
242
243 if (streq(name, "BlockIOWriteBandwidth"))
244 read = false;
245
718db961
LP
246 r = sd_bus_message_enter_container(message, 'a', "(st)");
247 if (r < 0)
248 return r;
f004c2ca 249
718db961 250 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
f004c2ca
G
251
252 if (mode != UNIT_CHECK) {
718db961 253 CGroupBlockIODeviceBandwidth *a = NULL, *b;
f004c2ca
G
254
255 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
256 if (path_equal(path, b->path) && read == b->read) {
257 a = b;
f004c2ca
G
258 break;
259 }
260 }
261
718db961 262 if (!a) {
f004c2ca
G
263 a = new0(CGroupBlockIODeviceBandwidth, 1);
264 if (!a)
265 return -ENOMEM;
266
267 a->read = read;
268 a->path = strdup(path);
269 if (!a->path) {
270 free(a);
271 return -ENOMEM;
272 }
718db961
LP
273
274 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
f004c2ca
G
275 }
276
277 a->bandwidth = u64;
f004c2ca
G
278 }
279
280 n++;
f004c2ca 281 }
718db961
LP
282 if (r < 0)
283 return r;
f004c2ca 284
9c96019d
LP
285 r = sd_bus_message_exit_container(message);
286 if (r < 0)
287 return r;
288
f004c2ca 289 if (mode != UNIT_CHECK) {
718db961 290 CGroupBlockIODeviceBandwidth *a, *next;
f004c2ca
G
291 _cleanup_free_ char *buf = NULL;
292 _cleanup_fclose_ FILE *f = NULL;
f004c2ca
G
293 size_t size = 0;
294
295 if (n == 0) {
296 LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
297 if (a->read == read)
298 cgroup_context_free_blockio_device_bandwidth(c, a);
299 }
300
3051f187
LP
301 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
302
f004c2ca
G
303 f = open_memstream(&buf, &size);
304 if (!f)
305 return -ENOMEM;
306
307 if (read) {
308 fputs("BlockIOReadBandwidth=\n", f);
309 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
310 if (a->read)
311 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
312 } else {
313 fputs("BlockIOWriteBandwidth=\n", f);
314 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
315 if (!a->read)
316 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
317 }
318
6f68ecb4
G
319 fflush(f);
320 unit_write_drop_in_private(u, mode, name, buf);
321 }
322
323 return 1;
324
325 } else if (streq(name, "BlockIODeviceWeight")) {
718db961
LP
326 const char *path;
327 uint64_t u64;
6f68ecb4
G
328 unsigned n = 0;
329
718db961
LP
330 r = sd_bus_message_enter_container(message, 'a', "(st)");
331 if (r < 0)
332 return r;
6f68ecb4 333
ccd06097
ZJS
334 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
335 unsigned long ul = u64;
6f68ecb4 336
6f68ecb4 337 if (ul < 10 || ul > 1000)
718db961 338 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
6f68ecb4
G
339
340 if (mode != UNIT_CHECK) {
718db961 341 CGroupBlockIODeviceWeight *a = NULL, *b;
6f68ecb4
G
342
343 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
344 if (path_equal(b->path, path)) {
345 a = b;
6f68ecb4
G
346 break;
347 }
348 }
349
718db961 350 if (!a) {
6f68ecb4
G
351 a = new0(CGroupBlockIODeviceWeight, 1);
352 if (!a)
353 return -ENOMEM;
354
355 a->path = strdup(path);
356 if (!a->path) {
357 free(a);
358 return -ENOMEM;
359 }
718db961 360 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
6f68ecb4
G
361 }
362
363 a->weight = ul;
6f68ecb4
G
364 }
365
366 n++;
6f68ecb4
G
367 }
368
9c96019d
LP
369 r = sd_bus_message_exit_container(message);
370 if (r < 0)
371 return r;
372
6f68ecb4
G
373 if (mode != UNIT_CHECK) {
374 _cleanup_free_ char *buf = NULL;
375 _cleanup_fclose_ FILE *f = NULL;
376 CGroupBlockIODeviceWeight *a;
377 size_t size = 0;
378
379 if (n == 0) {
380 while (c->blockio_device_weights)
381 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
382 }
383
3051f187
LP
384 u->cgroup_realized_mask &= ~CGROUP_BLKIO;
385
6f68ecb4
G
386 f = open_memstream(&buf, &size);
387 if (!f)
388 return -ENOMEM;
389
390 fputs("BlockIODeviceWeight=\n", f);
391 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
392 fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
393
f004c2ca
G
394 fflush(f);
395 unit_write_drop_in_private(u, mode, name, buf);
396 }
397
398 return 1;
399
8e2af478 400 } else if (streq(name, "MemoryAccounting")) {
718db961 401 int b;
8e2af478 402
718db961
LP
403 r = sd_bus_message_read(message, "b", &b);
404 if (r < 0)
405 return r;
8e2af478
LP
406
407 if (mode != UNIT_CHECK) {
b42defe3 408 c->memory_accounting = b;
3051f187 409 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
b9ec9359 410 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
8e2af478
LP
411 }
412
413 return 1;
8e2af478 414
ddca82ac 415 } else if (streq(name, "MemoryLimit")) {
718db961 416 uint64_t limit;
b42defe3 417
718db961
LP
418 r = sd_bus_message_read(message, "t", &limit);
419 if (r < 0)
420 return r;
b42defe3
LP
421
422 if (mode != UNIT_CHECK) {
ddca82ac 423 c->memory_limit = limit;
3051f187 424 u->cgroup_realized_mask &= ~CGROUP_MEMORY;
b9ec9359 425 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
b42defe3
LP
426 }
427
7041efe9
LP
428 return 1;
429
430 } else if (streq(name, "DevicePolicy")) {
431 const char *policy;
432 CGroupDevicePolicy p;
433
718db961
LP
434 r = sd_bus_message_read(message, "s", &policy);
435 if (r < 0)
436 return r;
7041efe9 437
7041efe9
LP
438 p = cgroup_device_policy_from_string(policy);
439 if (p < 0)
440 return -EINVAL;
441
442 if (mode != UNIT_CHECK) {
443 char *buf;
444
445 c->device_policy = p;
3051f187 446 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
7041efe9
LP
447
448 buf = strappenda("DevicePolicy=", policy);
b9ec9359 449 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
450 }
451
452 return 1;
453
454 } else if (streq(name, "DeviceAllow")) {
718db961 455 const char *path, *rwm;
7041efe9
LP
456 unsigned n = 0;
457
718db961
LP
458 r = sd_bus_message_enter_container(message, 'a', "(ss)");
459 if (r < 0)
460 return r;
7041efe9 461
718db961 462 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
7041efe9 463
90060676
LP
464 if ((!startswith(path, "/dev/") &&
465 !startswith(path, "block-") &&
466 !startswith(path, "char-")) ||
467 strpbrk(path, WHITESPACE))
468 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
7041efe9
LP
469
470 if (isempty(rwm))
471 rwm = "rwm";
472
718db961
LP
473 if (!in_charset(rwm, "rwm"))
474 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
7041efe9 475
7041efe9 476 if (mode != UNIT_CHECK) {
718db961 477 CGroupDeviceAllow *a = NULL, *b;
ad7bfffd
G
478
479 LIST_FOREACH(device_allow, b, c->device_allow) {
06eb4e3b 480 if (path_equal(b->path, path)) {
ad7bfffd 481 a = b;
ad7bfffd
G
482 break;
483 }
484 }
485
718db961 486 if (!a) {
ad7bfffd
G
487 a = new0(CGroupDeviceAllow, 1);
488 if (!a)
489 return -ENOMEM;
490
491 a->path = strdup(path);
492 if (!a->path) {
493 free(a);
494 return -ENOMEM;
495 }
718db961
LP
496
497 LIST_PREPEND(device_allow, c->device_allow, a);
7041efe9
LP
498 }
499
500 a->r = !!strchr(rwm, 'r');
501 a->w = !!strchr(rwm, 'w');
502 a->m = !!strchr(rwm, 'm');
7041efe9
LP
503 }
504
c2756a68 505 n++;
7041efe9 506 }
43a99a7a
LP
507 if (r < 0)
508 return r;
7041efe9 509
9c96019d
LP
510 r = sd_bus_message_exit_container(message);
511 if (r < 0)
512 return r;
513
7041efe9
LP
514 if (mode != UNIT_CHECK) {
515 _cleanup_free_ char *buf = NULL;
516 _cleanup_fclose_ FILE *f = NULL;
517 CGroupDeviceAllow *a;
518 size_t size = 0;
519
520 if (n == 0) {
521 while (c->device_allow)
522 cgroup_context_free_device_allow(c, c->device_allow);
523 }
524
3051f187
LP
525 u->cgroup_realized_mask &= ~CGROUP_DEVICE;
526
7041efe9
LP
527 f = open_memstream(&buf, &size);
528 if (!f)
529 return -ENOMEM;
530
531 fputs("DeviceAllow=\n", f);
532 LIST_FOREACH(device_allow, a, c->device_allow)
533 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
534
535 fflush(f);
b9ec9359 536 unit_write_drop_in_private(u, mode, name, buf);
7041efe9
LP
537 }
538
b42defe3
LP
539 return 1;
540 }
8e2af478
LP
541
542 return 0;
543}