mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fix mount refcount issue.
Each mount is holds a reference on a root Dirent, but the mount itself may live beyond it's own reference. This means that a call to Root() can come after the associated reference has been dropped. Instead of introducing a separate layer of references for mount objects, we simply change the Root() method to use TryIncRef() and allow it to return nil if the mount is already gone. This requires updating a small number of callers and minimizes the change (since VFSv2 will replace this code shortly). PiperOrigin-RevId: 297174230
This commit is contained in:
committed by
gVisor bot
parent
d7b7379251
commit
53504e29ca
@@ -36,11 +36,12 @@ func mountPathsAre(root *Dirent, got []*Mount, want ...string) error {
|
||||
gotPaths := make(map[string]struct{}, len(got))
|
||||
gotStr := make([]string, len(got))
|
||||
for i, g := range got {
|
||||
groot := g.Root()
|
||||
name, _ := groot.FullName(root)
|
||||
groot.DecRef()
|
||||
gotStr[i] = name
|
||||
gotPaths[name] = struct{}{}
|
||||
if groot := g.Root(); groot != nil {
|
||||
name, _ := groot.FullName(root)
|
||||
groot.DecRef()
|
||||
gotStr[i] = name
|
||||
gotPaths[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
return fmt.Errorf("mount paths are different, got: %q, want: %q", gotStr, want)
|
||||
|
||||
@@ -100,10 +100,14 @@ func newUndoMount(d *Dirent) *Mount {
|
||||
}
|
||||
}
|
||||
|
||||
// Root returns the root dirent of this mount. Callers must call DecRef on the
|
||||
// returned dirent.
|
||||
// Root returns the root dirent of this mount.
|
||||
//
|
||||
// This may return nil if the mount has already been free. Callers must handle this
|
||||
// case appropriately. If non-nil, callers must call DecRef on the returned *Dirent.
|
||||
func (m *Mount) Root() *Dirent {
|
||||
m.root.IncRef()
|
||||
if !m.root.TryIncRef() {
|
||||
return nil
|
||||
}
|
||||
return m.root
|
||||
}
|
||||
|
||||
|
||||
@@ -60,13 +60,15 @@ func forEachMount(t *kernel.Task, fn func(string, *fs.Mount)) {
|
||||
})
|
||||
for _, m := range ms {
|
||||
mroot := m.Root()
|
||||
if mroot == nil {
|
||||
continue // No longer valid.
|
||||
}
|
||||
mountPath, desc := mroot.FullName(rootDir)
|
||||
mroot.DecRef()
|
||||
if !desc {
|
||||
// MountSources that are not descendants of the chroot jail are ignored.
|
||||
continue
|
||||
}
|
||||
|
||||
fn(mountPath, m)
|
||||
}
|
||||
}
|
||||
@@ -91,6 +93,12 @@ func (mif *mountInfoFile) ReadSeqFileData(ctx context.Context, handle seqfile.Se
|
||||
|
||||
var buf bytes.Buffer
|
||||
forEachMount(mif.t, func(mountPath string, m *fs.Mount) {
|
||||
mroot := m.Root()
|
||||
if mroot == nil {
|
||||
return // No longer valid.
|
||||
}
|
||||
defer mroot.DecRef()
|
||||
|
||||
// Format:
|
||||
// 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||
// (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
||||
@@ -107,9 +115,6 @@ func (mif *mountInfoFile) ReadSeqFileData(ctx context.Context, handle seqfile.Se
|
||||
|
||||
// (3) Major:Minor device ID. We don't have a superblock, so we
|
||||
// just use the root inode device number.
|
||||
mroot := m.Root()
|
||||
defer mroot.DecRef()
|
||||
|
||||
sa := mroot.Inode.StableAttr
|
||||
fmt.Fprintf(&buf, "%d:%d ", sa.DeviceFileMajor, sa.DeviceFileMinor)
|
||||
|
||||
@@ -207,6 +212,9 @@ func (mf *mountsFile) ReadSeqFileData(ctx context.Context, handle seqfile.SeqHan
|
||||
//
|
||||
// The "needs dump"and fsck flags are always 0, which is allowed.
|
||||
root := m.Root()
|
||||
if root == nil {
|
||||
return // No longer valid.
|
||||
}
|
||||
defer root.DecRef()
|
||||
|
||||
flags := root.Inode.MountSource.Flags
|
||||
|
||||
Reference in New Issue
Block a user