mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Defer dec refing mounts in InvalidateDentry.
Reported-by: syzbot+f92ce6b097f3a67f5b9b@syzkaller.appspotmail.com PiperOrigin-RevId: 540648609
This commit is contained in:
committed by
gVisor bot
parent
6c0f22c66e
commit
bb5ada8caf
@@ -202,9 +202,9 @@ func (d *dentry) invalidate(ctx context.Context, vfsObj *vfs.VirtualFilesystem,
|
||||
// this, take a dentry reference first, then drop it while
|
||||
// deferring the call to dentry.checkCachingLocked().
|
||||
d.IncRef()
|
||||
vds := vfsObj.InvalidateDentry(ctx, &d.vfsd)
|
||||
for _, vd := range vds {
|
||||
vd.DecRef(ctx)
|
||||
rcs := vfsObj.InvalidateDentry(ctx, &d.vfsd)
|
||||
for _, rc := range rcs {
|
||||
rc.DecRef(ctx)
|
||||
}
|
||||
d.decRefNoCaching()
|
||||
|
||||
|
||||
@@ -118,9 +118,9 @@ func (fs *Filesystem) revalidateChildLocked(ctx context.Context, vfsObj *vfs.Vir
|
||||
// Drop the ref owned by kernfs.
|
||||
fs.deferDecRef(child)
|
||||
}
|
||||
vds := vfsObj.InvalidateDentry(ctx, child.VFSDentry())
|
||||
for _, vd := range vds {
|
||||
fs.deferDecRef(vd)
|
||||
rcs := vfsObj.InvalidateDentry(ctx, child.VFSDentry())
|
||||
for _, rc := range rcs {
|
||||
fs.deferDecRef(rc)
|
||||
}
|
||||
child = nil
|
||||
}
|
||||
|
||||
@@ -336,9 +336,9 @@ func (d *Dentry) cacheLocked(ctx context.Context) {
|
||||
// as described in Inode.Getlink.
|
||||
if isDead := d.VFSDentry().IsDead(); isDead || d.parent == nil {
|
||||
if !isDead {
|
||||
vds := d.fs.vfsfs.VirtualFilesystem().InvalidateDentry(ctx, d.VFSDentry())
|
||||
for _, vd := range vds {
|
||||
d.fs.deferDecRef(vd)
|
||||
rcs := d.fs.vfsfs.VirtualFilesystem().InvalidateDentry(ctx, d.VFSDentry())
|
||||
for _, rc := range rcs {
|
||||
d.fs.deferDecRef(rc)
|
||||
}
|
||||
}
|
||||
if d.cached {
|
||||
@@ -401,9 +401,9 @@ func (d *Dentry) evictLocked(ctx context.Context) {
|
||||
d.parent.dirMu.Lock()
|
||||
// Note that victim can't be a mount point (in any mount
|
||||
// namespace), since VFS holds references on mount points.
|
||||
vds := d.fs.vfsfs.VirtualFilesystem().InvalidateDentry(ctx, d.VFSDentry())
|
||||
for _, vd := range vds {
|
||||
d.fs.deferDecRef(vd)
|
||||
rcs := d.fs.vfsfs.VirtualFilesystem().InvalidateDentry(ctx, d.VFSDentry())
|
||||
for _, rc := range rcs {
|
||||
d.fs.deferDecRef(rc)
|
||||
}
|
||||
delete(d.parent.children, d.name)
|
||||
d.parent.dirMu.Unlock()
|
||||
|
||||
+20
-13
@@ -18,6 +18,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/atomicbitops"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
)
|
||||
|
||||
@@ -233,7 +234,7 @@ func (vfs *VirtualFilesystem) CommitDeleteDentry(ctx context.Context, d *Dentry)
|
||||
d.dead = true
|
||||
d.mu.Unlock()
|
||||
if d.isMounted() {
|
||||
vfs.forgetDeadMountpoint(ctx, d, false /*deferVdDecRef*/)
|
||||
vfs.forgetDeadMountpoint(ctx, d, false /*skipDecRef*/)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,12 +243,12 @@ func (vfs *VirtualFilesystem) CommitDeleteDentry(ctx context.Context, d *Dentry)
|
||||
// of a file on a remote filesystem on which the file has already been
|
||||
// deleted). If d is mounted, the method returns a list of Virtual Dentries
|
||||
// mounted on d that the caller is responsible for DecRefing.
|
||||
func (vfs *VirtualFilesystem) InvalidateDentry(ctx context.Context, d *Dentry) []VirtualDentry {
|
||||
func (vfs *VirtualFilesystem) InvalidateDentry(ctx context.Context, d *Dentry) []refs.RefCounter {
|
||||
d.mu.Lock()
|
||||
d.dead = true
|
||||
d.mu.Unlock()
|
||||
if d.isMounted() {
|
||||
return vfs.forgetDeadMountpoint(ctx, d, true /*deferVdDecRef*/)
|
||||
return vfs.forgetDeadMountpoint(ctx, d, true /*skipDecRef*/)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -309,7 +310,7 @@ func (vfs *VirtualFilesystem) CommitRenameReplaceDentry(ctx context.Context, fro
|
||||
to.dead = true
|
||||
to.mu.Unlock()
|
||||
if to.isMounted() {
|
||||
vfs.forgetDeadMountpoint(ctx, to, false /*deferVdDecRef*/)
|
||||
vfs.forgetDeadMountpoint(ctx, to, false /*skipDecRef*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,11 +327,13 @@ func (vfs *VirtualFilesystem) CommitRenameExchangeDentry(from, to *Dentry) {
|
||||
}
|
||||
|
||||
// forgetDeadMountpoint is called when a mount point is deleted or invalidated
|
||||
// to umount all mounts using it in all other mount namespaces.
|
||||
// to umount all mounts using it in all other mount namespaces. If skipDecRef
|
||||
// is true, the method returns a list of reference counted objects with an
|
||||
// an extra reference.
|
||||
//
|
||||
// forgetDeadMountpoint is analogous to Linux's
|
||||
// fs/namespace.c:__detach_mounts().
|
||||
func (vfs *VirtualFilesystem) forgetDeadMountpoint(ctx context.Context, d *Dentry, deferVdDecRef bool) []VirtualDentry {
|
||||
func (vfs *VirtualFilesystem) forgetDeadMountpoint(ctx context.Context, d *Dentry, skipDecRef bool) []refs.RefCounter {
|
||||
var (
|
||||
vdsToDecRef []VirtualDentry
|
||||
mountsToDecRef []*Mount
|
||||
@@ -342,14 +345,18 @@ func (vfs *VirtualFilesystem) forgetDeadMountpoint(ctx context.Context, d *Dentr
|
||||
}
|
||||
vfs.mounts.seq.EndWrite()
|
||||
vfs.mountMu.Unlock()
|
||||
rcs := make([]refs.RefCounter, 0, len(vdsToDecRef)+len(mountsToDecRef))
|
||||
for _, vd := range vdsToDecRef {
|
||||
rcs = append(rcs, vd)
|
||||
}
|
||||
for _, mnt := range mountsToDecRef {
|
||||
mnt.DecRef(ctx)
|
||||
rcs = append(rcs, mnt)
|
||||
}
|
||||
if !deferVdDecRef {
|
||||
for _, vd := range vdsToDecRef {
|
||||
vd.DecRef(ctx)
|
||||
}
|
||||
return nil
|
||||
if skipDecRef {
|
||||
return rcs
|
||||
}
|
||||
return vdsToDecRef
|
||||
for _, rc := range rcs {
|
||||
rc.DecRef(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user