From: Ivan Shapovalov Date: Fri, 20 Sep 2024 11:01:51 +0000 (+0200) Subject: core/cgroup: cache IO accounting data when pruning a cgroup X-Git-Tag: v257-rc1~360^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=17bbdefd8c49617d7596bbf708c818a9773a9b44;p=thirdparty%2Fsystemd.git 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. --- 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;