...
1 package fs2
2
3 import (
4 "bufio"
5 "errors"
6 "fmt"
7 "os"
8 "strings"
9 "time"
10
11 "golang.org/x/sys/unix"
12
13 "github.com/opencontainers/runc/libcontainer/cgroups"
14 "github.com/opencontainers/runc/libcontainer/configs"
15 )
16
17 func setFreezer(dirPath string, state configs.FreezerState) error {
18 var stateStr string
19 switch state {
20 case configs.Undefined:
21 return nil
22 case configs.Frozen:
23 stateStr = "1"
24 case configs.Thawed:
25 stateStr = "0"
26 default:
27 return fmt.Errorf("invalid freezer state %q requested", state)
28 }
29
30 fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDWR)
31 if err != nil {
32
33
34
35 if state != configs.Frozen {
36 return nil
37 }
38 return fmt.Errorf("freezer not supported: %w", err)
39 }
40 defer fd.Close()
41
42 if _, err := fd.WriteString(stateStr); err != nil {
43 return err
44 }
45
46 if actualState, err := readFreezer(dirPath, fd); err != nil {
47 return err
48 } else if actualState != state {
49 return fmt.Errorf(`expected "cgroup.freeze" to be in state %q but was in %q`, state, actualState)
50 }
51 return nil
52 }
53
54 func getFreezer(dirPath string) (configs.FreezerState, error) {
55 fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDONLY)
56 if err != nil {
57
58
59 if os.IsNotExist(err) || errors.Is(err, unix.ENODEV) {
60 err = nil
61 }
62 return configs.Undefined, err
63 }
64 defer fd.Close()
65
66 return readFreezer(dirPath, fd)
67 }
68
69 func readFreezer(dirPath string, fd *os.File) (configs.FreezerState, error) {
70 if _, err := fd.Seek(0, 0); err != nil {
71 return configs.Undefined, err
72 }
73 state := make([]byte, 2)
74 if _, err := fd.Read(state); err != nil {
75 return configs.Undefined, err
76 }
77 switch string(state) {
78 case "0\n":
79 return configs.Thawed, nil
80 case "1\n":
81 return waitFrozen(dirPath)
82 default:
83 return configs.Undefined, fmt.Errorf(`unknown "cgroup.freeze" state: %q`, state)
84 }
85 }
86
87
88 func waitFrozen(dirPath string) (configs.FreezerState, error) {
89 fd, err := cgroups.OpenFile(dirPath, "cgroup.events", unix.O_RDONLY)
90 if err != nil {
91 return configs.Undefined, err
92 }
93 defer fd.Close()
94
95
96
97
98 const (
99
100 waitTime = 10 * time.Millisecond
101 maxIter = 1000
102 )
103 scanner := bufio.NewScanner(fd)
104 for i := 0; scanner.Scan(); {
105 if i == maxIter {
106 return configs.Undefined, fmt.Errorf("timeout of %s reached waiting for the cgroup to freeze", waitTime*maxIter)
107 }
108 line := scanner.Text()
109 val := strings.TrimPrefix(line, "frozen ")
110 if val != line {
111 if val[0] == '1' {
112 return configs.Frozen, nil
113 }
114
115 i++
116
117 time.Sleep(waitTime)
118 _, err := fd.Seek(0, 0)
119 if err != nil {
120 return configs.Undefined, err
121 }
122 }
123 }
124
125
126 return configs.Undefined, scanner.Err()
127 }
128
View as plain text