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.
This commit is contained in:
+17
-46
@@ -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)
|
||||
unit_context = unit_get_cgroup_context(u);
|
||||
if (!unit_context)
|
||||
return -ENODATA;
|
||||
|
||||
if (!u->cgroup_path)
|
||||
continue;
|
||||
|
||||
slice_context = unit_get_cgroup_context(slice);
|
||||
if (!slice_context)
|
||||
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;
|
||||
unit_limit = MIN3(unit_limit, unit_context->memory_max, unit_context->memory_high);
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user