mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
overlay: remove dirInoCache entries from RmdirAt()
Right now, entries are never removed from dirInoCache and if someone creates and deletes directories in a loop, they observe memory leaks. PiperOrigin-RevId: 698195540
This commit is contained in:
@@ -330,7 +330,12 @@ func (fs *filesystem) lookupLocked(ctx context.Context, parent *dentry, name str
|
||||
// directories. Override them if necessary. We can use RacyLoad() because
|
||||
// child is still being initialized.
|
||||
if child.isDir() {
|
||||
child.ino.Store(fs.newDirIno(child.devMajor.RacyLoad(), child.devMinor.RacyLoad(), child.ino.RacyLoad()))
|
||||
orig := layerDevNoAndIno{
|
||||
layerDevNumber: layerDevNumber{child.devMajor.RacyLoad(), child.devMinor.RacyLoad()},
|
||||
ino: child.ino.RacyLoad(),
|
||||
}
|
||||
child.ino.Store(fs.newDirIno(orig))
|
||||
child.dirInoHash = orig
|
||||
child.devMajor = atomicbitops.FromUint32(linux.UNNAMED_MAJOR)
|
||||
child.devMinor = atomicbitops.FromUint32(fs.dirDevMinor)
|
||||
} else if !child.upperVD.Ok() {
|
||||
@@ -1486,6 +1491,7 @@ func (fs *filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
||||
|
||||
toDecRef = vfsObj.CommitDeleteDentry(ctx, &child.vfsd)
|
||||
delete(parent.children, name)
|
||||
fs.releaseDirIno(child.dirInoHash)
|
||||
ds = appendDentry(ds, child)
|
||||
parent.dirents = nil
|
||||
parent.watches.Notify(ctx, name, linux.IN_DELETE|linux.IN_ISDIR, 0 /* cookie */, vfs.InodeEvent, true /* unlinked */)
|
||||
|
||||
@@ -365,7 +365,12 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
root.devMinor = atomicbitops.FromUint32(fs.dirDevMinor)
|
||||
// For root dir, it is okay to use top most level's stat to compute inode
|
||||
// number because we don't allow copy ups on root dentries.
|
||||
root.ino.Store(fs.newDirIno(rootStat.DevMajor, rootStat.DevMinor, rootStat.Ino))
|
||||
orig := layerDevNoAndIno{
|
||||
layerDevNumber: layerDevNumber{rootStat.DevMajor, rootStat.DevMinor},
|
||||
ino: rootStat.Ino,
|
||||
}
|
||||
root.ino.Store(fs.newDirIno(orig))
|
||||
root.dirInoHash = orig
|
||||
} else if !root.upperVD.Ok() {
|
||||
root.devMajor = atomicbitops.FromUint32(linux.UNNAMED_MAJOR)
|
||||
rootDevMinor, err := fs.getLowerDevMinor(rootStat.DevMajor, rootStat.DevMinor)
|
||||
@@ -456,13 +461,9 @@ func (fs *filesystem) statFS(ctx context.Context) (linux.Statfs, error) {
|
||||
return fsstat, nil
|
||||
}
|
||||
|
||||
func (fs *filesystem) newDirIno(layerMajor, layerMinor uint32, layerIno uint64) uint64 {
|
||||
func (fs *filesystem) newDirIno(orig layerDevNoAndIno) uint64 {
|
||||
fs.dirInoCacheMu.Lock()
|
||||
defer fs.dirInoCacheMu.Unlock()
|
||||
orig := layerDevNoAndIno{
|
||||
layerDevNumber: layerDevNumber{layerMajor, layerMinor},
|
||||
ino: layerIno,
|
||||
}
|
||||
if ino, ok := fs.dirInoCache[orig]; ok {
|
||||
return ino
|
||||
}
|
||||
@@ -472,6 +473,12 @@ func (fs *filesystem) newDirIno(layerMajor, layerMinor uint32, layerIno uint64)
|
||||
return newIno
|
||||
}
|
||||
|
||||
func (fs *filesystem) releaseDirIno(orig layerDevNoAndIno) {
|
||||
fs.dirInoCacheMu.Lock()
|
||||
defer fs.dirInoCacheMu.Unlock()
|
||||
delete(fs.dirInoCache, orig)
|
||||
}
|
||||
|
||||
func (fs *filesystem) getLowerDevMinor(layerMajor, layerMinor uint32) (uint32, error) {
|
||||
fs.devMu.Lock()
|
||||
defer fs.devMu.Unlock()
|
||||
@@ -587,6 +594,10 @@ type dentry struct {
|
||||
// watches, due to the fact that we do not have inode structures in this
|
||||
// overlay implementation.
|
||||
watches vfs.Watches
|
||||
|
||||
// dirInoHash is the entry hash in fs.dirInoCache. This is only set for
|
||||
// directories.
|
||||
dirInoHash layerDevNoAndIno
|
||||
}
|
||||
|
||||
// newDentry creates a new dentry. The dentry initially has no references; it
|
||||
|
||||
Reference in New Issue
Block a user