diff options
-rw-r--r-- | src/basic/cgroup-util.h | 1 | ||||
-rw-r--r-- | src/core/cgroup.c | 63 | ||||
-rw-r--r-- | src/core/cgroup.h | 2 | ||||
-rw-r--r-- | src/core/dbus-cgroup.c | 1 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 1 | ||||
-rw-r--r-- | src/core/load-fragment.c | 11 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 3 |
7 files changed, 74 insertions, 8 deletions
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index a39ab451b9..73b4611536 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -78,6 +78,7 @@ bool cpu_accounting_is_cheap(void); #define CGROUP_WEIGHT_MAX UINT64_C(10000) #define CGROUP_WEIGHT_DEFAULT UINT64_C(100) +#define CGROUP_LIMIT_INVALID ((uint64_t) -2) #define CGROUP_LIMIT_MIN UINT64_C(0) #define CGROUP_LIMIT_MAX ((uint64_t) -1) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index ad67ba0438..4524edc140 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -104,6 +104,10 @@ void cgroup_context_init(CGroupContext *c) { .cpu_shares = CGROUP_CPU_SHARES_INVALID, .startup_cpu_shares = CGROUP_CPU_SHARES_INVALID, + .default_memory_low = CGROUP_LIMIT_INVALID, + + .memory_low = CGROUP_LIMIT_INVALID, + .memory_high = CGROUP_LIMIT_MAX, .memory_max = CGROUP_LIMIT_MAX, .memory_swap_max = CGROUP_LIMIT_MAX, @@ -232,6 +236,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sStartupIOWeight=%" PRIu64 "\n" "%sBlockIOWeight=%" PRIu64 "\n" "%sStartupBlockIOWeight=%" PRIu64 "\n" + "%sDefaultMemoryLow=%" PRIu64 "\n" "%sMemoryMin=%" PRIu64 "\n" "%sMemoryLow=%" PRIu64 "\n" "%sMemoryHigh=%" PRIu64 "\n" @@ -257,6 +262,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->default_memory_low, prefix, c->memory_min, prefix, c->memory_low, prefix, c->memory_high, @@ -380,6 +386,36 @@ int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode) return 0; } +static uint64_t unit_get_ancestor_memory_low(Unit *u) { + CGroupContext *c; + + /* 1. Is MemoryLow set in this unit? If so, use that. + * 2. Is DefaultMemoryLow set in this unit? If so, use that. + * 3. Is DefaultMemoryLow set in any ancestor? If so, use that. + * 4. Otherwise, return CGROUP_LIMIT_MIN. */ + + assert(u); + + c = unit_get_cgroup_context(u); + + if (c->memory_low != CGROUP_LIMIT_INVALID) + return c->memory_low; + + if (c->default_memory_low != CGROUP_LIMIT_INVALID) + return c->default_memory_low; + + while (UNIT_ISSET(u->slice)) { + u = UNIT_DEREF(u->slice); + c = unit_get_cgroup_context(u); + + if (c->default_memory_low != CGROUP_LIMIT_INVALID) + return c->default_memory_low; + } + + /* We've reached the root, but nobody had DefaultMemoryLow set, so set it to the kernel default. */ + return CGROUP_LIMIT_MIN; +} + static void cgroup_xattr_apply(Unit *u) { char ids[SD_ID128_STRING_MAX]; int r; @@ -875,8 +911,14 @@ static void cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint6 (void) set_attribute_and_warn(u, "blkio", "blkio.throttle.write_bps_device", buf); } -static bool cgroup_context_has_unified_memory_config(CGroupContext *c) { - 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 bool unit_has_unified_memory_config(Unit *u) { + CGroupContext *c; + + assert(u); + + c = unit_get_cgroup_context(u); + + return c->memory_min > 0 || unit_get_ancestor_memory_low(u) > 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) { @@ -1125,7 +1167,7 @@ static void cgroup_context_apply( if (cg_all_unified() > 0) { uint64_t max, swap_max = CGROUP_LIMIT_MAX; - if (cgroup_context_has_unified_memory_config(c)) { + if (unit_has_unified_memory_config(u)) { max = c->memory_max; swap_max = c->memory_swap_max; } else { @@ -1136,7 +1178,7 @@ static void cgroup_context_apply( } 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.low", unit_get_ancestor_memory_low(u)); cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high); cgroup_apply_unified_memory_limit(u, "memory.max", max); cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max); @@ -1145,7 +1187,7 @@ static void cgroup_context_apply( char buf[DECIMAL_STR_MAX(uint64_t) + 1]; uint64_t val; - if (cgroup_context_has_unified_memory_config(c)) { + if (unit_has_unified_memory_config(u)) { val = c->memory_max; log_cgroup_compat(u, "Applying MemoryMax=%" PRIi64 " as MemoryLimit=", val); } else @@ -1319,8 +1361,13 @@ static bool unit_get_needs_bpf_firewall(Unit *u) { return false; } -static CGroupMask cgroup_context_get_mask(CGroupContext *c) { +static CGroupMask unit_get_cgroup_mask(Unit *u) { CGroupMask mask = 0; + CGroupContext *c; + + assert(u); + + c = unit_get_cgroup_context(u); /* Figure out which controllers we need, based on the cgroup context object */ @@ -1337,7 +1384,7 @@ static CGroupMask cgroup_context_get_mask(CGroupContext *c) { if (c->memory_accounting || c->memory_limit != CGROUP_LIMIT_MAX || - cgroup_context_has_unified_memory_config(c)) + unit_has_unified_memory_config(u)) mask |= CGROUP_MASK_MEMORY; if (c->device_allow || @@ -1376,7 +1423,7 @@ CGroupMask unit_get_own_mask(Unit *u) { if (!c) return 0; - return (cgroup_context_get_mask(c) | unit_get_bpf_mask(u) | unit_get_delegate_mask(u)) & ~unit_get_ancestor_disable_mask(u); + return (unit_get_cgroup_mask(u) | unit_get_bpf_mask(u) | unit_get_delegate_mask(u)) & ~unit_get_ancestor_disable_mask(u); } CGroupMask unit_get_delegate_mask(Unit *u) { diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 51e7c96d60..eadb003cab 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -95,6 +95,8 @@ struct CGroupContext { LIST_HEAD(CGroupIODeviceLimit, io_device_limits); LIST_HEAD(CGroupIODeviceLatency, io_device_latencies); + uint64_t default_memory_low; + uint64_t memory_min; uint64_t memory_low; uint64_t memory_high; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 4615aeaf66..38cfcaee28 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -348,6 +348,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("DefaultMemoryLow", "t", NULL, offsetof(CGroupContext, default_memory_low), 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), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 7fb1e6cc8b..facba03452 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -172,6 +172,7 @@ $1.CPUQuota, config_parse_cpu_quota, 0, $1.CPUQuotaPeriodSec, config_parse_sec_def_infinity, 0, offsetof($1, cgroup_context.cpu_quota_period_usec) $1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting) $1.MemoryMin, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.DefaultMemoryLow, 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 6acfd9b8ea..d25246d9dc 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3104,6 +3104,17 @@ int config_parse_memory_limit( } } + /* Defaults come first, so that they can be overridden later. DefaultMemoryXXX= with no rvalue + * resets. */ + if (streq(lvalue, "DefaultMemoryLow")) { + if (isempty(rvalue)) { + c->default_memory_low = CGROUP_LIMIT_MIN; + } else { + c->default_memory_low = bytes; + c->memory_low = bytes; + } + } + if (streq(lvalue, "MemoryMin")) c->memory_min = bytes; else if (streq(lvalue, "MemoryLow")) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 92bbcfd276..c9edefdd82 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4129,6 +4129,8 @@ typedef struct UnitStatusInfo { uint64_t ip_ingress_bytes; uint64_t ip_egress_bytes; + uint64_t default_memory_low; + LIST_HEAD(ExecStatusInfo, exec); } UnitStatusInfo; @@ -5479,6 +5481,7 @@ static int show_one( { "Where", "s", NULL, offsetof(UnitStatusInfo, where) }, { "What", "s", NULL, offsetof(UnitStatusInfo, what) }, { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) }, + { "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) }, { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) }, { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) }, { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) }, |