cgroup: Fix MemoryAvailable= by considering physical memory

Currently, querying a unit's available memory would result in infinity
if there are no limits set on the unit or ancestors.
That undermines semantics implied by the name, so look at the physical
memory if the search propagates up to the -.slice.
This makes sense even in systemd user instances, limits of -.slice are
still looked at too.

Also change printed representation of infinite MemoryAvailable which
means we could not figure out a good estimate.
This commit is contained in:
Michal Koutný
2023-09-07 18:50:08 +02:00
parent 93f1da4556
commit 3565c709f5
2 changed files with 8 additions and 5 deletions

View File

@@ -3791,7 +3791,7 @@ int unit_get_memory_available(Unit *u, uint64_t *ret) {
available = LESS_BY(MIN(unit_context->memory_max, unit_context->memory_high), unit_current);
for (Unit *slice = UNIT_GET_SLICE(u); slice; slice = UNIT_GET_SLICE(slice)) {
uint64_t slice_current, slice_available = UINT64_MAX;
uint64_t slice_current, slice_available, slice_limit = UINT64_MAX;
CGroupContext *slice_context;
/* No point in continuing if we can't go any lower */
@@ -3805,14 +3805,17 @@ int unit_get_memory_available(Unit *u, uint64_t *ret) {
if (!slice_context)
continue;
if (slice_context->memory_max == UINT64_MAX && slice_context->memory_high == UINT64_MAX)
if (unit_has_name(slice, SPECIAL_ROOT_SLICE))
slice_limit = physical_memory();
else if (slice_context->memory_max == UINT64_MAX && slice_context->memory_high == UINT64_MAX)
continue;
slice_limit = MIN3(slice_limit, slice_context->memory_max, slice_context->memory_high);
r = cg_get_attribute_as_uint64("memory", slice->cgroup_path, memory_file, &slice_current);
if (r < 0)
continue;
slice_available = LESS_BY(MIN(slice_context->memory_max, slice_context->memory_high), slice_current);
slice_available = LESS_BY(slice_limit, slice_current);
available = MIN(slice_available, available);
}

View File

@@ -157,12 +157,12 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
(STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
(STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
(STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == UINT64_MAX) ||
(STR_IN_SET(name, "MemoryCurrent", "MemoryAvailable", "TasksCurrent") && u == UINT64_MAX) ||
(endswith(name, "NSec") && u == UINT64_MAX))
bus_print_property_value(name, expected_value, flags, "[not set]");
else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit", "MemoryAvailable") && u == CGROUP_LIMIT_MAX) ||
else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
(STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == UINT64_MAX) ||
(startswith(name, "Limit") && u == UINT64_MAX) ||
(startswith(name, "DefaultLimit") && u == UINT64_MAX))