summaryrefslogtreecommitdiffstats
path: root/src/core/cgroup.c
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2021-05-26 20:16:48 +0200
committerLuca Boccassi <luca.boccassi@microsoft.com>2021-06-08 15:05:56 +0200
commit93ff34e44aa6cfae2b3723ec57862ce54c1721eb (patch)
tree2d11fcaefbe32142045e71b785649e46e270fe0f /src/core/cgroup.c
parentpo: Translated using Weblate (Spanish) (diff)
downloadsystemd-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.c71
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;