From 294c4866ea93392dd81f68f97fe6d94bbbf8f9c1 Mon Sep 17 00:00:00 2001 From: Odin Ugedal Date: Mon, 5 Jul 2021 16:18:07 +0200 Subject: [PATCH] libct/cg/fs/freezer.GetState: report current cgroup state If a control group is frozen, all its descendants will report FROZEN in freezer.state cgroup file. OTOH cgroup v2 cgroup.freeze is not reporting the cgroup as frozen unless it is frozen directly (i.e. not via an ancestor). Fix the discrepancy between v1 and v2 drivers behavior by looking into freezer.self_freezing cgroup file, which, according to kernel documentation, will show 1 iff the cgroup was frozen directly. Co-authored-by: Kir Kolyshkin Signed-off-by: Odin Ugedal Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/fs/freezer.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libcontainer/cgroups/fs/freezer.go b/libcontainer/cgroups/fs/freezer.go index 519bd5136..4baa2798a 100644 --- a/libcontainer/cgroups/fs/freezer.go +++ b/libcontainer/cgroups/fs/freezer.go @@ -129,7 +129,25 @@ func (s *FreezerGroup) GetState(path string) (configs.FreezerState, error) { case "THAWED": return configs.Thawed, nil case "FROZEN": - return configs.Frozen, nil + // Find out whether the cgroup is frozen directly, + // or indirectly via an ancestor. + self, err := cgroups.ReadFile(path, "freezer.self_freezing") + if err != nil { + // If the kernel is too old, then we just treat + // it as being frozen. + if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.ENODEV) { + err = nil + } + return configs.Frozen, err + } + switch self { + case "0\n": + return configs.Thawed, nil + case "1\n": + return configs.Frozen, nil + default: + return configs.Undefined, fmt.Errorf(`unknown "freezer.self_freezing" state: %q`, self) + } case "FREEZING": // Make sure we get a stable freezer state, so retry if the cgroup // is still undergoing freezing. This should be a temporary delay.