From 8c975e6e6e68fefde64f68bdbebc41aafb0f9fcb Mon Sep 17 00:00:00 2001 From: Nicolas Lacasse Date: Thu, 8 Jun 2023 10:22:10 -0700 Subject: [PATCH] Mark some kernfs inode as Anonymous. These inodes can never be part of a filesystem tree. They are nameless and never have a parent. This allows us to avoid taking a lock in kernfs.InotifyWithParent for such anonymous inodes. PiperOrigin-RevId: 538823227 --- pkg/sentry/fsimpl/cgroupfs/cgroupfs.go | 5 +++-- pkg/sentry/fsimpl/devpts/devpts.go | 1 + pkg/sentry/fsimpl/devpts/master.go | 1 + pkg/sentry/fsimpl/devpts/replica.go | 1 + pkg/sentry/fsimpl/fuse/inode.go | 1 + pkg/sentry/fsimpl/host/host.go | 3 ++- .../fsimpl/kernfs/dynamic_bytes_file.go | 1 + pkg/sentry/fsimpl/kernfs/inode_impl_util.go | 21 +++++++++++++++++++ pkg/sentry/fsimpl/kernfs/kernfs.go | 20 +++++++++++++----- pkg/sentry/fsimpl/kernfs/kernfs_test.go | 4 +++- pkg/sentry/fsimpl/kernfs/symlink.go | 1 + .../fsimpl/kernfs/synthetic_directory.go | 1 + pkg/sentry/fsimpl/mqfs/root.go | 1 + pkg/sentry/fsimpl/pipefs/pipefs.go | 1 + pkg/sentry/fsimpl/proc/subtasks.go | 1 + pkg/sentry/fsimpl/proc/task.go | 1 + pkg/sentry/fsimpl/proc/task_fds.go | 3 +++ pkg/sentry/fsimpl/proc/task_files.go | 6 ++++++ pkg/sentry/fsimpl/proc/tasks.go | 1 + pkg/sentry/fsimpl/proc/tasks_files.go | 2 ++ pkg/sentry/fsimpl/sockfs/sockfs.go | 1 + pkg/sentry/fsimpl/sys/kcov.go | 1 + pkg/sentry/fsimpl/sys/sys.go | 3 ++- 23 files changed, 71 insertions(+), 10 deletions(-) diff --git a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go index 6529225de..504f5cadf 100644 --- a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go +++ b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go @@ -496,11 +496,12 @@ func (*implStatFS) StatFS(context.Context, *vfs.Filesystem) (linux.Statfs, error // // +stateify savable type dir struct { - kernfs.InodeNoopRefCount kernfs.InodeAlwaysValid kernfs.InodeAttrs - kernfs.InodeNotSymlink kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous + kernfs.InodeNotSymlink kernfs.InodeWatches kernfs.OrderedChildren implStatFS diff --git a/pkg/sentry/fsimpl/devpts/devpts.go b/pkg/sentry/fsimpl/devpts/devpts.go index 7a580de50..f1f6c6781 100644 --- a/pkg/sentry/fsimpl/devpts/devpts.go +++ b/pkg/sentry/fsimpl/devpts/devpts.go @@ -150,6 +150,7 @@ type rootInode struct { kernfs.InodeAlwaysValid kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary // This holds no meaning as this inode can't be Looked up and is always valid. kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/devpts/master.go b/pkg/sentry/fsimpl/devpts/master.go index 3153229b4..62b651706 100644 --- a/pkg/sentry/fsimpl/devpts/master.go +++ b/pkg/sentry/fsimpl/devpts/master.go @@ -36,6 +36,7 @@ type masterInode struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/devpts/replica.go b/pkg/sentry/fsimpl/devpts/replica.go index 6f9c29c6b..68614690f 100644 --- a/pkg/sentry/fsimpl/devpts/replica.go +++ b/pkg/sentry/fsimpl/devpts/replica.go @@ -35,6 +35,7 @@ type replicaInode struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/fuse/inode.go b/pkg/sentry/fsimpl/fuse/inode.go index ab8fdfc8d..740a568f7 100644 --- a/pkg/sentry/fsimpl/fuse/inode.go +++ b/pkg/sentry/fsimpl/fuse/inode.go @@ -45,6 +45,7 @@ type fileHandle struct { type inode struct { inodeRefs kernfs.InodeAlwaysValid + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeWatches kernfs.OrderedChildren diff --git a/pkg/sentry/fsimpl/host/host.go b/pkg/sentry/fsimpl/host/host.go index c7aea8303..894e199dc 100644 --- a/pkg/sentry/fsimpl/host/host.go +++ b/pkg/sentry/fsimpl/host/host.go @@ -94,10 +94,11 @@ func isEpollable(fd int) bool { // // +stateify savable type inode struct { + kernfs.CachedMappable kernfs.InodeNoStatFS + kernfs.InodeAnonymous // inode is effectively anonymous because it represents a donated FD. kernfs.InodeNotDirectory kernfs.InodeNotSymlink - kernfs.CachedMappable kernfs.InodeTemporary // This holds no meaning as this inode can't be Looked up and is always valid. kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go b/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go index 8fece48c4..52ed496d7 100644 --- a/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go +++ b/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go @@ -38,6 +38,7 @@ type DynamicBytesFile struct { InodeAttrs InodeNoStatFS InodeNoopRefCount + InodeNotAnonymous InodeNotDirectory InodeNotSymlink InodeWatches diff --git a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go index 6caa7fc67..db54a5057 100644 --- a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go +++ b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go @@ -724,6 +724,7 @@ type StaticDirectory struct { InodeAttrs InodeDirectoryNoNewChildren InodeNoStatFS + InodeNotAnonymous InodeNotSymlink InodeTemporary InodeWatches @@ -819,3 +820,23 @@ type InodeWatches struct { func (i *InodeWatches) Watches() *vfs.Watches { return &i.watches } + +// InodeAnonymous partially implements Inode. +// +// +stateify savable +type InodeAnonymous struct{} + +// Anonymous implements Inode.Anonymous +func (*InodeAnonymous) Anonymous() bool { + return true +} + +// InodeNotAnonymous partially implements Inode. +// +// +stateify savable +type InodeNotAnonymous struct{} + +// Anonymous implements Inode.Anonymous +func (*InodeNotAnonymous) Anonymous() bool { + return false +} diff --git a/pkg/sentry/fsimpl/kernfs/kernfs.go b/pkg/sentry/fsimpl/kernfs/kernfs.go index f7345be9d..1f0f82104 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs.go @@ -514,12 +514,18 @@ func (d *Dentry) InotifyWithParent(ctx context.Context, events, cookie uint32, e events |= linux.IN_ISDIR } - d.fs.mu.RLock() - defer d.fs.mu.RUnlock() - // The ordering below is important, Linux always notifies the parent first. - if d.parent != nil { - d.parent.inode.Watches().Notify(ctx, d.name, events, cookie, et, d.isDeleted()) + // Linux always notifies the parent first. + + // Don't bother looking for a parent if the inode is anonymous. It + // won't have one. + if !d.inode.Anonymous() { + d.fs.mu.RLock() + if d.parent != nil { + d.parent.inode.Watches().Notify(ctx, d.name, events, cookie, et, d.isDeleted()) + } + d.fs.mu.RUnlock() } + d.inode.Watches().Notify(ctx, "", events, cookie, et, d.isDeleted()) } @@ -704,6 +710,10 @@ type Inode interface { // Watches returns the set of inotify watches associated with this inode. Watches() *vfs.Watches + + // Anonymous indicates that the Inode is anonymous. It will never have + // a name or parent. + Anonymous() bool } type inodeRefs interface { diff --git a/pkg/sentry/fsimpl/kernfs/kernfs_test.go b/pkg/sentry/fsimpl/kernfs/kernfs_test.go index bcc6ec94a..1ece17057 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs_test.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs_test.go @@ -104,6 +104,7 @@ type readonlyDir struct { kernfs.InodeAlwaysValid kernfs.InodeDirectoryNoNewChildren kernfs.InodeNoStatFS + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches @@ -139,8 +140,9 @@ type dir struct { dirRefs attrs kernfs.InodeAlwaysValid - kernfs.InodeNotSymlink kernfs.InodeNoStatFS + kernfs.InodeNotAnonymous + kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren diff --git a/pkg/sentry/fsimpl/kernfs/symlink.go b/pkg/sentry/fsimpl/kernfs/symlink.go index a127804bf..0c9a7b3a6 100644 --- a/pkg/sentry/fsimpl/kernfs/symlink.go +++ b/pkg/sentry/fsimpl/kernfs/symlink.go @@ -29,6 +29,7 @@ import ( type StaticSymlink struct { InodeAttrs InodeNoopRefCount + InodeNotAnonymous InodeSymlink InodeNoStatFS InodeWatches diff --git a/pkg/sentry/fsimpl/kernfs/synthetic_directory.go b/pkg/sentry/fsimpl/kernfs/synthetic_directory.go index ed587bf47..4b28181d5 100644 --- a/pkg/sentry/fsimpl/kernfs/synthetic_directory.go +++ b/pkg/sentry/fsimpl/kernfs/synthetic_directory.go @@ -32,6 +32,7 @@ type syntheticDirectory struct { InodeAlwaysValid InodeAttrs InodeNoStatFS + InodeNotAnonymous InodeNotSymlink InodeWatches OrderedChildren diff --git a/pkg/sentry/fsimpl/mqfs/root.go b/pkg/sentry/fsimpl/mqfs/root.go index 4a3e950ba..7c26e2219 100644 --- a/pkg/sentry/fsimpl/mqfs/root.go +++ b/pkg/sentry/fsimpl/mqfs/root.go @@ -29,6 +29,7 @@ import ( type rootInode struct { rootInodeRefs kernfs.InodeAlwaysValid + kernfs.InodeAnonymous kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren kernfs.InodeNotSymlink diff --git a/pkg/sentry/fsimpl/pipefs/pipefs.go b/pkg/sentry/fsimpl/pipefs/pipefs.go index f5ebb7e77..6e26ad2b2 100644 --- a/pkg/sentry/fsimpl/pipefs/pipefs.go +++ b/pkg/sentry/fsimpl/pipefs/pipefs.go @@ -89,6 +89,7 @@ func (fs *filesystem) MountOptions() string { // // +stateify savable type inode struct { + kernfs.InodeAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeNoopRefCount diff --git a/pkg/sentry/fsimpl/proc/subtasks.go b/pkg/sentry/fsimpl/proc/subtasks.go index 5dec43bac..60e4dcb07 100644 --- a/pkg/sentry/fsimpl/proc/subtasks.go +++ b/pkg/sentry/fsimpl/proc/subtasks.go @@ -35,6 +35,7 @@ type subtasksInode struct { kernfs.InodeAlwaysValid kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/proc/task.go b/pkg/sentry/fsimpl/proc/task.go index c90c10b40..89ce31d64 100644 --- a/pkg/sentry/fsimpl/proc/task.go +++ b/pkg/sentry/fsimpl/proc/task.go @@ -35,6 +35,7 @@ type taskInode struct { implStatFS kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/proc/task_fds.go b/pkg/sentry/fsimpl/proc/task_fds.go index 94ed13bec..117b063e5 100644 --- a/pkg/sentry/fsimpl/proc/task_fds.go +++ b/pkg/sentry/fsimpl/proc/task_fds.go @@ -113,6 +113,7 @@ type fdDirInode struct { kernfs.InodeAlwaysValid kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches @@ -198,6 +199,7 @@ type fdSymlink struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches @@ -257,6 +259,7 @@ type fdInfoDirInode struct { kernfs.InodeAlwaysValid kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/proc/task_files.go b/pkg/sentry/fsimpl/proc/task_files.go index d3792a1ee..da24fdc12 100644 --- a/pkg/sentry/fsimpl/proc/task_files.go +++ b/pkg/sentry/fsimpl/proc/task_files.go @@ -410,6 +410,7 @@ type memInode struct { kernfs.InodeAttrs kernfs.InodeNoStatFS kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches @@ -730,6 +731,7 @@ type statusInode struct { kernfs.InodeAttrs kernfs.InodeNoStatFS kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches @@ -963,6 +965,7 @@ type exeSymlink struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches @@ -1035,6 +1038,7 @@ type cwdSymlink struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches @@ -1096,6 +1100,7 @@ type rootSymlink struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches @@ -1269,6 +1274,7 @@ type namespaceInode struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/proc/tasks.go b/pkg/sentry/fsimpl/proc/tasks.go index 4d4126d1f..b9c743b5c 100644 --- a/pkg/sentry/fsimpl/proc/tasks.go +++ b/pkg/sentry/fsimpl/proc/tasks.go @@ -41,6 +41,7 @@ type tasksInode struct { kernfs.InodeAlwaysValid kernfs.InodeAttrs kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous kernfs.InodeNotSymlink kernfs.InodeTemporary // This holds no meaning as this inode can't be Looked up and is always valid. kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/proc/tasks_files.go b/pkg/sentry/fsimpl/proc/tasks_files.go index a28f46a7b..5a1222601 100644 --- a/pkg/sentry/fsimpl/proc/tasks_files.go +++ b/pkg/sentry/fsimpl/proc/tasks_files.go @@ -37,6 +37,7 @@ type selfSymlink struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches @@ -79,6 +80,7 @@ type threadSelfSymlink struct { implStatFS kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeSymlink kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/sockfs/sockfs.go b/pkg/sentry/fsimpl/sockfs/sockfs.go index 290d55b8d..455481447 100644 --- a/pkg/sentry/fsimpl/sockfs/sockfs.go +++ b/pkg/sentry/fsimpl/sockfs/sockfs.go @@ -94,6 +94,7 @@ func (fs *filesystem) MountOptions() string { // // +stateify savable type inode struct { + kernfs.InodeAnonymous kernfs.InodeAttrs kernfs.InodeNoopRefCount kernfs.InodeNotDirectory diff --git a/pkg/sentry/fsimpl/sys/kcov.go b/pkg/sentry/fsimpl/sys/kcov.go index 24846a0a5..f71313543 100644 --- a/pkg/sentry/fsimpl/sys/kcov.go +++ b/pkg/sentry/fsimpl/sys/kcov.go @@ -39,6 +39,7 @@ func (fs *filesystem) newKcovFile(ctx context.Context, creds *auth.Credentials) type kcovInode struct { kernfs.InodeAttrs kernfs.InodeNoopRefCount + kernfs.InodeNotAnonymous kernfs.InodeNotDirectory kernfs.InodeNotSymlink kernfs.InodeWatches diff --git a/pkg/sentry/fsimpl/sys/sys.go b/pkg/sentry/fsimpl/sys/sys.go index b0d4e27fe..6bebcf736 100644 --- a/pkg/sentry/fsimpl/sys/sys.go +++ b/pkg/sentry/fsimpl/sys/sys.go @@ -199,8 +199,9 @@ type dir struct { dirRefs kernfs.InodeAlwaysValid kernfs.InodeAttrs - kernfs.InodeNotSymlink kernfs.InodeDirectoryNoNewChildren + kernfs.InodeNotAnonymous + kernfs.InodeNotSymlink kernfs.InodeTemporary kernfs.InodeWatches kernfs.OrderedChildren