[systemd-devel] [PATCH 4/4] cgroups: support for KernelTcpMemoryLimit= setting
Mika Eloranta
mel at ohmu.fi
Wed Oct 9 16:18:37 PDT 2013
Add a KernelTcpMemoryLimit setting that behaves the same way
as KernelMemoryLimit, except that it controls the
memory.kmem.tcp.limit_in_bytes cgroup attribute.
---
man/systemd.resource-control.xml | 17 +++++++++++++++++
src/core/cgroup.c | 16 ++++++++++++++++
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 | 3 ++-
8 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index e80c02f..b6576dc 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -171,6 +171,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</varlistentry>
<varlistentry>
+ <term><varname>KernelTcpMemoryLimit=<replaceable>bytes</replaceable></varname></term>
+
+ <listitem>
+ <para>Specify the limit on maximum kernel TCP buffer memory usage.
+ Takes a memory size in bytes. If the value is suffixed with K, M, G
+ or T, the specified memory size is parsed as Kilobytes,
+ Megabytes, Gigabytes, or Terabytes (with the base 1024),
+ respectively. This controls the
+ <literal>memory.kmem.tcp.limit_in_bytes</literal> control group
+ attribute.
+ </para>
+
+ <para>Implies <literal>MemoryAccounting=true</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>BlockIOAccounting=</varname></term>
<listitem>
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index d7aa49e..5482c78 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -36,6 +36,7 @@ void cgroup_context_init(CGroupContext *c) {
c->memory_limit = (uint64_t) -1;
c->memory_and_swap_limit = (uint64_t) -1;
c->kernel_memory_limit = (uint64_t) -1;
+ c->kernel_tcp_memory_limit = (uint64_t) -1;
c->memory_soft_limit = (uint64_t) -1;
c->blockio_weight = 1000;
}
@@ -100,6 +101,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sMemorySoftLimit=%" PRIu64 "\n"
"%sMemoryAndSwapLimit=%" PRIu64 "\n"
"%sKernelMemoryLimit=%" PRIu64 "\n"
+ "%sKernelTcpMemoryLimit=%" PRIu64 "\n"
"%sDevicePolicy=%s\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->blockio_accounting),
@@ -110,6 +112,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, c->memory_soft_limit,
prefix, c->memory_and_swap_limit,
prefix, c->kernel_memory_limit,
+ prefix, c->kernel_tcp_memory_limit,
prefix, cgroup_device_policy_to_string(c->device_policy));
LIST_FOREACH(device_allow, a, c->device_allow)
@@ -297,6 +300,18 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
if (r < 0)
log_error("Failed to set memory.kmem.limit_in_bytes on %s: %s", path, strerror(-r));
+ if (c->kernel_tcp_memory_limit != (uint64_t) -1) {
+ sprintf(buf, "%" PRIu64 "\n", c->kernel_tcp_memory_limit);
+ r = cg_set_attribute("memory", path, "memory.kmem.tcp.limit_in_bytes", buf);
+ } else {
+ r = cg_set_attribute("memory", path, "memory.kmem.tcp.limit_in_bytes", "-1");
+ if (r == -EACCES) /* CONFIG_MEMCG_KMEM not built into kernel, ignore */
+ r = 0;
+ }
+
+ if (r < 0)
+ log_error("Failed to set memory.kmem.tcp.limit_in_bytes on %s: %s", path, strerror(-r));
+
if (c->memory_soft_limit != (uint64_t) -1) {
sprintf(buf, "%" PRIu64 "\n", c->memory_soft_limit);
r = cg_set_attribute("memory", path, "memory.soft_limit_in_bytes", buf);
@@ -371,6 +386,7 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
c->memory_limit != (uint64_t) -1 ||
c->memory_and_swap_limit != (uint64_t) -1 ||
c->memory_soft_limit != (uint64_t) -1 ||
+ c->kernel_tcp_memory_limit != (uint64_t) -1 ||
c->kernel_memory_limit != (uint64_t) -1)
mask |= CGROUP_MEMORY;
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 501fb1b..2c9a538 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -79,6 +79,7 @@ struct CGroupContext {
uint64_t memory_limit;
uint64_t memory_and_swap_limit;
uint64_t kernel_memory_limit;
+ uint64_t kernel_tcp_memory_limit;
uint64_t memory_soft_limit;
CGroupDevicePolicy device_policy;
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 15f2e21..9fefd85 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -135,6 +135,7 @@ const BusProperty bus_cgroup_context_properties[] = {
{ "MemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_limit) },
{ "MemoryAndSwapLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_and_swap_limit) },
{ "KernelMemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, kernel_memory_limit) },
+ { "KernelTcpMemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, kernel_tcp_memory_limit) },
{ "MemorySoftLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_soft_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 7945922..e401e5d 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -92,6 +92,7 @@ $1.MemoryLimit, config_parse_memory_limit, 0,
$1.MemorySoftLimit, config_parse_memory_soft_limit, 0, offsetof($1, cgroup_context)
$1.MemoryAndSwapLimit, config_parse_memory_and_swap_limit, 0, offsetof($1, cgroup_context)
$1.KernelMemoryLimit, config_parse_kernel_memory_limit, 0, offsetof($1, cgroup_context)
+$1.KernelTcpMemoryLimit, config_parse_kernel_tcp_memory_limit, 0, offsetof($1, cgroup_context)
$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context)
$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy)
$1.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 3852632..03b087f 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2171,6 +2171,39 @@ int config_parse_kernel_memory_limit(
return 0;
}
+int config_parse_kernel_tcp_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) {
+
+ CGroupContext *c = data;
+ off_t bytes;
+ int r;
+
+ if (isempty(rvalue)) {
+ c->kernel_tcp_memory_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,
+ "Kernel TCP memory limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ c->kernel_tcp_memory_limit = (uint64_t) bytes;
+ return 0;
+}
+
int config_parse_device_allow(
const char *unit,
const char *filename,
@@ -2814,6 +2847,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_memory_soft_limit, "LIMIT" },
{ config_parse_memory_and_swap_limit, "LIMIT" },
{ config_parse_kernel_memory_limit, "LIMIT" },
+ { config_parse_kernel_tcp_memory_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 f90ce1a..f187e2d 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -81,6 +81,7 @@ int config_parse_memory_limit(const char *unit, const char *filename, unsigned l
int config_parse_memory_soft_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_kernel_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_kernel_tcp_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_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 1bea3bd..a834ed4 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3659,7 +3659,8 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) {
return log_oom();
} else if (streq(field, "MemoryLimit") || streq(field, "MemoryAndSwapLimit") ||
- streq(field, "MemorySoftLimit") || streq(field, "KernelMemoryLimit")) {
+ streq(field, "MemorySoftLimit") || streq(field, "KernelMemoryLimit") ||
+ streq(field, "KernelTcpMemoryLimit")) {
off_t bytes;
uint64_t u;
--
1.8.3.2
More information about the systemd-devel
mailing list