summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/architecture.c2
-rw-r--r--src/basic/architecture.h2
-rw-r--r--src/basic/cgroup-util.c41
-rw-r--r--src/basic/cgroup-util.h34
-rw-r--r--src/basic/ether-addr-util.c69
-rw-r--r--src/basic/ether-addr-util.h2
-rw-r--r--src/basic/missing.h4
-rw-r--r--src/basic/process-util.c2
-rw-r--r--src/basic/rm-rf.h6
-rw-r--r--src/basic/string-util.h1
-rw-r--r--src/cgtop/cgtop.c50
-rw-r--r--src/core/cgroup.c360
-rw-r--r--src/core/cgroup.h30
-rw-r--r--src/core/dbus-cgroup.c331
-rw-r--r--src/core/dbus-execute.c56
-rw-r--r--src/core/dbus-job.c2
-rw-r--r--src/core/job.c24
-rw-r--r--src/core/job.h2
-rw-r--r--src/core/load-fragment-gperf.gperf.m48
-rw-r--r--src/core/load-fragment.c232
-rw-r--r--src/core/load-fragment.h3
-rw-r--r--src/core/main.c3
-rw-r--r--src/core/manager.c2
-rw-r--r--src/core/manager.h1
-rw-r--r--src/core/namespace.c12
-rw-r--r--src/core/system.conf1
-rw-r--r--src/core/transaction.c2
-rw-r--r--src/core/unit.c18
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h2
-rw-r--r--src/libsystemd-network/dhcp6-internal.h3
-rw-r--r--src/libsystemd-network/icmp6-util.c9
-rw-r--r--src/libsystemd-network/network-internal.c15
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c31
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c28
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c45
-rw-r--r--src/libsystemd-network/test-ipv4ll.c9
-rw-r--r--src/libsystemd/sd-bus/busctl.c45
-rw-r--r--src/libsystemd/sd-device/sd-device.c6
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c18
-rw-r--r--src/login/70-uaccess.rules3
-rw-r--r--src/network/networkd-address.c39
-rw-r--r--src/network/networkd-dhcp4.c16
-rw-r--r--src/network/networkd-dhcp6.c10
-rw-r--r--src/network/networkd-ipv4ll.c4
-rw-r--r--src/network/networkd-link.c13
-rw-r--r--src/network/networkd-manager.c6
-rw-r--r--src/network/networkd-ndisc.c8
-rw-r--r--src/network/networkd-netdev-bridge.c7
-rw-r--r--src/network/networkd-netdev-bridge.h1
-rw-r--r--src/network/networkd-netdev-gperf.gperf1
-rw-r--r--src/network/networkd-netdev.c2
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c1
-rw-r--r--src/network/networkd-network.h1
-rw-r--r--src/network/networkd-route.c40
-rw-r--r--src/network/networkd-route.h1
-rw-r--r--src/network/test-networkd-conf.c51
-rw-r--r--src/nspawn/nspawn.c9
-rw-r--r--src/resolve/resolved-dns-server.c1
-rw-r--r--src/resolve/resolved-manager.c5
-rw-r--r--src/run/run.c7
-rw-r--r--src/shared/bus-unit-util.c31
-rw-r--r--src/shared/firewall-util.c6
-rw-r--r--src/systemctl/systemctl.c24
-rw-r--r--src/systemd/sd-dhcp-server.h1
-rw-r--r--src/test/test-cgroup-mask.c15
-rw-r--r--src/test/test-engine.c2
-rw-r--r--src/test/test-fileio.c2
-rw-r--r--src/test/test-path.c2
-rw-r--r--src/test/test-sched-prio.c2
-rw-r--r--src/test/test-unit-file.c2
-rw-r--r--src/udev/udevadm-info.c62
-rw-r--r--src/vconsole/vconsole-setup.c8
74 files changed, 1527 insertions, 370 deletions
diff --git a/src/basic/architecture.c b/src/basic/architecture.c
index 8e2c2b02d2..b1c8e91f50 100644
--- a/src/basic/architecture.c
+++ b/src/basic/architecture.c
@@ -63,7 +63,7 @@ int uname_architecture(void) {
#elif defined(__s390__) || defined(__s390x__)
{ "s390x", ARCHITECTURE_S390X },
{ "s390", ARCHITECTURE_S390 },
-#elif defined(__sparc__) || defined(__sparc64__)
+#elif defined(__sparc__)
{ "sparc64", ARCHITECTURE_SPARC64 },
{ "sparc", ARCHITECTURE_SPARC },
#elif defined(__mips__) || defined(__mips64__)
diff --git a/src/basic/architecture.h b/src/basic/architecture.h
index 91ec108e04..b3e4d85906 100644
--- a/src/basic/architecture.h
+++ b/src/basic/architecture.h
@@ -116,7 +116,7 @@ int uname_architecture(void);
#elif defined(__s390__)
# define native_architecture() ARCHITECTURE_S390
# define LIB_ARCH_TUPLE "s390-linux-gnu"
-#elif defined(__sparc64__)
+#elif defined(__sparc__) && defined (__arch64__)
# define native_architecture() ARCHITECTURE_SPARC64
# define LIB_ARCH_TUPLE "sparc64-linux-gnu"
#elif defined(__sparc__)
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 5043180747..7cdc97ee3c 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2060,10 +2060,10 @@ int cg_mask_supported(CGroupMask *ret) {
mask |= CGROUP_CONTROLLER_TO_MASK(v);
}
- /* Currently, we only support the memory and pids
+ /* Currently, we only support the memory, io and pids
* controller in the unified hierarchy, mask
* everything else off. */
- mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS;
+ mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
} else {
CGroupController c;
@@ -2249,6 +2249,42 @@ bool cg_is_legacy_wanted(void) {
return !cg_is_unified_wanted();
}
+int cg_weight_parse(const char *s, uint64_t *ret) {
+ uint64_t u;
+ int r;
+
+ if (isempty(s)) {
+ *ret = CGROUP_WEIGHT_INVALID;
+ return 0;
+ }
+
+ r = safe_atou64(s, &u);
+ if (r < 0)
+ return r;
+
+ if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX)
+ return -ERANGE;
+
+ *ret = u;
+ return 0;
+}
+
+const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
+ [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX,
+};
+
+static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = {
+ [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax",
+ [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax",
+ [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax",
+ [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
+
int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
uint64_t u;
int r;
@@ -2292,6 +2328,7 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
[CGROUP_CONTROLLER_CPU] = "cpu",
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
+ [CGROUP_CONTROLLER_IO] = "io",
[CGROUP_CONTROLLER_BLKIO] = "blkio",
[CGROUP_CONTROLLER_MEMORY] = "memory",
[CGROUP_CONTROLLER_DEVICES] = "devices",
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index 4254e51e5d..4bb5291296 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -34,6 +34,7 @@
typedef enum CGroupController {
CGROUP_CONTROLLER_CPU,
CGROUP_CONTROLLER_CPUACCT,
+ CGROUP_CONTROLLER_IO,
CGROUP_CONTROLLER_BLKIO,
CGROUP_CONTROLLER_MEMORY,
CGROUP_CONTROLLER_DEVICES,
@@ -48,6 +49,7 @@ typedef enum CGroupController {
typedef enum CGroupMask {
CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
+ CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
@@ -55,6 +57,37 @@ typedef enum CGroupMask {
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
} CGroupMask;
+/* Special values for all weight knobs on unified hierarchy */
+#define CGROUP_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_WEIGHT_MIN UINT64_C(1)
+#define CGROUP_WEIGHT_MAX UINT64_C(10000)
+#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
+
+#define CGROUP_LIMIT_MIN UINT64_C(0)
+#define CGROUP_LIMIT_MAX ((uint64_t) -1)
+
+static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_WEIGHT_INVALID ||
+ (x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX);
+}
+
+/* IO limits on unified hierarchy */
+typedef enum CGroupIOLimitType {
+ CGROUP_IO_RBPS_MAX,
+ CGROUP_IO_WBPS_MAX,
+ CGROUP_IO_RIOPS_MAX,
+ CGROUP_IO_WIOPS_MAX,
+
+ _CGROUP_IO_LIMIT_TYPE_MAX,
+ _CGROUP_IO_LIMIT_TYPE_INVALID = -1
+} CGroupIOLimitType;
+
+extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
+
+const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
+CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
+
/* Special values for the cpu.shares attribute */
#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
@@ -190,5 +223,6 @@ bool cg_is_legacy_wanted(void);
const char* cgroup_controller_to_string(CGroupController c) _const_;
CGroupController cgroup_controller_from_string(const char *s) _pure_;
+int cg_weight_parse(const char *s, uint64_t *ret);
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
int cg_blkio_weight_parse(const char *s, uint64_t *ret);
diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c
index a4d8d656da..5697e8d132 100644
--- a/src/basic/ether-addr-util.c
+++ b/src/basic/ether-addr-util.c
@@ -23,6 +23,7 @@
#include "ether-addr-util.h"
#include "macro.h"
+#include "string-util.h"
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
assert(addr);
@@ -54,3 +55,71 @@ bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
a->ether_addr_octet[5] == b->ether_addr_octet[5];
}
+
+int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) {
+ size_t pos = 0, n, field;
+ char sep = '\0';
+ const char *hex = HEXDIGITS, *hexoff;
+ size_t x;
+ bool touched;
+
+#define parse_fields(v) \
+ for (field = 0; field < ELEMENTSOF(v); field++) { \
+ touched = false; \
+ for (n = 0; n < (2 * sizeof(v[0])); n++) { \
+ if (s[pos] == '\0') \
+ break; \
+ hexoff = strchr(hex, s[pos]); \
+ if (hexoff == NULL) \
+ break; \
+ assert(hexoff >= hex); \
+ x = hexoff - hex; \
+ if (x >= 16) \
+ x -= 6; /* A-F */ \
+ assert(x < 16); \
+ touched = true; \
+ v[field] <<= 4; \
+ v[field] += x; \
+ pos++; \
+ } \
+ if (!touched) \
+ return -EINVAL; \
+ if (field < (ELEMENTSOF(v)-1)) { \
+ if (s[pos] != sep) \
+ return -EINVAL; \
+ else \
+ pos++; \
+ } \
+ }
+
+ assert(s);
+ assert(ret);
+
+ sep = s[strspn(s, hex)];
+ if (sep == '\n')
+ return -EINVAL;
+ if (strchr(":.-", sep) == NULL)
+ return -EINVAL;
+
+ if (sep == '.') {
+ uint16_t shorts[3] = { 0 };
+
+ parse_fields(shorts);
+
+ for (n = 0; n < ELEMENTSOF(shorts); n++) {
+ ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
+ ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
+ }
+ } else {
+ struct ether_addr out = { .ether_addr_octet = { 0 } };
+
+ parse_fields(out.ether_addr_octet);
+
+ for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
+ ret->ether_addr_octet[n] = out.ether_addr_octet[n];
+ }
+
+ if (offset)
+ *offset = pos;
+ return 0;
+}
diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h
index 074363793e..74e125a95f 100644
--- a/src/basic/ether-addr-util.h
+++ b/src/basic/ether-addr-util.h
@@ -35,3 +35,5 @@ bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b);
static inline bool ether_addr_is_null(const struct ether_addr *addr) {
return ether_addr_equal(addr, &ETHER_ADDR_NULL);
}
+
+int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 22ea8f67cc..651e414395 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -389,6 +389,10 @@ struct btrfs_ioctl_quota_ctl_args {
struct btrfs_ioctl_qgroup_limit_args)
#endif
+#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT
+#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)
+#endif
+
#ifndef BTRFS_FIRST_FREE_OBJECTID
#define BTRFS_FIRST_FREE_OBJECTID 256
#endif
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 4a7367cc92..1ad8816206 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -667,6 +667,8 @@ bool is_main_thread(void) {
noreturn void freeze(void) {
+ log_close();
+
/* Make sure nobody waits for us on a socket anymore */
close_all_fds(NULL, 0);
diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h
index 40b5b527d5..f693a5bb7c 100644
--- a/src/basic/rm-rf.h
+++ b/src/basic/rm-rf.h
@@ -32,10 +32,10 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
int rm_rf(const char *path, RemoveFlags flags);
/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
-static inline void rm_rf_and_free(char *p) {
+static inline void rm_rf_physical_and_free(char *p) {
if (!p)
return;
- (void) rm_rf(p, REMOVE_ROOT);
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
free(p);
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_and_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_physical_and_free);
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index ad0c813761..139cc8c91b 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -37,6 +37,7 @@
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
#define ALPHANUMERICAL LETTERS DIGITS
+#define HEXDIGITS DIGITS "abcdefABCDEF"
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 14eb46c8db..e088e4b197 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -269,13 +269,15 @@ static int process(
if (g->memory > 0)
g->memory_valid = true;
- } else if (streq(controller, "blkio") && cg_unified() <= 0) {
+ } else if ((streq(controller, "io") && cg_unified() > 0) ||
+ (streq(controller, "blkio") && cg_unified() <= 0)) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
+ bool unified = cg_unified() > 0;
uint64_t wr = 0, rd = 0;
nsec_t timestamp;
- r = cg_get_path(controller, path, "blkio.io_service_bytes", &p);
+ r = cg_get_path(controller, path, unified ? "io.stat" : "blkio.io_service_bytes", &p);
if (r < 0)
return r;
@@ -293,25 +295,38 @@ static int process(
if (!fgets(line, sizeof(line), f))
break;
+ /* Trim and skip the device */
l = strstrip(line);
l += strcspn(l, WHITESPACE);
l += strspn(l, WHITESPACE);
- if (first_word(l, "Read")) {
- l += 4;
- q = &rd;
- } else if (first_word(l, "Write")) {
- l += 5;
- q = &wr;
- } else
- continue;
-
- l += strspn(l, WHITESPACE);
- r = safe_atou64(l, &k);
- if (r < 0)
- continue;
+ if (unified) {
+ while (!isempty(l)) {
+ if (sscanf(l, "rbytes=%" SCNu64, &k))
+ rd += k;
+ else if (sscanf(l, "wbytes=%" SCNu64, &k))
+ wr += k;
- *q += k;
+ l += strcspn(l, WHITESPACE);
+ l += strspn(l, WHITESPACE);
+ }
+ } else {
+ if (first_word(l, "Read")) {
+ l += 4;
+ q = &rd;
+ } else if (first_word(l, "Write")) {
+ l += 5;
+ q = &wr;
+ } else
+ continue;
+
+ l += strspn(l, WHITESPACE);
+ r = safe_atou64(l, &k);
+ if (r < 0)
+ continue;
+
+ *q += k;
+ }
}
timestamp = now_nsec(CLOCK_MONOTONIC);
@@ -439,6 +454,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration)
r = refresh_one("memory", root, a, b, iteration, 0, NULL);
if (r < 0)
return r;
+ r = refresh_one("io", root, a, b, iteration, 0, NULL);
+ if (r < 0)
+ return r;
r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
if (r < 0)
return r;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 996efde22b..0fb63b1bd1 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -32,6 +32,7 @@
#include "special.h"
#include "string-table.h"
#include "string-util.h"
+#include "stdio-util.h"
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
@@ -47,6 +48,9 @@ void cgroup_context_init(CGroupContext *c) {
c->memory_limit = (uint64_t) -1;
+ c->io_weight = CGROUP_WEIGHT_INVALID;
+ c->startup_io_weight = CGROUP_WEIGHT_INVALID;
+
c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
@@ -62,6 +66,24 @@ void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
free(a);
}
+void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w) {
+ assert(c);
+ assert(w);
+
+ LIST_REMOVE(device_weights, c->io_device_weights, w);
+ free(w->path);
+ free(w);
+}
+
+void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l) {
+ assert(c);
+ assert(l);
+
+ LIST_REMOVE(device_limits, c->io_device_limits, l);
+ free(l->path);
+ free(l);
+}
+
void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
assert(c);
assert(w);
@@ -83,6 +105,12 @@ void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockI
void cgroup_context_done(CGroupContext *c) {
assert(c);
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_device_weights);
+
+ while (c->io_device_limits)
+ cgroup_context_free_io_device_limit(c, c->io_device_limits);
+
while (c->blockio_device_weights)
cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
@@ -94,6 +122,8 @@ void cgroup_context_done(CGroupContext *c) {
}
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+ CGroupIODeviceLimit *il;
+ CGroupIODeviceWeight *iw;
CGroupBlockIODeviceBandwidth *b;
CGroupBlockIODeviceWeight *w;
CGroupDeviceAllow *a;
@@ -106,12 +136,15 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
fprintf(f,
"%sCPUAccounting=%s\n"
+ "%sIOAccounting=%s\n"
"%sBlockIOAccounting=%s\n"
"%sMemoryAccounting=%s\n"
"%sTasksAccounting=%s\n"
"%sCPUShares=%" PRIu64 "\n"
"%sStartupCPUShares=%" PRIu64 "\n"
"%sCPUQuotaPerSecSec=%s\n"
+ "%sIOWeight=%" PRIu64 "\n"
+ "%sStartupIOWeight=%" PRIu64 "\n"
"%sBlockIOWeight=%" PRIu64 "\n"
"%sStartupBlockIOWeight=%" PRIu64 "\n"
"%sMemoryLimit=%" PRIu64 "\n"
@@ -119,12 +152,15 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sDevicePolicy=%s\n"
"%sDelegate=%s\n",
prefix, yes_no(c->cpu_accounting),
+ prefix, yes_no(c->io_accounting),
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
prefix, yes_no(c->tasks_accounting),
prefix, c->cpu_shares,
prefix, c->startup_cpu_shares,
prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
+ prefix, c->io_weight,
+ prefix, c->startup_io_weight,
prefix, c->blockio_weight,
prefix, c->startup_blockio_weight,
prefix, c->memory_limit,
@@ -139,6 +175,27 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
a->path,
a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+ LIST_FOREACH(device_weights, iw, c->io_device_weights)
+ fprintf(f,
+ "%sIODeviceWeight=%s %" PRIu64,
+ prefix,
+ iw->path,
+ iw->weight);
+
+ LIST_FOREACH(device_limits, il, c->io_device_limits) {
+ char buf[FORMAT_BYTES_MAX];
+ CGroupIOLimitType type;
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ if (il->limits[type] != cgroup_io_limit_defaults[type])
+ fprintf(f,
+ "%s%s=%s %s\n",
+ prefix,
+ cgroup_io_limit_type_to_string(type),
+ il->path,
+ format_bytes(buf, sizeof(buf), il->limits[type]));
+ }
+
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
fprintf(f,
"%sBlockIODeviceWeight=%s %" PRIu64,
@@ -149,16 +206,22 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
char buf[FORMAT_BYTES_MAX];
- fprintf(f,
- "%s%s=%s %s\n",
- prefix,
- b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
- b->path,
- format_bytes(buf, sizeof(buf), b->bandwidth));
+ if (b->rbps != CGROUP_LIMIT_MAX)
+ fprintf(f,
+ "%sBlockIOReadBandwidth=%s %s\n",
+ prefix,
+ b->path,
+ format_bytes(buf, sizeof(buf), b->rbps));
+ if (b->wbps != CGROUP_LIMIT_MAX)
+ fprintf(f,
+ "%sBlockIOWriteBandwidth=%s %s\n",
+ prefix,
+ b->path,
+ format_bytes(buf, sizeof(buf), b->wbps));
}
}
-static int lookup_blkio_device(const char *p, dev_t *dev) {
+static int lookup_block_device(const char *p, dev_t *dev) {
struct stat st;
int r;
@@ -295,6 +358,144 @@ fail:
return -errno;
}
+static bool cgroup_context_has_io_config(CGroupContext *c) {
+ return c->io_accounting ||
+ c->io_weight != CGROUP_WEIGHT_INVALID ||
+ c->startup_io_weight != CGROUP_WEIGHT_INVALID ||
+ c->io_device_weights ||
+ c->io_device_limits;
+}
+
+static bool cgroup_context_has_blockio_config(CGroupContext *c) {
+ return c->blockio_accounting ||
+ c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
+ c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
+ c->blockio_device_weights ||
+ c->blockio_device_bandwidths;
+}
+
+static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) {
+ if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
+ c->startup_io_weight != CGROUP_WEIGHT_INVALID)
+ return c->startup_io_weight;
+ else if (c->io_weight != CGROUP_WEIGHT_INVALID)
+ return c->io_weight;
+ else
+ return CGROUP_WEIGHT_DEFAULT;
+}
+
+static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) {
+ if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
+ c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID)
+ return c->startup_blockio_weight;
+ else if (c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID)
+ return c->blockio_weight;
+ else
+ return CGROUP_BLKIO_WEIGHT_DEFAULT;
+}
+
+static uint64_t cgroup_weight_blkio_to_io(uint64_t blkio_weight) {
+ return CLAMP(blkio_weight * CGROUP_WEIGHT_DEFAULT / CGROUP_BLKIO_WEIGHT_DEFAULT,
+ CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX);
+}
+
+static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) {
+ return CLAMP(io_weight * CGROUP_BLKIO_WEIGHT_DEFAULT / CGROUP_WEIGHT_DEFAULT,
+ CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX);
+}
+
+static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return;
+
+ xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight);
+ r = cg_set_attribute("io", path, "io.weight", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.weight on %s: %m", path);
+}
+
+static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return;
+
+ xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight);
+ r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.weight_device on %s: %m", path);
+}
+
+static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) {
+ char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4];
+ CGroupIOLimitType type;
+ dev_t dev;
+ unsigned n = 0;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return 0;
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) {
+ if (limits[type] != cgroup_io_limit_defaults[type]) {
+ xsprintf(limit_bufs[type], "%" PRIu64, limits[type]);
+ n++;
+ } else {
+ xsprintf(limit_bufs[type], "%s", limits[type] == CGROUP_LIMIT_MAX ? "max" : "0");
+ }
+ }
+
+ xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev),
+ limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
+ limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]);
+ r = cg_set_attribute("io", path, "io.max", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.max on %s: %m", path);
+ return n;
+}
+
+static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ unsigned n = 0;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return 0;
+
+ if (rbps != CGROUP_LIMIT_MAX)
+ n++;
+ sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps);
+ r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.throttle.read_bps_device on %s: %m", path);
+
+ if (wbps != CGROUP_LIMIT_MAX)
+ n++;
+ sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps);
+ r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.throttle.write_bps_device on %s: %m", path);
+
+ return n;
+}
+
void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
bool is_root;
int r;
@@ -343,53 +544,120 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
"Failed to set cpu.cfs_quota_us on %s: %m", path);
}
- if (mask & CGROUP_MASK_BLKIO) {
- char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
- CGroupBlockIODeviceWeight *w;
- CGroupBlockIODeviceBandwidth *b;
+ if (mask & CGROUP_MASK_IO) {
+ bool has_io = cgroup_context_has_io_config(c);
+ bool has_blockio = cgroup_context_has_blockio_config(c);
if (!is_root) {
- sprintf(buf, "%" PRIu64 "\n",
- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight :
- c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT);
- r = cg_set_attribute("blkio", path, "blkio.weight", buf);
+ char buf[8+DECIMAL_STR_MAX(uint64_t)+1];
+ uint64_t weight;
+
+ if (has_io)
+ weight = cgroup_context_io_weight(c, state);
+ else if (has_blockio)
+ weight = cgroup_weight_blkio_to_io(cgroup_context_blkio_weight(c, state));
+ else
+ weight = CGROUP_WEIGHT_DEFAULT;
+
+ xsprintf(buf, "default %" PRIu64 "\n", weight);
+ r = cg_set_attribute("io", path, "io.weight", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight on %s: %m", path);
+ "Failed to set io.weight on %s: %m", path);
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
- dev_t dev;
+ if (has_io) {
+ CGroupIODeviceWeight *w;
- r = lookup_blkio_device(w->path, &dev);
- if (r < 0)
- continue;
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->io_device_weights)
+ cgroup_apply_io_device_weight(path, w->path, w->weight);
+ } else if (has_blockio) {
+ CGroupBlockIODeviceWeight *w;
- sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight);
- r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight_device on %s: %m", path);
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights)
+ cgroup_apply_io_device_weight(path, w->path, cgroup_weight_blkio_to_io(w->weight));
}
}
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- const char *a;
- dev_t dev;
+ /* Apply limits and free ones without config. */
+ if (has_io) {
+ CGroupIODeviceLimit *l, *next;
- r = lookup_blkio_device(b->path, &dev);
- if (r < 0)
- continue;
+ LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
+ if (!cgroup_apply_io_device_limit(path, l->path, l->limits))
+ cgroup_context_free_io_device_limit(c, l);
+ }
+ } else if (has_blockio) {
+ CGroupBlockIODeviceBandwidth *b, *next;
+
+ LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
+ uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
+ CGroupIOLimitType type;
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ limits[type] = cgroup_io_limit_defaults[type];
+
+ limits[CGROUP_IO_RBPS_MAX] = b->rbps;
+ limits[CGROUP_IO_WBPS_MAX] = b->wbps;
+
+ if (!cgroup_apply_io_device_limit(path, b->path, limits))
+ cgroup_context_free_blockio_device_bandwidth(c, b);
+ }
+ }
+ }
+
+ if (mask & CGROUP_MASK_BLKIO) {
+ bool has_io = cgroup_context_has_io_config(c);
+ bool has_blockio = cgroup_context_has_blockio_config(c);
+
+ if (!is_root) {
+ char buf[DECIMAL_STR_MAX(uint64_t)+1];
+ uint64_t weight;
- a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
+ if (has_blockio)
+ weight = cgroup_context_blkio_weight(c, state);
+ else if (has_io)
+ weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state));
+ else
+ weight = CGROUP_BLKIO_WEIGHT_DEFAULT;
- sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
- r = cg_set_attribute("blkio", path, a, buf);
+ xsprintf(buf, "%" PRIu64 "\n", weight);
+ r = cg_set_attribute("blkio", path, "blkio.weight", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set %s on %s: %m", a, path);
+ "Failed to set blkio.weight on %s: %m", path);
+
+ if (has_blockio) {
+ CGroupBlockIODeviceWeight *w;
+
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights)
+ cgroup_apply_blkio_device_weight(path, w->path, w->weight);
+ } else if (has_io) {
+ CGroupIODeviceWeight *w;
+
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->io_device_weights)
+ cgroup_apply_blkio_device_weight(path, w->path, cgroup_weight_io_to_blkio(w->weight));
+ }
+ }
+
+ /* Apply limits and free ones without config. */
+ if (has_blockio) {
+ CGroupBlockIODeviceBandwidth *b, *next;
+
+ LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
+ if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps))
+ cgroup_context_free_blockio_device_bandwidth(c, b);
+ }
+ } else if (has_io) {
+ CGroupIODeviceLimit *l, *next;
+
+ LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
+ if (!cgroup_apply_blkio_device_limit(path, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]))
+ cgroup_context_free_io_device_limit(c, l);
+ }
}
}
@@ -506,12 +774,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
c->cpu_quota_per_sec_usec != USEC_INFINITY)
mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
- if (c->blockio_accounting ||
- c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
- c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
- c->blockio_device_weights ||
- c->blockio_device_bandwidths)
- mask |= CGROUP_MASK_BLKIO;
+ if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c))
+ mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
if (c->memory_accounting ||
c->memory_limit != (uint64_t) -1)
@@ -1601,6 +1865,10 @@ void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
if (m == 0)
return;
+ /* always invalidate compat pairs together */
+ if (m & (CGROUP_MASK_IO | CGROUP_MASK_BLKIO))
+ m |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
+
if ((u->cgroup_realized_mask & m) == 0)
return;
@@ -1615,7 +1883,7 @@ void manager_invalidate_startup_units(Manager *m) {
assert(m);
SET_FOREACH(u, m->startup_units, i)
- unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_BLKIO);
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO);
}
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 360bbca30f..2b1edbafc4 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -23,9 +23,12 @@
#include "list.h"
#include "time-util.h"
+#include "cgroup-util.h"
typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
+typedef struct CGroupIODeviceWeight CGroupIODeviceWeight;
+typedef struct CGroupIODeviceLimit CGroupIODeviceLimit;
typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth;
@@ -53,6 +56,18 @@ struct CGroupDeviceAllow {
bool m:1;
};
+struct CGroupIODeviceWeight {
+ LIST_FIELDS(CGroupIODeviceWeight, device_weights);
+ char *path;
+ uint64_t weight;
+};
+
+struct CGroupIODeviceLimit {
+ LIST_FIELDS(CGroupIODeviceLimit, device_limits);
+ char *path;
+ uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
+};
+
struct CGroupBlockIODeviceWeight {
LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights);
char *path;
@@ -62,16 +77,24 @@ struct CGroupBlockIODeviceWeight {
struct CGroupBlockIODeviceBandwidth {
LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths);
char *path;
- uint64_t bandwidth;
- bool read;
+ uint64_t rbps;
+ uint64_t wbps;
};
struct CGroupContext {
bool cpu_accounting;
+ bool io_accounting;
bool blockio_accounting;
bool memory_accounting;
bool tasks_accounting;
+ /* For unified hierarchy */
+ uint64_t io_weight;
+ uint64_t startup_io_weight;
+ LIST_HEAD(CGroupIODeviceWeight, io_device_weights);
+ LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
+
+ /* For legacy hierarchies */
uint64_t cpu_shares;
uint64_t startup_cpu_shares;
usec_t cpu_quota_per_sec_usec;
@@ -86,6 +109,7 @@ struct CGroupContext {
CGroupDevicePolicy device_policy;
LIST_HEAD(CGroupDeviceAllow, device_allow);
+ /* Common */
uint64_t tasks_max;
bool delegate;
@@ -102,6 +126,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
CGroupMask cgroup_context_get_mask(CGroupContext *c);
void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
+void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w);
+void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l);
void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 859d155ec1..eef1c47c14 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -28,6 +28,72 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
+static int property_get_io_device_weight(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CGroupContext *c = userdata;
+ CGroupIODeviceWeight *w;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(device_weights, w, c->io_device_weights) {
+ r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
+static int property_get_io_device_limits(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CGroupContext *c = userdata;
+ CGroupIODeviceLimit *l;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(device_limits, l, c->io_device_limits) {
+ CGroupIOLimitType type;
+
+ type = cgroup_io_limit_type_from_string(property);
+ if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
+ continue;
+
+ r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
static int property_get_blockio_device_weight(
sd_bus *bus,
const char *path,
@@ -80,11 +146,17 @@ static int property_get_blockio_device_bandwidths(
return r;
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ uint64_t v;
- if (streq(property, "BlockIOReadBandwidth") != b->read)
+ if (streq(property, "BlockIOReadBandwidth"))
+ v = b->rbps;
+ else
+ v = b->wbps;
+
+ if (v == CGROUP_LIMIT_MAX)
continue;
- r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
+ r = sd_bus_message_append(reply, "(st)", b->path, v);
if (r < 0)
return r;
}
@@ -141,6 +213,14 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
+ SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
+ SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
+ SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
+ SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
+ SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
@@ -197,6 +277,7 @@ int bus_cgroup_set_property(
UnitSetPropertiesMode mode,
sd_bus_error *error) {
+ CGroupIOLimitType iol_type;
int r;
assert(u);
@@ -281,6 +362,223 @@ int bus_cgroup_set_property(
return 1;
+ } else if (streq(name, "IOAccounting")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->io_accounting = b;
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+ unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no");
+ }
+
+ return 1;
+
+ } else if (streq(name, "IOWeight")) {
+ uint64_t weight;
+
+ r = sd_bus_message_read(message, "t", &weight);
+ if (r < 0)
+ return r;
+
+ if (!CGROUP_WEIGHT_IS_OK(weight))
+ return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->io_weight = weight;
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ if (weight == CGROUP_WEIGHT_INVALID)
+ unit_write_drop_in_private(u, mode, name, "IOWeight=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight);
+ }
+
+ return 1;
+
+ } else if (streq(name, "StartupIOWeight")) {
+ uint64_t weight;
+
+ r = sd_bus_message_read(message, "t", &weight);
+ if (r < 0)
+ return r;
+
+ if (CGROUP_WEIGHT_IS_OK(weight))
+ return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->startup_io_weight = weight;
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ if (weight == CGROUP_WEIGHT_INVALID)
+ unit_write_drop_in_private(u, mode, name, "StartupIOWeight=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight);
+ }
+
+ return 1;
+
+ } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
+ const char *path;
+ unsigned n = 0;
+ uint64_t u64;
+
+ r = sd_bus_message_enter_container(message, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
+
+ if (mode != UNIT_CHECK) {
+ CGroupIODeviceLimit *a = NULL, *b;
+
+ LIST_FOREACH(device_limits, b, c->io_device_limits) {
+ if (path_equal(path, b->path)) {
+ a = b;
+ break;
+ }
+ }
+
+ if (!a) {
+ CGroupIOLimitType type;
+
+ a = new0(CGroupIODeviceLimit, 1);
+ if (!a)
+ return -ENOMEM;
+
+ a->path = strdup(path);
+ if (!a->path) {
+ free(a);
+ return -ENOMEM;
+ }
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ a->limits[type] = cgroup_io_limit_defaults[type];
+
+ LIST_PREPEND(device_limits, c->io_device_limits, a);
+ }
+
+ a->limits[iol_type] = u64;
+ }
+
+ n++;
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ CGroupIODeviceLimit *a;
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ size_t size = 0;
+
+ if (n == 0) {
+ LIST_FOREACH(device_limits, a, c->io_device_limits)
+ a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
+ }
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ f = open_memstream(&buf, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fprintf(f, "%s=\n", name);
+ LIST_FOREACH(device_limits, a, c->io_device_limits)
+ if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
+ fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private(u, mode, name, buf);
+ }
+
+ return 1;
+
+ } else if (streq(name, "IODeviceWeight")) {
+ const char *path;
+ uint64_t weight;
+ unsigned n = 0;
+
+ r = sd_bus_message_enter_container(message, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
+
+ if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
+ return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range");
+
+ if (mode != UNIT_CHECK) {
+ CGroupIODeviceWeight *a = NULL, *b;
+
+ LIST_FOREACH(device_weights, b, c->io_device_weights) {
+ if (path_equal(b->path, path)) {
+ a = b;
+ break;
+ }
+ }
+
+ if (!a) {
+ a = new0(CGroupIODeviceWeight, 1);
+ if (!a)
+ return -ENOMEM;
+
+ a->path = strdup(path);
+ if (!a->path) {
+ free(a);
+ return -ENOMEM;
+ }
+ LIST_PREPEND(device_weights,c->io_device_weights, a);
+ }
+
+ a->weight = weight;
+ }
+
+ n++;
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ CGroupIODeviceWeight *a;
+ size_t size = 0;
+
+ if (n == 0) {
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_device_weights);
+ }
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ f = open_memstream(&buf, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fputs("IODeviceWeight=\n", f);
+ LIST_FOREACH(device_weights, a, c->io_device_weights)
+ fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private(u, mode, name, buf);
+ }
+
+ return 1;
+
} else if (streq(name, "BlockIOAccounting")) {
int b;
@@ -359,7 +657,7 @@ int bus_cgroup_set_property(
CGroupBlockIODeviceBandwidth *a = NULL, *b;
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- if (path_equal(path, b->path) && read == b->read) {
+ if (path_equal(path, b->path)) {
a = b;
break;
}
@@ -370,7 +668,8 @@ int bus_cgroup_set_property(
if (!a)
return -ENOMEM;
- a->read = read;
+ a->rbps = CGROUP_LIMIT_MAX;
+ a->wbps = CGROUP_LIMIT_MAX;
a->path = strdup(path);
if (!a->path) {
free(a);
@@ -380,7 +679,10 @@ int bus_cgroup_set_property(
LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
}
- a->bandwidth = u64;
+ if (read)
+ a->rbps = u64;
+ else
+ a->wbps = u64;
}
n++;
@@ -393,15 +695,18 @@ int bus_cgroup_set_property(
return r;
if (mode != UNIT_CHECK) {
- CGroupBlockIODeviceBandwidth *a, *next;
+ CGroupBlockIODeviceBandwidth *a;
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t size = 0;
if (n == 0) {
- LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
- if (a->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, a);
+ LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
+ if (read)
+ a->rbps = CGROUP_LIMIT_MAX;
+ else
+ a->wbps = CGROUP_LIMIT_MAX;
+ }
}
unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
@@ -413,13 +718,13 @@ int bus_cgroup_set_property(
if (read) {
fputs("BlockIOReadBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
- if (a->read)
- fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
+ if (a->rbps != CGROUP_LIMIT_MAX)
+ fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
} else {
fputs("BlockIOWriteBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
- if (!a->read)
- fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
+ if (a->wbps != CGROUP_LIMIT_MAX)
+ fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
}
r = fflush_and_check(f);
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 9dfca14914..06943c6365 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -839,16 +839,8 @@ int bus_exec_context_set_transient_property(
if (isempty(uu))
c->user = mfree(c->user);
- else {
- char *t;
-
- t = strdup(uu);
- if (!t)
- return -ENOMEM;
-
- free(c->user);
- c->user = t;
- }
+ else if (free_and_strdup(&c->user, uu) < 0)
+ return -ENOMEM;
unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
}
@@ -866,16 +858,8 @@ int bus_exec_context_set_transient_property(
if (isempty(gg))
c->group = mfree(c->group);
- else {
- char *t;
-
- t = strdup(gg);
- if (!t)
- return -ENOMEM;
-
- free(c->group);
- c->group = t;
- }
+ else if (free_and_strdup(&c->group, gg) < 0)
+ return -ENOMEM;
unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
}
@@ -890,18 +874,10 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
- if (isempty(id)) {
+ if (isempty(id))
c->syslog_identifier = mfree(c->syslog_identifier);
- } else {
- char *t;
-
- t = strdup(id);
- if (!t)
- return -ENOMEM;
-
- free(c->syslog_identifier);
- c->syslog_identifier = t;
- }
+ else if (free_and_strdup(&c->syslog_identifier, id) < 0)
+ return -ENOMEM;
unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
}
@@ -1478,6 +1454,24 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "SELinuxContext")) {
+ const char *s;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ if (isempty(s))
+ c->selinux_context = mfree(c->selinux_context);
+ else if (free_and_strdup(&c->selinux_context, s) < 0)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, strempty(s));
+ }
+
+ return 1;
+
}
ri = rlimit_from_string(name);
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 97a93fb2f1..ccf7453d47 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -75,7 +75,7 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
- job_finish_and_invalidate(j, JOB_CANCELED, true);
+ job_finish_and_invalidate(j, JOB_CANCELED, true, false);
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/core/job.c b/src/core/job.c
index d9c5669c9f..7557874d4d 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -191,7 +191,7 @@ Job* job_install(Job *j) {
if (uj) {
if (job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, false);
+ job_finish_and_invalidate(uj, JOB_CANCELED, false, false);
else {
/* not conflicting, i.e. mergeable */
@@ -614,19 +614,19 @@ int job_run_and_invalidate(Job *j) {
if (j) {
if (r == -EALREADY)
- r = job_finish_and_invalidate(j, JOB_DONE, true);
+ r = job_finish_and_invalidate(j, JOB_DONE, true, true);
else if (r == -EBADR)
- r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
+ r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false);
else if (r == -ENOEXEC)
- r = job_finish_and_invalidate(j, JOB_INVALID, true);
+ r = job_finish_and_invalidate(j, JOB_INVALID, true, false);
else if (r == -EPROTO)
- r = job_finish_and_invalidate(j, JOB_ASSERT, true);
+ r = job_finish_and_invalidate(j, JOB_ASSERT, true, false);
else if (r == -EOPNOTSUPP)
- r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
+ r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false);
else if (r == -EAGAIN)
job_set_state(j, JOB_WAITING);
else if (r < 0)
- r = job_finish_and_invalidate(j, JOB_FAILED, true);
+ r = job_finish_and_invalidate(j, JOB_FAILED, true, false);
}
return r;
@@ -827,11 +827,11 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) {
if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
continue;
- job_finish_and_invalidate(j, JOB_DEPENDENCY, true);
+ job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
}
}
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
Unit *u;
Unit *other;
JobType t;
@@ -848,7 +848,9 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
- job_emit_status_message(u, t, result);
+ /* If this job did nothing to respective unit we don't log the status message */
+ if (!already)
+ job_emit_status_message(u, t, result);
job_add_to_dbus_queue(j);
@@ -923,7 +925,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
log_unit_warning(j->unit, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
u = j->unit;
- job_finish_and_invalidate(j, JOB_TIMEOUT, true);
+ job_finish_and_invalidate(j, JOB_TIMEOUT, true, false);
failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg);
diff --git a/src/core/job.h b/src/core/job.h
index 856b0ce829..d359e8bb3e 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -219,7 +219,7 @@ void job_add_to_dbus_queue(Job *j);
int job_start_timer(Job *j);
int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive);
+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already);
char *job_dbus_path(Job *j);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 928b913c7b..8193418980 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -120,6 +120,14 @@ $1.MemoryAccounting, config_parse_bool, 0,
$1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context)
$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy)
+$1.IOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.io_accounting)
+$1.IOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.io_weight)
+$1.StartupIOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.startup_io_weight)
+$1.IODeviceWeight, config_parse_io_device_weight, 0, offsetof($1, cgroup_context)
+$1.IOReadBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IOWriteBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IOReadIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IOWriteIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
$1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting)
$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.blockio_weight)
$1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index a12dd38c60..86b4fb071b 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2910,6 +2910,193 @@ int config_parse_device_allow(
return 0;
}
+int config_parse_io_weight(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ uint64_t *weight = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = cg_weight_parse(rvalue, weight);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
+
+int config_parse_io_device_weight(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupIODeviceWeight *w;
+ CGroupContext *c = data;
+ const char *weight;
+ uint64_t u;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_device_weights);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ weight = rvalue + n;
+ weight += strspn(weight, WHITESPACE);
+
+ if (isempty(weight)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ r = cg_weight_parse(weight, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
+ return 0;
+ }
+
+ assert(u != CGROUP_WEIGHT_INVALID);
+
+ w = new0(CGroupIODeviceWeight, 1);
+ if (!w)
+ return log_oom();
+
+ w->path = path;
+ path = NULL;
+
+ w->weight = u;
+
+ LIST_PREPEND(device_weights, c->io_device_weights, w);
+ return 0;
+}
+
+int config_parse_io_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupIODeviceLimit *l = NULL, *t;
+ CGroupContext *c = data;
+ CGroupIOLimitType type;
+ const char *limit;
+ uint64_t num;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ type = cgroup_io_limit_type_from_string(lvalue);
+ assert(type >= 0);
+
+ if (isempty(rvalue)) {
+ LIST_FOREACH(device_limits, l, c->io_device_limits)
+ l->limits[type] = cgroup_io_limit_defaults[type];
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ limit = rvalue + n;
+ limit += strspn(limit, WHITESPACE);
+
+ if (!*limit) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ if (streq("max", limit)) {
+ num = CGROUP_LIMIT_MAX;
+ } else {
+ r = parse_size(limit, 1000, &num);
+ if (r < 0 || num <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ }
+
+ LIST_FOREACH(device_limits, t, c->io_device_limits) {
+ if (path_equal(path, t->path)) {
+ l = t;
+ break;
+ }
+ }
+
+ if (!l) {
+ CGroupIOLimitType ttype;
+
+ l = new0(CGroupIODeviceLimit, 1);
+ if (!l)
+ return log_oom();
+
+ l->path = path;
+ path = NULL;
+ for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
+ l->limits[ttype] = cgroup_io_limit_defaults[ttype];
+
+ LIST_PREPEND(device_limits, c->io_device_limits, l);
+ }
+
+ l->limits[type] = num;
+
+ return 0;
+}
+
int config_parse_blockio_weight(
const char *unit,
const char *filename,
@@ -3021,7 +3208,7 @@ int config_parse_blockio_bandwidth(
void *userdata) {
_cleanup_free_ char *path = NULL;
- CGroupBlockIODeviceBandwidth *b;
+ CGroupBlockIODeviceBandwidth *b = NULL, *t;
CGroupContext *c = data;
const char *bandwidth;
uint64_t bytes;
@@ -3036,12 +3223,10 @@ int config_parse_blockio_bandwidth(
read = streq("BlockIOReadBandwidth", lvalue);
if (isempty(rvalue)) {
- CGroupBlockIODeviceBandwidth *next;
-
- LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
- if (b->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, b);
-
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ b->rbps = CGROUP_LIMIT_MAX;
+ b->wbps = CGROUP_LIMIT_MAX;
+ }
return 0;
}
@@ -3069,16 +3254,30 @@ int config_parse_blockio_bandwidth(
return 0;
}
- b = new0(CGroupBlockIODeviceBandwidth, 1);
- if (!b)
- return log_oom();
+ LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
+ if (path_equal(path, t->path)) {
+ b = t;
+ break;
+ }
+ }
- b->path = path;
- path = NULL;
- b->bandwidth = bytes;
- b->read = read;
+ if (!t) {
+ b = new0(CGroupBlockIODeviceBandwidth, 1);
+ if (!b)
+ return log_oom();
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ b->path = path;
+ path = NULL;
+ b->rbps = CGROUP_LIMIT_MAX;
+ b->wbps = CGROUP_LIMIT_MAX;
+
+ LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ }
+
+ if (read)
+ b->rbps = bytes;
+ else
+ b->wbps = bytes;
return 0;
}
@@ -3830,6 +4029,9 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },
+ { config_parse_io_limit, "LIMIT" },
+ { config_parse_io_weight, "WEIGHT" },
+ { config_parse_io_device_weight, "DEVICEWEIGHT" },
{ config_parse_blockio_bandwidth, "BANDWIDTH" },
{ config_parse_blockio_weight, "WEIGHT" },
{ config_parse_blockio_device_weight, "DEVICEWEIGHT" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 34f15afa62..b36a2e3a02 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -86,6 +86,9 @@ int config_parse_memory_limit(const char *unit, const char *filename, unsigned l
int config_parse_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_io_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_io_device_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_io_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_blockio_device_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_blockio_bandwidth(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/core/main.c b/src/core/main.c
index ed4d42c8cc..6397aadc73 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -122,6 +122,7 @@ static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
static Set* arg_syscall_archs = NULL;
static FILE* arg_serialization = NULL;
static bool arg_default_cpu_accounting = false;
+static bool arg_default_io_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = true;
@@ -691,6 +692,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
+ { "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
@@ -733,6 +735,7 @@ static void manager_set_defaults(Manager *m) {
m->default_start_limit_interval = arg_default_start_limit_interval;
m->default_start_limit_burst = arg_default_start_limit_burst;
m->default_cpu_accounting = arg_default_cpu_accounting;
+ m->default_io_accounting = arg_default_io_accounting;
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
diff --git a/src/core/manager.c b/src/core/manager.c
index e192cd475d..7838f56fd2 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1494,7 +1494,7 @@ void manager_clear_jobs(Manager *m) {
while ((j = hashmap_first(m->jobs)))
/* No need to recurse. We're cancelling all jobs. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
+ job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
diff --git a/src/core/manager.h b/src/core/manager.h
index 4bccca75cb..6ed15c1a41 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -255,6 +255,7 @@ struct Manager {
bool default_cpu_accounting;
bool default_memory_accounting;
+ bool default_io_accounting;
bool default_blockio_accounting;
bool default_tasks_accounting;
diff --git a/src/core/namespace.c b/src/core/namespace.c
index b573f008b9..203d122810 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -44,6 +44,8 @@
#include "user-util.h"
#include "util.h"
+#define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
+
typedef enum MountMode {
/* This is ordered by priority! */
INACCESSIBLE,
@@ -153,7 +155,7 @@ static int mount_dev(BindMount *m) {
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
- if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
+ if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
r = -errno;
goto fail;
}
@@ -237,6 +239,8 @@ static int mount_dev(BindMount *m) {
*/
(void) mkdir_p_label(m->path, 0755);
+ /* Unmount everything in old /dev */
+ umount_recursive(m->path, 0);
if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
@@ -328,9 +332,11 @@ static int make_read_only(BindMount *m) {
if (IN_SET(m->mode, INACCESSIBLE, READONLY))
r = bind_remount_recursive(m->path, true);
- else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
+ else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) {
r = bind_remount_recursive(m->path, false);
- else
+ if (r == 0 && m->mode == PRIVATE_DEV) /* can be readonly but the submounts can't*/
+ r = mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL);
+ } else
r = 0;
if (m->ignore && r == -ENOENT)
diff --git a/src/core/system.conf b/src/core/system.conf
index eacd7ee282..db8b7acd78 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -38,6 +38,7 @@
#DefaultStartLimitBurst=5
#DefaultEnvironment=
#DefaultCPUAccounting=no
+#DefaultIOAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
#DefaultTasksAccounting=yes
diff --git a/src/core/transaction.c b/src/core/transaction.c
index d5370b2a14..e06a48a2f1 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -597,7 +597,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
/* Not invalidating recursively. Avoids triggering
* OnFailure= actions of dependent jobs. Also avoids
* invalidating our iterator. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
+ job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
}
diff --git a/src/core/unit.c b/src/core/unit.c
index d8ab5781b0..2fff3f2d8b 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -132,6 +132,7 @@ static void unit_init(Unit *u) {
* been initialized */
cc->cpu_accounting = u->manager->default_cpu_accounting;
+ cc->io_accounting = u->manager->default_io_accounting;
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
@@ -1213,6 +1214,7 @@ static int unit_add_startup_units(Unit *u) {
return 0;
if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID &&
+ c->startup_io_weight == CGROUP_WEIGHT_INVALID &&
c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID)
return 0;
@@ -1916,12 +1918,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_VERIFY_ACTIVE:
if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
+ job_finish_and_invalidate(u->job, JOB_DONE, true, false);
else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
}
break;
@@ -1932,12 +1934,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
+ job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false);
else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
}
}
@@ -1948,10 +1950,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_TRY_RESTART:
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
+ job_finish_and_invalidate(u->job, JOB_DONE, true, false);
else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
unexpected = true;
- job_finish_and_invalidate(u->job, JOB_FAILED, true);
+ job_finish_and_invalidate(u->job, JOB_FAILED, true, false);
}
break;
@@ -2400,9 +2402,11 @@ int unit_set_slice(Unit *u, Unit *slice) {
if (UNIT_DEREF(u->slice) == slice)
return 0;
- if (UNIT_ISSET(u->slice))
+ /* Disallow slice changes if @u is already bound to cgroups */
+ if (UNIT_ISSET(u->slice) && u->cgroup_realized)
return -EBUSY;
+ unit_ref_unset(&u->slice);
unit_ref_set(&u->slice, slice);
return 1;
}
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index adb557167a..0c76956fad 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -63,6 +63,8 @@ struct sd_dhcp_server {
struct in_addr *ntp, *dns;
unsigned n_ntp, n_dns;
+ bool emit_router;
+
Hashmap *leases_by_client_id;
DHCPLease **bound_leases;
DHCPLease invalid_lease;
diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index 749086d33a..945c3b9721 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -55,7 +55,8 @@ struct DHCP6IA {
typedef struct DHCP6IA DHCP6IA;
-#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_dhcp6_client(p, fmt, ...) log_dhcp6_client_errno(p, 0, fmt, ##__VA_ARGS__)
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval);
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
index acad9d7d6a..d81e9ebd88 100644
--- a/src/libsystemd-network/icmp6-util.c
+++ b/src/libsystemd-network/icmp6-util.c
@@ -26,6 +26,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
+#include <net/if.h>
#include <linux/if_packet.h>
#include "fd-util.h"
@@ -47,6 +48,7 @@ int icmp6_bind_router_solicitation(int index) {
.ipv6mr_interface = index,
};
_cleanup_close_ int s = -1;
+ char ifname[IF_NAMESIZE] = "";
int r, zero = 0, one = 1, hops = 255;
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
@@ -83,6 +85,13 @@ int icmp6_bind_router_solicitation(int index) {
if (r < 0)
return -errno;
+ if (if_indextoname(index, ifname) == 0)
+ return -errno;
+
+ r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+ if (r < 0)
+ return -errno;
+
r = s;
s = -1;
return r;
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 2badcdff58..046b0f9393 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -27,6 +27,7 @@
#include "condition.h"
#include "conf-parser.h"
#include "dhcp-lease-internal.h"
+#include "ether-addr-util.c"
#include "hexdecoct.h"
#include "log.h"
#include "network-internal.h"
@@ -272,6 +273,8 @@ int config_parse_hwaddr(const char *unit,
void *userdata) {
struct ether_addr **hwaddr = data;
struct ether_addr *n;
+ const char *start;
+ size_t offset;
int r;
assert(filename);
@@ -283,14 +286,10 @@ int config_parse_hwaddr(const char *unit,
if (!n)
return log_oom();
- r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
- &n->ether_addr_octet[0],
- &n->ether_addr_octet[1],
- &n->ether_addr_octet[2],
- &n->ether_addr_octet[3],
- &n->ether_addr_octet[4],
- &n->ether_addr_octet[5]);
- if (r != 6) {
+ start = rvalue + strspn(rvalue, WHITESPACE);
+ r = ether_addr_from_string(start, n, &offset);
+
+ if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
free(n);
return 0;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 3846cf7476..ad79c6cc2c 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1640,7 +1640,7 @@ static int client_receive_message_udp(
if (!message)
return -ENOMEM;
- len = read(fd, message, buflen);
+ len = recv(fd, message, buflen, 0);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 9adf8ec19d..fb335337c4 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -468,10 +468,12 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
if (r < 0)
return r;
- r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- SD_DHCP_OPTION_ROUTER, 4, &server->address);
- if (r < 0)
- return r;
+ if (server->emit_router) {
+ r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
+ SD_DHCP_OPTION_ROUTER, 4, &server->address);
+ if (r < 0)
+ return r;
+ }
r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
if (r < 0)
@@ -505,10 +507,12 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
if (r < 0)
return r;
- r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- SD_DHCP_OPTION_ROUTER, 4, &server->address);
- if (r < 0)
- return r;
+ if (server->emit_router) {
+ r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
+ SD_DHCP_OPTION_ROUTER, 4, &server->address);
+ if (r < 0)
+ return r;
+ }
if (server->n_dns > 0) {
r = dhcp_option_append(
@@ -1158,3 +1162,14 @@ int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], u
return 1;
}
+
+int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
+ assert_return(server, -EINVAL);
+
+ if (enabled == server->emit_router)
+ return 0;
+
+ server->emit_router = enabled;
+
+ return 1;
+}
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 4adb053a57..05972e01c9 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -917,14 +917,13 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
if (!message)
return -ENOMEM;
- len = read(fd, message, buflen);
+ len = recv(fd, message, buflen, 0);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
- log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
+ return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
- return -errno;
} else if ((size_t)len < sizeof(DHCP6Message))
return 0;
@@ -947,8 +946,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
break;
default:
- log_dhcp6_client(client, "unknown message type %d",
- message->type);
+ log_dhcp6_client(client, "Unknown message type %d", message->type);
return 0;
}
@@ -1007,10 +1005,9 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
return 0;
}
- if (r >= 0) {
+ if (r >= 0)
log_dhcp6_client(client, "Recv %s",
dhcp6_message_type_to_string(message->type));
- }
return 0;
}
@@ -1063,7 +1060,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
if (client->lease->ia.lifetime_t1 == 0xffffffff ||
client->lease->ia.lifetime_t2 == 0xffffffff) {
- log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
+ log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
be32toh(client->lease->ia.lifetime_t1),
be32toh(client->lease->ia.lifetime_t2));
@@ -1179,8 +1176,13 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
return r;
r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
- if (r < 0)
- return r;
+ if (r < 0) {
+ _cleanup_free_ char *p = NULL;
+
+ (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p);
+ return log_dhcp6_client_errno(client, r,
+ "Failed to bind to UDP socket at address %s: %m", strna(p));
+ }
client->fd = r;
@@ -1196,7 +1198,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
goto error;
r = sd_event_source_set_description(client->receive_message,
- "dhcp6-receive-message");
+ "dhcp6-receive-message");
if (r < 0)
goto error;
@@ -1204,8 +1206,8 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
state = DHCP6_STATE_INFORMATION_REQUEST;
log_dhcp6_client(client, "Started in %s mode",
- client->information_request? "Information request":
- "Managed");
+ client->information_request? "Information request":
+ "Managed");
return client_start(client, state);
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index cc7436db6b..c1f43c824b 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -28,6 +28,7 @@
#include "alloc-util.h"
#include "arp-util.h"
+#include "ether-addr-util.h"
#include "fd-util.h"
#include "in-addr-util.h"
#include "list.h"
@@ -155,8 +156,10 @@ static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counte
static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) {
assert(ll);
- if (ll->cb)
- ll->cb(ll, event, ll->userdata);
+ if (!ll->cb)
+ return;
+
+ ll->cb(ll, event, ll->userdata);
}
static void ipv4acd_stop(sd_ipv4acd *ll) {
@@ -346,22 +349,36 @@ static void ipv4acd_on_conflict(sd_ipv4acd *ll) {
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT);
}
-static int ipv4acd_on_packet(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+static int ipv4acd_on_packet(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+
sd_ipv4acd *ll = userdata;
struct ether_arp packet;
+ ssize_t n;
int r;
+ assert(s);
assert(ll);
assert(fd >= 0);
- r = read(fd, &packet, sizeof(struct ether_arp));
- if (r < (int) sizeof(struct ether_arp))
+ n = recv(fd, &packet, sizeof(struct ether_arp), 0);
+ if (n < 0) {
+ r = log_ipv4acd_debug_errno(ll, errno, "Failed to read ARP packet: %m");
goto out;
+ }
+ if ((size_t) n != sizeof(struct ether_arp)) {
+ log_ipv4acd_debug(ll, "Ignoring too short ARP packet.");
+ return 0;
+ }
switch (ll->state) {
+
case IPV4ACD_STATE_ANNOUNCING:
case IPV4ACD_STATE_RUNNING:
+
if (ipv4acd_arp_conflict(ll, &packet)) {
usec_t ts;
@@ -380,15 +397,15 @@ static int ipv4acd_on_packet(sd_event_source *s, int fd,
} else
ipv4acd_on_conflict(ll);
}
-
break;
+
case IPV4ACD_STATE_WAITING_PROBE:
case IPV4ACD_STATE_PROBING:
case IPV4ACD_STATE_WAITING_ANNOUNCE:
/* BPF ensures this packet indicates a conflict */
ipv4acd_on_conflict(ll);
-
break;
+
default:
assert_not_reached("Invalid state.");
}
@@ -472,16 +489,6 @@ int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
return ll->state != IPV4ACD_STATE_INIT;
}
-static bool ether_addr_is_nul(const struct ether_addr *addr) {
- const struct ether_addr nul_addr = {};
-
- assert(addr);
-
- return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0;
-}
-
-#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
-
int sd_ipv4acd_start(sd_ipv4acd *ll) {
int r;
@@ -489,7 +496,7 @@ int sd_ipv4acd_start(sd_ipv4acd *ll) {
assert_return(ll->event, -EINVAL);
assert_return(ll->index > 0, -EINVAL);
assert_return(ll->address != 0, -EINVAL);
- assert_return(!ether_addr_is_nul(&ll->mac_addr), -EINVAL);
+ assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL);
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
ll->defend_window = 0;
diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c
index a233e0378c..8cdbfb8ed8 100644
--- a/src/libsystemd-network/test-ipv4ll.c
+++ b/src/libsystemd-network/test-ipv4ll.c
@@ -38,7 +38,8 @@ static int test_fd[2];
static int basic_request_handler_bind = 0;
static int basic_request_handler_stop = 0;
-static void* basic_request_handler_userdata = (void*)0xCABCAB;
+static void* basic_request_handler_userdata = (void*) 0xCABCAB;
+
static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) {
assert_se(userdata == basic_request_handler_userdata);
@@ -181,16 +182,16 @@ static void test_basic_request(sd_event *e) {
/* PROBE */
sd_event_run(e, (uint64_t) -1);
- assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
+ assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp));
if (extended) {
/* PROBE */
sd_event_run(e, (uint64_t) -1);
- assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
+ assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp));
/* PROBE */
sd_event_run(e, (uint64_t) -1);
- assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
+ assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp));
sd_event_run(e, (uint64_t) -1);
assert_se(basic_request_handler_bind == 1);
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index 6fdb474b5e..bfe967bfb0 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -1079,10 +1079,21 @@ static int message_pcap(sd_bus_message *m, FILE *f) {
}
static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
- bool added_something = false;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char **i;
+ uint32_t flags = 0;
int r;
+ /* upgrade connection; it's not used for anything else after this call */
+ r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(message, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
STRV_FOREACH(i, argv+1) {
_cleanup_free_ char *m = NULL;
@@ -1095,34 +1106,38 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL
if (!m)
return log_oom();
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', m);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ return bus_log_create_error(r);
free(m);
m = strjoin("destination='", *i, "'", NULL);
if (!m)
return log_oom();
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', m);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
+ return bus_log_create_error(r);
}
STRV_FOREACH(i, arg_matches) {
- r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', *i);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
+ return bus_log_create_error(r);
}
- if (!added_something) {
- r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ r = sd_bus_message_close_container(message);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(message, 'u', &flags);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
+ if (r < 0) {
+ log_error("%s", bus_error_message(&error, r));
+ return r;
}
log_info("Monitoring bus message stream.");
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index b1c3d5f228..5c9e00ed80 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -533,7 +533,7 @@ int device_read_uevent_file(sd_device *device) {
return r;
}
- for (i = 0; i < uevent_len; i++) {
+ for (i = 0; i < uevent_len; i++)
switch (state) {
case PRE_KEY:
if (!strchr(NEWLINE, uevent[i])) {
@@ -558,10 +558,9 @@ int device_read_uevent_file(sd_device *device) {
break;
case PRE_VALUE:
value = &uevent[i];
-
state = VALUE;
- break;
+ /* fall through to handle empty property */
case VALUE:
if (strchr(NEWLINE, uevent[i])) {
uevent[i] = '\0';
@@ -577,7 +576,6 @@ int device_read_uevent_file(sd_device *device) {
default:
assert_not_reached("invalid state when parsing uevent file");
}
- }
if (major) {
r = device_set_devnum(device, major, minor);
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index f9b6787187..58c2e892f5 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -217,7 +217,7 @@ static void test_event_loop(int ifindex) {
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, NULL) >= 0);
assert_se(sd_event_default(&event) >= 0);
@@ -258,7 +258,7 @@ static void test_async(int ifindex) {
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, &serial) >= 0);
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
assert_se(sd_netlink_process(rtnl, &r) >= 0);
@@ -277,10 +277,10 @@ static void test_pipe(int ifindex) {
assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
counter++;
- assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, &counter, 0, NULL) >= 0);
counter++;
- assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, &counter, 0, NULL) >= 0);
while (counter > 0) {
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
@@ -330,12 +330,12 @@ static void test_match(void) {
assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
- assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+ assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
+ assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 0);
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules
index 886c5bfcdf..50dcd2e275 100644
--- a/src/login/70-uaccess.rules
+++ b/src/login/70-uaccess.rules
@@ -42,9 +42,8 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess"
SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess"
SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess"
-# DRI and frame buffer video devices
+# DRI video devices
SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess"
-SUBSYSTEM=="graphics", KERNEL=="fb*", TAG+="uaccess"
# KVM
SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 4eb0d927a6..367c340e08 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -98,6 +98,9 @@ void address_free(Address *address) {
if (address->link) {
set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address);
+
+ if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
+ memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
}
free(address);
@@ -331,6 +334,10 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
assert(address);
assert(cinfo);
+ assert_return(address->link, 1);
+
+ if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
ready = address_is_ready(address);
@@ -338,19 +345,18 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
address->scope = scope;
address->cinfo = *cinfo;
- if (address->link) {
- link_update_operstate(address->link);
-
- if (!ready && address_is_ready(address)) {
- link_check_ready(address->link);
-
- if (address->family == AF_INET6 &&
- in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
- in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
- r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
- if (r < 0)
- return r;
- }
+ link_update_operstate(address->link);
+
+ if (!ready && address_is_ready(address)) {
+ link_check_ready(address->link);
+
+ if (address->family == AF_INET6 &&
+ in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
+ in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
+
+ r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
+ if (r < 0)
+ return r;
}
}
@@ -404,8 +410,11 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi
return 0;
}
-int address_remove(Address *address, Link *link,
- sd_netlink_message_handler_t callback) {
+int address_remove(
+ Address *address,
+ Link *link,
+ sd_netlink_message_handler_t callback) {
+
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 89926e8a7e..2ddcee9db8 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -96,7 +96,7 @@ static int link_set_dhcp_routes(Link *link) {
route_gw->protocol = RTPROT_DHCP;
route_gw->priority = link->network->dhcp_route_metric;
- r = route_configure(route_gw, link, &dhcp4_route_handler);
+ r = route_configure(route_gw, link, dhcp4_route_handler);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set host route: %m");
@@ -107,7 +107,7 @@ static int link_set_dhcp_routes(Link *link) {
route->prefsrc.in = address;
route->priority = link->network->dhcp_route_metric;
- r = route_configure(route, link, &dhcp4_route_handler);
+ r = route_configure(route, link, dhcp4_route_handler);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set routes: %m");
link_enter_failed(link);
@@ -137,7 +137,7 @@ static int link_set_dhcp_routes(Link *link) {
assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
route->priority = link->network->dhcp_route_metric;
- r = route_configure(route, link, &dhcp4_route_handler);
+ r = route_configure(route, link, dhcp4_route_handler);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set host route: %m");
@@ -177,7 +177,7 @@ static int dhcp_lease_lost(Link *link) {
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
route_remove(route, link,
- &link_route_remove_handler);
+ link_route_remove_handler);
}
}
}
@@ -198,7 +198,7 @@ static int dhcp_lease_lost(Link *link) {
route_gw->scope = RT_SCOPE_LINK;
route_remove(route_gw, link,
- &link_route_remove_handler);
+ link_route_remove_handler);
}
r = route_new(&route);
@@ -207,7 +207,7 @@ static int dhcp_lease_lost(Link *link) {
route->gw.in = gateway;
route_remove(route, link,
- &link_route_remove_handler);
+ link_route_remove_handler);
}
}
@@ -221,7 +221,7 @@ static int dhcp_lease_lost(Link *link) {
address->in_addr.in = addr;
address->prefixlen = prefixlen;
- address_remove(address, link, &link_address_remove_handler);
+ address_remove(address, link, link_address_remove_handler);
}
}
@@ -309,7 +309,7 @@ static int dhcp4_update_address(Link *link,
/* allow reusing an existing address and simply update its lifetime
* in case it already exists */
- r = address_configure(addr, link, &dhcp4_address_handler, true);
+ r = address_configure(addr, link, dhcp4_address_handler, true);
if (r < 0)
return r;
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index ccca4e9522..37e13e639e 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -103,8 +103,8 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
sd_dhcp6_lease_reset_address_iter(lease);
while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
- &lifetime_preferred,
- &lifetime_valid) >= 0) {
+ &lifetime_preferred,
+ &lifetime_valid) >= 0) {
r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
if (r < 0)
@@ -194,12 +194,6 @@ int dhcp6_request_address(Link *link) {
if (r < 0)
return r;
- if (running) {
- r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0)
- return r;
- }
-
return 0;
}
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 35c9b06473..ae323d595b 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -51,7 +51,7 @@ static int ipv4ll_address_lost(Link *link) {
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
- address_remove(address, link, &link_address_remove_handler);
+ address_remove(address, link, link_address_remove_handler);
r = route_new(&route);
if (r < 0) {
@@ -63,7 +63,7 @@ static int ipv4ll_address_lost(Link *link) {
route->scope = RT_SCOPE_LINK;
route->priority = IPV4LL_ROUTE_METRIC;
- route_remove(route, link, &link_route_remove_handler);
+ route_remove(route, link, link_route_remove_handler);
link_check_ready(link);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 4e3f62cf51..a021fc886f 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -686,6 +686,9 @@ void link_check_ready(Link *link) {
assert(link);
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
if (!link->network)
return;
@@ -760,7 +763,7 @@ static int link_enter_set_routes(Link *link) {
link_set_state(link, LINK_STATE_SETTING_ROUTES);
LIST_FOREACH(routes, rt, link->network->static_routes) {
- r = route_configure(rt, link, &route_handler);
+ r = route_configure(rt, link, route_handler);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set routes: %m");
link_enter_failed(link);
@@ -929,7 +932,7 @@ static int link_enter_set_addresses(Link *link) {
link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
- r = address_configure(ad, link, &address_handler, false);
+ r = address_configure(ad, link, address_handler, false);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set addresses: %m");
link_enter_failed(link);
@@ -1020,6 +1023,12 @@ static int link_enter_set_addresses(Link *link) {
log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m");
}
+ r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to set router emission for DHCP server: %m");
+ return r;
+ }
+
if (link->network->dhcp_server_emit_timezone) {
_cleanup_free_ char *buffer = NULL;
const char *tz = NULL;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 5dcd4df536..9174dcc7f4 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -457,11 +457,9 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
break;
case RTM_DELROUTE:
-
- if (route)
- route_drop(route);
-
+ route_free(route);
break;
+
default:
assert_not_reached("Received invalid RTNL message type");
}
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index b22c58bfe5..1a380bd214 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -157,6 +157,10 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a
if (flags & ND_RA_FLAG_MANAGED)
dhcp6_request_address(link);
+ r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
+ if (r < 0 && r != -EBUSY)
+ log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m");
+
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0 && r != -EBUSY)
log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
@@ -203,6 +207,10 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
case SD_NDISC_EVENT_TIMEOUT:
dhcp6_request_address(link);
+ r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
+ if (r < 0 && r != -EBUSY)
+ log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m");
+
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0 && r != -EBUSY)
log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 3e44dd7960..4cfd00413f 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -96,6 +96,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
}
+ if (b->mcast_snooping >= 0) {
+ r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_SNOOPING, b->mcast_snooping);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
@@ -121,6 +127,7 @@ static void bridge_init(NetDev *n) {
assert(b);
b->mcast_querier = -1;
+ b->mcast_snooping = -1;
}
const NetDevVTable bridge_vtable = {
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index b921439f02..f2ae21fc50 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -25,6 +25,7 @@ typedef struct Bridge {
NetDev meta;
int mcast_querier;
+ int mcast_snooping;
usec_t forward_delay;
usec_t hello_time;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 1ebd0fdf20..ba04bb0165 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -99,3 +99,4 @@ Bridge.HelloTimeSec, config_parse_sec, 0,
Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
+Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index d7d014f05d..851a36290c 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -656,7 +656,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
if (!netdev->filename)
return log_oom();
- if (!netdev->mac) {
+ if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) {
r = netdev_get_mac(netdev->ifname, &netdev->mac);
if (r < 0)
return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 4425ee4e2f..03e4e3b39f 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -95,6 +95,7 @@ DHCPServer.EmitDNS, config_parse_bool,
DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0
DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp)
DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0
+DHCPServer.EmitRouter, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_router)
DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 206c270e50..dd89b3770c 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -113,6 +113,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->dhcp_server_emit_dns = true;
network->dhcp_server_emit_ntp = true;
+ network->dhcp_server_emit_router = true;
network->dhcp_server_emit_timezone = true;
network->use_bpdu = true;
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 4cd0fa4ab8..91099161ce 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -127,6 +127,7 @@ struct Network {
bool dhcp_server_emit_ntp;
struct in_addr *dhcp_server_ntp;
unsigned n_dhcp_server_ntp;
+ bool dhcp_server_emit_router;
bool dhcp_server_emit_timezone;
char *dhcp_server_timezone;
usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 43f37266d8..f001de772a 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -324,12 +324,6 @@ int route_update(Route *route,
return 0;
}
-void route_drop(Route *route) {
- assert(route);
-
- route_free(route);
-}
-
int route_remove(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
@@ -375,7 +369,7 @@ int route_remove(Route *route, Link *link,
else if (route->family == AF_INET6)
r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
if (r < 0)
- return log_error_errno(r, "Could not append RTA_DST attribute: %m");
+ return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
if (r < 0)
@@ -412,15 +406,45 @@ int route_remove(Route *route, Link *link,
return 0;
}
+static int route_expire_callback(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ Link *link = userdata;
+ int r;
+
+ assert(rtnl);
+ assert(m);
+ assert(link);
+ assert(link->ifname);
+ assert(link->link_messages > 0);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ link->link_messages--;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_warning_errno(link, r, "could not remove route: %m");
+
+ if (link->link_messages == 0)
+ log_link_debug(link, "route removed");
+
+ return 1;
+}
+
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
Route *route = userdata;
int r;
assert(route);
- r = route_remove(route, route->link, NULL);
+ r = route_remove(route, route->link, route_expire_callback);
if (r < 0)
log_warning_errno(r, "Could not remove route: %m");
+ else {
+ /* route may not be exist in kernel. If we fail still remove it */
+ route->link->link_messages++;
+ route_free(route);
+ }
return 1;
}
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 84d74992c9..39de8363ed 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -61,7 +61,6 @@ int route_get(Link *link, int family, union in_addr_union *dst, unsigned char ds
int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
-void route_drop(Route *route);
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c
index 9bd30b82c6..0e1a18457d 100644
--- a/src/network/test-networkd-conf.c
+++ b/src/network/test-networkd-conf.c
@@ -21,9 +21,11 @@
#include "log.h"
#include "macro.h"
#include "string-util.h"
+#include "ether-addr-util.h"
#include "networkd-conf.h"
#include "networkd-network.h"
+#include "network-internal.h"
static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) {
DUIDType actual = 0;
@@ -60,6 +62,21 @@ static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, cons
}
}
+static void test_config_parse_hwaddr_one(const char *rvalue, int ret, const struct ether_addr* expected) {
+ struct ether_addr *actual = NULL;
+ int r;
+
+ r = config_parse_hwaddr("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ assert_se(ret == r);
+ if (expected) {
+ assert_se(actual);
+ assert(ether_addr_equal(expected, actual));
+ } else {
+ assert_se(actual == NULL);
+ }
+ free(actual);
+}
+
#define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80"
#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80}
@@ -80,12 +97,46 @@ static void test_config_parse_duid_rawdata(void) {
test_config_parse_duid_rawdata_one(BYTES_0_128 + 2, 0, &(DUID){0, 128, BYTES_1_128});
}
+static void test_config_parse_hwaddr(void) {
+ const struct ether_addr t[] = {
+ { .ether_addr_octet = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } },
+ { .ether_addr_octet = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } },
+ };
+ test_config_parse_hwaddr_one("", 0, NULL);
+ test_config_parse_hwaddr_one("no:ta:ma:ca:dd:re", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:fx", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff", 0, &t[0]);
+ test_config_parse_hwaddr_one(" aa:bb:cc:dd:ee:ff", 0, &t[0]);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\n", 0, &t[0]);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\nxxx", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc: dd:ee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:d d:ee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee", 0, NULL);
+ test_config_parse_hwaddr_one("9:aa:bb:cc:dd:ee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff:gg", 0, NULL);
+ test_config_parse_hwaddr_one("aa:Bb:CC:dd:ee:ff", 0, &t[0]);
+ test_config_parse_hwaddr_one("01:23:45:67:89:aB", 0, &t[1]);
+ test_config_parse_hwaddr_one("1:23:45:67:89:aB", 0, &t[1]);
+ test_config_parse_hwaddr_one("aa-bb-cc-dd-ee-ff", 0, &t[0]);
+ test_config_parse_hwaddr_one("AA-BB-CC-DD-EE-FF", 0, &t[0]);
+ test_config_parse_hwaddr_one("01-23-45-67-89-ab", 0, &t[1]);
+ test_config_parse_hwaddr_one("aabb.ccdd.eeff", 0, &t[0]);
+ test_config_parse_hwaddr_one("0123.4567.89ab", 0, &t[1]);
+ test_config_parse_hwaddr_one("123.4567.89ab.", 0, NULL);
+ test_config_parse_hwaddr_one("aabbcc.ddeeff", 0, NULL);
+ test_config_parse_hwaddr_one("aabbccddeeff", 0, NULL);
+ test_config_parse_hwaddr_one("aabbccddee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("012345.6789ab", 0, NULL);
+ test_config_parse_hwaddr_one("123.4567.89ab", 0, &t[1]);
+}
+
int main(int argc, char **argv) {
log_parse_environment();
log_open();
test_config_parse_duid_type();
test_config_parse_duid_rawdata();
+ test_config_parse_hwaddr();
return 0;
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 8ec058431b..ac11bcea5a 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2446,10 +2446,9 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
switch (status.si_code) {
case CLD_EXITED:
- if (status.si_status == 0) {
+ if (status.si_status == 0)
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s exited successfully.", arg_machine);
-
- } else
+ else
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s failed with error code %i.", arg_machine, status.si_status);
*container = CONTAINER_TERMINATED;
@@ -2457,13 +2456,11 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
case CLD_KILLED:
if (status.si_status == SIGINT) {
-
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s has been shut down.", arg_machine);
*container = CONTAINER_TERMINATED;
return 0;
} else if (status.si_status == SIGHUP) {
-
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s is being rebooted.", arg_machine);
*container = CONTAINER_REBOOTED;
return 0;
@@ -2479,8 +2476,6 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
log_error("Container %s failed due to unknown reason.", arg_machine);
return -EIO;
}
-
- return r;
}
static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 49d488cec5..3095c042db 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -157,6 +157,7 @@ void dns_server_unlink(DnsServer *s) {
assert(s->link);
assert(s->link->n_dns_servers > 0);
LIST_REMOVE(servers, s->link->dns_servers, s);
+ s->link->n_dns_servers--;
break;
case DNS_SERVER_SYSTEM:
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index b3ff46b5da..9600bde1e9 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -643,6 +643,8 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
mh.msg_controllen = sizeof(control);
l = recvmsg(fd, &mh, 0);
+ if (l == 0)
+ return 0;
if (l < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
@@ -650,9 +652,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
return -errno;
}
- if (l <= 0)
- return -EIO;
-
assert(!(mh.msg_flags & MSG_CTRUNC));
assert(!(mh.msg_flags & MSG_TRUNC));
diff --git a/src/run/run.c b/src/run/run.c
index 1d0f74ad21..d6c9b6d37a 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -760,6 +760,7 @@ static int start_transient_service(
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
_cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL;
const char *s;
r = sd_bus_default_system(&system_bus);
@@ -772,19 +773,17 @@ static int start_transient_service(
"org.freedesktop.machine1.Manager",
"OpenMachinePTY",
&error,
- &reply,
+ &pty_reply,
"s", arg_host);
if (r < 0) {
log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
return r;
}
- r = sd_bus_message_read(reply, "hs", &master, &s);
+ r = sd_bus_message_read(pty_reply, "hs", &master, &s);
if (r < 0)
return bus_log_parse_error(r);
- reply = sd_bus_message_unref(reply);
-
master = fcntl(master, F_DUPFD_CLOEXEC, 3);
if (master < 0)
return log_error_errno(errno, "Failed to duplicate master fd: %m");
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index cfced96804..f6559cd854 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -154,7 +154,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
} else if (STR_IN_SET(field,
- "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
+ "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting",
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
"PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
@@ -207,6 +207,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "t", u);
+ } else if (STR_IN_SET(field, "IOWeight", "StartupIOWeight")) {
+ uint64_t u;
+
+ r = cg_weight_parse(eq, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", u);
+
} else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
uint64_t u;
@@ -224,7 +235,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"StandardInput", "StandardOutput", "StandardError",
"Description", "Slice", "Type", "WorkingDirectory",
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
- "ProtectHome"))
+ "ProtectHome", "SELinuxContext"))
r = sd_bus_message_append(m, "v", "s", eq);
else if (streq(field, "SyslogLevel")) {
@@ -273,7 +284,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
}
- } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
+ } else if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(st)", 0);
@@ -295,16 +306,20 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return -EINVAL;
}
- r = parse_size(bandwidth, 1000, &bytes);
- if (r < 0) {
- log_error("Failed to parse byte value %s.", bandwidth);
- return -EINVAL;
+ if (streq(bandwidth, "max")) {
+ bytes = CGROUP_LIMIT_MAX;
+ } else {
+ r = parse_size(bandwidth, 1000, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse byte value %s.", bandwidth);
+ return -EINVAL;
+ }
}
r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
}
- } else if (streq(field, "BlockIODeviceWeight")) {
+ } else if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(st)", 0);
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index 97865eac4a..f73108eaa3 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -29,12 +29,10 @@
#include <string.h>
#include <sys/socket.h>
#include <net/if.h>
-#include <linux/if.h>
#ifndef IFNAMSIZ
-#undef _NET_IF_H
-/* Let's make sure to include this one, too, if IFNAMSIZ isn't defined yet, as it is for kernels <= 4.2 */
-#include <net/if.h>
+#define IFNAMSIZ 16
#endif
+#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index bc35c25c1b..b943c68e1b 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -102,6 +102,7 @@ static bool arg_no_block = false;
static bool arg_no_legend = false;
static bool arg_no_pager = false;
static bool arg_no_wtmp = false;
+static bool arg_no_sync = false;
static bool arg_no_wall = false;
static bool arg_no_reload = false;
static bool arg_value = false;
@@ -4428,7 +4429,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return 0;
- } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
+ } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "IODeviceWeight") || streq(name, "BlockIODeviceWeight"))) {
const char *path;
uint64_t weight;
@@ -4447,7 +4448,8 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return 0;
- } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
+ } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (cgroup_io_limit_type_from_string(name) >= 0 ||
+ streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
const char *path;
uint64_t bandwidth;
@@ -5461,7 +5463,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int carries_install_info = -1;
- bool ignore_carries_install_info = false;
+ bool ignore_carries_install_info = arg_quiet;
int r;
if (!argv[1])
@@ -5476,8 +5478,11 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
return r;
/* If the operation was fully executed by the SysV compat, let's finish early */
- if (strv_isempty(names))
- return 0;
+ if (strv_isempty(names)) {
+ if (arg_no_reload || install_client_side())
+ return 0;
+ return daemon_reload(argc, argv, userdata);
+ }
if (install_client_side()) {
if (streq(verb, "enable")) {
@@ -6925,6 +6930,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
{ "force", no_argument, NULL, 'f' },
{ "wtmp-only", no_argument, NULL, 'w' },
{ "no-wtmp", no_argument, NULL, 'd' },
+ { "no-sync", no_argument, NULL, 'n' },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{}
};
@@ -6970,13 +6976,16 @@ static int halt_parse_argv(int argc, char *argv[]) {
arg_no_wtmp = true;
break;
+ case 'n':
+ arg_no_sync = true;
+ break;
+
case ARG_NO_WALL:
arg_no_wall = true;
break;
case 'i':
case 'h':
- case 'n':
/* Compatibility nops */
break;
@@ -7495,7 +7504,8 @@ static int halt_now(enum action a) {
/* The kernel will automaticall flush ATA disks and suchlike
* on reboot(), but the file systems need to be synce'd
* explicitly in advance. */
- (void) sync();
+ if (!arg_no_sync)
+ (void) sync();
/* Make sure C-A-D is handled by the kernel from this point
* on... */
diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h
index fcef083ce6..d4517a26d6 100644
--- a/src/systemd/sd-dhcp-server.h
+++ b/src/systemd/sd-dhcp-server.h
@@ -51,6 +51,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n);
int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n);
+int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t);
int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index 4eb8fcd773..a027eb0fd2 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -48,6 +48,7 @@ static int test_cgroup_mask(void) {
m->default_cpu_accounting =
m->default_memory_accounting =
m->default_blockio_accounting =
+ m->default_io_accounting =
m->default_tasks_accounting = false;
m->default_tasks_max = (uint64_t) -1;
@@ -76,7 +77,7 @@ static int test_cgroup_mask(void) {
assert_se(unit_get_own_mask(daughter) == 0);
assert_se(unit_get_own_mask(grandchild) == 0);
assert_se(unit_get_own_mask(parent_deep) == CGROUP_MASK_MEMORY);
- assert_se(unit_get_own_mask(parent) == CGROUP_MASK_BLKIO);
+ assert_se(unit_get_own_mask(parent) == (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
assert_se(unit_get_own_mask(root) == 0);
/* Verify aggregation of member masks */
@@ -85,23 +86,23 @@ static int test_cgroup_mask(void) {
assert_se(unit_get_members_mask(grandchild) == 0);
assert_se(unit_get_members_mask(parent_deep) == 0);
assert_se(unit_get_members_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
- assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+ assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
/* Verify aggregation of sibling masks. */
assert_se(unit_get_siblings_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
assert_se(unit_get_siblings_mask(daughter) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
assert_se(unit_get_siblings_mask(grandchild) == 0);
assert_se(unit_get_siblings_mask(parent_deep) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
- assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
- assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+ assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+ assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
/* Verify aggregation of target masks. */
assert_se(unit_get_target_mask(son) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported));
assert_se(unit_get_target_mask(daughter) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported));
assert_se(unit_get_target_mask(grandchild) == 0);
assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported));
- assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
- assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
+ assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
+ assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
manager_free(m);
@@ -109,7 +110,7 @@ static int test_cgroup_mask(void) {
}
int main(int argc, char* argv[]) {
- _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int rc = 0;
assert_se(runtime_dir = setup_fake_runtime_dir());
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index 361d1e7b0b..23da10fa1a 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -28,7 +28,7 @@
#include "tests.h"
int main(int argc, char *argv[]) {
- _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
Manager *m = NULL;
Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index ec9f173da2..79609765e0 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -289,7 +289,7 @@ static void test_capeff(void) {
assert_se(r == 0);
assert_se(*capeff);
- p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")];
+ p = capeff[strspn(capeff, HEXDIGITS)];
assert_se(!p || isspace(p));
}
}
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 435cafd83a..62181e22a0 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -255,7 +255,7 @@ int main(int argc, char *argv[]) {
NULL,
};
- _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
const test_function_t *test = NULL;
Manager *m = NULL;
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
index 3e9caafc71..c068f5c39e 100644
--- a/src/test/test-sched-prio.c
+++ b/src/test/test-sched-prio.c
@@ -26,7 +26,7 @@
#include "tests.h"
int main(int argc, char *argv[]) {
- _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
Manager *m = NULL;
Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
Service *ser;
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index c340673c6c..ade0ff2a63 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -842,7 +842,7 @@ static void test_config_parse_pass_environ(void) {
}
int main(int argc, char *argv[]) {
- _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int r;
log_parse_environment();
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index 7182668f23..66b51c1209 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -156,7 +156,7 @@ static int stat_device(const char *name, bool export, const char *prefix) {
struct stat statbuf;
if (stat(name, &statbuf) != 0)
- return -1;
+ return -errno;
if (export) {
if (prefix == NULL)
@@ -171,23 +171,22 @@ static int stat_device(const char *name, bool export, const char *prefix) {
}
static int export_devices(struct udev *udev) {
- struct udev_enumerate *udev_enumerate;
+ _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate;
struct udev_list_entry *list_entry;
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
- return -1;
+ return -ENOMEM;
+
udev_enumerate_scan_devices(udev_enumerate);
udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
- struct udev_device *device;
+ _cleanup_udev_device_unref_ struct udev_device *device;
device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
- if (device != NULL) {
+ if (device != NULL)
print_record(device);
- udev_device_unref(device);
- }
}
- udev_enumerate_unref(udev_enumerate);
+
return 0;
}
@@ -220,39 +219,29 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
}
static void cleanup_db(struct udev *udev) {
- DIR *dir;
+ _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL;
- unlink("/run/udev/queue.bin");
+ (void) unlink("/run/udev/queue.bin");
- dir = opendir("/run/udev/data");
- if (dir != NULL) {
- cleanup_dir(dir, S_ISVTX, 1);
- closedir(dir);
- }
+ dir1 = opendir("/run/udev/data");
+ if (dir1 != NULL)
+ cleanup_dir(dir1, S_ISVTX, 1);
- dir = opendir("/run/udev/links");
- if (dir != NULL) {
- cleanup_dir(dir, 0, 2);
- closedir(dir);
- }
+ dir2 = opendir("/run/udev/links");
+ if (dir2 != NULL)
+ cleanup_dir(dir2, 0, 2);
- dir = opendir("/run/udev/tags");
- if (dir != NULL) {
- cleanup_dir(dir, 0, 2);
- closedir(dir);
- }
+ dir3 = opendir("/run/udev/tags");
+ if (dir3 != NULL)
+ cleanup_dir(dir3, 0, 2);
- dir = opendir("/run/udev/static_node-tags");
- if (dir != NULL) {
- cleanup_dir(dir, 0, 2);
- closedir(dir);
- }
+ dir4 = opendir("/run/udev/static_node-tags");
+ if (dir4 != NULL)
+ cleanup_dir(dir4, 0, 2);
- dir = opendir("/run/udev/watch");
- if (dir != NULL) {
- cleanup_dir(dir, 0, 1);
- closedir(dir);
- }
+ dir5 = opendir("/run/udev/watch");
+ if (dir5 != NULL)
+ cleanup_dir(dir5, 0, 1);
}
static void help(void) {
@@ -374,7 +363,8 @@ static int uinfo(struct udev *udev, int argc, char *argv[]) {
action = ACTION_ATTRIBUTE_WALK;
break;
case 'e':
- export_devices(udev);
+ if (export_devices(udev) < 0)
+ return 1;
return 0;
case 'c':
cleanup_db(udev);
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index 8a1b824e65..1118118450 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -195,9 +195,15 @@ static void font_copy_to_all_vcs(int fd) {
unsigned char map8[E_TABSZ];
unsigned short map16[E_TABSZ];
struct unimapdesc unimapd;
- struct unipair unipairs[USHRT_MAX];
+ _cleanup_free_ struct unipair* unipairs = NULL;
int i, r;
+ unipairs = new(struct unipair, USHRT_MAX);
+ if (!unipairs) {
+ log_oom();
+ return;
+ }
+
/* get active, and 16 bit mask of used VT numbers */
r = ioctl(fd, VT_GETSTATE, &vcs);
if (r < 0) {