mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Filter dentries with non-zero refs in VFS2 gofer/overlay checks.
PiperOrigin-RevId: 342161204
This commit is contained in:
@@ -114,6 +114,51 @@ func putDentrySlice(ds *[]*dentry) {
|
||||
dentrySlicePool.Put(ds)
|
||||
}
|
||||
|
||||
// renameMuRUnlockAndCheckCaching calls fs.renameMu.RUnlock(), then calls
|
||||
// dentry.checkCachingLocked on all dentries in *dsp with fs.renameMu locked
|
||||
// for writing.
|
||||
//
|
||||
// dsp is a pointer-to-pointer since defer evaluates its arguments immediately,
|
||||
// but dentry slices are allocated lazily, and it's much easier to say "defer
|
||||
// fs.renameMuRUnlockAndCheckCaching(&ds)" than "defer func() {
|
||||
// fs.renameMuRUnlockAndCheckCaching(ds) }()" to work around this.
|
||||
func (fs *filesystem) renameMuRUnlockAndCheckCaching(ctx context.Context, dsp **[]*dentry) {
|
||||
fs.renameMu.RUnlock()
|
||||
if *dsp == nil {
|
||||
return
|
||||
}
|
||||
ds := **dsp
|
||||
// Only go through calling dentry.checkCachingLocked() (which requires
|
||||
// re-locking renameMu) if we actually have any dentries with zero refs.
|
||||
checkAny := false
|
||||
for i := range ds {
|
||||
if atomic.LoadInt64(&ds[i].refs) == 0 {
|
||||
checkAny = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if checkAny {
|
||||
fs.renameMu.Lock()
|
||||
for _, d := range ds {
|
||||
d.checkCachingLocked(ctx)
|
||||
}
|
||||
fs.renameMu.Unlock()
|
||||
}
|
||||
putDentrySlice(*dsp)
|
||||
}
|
||||
|
||||
func (fs *filesystem) renameMuUnlockAndCheckCaching(ctx context.Context, ds **[]*dentry) {
|
||||
if *ds == nil {
|
||||
fs.renameMu.Unlock()
|
||||
return
|
||||
}
|
||||
for _, d := range **ds {
|
||||
d.checkCachingLocked(ctx)
|
||||
}
|
||||
fs.renameMu.Unlock()
|
||||
putDentrySlice(*ds)
|
||||
}
|
||||
|
||||
// stepLocked resolves rp.Component() to an existing file, starting from the
|
||||
// given directory.
|
||||
//
|
||||
@@ -651,41 +696,6 @@ func (fs *filesystem) unlinkAt(ctx context.Context, rp *vfs.ResolvingPath, dir b
|
||||
return nil
|
||||
}
|
||||
|
||||
// renameMuRUnlockAndCheckCaching calls fs.renameMu.RUnlock(), then calls
|
||||
// dentry.checkCachingLocked on all dentries in *ds with fs.renameMu locked for
|
||||
// writing.
|
||||
//
|
||||
// ds is a pointer-to-pointer since defer evaluates its arguments immediately,
|
||||
// but dentry slices are allocated lazily, and it's much easier to say "defer
|
||||
// fs.renameMuRUnlockAndCheckCaching(&ds)" than "defer func() {
|
||||
// fs.renameMuRUnlockAndCheckCaching(ds) }()" to work around this.
|
||||
func (fs *filesystem) renameMuRUnlockAndCheckCaching(ctx context.Context, ds **[]*dentry) {
|
||||
fs.renameMu.RUnlock()
|
||||
if *ds == nil {
|
||||
return
|
||||
}
|
||||
if len(**ds) != 0 {
|
||||
fs.renameMu.Lock()
|
||||
for _, d := range **ds {
|
||||
d.checkCachingLocked(ctx)
|
||||
}
|
||||
fs.renameMu.Unlock()
|
||||
}
|
||||
putDentrySlice(*ds)
|
||||
}
|
||||
|
||||
func (fs *filesystem) renameMuUnlockAndCheckCaching(ctx context.Context, ds **[]*dentry) {
|
||||
if *ds == nil {
|
||||
fs.renameMu.Unlock()
|
||||
return
|
||||
}
|
||||
for _, d := range **ds {
|
||||
d.checkCachingLocked(ctx)
|
||||
}
|
||||
fs.renameMu.Unlock()
|
||||
putDentrySlice(*ds)
|
||||
}
|
||||
|
||||
// AccessAt implements vfs.Filesystem.Impl.AccessAt.
|
||||
func (fs *filesystem) AccessAt(ctx context.Context, rp *vfs.ResolvingPath, creds *auth.Credentials, ats vfs.AccessTypes) error {
|
||||
var ds *[]*dentry
|
||||
|
||||
@@ -1352,6 +1352,11 @@ func (d *dentry) checkCachingLocked(ctx context.Context) {
|
||||
}
|
||||
if refs > 0 {
|
||||
if d.cached {
|
||||
// This isn't strictly necessary (fs.cachedDentries is permitted to
|
||||
// contain dentries with non-zero refs, which are skipped by
|
||||
// fs.evictCachedDentryLocked() upon reaching the end of the LRU),
|
||||
// but since we are already holding fs.renameMu for writing we may
|
||||
// as well.
|
||||
d.fs.cachedDentries.Remove(d)
|
||||
d.fs.cachedDentriesLen--
|
||||
d.cached = false
|
||||
|
||||
@@ -78,26 +78,36 @@ func putDentrySlice(ds *[]*dentry) {
|
||||
}
|
||||
|
||||
// renameMuRUnlockAndCheckDrop calls fs.renameMu.RUnlock(), then calls
|
||||
// dentry.checkDropLocked on all dentries in *ds with fs.renameMu locked for
|
||||
// dentry.checkDropLocked on all dentries in *dsp with fs.renameMu locked for
|
||||
// writing.
|
||||
//
|
||||
// ds is a pointer-to-pointer since defer evaluates its arguments immediately,
|
||||
// dsp is a pointer-to-pointer since defer evaluates its arguments immediately,
|
||||
// but dentry slices are allocated lazily, and it's much easier to say "defer
|
||||
// fs.renameMuRUnlockAndCheckDrop(&ds)" than "defer func() {
|
||||
// fs.renameMuRUnlockAndCheckDrop(ds) }()" to work around this.
|
||||
func (fs *filesystem) renameMuRUnlockAndCheckDrop(ctx context.Context, ds **[]*dentry) {
|
||||
func (fs *filesystem) renameMuRUnlockAndCheckDrop(ctx context.Context, dsp **[]*dentry) {
|
||||
fs.renameMu.RUnlock()
|
||||
if *ds == nil {
|
||||
if *dsp == nil {
|
||||
return
|
||||
}
|
||||
if len(**ds) != 0 {
|
||||
ds := **dsp
|
||||
// Only go through calling dentry.checkDropLocked() (which requires
|
||||
// re-locking renameMu) if we actually have any dentries with zero refs.
|
||||
checkAny := false
|
||||
for i := range ds {
|
||||
if atomic.LoadInt64(&ds[i].refs) == 0 {
|
||||
checkAny = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if checkAny {
|
||||
fs.renameMu.Lock()
|
||||
for _, d := range **ds {
|
||||
for _, d := range ds {
|
||||
d.checkDropLocked(ctx)
|
||||
}
|
||||
fs.renameMu.Unlock()
|
||||
}
|
||||
putDentrySlice(*ds)
|
||||
putDentrySlice(*dsp)
|
||||
}
|
||||
|
||||
func (fs *filesystem) renameMuUnlockAndCheckDrop(ctx context.Context, ds **[]*dentry) {
|
||||
|
||||
Reference in New Issue
Block a user