[systemd-devel] [PATCH 1/4] cgroups: support for MemoryAndSwapLimit= setting

Mika Eloranta mel at ohmu.fi
Wed Oct 9 16:18:34 PDT 2013


Add a MemoryAndSwapLimit setting that behaves the same way
as MemoryLimit, except that it controls the
memory.memsw.limit_in_bytes cgroup attribute.
---
 man/systemd.resource-control.xml      |  9 +++++++--
 src/core/cgroup.c                     | 21 ++++++++++++++++++---
 src/core/cgroup.h                     |  1 +
 src/core/dbus-cgroup.c                |  1 +
 src/core/load-fragment-gperf.gperf.m4 |  1 +
 src/core/load-fragment.c              | 34 ++++++++++++++++++++++++++++++++++
 src/core/load-fragment.h              |  1 +
 src/systemctl/systemctl.c             |  2 +-
 8 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 8688905..606e078 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -138,7 +138,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
       </varlistentry>
 
       <varlistentry>
-        <term><varname>MemoryLimit=<replaceable>bytes</replaceable></varname></term>
+        <term><varname>MemoryLimit=, MemoryAndSwapLimit=<replaceable>bytes</replaceable></varname></term>
 
         <listitem>
           <para>Specify the limit on maximum memory usage of the
@@ -149,7 +149,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
           Megabytes, Gigabytes, or Terabytes (with the base 1024),
           respectively. This controls the
           <literal>memory.limit_in_bytes</literal> control group
-          attribute. For details about this control group attribute,
+          attribute.
+          <literal>MemoryAndSwapLimit</literal> controls the
+          <literal>memory.limit_in_bytes</literal> control group
+          attribute, which sets the limit for the sum of the used
+          memory and used swap space.
+          For details about these control group attributes,
           see <ulink
           url="https://www.kernel.org/doc/Documentation/cgroups/memory.txt">memory.txt</ulink>.</para>
 
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 8bf4d89..3b465cc 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -34,6 +34,7 @@ void cgroup_context_init(CGroupContext *c) {
 
         c->cpu_shares = 1024;
         c->memory_limit = (uint64_t) -1;
+        c->memory_and_swap_limit = (uint64_t) -1;
         c->blockio_weight = 1000;
 }
 
@@ -94,6 +95,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 "%sCPUShares=%lu\n"
                 "%sBlockIOWeight=%lu\n"
                 "%sMemoryLimit=%" PRIu64 "\n"
+                "%sMemoryAndSwapLimit=%" PRIu64 "\n"
                 "%sDevicePolicy=%s\n",
                 prefix, yes_no(c->cpu_accounting),
                 prefix, yes_no(c->blockio_accounting),
@@ -101,6 +103,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 prefix, c->cpu_shares,
                 prefix, c->blockio_weight,
                 prefix, c->memory_limit,
+                prefix, c->memory_and_swap_limit,
                 prefix, cgroup_device_policy_to_string(c->device_policy));
 
         LIST_FOREACH(device_allow, a, c->device_allow)
@@ -254,9 +257,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
         }
 
         if (mask & CGROUP_MEMORY) {
+                char buf[DECIMAL_STR_MAX(uint64_t) + 1];
                 if (c->memory_limit != (uint64_t) -1) {
-                        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
-
                         sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
                         r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
                 } else
@@ -264,6 +266,18 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
 
                 if (r < 0)
                         log_error("Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r));
+
+                if (c->memory_and_swap_limit != (uint64_t) -1) {
+                        sprintf(buf, "%" PRIu64 "\n", c->memory_and_swap_limit);
+                        r = cg_set_attribute("memory", path, "memory.memsw.limit_in_bytes", buf);
+                } else {
+                        r = cg_set_attribute("memory", path, "memory.memsw.limit_in_bytes", "-1");
+                        if (r == -EACCES) /* CONFIG_MEMCG_SWAP not built into kernel, ignore */
+                                r = 0;
+                }
+
+                if (r < 0)
+                        log_error("Failed to set memory.memsw.limit_in_bytes on %s: %s", path, strerror(-r));
         }
 
         if (mask & CGROUP_DEVICE) {
@@ -326,7 +340,8 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
                 mask |= CGROUP_BLKIO;
 
         if (c->memory_accounting ||
-            c->memory_limit != (uint64_t) -1)
+            c->memory_limit != (uint64_t) -1 ||
+            c->memory_and_swap_limit != (uint64_t) -1)
                 mask |= CGROUP_MEMORY;
 
         if (c->device_allow || c->device_policy != CGROUP_AUTO)
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 0a079e9..c84eed2 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -77,6 +77,7 @@ struct CGroupContext {
         LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths);
 
         uint64_t memory_limit;
+        uint64_t memory_and_swap_limit;
 
         CGroupDevicePolicy device_policy;
         LIST_HEAD(CGroupDeviceAllow, device_allow);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 9ebcad9..d86a03a 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -133,6 +133,7 @@ const BusProperty bus_cgroup_context_properties[] = {
         { "BlockIOWriteBandwidth",   bus_cgroup_append_device_bandwidths, "a(st)", 0                                           },
         { "MemoryAccounting",        bus_property_append_bool,            "b",     offsetof(CGroupContext, memory_accounting)  },
         { "MemoryLimit",             bus_property_append_uint64,          "t",     offsetof(CGroupContext, memory_limit)       },
+        { "MemoryAndSwapLimit",      bus_property_append_uint64,          "t",     offsetof(CGroupContext, memory_and_swap_limit) },
         { "DevicePolicy",            bus_cgroup_append_device_policy,     "s",     offsetof(CGroupContext, device_policy)      },
         { "DeviceAllow",             bus_cgroup_append_device_allow,      "a(ss)", 0                                           },
         {}
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 31fb7bc..f86352e 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -89,6 +89,7 @@ $1.CPUAccounting,                config_parse_bool,                  0,
 $1.CPUShares,                    config_parse_cpu_shares,            0,                             offsetof($1, cgroup_context)
 $1.MemoryAccounting,             config_parse_bool,                  0,                             offsetof($1, cgroup_context.memory_accounting)
 $1.MemoryLimit,                  config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
+$1.MemoryAndSwapLimit,           config_parse_memory_and_swap_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.BlockIOAccounting,            config_parse_bool,                  0,                             offsetof($1, cgroup_context.blockio_accounting)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 44920d6..6dabf4c 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2072,6 +2072,39 @@ int config_parse_memory_limit(
         return 0;
 }
 
+int config_parse_memory_and_swap_limit(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        CGroupContext *c = data;
+        off_t bytes;
+        int r;
+
+        if (isempty(rvalue)) {
+                c->memory_and_swap_limit = (uint64_t) -1;
+                return 0;
+        }
+
+        assert_cc(sizeof(uint64_t) == sizeof(off_t));
+
+        r = parse_bytes(rvalue, &bytes);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Memory and swap limit '%s' invalid. Ignoring.", rvalue);
+                return 0;
+        }
+
+        c->memory_and_swap_limit = (uint64_t) bytes;
+        return 0;
+}
+
 int config_parse_device_allow(
                 const char *unit,
                 const char *filename,
@@ -2712,6 +2745,7 @@ void unit_dump_config_items(FILE *f) {
                 { config_parse_syscall_filter,        "SYSCALL" },
                 { config_parse_cpu_shares,            "SHARES" },
                 { config_parse_memory_limit,          "LIMIT" },
+                { config_parse_memory_and_swap_limit, "LIMIT" },
                 { config_parse_device_allow,          "DEVICE" },
                 { config_parse_device_policy,         "POLICY" },
                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 90e5e3a..846825c 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -78,6 +78,7 @@ int config_parse_environ(const char *unit, const char *filename, unsigned line,
 int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_memory_and_swap_limit(const char *unit, const char *filename, unsigned line, const char *section, 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, 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, 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, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d75281f..9e6bb06 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3658,7 +3658,7 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) {
                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
                         return log_oom();
 
-        } else if (streq(field, "MemoryLimit")) {
+        } else if (streq(field, "MemoryLimit") || streq(field, "MemoryAndSwapLimit")) {
                 off_t bytes;
                 uint64_t u;
 
-- 
1.8.3.2



More information about the systemd-devel mailing list