@@ -63,6 +63,13 @@ func neededControllers(cgroup *configs.Cgroup) ([]string, error) {
6363 return list , nil
6464}
6565
66+ // containsDomainController returns whether the current config contains domain controller or not.
67+ // Refer to: http://man7.org/linux/man-pages/man7/cgroups.7.html
68+ // As at Linux 4.19, the following controllers are threaded: cpu, perf_event, and pids.
69+ func containsDomainController (cg * configs.Cgroup ) bool {
70+ return isMemorySet (cg ) || isIoSet (cg ) || isCpuSet (cg ) || isHugeTlbSet (cg )
71+ }
72+
6673// CreateCgroupPath creates cgroupv2 path, enabling all the
6774// needed controllers in the process.
6875func CreateCgroupPath (path string , c * configs.Cgroup ) (Err error ) {
@@ -95,10 +102,34 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
95102 }
96103 }()
97104 }
98- // Write cgroup.type explicitly.
99- // Otherwise ENOTSUP may happen.
100- cgType := filepath .Join (current , "cgroup.type" )
101- _ = ioutil .WriteFile (cgType , []byte ("threaded" ), 0644 )
105+ cgTypeFile := filepath .Join (current , "cgroup.type" )
106+ cgType , _ := ioutil .ReadFile (cgTypeFile )
107+ switch strings .TrimSpace (string (cgType )) {
108+ // If the cgroup is in an invalid mode (usually this means there's an internal
109+ // process in the cgroup tree, because we created a cgroup under an
110+ // already-populated-by-other-processes cgroup), then we have to error out if
111+ // the user requested controllers which are not thread-aware. However, if all
112+ // the controllers requested are thread-aware we can simply put the cgroup into
113+ // threaded mode.
114+ case "domain invalid" :
115+ if containsDomainController (c ) {
116+ return fmt .Errorf ("cannot enter cgroupv2 %q with domain controllers -- it is in an invalid state" , current )
117+ } else {
118+ // Not entirely correct (in theory we'd always want to be a domain --
119+ // since that means we're a properly delegated cgroup subtree) but in
120+ // this case there's not much we can do and it's better than giving an
121+ // error.
122+ _ = ioutil .WriteFile (cgTypeFile , []byte ("threaded" ), 0644 )
123+ }
124+ // If the cgroup is in (threaded) or (domain threaded) mode, we can only use thread-aware controllers
125+ // (and you cannot usually take a cgroup out of threaded mode).
126+ case "domain threaded" :
127+ fallthrough
128+ case "threaded" :
129+ if containsDomainController (c ) {
130+ return fmt .Errorf ("cannot enter cgroupv2 %q with domain controllers -- it is in %s mode" , current , strings .TrimSpace (string (cgType )))
131+ }
132+ }
102133 }
103134 // enable needed controllers
104135 if i < len (elements )- 1 {
0 commit comments