From cfb8a3cf09d9a958388ca1181bb92d9f77ab100e Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Thu, 6 May 2021 09:38:54 +0800
Subject: [PATCH] core-cgroup: support memorysw

Upstream systemd dosen't support setting memory.memsw.limit_in_bytes.
This patch enables setting memory.memsw.limit_in_bytes by MemoryMemswLimit.
---
 src/core/cgroup.c                               | 17 +++++++++++++++--
 src/core/cgroup.h                               |  1 +
 src/core/dbus-cgroup.c                          |  4 ++++
 src/core/load-fragment-gperf.gperf.in           |  1 +
 src/core/load-fragment.c                        |  2 ++
 src/shared/bus-print-properties.c               |  2 +-
 src/shared/bus-unit-util.c                      |  1 +
 test/fuzz/fuzz-unit-file/directives-all.service |  1 +
 8 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 9e472ca..9de2283 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -171,6 +171,7 @@ void cgroup_context_init(CGroupContext *c) {
                 .startup_memory_zswap_max = CGROUP_LIMIT_MAX,
 
                 .memory_limit = CGROUP_LIMIT_MAX,
+                .memory_memsw_limit = CGROUP_LIMIT_MAX,
 
                 .io_weight = CGROUP_WEIGHT_INVALID,
                 .startup_io_weight = CGROUP_WEIGHT_INVALID,
@@ -577,6 +578,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 "%sMemoryZSwapMax: %" PRIu64 "%s\n"
                 "%sStartupMemoryZSwapMax: %" PRIu64 "%s\n"
                 "%sMemoryLimit: %" PRIu64 "\n"
+                "%sMemoryMemswLimit=%" PRIu64 "\n"
                 "%sCPUSetCpus=%s\n"
                 "%sCPUSetMems=%s\n"
                 "%sCPUSetCloneChildren=%s\n"
@@ -628,6 +630,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 prefix, c->memory_zswap_max, format_cgroup_memory_limit_comparison(cdj, sizeof(cdj), u, "MemoryZSwapMax"),
                 prefix, c->startup_memory_zswap_max, format_cgroup_memory_limit_comparison(cdk, sizeof(cdk), u, "StartupMemoryZSwapMax"),
                 prefix, c->memory_limit,
+                prefix, c->memory_memsw_limit,
                 prefix, c->cpuset_cpus_v1,
                 prefix, c->cpuset_mems_v1,
                 prefix, yes_no(c->cpuset_clone_children),
@@ -1908,14 +1911,17 @@ static void cgroup_context_apply(
 
                 } else {
                         char buf[DECIMAL_STR_MAX(uint64_t) + 1];
-                        uint64_t val;
+                        uint64_t val, sw_val;
 
                         if (unit_has_unified_memory_config(u)) {
                                 val = c->memory_max;
+                                sw_val = CGROUP_LIMIT_MAX;
                                 if (val != CGROUP_LIMIT_MAX)
                                         log_cgroup_compat(u, "Applying MemoryMax=%" PRIu64 " as MemoryLimit=", val);
-                        } else
+                        } else {
                                 val = c->memory_limit;
+                                sw_val = c->memory_memsw_limit;
+                        }
 
                         if (val == CGROUP_LIMIT_MAX)
                                 strncpy(buf, "-1\n", sizeof(buf));
@@ -1923,6 +1929,12 @@ static void cgroup_context_apply(
                                 xsprintf(buf, "%" PRIu64 "\n", val);
 
                         (void) set_attribute_and_warn(u, "memory", "memory.limit_in_bytes", buf);
+
+                        if (sw_val == CGROUP_LIMIT_MAX)
+                                strncpy(buf, "-1\n", sizeof(buf));
+                        else
+                                xsprintf(buf, "%" PRIu64 "\n", sw_val);
+                        (void) set_attribute_and_warn(u, "memory", "memory.memsw.limit_in_bytes", buf);
                 }
         }
 
@@ -2120,6 +2132,7 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
 
         if (c->memory_accounting ||
             c->memory_limit != CGROUP_LIMIT_MAX ||
+            c->memory_memsw_limit != CGROUP_LIMIT_MAX ||
             unit_has_unified_memory_config(u))
                 mask |= CGROUP_MASK_MEMORY;
 
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 7fb792a..b585fdb 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -219,6 +219,7 @@ struct CGroupContext {
         LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths);
 
         uint64_t memory_limit;
+        uint64_t memory_memsw_limit;
 
         CGroupDevicePolicy device_policy;
         LIST_HEAD(CGroupDeviceAllow, device_allow);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 052049c..e0a64e4 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -488,6 +488,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         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("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
+        SD_BUS_PROPERTY("MemoryMemswLimit", "t", NULL, offsetof(CGroupContext, memory_memsw_limit), 0),
         SD_BUS_PROPERTY("CPUSetAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_accounting), 0),
         SD_BUS_PROPERTY("CPUSetCpus", "s", NULL, offsetof(CGroupContext, cpuset_cpus_v1), 0),
         SD_BUS_PROPERTY("CPUSetMems", "s", NULL, offsetof(CGroupContext, cpuset_mems_v1), 0),
@@ -1243,6 +1244,9 @@ int bus_cgroup_set_property(
         if (streq(name, "MemoryLimit"))
                 return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
 
+        if (streq(name, "MemoryMemswLimit"))
+                return bus_cgroup_set_memory(u, name, &c->memory_memsw_limit, message, flags, error);
+
         if (streq(name, "MemoryMinScale")) {
                 r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
                 if (r > 0)
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 1e5b7ab..160c891 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -221,6 +221,7 @@
 {{type}}.MemoryZSwapMax,                   config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
 {{type}}.StartupMemoryZSwapMax,            config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
 {{type}}.MemoryLimit,                      config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
+{{type}}.MemoryMemswLimit,                 config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
 {{type}}.CPUSetAccounting,                 config_parse_bool,                           0,                                  offsetof({{type}}, cgroup_context.cpuset_accounting)
 {{type}}.CPUSetCpus,                       config_parse_cpuset_cpumems,                 0,                                  offsetof({{type}}, cgroup_context.cpuset_cpus_v1)
 {{type}}.CPUSetMems,                       config_parse_cpuset_cpumems,                 0,                                  offsetof({{type}}, cgroup_context.cpuset_mems_v1)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 8648fb1..aaf906f 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3891,6 +3891,8 @@ int config_parse_memory_limit(
                 c->startup_memory_swap_max_set = true;
         } else if (streq(lvalue, "MemoryZSwapMax"))
                 c->memory_zswap_max = bytes;
+        else if (streq(lvalue, "MemoryMemswLimit"))
+                c->memory_memsw_limit = bytes;
         else if (streq(lvalue, "StartupMemoryZSwapMax")) {
                 c->startup_memory_zswap_max = bytes;
                 c->startup_memory_zswap_max_set = true;
diff --git a/src/shared/bus-print-properties.c b/src/shared/bus-print-properties.c
index 6704e1e..0cded0c 100644
--- a/src/shared/bus-print-properties.c
+++ b/src/shared/bus-print-properties.c
@@ -164,7 +164,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
 
                         bus_print_property_value(name, expected_value, flags, "[not set]");
 
-                else if ((ENDSWITH_SET(name, "MemoryLow", "MemoryMin", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit") &&
+                else if ((ENDSWITH_SET(name, "MemoryLow", "MemoryMin", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit", "MemoryMemswLimit") &&
                           u == CGROUP_LIMIT_MAX) ||
                          (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == UINT64_MAX) ||
                          (startswith(name, "Limit") && u == UINT64_MAX) ||
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 6390986..3f97ada 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -632,6 +632,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                               "MemorySwapMax",
                               "MemoryZSwapMax",
                               "MemoryLimit",
+                              "MemoryMemswLimit",
                               "TasksMax")) {
 
                 if (streq(eq, "infinity")) {
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
index 123c98e..397b5da 100644
--- a/test/fuzz/fuzz-unit-file/directives-all.service
+++ b/test/fuzz/fuzz-unit-file/directives-all.service
@@ -166,6 +166,7 @@ MemoryHigh=
 MemoryLimit=
 MemoryLow=
 MemoryMax=
+MemoryMemswLimit=
 MemoryPressureThresholdSec=
 MemoryPressureWatch=
 MemorySwapMax=
-- 
2.33.0