]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cgroup: Fix MemoryAvailable= by considering physical memory
authorMichal Koutný <mkoutny@suse.com>
Thu, 7 Sep 2023 16:50:08 +0000 (18:50 +0200)
committerMichal Koutný <mkoutny@suse.com>
Fri, 8 Sep 2023 17:05:52 +0000 (19:05 +0200)
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.

src/core/cgroup.c
src/shared/bus-print-properties.c

index 91ef33b12c922e4d426d4f30b3e0841563740cc2..a5c8687252c2e99667bae94ea4273afb27d8a6ae 100644 (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);
         }
 
index db41ad249579da84796f3ab616620fc2cf054128..8999a1a4fad5a512ccfee60078170326418935ca 100644 (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))