diff options
Diffstat (limited to 'pkg/sentry/fs/file_overlay.go')
-rw-r--r-- | pkg/sentry/fs/file_overlay.go | 85 |
1 files changed, 47 insertions, 38 deletions
diff --git a/pkg/sentry/fs/file_overlay.go b/pkg/sentry/fs/file_overlay.go index 5fb5fbe97..29e5618f4 100644 --- a/pkg/sentry/fs/file_overlay.go +++ b/pkg/sentry/fs/file_overlay.go @@ -85,12 +85,6 @@ type overlayFileOperations struct { // protected by File.mu of the owning file, which is held during // Readdir and Seek calls. dirCursor string - - // dirCacheMu protects dirCache. - dirCacheMu sync.RWMutex `state:"nosave"` - - // dirCache is cache of DentAttrs from upper and lower Inodes. - dirCache *SortedDentryMap } // Release implements FileOperations.Release. @@ -171,53 +165,68 @@ func (f *overlayFileOperations) Readdir(ctx context.Context, file *File, seriali if root != nil { defer root.DecRef() } + dirCtx := &DirCtx{ Serializer: serializer, DirCursor: &f.dirCursor, } + return DirentReaddir(ctx, file.Dirent, f, root, dirCtx, file.Offset()) +} - // If the directory dirent is frozen, then DirentReaddir will calculate - // the children based off the frozen dirent tree. There is no need to - // call readdir on the upper/lower layers. - if file.Dirent.frozen { - return DirentReaddir(ctx, file.Dirent, f, root, dirCtx, file.Offset()) +// IterateDir implements DirIterator.IterateDir. +func (f *overlayFileOperations) IterateDir(ctx context.Context, d *Dirent, dirCtx *DirCtx, offset int) (int, error) { + o := d.Inode.overlay + + if !d.Inode.MountSource.CacheReaddir() { + // Can't use the dirCache. Simply read the entries. + entries, err := readdirEntries(ctx, o) + if err != nil { + return offset, err + } + n, err := GenericReaddir(dirCtx, entries) + return offset + n, err } - // Otherwise proceed with usual overlay readdir. - o := file.Dirent.Inode.overlay + // Otherwise, use or create cached entries. + + o.dirCacheMu.RLock() + if o.dirCache != nil { + n, err := GenericReaddir(dirCtx, o.dirCache) + o.dirCacheMu.RUnlock() + return offset + n, err + } + o.dirCacheMu.RUnlock() // readdirEntries holds o.copyUpMu to ensure that copy-up does not - // occur while calculating the readir results. + // occur while calculating the readdir results. // // However, it is possible for a copy-up to occur after the call to - // readdirEntries, but before setting f.dirCache. This is OK, since - // copy-up only does not change the children in a way that would affect - // the children returned in dirCache. Copy-up only moves - // files/directories between layers in the overlay. + // readdirEntries, but before setting o.dirCache. This is OK, since + // copy-up does not change the children in a way that would affect the + // children returned in dirCache. Copy-up only moves files/directories + // between layers in the overlay. // - // It is also possible for Readdir to race with a Create operation - // (which may trigger a copy-up during it's execution). Depending on - // whether the Create happens before or after the readdirEntries call, - // the newly created file may or may not appear in the readdir results. - // But this can only be caused by a real race between readdir and - // create syscalls, so it's also OK. - dirCache, err := readdirEntries(ctx, o) - if err != nil { - return file.Offset(), err + // We must hold dirCacheMu around both readdirEntries and setting + // o.dirCache to synchronize with dirCache invalidations done by + // Create, Remove, Rename. + o.dirCacheMu.Lock() + + // We expect dirCache to be nil (we just checked above), but there is a + // chance that a racing call managed to just set it, in which case we + // can use that new value. + if o.dirCache == nil { + dirCache, err := readdirEntries(ctx, o) + if err != nil { + o.dirCacheMu.Unlock() + return offset, err + } + o.dirCache = dirCache } - f.dirCacheMu.Lock() - f.dirCache = dirCache - f.dirCacheMu.Unlock() + o.dirCacheMu.DowngradeLock() + n, err := GenericReaddir(dirCtx, o.dirCache) + o.dirCacheMu.RUnlock() - return DirentReaddir(ctx, file.Dirent, f, root, dirCtx, file.Offset()) -} - -// IterateDir implements DirIterator.IterateDir. -func (f *overlayFileOperations) IterateDir(ctx context.Context, dirCtx *DirCtx, offset int) (int, error) { - f.dirCacheMu.RLock() - n, err := GenericReaddir(dirCtx, f.dirCache) - f.dirCacheMu.RUnlock() return offset + n, err } |