Break Task.mu -> kernfs.Filesystem.mu lock chain when managing cgroups.

This led to circular locking since procfs aquires Task.mu while
holding kernfs.Filesystem.mu. The procfs case is harder to break, as
procfs needs to acquire an mm reference during a filesystem operation.

PiperOrigin-RevId: 445237505
This commit is contained in:
Rahat Mahmood
2022-04-28 13:45:10 -07:00
committed by gVisor bot
parent ef4a490693
commit 47b5915a7b
4 changed files with 27 additions and 11 deletions
+2
View File
@@ -48,6 +48,8 @@
// Lock ordering:
//
// kernfs.Filesystem.mu
// kernel.TaskSet.mu
// kernel.Task.mu
// kernfs.Dentry.dirMu
// vfs.VirtualFilesystem.mountMu
// vfs.Dentry.mu
+2
View File
@@ -91,6 +91,8 @@ type Cgroup struct {
CgroupImpl
}
// decRef drops a reference on the cgroup. This must happen outside a Task.mu
// critical section.
func (c *Cgroup) decRef() {
c.Dentry.DecRef(context.Background())
}
+15 -1
View File
@@ -1871,7 +1871,11 @@ func (k *Kernel) PopulateNewCgroupHierarchy(root Cgroup) {
// hierarchy with the provided id. This is intended for use during hierarchy
// teardown, as otherwise the tasks would be orphaned w.r.t to some controllers.
func (k *Kernel) ReleaseCgroupHierarchy(hid uint32) {
var releasedCGs []Cgroup
k.tasks.mu.RLock()
// We'll have one cgroup per hierarchy per task.
releasedCGs = make([]Cgroup, 0, len(k.tasks.Root.tids))
k.tasks.forEachTaskLocked(func(t *Task) {
if t.exitState != TaskExitNone {
return
@@ -1879,12 +1883,22 @@ func (k *Kernel) ReleaseCgroupHierarchy(hid uint32) {
t.mu.Lock()
for cg := range t.cgroups {
if cg.HierarchyID() == hid {
t.leaveCgroupLocked(cg)
cg.Leave(t)
delete(t.cgroups, cg)
releasedCGs = append(releasedCGs, cg)
// A task can't be part of multiple cgroups from the same
// hierarchy, so we can skip checking the rest once we find a
// match.
break
}
}
t.mu.Unlock()
})
k.tasks.mu.RUnlock()
for _, c := range releasedCGs {
c.decRef()
}
}
func (k *Kernel) ReplaceFSContextRoots(ctx context.Context, oldRoot vfs.VirtualDentry, newRoot vfs.VirtualDentry) {
+8 -10
View File
@@ -90,17 +90,15 @@ func (t *Task) enterCgroupIfNotYetLocked(c Cgroup) {
// LeaveCgroups removes t out from all its cgroups.
func (t *Task) LeaveCgroups() {
t.mu.Lock()
defer t.mu.Unlock()
for c, _ := range t.cgroups {
t.leaveCgroupLocked(c)
cgs := t.cgroups
t.cgroups = nil
for c := range cgs {
c.Leave(t)
}
t.mu.Unlock()
for c := range cgs {
c.decRef()
}
}
// +checklocks:t.mu
func (t *Task) leaveCgroupLocked(c Cgroup) {
c.Leave(t)
delete(t.cgroups, c)
c.decRef()
}
// +checklocks:t.mu