mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
ef4a490693
commit
47b5915a7b
@@ -48,6 +48,8 @@
|
||||
// Lock ordering:
|
||||
//
|
||||
// kernfs.Filesystem.mu
|
||||
// kernel.TaskSet.mu
|
||||
// kernel.Task.mu
|
||||
// kernfs.Dentry.dirMu
|
||||
// vfs.VirtualFilesystem.mountMu
|
||||
// vfs.Dentry.mu
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user