@@ -6,13 +6,48 @@ import (
6
6
"path/filepath"
7
7
"strconv"
8
8
"strings"
9
+ "sync"
9
10
10
11
"golang.org/x/sys/unix"
11
12
12
13
"github.com/opencontainers/runc/libcontainer/cgroups"
13
14
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
14
15
)
15
16
17
+ var (
18
+ cpusetLock sync.Mutex
19
+ cpusetPrefix = "cpuset."
20
+ cpusetFastPath bool
21
+ )
22
+
23
+ func cpusetFile (path string , name string ) string {
24
+ cpusetLock .Lock ()
25
+ defer cpusetLock .Unlock ()
26
+
27
+ // Only the v1 cpuset cgroup is allowed to mount with noprefix.
28
+ // See kernel source: https://github.com/torvalds/linux/blob/2e1b3cc9d7f790145a80cb705b168f05dab65df2/kernel/cgroup/cgroup-v1.c#L1070
29
+ // Cpuset cannot be mounted with and without prefix simultaneously.
30
+ // Commonly used in Android environments.
31
+
32
+ if cpusetFastPath {
33
+ return cpusetPrefix + name
34
+ }
35
+
36
+ err := unix .Access (filepath .Join (path , cpusetPrefix + name ), unix .F_OK )
37
+ if err == nil {
38
+ // Use the fast path only if we can access one type of mount for cpuset already
39
+ cpusetFastPath = true
40
+ } else {
41
+ err = unix .Access (filepath .Join (path , name ), unix .F_OK )
42
+ if err == nil {
43
+ cpusetPrefix = ""
44
+ cpusetFastPath = true
45
+ }
46
+ }
47
+
48
+ return cpusetPrefix + name
49
+ }
50
+
16
51
type CpusetGroup struct {}
17
52
18
53
func (s * CpusetGroup ) Name () string {
@@ -25,12 +60,12 @@ func (s *CpusetGroup) Apply(path string, r *cgroups.Resources, pid int) error {
25
60
26
61
func (s * CpusetGroup ) Set (path string , r * cgroups.Resources ) error {
27
62
if r .CpusetCpus != "" {
28
- if err := cgroups .WriteFile (path , "cpuset. cpus" , r .CpusetCpus ); err != nil {
63
+ if err := cgroups .WriteFile (path , cpusetFile ( path , " cpus") , r .CpusetCpus ); err != nil {
29
64
return err
30
65
}
31
66
}
32
67
if r .CpusetMems != "" {
33
- if err := cgroups .WriteFile (path , "cpuset. mems" , r .CpusetMems ); err != nil {
68
+ if err := cgroups .WriteFile (path , cpusetFile ( path , " mems") , r .CpusetMems ); err != nil {
34
69
return err
35
70
}
36
71
}
@@ -79,57 +114,57 @@ func getCpusetStat(path string, file string) ([]uint16, error) {
79
114
func (s * CpusetGroup ) GetStats (path string , stats * cgroups.Stats ) error {
80
115
var err error
81
116
82
- stats .CPUSetStats .CPUs , err = getCpusetStat (path , "cpuset. cpus" )
117
+ stats .CPUSetStats .CPUs , err = getCpusetStat (path , cpusetFile ( path , " cpus") )
83
118
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
84
119
return err
85
120
}
86
121
87
- stats .CPUSetStats .CPUExclusive , err = fscommon .GetCgroupParamUint (path , "cpuset. cpu_exclusive" )
122
+ stats .CPUSetStats .CPUExclusive , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " cpu_exclusive") )
88
123
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
89
124
return err
90
125
}
91
126
92
- stats .CPUSetStats .Mems , err = getCpusetStat (path , "cpuset. mems" )
127
+ stats .CPUSetStats .Mems , err = getCpusetStat (path , cpusetFile ( path , " mems") )
93
128
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
94
129
return err
95
130
}
96
131
97
- stats .CPUSetStats .MemHardwall , err = fscommon .GetCgroupParamUint (path , "cpuset. mem_hardwall" )
132
+ stats .CPUSetStats .MemHardwall , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " mem_hardwall") )
98
133
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
99
134
return err
100
135
}
101
136
102
- stats .CPUSetStats .MemExclusive , err = fscommon .GetCgroupParamUint (path , "cpuset. mem_exclusive" )
137
+ stats .CPUSetStats .MemExclusive , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " mem_exclusive") )
103
138
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
104
139
return err
105
140
}
106
141
107
- stats .CPUSetStats .MemoryMigrate , err = fscommon .GetCgroupParamUint (path , "cpuset. memory_migrate" )
142
+ stats .CPUSetStats .MemoryMigrate , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " memory_migrate") )
108
143
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
109
144
return err
110
145
}
111
146
112
- stats .CPUSetStats .MemorySpreadPage , err = fscommon .GetCgroupParamUint (path , "cpuset. memory_spread_page" )
147
+ stats .CPUSetStats .MemorySpreadPage , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " memory_spread_page") )
113
148
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
114
149
return err
115
150
}
116
151
117
- stats .CPUSetStats .MemorySpreadSlab , err = fscommon .GetCgroupParamUint (path , "cpuset. memory_spread_slab" )
152
+ stats .CPUSetStats .MemorySpreadSlab , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " memory_spread_slab") )
118
153
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
119
154
return err
120
155
}
121
156
122
- stats .CPUSetStats .MemoryPressure , err = fscommon .GetCgroupParamUint (path , "cpuset. memory_pressure" )
157
+ stats .CPUSetStats .MemoryPressure , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " memory_pressure") )
123
158
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
124
159
return err
125
160
}
126
161
127
- stats .CPUSetStats .SchedLoadBalance , err = fscommon .GetCgroupParamUint (path , "cpuset. sched_load_balance" )
162
+ stats .CPUSetStats .SchedLoadBalance , err = fscommon .GetCgroupParamUint (path , cpusetFile ( path , " sched_load_balance") )
128
163
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
129
164
return err
130
165
}
131
166
132
- stats .CPUSetStats .SchedRelaxDomainLevel , err = fscommon .GetCgroupParamInt (path , "cpuset. sched_relax_domain_level" )
167
+ stats .CPUSetStats .SchedRelaxDomainLevel , err = fscommon .GetCgroupParamInt (path , cpusetFile ( path , " sched_relax_domain_level") )
133
168
if err != nil && ! errors .Is (err , os .ErrNotExist ) {
134
169
return err
135
170
}
@@ -168,10 +203,10 @@ func (s *CpusetGroup) ApplyDir(dir string, r *cgroups.Resources, pid int) error
168
203
}
169
204
170
205
func getCpusetSubsystemSettings (parent string ) (cpus , mems string , err error ) {
171
- if cpus , err = cgroups .ReadFile (parent , "cpuset. cpus" ); err != nil {
206
+ if cpus , err = cgroups .ReadFile (parent , cpusetFile ( parent , " cpus") ); err != nil {
172
207
return
173
208
}
174
- if mems , err = cgroups .ReadFile (parent , "cpuset. mems" ); err != nil {
209
+ if mems , err = cgroups .ReadFile (parent , cpusetFile ( parent , " mems") ); err != nil {
175
210
return
176
211
}
177
212
return cpus , mems , nil
@@ -217,12 +252,12 @@ func cpusetCopyIfNeeded(current, parent string) error {
217
252
}
218
253
219
254
if isEmptyCpuset (currentCpus ) {
220
- if err := cgroups .WriteFile (current , "cpuset. cpus" , parentCpus ); err != nil {
255
+ if err := cgroups .WriteFile (current , cpusetFile ( current , " cpus") , parentCpus ); err != nil {
221
256
return err
222
257
}
223
258
}
224
259
if isEmptyCpuset (currentMems ) {
225
- if err := cgroups .WriteFile (current , "cpuset. mems" , parentMems ); err != nil {
260
+ if err := cgroups .WriteFile (current , cpusetFile ( current , " mems") , parentMems ); err != nil {
226
261
return err
227
262
}
228
263
}
0 commit comments