Fix memmap.MappingIdentity.Device/InodeID() lock ordering.

For vfs.FileDescriptions for which FileDescriptionOptions.UseDentryMetadata is
true, memmap.MappingIdentity.Device/InodeID() => FileDescription.Stat() =>
FilesystemImpl.StatAt() takes fsimpl locks for path traversal, which violates
the lock ordering and is unnecessary since no path is being traversed. Fix this
by carving out a special case where FilesystemImpl.Stat() (and
FileDescriptionImpl.Stat()) are required to meet the lock ordering requirements
of memmap.MappingIdentity.Device/InodeID(), and implement that special case by
skipping path traversal (and gofer revalidation) locks when not required.

PiperOrigin-RevId: 698608924
This commit is contained in:
Jamie Liu
2024-11-20 19:30:02 -08:00
committed by gVisor bot
parent 004ed53163
commit f66f0e235a
6 changed files with 41 additions and 11 deletions
+6
View File
@@ -1578,6 +1578,12 @@ func (fs *filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
// StatAt implements vfs.FilesystemImpl.StatAt.
func (fs *filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
if rp.Done() && opts.Sync == linux.AT_STATX_DONT_SYNC {
var stat linux.Statx
rp.Start().Impl().(*dentry).statTo(&stat)
return stat, nil
}
var ds *[]*dentry
fs.renameMu.RLock()
defer fs.renameMuRUnlockAndCheckCaching(ctx, &ds)
+4
View File
@@ -915,6 +915,10 @@ func (fs *Filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
// StatAt implements vfs.FilesystemImpl.StatAt.
func (fs *Filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
if rp.Done() && opts.Sync == linux.AT_STATX_DONT_SYNC {
return rp.Start().Impl().(*Dentry).inode.Stat(ctx, fs.VFSFilesystem(), opts)
}
fs.mu.RLock()
defer fs.processDeferredDecRefs(ctx)
defer fs.mu.RUnlock()
+13 -6
View File
@@ -1548,17 +1548,24 @@ func (d *dentry) setStatLocked(ctx context.Context, rp *vfs.ResolvingPath, opts
// StatAt implements vfs.FilesystemImpl.StatAt.
func (fs *filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
var ds *[]*dentry
fs.renameMu.RLock()
defer fs.renameMuRUnlockAndCheckDrop(ctx, &ds)
d, err := fs.resolveLocked(ctx, rp, &ds)
if err != nil {
return linux.Statx{}, err
var d *dentry
if rp.Done() {
d = rp.Start().Impl().(*dentry)
} else {
var ds *[]*dentry
fs.renameMu.RLock()
defer fs.renameMuRUnlockAndCheckDrop(ctx, &ds)
var err error
d, err = fs.resolveLocked(ctx, rp, &ds)
if err != nil {
return linux.Statx{}, err
}
}
var stat linux.Statx
if layerMask := opts.Mask &^ statInternalMask; layerMask != 0 {
layerVD := d.topLayer()
var err error
stat, err = fs.vfsfs.VirtualFilesystem().StatAt(ctx, fs.creds, &vfs.PathOperation{
Root: layerVD,
Start: layerVD,
+11 -5
View File
@@ -757,11 +757,17 @@ func (fs *filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
// StatAt implements vfs.FilesystemImpl.StatAt.
func (fs *filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
fs.mu.RLock()
defer fs.mu.RUnlock()
d, err := resolveLocked(ctx, rp)
if err != nil {
return linux.Statx{}, err
var d *dentry
if rp.Done() {
d = rp.Start().Impl().(*dentry)
} else {
fs.mu.RLock()
defer fs.mu.RUnlock()
var err error
d, err = resolveLocked(ctx, rp)
if err != nil {
return linux.Statx{}, err
}
}
var stat linux.Statx
d.inode.statTo(&stat)
+3
View File
@@ -334,6 +334,9 @@ type FileDescriptionImpl interface {
OnClose(ctx context.Context) error
// Stat returns metadata for the file represented by the FileDescription.
//
// If opts.Sync == linux.AT_STATX_SYNC_DONT_SYNC, Stat cannot take locks
// preceding memmap.MappingIdentity locks.
Stat(ctx context.Context, opts StatOptions) (linux.Statx, error)
// SetStat updates metadata for the file represented by the
+4
View File
@@ -365,6 +365,10 @@ type FilesystemImpl interface {
SetStatAt(ctx context.Context, rp *ResolvingPath, opts SetStatOptions) error
// StatAt returns metadata for the file at rp.
//
// If rp.Done() (i.e. rp refers to the dentry rp.Start()) and opts.Sync ==
// linux.AT_STATX_DONT_SYNC, StatAt cannot take locks preceding
// memmap.MappingIdentity locks.
StatAt(ctx context.Context, rp *ResolvingPath, opts StatOptions) (linux.Statx, error)
// StatFSAt returns metadata for the filesystem containing the file at rp.