From: Michal Privoznik <mprivozn@redhat.com> With CGroupsV2 the freezer controller is split into two files: 1) cgroup.freeze where an integer is written to thaw(0)/freeze(1) processes within the cgroup, and 2) cgroup.events where the frozen status can be read. Now, freezing/thawing a cgroup is as simple as writing corresponding integer into cgroup.freeze. But similarly to CGroupsV1, it may take some time to actually freeze all processes inside the cgroup. So read both file and map combination of their values according to this table: | frozen from cgroup.events cgroup.freeze | 0 | 1 --------------+------------+------------- 0 | THAWED | N/A --+------------+------------- 1 | FREEZING | FROZEN Resolves: https://gitlab.com/libvirt/libvirt/-/work_items/870 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/vircgroupv2.c | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c index 3fbd67fbda..1f2ba72c4d 100644 --- a/src/util/vircgroupv2.c +++ b/src/util/vircgroupv2.c @@ -1907,6 +1907,90 @@ virCgroupV2DenyAllDevices(virCgroup *group) } +static int +virCgroupV2SetFreezerState(virCgroup *group, + virCgroupFreezerState state) +{ + unsigned long long val; + + switch (state) { + case VIR_CGROUP_FREEZER_STATE_THAWED: + val = 0; break; + case VIR_CGROUP_FREEZER_STATE_FROZEN: + val = 1; break; + case VIR_CGROUP_FREEZER_STATE_FREEZING: + case VIR_CGROUP_FREEZER_STATE_LAST: + default: + virReportEnumRangeError(virCgroupFreezerState, state); + return -1; + } + + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_FREEZER, + "cgroup.freeze", + val); +} + + +static int +virCgroupV2GetFreezerState(virCgroup *group, + virCgroupFreezerState *state) +{ + unsigned long long freezeReqested; + g_autofree char *eventsStr = NULL; + const char *frozenStr = "frozen "; + const char *tmp; + + if (virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_FREEZER, + "cgroup.freeze", &freezeReqested) < 0) { + + return -1; + } + + if (freezeReqested == 0) { + /* No freeze is requested. */ + *state = VIR_CGROUP_FREEZER_STATE_THAWED; + return 0; + } else if (freezeReqested != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown value of freezer controller: %1$llu"), + freezeReqested); + return -1; + } + + /* Now look at cgroup.events at 'frozen' state. If it's 0, then some + * processes inside the CGroup are still being frozen. If it's 1, + * then all processes are frozen. */ + if (virCgroupGetValueStr(group, + VIR_CGROUP_CONTROLLER_FREEZER, + "cgroup.events", &eventsStr) < 0) { + return -1; + } + + if (!eventsStr || + !(tmp = strstr(eventsStr, frozenStr))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid format of cgroup.events file")); + return -1; + } + + tmp += strlen(frozenStr); + if (*tmp == '0') { + *state = VIR_CGROUP_FREEZER_STATE_FREEZING; + } else if (*tmp == '1') { + *state = VIR_CGROUP_FREEZER_STATE_FROZEN; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown state of freezer controller: %1$s"), + tmp); + return -1; + } + + return 0; +} + + virCgroupBackend virCgroupV2Backend = { .type = VIR_CGROUP_BACKEND_TYPE_V2, @@ -1980,6 +2064,9 @@ virCgroupBackend virCgroupV2Backend = { .getCpusetMemoryMigrate = virCgroupV2GetCpusetMemoryMigrate, .setCpusetCpus = virCgroupV2SetCpusetCpus, .getCpusetCpus = virCgroupV2GetCpusetCpus, + + .setFreezerState = virCgroupV2SetFreezerState, + .getFreezerState = virCgroupV2GetFreezerState, }; -- 2.53.0