From: Michal Koutný Date: Thu, 7 Sep 2023 17:27:52 +0000 (+0200) Subject: cgroup: Refactor MemoryAvailable= evaluation X-Git-Tag: v255-rc1~538^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=727cea7652c978c5ef2cffa682d163be3a9f7768;p=thirdparty%2Fsystemd.git cgroup: Refactor MemoryAvailable= evaluation 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. --- diff --git a/src/core/cgroup.c b/src/core/cgroup.c index a5c8687252c..9fd62b2b5b9 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -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;