summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS131
-rw-r--r--man/halt.xml8
-rw-r--r--man/systemd.network.xml5
-rw-r--r--man/systemd.resource-control.xml49
-rw-r--r--rules/60-persistent-storage.rules2
-rw-r--r--src/basic/cgroup-util.c16
-rw-r--r--src/basic/cgroup-util.h16
-rw-r--r--src/basic/ether-addr-util.c69
-rw-r--r--src/basic/ether-addr-util.h2
-rw-r--r--src/basic/rm-rf.h6
-rw-r--r--src/basic/string-util.h1
-rw-r--r--src/core/cgroup.c363
-rw-r--r--src/core/cgroup.h8
-rw-r--r--src/core/dbus-cgroup.c91
-rw-r--r--src/core/dbus-execute.c56
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c63
-rw-r--r--src/libsystemd-network/network-internal.c15
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c3
-rw-r--r--src/network/test-networkd-conf.c51
-rw-r--r--src/resolve/resolved-dns-server.c1
-rw-r--r--src/shared/bus-unit-util.c5
-rw-r--r--src/shared/firewall-util.c6
-rw-r--r--src/systemctl/systemctl.c21
-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--test/parent.slice2
31 files changed, 711 insertions, 306 deletions
diff --git a/NEWS b/NEWS
index a6e0581879..cce8883193 100644
--- a/NEWS
+++ b/NEWS
@@ -24,7 +24,7 @@ CHANGES WITH 230 in spe:
* systemd-resolve conveniently resolves DANE records with the --tlsa
option and OPENPGPKEY records with the --openpgp option. It also
- supports dumping raw DNS record data via the new --raw= switch now.
+ supports dumping raw DNS record data via the new --raw= switch.
* systemd-logind will now by default terminate user processes that are
part of the user session scope unit (session-XX.scope) when the user
@@ -51,6 +51,12 @@ CHANGES WITH 230 in spe:
Previous defaults can be restored at compile time by the
--without-kill-user-processes option to "configure".
+ * systemd-logind gained new configuration settings SessionsMax= and
+ InhibitorsMax=, both with a default of 8192. It will not register new
+ user sessions or inhibitors above this limit.
+
+ * systemd-logind will now reload configuration on SIGHUP.
+
* The unified cgroup hierarchy added in Linux 4.5 is now supported.
Use systemd.unified_cgroup_hierarchy=1 on the kernel command line to
enable. Also, support for the "io" cgroup controller in the unified
@@ -71,7 +77,22 @@ CHANGES WITH 230 in spe:
* The IAID and DUID unique identifier sent in DHCP requests may now be
configured for the system and each .network file managed by
- systemd-networkd.
+ systemd-networkd using the DUIDType=, DUIDRawData=, IAID= options.
+
+ * systemd-networkd gained support for configuring proxy ARP support for
+ each interface, via the ProxyArp= setting in .network files. It also
+ gained support for configuring the multicast querier feature of
+ bridge devices, via the new MulticastQuerier= setting in .netdev
+ files. Similarly, snooping on the IGMP traffic can be controlled
+ via the new setting MulticastSnooping=.
+
+ A new setting PreferredLifetime= has been added for addresses
+ configured in .network file to configure the lifetime intended for an
+ address.
+
+ The systemd-networkd DHCP server gained the option EmitRouter=, which
+ defaults to yes, to configure whether the DHCP Option 3 (Router)
+ should be emitted.
* The testing tool /usr/lib/systemd/systemd-activate is renamed to
systemd-socket-activate and installed into /usr/bin. It is now fully
@@ -81,6 +102,18 @@ CHANGES WITH 230 in spe:
when closing journal files, thus reducing impact of slow disk I/O on
logging performance.
+ * The sd-journal API gained two new calls
+ sd_journal_open_directory_fd() and sd_journal_open_files_fd() which
+ can be used to open journal files using file descriptors instead of
+ file or directory paths. sd_journal_open_container() has been
+ deprecated, sd_journal_open_directory_fd() should be used instead
+ with the flag SD_JOURNAL_OS_ROOT.
+
+ * journalctl learned a new output mode "-o short-unix" that outputs log
+ lines prefixed by their UNIX time (i.e. seconds since Jan 1st, 1970
+ UTC). It also gained support for a new --no-hostname setting to
+ suppress the hostname column in the family of "short" output modes.
+
* systemd-ask-password now optionally skips printing of the password to
stdout with --no-output which can be useful in scripts.
@@ -88,24 +121,18 @@ CHANGES WITH 230 in spe:
(devices tagged with ID_MAKER_TOOL) are now tagged with
"uaccess" and are available to logged in users.
- * systemd-bootchart has been split out to a separate repository:
- https://github.com/systemd/systemd-bootchart
-
- * The compatibility libraries libsystemd-daemon.so,
- libsystemd-journal.so, libsystemd-id128.so, and libsystemd-login.so
- which have been deprecated since systemd-209 have been removed along
- with the corresponding pkg-config files. All symbols provided by
- those libraries are provided by libsystemd.so.
-
- * The Capabilities= unit file setting has been removed (it is ignored
- for backwards compatibility). AmbientCapabilities= and
- CapabilityBoundingSet= should be used instead.
+ * The DeviceAllow= unit setting now supports specifiers (with "%").
* "systemctl show" gained a new --value switch, which allows print a
only the contents of a specific unit property, without also printing
the property's name. Similar support was added to "show*" verbs
of loginctl and machinectl that output "key=value" lists.
+ * A new unit type "generated" was added for files dynamically generated
+ by generator tools. Similarly, a new unit type "transient" is used
+ for unit files created using the runtime API. "systemctl enable" will
+ refuse to operate on such files.
+
* A new command "systemctl revert" has been added that may be used to
revert to the vendor version of a unit file, in case local changes
have been made by adding drop-ins or overriding the unit file.
@@ -113,25 +140,9 @@ CHANGES WITH 230 in spe:
* "machinectl clean" gained a new verb to automatically remove all or
just hidden container images.
- * systemd-bus-proxyd has been removed, as kdbus is unlikely to still be
- merged into the kernel in its current form.
-
- * systemd-networkd gained support for configuring proxy ARP support for
- each interface, via the ProxyArp= setting in .network files. It also
- gained support for configuring the multicast querier feature of
- bridge devices, via the new MulticastQuerier= setting in .netdev
- files. A new setting PreferredLifetime= has been added for addresses
- configured in .network file to configure the lifetime intended for an
- address.
-
* systemd-tmpfiles gained support for a new line type "e" for emptying
directories, if they exist, without creating them if they don't.
- * journalctl learned a new output mode "-o short-unix" that outputs log
- lines prefixed by their UNIX time (i.e. seconds since Jan 1st, 1970
- UTC). It also gained support for a new --no-hostname setting to
- suppress the hostname column in the family of "short" output modes.
-
* systemd-nspawn gained support for automatically patching the UID/GIDs
of the owners and the ACLs of all files and directories in a
container tree to match the UID/GID user namespacing range selected
@@ -175,38 +186,52 @@ CHANGES WITH 230 in spe:
* Note that the effect of the PrivateDevices= unit file setting changed
slightly with this release: the per-device /dev file system will be
mounted read-only from this version on, and will have "noexec"
- set. This (minor) change of behaviour might cause some (exceptional)
+ set. This (minor) change of behavior might cause some (exceptional)
legacy software to break, when PrivateDevices=yes is set for its
service. Please leave PrivateDevices= off if you run into problems
with this.
- * The systemd-networkd DHCP server gained the option EmitRouter=, which
- defaults to yes, to configure if the DHCP Option 3 (Router) should be
- emitted.
-
- Contributions from: Alban Crequy, Alexander Kuleshov, Alex Crawford,
- Andrew Eikum, Beniamino Galvani, Benjamin Robin, Benjamin ROBIN, Biao
- Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Clemens Gruber, Colin
- Guthrie, Daniel J Walsh, Daniel Mack, Dan Nicholson, daurnimator, David
- Herrmann, David R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko,
- Evgeny Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger,
- Franck Bui, frankheckenbach, Georgia Brikis, Harald Hoyer, Hendrik
+ * systemd-bootchart has been split out to a separate repository:
+ https://github.com/systemd/systemd-bootchart
+
+ * systemd-bus-proxyd has been removed, as kdbus is unlikely to still be
+ merged into the kernel in its current form.
+
+ * The compatibility libraries libsystemd-daemon.so,
+ libsystemd-journal.so, libsystemd-id128.so, and libsystemd-login.so
+ which have been deprecated since systemd-209 have been removed along
+ with the corresponding pkg-config files. All symbols provided by
+ those libraries are provided by libsystemd.so.
+
+ * The Capabilities= unit file setting has been removed (it is ignored
+ for backwards compatibility). AmbientCapabilities= and
+ CapabilityBoundingSet= should be used instead.
+
+ Contributions from: Alban Crequy, Alexander Kuleshov, Alexander Shopov,
+ Alex Crawford, Andre Klärner, Andrew Eikum, Beniamino Galvani, Benjamin
+ Robin, Biao Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Clemens
+ Gruber, Colin Guthrie, Daniel Drake, Daniele Medri, Daniel J Walsh,
+ Daniel Mack, Dan Nicholson, daurnimator, David Herrmann, David
+ R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko, Evgeny
+ Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger, Franck
+ Bui, frankheckenbach, gdamjan, Georgia Brikis, Harald Hoyer, Hendrik
Brueckner, Hristo Venev, Iago López Galeiras, Ian Kelling, Ismo
Puustinen, Jakub Wilk, Jaroslav Škarvada, Jeff Huang, Joel Holdsworth,
- kayrus, Klearchos Chaloulos, Lennart Poettering, Lubomir Rintel, Lukas
- Nykryn, Lukáš Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt,
+ John Paul Adrian Glaubitz, Jonathan Boulle, kayrus, Klearchos
+ Chaloulos, Kyle Russell, Lars Uebernickel, Lennart Poettering, Lubomir
+ Rintel, Lukáš Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt,
Michael Biebl, michaelolbrich, Michał Bartoszkiewicz, Michal Koutný,
Michal Sekletar, Mike Frysinger, Mike Gilbert, Mingcong Bai, Ming Lin,
mulkieran, muzena, Nalin Dahyabhai, Naohiro Aota, Nathan McSween,
- Nicolas Braud-Santoni, Patrik Flykt, Peter Hutterer, Petr Lautrbach,
- Petros Angelatos, Piotr Drąg, Rabin Vincent, Robert Węcławski, Ronny
- Chevalier, Samuel Tardieu, Stefan Schallenberg, Steven Siloti, Susant
- Sahani, Sylvain Plantefève, Taylor Smock, tblume, Tejun Heo, Thomas
- Blume, Thomas Haller, Thomas Hindoe Paaboel Andersen, Thomas
- H. P. Andersen, Tobias Klauser, Tom Gundersen, Torstein Husebø, Umut
- Tezduyar Lindskog, Vinay Kulkarni, Vito Caputo, Vittorio G (VittGam),
- Vladimir Panteleev, Wieland Hoffmann, Wouter Verhelst, Yu Watanabe,
- Zbigniew Jędrzejewski-Szmek
+ Nicolas Braud-Santoni, Patrik Flykt, Peter Hutterer, Peter Mattern,
+ Petr Lautrbach, Petros Angelatos, Piotr Drąg, Rabin Vincent, Robert
+ Węcławski, Ronny Chevalier, Samuel Tardieu, Stefan Saraev, Stefan
+ Schallenberg aka nafets227, Steven Siloti, Susant Sahani, Sylvain
+ Plantefève, Taylor Smock, Tejun Heo, Thomas Blume, Thomas Haller,
+ Thomas H. P. Andersen, Tobias Klauser, Tom Gundersen, topimiettinen,
+ Torstein Husebø, Umut Tezduyar Lindskog, Victor Toso, Vinay Kulkarni,
+ Vito Caputo, Vittorio G (VittGam), Vladimir Panteleev, Wieland
+ Hoffmann, Wouter Verhelst, Yu Watanabe, Zbigniew Jędrzejewski-Szmek
— Berlin, 2016-05-XX
diff --git a/man/halt.xml b/man/halt.xml
index a06dbd0097..e3fa60a915 100644
--- a/man/halt.xml
+++ b/man/halt.xml
@@ -133,6 +133,14 @@
</varlistentry>
<varlistentry>
+ <term><option>-n</option></term>
+ <term><option>--no-sync</option></term>
+
+ <listitem><para>Don't sync hard disks/storage media before
+ halt, power-off, reboot.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--no-wall</option></term>
<listitem><para>Do not send wall message before halt,
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index d917fe2c12..821e22aff8 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -105,7 +105,8 @@
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
- <para>The hardware address.</para>
+ <para>The hardware address of the interface (use full colon-delimited hexadecimal, e.g.,
+ 01:23:45:67:89:ab).</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -198,7 +199,7 @@
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
- <para>The hardware address.</para>
+ <para>The hardware address to set for the device.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 313a49a959..066f2cc19b 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -99,6 +99,31 @@
</refsect1>
<refsect1>
+ <title>Unified and Legacy Control Group Hierarchies</title>
+
+ <para>Unified control group hierarchy is the new version of kernel control group interface. Depending on the
+ resource type, there are differences in resource control capabilities. Also, because of interface changes, some
+ resource types have a separate set of options on the unified hierarchy.</para>
+
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><option>IO</option></term>
+ <listitem>
+ <para><varname>IO</varname> prefixed settings are superset of and replace <varname>BlockIO</varname>
+ prefixed ones. On unified hierarchy, IO resource control also applies to buffered writes.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>To ease the transition, there is best-effort translation between the two versions of settings. If all
+ settings of a unit for a given resource type are for the other hierarchy type, the settings are translated and
+ applied. If there are any valid settings for the hierarchy in use, all translations are disabled for the resource
+ type. Mixing the two types of settings on a unit can lead to confusing results.</para>
+ </refsect1>
+
+ <refsect1>
<title>Options</title>
<para>Units of the types listed above can have settings
@@ -337,6 +362,30 @@
</varlistentry>
<varlistentry>
+ <term><varname>IOReadIOPSMax=<replaceable>device</replaceable> <replaceable>IOPS</replaceable></varname></term>
+ <term><varname>IOWriteIOPSMax=<replaceable>device</replaceable> <replaceable>IOPS</replaceable></varname></term>
+
+ <listitem>
+ <para>Set the per-device overall block I/O IOs-Per-Second maximum limit for the executed processes, if the
+ unified control group hierarchy is used on the system. This limit is not work-conserving and the executed
+ processes are not allowed to use more even if the device has idle capacity. Takes a space-separated pair of
+ a file path and an IOPS value to specify the device specific IOPS. The file path may be a path to a block
+ device node, or as any other file in which case the backing block device of the file system of the file is
+ used. If the IOPS is suffixed with K, M, G, or T, the specified IOPS is parsed as KiloIOPS, MegaIOPS,
+ GigaIOPS, or TeraIOPS, respectively, to the base of 1000. (Example:
+ "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 1K"). This controls the <literal>io.max</literal> control
+ group attributes. Use this option multiple times to set IOPS limits for multiple devices. For details about
+ this control group attribute, see <ulink
+ url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.
+ </para>
+
+ <para>Implies <literal>IOAccounting=true</literal>.</para>
+
+ <para>This setting is supported only if the unified control group hierarchy is used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>BlockIOAccounting=</varname></term>
<listitem>
diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules
index 7ad8a557ff..408733915c 100644
--- a/rules/60-persistent-storage.rules
+++ b/rules/60-persistent-storage.rules
@@ -78,7 +78,7 @@ ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn
ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}-part%n"
# by-partlabel/by-partuuid links (partition metadata)
-ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
+ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
# add symlink to GPT root disk
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index ff57cf30b7..7cdc97ee3c 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2269,6 +2269,22 @@ int cg_weight_parse(const char *s, uint64_t *ret) {
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;
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index a696c1fa60..4bb5291296 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -72,6 +72,22 @@ static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
(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)
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/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/core/cgroup.c b/src/core/cgroup.c
index 4f1637ffe9..8b8b2ac5ff 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -184,20 +184,16 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_limits, il, c->io_device_limits) {
char buf[FORMAT_BYTES_MAX];
-
- if (il->rbps_max != CGROUP_LIMIT_MAX)
- fprintf(f,
- "%sIOReadBandwidthMax=%s %s\n",
- prefix,
- il->path,
- format_bytes(buf, sizeof(buf), il->rbps_max));
-
- if (il->wbps_max != CGROUP_LIMIT_MAX)
- fprintf(f,
- "%sIOWriteBandwidthMax=%s %s\n",
- prefix,
- il->path,
- format_bytes(buf, sizeof(buf), il->wbps_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)
@@ -210,12 +206,18 @@ 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));
}
}
@@ -356,6 +358,154 @@ 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;
@@ -405,19 +555,19 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
}
if (mask & CGROUP_MASK_IO) {
- CGroupIODeviceWeight *w;
- CGroupIODeviceLimit *l, *next;
+ bool has_io = cgroup_context_has_io_config(c);
+ bool has_blockio = cgroup_context_has_blockio_config(c);
if (!is_root) {
- char buf[MAX(8+DECIMAL_STR_MAX(uint64_t)+1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
- uint64_t weight = CGROUP_WEIGHT_DEFAULT;
+ char buf[8+DECIMAL_STR_MAX(uint64_t)+1];
+ uint64_t weight;
- if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
- c->startup_io_weight != CGROUP_WEIGHT_INVALID)
- weight = c->startup_io_weight;
- else if (c->io_weight != CGROUP_WEIGHT_INVALID)
- weight = c->io_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);
@@ -425,103 +575,99 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set io.weight on %s: %m", path);
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_weights, w, c->io_device_weights) {
- dev_t dev;
+ if (has_io) {
+ CGroupIODeviceWeight *w;
- r = lookup_block_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;
- xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->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);
+ /* 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));
}
}
- LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
- char rbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max";
- char wbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max";
- char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2];
- dev_t dev;
- unsigned n = 0;
-
- r = lookup_block_device(l->path, &dev);
- if (r < 0)
- continue;
+ /* Apply limits and free ones without config. */
+ if (has_io) {
+ CGroupIODeviceLimit *l, *next;
- if (l->rbps_max != CGROUP_LIMIT_MAX) {
- xsprintf(rbps_buf, "%" PRIu64, l->rbps_max);
- n++;
+ 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;
- if (l->wbps_max != CGROUP_LIMIT_MAX) {
- xsprintf(wbps_buf, "%" PRIu64, l->wbps_max);
- n++;
- }
+ LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
+ uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
+ CGroupIOLimitType type;
- xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), rbps_buf, wbps_buf);
- 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);
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ limits[type] = cgroup_io_limit_defaults[type];
- /* If @l contained no config, we just cleared the kernel
- counterpart too. No reason to keep @l around. */
- if (!n)
- cgroup_context_free_io_device_limit(c, l);
+ 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) {
- 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;
+ 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);
+ char buf[DECIMAL_STR_MAX(uint64_t)+1];
+ uint64_t weight;
+
+ 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;
+
+ 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 blkio.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_blockio) {
+ CGroupBlockIODeviceWeight *w;
- r = lookup_block_device(w->path, &dev);
- if (r < 0)
- continue;
+ /* 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;
- 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->io_device_weights)
+ cgroup_apply_blkio_device_weight(path, w->path, cgroup_weight_io_to_blkio(w->weight));
}
}
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- const char *a;
- dev_t dev;
-
- r = lookup_block_device(b->path, &dev);
- if (r < 0)
- continue;
+ /* Apply limits and free ones without config. */
+ if (has_blockio) {
+ CGroupBlockIODeviceBandwidth *b, *next;
- a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
+ 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;
- sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
- r = cg_set_attribute("blkio", path, a, 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);
+ 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);
+ }
}
}
@@ -638,19 +784,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->io_accounting ||
- c->io_weight != CGROUP_WEIGHT_INVALID ||
- c->startup_io_weight != CGROUP_WEIGHT_INVALID ||
- c->io_device_weights ||
- c->io_device_limits)
- mask |= CGROUP_MASK_IO;
-
- 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)
@@ -1740,6 +1875,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;
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index a533923072..2b1edbafc4 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -23,6 +23,7 @@
#include "list.h"
#include "time-util.h"
+#include "cgroup-util.h"
typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
@@ -64,8 +65,7 @@ struct CGroupIODeviceWeight {
struct CGroupIODeviceLimit {
LIST_FIELDS(CGroupIODeviceLimit, device_limits);
char *path;
- uint64_t rbps_max;
- uint64_t wbps_max;
+ uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
};
struct CGroupBlockIODeviceWeight {
@@ -77,8 +77,8 @@ struct CGroupBlockIODeviceWeight {
struct CGroupBlockIODeviceBandwidth {
LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths);
char *path;
- uint64_t bandwidth;
- bool read;
+ uint64_t rbps;
+ uint64_t wbps;
};
struct CGroupContext {
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index a2a4a6249c..eef1c47c14 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -80,17 +80,13 @@ static int property_get_io_device_limits(
return r;
LIST_FOREACH(device_limits, l, c->io_device_limits) {
- uint64_t v;
-
- if (streq(property, "IOReadBandwidthMax"))
- v = l->rbps_max;
- else
- v = l->wbps_max;
+ CGroupIOLimitType type;
- if (v == CGROUP_LIMIT_MAX)
+ 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, v);
+ r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
if (r < 0)
return r;
}
@@ -150,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"))
+ v = b->rbps;
+ else
+ v = b->wbps;
- if (streq(property, "BlockIOReadBandwidth") != b->read)
+ 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;
}
@@ -217,6 +219,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
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),
@@ -273,6 +277,7 @@ int bus_cgroup_set_property(
UnitSetPropertiesMode mode,
sd_bus_error *error) {
+ CGroupIOLimitType iol_type;
int r;
assert(u);
@@ -416,15 +421,11 @@ int bus_cgroup_set_property(
return 1;
- } else if (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax")) {
+ } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
const char *path;
- bool read = true;
unsigned n = 0;
uint64_t u64;
- if (streq(name, "IOWriteBandwidthMax"))
- read = false;
-
r = sd_bus_message_enter_container(message, 'a', "(st)");
if (r < 0)
return r;
@@ -442,6 +443,8 @@ int bus_cgroup_set_property(
}
if (!a) {
+ CGroupIOLimitType type;
+
a = new0(CGroupIODeviceLimit, 1);
if (!a)
return -ENOMEM;
@@ -452,16 +455,13 @@ int bus_cgroup_set_property(
return -ENOMEM;
}
- a->rbps_max = CGROUP_LIMIT_MAX;
- a->wbps_max = CGROUP_LIMIT_MAX;
+ 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);
}
- if (read)
- a->rbps_max = u64;
- else
- a->wbps_max = u64;
+ a->limits[iol_type] = u64;
}
n++;
@@ -481,10 +481,7 @@ int bus_cgroup_set_property(
if (n == 0) {
LIST_FOREACH(device_limits, a, c->io_device_limits)
- if (read)
- a->rbps_max = CGROUP_LIMIT_MAX;
- else
- a->wbps_max = CGROUP_LIMIT_MAX;
+ a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
}
unit_invalidate_cgroup(u, CGROUP_MASK_IO);
@@ -493,17 +490,10 @@ int bus_cgroup_set_property(
if (!f)
return -ENOMEM;
- if (read) {
- fputs("IOReadBandwidthMax=\n", f);
- LIST_FOREACH(device_limits, a, c->io_device_limits)
- if (a->rbps_max != CGROUP_LIMIT_MAX)
- fprintf(f, "IOReadBandwidthMax=%s %" PRIu64 "\n", a->path, a->rbps_max);
- } else {
- fputs("IOWriteBandwidthMax=\n", f);
- LIST_FOREACH(device_limits, a, c->io_device_limits)
- if (a->wbps_max != CGROUP_LIMIT_MAX)
- fprintf(f, "IOWriteBandwidthMax=%s %" PRIu64 "\n", a->path, a->wbps_max);
- }
+ 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)
@@ -667,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;
}
@@ -678,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);
@@ -688,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++;
@@ -701,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);
@@ -721,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 646bd779a2..3be88ddf90 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -836,11 +836,9 @@ int bus_exec_context_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
-
- if (isempty(uu))
- c->user = mfree(c->user);
- else if (free_and_strdup(&c->user, uu) < 0)
- return -ENOMEM;
+ r = free_and_strdup(&c->user, uu);
+ if (r < 0)
+ return r;
unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
}
@@ -855,11 +853,9 @@ int bus_exec_context_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
-
- if (isempty(gg))
- c->group = mfree(c->group);
- else if (free_and_strdup(&c->group, gg) < 0)
- return -ENOMEM;
+ r = free_and_strdup(&c->group, gg);
+ if (r < 0)
+ return r;
unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
}
@@ -873,11 +869,9 @@ int bus_exec_context_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
-
- if (isempty(id))
- c->syslog_identifier = mfree(c->syslog_identifier);
- else if (free_and_strdup(&c->syslog_identifier, id) < 0)
- return -ENOMEM;
+ r = free_and_strdup(&c->syslog_identifier, id);
+ if (r < 0)
+ return r;
unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
}
@@ -1094,10 +1088,9 @@ int bus_exec_context_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
- if (isempty(id))
- c->utmp_id = mfree(c->utmp_id);
- else if (free_and_strdup(&c->utmp_id, id) < 0)
- return -ENOMEM;
+ r = free_and_strdup(&c->utmp_id, id);
+ if (r < 0)
+ return r;
unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id));
}
@@ -1132,10 +1125,9 @@ int bus_exec_context_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
- if (isempty(n))
- c->pam_name = mfree(c->pam_name);
- else if (free_and_strdup(&c->pam_name, n) < 0)
- return -ENOMEM;
+ r = free_and_strdup(&c->pam_name, n);
+ if (r < 0)
+ return r;
unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n));
}
@@ -1454,6 +1446,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/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index ad45611d9d..8193418980 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -126,6 +126,8 @@ $1.StartupIOWeight, config_parse_io_weight, 0,
$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 cea615132a..86b4fb071b 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3023,9 +3023,9 @@ int config_parse_io_limit(
_cleanup_free_ char *path = NULL;
CGroupIODeviceLimit *l = NULL, *t;
CGroupContext *c = data;
+ CGroupIOLimitType type;
const char *limit;
uint64_t num;
- bool read;
size_t n;
int r;
@@ -3033,14 +3033,12 @@ int config_parse_io_limit(
assert(lvalue);
assert(rvalue);
- read = streq("IOReadBandwidthMax", lvalue);
+ type = cgroup_io_limit_type_from_string(lvalue);
+ assert(type >= 0);
if (isempty(rvalue)) {
LIST_FOREACH(device_limits, l, c->io_device_limits)
- if (read)
- l->rbps_max = CGROUP_LIMIT_MAX;
- else
- l->wbps_max = CGROUP_LIMIT_MAX;
+ l->limits[type] = cgroup_io_limit_defaults[type];
return 0;
}
@@ -3080,22 +3078,21 @@ int config_parse_io_limit(
}
if (!l) {
+ CGroupIOLimitType ttype;
+
l = new0(CGroupIODeviceLimit, 1);
if (!l)
return log_oom();
l->path = path;
path = NULL;
- l->rbps_max = CGROUP_LIMIT_MAX;
- l->wbps_max = CGROUP_LIMIT_MAX;
+ 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);
}
- if (read)
- l->rbps_max = num;
- else
- l->wbps_max = num;
+ l->limits[type] = num;
return 0;
}
@@ -3211,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;
@@ -3226,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;
}
@@ -3259,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;
}
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..123169832c 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1636,6 +1636,9 @@ static int client_receive_message_udp(
if (buflen < 0)
return buflen;
+ if (buflen == 0)
+ buflen = 1;
+
message = malloc0(buflen);
if (!message)
return -ENOMEM;
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/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/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 8f0df84793..f6559cd854 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -235,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")) {
@@ -284,8 +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, "IOReadBandwidthMax", "IOWriteBandwidthMax",
- "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);
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 0faf37d320..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;
@@ -4447,7 +4448,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, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax") ||
+ } 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;
@@ -5462,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])
@@ -5477,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")) {
@@ -6926,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 },
{}
};
@@ -6971,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;
@@ -7496,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/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/test/parent.slice b/test/parent.slice
index 0222f8eb47..a95f90392d 100644
--- a/test/parent.slice
+++ b/test/parent.slice
@@ -2,4 +2,4 @@
Description=Parent Slice
[Slice]
-BlockIOWeight=200
+IOWeight=200