From 17bbdefd8c49617d7596bbf708c818a9773a9b44 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Fri, 20 Sep 2024 13:01:51 +0200 Subject: [PATCH] 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. --- src/core/cgroup.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 61814efa9cd..fb89a22d2e1 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -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; -- 2.47.3