]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cgroup: Refactor MemoryAvailable= evaluation
authorMichal Koutný <mkoutny@suse.com>
Thu, 7 Sep 2023 17:27:52 +0000 (19:27 +0200)
committerMichal Koutný <mkoutny@suse.com>
Fri, 8 Sep 2023 17:07:12 +0000 (19:07 +0200)
unit_get_memory_available() duplicates similar logic contained in
unit_get_memory_current(). Instead, it can call it for each unit it
needs data for.
Additionally, simplify the flow by treating all units from leaf to root
uniformly in one loop.

Functional change when a queried unit does not have MemoryAccounting=yes
(or cgroup_path), we will try getting an estimate from ancestors.

src/core/cgroup.c

index a5c8687252c2e99667bae94ea4273afb27d8a6ae..9fd62b2b5b90fc23912767b6b8c41dcb9965905f 100644 (file)
@@ -3751,9 +3751,7 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
 }
 
 int unit_get_memory_available(Unit *u, uint64_t *ret) {
-        uint64_t unit_current, available = UINT64_MAX;
-        CGroupContext *unit_context;
-        const char *memory_file;
+        uint64_t available = UINT64_MAX;
         int r;
 
         assert(u);
@@ -3763,61 +3761,34 @@ int unit_get_memory_available(Unit *u, uint64_t *ret) {
          * claim before hitting the configured cgroup limits (if any). Consider both MemoryHigh
          * and MemoryMax, and also any slice the unit might be nested below. */
 
-        if (!UNIT_CGROUP_BOOL(u, memory_accounting))
-                return -ENODATA;
-
-        if (!u->cgroup_path)
-                return -ENODATA;
-
-        /* The root cgroup doesn't expose this information */
-        if (unit_has_host_root_cgroup(u))
-                return -ENODATA;
-
-        if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
-                return -ENODATA;
-
-        r = cg_all_unified();
-        if (r < 0)
-                return r;
-        memory_file = r > 0 ? "memory.current" : "memory.usage_in_bytes";
-
-        r = cg_get_attribute_as_uint64("memory", u->cgroup_path, memory_file, &unit_current);
-        if (r < 0)
-                return r;
-
-        assert_se(unit_context = unit_get_cgroup_context(u));
-
-        if (unit_context->memory_max != UINT64_MAX || unit_context->memory_high != UINT64_MAX)
-                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, slice_limit = UINT64_MAX;
-                CGroupContext *slice_context;
+        do {
+                uint64_t unit_current, unit_available, unit_limit = UINT64_MAX;
+                CGroupContext *unit_context;
 
                 /* No point in continuing if we can't go any lower */
                 if (available == 0)
                         break;
 
-                if (!slice->cgroup_path)
-                        continue;
+                unit_context = unit_get_cgroup_context(u);
+                if (!unit_context)
+                        return -ENODATA;
 
-                slice_context = unit_get_cgroup_context(slice);
-                if (!slice_context)
+                if (!u->cgroup_path)
                         continue;
 
-                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)
+                if (unit_has_name(u, SPECIAL_ROOT_SLICE))
+                        unit_limit = physical_memory();
+                else if (unit_context->memory_max == UINT64_MAX && unit_context->memory_high == UINT64_MAX)
                         continue;
-                slice_limit = MIN3(slice_limit, slice_context->memory_max, slice_context->memory_high);
+                unit_limit = MIN3(unit_limit, unit_context->memory_max, unit_context->memory_high);
 
-                r = cg_get_attribute_as_uint64("memory", slice->cgroup_path, memory_file, &slice_current);
+                r = unit_get_memory_current(u, &unit_current);
                 if (r < 0)
                         continue;
 
-                slice_available = LESS_BY(slice_limit, slice_current);
-                available = MIN(slice_available, available);
-        }
+                unit_available = LESS_BY(unit_limit, unit_current);
+                available = MIN(unit_available, available);
+        } while ((u = UNIT_GET_SLICE(u)));
 
         *ret = available;