core/cgroup: cache IO accounting data when pruning a cgroup

When removing a cgroup in unit_prune_cgroup(), read IO metrics to cache
them similar to the existing treatment of the CPU and memory usage data.

Note that we do not do this for the IP metrics as the firewall objects
are only destroyed in unit_free() and thus stay alive long enough to
be read out directly by all interested parties.

Fixes #26988.
This commit is contained in:
Ivan Shapovalov
2024-09-23 20:12:58 +02:00
parent a0020ad84b
commit 17bbdefd8c
+15 -3
View File
@@ -3571,12 +3571,17 @@ void unit_prune_cgroup(Unit *u) {
if (!crt || !crt->cgroup_path)
return;
/* Cache the last CPU and memory usage values before we destroy the cgroup */
/* Cache the last resource usage values before we destroy the cgroup */
(void) unit_get_cpu_usage(u, /* ret = */ NULL);
for (CGroupMemoryAccountingMetric metric = 0; metric <= _CGROUP_MEMORY_ACCOUNTING_METRIC_CACHED_LAST; metric++)
(void) unit_get_memory_accounting(u, metric, /* ret = */ NULL);
/* All IO metrics are read at once from the underlying cgroup, so issue just a single call */
(void) unit_get_io_accounting(u, _CGROUP_IO_ACCOUNTING_METRIC_INVALID, /* ret = */ NULL);
/* We do not cache IP metrics here because the firewall objects are not freed with cgroups */
#if BPF_FRAMEWORK
(void) bpf_restrict_fs_cleanup(u); /* Remove cgroup from the global LSM BPF map */
#endif
@@ -4863,7 +4868,14 @@ int unit_get_io_accounting(
uint64_t raw[_CGROUP_IO_ACCOUNTING_METRIC_MAX];
int r;
/* Retrieve an IO account parameter. This will subtract the counter when the unit was started. */
/*
* Retrieve an IO counter, subtracting the value of the counter value at the time the unit was started.
* If ret == NULL and metric == _<...>_INVALID, no return value is expected (refresh the caches only).
*/
assert(u);
assert(metric >= 0 || (!ret && metric == _CGROUP_IO_ACCOUNTING_METRIC_INVALID));
assert(metric < _CGROUP_IO_ACCOUNTING_METRIC_MAX);
if (!UNIT_CGROUP_BOOL(u, io_accounting))
return -ENODATA;
@@ -4873,7 +4885,7 @@ int unit_get_io_accounting(
return -ENODATA;
r = unit_get_io_accounting_raw(u, crt, raw);
if (r == -ENODATA && crt->io_accounting_last[metric] != UINT64_MAX)
if (r == -ENODATA && metric >= 0 && crt->io_accounting_last[metric] != UINT64_MAX)
goto done;
if (r < 0)
return r;