From efacb45c502ac57a8dd3809e16452222a74419d6 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 22 Sep 2025 10:50:12 -0700 Subject: [PATCH] fsgofer: update lastUnlockedDentry only after unlocking the dentry Update lastUnlockedDentry only after the mutex has been unlocked. If doRevalidationLisafs panics, deferred functions are executed. Updating lastUnlockedDentry earlier could lead to a deferred function attempting to acquire an already locked mutex, resulting in a deadlock. PiperOrigin-RevId: 810075556 --- pkg/sentry/fsimpl/gofer/lisafs_inode.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/sentry/fsimpl/gofer/lisafs_inode.go b/pkg/sentry/fsimpl/gofer/lisafs_inode.go index e2c5a68c20..51bc8831ef 100644 --- a/pkg/sentry/fsimpl/gofer/lisafs_inode.go +++ b/pkg/sentry/fsimpl/gofer/lisafs_inode.go @@ -704,13 +704,11 @@ func doRevalidationLisafs(ctx context.Context, vfsObj *vfs.VirtualFilesystem, st for i := 0; i < len(state.dentries); i++ { d := state.dentries[i] found := i < len(stats) - // Advance lastUnlockedDentry. It is the responsibility of this for loop - // block to unlock i.metadataMu. - lastUnlockedDentry = i // Note that synthetic dentries will always fail this comparison check. if !found || d.inode.inoKey != inoKeyFromStatx(&stats[i]) { d.inode.metadataMu.Unlock() + lastUnlockedDentry = i if !found && d.inode.isSynthetic() { // We have a synthetic file, and no remote file has arisen to replace // it. @@ -732,6 +730,7 @@ func doRevalidationLisafs(ctx context.Context, vfsObj *vfs.VirtualFilesystem, st // The file at this path hasn't changed. Just update cached metadata. d.inode.impl.(*lisafsInode).updateMetadataFromStatxLocked(&stats[i]) // +checklocksforce: see above. d.inode.metadataMu.Unlock() + lastUnlockedDentry = i } return nil }