diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index fa2ebb6fe5..3a37a636b3 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2916,6 +2916,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t StartupMemoryZSwapMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly b MemoryZSwapWriteback = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t MemoryLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DevicePolicy = '...';
@@ -3553,6 +3555,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
+
+
@@ -4203,6 +4207,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
+
+
@@ -5013,6 +5019,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t StartupMemoryZSwapMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly b MemoryZSwapWriteback = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t MemoryLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DevicePolicy = '...';
@@ -5660,6 +5668,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
+
+
@@ -6292,6 +6302,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
+
+
@@ -6976,6 +6988,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t StartupMemoryZSwapMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly b MemoryZSwapWriteback = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t MemoryLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DevicePolicy = '...';
@@ -7551,6 +7565,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
+
+
@@ -8097,6 +8113,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
+
+
@@ -8904,6 +8922,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t StartupMemoryZSwapMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly b MemoryZSwapWriteback = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t MemoryLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DevicePolicy = '...';
@@ -9465,6 +9485,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
+
+
@@ -9997,6 +10019,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
+
+
@@ -10663,6 +10687,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t StartupMemoryZSwapMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly b MemoryZSwapWriteback = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t MemoryLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DevicePolicy = '...';
@@ -10850,6 +10876,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
+
+
@@ -11046,6 +11074,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
+
+
@@ -11266,6 +11296,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t StartupMemoryZSwapMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly b MemoryZSwapWriteback = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t MemoryLimit = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DevicePolicy = '...';
@@ -11473,6 +11505,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
+
+
@@ -11699,6 +11733,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
+
+
@@ -11990,7 +12026,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
MemoryZSwapCurrent were added in version 255.
EffectiveMemoryHigh,
EffectiveMemoryMax,
- EffectiveTasksMax were added in version 256.
+ EffectiveTasksMax, and
+ MemoryZSwapWriteback were added in version 256.
Socket Unit Objects
@@ -12024,7 +12061,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
MemoryZSwapCurrent were added in version 255.
EffectiveMemoryHigh,
EffectiveMemoryMax,
- EffectiveTasksMax were added in version 256.
+ EffectiveTasksMax, and
+ MemoryZSwapWriteback were added in version 256.
Mount Unit Objects
@@ -12056,7 +12094,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
MemoryZSwapCurrent were added in version 255.
EffectiveMemoryHigh,
EffectiveMemoryMax,
- EffectiveTasksMax were added in version 256.
+ EffectiveTasksMax, and
+ MemoryZSwapWriteback were added in version 256.
Swap Unit Objects
@@ -12088,7 +12127,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
MemoryZSwapCurrent were added in version 255.
EffectiveMemoryHigh,
EffectiveMemoryMax,
- EffectiveTasksMax were added in version 256.
+ EffectiveTasksMax, and
+ MemoryZSwapWriteback were added in version 256.
Slice Unit Objects
@@ -12111,7 +12151,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
MemoryZSwapCurrent were added in version 255.
EffectiveMemoryHigh,
EffectiveMemoryMax,
- EffectiveTasksMax were added in version 256.
+ EffectiveTasksMax, and
+ MemoryZSwapWriteback were added in version 256.
Scope Unit Objects
@@ -12135,7 +12176,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
MemoryZSwapCurrent were added in version 255.
EffectiveMemoryHigh,
EffectiveMemoryMax,
- EffectiveTasksMax were added in version 256.
+ EffectiveTasksMax, and
+ MemoryZSwapWriteback were added in version 256.
Job Objects
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 972e1d2316..d5b77dc833 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -504,6 +504,23 @@ CPUWeight=20 DisableControllers=cpu / \
+
+ MemoryZSwapWriteback=
+
+
+ This setting controls the controller in the unified hierarchy.
+
+ Takes a boolean argument. When true, pages stored in the Zswap cache are permitted to be
+ written to the backing storage, false otherwise. Defaults to true. This allows disabling
+ writeback of swap pages for IO-intensive applications, while retaining the ability to store
+ compressed pages in Zswap. See the kernel's
+ Zswap documentation
+ for more details.
+
+
+
+
+
AllowedMemoryNodes=
StartupAllowedMemoryNodes=
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index ccbbda47b2..fdca434df9 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -180,6 +180,8 @@ void cgroup_context_init(CGroupContext *c) {
.memory_limit = CGROUP_LIMIT_MAX,
+ .memory_zswap_writeback = true,
+
.io_weight = CGROUP_WEIGHT_INVALID,
.startup_io_weight = CGROUP_WEIGHT_INVALID,
@@ -423,6 +425,7 @@ int cgroup_context_copy(CGroupContext *dst, const CGroupContext *src) {
dst->startup_memory_max_set = src->startup_memory_max_set;
dst->startup_memory_swap_max_set = src->startup_memory_swap_max_set;
dst->startup_memory_zswap_max_set = src->startup_memory_zswap_max_set;
+ dst->memory_zswap_writeback = src->memory_zswap_writeback;
SET_FOREACH(i, src->ip_address_allow) {
r = in_addr_prefix_add(&dst->ip_address_allow, i);
@@ -877,6 +880,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
"%sStartupMemorySwapMax: %" PRIu64 "%s\n"
"%sMemoryZSwapMax: %" PRIu64 "%s\n"
"%sStartupMemoryZSwapMax: %" PRIu64 "%s\n"
+ "%sMemoryZSwapWriteback: %s\n"
"%sMemoryLimit: %" PRIu64 "\n"
"%sTasksMax: %" PRIu64 "\n"
"%sDevicePolicy: %s\n"
@@ -921,6 +925,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
prefix, c->startup_memory_swap_max, format_cgroup_memory_limit_comparison(u, "StartupMemorySwapMax", cdi, sizeof(cdi)),
prefix, c->memory_zswap_max, format_cgroup_memory_limit_comparison(u, "MemoryZSwapMax", cdj, sizeof(cdj)),
prefix, c->startup_memory_zswap_max, format_cgroup_memory_limit_comparison(u, "StartupMemoryZSwapMax", cdk, sizeof(cdk)),
+ prefix, yes_no(c->memory_zswap_writeback),
prefix, c->memory_limit,
prefix, cgroup_tasks_max_resolve(&c->tasks_max),
prefix, cgroup_device_policy_to_string(c->device_policy),
@@ -2236,6 +2241,7 @@ static void cgroup_context_apply(
cgroup_apply_unified_memory_limit(u, "memory.zswap.max", zswap_max);
(void) set_attribute_and_warn(u, "memory", "memory.oom.group", one_zero(c->memory_oom_group));
+ (void) set_attribute_and_warn(u, "memory", "memory.zswap.writeback", one_zero(c->memory_zswap_writeback));
} else {
char buf[DECIMAL_STR_MAX(uint64_t) + 1];
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index ad34f77958..72fe275e8c 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -197,6 +197,8 @@ struct CGroupContext {
bool startup_memory_swap_max_set:1;
bool startup_memory_zswap_max_set:1;
+ bool memory_zswap_writeback;
+
Set *ip_address_allow;
Set *ip_address_deny;
/* These two flags indicate that redundant entries have been removed from
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 9afc0827e6..6cb335608b 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -487,6 +487,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("StartupMemorySwapMax", "t", NULL, offsetof(CGroupContext, startup_memory_swap_max), 0),
SD_BUS_PROPERTY("MemoryZSwapMax", "t", NULL, offsetof(CGroupContext, memory_zswap_max), 0),
SD_BUS_PROPERTY("StartupMemoryZSwapMax", "t", NULL, offsetof(CGroupContext, startup_memory_zswap_max), 0),
+ SD_BUS_PROPERTY("MemoryZSwapWriteback", "b", bus_property_get_bool, offsetof(CGroupContext, memory_zswap_writeback), 0),
SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
@@ -1279,6 +1280,9 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryLimitScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error);
+ if (streq(name, "MemoryZSwapWriteback"))
+ return bus_cgroup_set_boolean(u, name, &c->memory_zswap_writeback, CGROUP_MASK_MEMORY, message, flags, error);
+
if (streq(name, "TasksAccounting"))
return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error);
diff --git a/src/core/execute-serialize.c b/src/core/execute-serialize.c
index 5782c2f175..1ae77f39fb 100644
--- a/src/core/execute-serialize.c
+++ b/src/core/execute-serialize.c
@@ -230,6 +230,10 @@ static int exec_cgroup_context_serialize(const CGroupContext *c, FILE *f) {
return r;
}
+ r = serialize_bool(f, "exec-cgroup-context-memory-zswap-writeback", c->memory_zswap_writeback);
+ if (r < 0)
+ return r;
+
if (c->memory_limit != CGROUP_LIMIT_MAX) {
r = serialize_item_format(f, "exec-cgroup-context-memory-limit", "%" PRIu64, c->memory_limit);
if (r < 0)
@@ -677,6 +681,11 @@ static int exec_cgroup_context_deserialize(CGroupContext *c, FILE *f) {
r = safe_atou64(val, &c->startup_memory_zswap_max);
if (r < 0)
return r;
+ } else if ((val = startswith(l, "exec-cgroup-context-memory-zswap-writeback="))) {
+ r = parse_boolean(val);
+ if (r < 0)
+ return r;
+ c->memory_zswap_writeback = r;
} else if ((val = startswith(l, "exec-cgroup-context-memory-limit="))) {
r = safe_atou64(val, &c->memory_limit);
if (r < 0)
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 92d5fc4cc3..c5ea99726a 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -220,6 +220,7 @@
{{type}}.StartupMemorySwapMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
{{type}}.MemoryZSwapMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
{{type}}.StartupMemoryZSwapMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
+{{type}}.MemoryZSwapWriteback, config_parse_bool, 0, offsetof({{type}}, cgroup_context.memory_zswap_writeback)
{{type}}.MemoryLimit, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
{{type}}.DeviceAllow, config_parse_device_allow, 0, offsetof({{type}}, cgroup_context)
{{type}}.DevicePolicy, config_parse_device_policy, 0, offsetof({{type}}, cgroup_context.device_policy)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 0fedafd881..7d847b9425 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -562,6 +562,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
if (STR_IN_SET(field, "CPUAccounting",
"MemoryAccounting",
+ "MemoryZSwapWriteback",
"IOAccounting",
"BlockIOAccounting",
"TasksAccounting",