diff --git a/pkg/sentry/fsimpl/overlay/filesystem.go b/pkg/sentry/fsimpl/overlay/filesystem.go index 21407e95b..e760610e0 100644 --- a/pkg/sentry/fsimpl/overlay/filesystem.go +++ b/pkg/sentry/fsimpl/overlay/filesystem.go @@ -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 */) diff --git a/pkg/sentry/fsimpl/overlay/overlay.go b/pkg/sentry/fsimpl/overlay/overlay.go index d14a9c4f8..9f1fb66c6 100644 --- a/pkg/sentry/fsimpl/overlay/overlay.go +++ b/pkg/sentry/fsimpl/overlay/overlay.go @@ -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