diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-05-26 20:16:48 +0200 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-06-08 15:05:56 +0200 |
commit | 93ff34e44aa6cfae2b3723ec57862ce54c1721eb (patch) | |
tree | 2d11fcaefbe32142045e71b785649e46e270fe0f /src/core/cgroup.c | |
parent | po: Translated using Weblate (Spanish) (diff) | |
download | systemd-93ff34e44aa6cfae2b3723ec57862ce54c1721eb.tar.xz systemd-93ff34e44aa6cfae2b3723ec57862ce54c1721eb.zip |
core: add MemoryAvailable unit property
Try to infer the unused memory that a unit can claim before the
memory.max limit is reached, including any limit set on any parent
slice above the unit itself.
Diffstat (limited to 'src/core/cgroup.c')
-rw-r--r-- | src/core/cgroup.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 6a46e14556..7fde1efce4 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -3402,6 +3402,77 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { return 1; } +int unit_get_memory_available(Unit *u, uint64_t *ret) { + uint64_t unit_current, available = UINT64_MAX; + CGroupContext *unit_context; + const char *memory_file; + int r; + + assert(u); + assert(ret); + + /* If data from cgroups can be accessed, try to find out how much more memory a unit can + * 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 = UINT64_MAX; + CGroupContext *slice_context; + + /* No point in continuing if we can't go any lower */ + if (available == 0) + break; + + if (!slice->cgroup_path) + continue; + + slice_context = unit_get_cgroup_context(slice); + if (!slice_context) + continue; + + if (slice_context->memory_max == UINT64_MAX && slice_context->memory_high == UINT64_MAX) + continue; + + 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); + available = MIN(slice_available, available); + } + + *ret = available; + + return 0; +} + int unit_get_memory_current(Unit *u, uint64_t *ret) { int r; |