]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/cgroup: cache IO accounting data when pruning a cgroup 34508/head
authorIvan Shapovalov <intelfx@intelfx.name>
Fri, 20 Sep 2024 11:01:51 +0000 (13:01 +0200)
committerIvan Shapovalov <intelfx@intelfx.name>
Mon, 23 Sep 2024 18:12:58 +0000 (20:12 +0200)
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

index 61814efa9cd660f6dfa7eaee62043b27ab392906..fb89a22d2e1ceb01f56336841a624439bb67d949 100644 (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;