From 484226357789991de0b3363beb69258be06b4c92 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 Jun 2018 17:33:14 -0700 Subject: [PATCH] core: add MemoryMin The kernel added support for a new cgroup memory controller knob memory.min in bf8d5d52ffe8 ("memcg: introduce memory.min") which was merged during v4.18 merge window. Add MemoryMin to support memory.min. --- doc/TRANSIENT-SETTINGS.md | 1 + man/systemd.resource-control.xml | 21 +++++++++++++++++++++ src/core/cgroup.c | 5 ++++- src/core/cgroup.h | 1 + src/core/dbus-cgroup.c | 7 +++++++ src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/load-fragment.c | 4 +++- src/shared/bus-unit-util.c | 2 +- src/systemctl/systemctl.c | 11 +++++++++-- 9 files changed, 48 insertions(+), 5 deletions(-) diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md index ca9e8387b74..0df36967ac6 100644 --- a/doc/TRANSIENT-SETTINGS.md +++ b/doc/TRANSIENT-SETTINGS.md @@ -216,6 +216,7 @@ All cgroup/resource control settings are available for transient units ✓ StartupCPUShares= ✓ CPUQuota= ✓ MemoryAccounting= +✓ MemoryMin= ✓ MemoryLow= ✓ MemoryHigh= ✓ MemoryMax= diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index af839a1ee01..8ebd162be79 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -216,6 +216,27 @@ + + MemoryMin=bytes + + + Specify the memory usage protection of the executed processes in this unit. If the memory usages of + this unit and all its ancestors are below their minimum boundaries, this unit's memory won't be reclaimed. + + 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. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the + system. This controls the memory.min control group attribute. For details about this + control group attribute, see cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used and disables + MemoryLimit=. + + + MemoryLow=bytes diff --git a/src/core/cgroup.c b/src/core/cgroup.c index d4b9bdb8847..eea30b21ff5 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -193,6 +193,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sStartupIOWeight=%" PRIu64 "\n" "%sBlockIOWeight=%" PRIu64 "\n" "%sStartupBlockIOWeight=%" PRIu64 "\n" + "%sMemoryMin=%" PRIu64 "\n" "%sMemoryLow=%" PRIu64 "\n" "%sMemoryHigh=%" PRIu64 "\n" "%sMemoryMax=%" PRIu64 "\n" @@ -216,6 +217,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, c->startup_io_weight, prefix, c->blockio_weight, prefix, c->startup_blockio_weight, + prefix, c->memory_min, prefix, c->memory_low, prefix, c->memory_high, prefix, c->memory_max, @@ -668,7 +670,7 @@ static void cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint6 } static bool cgroup_context_has_unified_memory_config(CGroupContext *c) { - return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX || c->memory_swap_max != CGROUP_LIMIT_MAX; + return c->memory_min > 0 || c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX || c->memory_swap_max != CGROUP_LIMIT_MAX; } static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) { @@ -920,6 +922,7 @@ static void cgroup_context_apply( log_cgroup_compat(u, "Applying MemoryLimit %" PRIu64 " as MemoryMax", max); } + cgroup_apply_unified_memory_limit(u, "memory.min", c->memory_min); cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low); cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high); cgroup_apply_unified_memory_limit(u, "memory.max", max); diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 2d2ff6fc3c7..bda139c30bc 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -82,6 +82,7 @@ struct CGroupContext { LIST_HEAD(CGroupIODeviceWeight, io_device_weights); LIST_HEAD(CGroupIODeviceLimit, io_device_limits); + uint64_t memory_min; uint64_t memory_low; uint64_t memory_high; uint64_t memory_max; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 540bc77aed9..137bd47d87c 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -298,6 +298,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0), + SD_BUS_PROPERTY("MemoryMin", "t", NULL, offsetof(CGroupContext, memory_min), 0), SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0), SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0), SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0), @@ -606,6 +607,9 @@ int bus_cgroup_set_property( if (streq(name, "MemoryAccounting")) return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error); + if (streq(name, "MemoryMin")) + return bus_cgroup_set_memory(u, name, &c->memory_min, message, flags, error); + if (streq(name, "MemoryLow")) return bus_cgroup_set_memory(u, name, &c->memory_low, message, flags, error); @@ -621,6 +625,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, "MemoryMinScale")) + return bus_cgroup_set_memory_scale(u, name, &c->memory_min, message, flags, error); + if (streq(name, "MemoryLowScale")) return bus_cgroup_set_memory_scale(u, name, &c->memory_low, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 15fb47838c0..290e8001d8c 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -162,6 +162,7 @@ $1.CPUShares, config_parse_cpu_shares, 0, $1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares) $1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context) $1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting) +$1.MemoryMin, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 94c7d33117b..e18499384a2 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3047,7 +3047,9 @@ int config_parse_memory_limit( } } - if (streq(lvalue, "MemoryLow")) + if (streq(lvalue, "MemoryMin")) + c->memory_min = bytes; + else if (streq(lvalue, "MemoryLow")) c->memory_low = bytes; else if (streq(lvalue, "MemoryHigh")) c->memory_high = bytes; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 3238b442c05..0c713678e2d 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -413,7 +413,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return 1; } - if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) { + if (STR_IN_SET(field, "MemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) { if (isempty(eq) || streq(eq, "infinity")) { r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9c6156237a2..8f337b78a23 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3911,6 +3911,7 @@ typedef struct UnitStatusInfo { /* CGroup */ uint64_t memory_current; + uint64_t memory_min; uint64_t memory_low; uint64_t memory_high; uint64_t memory_max; @@ -4290,12 +4291,17 @@ static void print_status_info( printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current)); - if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX || - i->memory_max != CGROUP_LIMIT_MAX || i->memory_swap_max != CGROUP_LIMIT_MAX || + if (i->memory_min > 0 || i->memory_low > 0 || + i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX || + i->memory_swap_max != CGROUP_LIMIT_MAX || i->memory_limit != CGROUP_LIMIT_MAX) { const char *prefix = ""; printf(" ("); + if (i->memory_min > 0) { + printf("%smin: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_min)); + prefix = " "; + } if (i->memory_low > 0) { printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low)); prefix = " "; @@ -4971,6 +4977,7 @@ static int show_one( { "Where", "s", NULL, offsetof(UnitStatusInfo, where) }, { "What", "s", NULL, offsetof(UnitStatusInfo, what) }, { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) }, + { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) }, { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) }, { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) }, { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) }, -- 2.39.5