github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/kernel/task_cgroup.go (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package kernel 16 17 import ( 18 "bytes" 19 "fmt" 20 "sort" 21 "strings" 22 23 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 24 "github.com/SagerNet/gvisor/pkg/log" 25 ) 26 27 // EnterInitialCgroups moves t into an initial set of cgroups. 28 // 29 // Precondition: t isn't in any cgroups yet, t.cgs is empty. 30 // 31 // +checklocksignore parent.mu is conditionally acquired. 32 func (t *Task) EnterInitialCgroups(parent *Task) { 33 var inherit map[Cgroup]struct{} 34 if parent != nil { 35 parent.mu.Lock() 36 defer parent.mu.Unlock() 37 inherit = parent.cgroups 38 } 39 joinSet := t.k.cgroupRegistry.computeInitialGroups(inherit) 40 41 t.mu.Lock() 42 defer t.mu.Unlock() 43 // Transfer ownership of joinSet refs to the task's cgset. 44 t.cgroups = joinSet 45 for c, _ := range t.cgroups { 46 // Since t isn't in any cgroup yet, we can skip the check against 47 // existing cgroups. 48 c.Enter(t) 49 } 50 } 51 52 // EnterCgroup moves t into c. 53 func (t *Task) EnterCgroup(c Cgroup) error { 54 newControllers := make(map[CgroupControllerType]struct{}) 55 for _, ctl := range c.Controllers() { 56 newControllers[ctl.Type()] = struct{}{} 57 } 58 59 t.mu.Lock() 60 defer t.mu.Unlock() 61 62 for oldCG, _ := range t.cgroups { 63 for _, oldCtl := range oldCG.Controllers() { 64 if _, ok := newControllers[oldCtl.Type()]; ok { 65 // Already in a cgroup with the same controller as one of the 66 // new ones. Requires migration between cgroups. 67 // 68 // TODO(b/183137098): Implement cgroup migration. 69 log.Warningf("Cgroup migration is not implemented") 70 return linuxerr.EBUSY 71 } 72 } 73 } 74 75 // No migration required. 76 t.enterCgroupLocked(c) 77 78 return nil 79 } 80 81 // +checklocks:t.mu 82 func (t *Task) enterCgroupLocked(c Cgroup) { 83 c.IncRef() 84 t.cgroups[c] = struct{}{} 85 c.Enter(t) 86 } 87 88 // +checklocks:t.mu 89 func (t *Task) enterCgroupIfNotYetLocked(c Cgroup) { 90 if _, ok := t.cgroups[c]; ok { 91 return 92 } 93 t.enterCgroupLocked(c) 94 } 95 96 // LeaveCgroups removes t out from all its cgroups. 97 func (t *Task) LeaveCgroups() { 98 t.mu.Lock() 99 defer t.mu.Unlock() 100 for c, _ := range t.cgroups { 101 t.leaveCgroupLocked(c) 102 } 103 } 104 105 // +checklocks:t.mu 106 func (t *Task) leaveCgroupLocked(c Cgroup) { 107 c.Leave(t) 108 delete(t.cgroups, c) 109 c.decRef() 110 } 111 112 // taskCgroupEntry represents a line in /proc/<pid>/cgroup, and is used to 113 // format a cgroup for display. 114 type taskCgroupEntry struct { 115 hierarchyID uint32 116 controllers string 117 path string 118 } 119 120 // GenerateProcTaskCgroup writes the contents of /proc/<pid>/cgroup for t to buf. 121 func (t *Task) GenerateProcTaskCgroup(buf *bytes.Buffer) { 122 t.mu.Lock() 123 defer t.mu.Unlock() 124 125 cgEntries := make([]taskCgroupEntry, 0, len(t.cgroups)) 126 for c, _ := range t.cgroups { 127 ctls := c.Controllers() 128 ctlNames := make([]string, 0, len(ctls)) 129 for _, ctl := range ctls { 130 ctlNames = append(ctlNames, string(ctl.Type())) 131 } 132 133 cgEntries = append(cgEntries, taskCgroupEntry{ 134 // Note: We're guaranteed to have at least one controller, and all 135 // controllers are guaranteed to be on the same hierarchy. 136 hierarchyID: ctls[0].HierarchyID(), 137 controllers: strings.Join(ctlNames, ","), 138 path: c.Path(), 139 }) 140 } 141 142 sort.Slice(cgEntries, func(i, j int) bool { return cgEntries[i].hierarchyID > cgEntries[j].hierarchyID }) 143 for _, cgE := range cgEntries { 144 fmt.Fprintf(buf, "%d:%s:%s\n", cgE.hierarchyID, cgE.controllers, cgE.path) 145 } 146 }