]> git.proxmox.com Git - systemd.git/blame - src/core/dbus-cgroup.c
Imported Upstream version 231
[systemd.git] / src / core / dbus-cgroup.c
CommitLineData
14228c0d
MB
1/***
2 This file is part of systemd.
3
4 Copyright 2013 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
db2df898 20#include "alloc-util.h"
60f067b4 21#include "bus-util.h"
60f067b4
JS
22#include "cgroup-util.h"
23#include "cgroup.h"
14228c0d 24#include "dbus-cgroup.h"
db2df898
MP
25#include "fd-util.h"
26#include "fileio.h"
27#include "path-util.h"
14228c0d 28
60f067b4
JS
29static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
30
aa27b158
MP
31static int property_get_io_device_weight(
32 sd_bus *bus,
33 const char *path,
34 const char *interface,
35 const char *property,
36 sd_bus_message *reply,
37 void *userdata,
38 sd_bus_error *error) {
39
40 CGroupContext *c = userdata;
41 CGroupIODeviceWeight *w;
42 int r;
43
44 assert(bus);
45 assert(reply);
46 assert(c);
47
48 r = sd_bus_message_open_container(reply, 'a', "(st)");
49 if (r < 0)
50 return r;
51
52 LIST_FOREACH(device_weights, w, c->io_device_weights) {
53 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
54 if (r < 0)
55 return r;
56 }
57
58 return sd_bus_message_close_container(reply);
59}
60
61static int property_get_io_device_limits(
62 sd_bus *bus,
63 const char *path,
64 const char *interface,
65 const char *property,
66 sd_bus_message *reply,
67 void *userdata,
68 sd_bus_error *error) {
69
70 CGroupContext *c = userdata;
71 CGroupIODeviceLimit *l;
72 int r;
73
74 assert(bus);
75 assert(reply);
76 assert(c);
77
78 r = sd_bus_message_open_container(reply, 'a', "(st)");
79 if (r < 0)
80 return r;
81
82 LIST_FOREACH(device_limits, l, c->io_device_limits) {
83 CGroupIOLimitType type;
84
85 type = cgroup_io_limit_type_from_string(property);
86 if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
87 continue;
88
89 r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
90 if (r < 0)
91 return r;
92 }
93
94 return sd_bus_message_close_container(reply);
95}
96
60f067b4
JS
97static int property_get_blockio_device_weight(
98 sd_bus *bus,
99 const char *path,
100 const char *interface,
101 const char *property,
102 sd_bus_message *reply,
103 void *userdata,
104 sd_bus_error *error) {
14228c0d 105
60f067b4 106 CGroupContext *c = userdata;
14228c0d 107 CGroupBlockIODeviceWeight *w;
60f067b4 108 int r;
14228c0d 109
60f067b4
JS
110 assert(bus);
111 assert(reply);
14228c0d
MB
112 assert(c);
113
60f067b4
JS
114 r = sd_bus_message_open_container(reply, 'a', "(st)");
115 if (r < 0)
116 return r;
14228c0d
MB
117
118 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
60f067b4
JS
119 r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
120 if (r < 0)
121 return r;
14228c0d
MB
122 }
123
60f067b4 124 return sd_bus_message_close_container(reply);
14228c0d
MB
125}
126
60f067b4
JS
127static int property_get_blockio_device_bandwidths(
128 sd_bus *bus,
129 const char *path,
130 const char *interface,
131 const char *property,
132 sd_bus_message *reply,
133 void *userdata,
134 sd_bus_error *error) {
135
136 CGroupContext *c = userdata;
14228c0d 137 CGroupBlockIODeviceBandwidth *b;
60f067b4 138 int r;
14228c0d 139
60f067b4
JS
140 assert(bus);
141 assert(reply);
14228c0d
MB
142 assert(c);
143
60f067b4
JS
144 r = sd_bus_message_open_container(reply, 'a', "(st)");
145 if (r < 0)
146 return r;
14228c0d
MB
147
148 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
aa27b158
MP
149 uint64_t v;
150
151 if (streq(property, "BlockIOReadBandwidth"))
152 v = b->rbps;
153 else
154 v = b->wbps;
14228c0d 155
aa27b158 156 if (v == CGROUP_LIMIT_MAX)
14228c0d
MB
157 continue;
158
aa27b158 159 r = sd_bus_message_append(reply, "(st)", b->path, v);
60f067b4
JS
160 if (r < 0)
161 return r;
14228c0d
MB
162 }
163
60f067b4 164 return sd_bus_message_close_container(reply);
14228c0d
MB
165}
166
60f067b4
JS
167static int property_get_device_allow(
168 sd_bus *bus,
169 const char *path,
170 const char *interface,
171 const char *property,
172 sd_bus_message *reply,
173 void *userdata,
174 sd_bus_error *error) {
175
176 CGroupContext *c = userdata;
14228c0d 177 CGroupDeviceAllow *a;
60f067b4 178 int r;
14228c0d 179
60f067b4
JS
180 assert(bus);
181 assert(reply);
14228c0d
MB
182 assert(c);
183
60f067b4
JS
184 r = sd_bus_message_open_container(reply, 'a', "(ss)");
185 if (r < 0)
186 return r;
14228c0d
MB
187
188 LIST_FOREACH(device_allow, a, c->device_allow) {
14228c0d 189 unsigned k = 0;
60f067b4 190 char rwm[4];
14228c0d
MB
191
192 if (a->r)
60f067b4 193 rwm[k++] = 'r';
14228c0d 194 if (a->w)
60f067b4 195 rwm[k++] = 'w';
14228c0d 196 if (a->m)
60f067b4 197 rwm[k++] = 'm';
14228c0d 198
60f067b4 199 rwm[k] = 0;
14228c0d 200
60f067b4
JS
201 r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
202 if (r < 0)
203 return r;
14228c0d
MB
204 }
205
60f067b4
JS
206 return sd_bus_message_close_container(reply);
207}
208
60f067b4
JS
209const sd_bus_vtable bus_cgroup_vtable[] = {
210 SD_BUS_VTABLE_START(0),
f47781d8 211 SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
60f067b4 212 SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
6300502b
MP
213 SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
214 SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
5eef597e 215 SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
aa27b158
MP
216 SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
217 SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
218 SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
219 SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
220 SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
221 SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
222 SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
223 SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
60f067b4 224 SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
6300502b
MP
225 SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
226 SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
60f067b4
JS
227 SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
228 SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
229 SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
230 SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
5a920b42
MP
231 SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
232 SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
233 SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
60f067b4
JS
234 SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
235 SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
236 SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
6300502b
MP
237 SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
238 SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
60f067b4 239 SD_BUS_VTABLE_END
14228c0d
MB
240};
241
f47781d8
MP
242static int bus_cgroup_set_transient_property(
243 Unit *u,
244 CGroupContext *c,
245 const char *name,
246 sd_bus_message *message,
247 UnitSetPropertiesMode mode,
248 sd_bus_error *error) {
249
250 int r;
251
252 assert(u);
253 assert(c);
254 assert(name);
255 assert(message);
256
257 if (streq(name, "Delegate")) {
258 int b;
259
260 r = sd_bus_message_read(message, "b", &b);
261 if (r < 0)
262 return r;
263
264 if (mode != UNIT_CHECK) {
265 c->delegate = b;
266 unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
267 }
268
269 return 1;
270 }
271
272 return 0;
273}
274
14228c0d
MB
275int bus_cgroup_set_property(
276 Unit *u,
277 CGroupContext *c,
278 const char *name,
60f067b4 279 sd_bus_message *message,
14228c0d 280 UnitSetPropertiesMode mode,
60f067b4
JS
281 sd_bus_error *error) {
282
aa27b158 283 CGroupIOLimitType iol_type;
60f067b4 284 int r;
14228c0d 285
14228c0d
MB
286 assert(u);
287 assert(c);
60f067b4
JS
288 assert(name);
289 assert(message);
14228c0d
MB
290
291 if (streq(name, "CPUAccounting")) {
60f067b4 292 int b;
14228c0d 293
60f067b4
JS
294 r = sd_bus_message_read(message, "b", &b);
295 if (r < 0)
296 return r;
14228c0d
MB
297
298 if (mode != UNIT_CHECK) {
14228c0d 299 c->cpu_accounting = b;
6300502b 300 unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
14228c0d
MB
301 unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
302 }
303
304 return 1;
305
306 } else if (streq(name, "CPUShares")) {
6300502b 307 uint64_t shares;
14228c0d 308
6300502b 309 r = sd_bus_message_read(message, "t", &shares);
60f067b4
JS
310 if (r < 0)
311 return r;
14228c0d 312
6300502b
MP
313 if (!CGROUP_CPU_SHARES_IS_OK(shares))
314 return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
14228c0d
MB
315
316 if (mode != UNIT_CHECK) {
6300502b
MP
317 c->cpu_shares = shares;
318 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
319
320 if (shares == CGROUP_CPU_SHARES_INVALID)
321 unit_write_drop_in_private(u, mode, name, "CPUShares=");
322 else
323 unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares);
14228c0d
MB
324 }
325
326 return 1;
327
60f067b4 328 } else if (streq(name, "StartupCPUShares")) {
6300502b 329 uint64_t shares;
14228c0d 330
6300502b 331 r = sd_bus_message_read(message, "t", &shares);
60f067b4
JS
332 if (r < 0)
333 return r;
334
6300502b
MP
335 if (!CGROUP_CPU_SHARES_IS_OK(shares))
336 return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
60f067b4
JS
337
338 if (mode != UNIT_CHECK) {
6300502b
MP
339 c->startup_cpu_shares = shares;
340 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
341
342 if (shares == CGROUP_CPU_SHARES_INVALID)
343 unit_write_drop_in_private(u, mode, name, "StartupCPUShares=");
344 else
345 unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares);
60f067b4
JS
346 }
347
348 return 1;
349
350 } else if (streq(name, "CPUQuotaPerSecUSec")) {
351 uint64_t u64;
352
353 r = sd_bus_message_read(message, "t", &u64);
354 if (r < 0)
355 return r;
356
357 if (u64 <= 0)
358 return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
14228c0d
MB
359
360 if (mode != UNIT_CHECK) {
60f067b4 361 c->cpu_quota_per_sec_usec = u64;
6300502b 362 unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
60f067b4
JS
363 unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
364 }
365
366 return 1;
367
aa27b158
MP
368 } else if (streq(name, "IOAccounting")) {
369 int b;
370
371 r = sd_bus_message_read(message, "b", &b);
372 if (r < 0)
373 return r;
374
375 if (mode != UNIT_CHECK) {
376 c->io_accounting = b;
377 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
378 unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no");
379 }
380
381 return 1;
382
383 } else if (streq(name, "IOWeight")) {
384 uint64_t weight;
385
386 r = sd_bus_message_read(message, "t", &weight);
387 if (r < 0)
388 return r;
389
390 if (!CGROUP_WEIGHT_IS_OK(weight))
391 return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range");
392
393 if (mode != UNIT_CHECK) {
394 c->io_weight = weight;
395 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
396
397 if (weight == CGROUP_WEIGHT_INVALID)
398 unit_write_drop_in_private(u, mode, name, "IOWeight=");
399 else
400 unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight);
401 }
402
403 return 1;
404
405 } else if (streq(name, "StartupIOWeight")) {
406 uint64_t weight;
407
408 r = sd_bus_message_read(message, "t", &weight);
409 if (r < 0)
410 return r;
411
412 if (CGROUP_WEIGHT_IS_OK(weight))
413 return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range");
414
415 if (mode != UNIT_CHECK) {
416 c->startup_io_weight = weight;
417 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
418
419 if (weight == CGROUP_WEIGHT_INVALID)
420 unit_write_drop_in_private(u, mode, name, "StartupIOWeight=");
421 else
422 unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight);
423 }
424
425 return 1;
426
427 } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
428 const char *path;
429 unsigned n = 0;
430 uint64_t u64;
431
432 r = sd_bus_message_enter_container(message, 'a', "(st)");
433 if (r < 0)
434 return r;
435
436 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
437
438 if (mode != UNIT_CHECK) {
439 CGroupIODeviceLimit *a = NULL, *b;
440
441 LIST_FOREACH(device_limits, b, c->io_device_limits) {
442 if (path_equal(path, b->path)) {
443 a = b;
444 break;
445 }
446 }
447
448 if (!a) {
449 CGroupIOLimitType type;
450
451 a = new0(CGroupIODeviceLimit, 1);
452 if (!a)
453 return -ENOMEM;
454
455 a->path = strdup(path);
456 if (!a->path) {
457 free(a);
458 return -ENOMEM;
459 }
460
461 for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
462 a->limits[type] = cgroup_io_limit_defaults[type];
463
464 LIST_PREPEND(device_limits, c->io_device_limits, a);
465 }
466
467 a->limits[iol_type] = u64;
468 }
469
470 n++;
471 }
472 if (r < 0)
473 return r;
474
475 r = sd_bus_message_exit_container(message);
476 if (r < 0)
477 return r;
478
479 if (mode != UNIT_CHECK) {
480 CGroupIODeviceLimit *a;
481 _cleanup_free_ char *buf = NULL;
482 _cleanup_fclose_ FILE *f = NULL;
483 size_t size = 0;
484
485 if (n == 0) {
486 LIST_FOREACH(device_limits, a, c->io_device_limits)
487 a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
488 }
489
490 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
491
492 f = open_memstream(&buf, &size);
493 if (!f)
494 return -ENOMEM;
495
496 fprintf(f, "%s=\n", name);
497 LIST_FOREACH(device_limits, a, c->io_device_limits)
498 if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
499 fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
500
501 r = fflush_and_check(f);
502 if (r < 0)
503 return r;
504 unit_write_drop_in_private(u, mode, name, buf);
505 }
506
507 return 1;
508
509 } else if (streq(name, "IODeviceWeight")) {
510 const char *path;
511 uint64_t weight;
512 unsigned n = 0;
513
514 r = sd_bus_message_enter_container(message, 'a', "(st)");
515 if (r < 0)
516 return r;
517
518 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
519
520 if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
521 return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range");
522
523 if (mode != UNIT_CHECK) {
524 CGroupIODeviceWeight *a = NULL, *b;
525
526 LIST_FOREACH(device_weights, b, c->io_device_weights) {
527 if (path_equal(b->path, path)) {
528 a = b;
529 break;
530 }
531 }
532
533 if (!a) {
534 a = new0(CGroupIODeviceWeight, 1);
535 if (!a)
536 return -ENOMEM;
537
538 a->path = strdup(path);
539 if (!a->path) {
540 free(a);
541 return -ENOMEM;
542 }
543 LIST_PREPEND(device_weights,c->io_device_weights, a);
544 }
545
546 a->weight = weight;
547 }
548
549 n++;
550 }
551
552 r = sd_bus_message_exit_container(message);
553 if (r < 0)
554 return r;
555
556 if (mode != UNIT_CHECK) {
557 _cleanup_free_ char *buf = NULL;
558 _cleanup_fclose_ FILE *f = NULL;
559 CGroupIODeviceWeight *a;
560 size_t size = 0;
561
562 if (n == 0) {
563 while (c->io_device_weights)
564 cgroup_context_free_io_device_weight(c, c->io_device_weights);
565 }
566
567 unit_invalidate_cgroup(u, CGROUP_MASK_IO);
568
569 f = open_memstream(&buf, &size);
570 if (!f)
571 return -ENOMEM;
572
573 fputs("IODeviceWeight=\n", f);
574 LIST_FOREACH(device_weights, a, c->io_device_weights)
575 fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
576
577 r = fflush_and_check(f);
578 if (r < 0)
579 return r;
580 unit_write_drop_in_private(u, mode, name, buf);
581 }
582
583 return 1;
584
60f067b4
JS
585 } else if (streq(name, "BlockIOAccounting")) {
586 int b;
587
588 r = sd_bus_message_read(message, "b", &b);
589 if (r < 0)
590 return r;
14228c0d 591
60f067b4 592 if (mode != UNIT_CHECK) {
14228c0d 593 c->blockio_accounting = b;
6300502b 594 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
14228c0d
MB
595 unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
596 }
597
598 return 1;
599
600 } else if (streq(name, "BlockIOWeight")) {
6300502b 601 uint64_t weight;
14228c0d 602
6300502b 603 r = sd_bus_message_read(message, "t", &weight);
60f067b4
JS
604 if (r < 0)
605 return r;
14228c0d 606
6300502b
MP
607 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
608 return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
14228c0d
MB
609
610 if (mode != UNIT_CHECK) {
6300502b
MP
611 c->blockio_weight = weight;
612 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
613
614 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
615 unit_write_drop_in_private(u, mode, name, "BlockIOWeight=");
616 else
617 unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight);
14228c0d
MB
618 }
619
620 return 1;
621
60f067b4 622 } else if (streq(name, "StartupBlockIOWeight")) {
6300502b 623 uint64_t weight;
60f067b4 624
6300502b 625 r = sd_bus_message_read(message, "t", &weight);
60f067b4
JS
626 if (r < 0)
627 return r;
628
5a920b42 629 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
6300502b 630 return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
60f067b4
JS
631
632 if (mode != UNIT_CHECK) {
6300502b
MP
633 c->startup_blockio_weight = weight;
634 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
635
636 if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
637 unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=");
638 else
639 unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight);
60f067b4
JS
640 }
641
642 return 1;
643
5a920b42 644 } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
60f067b4 645 const char *path;
14228c0d 646 bool read = true;
60f067b4
JS
647 unsigned n = 0;
648 uint64_t u64;
14228c0d
MB
649
650 if (streq(name, "BlockIOWriteBandwidth"))
651 read = false;
652
60f067b4
JS
653 r = sd_bus_message_enter_container(message, 'a', "(st)");
654 if (r < 0)
655 return r;
14228c0d 656
60f067b4 657 while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
14228c0d
MB
658
659 if (mode != UNIT_CHECK) {
60f067b4 660 CGroupBlockIODeviceBandwidth *a = NULL, *b;
14228c0d
MB
661
662 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
aa27b158 663 if (path_equal(path, b->path)) {
14228c0d 664 a = b;
14228c0d
MB
665 break;
666 }
667 }
668
60f067b4 669 if (!a) {
14228c0d
MB
670 a = new0(CGroupBlockIODeviceBandwidth, 1);
671 if (!a)
672 return -ENOMEM;
673
aa27b158
MP
674 a->rbps = CGROUP_LIMIT_MAX;
675 a->wbps = CGROUP_LIMIT_MAX;
14228c0d
MB
676 a->path = strdup(path);
677 if (!a->path) {
678 free(a);
679 return -ENOMEM;
680 }
60f067b4
JS
681
682 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
14228c0d
MB
683 }
684
aa27b158
MP
685 if (read)
686 a->rbps = u64;
687 else
688 a->wbps = u64;
14228c0d
MB
689 }
690
691 n++;
14228c0d 692 }
60f067b4
JS
693 if (r < 0)
694 return r;
695
696 r = sd_bus_message_exit_container(message);
697 if (r < 0)
698 return r;
14228c0d
MB
699
700 if (mode != UNIT_CHECK) {
aa27b158 701 CGroupBlockIODeviceBandwidth *a;
14228c0d
MB
702 _cleanup_free_ char *buf = NULL;
703 _cleanup_fclose_ FILE *f = NULL;
14228c0d
MB
704 size_t size = 0;
705
706 if (n == 0) {
aa27b158
MP
707 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
708 if (read)
709 a->rbps = CGROUP_LIMIT_MAX;
710 else
711 a->wbps = CGROUP_LIMIT_MAX;
712 }
14228c0d
MB
713 }
714
6300502b 715 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
60f067b4 716
14228c0d
MB
717 f = open_memstream(&buf, &size);
718 if (!f)
719 return -ENOMEM;
720
13d276d0 721 if (read) {
14228c0d 722 fputs("BlockIOReadBandwidth=\n", f);
13d276d0 723 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
aa27b158
MP
724 if (a->rbps != CGROUP_LIMIT_MAX)
725 fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
14228c0d
MB
726 } else {
727 fputs("BlockIOWriteBandwidth=\n", f);
728 LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
aa27b158
MP
729 if (a->wbps != CGROUP_LIMIT_MAX)
730 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
14228c0d
MB
731 }
732
db2df898
MP
733 r = fflush_and_check(f);
734 if (r < 0)
735 return r;
14228c0d
MB
736 unit_write_drop_in_private(u, mode, name, buf);
737 }
738
739 return 1;
740
741 } else if (streq(name, "BlockIODeviceWeight")) {
60f067b4 742 const char *path;
6300502b 743 uint64_t weight;
14228c0d
MB
744 unsigned n = 0;
745
60f067b4
JS
746 r = sd_bus_message_enter_container(message, 'a', "(st)");
747 if (r < 0)
748 return r;
14228c0d 749
6300502b 750 while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
14228c0d 751
6300502b 752 if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
60f067b4 753 return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
14228c0d
MB
754
755 if (mode != UNIT_CHECK) {
60f067b4 756 CGroupBlockIODeviceWeight *a = NULL, *b;
14228c0d
MB
757
758 LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
759 if (path_equal(b->path, path)) {
760 a = b;
14228c0d
MB
761 break;
762 }
763 }
764
60f067b4 765 if (!a) {
14228c0d
MB
766 a = new0(CGroupBlockIODeviceWeight, 1);
767 if (!a)
768 return -ENOMEM;
769
770 a->path = strdup(path);
771 if (!a->path) {
772 free(a);
773 return -ENOMEM;
774 }
60f067b4 775 LIST_PREPEND(device_weights,c->blockio_device_weights, a);
14228c0d
MB
776 }
777
6300502b 778 a->weight = weight;
14228c0d
MB
779 }
780
781 n++;
14228c0d
MB
782 }
783
60f067b4
JS
784 r = sd_bus_message_exit_container(message);
785 if (r < 0)
786 return r;
787
14228c0d
MB
788 if (mode != UNIT_CHECK) {
789 _cleanup_free_ char *buf = NULL;
790 _cleanup_fclose_ FILE *f = NULL;
791 CGroupBlockIODeviceWeight *a;
792 size_t size = 0;
793
794 if (n == 0) {
795 while (c->blockio_device_weights)
796 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
797 }
798
6300502b 799 unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
60f067b4 800
14228c0d
MB
801 f = open_memstream(&buf, &size);
802 if (!f)
803 return -ENOMEM;
804
805 fputs("BlockIODeviceWeight=\n", f);
806 LIST_FOREACH(device_weights, a, c->blockio_device_weights)
6300502b 807 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
14228c0d 808
db2df898
MP
809 r = fflush_and_check(f);
810 if (r < 0)
811 return r;
14228c0d
MB
812 unit_write_drop_in_private(u, mode, name, buf);
813 }
814
815 return 1;
816
817 } else if (streq(name, "MemoryAccounting")) {
60f067b4 818 int b;
14228c0d 819
60f067b4
JS
820 r = sd_bus_message_read(message, "b", &b);
821 if (r < 0)
822 return r;
14228c0d
MB
823
824 if (mode != UNIT_CHECK) {
14228c0d 825 c->memory_accounting = b;
6300502b 826 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
14228c0d
MB
827 unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
828 }
829
830 return 1;
831
5a920b42
MP
832 } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax")) {
833 uint64_t v;
834
835 r = sd_bus_message_read(message, "t", &v);
836 if (r < 0)
837 return r;
838 if (v <= 0)
839 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
840
841 if (mode != UNIT_CHECK) {
842 if (streq(name, "MemoryLow"))
843 c->memory_low = v;
844 else if (streq(name, "MemoryHigh"))
845 c->memory_high = v;
846 else
847 c->memory_max = v;
848
849 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
850
851 if (v == CGROUP_LIMIT_MAX)
852 unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name);
853 else
854 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v);
855 }
856
857 return 1;
858
859 } else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale")) {
860 uint32_t raw;
861 uint64_t v;
862
863 r = sd_bus_message_read(message, "u", &raw);
864 if (r < 0)
865 return r;
866
867 v = physical_memory_scale(raw, UINT32_MAX);
868 if (v <= 0 || v == UINT64_MAX)
869 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
870
871 if (mode != UNIT_CHECK) {
872 const char *e;
873
874 /* Chop off suffix */
875 assert_se(e = endswith(name, "Scale"));
876 name = strndupa(name, e - name);
877
878 if (streq(name, "MemoryLow"))
879 c->memory_low = v;
880 else if (streq(name, "MemoryHigh"))
881 c->memory_high = v;
882 else
883 c->memory_max = v;
884
885 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
886 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name,
887 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
888 }
889
890 return 1;
891
14228c0d 892 } else if (streq(name, "MemoryLimit")) {
60f067b4 893 uint64_t limit;
14228c0d 894
60f067b4
JS
895 r = sd_bus_message_read(message, "t", &limit);
896 if (r < 0)
897 return r;
5a920b42
MP
898 if (limit <= 0)
899 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
14228c0d
MB
900
901 if (mode != UNIT_CHECK) {
14228c0d 902 c->memory_limit = limit;
6300502b
MP
903 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
904
905 if (limit == (uint64_t) -1)
906 unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
907 else
908 unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
14228c0d
MB
909 }
910
911 return 1;
912
5a920b42
MP
913 } else if (streq(name, "MemoryLimitScale")) {
914 uint64_t limit;
915 uint32_t raw;
916
917 r = sd_bus_message_read(message, "u", &raw);
918 if (r < 0)
919 return r;
920
921 limit = physical_memory_scale(raw, UINT32_MAX);
922 if (limit <= 0 || limit == UINT64_MAX)
923 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
924
925 if (mode != UNIT_CHECK) {
926 c->memory_limit = limit;
927 unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
928 unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
929 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
930 }
931
932 return 1;
933
14228c0d
MB
934 } else if (streq(name, "DevicePolicy")) {
935 const char *policy;
936 CGroupDevicePolicy p;
937
60f067b4
JS
938 r = sd_bus_message_read(message, "s", &policy);
939 if (r < 0)
940 return r;
14228c0d 941
14228c0d
MB
942 p = cgroup_device_policy_from_string(policy);
943 if (p < 0)
944 return -EINVAL;
945
946 if (mode != UNIT_CHECK) {
14228c0d 947 c->device_policy = p;
6300502b 948 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
5a920b42 949 unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s", policy);
14228c0d
MB
950 }
951
952 return 1;
953
954 } else if (streq(name, "DeviceAllow")) {
60f067b4 955 const char *path, *rwm;
14228c0d
MB
956 unsigned n = 0;
957
60f067b4
JS
958 r = sd_bus_message_enter_container(message, 'a', "(ss)");
959 if (r < 0)
960 return r;
14228c0d 961
60f067b4 962 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
14228c0d 963
60f067b4 964 if ((!startswith(path, "/dev/") &&
5a920b42 965 !startswith(path, "/run/systemd/inaccessible/") &&
60f067b4
JS
966 !startswith(path, "block-") &&
967 !startswith(path, "char-")) ||
968 strpbrk(path, WHITESPACE))
969 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
14228c0d
MB
970
971 if (isempty(rwm))
972 rwm = "rwm";
973
60f067b4
JS
974 if (!in_charset(rwm, "rwm"))
975 return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
14228c0d
MB
976
977 if (mode != UNIT_CHECK) {
60f067b4 978 CGroupDeviceAllow *a = NULL, *b;
14228c0d
MB
979
980 LIST_FOREACH(device_allow, b, c->device_allow) {
981 if (path_equal(b->path, path)) {
982 a = b;
14228c0d
MB
983 break;
984 }
985 }
986
60f067b4 987 if (!a) {
14228c0d
MB
988 a = new0(CGroupDeviceAllow, 1);
989 if (!a)
990 return -ENOMEM;
991
992 a->path = strdup(path);
993 if (!a->path) {
994 free(a);
995 return -ENOMEM;
996 }
60f067b4
JS
997
998 LIST_PREPEND(device_allow, c->device_allow, a);
14228c0d
MB
999 }
1000
1001 a->r = !!strchr(rwm, 'r');
1002 a->w = !!strchr(rwm, 'w');
1003 a->m = !!strchr(rwm, 'm');
14228c0d
MB
1004 }
1005
1006 n++;
14228c0d 1007 }
60f067b4
JS
1008 if (r < 0)
1009 return r;
1010
1011 r = sd_bus_message_exit_container(message);
1012 if (r < 0)
1013 return r;
14228c0d
MB
1014
1015 if (mode != UNIT_CHECK) {
1016 _cleanup_free_ char *buf = NULL;
1017 _cleanup_fclose_ FILE *f = NULL;
1018 CGroupDeviceAllow *a;
1019 size_t size = 0;
1020
1021 if (n == 0) {
1022 while (c->device_allow)
1023 cgroup_context_free_device_allow(c, c->device_allow);
1024 }
1025
6300502b 1026 unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
60f067b4 1027
14228c0d
MB
1028 f = open_memstream(&buf, &size);
1029 if (!f)
1030 return -ENOMEM;
1031
1032 fputs("DeviceAllow=\n", f);
1033 LIST_FOREACH(device_allow, a, c->device_allow)
1034 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
1035
db2df898
MP
1036 r = fflush_and_check(f);
1037 if (r < 0)
1038 return r;
14228c0d
MB
1039 unit_write_drop_in_private(u, mode, name, buf);
1040 }
1041
1042 return 1;
f47781d8 1043
6300502b
MP
1044 } else if (streq(name, "TasksAccounting")) {
1045 int b;
1046
1047 r = sd_bus_message_read(message, "b", &b);
1048 if (r < 0)
1049 return r;
1050
1051 if (mode != UNIT_CHECK) {
1052 c->tasks_accounting = b;
1053 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1054 unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
1055 }
1056
1057 return 1;
1058
1059 } else if (streq(name, "TasksMax")) {
1060 uint64_t limit;
1061
1062 r = sd_bus_message_read(message, "t", &limit);
1063 if (r < 0)
1064 return r;
5a920b42
MP
1065 if (limit <= 0)
1066 return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
6300502b
MP
1067
1068 if (mode != UNIT_CHECK) {
1069 c->tasks_max = limit;
1070 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1071
1072 if (limit == (uint64_t) -1)
1073 unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
1074 else
1075 unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
1076 }
1077
5a920b42
MP
1078 return 1;
1079 } else if (streq(name, "TasksMaxScale")) {
1080 uint64_t limit;
1081 uint32_t raw;
1082
1083 r = sd_bus_message_read(message, "u", &raw);
1084 if (r < 0)
1085 return r;
1086
1087 limit = system_tasks_max_scale(raw, UINT32_MAX);
1088 if (limit <= 0 || limit >= UINT64_MAX)
1089 return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
1090
1091 if (mode != UNIT_CHECK) {
1092 c->tasks_max = limit;
1093 unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
1094 unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%",
1095 (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
1096 }
1097
6300502b 1098 return 1;
f47781d8
MP
1099 }
1100
1101 if (u->transient && u->load_state == UNIT_STUB) {
1102 r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
1103 if (r != 0)
1104 return r;
1105
14228c0d
MB
1106 }
1107
1108 return 0;
1109}