...
1 package fs
2
3 import (
4 "errors"
5 "fmt"
6 "os"
7 "strings"
8 "time"
9
10 "github.com/opencontainers/runc/libcontainer/cgroups"
11 "github.com/opencontainers/runc/libcontainer/configs"
12 "github.com/sirupsen/logrus"
13 "golang.org/x/sys/unix"
14 )
15
16 type FreezerGroup struct{}
17
18 func (s *FreezerGroup) Name() string {
19 return "freezer"
20 }
21
22 func (s *FreezerGroup) Apply(path string, _ *configs.Resources, pid int) error {
23 return apply(path, pid)
24 }
25
26 func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) {
27 switch r.Freezer {
28 case configs.Frozen:
29 defer func() {
30 if Err != nil {
31
32
33
34 _ = cgroups.WriteFile(path, "freezer.state", string(configs.Thawed))
35 }
36 }()
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 for i := 0; i < 1000; i++ {
62 if i%50 == 49 {
63
64
65
66
67 _ = cgroups.WriteFile(path, "freezer.state", string(configs.Thawed))
68 time.Sleep(10 * time.Millisecond)
69 }
70
71 if err := cgroups.WriteFile(path, "freezer.state", string(configs.Frozen)); err != nil {
72 return err
73 }
74
75 if i%25 == 24 {
76
77
78
79
80 time.Sleep(10 * time.Microsecond)
81 }
82 state, err := cgroups.ReadFile(path, "freezer.state")
83 if err != nil {
84 return err
85 }
86 state = strings.TrimSpace(state)
87 switch state {
88 case "FREEZING":
89 continue
90 case string(configs.Frozen):
91 if i > 1 {
92 logrus.Debugf("frozen after %d retries", i)
93 }
94 return nil
95 default:
96
97 return fmt.Errorf("unexpected state %s while freezing", strings.TrimSpace(state))
98 }
99 }
100
101 return errors.New("unable to freeze")
102 case configs.Thawed:
103 return cgroups.WriteFile(path, "freezer.state", string(configs.Thawed))
104 case configs.Undefined:
105 return nil
106 default:
107 return fmt.Errorf("Invalid argument '%s' to freezer.state", string(r.Freezer))
108 }
109 }
110
111 func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error {
112 return nil
113 }
114
115 func (s *FreezerGroup) GetState(path string) (configs.FreezerState, error) {
116 for {
117 state, err := cgroups.ReadFile(path, "freezer.state")
118 if err != nil {
119
120
121 if os.IsNotExist(err) || errors.Is(err, unix.ENODEV) {
122 err = nil
123 }
124 return configs.Undefined, err
125 }
126 switch strings.TrimSpace(state) {
127 case "THAWED":
128 return configs.Thawed, nil
129 case "FROZEN":
130
131
132 self, err := cgroups.ReadFile(path, "freezer.self_freezing")
133 if err != nil {
134
135
136 if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.ENODEV) {
137 err = nil
138 }
139 return configs.Frozen, err
140 }
141 switch self {
142 case "0\n":
143 return configs.Thawed, nil
144 case "1\n":
145 return configs.Frozen, nil
146 default:
147 return configs.Undefined, fmt.Errorf(`unknown "freezer.self_freezing" state: %q`, self)
148 }
149 case "FREEZING":
150
151
152 time.Sleep(1 * time.Millisecond)
153 continue
154 default:
155 return configs.Undefined, fmt.Errorf("unknown freezer.state %q", state)
156 }
157 }
158 }
159
View as plain text