diff options
90 files changed, 5604 insertions, 71 deletions
diff --git a/pkg/sentry/devices/memdev/full.go b/pkg/sentry/devices/memdev/full.go index 511179e31..fece3e762 100644 --- a/pkg/sentry/devices/memdev/full.go +++ b/pkg/sentry/devices/memdev/full.go @@ -24,6 +24,8 @@ import ( const fullDevMinor = 7 // fullDevice implements vfs.Device for /dev/full. +// +// +stateify savable type fullDevice struct{} // Open implements vfs.Device.Open. @@ -38,6 +40,8 @@ func (fullDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, op } // fullFD implements vfs.FileDescriptionImpl for /dev/full. +// +// +stateify savable type fullFD struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/devices/memdev/memdev_state_autogen.go b/pkg/sentry/devices/memdev/memdev_state_autogen.go index 2676fbbe5..127ea03ee 100644 --- a/pkg/sentry/devices/memdev/memdev_state_autogen.go +++ b/pkg/sentry/devices/memdev/memdev_state_autogen.go @@ -1,3 +1,225 @@ // automatically generated by stateify. package memdev + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *fullDevice) StateTypeName() string { + return "pkg/sentry/devices/memdev.fullDevice" +} + +func (x *fullDevice) StateFields() []string { + return []string{} +} + +func (x *fullDevice) beforeSave() {} + +func (x *fullDevice) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *fullDevice) afterLoad() {} + +func (x *fullDevice) StateLoad(m state.Source) { +} + +func (x *fullFD) StateTypeName() string { + return "pkg/sentry/devices/memdev.fullFD" +} + +func (x *fullFD) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + } +} + +func (x *fullFD) beforeSave() {} + +func (x *fullFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) +} + +func (x *fullFD) afterLoad() {} + +func (x *fullFD) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) +} + +func (x *nullDevice) StateTypeName() string { + return "pkg/sentry/devices/memdev.nullDevice" +} + +func (x *nullDevice) StateFields() []string { + return []string{} +} + +func (x *nullDevice) beforeSave() {} + +func (x *nullDevice) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *nullDevice) afterLoad() {} + +func (x *nullDevice) StateLoad(m state.Source) { +} + +func (x *nullFD) StateTypeName() string { + return "pkg/sentry/devices/memdev.nullFD" +} + +func (x *nullFD) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + } +} + +func (x *nullFD) beforeSave() {} + +func (x *nullFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) +} + +func (x *nullFD) afterLoad() {} + +func (x *nullFD) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) +} + +func (x *randomDevice) StateTypeName() string { + return "pkg/sentry/devices/memdev.randomDevice" +} + +func (x *randomDevice) StateFields() []string { + return []string{} +} + +func (x *randomDevice) beforeSave() {} + +func (x *randomDevice) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *randomDevice) afterLoad() {} + +func (x *randomDevice) StateLoad(m state.Source) { +} + +func (x *randomFD) StateTypeName() string { + return "pkg/sentry/devices/memdev.randomFD" +} + +func (x *randomFD) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + "off", + } +} + +func (x *randomFD) beforeSave() {} + +func (x *randomFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) + m.Save(4, &x.off) +} + +func (x *randomFD) afterLoad() {} + +func (x *randomFD) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) + m.Load(4, &x.off) +} + +func (x *zeroDevice) StateTypeName() string { + return "pkg/sentry/devices/memdev.zeroDevice" +} + +func (x *zeroDevice) StateFields() []string { + return []string{} +} + +func (x *zeroDevice) beforeSave() {} + +func (x *zeroDevice) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *zeroDevice) afterLoad() {} + +func (x *zeroDevice) StateLoad(m state.Source) { +} + +func (x *zeroFD) StateTypeName() string { + return "pkg/sentry/devices/memdev.zeroFD" +} + +func (x *zeroFD) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + } +} + +func (x *zeroFD) beforeSave() {} + +func (x *zeroFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) +} + +func (x *zeroFD) afterLoad() {} + +func (x *zeroFD) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) +} + +func init() { + state.Register((*fullDevice)(nil)) + state.Register((*fullFD)(nil)) + state.Register((*nullDevice)(nil)) + state.Register((*nullFD)(nil)) + state.Register((*randomDevice)(nil)) + state.Register((*randomFD)(nil)) + state.Register((*zeroDevice)(nil)) + state.Register((*zeroFD)(nil)) +} diff --git a/pkg/sentry/devices/memdev/null.go b/pkg/sentry/devices/memdev/null.go index 4918dbeeb..ff5837747 100644 --- a/pkg/sentry/devices/memdev/null.go +++ b/pkg/sentry/devices/memdev/null.go @@ -25,6 +25,8 @@ import ( const nullDevMinor = 3 // nullDevice implements vfs.Device for /dev/null. +// +// +stateify savable type nullDevice struct{} // Open implements vfs.Device.Open. @@ -39,6 +41,8 @@ func (nullDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, op } // nullFD implements vfs.FileDescriptionImpl for /dev/null. +// +// +stateify savable type nullFD struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/devices/memdev/random.go b/pkg/sentry/devices/memdev/random.go index 5e7fe0280..ac943e3ba 100644 --- a/pkg/sentry/devices/memdev/random.go +++ b/pkg/sentry/devices/memdev/random.go @@ -30,6 +30,8 @@ const ( ) // randomDevice implements vfs.Device for /dev/random and /dev/urandom. +// +// +stateify savable type randomDevice struct{} // Open implements vfs.Device.Open. @@ -44,6 +46,8 @@ func (randomDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, } // randomFD implements vfs.FileDescriptionImpl for /dev/random. +// +// +stateify savable type randomFD struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/devices/memdev/zero.go b/pkg/sentry/devices/memdev/zero.go index 60cfea888..1929e41cd 100644 --- a/pkg/sentry/devices/memdev/zero.go +++ b/pkg/sentry/devices/memdev/zero.go @@ -27,6 +27,8 @@ import ( const zeroDevMinor = 5 // zeroDevice implements vfs.Device for /dev/zero. +// +// +stateify savable type zeroDevice struct{} // Open implements vfs.Device.Open. @@ -41,6 +43,8 @@ func (zeroDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, op } // zeroFD implements vfs.FileDescriptionImpl for /dev/zero. +// +// +stateify savable type zeroFD struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/devices/ttydev/ttydev.go b/pkg/sentry/devices/ttydev/ttydev.go index 664e54498..a287c65ca 100644 --- a/pkg/sentry/devices/ttydev/ttydev.go +++ b/pkg/sentry/devices/ttydev/ttydev.go @@ -30,6 +30,8 @@ const ( ) // ttyDevice implements vfs.Device for /dev/tty. +// +// +stateify savable type ttyDevice struct{} // Open implements vfs.Device.Open. diff --git a/pkg/sentry/devices/ttydev/ttydev_state_autogen.go b/pkg/sentry/devices/ttydev/ttydev_state_autogen.go index 29014107c..9883dcf08 100644 --- a/pkg/sentry/devices/ttydev/ttydev_state_autogen.go +++ b/pkg/sentry/devices/ttydev/ttydev_state_autogen.go @@ -1,3 +1,30 @@ // automatically generated by stateify. package ttydev + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *ttyDevice) StateTypeName() string { + return "pkg/sentry/devices/ttydev.ttyDevice" +} + +func (x *ttyDevice) StateFields() []string { + return []string{} +} + +func (x *ttyDevice) beforeSave() {} + +func (x *ttyDevice) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *ttyDevice) afterLoad() {} + +func (x *ttyDevice) StateLoad(m state.Source) { +} + +func init() { + state.Register((*ttyDevice)(nil)) +} diff --git a/pkg/sentry/fsimpl/devpts/devpts.go b/pkg/sentry/fsimpl/devpts/devpts.go index 77d1f493d..903135fae 100644 --- a/pkg/sentry/fsimpl/devpts/devpts.go +++ b/pkg/sentry/fsimpl/devpts/devpts.go @@ -35,6 +35,8 @@ import ( const Name = "devpts" // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct{} // Name implements vfs.FilesystemType.Name. @@ -58,6 +60,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt return fs.Filesystem.VFSFilesystem(), root.VFSDentry(), nil } +// +stateify savable type filesystem struct { kernfs.Filesystem @@ -110,6 +113,8 @@ func (fs *filesystem) Release(ctx context.Context) { } // rootInode is the root directory inode for the devpts mounts. +// +// +stateify savable type rootInode struct { implStatFS kernfs.AlwaysValid @@ -131,7 +136,7 @@ type rootInode struct { root *rootInode // mu protects the fields below. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // replicas maps pty ids to replica inodes. replicas map[uint32]*replicaInode @@ -242,6 +247,7 @@ func (i *rootInode) DecRef(context.Context) { i.rootInodeRefs.DecRef(i.Destroy) } +// +stateify savable type implStatFS struct{} // StatFS implements kernfs.Inode.StatFS. diff --git a/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go b/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go index 5e9f200c8..61e4f6fdf 100644 --- a/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go +++ b/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go @@ -6,6 +6,129 @@ import ( "gvisor.dev/gvisor/pkg/state" ) +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{} +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) +} + +func (x *rootInode) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.rootInode" +} + +func (x *rootInode) StateFields() []string { + return []string{ + "implStatFS", + "AlwaysValid", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNotSymlink", + "OrderedChildren", + "rootInodeRefs", + "locks", + "dentry", + "master", + "root", + "replicas", + "nextIdx", + } +} + +func (x *rootInode) beforeSave() {} + +func (x *rootInode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.AlwaysValid) + m.Save(2, &x.InodeAttrs) + m.Save(3, &x.InodeDirectoryNoNewChildren) + m.Save(4, &x.InodeNotSymlink) + m.Save(5, &x.OrderedChildren) + m.Save(6, &x.rootInodeRefs) + m.Save(7, &x.locks) + m.Save(8, &x.dentry) + m.Save(9, &x.master) + m.Save(10, &x.root) + m.Save(11, &x.replicas) + m.Save(12, &x.nextIdx) +} + +func (x *rootInode) afterLoad() {} + +func (x *rootInode) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.AlwaysValid) + m.Load(2, &x.InodeAttrs) + m.Load(3, &x.InodeDirectoryNoNewChildren) + m.Load(4, &x.InodeNotSymlink) + m.Load(5, &x.OrderedChildren) + m.Load(6, &x.rootInodeRefs) + m.Load(7, &x.locks) + m.Load(8, &x.dentry) + m.Load(9, &x.master) + m.Load(10, &x.root) + m.Load(11, &x.replicas) + m.Load(12, &x.nextIdx) +} + +func (x *implStatFS) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.implStatFS" +} + +func (x *implStatFS) StateFields() []string { + return []string{} +} + +func (x *implStatFS) beforeSave() {} + +func (x *implStatFS) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *implStatFS) afterLoad() {} + +func (x *implStatFS) StateLoad(m state.Source) { +} + func (x *lineDiscipline) StateTypeName() string { return "pkg/sentry/fsimpl/devpts.lineDiscipline" } @@ -85,6 +208,85 @@ func (x *inputQueueTransformer) afterLoad() {} func (x *inputQueueTransformer) StateLoad(m state.Source) { } +func (x *masterInode) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.masterInode" +} + +func (x *masterInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "locks", + "dentry", + "root", + } +} + +func (x *masterInode) beforeSave() {} + +func (x *masterInode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeNoopRefCount) + m.Save(3, &x.InodeNotDirectory) + m.Save(4, &x.InodeNotSymlink) + m.Save(5, &x.locks) + m.Save(6, &x.dentry) + m.Save(7, &x.root) +} + +func (x *masterInode) afterLoad() {} + +func (x *masterInode) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeNoopRefCount) + m.Load(3, &x.InodeNotDirectory) + m.Load(4, &x.InodeNotSymlink) + m.Load(5, &x.locks) + m.Load(6, &x.dentry) + m.Load(7, &x.root) +} + +func (x *masterFileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.masterFileDescription" +} + +func (x *masterFileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + "inode", + "t", + } +} + +func (x *masterFileDescription) beforeSave() {} + +func (x *masterFileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) + m.Save(3, &x.inode) + m.Save(4, &x.t) +} + +func (x *masterFileDescription) afterLoad() {} + +func (x *masterFileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) + m.Load(3, &x.inode) + m.Load(4, &x.t) +} + func (x *queue) StateTypeName() string { return "pkg/sentry/fsimpl/devpts.queue" } @@ -120,6 +322,85 @@ func (x *queue) StateLoad(m state.Source) { m.Load(4, &x.transformer) } +func (x *replicaInode) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.replicaInode" +} + +func (x *replicaInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "locks", + "dentry", + "root", + "t", + } +} + +func (x *replicaInode) beforeSave() {} + +func (x *replicaInode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeNoopRefCount) + m.Save(3, &x.InodeNotDirectory) + m.Save(4, &x.InodeNotSymlink) + m.Save(5, &x.locks) + m.Save(6, &x.dentry) + m.Save(7, &x.root) + m.Save(8, &x.t) +} + +func (x *replicaInode) afterLoad() {} + +func (x *replicaInode) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeNoopRefCount) + m.Load(3, &x.InodeNotDirectory) + m.Load(4, &x.InodeNotSymlink) + m.Load(5, &x.locks) + m.Load(6, &x.dentry) + m.Load(7, &x.root) + m.Load(8, &x.t) +} + +func (x *replicaFileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/devpts.replicaFileDescription" +} + +func (x *replicaFileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + "inode", + } +} + +func (x *replicaFileDescription) beforeSave() {} + +func (x *replicaFileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) + m.Save(3, &x.inode) +} + +func (x *replicaFileDescription) afterLoad() {} + +func (x *replicaFileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) + m.Load(3, &x.inode) +} + func (x *rootInodeRefs) StateTypeName() string { return "pkg/sentry/fsimpl/devpts.rootInodeRefs" } @@ -176,10 +457,18 @@ func (x *Terminal) StateLoad(m state.Source) { } func init() { + state.Register((*FilesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*rootInode)(nil)) + state.Register((*implStatFS)(nil)) state.Register((*lineDiscipline)(nil)) state.Register((*outputQueueTransformer)(nil)) state.Register((*inputQueueTransformer)(nil)) + state.Register((*masterInode)(nil)) + state.Register((*masterFileDescription)(nil)) state.Register((*queue)(nil)) + state.Register((*replicaInode)(nil)) + state.Register((*replicaFileDescription)(nil)) state.Register((*rootInodeRefs)(nil)) state.Register((*Terminal)(nil)) } diff --git a/pkg/sentry/fsimpl/devpts/master.go b/pkg/sentry/fsimpl/devpts/master.go index 98d4ffb22..bfcaf60bd 100644 --- a/pkg/sentry/fsimpl/devpts/master.go +++ b/pkg/sentry/fsimpl/devpts/master.go @@ -31,6 +31,8 @@ import ( ) // masterInode is the inode for the master end of the Terminal. +// +// +stateify savable type masterInode struct { implStatFS kernfs.InodeAttrs @@ -89,6 +91,7 @@ func (mi *masterInode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds return mi.InodeAttrs.SetStat(ctx, vfsfs, creds, opts) } +// +stateify savable type masterFileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/devpts/replica.go b/pkg/sentry/fsimpl/devpts/replica.go index 816bac80c..9638eb6c5 100644 --- a/pkg/sentry/fsimpl/devpts/replica.go +++ b/pkg/sentry/fsimpl/devpts/replica.go @@ -30,6 +30,8 @@ import ( ) // replicaInode is the inode for the replica end of the Terminal. +// +// +stateify savable type replicaInode struct { implStatFS kernfs.InodeAttrs @@ -95,6 +97,7 @@ func (si *replicaInode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, cred return si.InodeAttrs.SetStat(ctx, vfsfs, creds, opts) } +// +stateify savable type replicaFileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go index a23094e54..6d1753080 100644 --- a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go +++ b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go @@ -33,8 +33,10 @@ import ( const Name = "devtmpfs" // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct { - initOnce sync.Once + initOnce sync.Once `state:"nosave"` // FIXME(gvisor.dev/issue/1664): not yet supported. initErr error // fs is the tmpfs filesystem that backs all mounts of this FilesystemType. diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go index ac054eb77..1253bed4e 100644 --- a/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go +++ b/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go @@ -1,3 +1,40 @@ // automatically generated by stateify. package devtmpfs + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/devtmpfs.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{ + "initErr", + "fs", + "root", + } +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.initErr) + m.Save(1, &x.fs) + m.Save(2, &x.root) +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { + m.Load(0, &x.initErr) + m.Load(1, &x.fs) + m.Load(2, &x.root) +} + +func init() { + state.Register((*FilesystemType)(nil)) +} diff --git a/pkg/sentry/fsimpl/eventfd/eventfd.go b/pkg/sentry/fsimpl/eventfd/eventfd.go index bb0bf3a07..1c27ad700 100644 --- a/pkg/sentry/fsimpl/eventfd/eventfd.go +++ b/pkg/sentry/fsimpl/eventfd/eventfd.go @@ -33,6 +33,8 @@ import ( // EventFileDescription implements vfs.FileDescriptionImpl for file-based event // notification (eventfd). Eventfds are usually internal to the Sentry but in // certain situations they may be converted into a host-backed eventfd. +// +// +stateify savable type EventFileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go b/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go index e83f6aed8..0507be064 100644 --- a/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go +++ b/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go @@ -1,3 +1,55 @@ // automatically generated by stateify. package eventfd + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *EventFileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/eventfd.EventFileDescription" +} + +func (x *EventFileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + "val", + "semMode", + "hostfd", + } +} + +func (x *EventFileDescription) beforeSave() {} + +func (x *EventFileDescription) StateSave(m state.Sink) { + x.beforeSave() + if !state.IsZeroValue(&x.queue) { + state.Failf("queue is %#v, expected zero", &x.queue) + } + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) + m.Save(4, &x.val) + m.Save(5, &x.semMode) + m.Save(6, &x.hostfd) +} + +func (x *EventFileDescription) afterLoad() {} + +func (x *EventFileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) + m.Load(4, &x.val) + m.Load(5, &x.semMode) + m.Load(6, &x.hostfd) +} + +func init() { + state.Register((*EventFileDescription)(nil)) +} diff --git a/pkg/sentry/fsimpl/fuse/connection.go b/pkg/sentry/fsimpl/fuse/connection.go index dbc5e1954..8ccda1264 100644 --- a/pkg/sentry/fsimpl/fuse/connection.go +++ b/pkg/sentry/fsimpl/fuse/connection.go @@ -39,15 +39,18 @@ const ( ) // connection is the struct by which the sentry communicates with the FUSE server daemon. +// // Lock order: // - conn.fd.mu // - conn.mu // - conn.asyncMu +// +// +stateify savable type connection struct { fd *DeviceFD // mu protects access to struct memebers. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // attributeVersion is the version of connection's attributes. attributeVersion uint64 @@ -75,7 +78,7 @@ type connection struct { initialized int32 // initializedChan is used to block requests before initialization. - initializedChan chan struct{} + initializedChan chan struct{} `state:".(bool)"` // connected (connection established) when a new FUSE file system is created. // Set to false when: @@ -113,7 +116,7 @@ type connection struct { // i.e. `!request.noReply` // asyncMu protects the async request fields. - asyncMu sync.Mutex + asyncMu sync.Mutex `state:"nosave"` // asyncNum is the number of async requests. // Protected by asyncMu. @@ -174,6 +177,22 @@ type connection struct { noOpen bool } +func (conn *connection) saveInitializedChan() bool { + select { + case <-conn.initializedChan: + return true // Closed. + default: + return false // Not closed. + } +} + +func (conn *connection) loadInitializedChan(closed bool) { + conn.initializedChan = make(chan struct{}, 1) + if closed { + close(conn.initializedChan) + } +} + // newFUSEConnection creates a FUSE connection to fd. func newFUSEConnection(_ context.Context, fd *vfs.FileDescription, opts *filesystemOptions) (*connection, error) { // Mark the device as ready so it can be used. /dev/fuse can only be used if the FD was used to diff --git a/pkg/sentry/fsimpl/fuse/dev.go b/pkg/sentry/fsimpl/fuse/dev.go index f690ef5ad..1b86a4b4c 100644 --- a/pkg/sentry/fsimpl/fuse/dev.go +++ b/pkg/sentry/fsimpl/fuse/dev.go @@ -31,6 +31,8 @@ import ( const fuseDevMinor = 229 // fuseDevice implements vfs.Device for /dev/fuse. +// +// +stateify savable type fuseDevice struct{} // Open implements vfs.Device.Open. @@ -49,6 +51,8 @@ func (fuseDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, op } // DeviceFD implements vfs.FileDescriptionImpl for /dev/fuse. +// +// +stateify savable type DeviceFD struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl @@ -79,7 +83,7 @@ type DeviceFD struct { writeCursorFR *futureResponse // mu protects all the queues, maps, buffers and cursors and nextOpID. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // waitQueue is used to notify interested parties when the device becomes // readable or writable. @@ -88,12 +92,20 @@ type DeviceFD struct { // fullQueueCh is a channel used to synchronize the readers with the writers. // Writers (inbound requests to the filesystem) block if there are too many // unprocessed in-flight requests. - fullQueueCh chan struct{} + fullQueueCh chan struct{} `state:".(int)"` // fs is the FUSE filesystem that this FD is being used for. fs *filesystem } +func (fd *DeviceFD) saveFullQueueCh() int { + return cap(fd.fullQueueCh) +} + +func (fd *DeviceFD) loadFullQueueCh(capacity int) { + fd.fullQueueCh = make(chan struct{}, capacity) +} + // Release implements vfs.FileDescriptionImpl.Release. func (fd *DeviceFD) Release(ctx context.Context) { if fd.fs != nil { diff --git a/pkg/sentry/fsimpl/fuse/fuse_state_autogen.go b/pkg/sentry/fsimpl/fuse/fuse_state_autogen.go index 6c82dce30..b127b2015 100644 --- a/pkg/sentry/fsimpl/fuse/fuse_state_autogen.go +++ b/pkg/sentry/fsimpl/fuse/fuse_state_autogen.go @@ -6,6 +6,332 @@ import ( "gvisor.dev/gvisor/pkg/state" ) +func (x *connection) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.connection" +} + +func (x *connection) StateFields() []string { + return []string{ + "fd", + "attributeVersion", + "initialized", + "initializedChan", + "connected", + "connInitError", + "connInitSuccess", + "aborted", + "numWaiting", + "asyncNum", + "asyncCongestionThreshold", + "asyncNumMax", + "maxRead", + "maxWrite", + "maxPages", + "minor", + "atomicOTrunc", + "asyncRead", + "writebackCache", + "bigWrites", + "dontMask", + "noOpen", + } +} + +func (x *connection) beforeSave() {} + +func (x *connection) StateSave(m state.Sink) { + x.beforeSave() + var initializedChan bool = x.saveInitializedChan() + m.SaveValue(3, initializedChan) + m.Save(0, &x.fd) + m.Save(1, &x.attributeVersion) + m.Save(2, &x.initialized) + m.Save(4, &x.connected) + m.Save(5, &x.connInitError) + m.Save(6, &x.connInitSuccess) + m.Save(7, &x.aborted) + m.Save(8, &x.numWaiting) + m.Save(9, &x.asyncNum) + m.Save(10, &x.asyncCongestionThreshold) + m.Save(11, &x.asyncNumMax) + m.Save(12, &x.maxRead) + m.Save(13, &x.maxWrite) + m.Save(14, &x.maxPages) + m.Save(15, &x.minor) + m.Save(16, &x.atomicOTrunc) + m.Save(17, &x.asyncRead) + m.Save(18, &x.writebackCache) + m.Save(19, &x.bigWrites) + m.Save(20, &x.dontMask) + m.Save(21, &x.noOpen) +} + +func (x *connection) afterLoad() {} + +func (x *connection) StateLoad(m state.Source) { + m.Load(0, &x.fd) + m.Load(1, &x.attributeVersion) + m.Load(2, &x.initialized) + m.Load(4, &x.connected) + m.Load(5, &x.connInitError) + m.Load(6, &x.connInitSuccess) + m.Load(7, &x.aborted) + m.Load(8, &x.numWaiting) + m.Load(9, &x.asyncNum) + m.Load(10, &x.asyncCongestionThreshold) + m.Load(11, &x.asyncNumMax) + m.Load(12, &x.maxRead) + m.Load(13, &x.maxWrite) + m.Load(14, &x.maxPages) + m.Load(15, &x.minor) + m.Load(16, &x.atomicOTrunc) + m.Load(17, &x.asyncRead) + m.Load(18, &x.writebackCache) + m.Load(19, &x.bigWrites) + m.Load(20, &x.dontMask) + m.Load(21, &x.noOpen) + m.LoadValue(3, new(bool), func(y interface{}) { x.loadInitializedChan(y.(bool)) }) +} + +func (x *fuseDevice) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.fuseDevice" +} + +func (x *fuseDevice) StateFields() []string { + return []string{} +} + +func (x *fuseDevice) beforeSave() {} + +func (x *fuseDevice) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *fuseDevice) afterLoad() {} + +func (x *fuseDevice) StateLoad(m state.Source) { +} + +func (x *DeviceFD) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.DeviceFD" +} + +func (x *DeviceFD) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + "nextOpID", + "queue", + "numActiveRequests", + "completions", + "writeCursor", + "writeBuf", + "writeCursorFR", + "waitQueue", + "fullQueueCh", + "fs", + } +} + +func (x *DeviceFD) beforeSave() {} + +func (x *DeviceFD) StateSave(m state.Sink) { + x.beforeSave() + var fullQueueCh int = x.saveFullQueueCh() + m.SaveValue(12, fullQueueCh) + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) + m.Save(4, &x.nextOpID) + m.Save(5, &x.queue) + m.Save(6, &x.numActiveRequests) + m.Save(7, &x.completions) + m.Save(8, &x.writeCursor) + m.Save(9, &x.writeBuf) + m.Save(10, &x.writeCursorFR) + m.Save(11, &x.waitQueue) + m.Save(13, &x.fs) +} + +func (x *DeviceFD) afterLoad() {} + +func (x *DeviceFD) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) + m.Load(4, &x.nextOpID) + m.Load(5, &x.queue) + m.Load(6, &x.numActiveRequests) + m.Load(7, &x.completions) + m.Load(8, &x.writeCursor) + m.Load(9, &x.writeBuf) + m.Load(10, &x.writeCursorFR) + m.Load(11, &x.waitQueue) + m.Load(13, &x.fs) + m.LoadValue(12, new(int), func(y interface{}) { x.loadFullQueueCh(y.(int)) }) +} + +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{} +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { +} + +func (x *filesystemOptions) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.filesystemOptions" +} + +func (x *filesystemOptions) StateFields() []string { + return []string{ + "userID", + "groupID", + "rootMode", + "maxActiveRequests", + "maxRead", + } +} + +func (x *filesystemOptions) beforeSave() {} + +func (x *filesystemOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.userID) + m.Save(1, &x.groupID) + m.Save(2, &x.rootMode) + m.Save(3, &x.maxActiveRequests) + m.Save(4, &x.maxRead) +} + +func (x *filesystemOptions) afterLoad() {} + +func (x *filesystemOptions) StateLoad(m state.Source) { + m.Load(0, &x.userID) + m.Load(1, &x.groupID) + m.Load(2, &x.rootMode) + m.Load(3, &x.maxActiveRequests) + m.Load(4, &x.maxRead) +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + "conn", + "opts", + "umounted", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) + m.Save(2, &x.conn) + m.Save(3, &x.opts) + m.Save(4, &x.umounted) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) + m.Load(2, &x.conn) + m.Load(3, &x.opts) + m.Load(4, &x.umounted) +} + +func (x *inode) StateTypeName() string { + return "pkg/sentry/fsimpl/fuse.inode" +} + +func (x *inode) StateFields() []string { + return []string{ + "inodeRefs", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNoDynamicLookup", + "InodeNotSymlink", + "OrderedChildren", + "dentry", + "fs", + "metadataMu", + "nodeID", + "locks", + "size", + "attributeVersion", + "attributeTime", + "version", + "link", + } +} + +func (x *inode) beforeSave() {} + +func (x *inode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inodeRefs) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeDirectoryNoNewChildren) + m.Save(3, &x.InodeNoDynamicLookup) + m.Save(4, &x.InodeNotSymlink) + m.Save(5, &x.OrderedChildren) + m.Save(6, &x.dentry) + m.Save(7, &x.fs) + m.Save(8, &x.metadataMu) + m.Save(9, &x.nodeID) + m.Save(10, &x.locks) + m.Save(11, &x.size) + m.Save(12, &x.attributeVersion) + m.Save(13, &x.attributeTime) + m.Save(14, &x.version) + m.Save(15, &x.link) +} + +func (x *inode) afterLoad() {} + +func (x *inode) StateLoad(m state.Source) { + m.Load(0, &x.inodeRefs) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeDirectoryNoNewChildren) + m.Load(3, &x.InodeNoDynamicLookup) + m.Load(4, &x.InodeNotSymlink) + m.Load(5, &x.OrderedChildren) + m.Load(6, &x.dentry) + m.Load(7, &x.fs) + m.Load(8, &x.metadataMu) + m.Load(9, &x.nodeID) + m.Load(10, &x.locks) + m.Load(11, &x.size) + m.Load(12, &x.attributeVersion) + m.Load(13, &x.attributeTime) + m.Load(14, &x.version) + m.Load(15, &x.link) +} + func (x *inodeRefs) StateTypeName() string { return "pkg/sentry/fsimpl/fuse.inodeRefs" } @@ -187,6 +513,13 @@ func (x *Response) StateLoad(m state.Source) { } func init() { + state.Register((*connection)(nil)) + state.Register((*fuseDevice)(nil)) + state.Register((*DeviceFD)(nil)) + state.Register((*FilesystemType)(nil)) + state.Register((*filesystemOptions)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*inode)(nil)) state.Register((*inodeRefs)(nil)) state.Register((*requestList)(nil)) state.Register((*requestEntry)(nil)) diff --git a/pkg/sentry/fsimpl/fuse/fusefs.go b/pkg/sentry/fsimpl/fuse/fusefs.go index 5ccfc43e7..2f7cd8b8a 100644 --- a/pkg/sentry/fsimpl/fuse/fusefs.go +++ b/pkg/sentry/fsimpl/fuse/fusefs.go @@ -41,8 +41,11 @@ const Name = "fuse" const maxActiveRequestsDefault = 10000 // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct{} +// +stateify savable type filesystemOptions struct { // userID specifies the numeric uid of the mount owner. // This option should not be specified by the filesystem owner. @@ -73,6 +76,8 @@ type filesystemOptions struct { } // filesystem implements vfs.FilesystemImpl. +// +// +stateify savable type filesystem struct { kernfs.Filesystem devMinor uint32 @@ -240,6 +245,8 @@ func (fs *filesystem) Release(ctx context.Context) { } // inode implements kernfs.Inode. +// +// +stateify savable type inode struct { inodeRefs kernfs.InodeAttrs diff --git a/pkg/sentry/fsimpl/gofer/directory.go b/pkg/sentry/fsimpl/gofer/directory.go index 91d2ae199..18c884b59 100644 --- a/pkg/sentry/fsimpl/gofer/directory.go +++ b/pkg/sentry/fsimpl/gofer/directory.go @@ -117,11 +117,12 @@ func (d *dentry) createSyntheticChildLocked(opts *createSyntheticOpts) { d.syntheticChildren++ } +// +stateify savable type directoryFD struct { fileDescription vfs.DirectoryFileDescriptionDefaultImpl - mu sync.Mutex + mu sync.Mutex `state:"nosave"` off int64 dirents []vfs.Dirent } diff --git a/pkg/sentry/fsimpl/gofer/gofer.go b/pkg/sentry/fsimpl/gofer/gofer.go index aaad9c0d9..8608471f8 100644 --- a/pkg/sentry/fsimpl/gofer/gofer.go +++ b/pkg/sentry/fsimpl/gofer/gofer.go @@ -62,9 +62,13 @@ import ( const Name = "9p" // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct{} // filesystem implements vfs.FilesystemImpl. +// +// +stateify savable type filesystem struct { vfsfs vfs.Filesystem @@ -77,7 +81,7 @@ type filesystem struct { iopts InternalFilesystemOptions // client is the client used by this filesystem. client is immutable. - client *p9.Client + client *p9.Client `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. // clock is a realtime clock used to set timestamps in file operations. clock ktime.Clock @@ -95,7 +99,7 @@ type filesystem struct { // reference count (such that it is usable as vfs.ResolvingPath.Start() or // is reachable from its children), or if it is a child dentry (such that // it is reachable from its parent). - renameMu sync.RWMutex + renameMu sync.RWMutex `state:"nosave"` // cachedDentries contains all dentries with 0 references. (Due to race // conditions, it may also contain dentries with non-zero references.) @@ -107,7 +111,7 @@ type filesystem struct { // syncableDentries contains all dentries in this filesystem for which // !dentry.file.isNil(). specialFileFDs contains all open specialFileFDs. // These fields are protected by syncMu. - syncMu sync.Mutex + syncMu sync.Mutex `state:"nosave"` syncableDentries map[*dentry]struct{} specialFileFDs map[*specialFileFD]struct{} @@ -120,6 +124,8 @@ type filesystem struct { // dentries, it comes from QID.Path from the 9P server. Synthetic dentries // have have their inodeNumber generated sequentially, with the MSB reserved to // prevent conflicts with regular dentries. +// +// +stateify savable type inodeNumber uint64 // Reserve MSB for synthetic mounts. @@ -132,6 +138,7 @@ func inoFromPath(path uint64) inodeNumber { return inodeNumber(path &^ syntheticInoMask) } +// +stateify savable type filesystemOptions struct { // "Standard" 9P options. fd int @@ -177,6 +184,8 @@ type filesystemOptions struct { // InteropMode controls the client's interaction with other remote filesystem // users. +// +// +stateify savable type InteropMode uint32 const ( @@ -235,6 +244,8 @@ const ( // InternalFilesystemOptions may be passed as // vfs.GetFilesystemOptions.InternalData to FilesystemType.GetFilesystem. +// +// +stateify savable type InternalFilesystemOptions struct { // If LeakConnection is true, do not close the connection to the server // when the Filesystem is released. This is necessary for deployments in @@ -534,6 +545,8 @@ func (fs *filesystem) Release(ctx context.Context) { } // dentry implements vfs.DentryImpl. +// +// +stateify savable type dentry struct { vfsd vfs.Dentry @@ -563,7 +576,7 @@ type dentry struct { // If file.isNil(), this dentry represents a synthetic file, i.e. a file // that does not exist on the remote filesystem. As of this writing, the // only files that can be synthetic are sockets, pipes, and directories. - file p9file + file p9file `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. // If deleted is non-zero, the file represented by this dentry has been // deleted. deleted is accessed using atomic memory operations. @@ -575,7 +588,7 @@ type dentry struct { cached bool dentryEntry - dirMu sync.Mutex + dirMu sync.Mutex `state:"nosave"` // If this dentry represents a directory, children contains: // @@ -607,7 +620,7 @@ type dentry struct { // To mutate: // - Lock metadataMu and use atomic operations to update because we might // have atomic readers that don't hold the lock. - metadataMu sync.Mutex + metadataMu sync.Mutex `state:"nosave"` ino inodeNumber // immutable mode uint32 // type is immutable, perms are mutable uid uint32 // auth.KUID, but stored as raw uint32 for sync/atomic @@ -638,7 +651,7 @@ type dentry struct { // other metadata fields. nlink uint32 - mapsMu sync.Mutex + mapsMu sync.Mutex `state:"nosave"` // If this dentry represents a regular file, mappings tracks mappings of // the file into memmap.MappingSpaces. mappings is protected by mapsMu. @@ -662,12 +675,12 @@ type dentry struct { // either p9.File transitions from closed (isNil() == true) to open // (isNil() == false), it may be mutated with handleMu locked, but cannot // be closed until the dentry is destroyed. - handleMu sync.RWMutex - readFile p9file - writeFile p9file + handleMu sync.RWMutex `state:"nosave"` + readFile p9file `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. + writeFile p9file `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. hostFD int32 - dataMu sync.RWMutex + dataMu sync.RWMutex `state:"nosave"` // If this dentry represents a regular file that is client-cached, cache // maps offsets into the cached file to offsets into @@ -1627,12 +1640,14 @@ func (d *dentry) decLinks() { // fileDescription is embedded by gofer implementations of // vfs.FileDescriptionImpl. +// +// +stateify savable type fileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl vfs.LockFD - lockLogging sync.Once + lockLogging sync.Once `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. } func (fd *fileDescription) filesystem() *filesystem { diff --git a/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go b/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go index 19b1eef9e..7831e1830 100644 --- a/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go +++ b/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go @@ -58,7 +58,495 @@ func (x *dentryEntry) StateLoad(m state.Source) { m.Load(1, &x.prev) } +func (x *directoryFD) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.directoryFD" +} + +func (x *directoryFD) StateFields() []string { + return []string{ + "fileDescription", + "DirectoryFileDescriptionDefaultImpl", + "off", + "dirents", + } +} + +func (x *directoryFD) beforeSave() {} + +func (x *directoryFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Save(2, &x.off) + m.Save(3, &x.dirents) +} + +func (x *directoryFD) afterLoad() {} + +func (x *directoryFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Load(2, &x.off) + m.Load(3, &x.dirents) +} + +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{} +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "vfsfs", + "mfp", + "opts", + "iopts", + "clock", + "devMinor", + "cachedDentries", + "cachedDentriesLen", + "syncableDentries", + "specialFileFDs", + "syntheticSeq", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfs) + m.Save(1, &x.mfp) + m.Save(2, &x.opts) + m.Save(3, &x.iopts) + m.Save(4, &x.clock) + m.Save(5, &x.devMinor) + m.Save(6, &x.cachedDentries) + m.Save(7, &x.cachedDentriesLen) + m.Save(8, &x.syncableDentries) + m.Save(9, &x.specialFileFDs) + m.Save(10, &x.syntheticSeq) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.vfsfs) + m.Load(1, &x.mfp) + m.Load(2, &x.opts) + m.Load(3, &x.iopts) + m.Load(4, &x.clock) + m.Load(5, &x.devMinor) + m.Load(6, &x.cachedDentries) + m.Load(7, &x.cachedDentriesLen) + m.Load(8, &x.syncableDentries) + m.Load(9, &x.specialFileFDs) + m.Load(10, &x.syntheticSeq) +} + +func (x *inodeNumber) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.inodeNumber" +} + +func (x *inodeNumber) StateFields() []string { + return nil +} + +func (x *filesystemOptions) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.filesystemOptions" +} + +func (x *filesystemOptions) StateFields() []string { + return []string{ + "fd", + "aname", + "interop", + "dfltuid", + "dfltgid", + "msize", + "version", + "maxCachedDentries", + "forcePageCache", + "limitHostFDTranslation", + "overlayfsStaleRead", + "regularFilesUseSpecialFileFD", + } +} + +func (x *filesystemOptions) beforeSave() {} + +func (x *filesystemOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fd) + m.Save(1, &x.aname) + m.Save(2, &x.interop) + m.Save(3, &x.dfltuid) + m.Save(4, &x.dfltgid) + m.Save(5, &x.msize) + m.Save(6, &x.version) + m.Save(7, &x.maxCachedDentries) + m.Save(8, &x.forcePageCache) + m.Save(9, &x.limitHostFDTranslation) + m.Save(10, &x.overlayfsStaleRead) + m.Save(11, &x.regularFilesUseSpecialFileFD) +} + +func (x *filesystemOptions) afterLoad() {} + +func (x *filesystemOptions) StateLoad(m state.Source) { + m.Load(0, &x.fd) + m.Load(1, &x.aname) + m.Load(2, &x.interop) + m.Load(3, &x.dfltuid) + m.Load(4, &x.dfltgid) + m.Load(5, &x.msize) + m.Load(6, &x.version) + m.Load(7, &x.maxCachedDentries) + m.Load(8, &x.forcePageCache) + m.Load(9, &x.limitHostFDTranslation) + m.Load(10, &x.overlayfsStaleRead) + m.Load(11, &x.regularFilesUseSpecialFileFD) +} + +func (x *InteropMode) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.InteropMode" +} + +func (x *InteropMode) StateFields() []string { + return nil +} + +func (x *InternalFilesystemOptions) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.InternalFilesystemOptions" +} + +func (x *InternalFilesystemOptions) StateFields() []string { + return []string{ + "LeakConnection", + "OpenSocketsByConnecting", + } +} + +func (x *InternalFilesystemOptions) beforeSave() {} + +func (x *InternalFilesystemOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.LeakConnection) + m.Save(1, &x.OpenSocketsByConnecting) +} + +func (x *InternalFilesystemOptions) afterLoad() {} + +func (x *InternalFilesystemOptions) StateLoad(m state.Source) { + m.Load(0, &x.LeakConnection) + m.Load(1, &x.OpenSocketsByConnecting) +} + +func (x *dentry) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.dentry" +} + +func (x *dentry) StateFields() []string { + return []string{ + "vfsd", + "refs", + "fs", + "parent", + "name", + "deleted", + "cached", + "dentryEntry", + "children", + "syntheticChildren", + "dirents", + "ino", + "mode", + "uid", + "gid", + "blockSize", + "atime", + "mtime", + "ctime", + "btime", + "size", + "atimeDirty", + "mtimeDirty", + "nlink", + "mappings", + "hostFD", + "cache", + "dirty", + "pf", + "haveTarget", + "target", + "endpoint", + "pipe", + "locks", + "watches", + } +} + +func (x *dentry) beforeSave() {} + +func (x *dentry) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsd) + m.Save(1, &x.refs) + m.Save(2, &x.fs) + m.Save(3, &x.parent) + m.Save(4, &x.name) + m.Save(5, &x.deleted) + m.Save(6, &x.cached) + m.Save(7, &x.dentryEntry) + m.Save(8, &x.children) + m.Save(9, &x.syntheticChildren) + m.Save(10, &x.dirents) + m.Save(11, &x.ino) + m.Save(12, &x.mode) + m.Save(13, &x.uid) + m.Save(14, &x.gid) + m.Save(15, &x.blockSize) + m.Save(16, &x.atime) + m.Save(17, &x.mtime) + m.Save(18, &x.ctime) + m.Save(19, &x.btime) + m.Save(20, &x.size) + m.Save(21, &x.atimeDirty) + m.Save(22, &x.mtimeDirty) + m.Save(23, &x.nlink) + m.Save(24, &x.mappings) + m.Save(25, &x.hostFD) + m.Save(26, &x.cache) + m.Save(27, &x.dirty) + m.Save(28, &x.pf) + m.Save(29, &x.haveTarget) + m.Save(30, &x.target) + m.Save(31, &x.endpoint) + m.Save(32, &x.pipe) + m.Save(33, &x.locks) + m.Save(34, &x.watches) +} + +func (x *dentry) afterLoad() {} + +func (x *dentry) StateLoad(m state.Source) { + m.Load(0, &x.vfsd) + m.Load(1, &x.refs) + m.Load(2, &x.fs) + m.Load(3, &x.parent) + m.Load(4, &x.name) + m.Load(5, &x.deleted) + m.Load(6, &x.cached) + m.Load(7, &x.dentryEntry) + m.Load(8, &x.children) + m.Load(9, &x.syntheticChildren) + m.Load(10, &x.dirents) + m.Load(11, &x.ino) + m.Load(12, &x.mode) + m.Load(13, &x.uid) + m.Load(14, &x.gid) + m.Load(15, &x.blockSize) + m.Load(16, &x.atime) + m.Load(17, &x.mtime) + m.Load(18, &x.ctime) + m.Load(19, &x.btime) + m.Load(20, &x.size) + m.Load(21, &x.atimeDirty) + m.Load(22, &x.mtimeDirty) + m.Load(23, &x.nlink) + m.Load(24, &x.mappings) + m.Load(25, &x.hostFD) + m.Load(26, &x.cache) + m.Load(27, &x.dirty) + m.Load(28, &x.pf) + m.Load(29, &x.haveTarget) + m.Load(30, &x.target) + m.Load(31, &x.endpoint) + m.Load(32, &x.pipe) + m.Load(33, &x.locks) + m.Load(34, &x.watches) +} + +func (x *fileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.fileDescription" +} + +func (x *fileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + } +} + +func (x *fileDescription) beforeSave() {} + +func (x *fileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) +} + +func (x *fileDescription) afterLoad() {} + +func (x *fileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) +} + +func (x *regularFileFD) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.regularFileFD" +} + +func (x *regularFileFD) StateFields() []string { + return []string{ + "fileDescription", + "off", + } +} + +func (x *regularFileFD) beforeSave() {} + +func (x *regularFileFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.off) +} + +func (x *regularFileFD) afterLoad() {} + +func (x *regularFileFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.off) +} + +func (x *dentryPlatformFile) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.dentryPlatformFile" +} + +func (x *dentryPlatformFile) StateFields() []string { + return []string{ + "dentry", + "fdRefs", + "hostFileMapper", + } +} + +func (x *dentryPlatformFile) beforeSave() {} + +func (x *dentryPlatformFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.dentry) + m.Save(1, &x.fdRefs) + m.Save(2, &x.hostFileMapper) +} + +func (x *dentryPlatformFile) afterLoad() {} + +func (x *dentryPlatformFile) StateLoad(m state.Source) { + m.Load(0, &x.dentry) + m.Load(1, &x.fdRefs) + m.Load(2, &x.hostFileMapper) +} + +func (x *endpoint) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.endpoint" +} + +func (x *endpoint) StateFields() []string { + return []string{ + "dentry", + "path", + } +} + +func (x *endpoint) beforeSave() {} + +func (x *endpoint) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.dentry) + m.Save(1, &x.path) +} + +func (x *endpoint) afterLoad() {} + +func (x *endpoint) StateLoad(m state.Source) { + m.Load(0, &x.dentry) + m.Load(1, &x.path) +} + +func (x *specialFileFD) StateTypeName() string { + return "pkg/sentry/fsimpl/gofer.specialFileFD" +} + +func (x *specialFileFD) StateFields() []string { + return []string{ + "fileDescription", + "isRegularFile", + "seekable", + "haveQueue", + "queue", + "off", + } +} + +func (x *specialFileFD) beforeSave() {} + +func (x *specialFileFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.isRegularFile) + m.Save(2, &x.seekable) + m.Save(3, &x.haveQueue) + m.Save(4, &x.queue) + m.Save(5, &x.off) +} + +func (x *specialFileFD) afterLoad() {} + +func (x *specialFileFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.isRegularFile) + m.Load(2, &x.seekable) + m.Load(3, &x.haveQueue) + m.Load(4, &x.queue) + m.Load(5, &x.off) +} + func init() { state.Register((*dentryList)(nil)) state.Register((*dentryEntry)(nil)) + state.Register((*directoryFD)(nil)) + state.Register((*FilesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*inodeNumber)(nil)) + state.Register((*filesystemOptions)(nil)) + state.Register((*InteropMode)(nil)) + state.Register((*InternalFilesystemOptions)(nil)) + state.Register((*dentry)(nil)) + state.Register((*fileDescription)(nil)) + state.Register((*regularFileFD)(nil)) + state.Register((*dentryPlatformFile)(nil)) + state.Register((*endpoint)(nil)) + state.Register((*specialFileFD)(nil)) } diff --git a/pkg/sentry/fsimpl/gofer/handle.go b/pkg/sentry/fsimpl/gofer/handle.go index 104157512..a9ebe1206 100644 --- a/pkg/sentry/fsimpl/gofer/handle.go +++ b/pkg/sentry/fsimpl/gofer/handle.go @@ -25,6 +25,8 @@ import ( // handle represents a remote "open file descriptor", consisting of an opened // fid (p9.File) and optionally a host file descriptor. +// +// These are explicitly not savable. type handle struct { file p9file fd int32 // -1 if unavailable diff --git a/pkg/sentry/fsimpl/gofer/regular_file.go b/pkg/sentry/fsimpl/gofer/regular_file.go index 24f03ee94..eeaf6e444 100644 --- a/pkg/sentry/fsimpl/gofer/regular_file.go +++ b/pkg/sentry/fsimpl/gofer/regular_file.go @@ -39,11 +39,12 @@ func (d *dentry) isRegularFile() bool { return d.fileType() == linux.S_IFREG } +// +stateify savable type regularFileFD struct { fileDescription // off is the file offset. off is protected by mu. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` off int64 } @@ -898,6 +899,8 @@ func (d *dentry) Evict(ctx context.Context, er pgalloc.EvictableRange) { // dentryPlatformFile is only used when a host FD representing the remote file // is available (i.e. dentry.hostFD >= 0), and that FD is used for application // memory mappings (i.e. !filesystem.opts.forcePageCache). +// +// +stateify savable type dentryPlatformFile struct { *dentry @@ -910,7 +913,7 @@ type dentryPlatformFile struct { hostFileMapper fsutil.HostFileMapper // hostFileMapperInitOnce is used to lazily initialize hostFileMapper. - hostFileMapperInitOnce sync.Once + hostFileMapperInitOnce sync.Once `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. } // IncRef implements memmap.File.IncRef. diff --git a/pkg/sentry/fsimpl/gofer/socket.go b/pkg/sentry/fsimpl/gofer/socket.go index 85d2bee72..326b940a7 100644 --- a/pkg/sentry/fsimpl/gofer/socket.go +++ b/pkg/sentry/fsimpl/gofer/socket.go @@ -36,12 +36,14 @@ func (d *dentry) isSocket() bool { // An endpoint's lifetime is the time between when filesystem.BoundEndpointAt() // is called and either BoundEndpoint.BidirectionalConnect or // BoundEndpoint.UnidirectionalConnect is called. +// +// +stateify savable type endpoint struct { // dentry is the filesystem dentry which produced this endpoint. dentry *dentry // file is the p9 file that contains a single unopened fid. - file p9.File + file p9.File `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. // path is the sentry path where this endpoint is bound. path string diff --git a/pkg/sentry/fsimpl/gofer/special_file.go b/pkg/sentry/fsimpl/gofer/special_file.go index 576c57491..71581736c 100644 --- a/pkg/sentry/fsimpl/gofer/special_file.go +++ b/pkg/sentry/fsimpl/gofer/special_file.go @@ -34,11 +34,13 @@ import ( // special files, and (when filesystemOptions.regularFilesUseSpecialFileFD is // in effect) regular files. specialFileFD differs from regularFileFD by using // per-FD handles instead of shared per-dentry handles, and never buffering I/O. +// +// +stateify savable type specialFileFD struct { fileDescription // handle is used for file I/O. handle is immutable. - handle handle + handle handle `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. // isRegularFile is true if this FD represents a regular file which is only // possible when filesystemOptions.regularFilesUseSpecialFileFD is in @@ -56,7 +58,7 @@ type specialFileFD struct { queue waiter.Queue // If seekable is true, off is the file offset. off is protected by mu. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` off int64 } diff --git a/pkg/sentry/fsimpl/host/host.go b/pkg/sentry/fsimpl/host/host.go index c0cef3453..ffe4ddb32 100644 --- a/pkg/sentry/fsimpl/host/host.go +++ b/pkg/sentry/fsimpl/host/host.go @@ -137,6 +137,8 @@ func ImportFD(ctx context.Context, mnt *vfs.Mount, hostFD int, isTTY bool) (*vfs } // filesystemType implements vfs.FilesystemType. +// +// +stateify savable type filesystemType struct{} // GetFilesystem implements vfs.FilesystemType.GetFilesystem. @@ -166,6 +168,8 @@ func NewFilesystem(vfsObj *vfs.VirtualFilesystem) (*vfs.Filesystem, error) { } // filesystem implements vfs.FilesystemImpl. +// +// +stateify savable type filesystem struct { kernfs.Filesystem @@ -185,6 +189,8 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe } // inode implements kernfs.Inode. +// +// +stateify savable type inode struct { kernfs.InodeNoStatFS kernfs.InodeNotDirectory @@ -233,7 +239,7 @@ type inode struct { canMap bool // mapsMu protects mappings. - mapsMu sync.Mutex + mapsMu sync.Mutex `state:"nosave"` // If canMap is true, mappings tracks mappings of hostFD into // memmap.MappingSpaces. @@ -511,6 +517,8 @@ func (i *inode) open(ctx context.Context, d *kernfs.Dentry, mnt *vfs.Mount, flag } // fileDescription is embedded by host fd implementations of FileDescriptionImpl. +// +// +stateify savable type fileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl @@ -525,7 +533,7 @@ type fileDescription struct { inode *inode // offsetMu protects offset. - offsetMu sync.Mutex + offsetMu sync.Mutex `state:"nosave"` // offset specifies the current file offset. It is only meaningful when // inode.seekable is true. diff --git a/pkg/sentry/fsimpl/host/host_state_autogen.go b/pkg/sentry/fsimpl/host/host_state_autogen.go index 400320c78..c97fa7212 100644 --- a/pkg/sentry/fsimpl/host/host_state_autogen.go +++ b/pkg/sentry/fsimpl/host/host_state_autogen.go @@ -29,6 +29,148 @@ func (x *ConnectedEndpointRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *filesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/host.filesystemType" +} + +func (x *filesystemType) StateFields() []string { + return []string{} +} + +func (x *filesystemType) beforeSave() {} + +func (x *filesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *filesystemType) afterLoad() {} + +func (x *filesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/host.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) +} + +func (x *inode) StateTypeName() string { + return "pkg/sentry/fsimpl/host.inode" +} + +func (x *inode) StateFields() []string { + return []string{ + "InodeNoStatFS", + "InodeNotDirectory", + "InodeNotSymlink", + "locks", + "inodeRefs", + "hostFD", + "ino", + "isTTY", + "seekable", + "wouldBlock", + "queue", + "canMap", + "mappings", + "pf", + } +} + +func (x *inode) beforeSave() {} + +func (x *inode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.InodeNoStatFS) + m.Save(1, &x.InodeNotDirectory) + m.Save(2, &x.InodeNotSymlink) + m.Save(3, &x.locks) + m.Save(4, &x.inodeRefs) + m.Save(5, &x.hostFD) + m.Save(6, &x.ino) + m.Save(7, &x.isTTY) + m.Save(8, &x.seekable) + m.Save(9, &x.wouldBlock) + m.Save(10, &x.queue) + m.Save(11, &x.canMap) + m.Save(12, &x.mappings) + m.Save(13, &x.pf) +} + +func (x *inode) afterLoad() {} + +func (x *inode) StateLoad(m state.Source) { + m.Load(0, &x.InodeNoStatFS) + m.Load(1, &x.InodeNotDirectory) + m.Load(2, &x.InodeNotSymlink) + m.Load(3, &x.locks) + m.Load(4, &x.inodeRefs) + m.Load(5, &x.hostFD) + m.Load(6, &x.ino) + m.Load(7, &x.isTTY) + m.Load(8, &x.seekable) + m.Load(9, &x.wouldBlock) + m.Load(10, &x.queue) + m.Load(11, &x.canMap) + m.Load(12, &x.mappings) + m.Load(13, &x.pf) +} + +func (x *fileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/host.fileDescription" +} + +func (x *fileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + "inode", + "offset", + } +} + +func (x *fileDescription) beforeSave() {} + +func (x *fileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) + m.Save(3, &x.inode) + m.Save(4, &x.offset) +} + +func (x *fileDescription) afterLoad() {} + +func (x *fileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) + m.Load(3, &x.inode) + m.Load(4, &x.offset) +} + func (x *inodeRefs) StateTypeName() string { return "pkg/sentry/fsimpl/host.inodeRefs" } @@ -52,6 +194,35 @@ func (x *inodeRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *inodePlatformFile) StateTypeName() string { + return "pkg/sentry/fsimpl/host.inodePlatformFile" +} + +func (x *inodePlatformFile) StateFields() []string { + return []string{ + "inode", + "fdRefs", + "fileMapper", + } +} + +func (x *inodePlatformFile) beforeSave() {} + +func (x *inodePlatformFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inode) + m.Save(1, &x.fdRefs) + m.Save(2, &x.fileMapper) +} + +func (x *inodePlatformFile) afterLoad() {} + +func (x *inodePlatformFile) StateLoad(m state.Source) { + m.Load(0, &x.inode) + m.Load(1, &x.fdRefs) + m.Load(2, &x.fileMapper) +} + func (x *ConnectedEndpoint) StateTypeName() string { return "pkg/sentry/fsimpl/host.ConnectedEndpoint" } @@ -84,8 +255,46 @@ func (x *ConnectedEndpoint) StateLoad(m state.Source) { m.Load(3, &x.stype) } +func (x *TTYFileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/host.TTYFileDescription" +} + +func (x *TTYFileDescription) StateFields() []string { + return []string{ + "fileDescription", + "session", + "fgProcessGroup", + "termios", + } +} + +func (x *TTYFileDescription) beforeSave() {} + +func (x *TTYFileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.session) + m.Save(2, &x.fgProcessGroup) + m.Save(3, &x.termios) +} + +func (x *TTYFileDescription) afterLoad() {} + +func (x *TTYFileDescription) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.session) + m.Load(2, &x.fgProcessGroup) + m.Load(3, &x.termios) +} + func init() { state.Register((*ConnectedEndpointRefs)(nil)) + state.Register((*filesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*inode)(nil)) + state.Register((*fileDescription)(nil)) state.Register((*inodeRefs)(nil)) + state.Register((*inodePlatformFile)(nil)) state.Register((*ConnectedEndpoint)(nil)) + state.Register((*TTYFileDescription)(nil)) } diff --git a/pkg/sentry/fsimpl/host/mmap.go b/pkg/sentry/fsimpl/host/mmap.go index 65d3af38c..b51a17bed 100644 --- a/pkg/sentry/fsimpl/host/mmap.go +++ b/pkg/sentry/fsimpl/host/mmap.go @@ -27,11 +27,13 @@ import ( // cannot implement both kernfs.Inode.IncRef and memmap.File.IncRef. // // inodePlatformFile should only be used if inode.canMap is true. +// +// +stateify savable type inodePlatformFile struct { *inode // fdRefsMu protects fdRefs. - fdRefsMu sync.Mutex + fdRefsMu sync.Mutex `state:"nosave"` // fdRefs counts references on memmap.File offsets. It is used solely for // memory accounting. @@ -41,7 +43,7 @@ type inodePlatformFile struct { fileMapper fsutil.HostFileMapper // fileMapperInitOnce is used to lazily initialize fileMapper. - fileMapperInitOnce sync.Once + fileMapperInitOnce sync.Once `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported. } // IncRef implements memmap.File.IncRef. diff --git a/pkg/sentry/fsimpl/host/tty.go b/pkg/sentry/fsimpl/host/tty.go index e02b9b8f6..f5c596fec 100644 --- a/pkg/sentry/fsimpl/host/tty.go +++ b/pkg/sentry/fsimpl/host/tty.go @@ -30,6 +30,8 @@ import ( // TTYFileDescription implements vfs.FileDescriptionImpl for a host file // descriptor that wraps a TTY FD. +// +// +stateify savable type TTYFileDescription struct { fileDescription diff --git a/pkg/sentry/fsimpl/kernfs/fd_impl_util.go b/pkg/sentry/fsimpl/kernfs/fd_impl_util.go index 2b4294228..c7bd3baae 100644 --- a/pkg/sentry/fsimpl/kernfs/fd_impl_util.go +++ b/pkg/sentry/fsimpl/kernfs/fd_impl_util.go @@ -29,6 +29,8 @@ import ( ) // SeekEndConfig describes the SEEK_END behaviour for FDs. +// +// +stateify savable type SeekEndConfig int // Constants related to SEEK_END behaviour for FDs. @@ -41,6 +43,8 @@ const ( ) // GenericDirectoryFDOptions contains configuration for a GenericDirectoryFD. +// +// +stateify savable type GenericDirectoryFDOptions struct { SeekEnd SeekEndConfig } @@ -56,6 +60,8 @@ type GenericDirectoryFDOptions struct { // Must be initialize with Init before first use. // // Lock ordering: mu => children.mu. +// +// +stateify savable type GenericDirectoryFD struct { vfs.FileDescriptionDefaultImpl vfs.DirectoryFileDescriptionDefaultImpl @@ -68,7 +74,7 @@ type GenericDirectoryFD struct { children *OrderedChildren // mu protects the fields below. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // off is the current directory offset. Protected by "mu". off int64 diff --git a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go index 5cc196980..d8e321acb 100644 --- a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go +++ b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go @@ -31,6 +31,8 @@ import ( // count for inodes, performing no extra actions when references are obtained or // released. This is suitable for simple file inodes that don't reference any // resources. +// +// +stateify savable type InodeNoopRefCount struct { } @@ -50,6 +52,8 @@ func (InodeNoopRefCount) TryIncRef() bool { // InodeDirectoryNoNewChildren partially implements the Inode interface. // InodeDirectoryNoNewChildren represents a directory inode which does not // support creation of new children. +// +// +stateify savable type InodeDirectoryNoNewChildren struct{} // NewFile implements Inode.NewFile. @@ -81,6 +85,8 @@ func (InodeDirectoryNoNewChildren) NewNode(context.Context, string, vfs.MknodOpt // inodeDirectory and inodeDynamicDirectory sub interfaces. Inodes that do not // represent directories can embed this to provide no-op implementations for // directory-related functions. +// +// +stateify savable type InodeNotDirectory struct { } @@ -149,6 +155,8 @@ func (InodeNotDirectory) Valid(context.Context) bool { // dymanic entries (i.e. entries that are not "hashed" into the // vfs.Dentry.children) can embed this to provide no-op implementations for // functions related to dynamic entries. +// +// +stateify savable type InodeNoDynamicLookup struct{} // Lookup implements Inode.Lookup. @@ -169,6 +177,8 @@ func (InodeNoDynamicLookup) Valid(ctx context.Context) bool { // InodeNotSymlink partially implements the Inode interface, specifically the // inodeSymlink sub interface. All inodes that are not symlinks may embed this // to return the appropriate errors from symlink-related functions. +// +// +stateify savable type InodeNotSymlink struct{} // Readlink implements Inode.Readlink. @@ -186,6 +196,8 @@ func (InodeNotSymlink) Getlink(context.Context, *vfs.Mount) (vfs.VirtualDentry, // inode attributes. // // Must be initialized by Init prior to first use. +// +// +stateify savable type InodeAttrs struct { devMajor uint32 devMinor uint32 @@ -330,6 +342,7 @@ func (a *InodeAttrs) DecLinks() { } } +// +stateify savable type slot struct { Name string Dentry *vfs.Dentry @@ -337,6 +350,8 @@ type slot struct { } // OrderedChildrenOptions contains initialization options for OrderedChildren. +// +// +stateify savable type OrderedChildrenOptions struct { // Writable indicates whether vfs.FilesystemImpl methods implemented by // OrderedChildren may modify the tracked children. This applies to @@ -352,12 +367,14 @@ type OrderedChildrenOptions struct { // directories. // // Must be initialize with Init before first use. +// +// +stateify savable type OrderedChildren struct { // Can children be modified by user syscalls? It set to false, interface // methods that would modify the children return EPERM. Immutable. writable bool - mu sync.RWMutex + mu sync.RWMutex `state:"nosave"` order slotList set map[string]*slot } @@ -484,6 +501,7 @@ func (o *OrderedChildren) RmDir(ctx context.Context, name string, child *vfs.Den return o.Unlink(ctx, name, child) } +// +stateify savable type renameAcrossDifferentImplementationsError struct{} func (renameAcrossDifferentImplementationsError) Error() string { @@ -542,6 +560,8 @@ func (o *OrderedChildren) nthLocked(i int64) *slot { } // InodeSymlink partially implements Inode interface for symlinks. +// +// +stateify savable type InodeSymlink struct { InodeNotDirectory } @@ -615,6 +635,8 @@ func (s *StaticDirectory) DecRef(context.Context) { } // AlwaysValid partially implements kernfs.inodeDynamicLookup. +// +// +stateify savable type AlwaysValid struct{} // Valid implements kernfs.inodeDynamicLookup.Valid. @@ -624,6 +646,8 @@ func (*AlwaysValid) Valid(context.Context) bool { // InodeNoStatFS partially implements the Inode interface, where the client // filesystem doesn't support statfs(2). +// +// +stateify savable type InodeNoStatFS struct{} // StatFS implements Inode.StatFS. diff --git a/pkg/sentry/fsimpl/kernfs/kernfs.go b/pkg/sentry/fsimpl/kernfs/kernfs.go index 14bf43ede..96dfb03c7 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs.go @@ -66,10 +66,12 @@ import ( // Filesystem mostly implements vfs.FilesystemImpl for a generic in-memory // filesystem. Concrete implementations are expected to embed this in their own // Filesystem type. +// +// +stateify savable type Filesystem struct { vfsfs vfs.Filesystem - droppedDentriesMu sync.Mutex + droppedDentriesMu sync.Mutex `state:"nosave"` // droppedDentries is a list of dentries waiting to be DecRef()ed. This is // used to defer dentry destruction until mu can be acquired for @@ -97,7 +99,7 @@ type Filesystem struct { // defer fs.mu.RUnlock() // ... // fs.deferDecRef(dentry) - mu sync.RWMutex + mu sync.RWMutex `state:"nosave"` // nextInoMinusOne is used to to allocate inode numbers on this // filesystem. Must be accessed by atomic operations. @@ -160,6 +162,8 @@ const ( // to, and child dentries hold a reference on their parent. // // Must be initialized by Init prior to first use. +// +// +stateify savable type Dentry struct { DentryRefs @@ -173,7 +177,7 @@ type Dentry struct { name string // dirMu protects children and the names of child Dentries. - dirMu sync.Mutex + dirMu sync.Mutex `state:"nosave"` children map[string]*Dentry inode Inode diff --git a/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go b/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go index 31cf0f33c..f42662d2d 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go @@ -105,6 +105,337 @@ func (x *DynamicBytesFD) StateLoad(m state.Source) { m.Load(4, &x.inode) } +func (x *SeekEndConfig) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.SeekEndConfig" +} + +func (x *SeekEndConfig) StateFields() []string { + return nil +} + +func (x *GenericDirectoryFDOptions) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.GenericDirectoryFDOptions" +} + +func (x *GenericDirectoryFDOptions) StateFields() []string { + return []string{ + "SeekEnd", + } +} + +func (x *GenericDirectoryFDOptions) beforeSave() {} + +func (x *GenericDirectoryFDOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.SeekEnd) +} + +func (x *GenericDirectoryFDOptions) afterLoad() {} + +func (x *GenericDirectoryFDOptions) StateLoad(m state.Source) { + m.Load(0, &x.SeekEnd) +} + +func (x *GenericDirectoryFD) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.GenericDirectoryFD" +} + +func (x *GenericDirectoryFD) StateFields() []string { + return []string{ + "FileDescriptionDefaultImpl", + "DirectoryFileDescriptionDefaultImpl", + "LockFD", + "seekEnd", + "vfsfd", + "children", + "off", + } +} + +func (x *GenericDirectoryFD) beforeSave() {} + +func (x *GenericDirectoryFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.FileDescriptionDefaultImpl) + m.Save(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) + m.Save(3, &x.seekEnd) + m.Save(4, &x.vfsfd) + m.Save(5, &x.children) + m.Save(6, &x.off) +} + +func (x *GenericDirectoryFD) afterLoad() {} + +func (x *GenericDirectoryFD) StateLoad(m state.Source) { + m.Load(0, &x.FileDescriptionDefaultImpl) + m.Load(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) + m.Load(3, &x.seekEnd) + m.Load(4, &x.vfsfd) + m.Load(5, &x.children) + m.Load(6, &x.off) +} + +func (x *InodeNoopRefCount) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeNoopRefCount" +} + +func (x *InodeNoopRefCount) StateFields() []string { + return []string{} +} + +func (x *InodeNoopRefCount) beforeSave() {} + +func (x *InodeNoopRefCount) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *InodeNoopRefCount) afterLoad() {} + +func (x *InodeNoopRefCount) StateLoad(m state.Source) { +} + +func (x *InodeDirectoryNoNewChildren) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeDirectoryNoNewChildren" +} + +func (x *InodeDirectoryNoNewChildren) StateFields() []string { + return []string{} +} + +func (x *InodeDirectoryNoNewChildren) beforeSave() {} + +func (x *InodeDirectoryNoNewChildren) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *InodeDirectoryNoNewChildren) afterLoad() {} + +func (x *InodeDirectoryNoNewChildren) StateLoad(m state.Source) { +} + +func (x *InodeNotDirectory) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeNotDirectory" +} + +func (x *InodeNotDirectory) StateFields() []string { + return []string{} +} + +func (x *InodeNotDirectory) beforeSave() {} + +func (x *InodeNotDirectory) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *InodeNotDirectory) afterLoad() {} + +func (x *InodeNotDirectory) StateLoad(m state.Source) { +} + +func (x *InodeNoDynamicLookup) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeNoDynamicLookup" +} + +func (x *InodeNoDynamicLookup) StateFields() []string { + return []string{} +} + +func (x *InodeNoDynamicLookup) beforeSave() {} + +func (x *InodeNoDynamicLookup) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *InodeNoDynamicLookup) afterLoad() {} + +func (x *InodeNoDynamicLookup) StateLoad(m state.Source) { +} + +func (x *InodeNotSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeNotSymlink" +} + +func (x *InodeNotSymlink) StateFields() []string { + return []string{} +} + +func (x *InodeNotSymlink) beforeSave() {} + +func (x *InodeNotSymlink) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *InodeNotSymlink) afterLoad() {} + +func (x *InodeNotSymlink) StateLoad(m state.Source) { +} + +func (x *InodeAttrs) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeAttrs" +} + +func (x *InodeAttrs) StateFields() []string { + return []string{ + "devMajor", + "devMinor", + "ino", + "mode", + "uid", + "gid", + "nlink", + } +} + +func (x *InodeAttrs) beforeSave() {} + +func (x *InodeAttrs) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.devMajor) + m.Save(1, &x.devMinor) + m.Save(2, &x.ino) + m.Save(3, &x.mode) + m.Save(4, &x.uid) + m.Save(5, &x.gid) + m.Save(6, &x.nlink) +} + +func (x *InodeAttrs) afterLoad() {} + +func (x *InodeAttrs) StateLoad(m state.Source) { + m.Load(0, &x.devMajor) + m.Load(1, &x.devMinor) + m.Load(2, &x.ino) + m.Load(3, &x.mode) + m.Load(4, &x.uid) + m.Load(5, &x.gid) + m.Load(6, &x.nlink) +} + +func (x *slot) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.slot" +} + +func (x *slot) StateFields() []string { + return []string{ + "Name", + "Dentry", + "slotEntry", + } +} + +func (x *slot) beforeSave() {} + +func (x *slot) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Name) + m.Save(1, &x.Dentry) + m.Save(2, &x.slotEntry) +} + +func (x *slot) afterLoad() {} + +func (x *slot) StateLoad(m state.Source) { + m.Load(0, &x.Name) + m.Load(1, &x.Dentry) + m.Load(2, &x.slotEntry) +} + +func (x *OrderedChildrenOptions) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.OrderedChildrenOptions" +} + +func (x *OrderedChildrenOptions) StateFields() []string { + return []string{ + "Writable", + } +} + +func (x *OrderedChildrenOptions) beforeSave() {} + +func (x *OrderedChildrenOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Writable) +} + +func (x *OrderedChildrenOptions) afterLoad() {} + +func (x *OrderedChildrenOptions) StateLoad(m state.Source) { + m.Load(0, &x.Writable) +} + +func (x *OrderedChildren) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.OrderedChildren" +} + +func (x *OrderedChildren) StateFields() []string { + return []string{ + "writable", + "order", + "set", + } +} + +func (x *OrderedChildren) beforeSave() {} + +func (x *OrderedChildren) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.writable) + m.Save(1, &x.order) + m.Save(2, &x.set) +} + +func (x *OrderedChildren) afterLoad() {} + +func (x *OrderedChildren) StateLoad(m state.Source) { + m.Load(0, &x.writable) + m.Load(1, &x.order) + m.Load(2, &x.set) +} + +func (x *renameAcrossDifferentImplementationsError) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.renameAcrossDifferentImplementationsError" +} + +func (x *renameAcrossDifferentImplementationsError) StateFields() []string { + return []string{} +} + +func (x *renameAcrossDifferentImplementationsError) beforeSave() {} + +func (x *renameAcrossDifferentImplementationsError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *renameAcrossDifferentImplementationsError) afterLoad() {} + +func (x *renameAcrossDifferentImplementationsError) StateLoad(m state.Source) { +} + +func (x *InodeSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeSymlink" +} + +func (x *InodeSymlink) StateFields() []string { + return []string{ + "InodeNotDirectory", + } +} + +func (x *InodeSymlink) beforeSave() {} + +func (x *InodeSymlink) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.InodeNotDirectory) +} + +func (x *InodeSymlink) afterLoad() {} + +func (x *InodeSymlink) StateLoad(m state.Source) { + m.Load(0, &x.InodeNotDirectory) +} + func (x *StaticDirectory) StateTypeName() string { return "pkg/sentry/fsimpl/kernfs.StaticDirectory" } @@ -152,6 +483,114 @@ func (x *StaticDirectory) StateLoad(m state.Source) { m.Load(8, &x.fdOpts) } +func (x *AlwaysValid) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.AlwaysValid" +} + +func (x *AlwaysValid) StateFields() []string { + return []string{} +} + +func (x *AlwaysValid) beforeSave() {} + +func (x *AlwaysValid) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *AlwaysValid) afterLoad() {} + +func (x *AlwaysValid) StateLoad(m state.Source) { +} + +func (x *InodeNoStatFS) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.InodeNoStatFS" +} + +func (x *InodeNoStatFS) StateFields() []string { + return []string{} +} + +func (x *InodeNoStatFS) beforeSave() {} + +func (x *InodeNoStatFS) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *InodeNoStatFS) afterLoad() {} + +func (x *InodeNoStatFS) StateLoad(m state.Source) { +} + +func (x *Filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.Filesystem" +} + +func (x *Filesystem) StateFields() []string { + return []string{ + "vfsfs", + "droppedDentries", + "nextInoMinusOne", + } +} + +func (x *Filesystem) beforeSave() {} + +func (x *Filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfs) + m.Save(1, &x.droppedDentries) + m.Save(2, &x.nextInoMinusOne) +} + +func (x *Filesystem) afterLoad() {} + +func (x *Filesystem) StateLoad(m state.Source) { + m.Load(0, &x.vfsfs) + m.Load(1, &x.droppedDentries) + m.Load(2, &x.nextInoMinusOne) +} + +func (x *Dentry) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.Dentry" +} + +func (x *Dentry) StateFields() []string { + return []string{ + "DentryRefs", + "vfsd", + "flags", + "parent", + "name", + "children", + "inode", + } +} + +func (x *Dentry) beforeSave() {} + +func (x *Dentry) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.DentryRefs) + m.Save(1, &x.vfsd) + m.Save(2, &x.flags) + m.Save(3, &x.parent) + m.Save(4, &x.name) + m.Save(5, &x.children) + m.Save(6, &x.inode) +} + +func (x *Dentry) afterLoad() {} + +func (x *Dentry) StateLoad(m state.Source) { + m.Load(0, &x.DentryRefs) + m.Load(1, &x.vfsd) + m.Load(2, &x.flags) + m.Load(3, &x.parent) + m.Load(4, &x.name) + m.Load(5, &x.children) + m.Load(6, &x.inode) +} + func (x *slotList) StateTypeName() string { return "pkg/sentry/fsimpl/kernfs.slotList" } @@ -227,6 +666,41 @@ func (x *StaticDirectoryRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *StaticSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/kernfs.StaticSymlink" +} + +func (x *StaticSymlink) StateFields() []string { + return []string{ + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "InodeNoStatFS", + "target", + } +} + +func (x *StaticSymlink) beforeSave() {} + +func (x *StaticSymlink) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.InodeAttrs) + m.Save(1, &x.InodeNoopRefCount) + m.Save(2, &x.InodeSymlink) + m.Save(3, &x.InodeNoStatFS) + m.Save(4, &x.target) +} + +func (x *StaticSymlink) afterLoad() {} + +func (x *StaticSymlink) StateLoad(m state.Source) { + m.Load(0, &x.InodeAttrs) + m.Load(1, &x.InodeNoopRefCount) + m.Load(2, &x.InodeSymlink) + m.Load(3, &x.InodeNoStatFS) + m.Load(4, &x.target) +} + func (x *syntheticDirectory) StateTypeName() string { return "pkg/sentry/fsimpl/kernfs.syntheticDirectory" } @@ -272,9 +746,28 @@ func init() { state.Register((*DentryRefs)(nil)) state.Register((*DynamicBytesFile)(nil)) state.Register((*DynamicBytesFD)(nil)) + state.Register((*SeekEndConfig)(nil)) + state.Register((*GenericDirectoryFDOptions)(nil)) + state.Register((*GenericDirectoryFD)(nil)) + state.Register((*InodeNoopRefCount)(nil)) + state.Register((*InodeDirectoryNoNewChildren)(nil)) + state.Register((*InodeNotDirectory)(nil)) + state.Register((*InodeNoDynamicLookup)(nil)) + state.Register((*InodeNotSymlink)(nil)) + state.Register((*InodeAttrs)(nil)) + state.Register((*slot)(nil)) + state.Register((*OrderedChildrenOptions)(nil)) + state.Register((*OrderedChildren)(nil)) + state.Register((*renameAcrossDifferentImplementationsError)(nil)) + state.Register((*InodeSymlink)(nil)) state.Register((*StaticDirectory)(nil)) + state.Register((*AlwaysValid)(nil)) + state.Register((*InodeNoStatFS)(nil)) + state.Register((*Filesystem)(nil)) + state.Register((*Dentry)(nil)) state.Register((*slotList)(nil)) state.Register((*slotEntry)(nil)) state.Register((*StaticDirectoryRefs)(nil)) + state.Register((*StaticSymlink)(nil)) state.Register((*syntheticDirectory)(nil)) } diff --git a/pkg/sentry/fsimpl/kernfs/symlink.go b/pkg/sentry/fsimpl/kernfs/symlink.go index 443121c99..58a93eaac 100644 --- a/pkg/sentry/fsimpl/kernfs/symlink.go +++ b/pkg/sentry/fsimpl/kernfs/symlink.go @@ -24,6 +24,8 @@ import ( // StaticSymlink provides an Inode implementation for symlinks that point to // a immutable target. +// +// +stateify savable type StaticSymlink struct { InodeAttrs InodeNoopRefCount diff --git a/pkg/sentry/fsimpl/overlay/directory.go b/pkg/sentry/fsimpl/overlay/directory.go index 7ab42e71e..aea599460 100644 --- a/pkg/sentry/fsimpl/overlay/directory.go +++ b/pkg/sentry/fsimpl/overlay/directory.go @@ -100,12 +100,13 @@ func (d *dentry) collectWhiteoutsForRmdirLocked(ctx context.Context) (map[string return whiteouts, readdirErr } +// +stateify savable type directoryFD struct { fileDescription vfs.DirectoryFileDescriptionDefaultImpl vfs.DentryMetadataFileDescriptionImpl - mu sync.Mutex + mu sync.Mutex `state:"nosave"` off int64 dirents []vfs.Dirent } diff --git a/pkg/sentry/fsimpl/overlay/non_directory.go b/pkg/sentry/fsimpl/overlay/non_directory.go index 6e04705c7..50b4a50f1 100644 --- a/pkg/sentry/fsimpl/overlay/non_directory.go +++ b/pkg/sentry/fsimpl/overlay/non_directory.go @@ -39,6 +39,7 @@ func (d *dentry) readlink(ctx context.Context) (string, error) { }) } +// +stateify savable type nonDirectoryFD struct { fileDescription @@ -47,7 +48,7 @@ type nonDirectoryFD struct { // fileDescription.dentry().upperVD. cachedFlags is the last known value of // cachedFD.StatusFlags(). copiedUp, cachedFD, and cachedFlags are // protected by mu. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` copiedUp bool cachedFD *vfs.FileDescription cachedFlags uint32 diff --git a/pkg/sentry/fsimpl/overlay/overlay.go b/pkg/sentry/fsimpl/overlay/overlay.go index d0d26185e..b03fa9121 100644 --- a/pkg/sentry/fsimpl/overlay/overlay.go +++ b/pkg/sentry/fsimpl/overlay/overlay.go @@ -51,6 +51,8 @@ import ( const Name = "overlay" // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct{} // Name implements vfs.FilesystemType.Name. @@ -60,6 +62,8 @@ func (FilesystemType) Name() string { // FilesystemOptions may be passed as vfs.GetFilesystemOptions.InternalData to // FilesystemType.GetFilesystem. +// +// +stateify savable type FilesystemOptions struct { // Callers passing FilesystemOptions to // overlay.FilesystemType.GetFilesystem() are responsible for ensuring that @@ -76,6 +80,8 @@ type FilesystemOptions struct { } // filesystem implements vfs.FilesystemImpl. +// +// +stateify savable type filesystem struct { vfsfs vfs.Filesystem @@ -98,7 +104,7 @@ type filesystem struct { // renameMu synchronizes renaming with non-renaming operations in order to // ensure consistent lock ordering between dentry.dirMu in different // dentries. - renameMu sync.RWMutex + renameMu sync.RWMutex `state:"nosave"` // lastDirIno is the last inode number assigned to a directory. lastDirIno // is accessed using atomic memory operations. @@ -367,6 +373,8 @@ func (fs *filesystem) newDirIno() uint64 { } // dentry implements vfs.DentryImpl. +// +// +stateify savable type dentry struct { vfsd vfs.Dentry @@ -399,7 +407,7 @@ type dentry struct { // and dirents (if not nil) is a cache of dirents as returned by // directoryFDs representing this directory. children is protected by // dirMu. - dirMu sync.Mutex + dirMu sync.Mutex `state:"nosave"` children map[string]*dentry dirents []vfs.Dirent @@ -409,7 +417,7 @@ type dentry struct { // If !upperVD.Ok(), it can transition to a valid vfs.VirtualDentry (i.e. // be copied up) with copyMu locked for writing; otherwise, it is // immutable. lowerVDs is always immutable. - copyMu sync.RWMutex + copyMu sync.RWMutex `state:"nosave"` upperVD vfs.VirtualDentry lowerVDs []vfs.VirtualDentry @@ -652,6 +660,8 @@ func (d *dentry) updateAfterSetStatLocked(opts *vfs.SetStatOptions) { // fileDescription is embedded by overlay implementations of // vfs.FileDescriptionImpl. +// +// +stateify savable type fileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/overlay/overlay_state_autogen.go b/pkg/sentry/fsimpl/overlay/overlay_state_autogen.go index 0c184964f..5fd2dc37e 100644 --- a/pkg/sentry/fsimpl/overlay/overlay_state_autogen.go +++ b/pkg/sentry/fsimpl/overlay/overlay_state_autogen.go @@ -1,3 +1,285 @@ // automatically generated by stateify. package overlay + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *directoryFD) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.directoryFD" +} + +func (x *directoryFD) StateFields() []string { + return []string{ + "fileDescription", + "DirectoryFileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "off", + "dirents", + } +} + +func (x *directoryFD) beforeSave() {} + +func (x *directoryFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.off) + m.Save(4, &x.dirents) +} + +func (x *directoryFD) afterLoad() {} + +func (x *directoryFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.off) + m.Load(4, &x.dirents) +} + +func (x *nonDirectoryFD) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.nonDirectoryFD" +} + +func (x *nonDirectoryFD) StateFields() []string { + return []string{ + "fileDescription", + "copiedUp", + "cachedFD", + "cachedFlags", + } +} + +func (x *nonDirectoryFD) beforeSave() {} + +func (x *nonDirectoryFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.copiedUp) + m.Save(2, &x.cachedFD) + m.Save(3, &x.cachedFlags) +} + +func (x *nonDirectoryFD) afterLoad() {} + +func (x *nonDirectoryFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.copiedUp) + m.Load(2, &x.cachedFD) + m.Load(3, &x.cachedFlags) +} + +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{} +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { +} + +func (x *FilesystemOptions) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.FilesystemOptions" +} + +func (x *FilesystemOptions) StateFields() []string { + return []string{ + "UpperRoot", + "LowerRoots", + } +} + +func (x *FilesystemOptions) beforeSave() {} + +func (x *FilesystemOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.UpperRoot) + m.Save(1, &x.LowerRoots) +} + +func (x *FilesystemOptions) afterLoad() {} + +func (x *FilesystemOptions) StateLoad(m state.Source) { + m.Load(0, &x.UpperRoot) + m.Load(1, &x.LowerRoots) +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "vfsfs", + "opts", + "creds", + "dirDevMinor", + "lowerDevMinors", + "lastDirIno", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfs) + m.Save(1, &x.opts) + m.Save(2, &x.creds) + m.Save(3, &x.dirDevMinor) + m.Save(4, &x.lowerDevMinors) + m.Save(5, &x.lastDirIno) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.vfsfs) + m.Load(1, &x.opts) + m.Load(2, &x.creds) + m.Load(3, &x.dirDevMinor) + m.Load(4, &x.lowerDevMinors) + m.Load(5, &x.lastDirIno) +} + +func (x *dentry) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.dentry" +} + +func (x *dentry) StateFields() []string { + return []string{ + "vfsd", + "refs", + "fs", + "mode", + "uid", + "gid", + "copiedUp", + "parent", + "name", + "children", + "dirents", + "upperVD", + "lowerVDs", + "inlineLowerVDs", + "devMajor", + "devMinor", + "ino", + "mapsMu", + "lowerMappings", + "dataMu", + "wrappedMappable", + "isMappable", + "locks", + } +} + +func (x *dentry) beforeSave() {} + +func (x *dentry) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsd) + m.Save(1, &x.refs) + m.Save(2, &x.fs) + m.Save(3, &x.mode) + m.Save(4, &x.uid) + m.Save(5, &x.gid) + m.Save(6, &x.copiedUp) + m.Save(7, &x.parent) + m.Save(8, &x.name) + m.Save(9, &x.children) + m.Save(10, &x.dirents) + m.Save(11, &x.upperVD) + m.Save(12, &x.lowerVDs) + m.Save(13, &x.inlineLowerVDs) + m.Save(14, &x.devMajor) + m.Save(15, &x.devMinor) + m.Save(16, &x.ino) + m.Save(17, &x.mapsMu) + m.Save(18, &x.lowerMappings) + m.Save(19, &x.dataMu) + m.Save(20, &x.wrappedMappable) + m.Save(21, &x.isMappable) + m.Save(22, &x.locks) +} + +func (x *dentry) afterLoad() {} + +func (x *dentry) StateLoad(m state.Source) { + m.Load(0, &x.vfsd) + m.Load(1, &x.refs) + m.Load(2, &x.fs) + m.Load(3, &x.mode) + m.Load(4, &x.uid) + m.Load(5, &x.gid) + m.Load(6, &x.copiedUp) + m.Load(7, &x.parent) + m.Load(8, &x.name) + m.Load(9, &x.children) + m.Load(10, &x.dirents) + m.Load(11, &x.upperVD) + m.Load(12, &x.lowerVDs) + m.Load(13, &x.inlineLowerVDs) + m.Load(14, &x.devMajor) + m.Load(15, &x.devMinor) + m.Load(16, &x.ino) + m.Load(17, &x.mapsMu) + m.Load(18, &x.lowerMappings) + m.Load(19, &x.dataMu) + m.Load(20, &x.wrappedMappable) + m.Load(21, &x.isMappable) + m.Load(22, &x.locks) +} + +func (x *fileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/overlay.fileDescription" +} + +func (x *fileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + } +} + +func (x *fileDescription) beforeSave() {} + +func (x *fileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) +} + +func (x *fileDescription) afterLoad() {} + +func (x *fileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) +} + +func init() { + state.Register((*directoryFD)(nil)) + state.Register((*nonDirectoryFD)(nil)) + state.Register((*FilesystemType)(nil)) + state.Register((*FilesystemOptions)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*dentry)(nil)) + state.Register((*fileDescription)(nil)) +} diff --git a/pkg/sentry/fsimpl/pipefs/pipefs.go b/pkg/sentry/fsimpl/pipefs/pipefs.go index 33e247578..4e2da4810 100644 --- a/pkg/sentry/fsimpl/pipefs/pipefs.go +++ b/pkg/sentry/fsimpl/pipefs/pipefs.go @@ -31,6 +31,7 @@ import ( "gvisor.dev/gvisor/pkg/usermem" ) +// +stateify savable type filesystemType struct{} // Name implements vfs.FilesystemType.Name. @@ -43,6 +44,7 @@ func (filesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFile panic("pipefs.filesystemType.GetFilesystem should never be called") } +// +stateify savable type filesystem struct { kernfs.Filesystem @@ -76,6 +78,8 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe } // inode implements kernfs.Inode. +// +// +stateify savable type inode struct { kernfs.InodeNotDirectory kernfs.InodeNotSymlink diff --git a/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go b/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go index e3e3887cd..bdb899396 100644 --- a/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go +++ b/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go @@ -1,3 +1,105 @@ // automatically generated by stateify. package pipefs + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *filesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/pipefs.filesystemType" +} + +func (x *filesystemType) StateFields() []string { + return []string{} +} + +func (x *filesystemType) beforeSave() {} + +func (x *filesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *filesystemType) afterLoad() {} + +func (x *filesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/pipefs.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) +} + +func (x *inode) StateTypeName() string { + return "pkg/sentry/fsimpl/pipefs.inode" +} + +func (x *inode) StateFields() []string { + return []string{ + "InodeNotDirectory", + "InodeNotSymlink", + "InodeNoopRefCount", + "locks", + "pipe", + "ino", + "uid", + "gid", + "ctime", + } +} + +func (x *inode) beforeSave() {} + +func (x *inode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.InodeNotDirectory) + m.Save(1, &x.InodeNotSymlink) + m.Save(2, &x.InodeNoopRefCount) + m.Save(3, &x.locks) + m.Save(4, &x.pipe) + m.Save(5, &x.ino) + m.Save(6, &x.uid) + m.Save(7, &x.gid) + m.Save(8, &x.ctime) +} + +func (x *inode) afterLoad() {} + +func (x *inode) StateLoad(m state.Source) { + m.Load(0, &x.InodeNotDirectory) + m.Load(1, &x.InodeNotSymlink) + m.Load(2, &x.InodeNoopRefCount) + m.Load(3, &x.locks) + m.Load(4, &x.pipe) + m.Load(5, &x.ino) + m.Load(6, &x.uid) + m.Load(7, &x.gid) + m.Load(8, &x.ctime) +} + +func init() { + state.Register((*filesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*inode)(nil)) +} diff --git a/pkg/sentry/fsimpl/proc/filesystem.go b/pkg/sentry/fsimpl/proc/filesystem.go index 03b5941b9..05d7948ea 100644 --- a/pkg/sentry/fsimpl/proc/filesystem.go +++ b/pkg/sentry/fsimpl/proc/filesystem.go @@ -41,6 +41,7 @@ func (FilesystemType) Name() string { return Name } +// +stateify savable type filesystem struct { kernfs.Filesystem @@ -84,6 +85,8 @@ func (fs *filesystem) Release(ctx context.Context) { // dynamicInode is an overfitted interface for common Inodes with // dynamicByteSource types used in procfs. +// +// +stateify savable type dynamicInode interface { kernfs.Inode vfs.DynamicBytesSource @@ -99,6 +102,7 @@ func (fs *filesystem) newDentry(creds *auth.Credentials, ino uint64, perm linux. return d } +// +stateify savable type staticFile struct { kernfs.DynamicBytesFile vfs.StaticData @@ -118,10 +122,13 @@ func newStaticDir(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64 // InternalData contains internal data passed in to the procfs mount via // vfs.GetFilesystemOptions.InternalData. +// +// +stateify savable type InternalData struct { Cgroups map[string]string } +// +stateify savable type implStatFS struct{} // StatFS implements kernfs.Inode.StatFS. diff --git a/pkg/sentry/fsimpl/proc/proc_state_autogen.go b/pkg/sentry/fsimpl/proc/proc_state_autogen.go index 60a5644f3..3eea5708c 100644 --- a/pkg/sentry/fsimpl/proc/proc_state_autogen.go +++ b/pkg/sentry/fsimpl/proc/proc_state_autogen.go @@ -71,6 +71,100 @@ func (x *FilesystemType) afterLoad() {} func (x *FilesystemType) StateLoad(m state.Source) { } +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) +} + +func (x *staticFile) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.staticFile" +} + +func (x *staticFile) StateFields() []string { + return []string{ + "DynamicBytesFile", + "StaticData", + } +} + +func (x *staticFile) beforeSave() {} + +func (x *staticFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.DynamicBytesFile) + m.Save(1, &x.StaticData) +} + +func (x *staticFile) afterLoad() {} + +func (x *staticFile) StateLoad(m state.Source) { + m.Load(0, &x.DynamicBytesFile) + m.Load(1, &x.StaticData) +} + +func (x *InternalData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.InternalData" +} + +func (x *InternalData) StateFields() []string { + return []string{ + "Cgroups", + } +} + +func (x *InternalData) beforeSave() {} + +func (x *InternalData) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Cgroups) +} + +func (x *InternalData) afterLoad() {} + +func (x *InternalData) StateLoad(m state.Source) { + m.Load(0, &x.Cgroups) +} + +func (x *implStatFS) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.implStatFS" +} + +func (x *implStatFS) StateFields() []string { + return []string{} +} + +func (x *implStatFS) beforeSave() {} + +func (x *implStatFS) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *implStatFS) afterLoad() {} + +func (x *implStatFS) StateLoad(m state.Source) { +} + func (x *subtasksInode) StateTypeName() string { return "pkg/sentry/fsimpl/proc.subtasksInode" } @@ -127,6 +221,32 @@ func (x *subtasksInode) StateLoad(m state.Source) { m.Load(11, &x.cgroupControllers) } +func (x *subtasksFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.subtasksFD" +} + +func (x *subtasksFD) StateFields() []string { + return []string{ + "GenericDirectoryFD", + "task", + } +} + +func (x *subtasksFD) beforeSave() {} + +func (x *subtasksFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.GenericDirectoryFD) + m.Save(1, &x.task) +} + +func (x *subtasksFD) afterLoad() {} + +func (x *subtasksFD) StateLoad(m state.Source) { + m.Load(0, &x.GenericDirectoryFD) + m.Load(1, &x.task) +} + func (x *subtasksInodeRefs) StateTypeName() string { return "pkg/sentry/fsimpl/proc.subtasksInodeRefs" } @@ -197,6 +317,64 @@ func (x *taskInode) StateLoad(m state.Source) { m.Load(8, &x.task) } +func (x *taskOwnedInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.taskOwnedInode" +} + +func (x *taskOwnedInode) StateFields() []string { + return []string{ + "Inode", + "owner", + } +} + +func (x *taskOwnedInode) beforeSave() {} + +func (x *taskOwnedInode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Inode) + m.Save(1, &x.owner) +} + +func (x *taskOwnedInode) afterLoad() {} + +func (x *taskOwnedInode) StateLoad(m state.Source) { + m.Load(0, &x.Inode) + m.Load(1, &x.owner) +} + +func (x *fdDir) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdDir" +} + +func (x *fdDir) StateFields() []string { + return []string{ + "locks", + "fs", + "task", + "produceSymlink", + } +} + +func (x *fdDir) beforeSave() {} + +func (x *fdDir) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.locks) + m.Save(1, &x.fs) + m.Save(2, &x.task) + m.Save(3, &x.produceSymlink) +} + +func (x *fdDir) afterLoad() {} + +func (x *fdDir) StateLoad(m state.Source) { + m.Load(0, &x.locks) + m.Load(1, &x.fs) + m.Load(2, &x.task) + m.Load(3, &x.produceSymlink) +} + func (x *fdDirInode) StateTypeName() string { return "pkg/sentry/fsimpl/proc.fdDirInode" } @@ -766,6 +944,102 @@ func (x *mountsData) StateLoad(m state.Source) { m.Load(1, &x.task) } +func (x *namespaceSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.namespaceSymlink" +} + +func (x *namespaceSymlink) StateFields() []string { + return []string{ + "StaticSymlink", + "task", + } +} + +func (x *namespaceSymlink) beforeSave() {} + +func (x *namespaceSymlink) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.StaticSymlink) + m.Save(1, &x.task) +} + +func (x *namespaceSymlink) afterLoad() {} + +func (x *namespaceSymlink) StateLoad(m state.Source) { + m.Load(0, &x.StaticSymlink) + m.Load(1, &x.task) +} + +func (x *namespaceInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.namespaceInode" +} + +func (x *namespaceInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "locks", + } +} + +func (x *namespaceInode) beforeSave() {} + +func (x *namespaceInode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeNoopRefCount) + m.Save(3, &x.InodeNotDirectory) + m.Save(4, &x.InodeNotSymlink) + m.Save(5, &x.locks) +} + +func (x *namespaceInode) afterLoad() {} + +func (x *namespaceInode) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeNoopRefCount) + m.Load(3, &x.InodeNotDirectory) + m.Load(4, &x.InodeNotSymlink) + m.Load(5, &x.locks) +} + +func (x *namespaceFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.namespaceFD" +} + +func (x *namespaceFD) StateFields() []string { + return []string{ + "FileDescriptionDefaultImpl", + "LockFD", + "vfsfd", + "inode", + } +} + +func (x *namespaceFD) beforeSave() {} + +func (x *namespaceFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.FileDescriptionDefaultImpl) + m.Save(1, &x.LockFD) + m.Save(2, &x.vfsfd) + m.Save(3, &x.inode) +} + +func (x *namespaceFD) afterLoad() {} + +func (x *namespaceFD) StateLoad(m state.Source) { + m.Load(0, &x.FileDescriptionDefaultImpl) + m.Load(1, &x.LockFD) + m.Load(2, &x.vfsfd) + m.Load(3, &x.inode) +} + func (x *taskInodeRefs) StateTypeName() string { return "pkg/sentry/fsimpl/proc.taskInodeRefs" } @@ -971,6 +1245,32 @@ func (x *netSnmpData) StateLoad(m state.Source) { m.Load(1, &x.stack) } +func (x *snmpLine) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.snmpLine" +} + +func (x *snmpLine) StateFields() []string { + return []string{ + "prefix", + "header", + } +} + +func (x *snmpLine) beforeSave() {} + +func (x *snmpLine) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.prefix) + m.Save(1, &x.header) +} + +func (x *snmpLine) afterLoad() {} + +func (x *snmpLine) StateLoad(m state.Source) { + m.Load(0, &x.prefix) + m.Load(1, &x.header) +} + func (x *netRouteData) StateTypeName() string { return "pkg/sentry/fsimpl/proc.netRouteData" } @@ -1082,6 +1382,175 @@ func (x *tasksInode) StateLoad(m state.Source) { m.Load(12, &x.cgroupControllers) } +func (x *staticFileSetStat) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.staticFileSetStat" +} + +func (x *staticFileSetStat) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + "StaticData", + } +} + +func (x *staticFileSetStat) beforeSave() {} + +func (x *staticFileSetStat) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.dynamicBytesFileSetAttr) + m.Save(1, &x.StaticData) +} + +func (x *staticFileSetStat) afterLoad() {} + +func (x *staticFileSetStat) StateLoad(m state.Source) { + m.Load(0, &x.dynamicBytesFileSetAttr) + m.Load(1, &x.StaticData) +} + +func (x *selfSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.selfSymlink" +} + +func (x *selfSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "pidns", + } +} + +func (x *selfSymlink) beforeSave() {} + +func (x *selfSymlink) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeNoopRefCount) + m.Save(3, &x.InodeSymlink) + m.Save(4, &x.pidns) +} + +func (x *selfSymlink) afterLoad() {} + +func (x *selfSymlink) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeNoopRefCount) + m.Load(3, &x.InodeSymlink) + m.Load(4, &x.pidns) +} + +func (x *threadSelfSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.threadSelfSymlink" +} + +func (x *threadSelfSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "pidns", + } +} + +func (x *threadSelfSymlink) beforeSave() {} + +func (x *threadSelfSymlink) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeNoopRefCount) + m.Save(3, &x.InodeSymlink) + m.Save(4, &x.pidns) +} + +func (x *threadSelfSymlink) afterLoad() {} + +func (x *threadSelfSymlink) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeNoopRefCount) + m.Load(3, &x.InodeSymlink) + m.Load(4, &x.pidns) +} + +func (x *dynamicBytesFileSetAttr) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.dynamicBytesFileSetAttr" +} + +func (x *dynamicBytesFileSetAttr) StateFields() []string { + return []string{ + "DynamicBytesFile", + } +} + +func (x *dynamicBytesFileSetAttr) beforeSave() {} + +func (x *dynamicBytesFileSetAttr) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.DynamicBytesFile) +} + +func (x *dynamicBytesFileSetAttr) afterLoad() {} + +func (x *dynamicBytesFileSetAttr) StateLoad(m state.Source) { + m.Load(0, &x.DynamicBytesFile) +} + +func (x *cpuStats) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.cpuStats" +} + +func (x *cpuStats) StateFields() []string { + return []string{ + "user", + "nice", + "system", + "idle", + "ioWait", + "irq", + "softirq", + "steal", + "guest", + "guestNice", + } +} + +func (x *cpuStats) beforeSave() {} + +func (x *cpuStats) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.user) + m.Save(1, &x.nice) + m.Save(2, &x.system) + m.Save(3, &x.idle) + m.Save(4, &x.ioWait) + m.Save(5, &x.irq) + m.Save(6, &x.softirq) + m.Save(7, &x.steal) + m.Save(8, &x.guest) + m.Save(9, &x.guestNice) +} + +func (x *cpuStats) afterLoad() {} + +func (x *cpuStats) StateLoad(m state.Source) { + m.Load(0, &x.user) + m.Load(1, &x.nice) + m.Load(2, &x.system) + m.Load(3, &x.idle) + m.Load(4, &x.ioWait) + m.Load(5, &x.irq) + m.Load(6, &x.softirq) + m.Load(7, &x.steal) + m.Load(8, &x.guest) + m.Load(9, &x.guestNice) +} + func (x *statData) StateTypeName() string { return "pkg/sentry/fsimpl/proc.statData" } @@ -1243,6 +1712,14 @@ func (x *tasksInodeRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *tcpMemDir) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tcpMemDir" +} + +func (x *tcpMemDir) StateFields() []string { + return nil +} + func (x *mmapMinAddrData) StateTypeName() string { return "pkg/sentry/fsimpl/proc.mmapMinAddrData" } @@ -1409,9 +1886,16 @@ func init() { state.Register((*fdDirInodeRefs)(nil)) state.Register((*fdInfoDirInodeRefs)(nil)) state.Register((*FilesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*staticFile)(nil)) + state.Register((*InternalData)(nil)) + state.Register((*implStatFS)(nil)) state.Register((*subtasksInode)(nil)) + state.Register((*subtasksFD)(nil)) state.Register((*subtasksInodeRefs)(nil)) state.Register((*taskInode)(nil)) + state.Register((*taskOwnedInode)(nil)) + state.Register((*fdDir)(nil)) state.Register((*fdDirInode)(nil)) state.Register((*fdSymlink)(nil)) state.Register((*fdInfoDirInode)(nil)) @@ -1431,6 +1915,9 @@ func init() { state.Register((*exeSymlink)(nil)) state.Register((*mountInfoData)(nil)) state.Register((*mountsData)(nil)) + state.Register((*namespaceSymlink)(nil)) + state.Register((*namespaceInode)(nil)) + state.Register((*namespaceFD)(nil)) state.Register((*taskInodeRefs)(nil)) state.Register((*ifinet6)(nil)) state.Register((*netDevData)(nil)) @@ -1439,9 +1926,15 @@ func init() { state.Register((*netTCP6Data)(nil)) state.Register((*netUDPData)(nil)) state.Register((*netSnmpData)(nil)) + state.Register((*snmpLine)(nil)) state.Register((*netRouteData)(nil)) state.Register((*netStatData)(nil)) state.Register((*tasksInode)(nil)) + state.Register((*staticFileSetStat)(nil)) + state.Register((*selfSymlink)(nil)) + state.Register((*threadSelfSymlink)(nil)) + state.Register((*dynamicBytesFileSetAttr)(nil)) + state.Register((*cpuStats)(nil)) state.Register((*statData)(nil)) state.Register((*loadavgData)(nil)) state.Register((*meminfoData)(nil)) @@ -1449,6 +1942,7 @@ func init() { state.Register((*versionData)(nil)) state.Register((*filesystemsData)(nil)) state.Register((*tasksInodeRefs)(nil)) + state.Register((*tcpMemDir)(nil)) state.Register((*mmapMinAddrData)(nil)) state.Register((*hostnameData)(nil)) state.Register((*tcpSackData)(nil)) diff --git a/pkg/sentry/fsimpl/proc/subtasks.go b/pkg/sentry/fsimpl/proc/subtasks.go index 47dc0ac9a..47ecd941c 100644 --- a/pkg/sentry/fsimpl/proc/subtasks.go +++ b/pkg/sentry/fsimpl/proc/subtasks.go @@ -116,6 +116,7 @@ func (i *subtasksInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallb return offset, nil } +// +stateify savable type subtasksFD struct { kernfs.GenericDirectoryFD diff --git a/pkg/sentry/fsimpl/proc/task.go b/pkg/sentry/fsimpl/proc/task.go index ae461bb48..1f99183eb 100644 --- a/pkg/sentry/fsimpl/proc/task.go +++ b/pkg/sentry/fsimpl/proc/task.go @@ -129,6 +129,8 @@ func (i *taskInode) DecRef(context.Context) { // taskOwnedInode implements kernfs.Inode and overrides inode owner with task // effective user and group. +// +// +stateify savable type taskOwnedInode struct { kernfs.Inode diff --git a/pkg/sentry/fsimpl/proc/task_fds.go b/pkg/sentry/fsimpl/proc/task_fds.go index c7104458f..0866cea2b 100644 --- a/pkg/sentry/fsimpl/proc/task_fds.go +++ b/pkg/sentry/fsimpl/proc/task_fds.go @@ -51,6 +51,7 @@ func taskFDExists(ctx context.Context, t *kernel.Task, fd int32) bool { return true } +// +stateify savable type fdDir struct { locks vfs.FileLocks diff --git a/pkg/sentry/fsimpl/proc/task_files.go b/pkg/sentry/fsimpl/proc/task_files.go index feed5bc3f..b81c8279e 100644 --- a/pkg/sentry/fsimpl/proc/task_files.go +++ b/pkg/sentry/fsimpl/proc/task_files.go @@ -785,6 +785,7 @@ func (i *mountsData) Generate(ctx context.Context, buf *bytes.Buffer) error { return nil } +// +stateify savable type namespaceSymlink struct { kernfs.StaticSymlink @@ -832,6 +833,8 @@ func (s *namespaceSymlink) Getlink(ctx context.Context, mnt *vfs.Mount) (vfs.Vir // namespaceInode is a synthetic inode created to represent a namespace in // /proc/[pid]/ns/*. +// +// +stateify savable type namespaceInode struct { implStatFS kernfs.InodeAttrs @@ -865,6 +868,8 @@ func (i *namespaceInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *ker // namespace FD is a synthetic file that represents a namespace in // /proc/[pid]/ns/*. +// +// +stateify savable type namespaceFD struct { vfs.FileDescriptionDefaultImpl vfs.LockFD diff --git a/pkg/sentry/fsimpl/proc/task_net.go b/pkg/sentry/fsimpl/proc/task_net.go index 1607eac19..e7f748655 100644 --- a/pkg/sentry/fsimpl/proc/task_net.go +++ b/pkg/sentry/fsimpl/proc/task_net.go @@ -616,6 +616,7 @@ type netSnmpData struct { var _ dynamicInode = (*netSnmpData)(nil) +// +stateify savable type snmpLine struct { prefix string header string diff --git a/pkg/sentry/fsimpl/proc/tasks.go b/pkg/sentry/fsimpl/proc/tasks.go index ad08c3626..d8f5dd509 100644 --- a/pkg/sentry/fsimpl/proc/tasks.go +++ b/pkg/sentry/fsimpl/proc/tasks.go @@ -236,6 +236,8 @@ func (i *tasksInode) DecRef(context.Context) { // staticFileSetStat implements a special static file that allows inode // attributes to be set. This is to support /proc files that are readonly, but // allow attributes to be set. +// +// +stateify savable type staticFileSetStat struct { dynamicBytesFileSetAttr vfs.StaticData diff --git a/pkg/sentry/fsimpl/proc/tasks_files.go b/pkg/sentry/fsimpl/proc/tasks_files.go index 459a8e52e..f268c59b0 100644 --- a/pkg/sentry/fsimpl/proc/tasks_files.go +++ b/pkg/sentry/fsimpl/proc/tasks_files.go @@ -31,6 +31,7 @@ import ( "gvisor.dev/gvisor/pkg/usermem" ) +// +stateify savable type selfSymlink struct { implStatFS kernfs.InodeAttrs @@ -74,6 +75,7 @@ func (*selfSymlink) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, return syserror.EPERM } +// +stateify savable type threadSelfSymlink struct { implStatFS kernfs.InodeAttrs @@ -121,6 +123,8 @@ func (*threadSelfSymlink) SetStat(context.Context, *vfs.Filesystem, *auth.Creden // dynamicBytesFileSetAttr implements a special file that allows inode // attributes to be set. This is to support /proc files that are readonly, but // allow attributes to be set. +// +// +stateify savable type dynamicBytesFileSetAttr struct { kernfs.DynamicBytesFile } @@ -131,6 +135,8 @@ func (d *dynamicBytesFileSetAttr) SetStat(ctx context.Context, fs *vfs.Filesyste } // cpuStats contains the breakdown of CPU time for /proc/stat. +// +// +stateify savable type cpuStats struct { // user is time spent in userspace tasks with non-positive niceness. user uint64 diff --git a/pkg/sentry/fsimpl/proc/tasks_sys.go b/pkg/sentry/fsimpl/proc/tasks_sys.go index a3ffbb15e..3312b0418 100644 --- a/pkg/sentry/fsimpl/proc/tasks_sys.go +++ b/pkg/sentry/fsimpl/proc/tasks_sys.go @@ -31,6 +31,7 @@ import ( "gvisor.dev/gvisor/pkg/usermem" ) +// +stateify savable type tcpMemDir int const ( diff --git a/pkg/sentry/fsimpl/signalfd/signalfd.go b/pkg/sentry/fsimpl/signalfd/signalfd.go index 3c02af8c9..bf11b425a 100644 --- a/pkg/sentry/fsimpl/signalfd/signalfd.go +++ b/pkg/sentry/fsimpl/signalfd/signalfd.go @@ -27,6 +27,8 @@ import ( ) // SignalFileDescription implements vfs.FileDescriptionImpl for signal fds. +// +// +stateify savable type SignalFileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl @@ -43,7 +45,7 @@ type SignalFileDescription struct { target *kernel.Task // mu protects mask. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // mask is the signal mask. Protected by mu. mask linux.SignalSet diff --git a/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go b/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go index c3d9b2ffb..acd2ff5b4 100644 --- a/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go +++ b/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go @@ -1,3 +1,49 @@ // automatically generated by stateify. package signalfd + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *SignalFileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/signalfd.SignalFileDescription" +} + +func (x *SignalFileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + "target", + "mask", + } +} + +func (x *SignalFileDescription) beforeSave() {} + +func (x *SignalFileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) + m.Save(4, &x.target) + m.Save(5, &x.mask) +} + +func (x *SignalFileDescription) afterLoad() {} + +func (x *SignalFileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) + m.Load(4, &x.target) + m.Load(5, &x.mask) +} + +func init() { + state.Register((*SignalFileDescription)(nil)) +} diff --git a/pkg/sentry/fsimpl/sockfs/sockfs.go b/pkg/sentry/fsimpl/sockfs/sockfs.go index f1e75e277..29e5371d6 100644 --- a/pkg/sentry/fsimpl/sockfs/sockfs.go +++ b/pkg/sentry/fsimpl/sockfs/sockfs.go @@ -28,6 +28,8 @@ import ( ) // filesystemType implements vfs.FilesystemType. +// +// +stateify savable type filesystemType struct{} // GetFilesystem implements vfs.FilesystemType.GetFilesystem. @@ -44,6 +46,7 @@ func (filesystemType) Name() string { return "sockfs" } +// +stateify savable type filesystem struct { kernfs.Filesystem @@ -80,6 +83,8 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe } // inode implements kernfs.Inode. +// +// +stateify savable type inode struct { kernfs.InodeAttrs kernfs.InodeNoopRefCount diff --git a/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go b/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go index 8d5b85e2c..bbc868a48 100644 --- a/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go +++ b/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go @@ -1,3 +1,90 @@ // automatically generated by stateify. package sockfs + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *filesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/sockfs.filesystemType" +} + +func (x *filesystemType) StateFields() []string { + return []string{} +} + +func (x *filesystemType) beforeSave() {} + +func (x *filesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *filesystemType) afterLoad() {} + +func (x *filesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/sockfs.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) +} + +func (x *inode) StateTypeName() string { + return "pkg/sentry/fsimpl/sockfs.inode" +} + +func (x *inode) StateFields() []string { + return []string{ + "InodeAttrs", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + } +} + +func (x *inode) beforeSave() {} + +func (x *inode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.InodeAttrs) + m.Save(1, &x.InodeNoopRefCount) + m.Save(2, &x.InodeNotDirectory) + m.Save(3, &x.InodeNotSymlink) +} + +func (x *inode) afterLoad() {} + +func (x *inode) StateLoad(m state.Source) { + m.Load(0, &x.InodeAttrs) + m.Load(1, &x.InodeNoopRefCount) + m.Load(2, &x.InodeNotDirectory) + m.Load(3, &x.InodeNotSymlink) +} + +func init() { + state.Register((*filesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*inode)(nil)) +} diff --git a/pkg/sentry/fsimpl/sys/kcov.go b/pkg/sentry/fsimpl/sys/kcov.go index 252f75d26..b75d70ae6 100644 --- a/pkg/sentry/fsimpl/sys/kcov.go +++ b/pkg/sentry/fsimpl/sys/kcov.go @@ -36,6 +36,8 @@ func (fs *filesystem) newKcovFile(ctx context.Context, creds *auth.Credentials) } // kcovInode implements kernfs.Inode. +// +// +stateify savable type kcovInode struct { kernfs.InodeAttrs kernfs.InodeNoopRefCount @@ -63,6 +65,7 @@ func (i *kcovInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.D return &fd.vfsfd, nil } +// +stateify savable type kcovFD struct { vfs.FileDescriptionDefaultImpl vfs.NoLockFD diff --git a/pkg/sentry/fsimpl/sys/sys.go b/pkg/sentry/fsimpl/sys/sys.go index 8bcefc103..1568c581f 100644 --- a/pkg/sentry/fsimpl/sys/sys.go +++ b/pkg/sentry/fsimpl/sys/sys.go @@ -34,9 +34,13 @@ const Name = "sysfs" const defaultSysDirMode = linux.FileMode(0755) // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct{} // filesystem implements vfs.FilesystemImpl. +// +// +stateify savable type filesystem struct { kernfs.Filesystem @@ -117,6 +121,8 @@ func (fs *filesystem) Release(ctx context.Context) { } // dir implements kernfs.Inode. +// +// +stateify savable type dir struct { dirRefs kernfs.InodeAttrs @@ -169,6 +175,8 @@ func (d *dir) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, err } // cpuFile implements kernfs.Inode. +// +// +stateify savable type cpuFile struct { implStatFS kernfs.DynamicBytesFile @@ -190,6 +198,7 @@ func (fs *filesystem) newCPUFile(creds *auth.Credentials, maxCores uint, mode li return d } +// +stateify savable type implStatFS struct{} // StatFS implements kernfs.Inode.StatFS. diff --git a/pkg/sentry/fsimpl/sys/sys_state_autogen.go b/pkg/sentry/fsimpl/sys/sys_state_autogen.go index 347a46318..14d4efce9 100644 --- a/pkg/sentry/fsimpl/sys/sys_state_autogen.go +++ b/pkg/sentry/fsimpl/sys/sys_state_autogen.go @@ -29,6 +29,220 @@ func (x *dirRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *kcovInode) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.kcovInode" +} + +func (x *kcovInode) StateFields() []string { + return []string{ + "InodeAttrs", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "implStatFS", + } +} + +func (x *kcovInode) beforeSave() {} + +func (x *kcovInode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.InodeAttrs) + m.Save(1, &x.InodeNoopRefCount) + m.Save(2, &x.InodeNotDirectory) + m.Save(3, &x.InodeNotSymlink) + m.Save(4, &x.implStatFS) +} + +func (x *kcovInode) afterLoad() {} + +func (x *kcovInode) StateLoad(m state.Source) { + m.Load(0, &x.InodeAttrs) + m.Load(1, &x.InodeNoopRefCount) + m.Load(2, &x.InodeNotDirectory) + m.Load(3, &x.InodeNotSymlink) + m.Load(4, &x.implStatFS) +} + +func (x *kcovFD) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.kcovFD" +} + +func (x *kcovFD) StateFields() []string { + return []string{ + "FileDescriptionDefaultImpl", + "NoLockFD", + "vfsfd", + "inode", + "kcov", + } +} + +func (x *kcovFD) beforeSave() {} + +func (x *kcovFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.FileDescriptionDefaultImpl) + m.Save(1, &x.NoLockFD) + m.Save(2, &x.vfsfd) + m.Save(3, &x.inode) + m.Save(4, &x.kcov) +} + +func (x *kcovFD) afterLoad() {} + +func (x *kcovFD) StateLoad(m state.Source) { + m.Load(0, &x.FileDescriptionDefaultImpl) + m.Load(1, &x.NoLockFD) + m.Load(2, &x.vfsfd) + m.Load(3, &x.inode) + m.Load(4, &x.kcov) +} + +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{} +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Filesystem) + m.Save(1, &x.devMinor) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.Filesystem) + m.Load(1, &x.devMinor) +} + +func (x *dir) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.dir" +} + +func (x *dir) StateFields() []string { + return []string{ + "dirRefs", + "InodeAttrs", + "InodeNoDynamicLookup", + "InodeNotSymlink", + "InodeDirectoryNoNewChildren", + "OrderedChildren", + "locks", + "dentry", + } +} + +func (x *dir) beforeSave() {} + +func (x *dir) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.dirRefs) + m.Save(1, &x.InodeAttrs) + m.Save(2, &x.InodeNoDynamicLookup) + m.Save(3, &x.InodeNotSymlink) + m.Save(4, &x.InodeDirectoryNoNewChildren) + m.Save(5, &x.OrderedChildren) + m.Save(6, &x.locks) + m.Save(7, &x.dentry) +} + +func (x *dir) afterLoad() {} + +func (x *dir) StateLoad(m state.Source) { + m.Load(0, &x.dirRefs) + m.Load(1, &x.InodeAttrs) + m.Load(2, &x.InodeNoDynamicLookup) + m.Load(3, &x.InodeNotSymlink) + m.Load(4, &x.InodeDirectoryNoNewChildren) + m.Load(5, &x.OrderedChildren) + m.Load(6, &x.locks) + m.Load(7, &x.dentry) +} + +func (x *cpuFile) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.cpuFile" +} + +func (x *cpuFile) StateFields() []string { + return []string{ + "implStatFS", + "DynamicBytesFile", + "maxCores", + } +} + +func (x *cpuFile) beforeSave() {} + +func (x *cpuFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.implStatFS) + m.Save(1, &x.DynamicBytesFile) + m.Save(2, &x.maxCores) +} + +func (x *cpuFile) afterLoad() {} + +func (x *cpuFile) StateLoad(m state.Source) { + m.Load(0, &x.implStatFS) + m.Load(1, &x.DynamicBytesFile) + m.Load(2, &x.maxCores) +} + +func (x *implStatFS) StateTypeName() string { + return "pkg/sentry/fsimpl/sys.implStatFS" +} + +func (x *implStatFS) StateFields() []string { + return []string{} +} + +func (x *implStatFS) beforeSave() {} + +func (x *implStatFS) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *implStatFS) afterLoad() {} + +func (x *implStatFS) StateLoad(m state.Source) { +} + func init() { state.Register((*dirRefs)(nil)) + state.Register((*kcovInode)(nil)) + state.Register((*kcovFD)(nil)) + state.Register((*FilesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*dir)(nil)) + state.Register((*cpuFile)(nil)) + state.Register((*implStatFS)(nil)) } diff --git a/pkg/sentry/fsimpl/timerfd/timerfd.go b/pkg/sentry/fsimpl/timerfd/timerfd.go index ac8a4e3bb..8853c8ad2 100644 --- a/pkg/sentry/fsimpl/timerfd/timerfd.go +++ b/pkg/sentry/fsimpl/timerfd/timerfd.go @@ -28,6 +28,8 @@ import ( // TimerFileDescription implements vfs.FileDescriptionImpl for timer fds. It also // implements ktime.TimerListener. +// +// +stateify savable type TimerFileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go b/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go index 4e5976369..722153ff8 100644 --- a/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go +++ b/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go @@ -1,3 +1,52 @@ // automatically generated by stateify. package timerfd + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (x *TimerFileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/timerfd.TimerFileDescription" +} + +func (x *TimerFileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + "events", + "timer", + "val", + } +} + +func (x *TimerFileDescription) beforeSave() {} + +func (x *TimerFileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) + m.Save(4, &x.events) + m.Save(5, &x.timer) + m.Save(6, &x.val) +} + +func (x *TimerFileDescription) afterLoad() {} + +func (x *TimerFileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) + m.Load(4, &x.events) + m.Load(5, &x.timer) + m.Load(6, &x.val) +} + +func init() { + state.Register((*TimerFileDescription)(nil)) +} diff --git a/pkg/sentry/fsimpl/tmpfs/device_file.go b/pkg/sentry/fsimpl/tmpfs/device_file.go index ac54d420d..9129d35b7 100644 --- a/pkg/sentry/fsimpl/tmpfs/device_file.go +++ b/pkg/sentry/fsimpl/tmpfs/device_file.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/vfs" ) +// +stateify savable type deviceFile struct { inode inode kind vfs.DeviceKind diff --git a/pkg/sentry/fsimpl/tmpfs/directory.go b/pkg/sentry/fsimpl/tmpfs/directory.go index 070c75e68..e90669cf0 100644 --- a/pkg/sentry/fsimpl/tmpfs/directory.go +++ b/pkg/sentry/fsimpl/tmpfs/directory.go @@ -25,6 +25,7 @@ import ( "gvisor.dev/gvisor/pkg/syserror" ) +// +stateify savable type directory struct { // Since directories can't be hard-linked, each directory can only be // associated with a single dentry, which we can store in the directory @@ -44,7 +45,7 @@ type directory struct { // (with inode == nil) that represent the iteration position of // directoryFDs. childList is used to support directoryFD.IterDirents() // efficiently. childList is protected by iterMu. - iterMu sync.Mutex + iterMu sync.Mutex `state:"nosave"` childList dentryList } @@ -86,6 +87,7 @@ func (dir *directory) mayDelete(creds *auth.Credentials, child *dentry) error { return vfs.CheckDeleteSticky(creds, linux.FileMode(atomic.LoadUint32(&dir.inode.mode)), auth.KUID(atomic.LoadUint32(&child.inode.uid))) } +// +stateify savable type directoryFD struct { fileDescription vfs.DirectoryFileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/tmpfs/named_pipe.go b/pkg/sentry/fsimpl/tmpfs/named_pipe.go index 5b0471ff4..d772db9e9 100644 --- a/pkg/sentry/fsimpl/tmpfs/named_pipe.go +++ b/pkg/sentry/fsimpl/tmpfs/named_pipe.go @@ -21,6 +21,7 @@ import ( "gvisor.dev/gvisor/pkg/usermem" ) +// +stateify savable type namedPipe struct { inode inode diff --git a/pkg/sentry/fsimpl/tmpfs/regular_file.go b/pkg/sentry/fsimpl/tmpfs/regular_file.go index b8699d064..a199eb33d 100644 --- a/pkg/sentry/fsimpl/tmpfs/regular_file.go +++ b/pkg/sentry/fsimpl/tmpfs/regular_file.go @@ -36,6 +36,8 @@ import ( ) // regularFile is a regular (=S_IFREG) tmpfs file. +// +// +stateify savable type regularFile struct { inode inode @@ -66,7 +68,7 @@ type regularFile struct { writableMappingPages uint64 // dataMu protects the fields below. - dataMu sync.RWMutex + dataMu sync.RWMutex `state:"nosave"` // data maps offsets into the file to offsets into memFile that store // the file's data. @@ -325,13 +327,14 @@ func (*regularFile) InvalidateUnsavable(context.Context) error { return nil } +// +stateify savable type regularFileFD struct { fileDescription // off is the file offset. off is accessed using atomic memory operations. // offMu serializes operations that may mutate off. off int64 - offMu sync.Mutex + offMu sync.Mutex `state:"nosave"` } // Release implements vfs.FileDescriptionImpl.Release. diff --git a/pkg/sentry/fsimpl/tmpfs/socket_file.go b/pkg/sentry/fsimpl/tmpfs/socket_file.go index 3ed650474..5699d5975 100644 --- a/pkg/sentry/fsimpl/tmpfs/socket_file.go +++ b/pkg/sentry/fsimpl/tmpfs/socket_file.go @@ -21,6 +21,8 @@ import ( ) // socketFile is a socket (=S_IFSOCK) tmpfs file. +// +// +stateify savable type socketFile struct { inode inode ep transport.BoundEndpoint diff --git a/pkg/sentry/fsimpl/tmpfs/symlink.go b/pkg/sentry/fsimpl/tmpfs/symlink.go index b0de5fabe..a102a2ee2 100644 --- a/pkg/sentry/fsimpl/tmpfs/symlink.go +++ b/pkg/sentry/fsimpl/tmpfs/symlink.go @@ -19,6 +19,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/kernel/auth" ) +// +stateify savable type symlink struct { inode inode target string // immutable diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs.go b/pkg/sentry/fsimpl/tmpfs/tmpfs.go index 4658e1533..cefec8fde 100644 --- a/pkg/sentry/fsimpl/tmpfs/tmpfs.go +++ b/pkg/sentry/fsimpl/tmpfs/tmpfs.go @@ -51,9 +51,13 @@ import ( const Name = "tmpfs" // FilesystemType implements vfs.FilesystemType. +// +// +stateify savable type FilesystemType struct{} // filesystem implements vfs.FilesystemImpl. +// +// +stateify savable type filesystem struct { vfsfs vfs.Filesystem @@ -67,7 +71,7 @@ type filesystem struct { devMinor uint32 // mu serializes changes to the Dentry tree. - mu sync.RWMutex + mu sync.RWMutex `state:"nosave"` nextInoMinusOne uint64 // accessed using atomic memory operations } @@ -78,6 +82,8 @@ func (FilesystemType) Name() string { } // FilesystemOpts is used to pass configuration data to tmpfs. +// +// +stateify savable type FilesystemOpts struct { // RootFileType is the FileType of the filesystem root. Valid values // are: S_IFDIR, S_IFREG, and S_IFLNK. Defaults to S_IFDIR. @@ -221,6 +227,8 @@ var globalStatfs = linux.Statfs{ } // dentry implements vfs.DentryImpl. +// +// +stateify savable type dentry struct { vfsd vfs.Dentry @@ -300,6 +308,8 @@ func (d *dentry) Watches() *vfs.Watches { func (d *dentry) OnZeroWatches(context.Context) {} // inode represents a filesystem object. +// +// +stateify savable type inode struct { // fs is the owning filesystem. fs is immutable. fs *filesystem @@ -316,12 +326,12 @@ type inode struct { // Inode metadata. Writing multiple fields atomically requires holding // mu, othewise atomic operations can be used. - mu sync.Mutex - mode uint32 // file type and mode - nlink uint32 // protected by filesystem.mu instead of inode.mu - uid uint32 // auth.KUID, but stored as raw uint32 for sync/atomic - gid uint32 // auth.KGID, but ... - ino uint64 // immutable + mu sync.Mutex `state:"nosave"` + mode uint32 // file type and mode + nlink uint32 // protected by filesystem.mu instead of inode.mu + uid uint32 // auth.KUID, but stored as raw uint32 for sync/atomic + gid uint32 // auth.KGID, but ... + ino uint64 // immutable // Linux's tmpfs has no concept of btime. atime int64 // nanoseconds @@ -668,6 +678,8 @@ func (i *inode) checkXattrPermissions(creds *auth.Credentials, name string, ats // fileDescription is embedded by tmpfs implementations of // vfs.FileDescriptionImpl. +// +// +stateify savable type fileDescription struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go b/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go index d88136656..4252b95e6 100644 --- a/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go +++ b/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go @@ -58,6 +58,105 @@ func (x *dentryEntry) StateLoad(m state.Source) { m.Load(1, &x.prev) } +func (x *deviceFile) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.deviceFile" +} + +func (x *deviceFile) StateFields() []string { + return []string{ + "inode", + "kind", + "major", + "minor", + } +} + +func (x *deviceFile) beforeSave() {} + +func (x *deviceFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inode) + m.Save(1, &x.kind) + m.Save(2, &x.major) + m.Save(3, &x.minor) +} + +func (x *deviceFile) afterLoad() {} + +func (x *deviceFile) StateLoad(m state.Source) { + m.Load(0, &x.inode) + m.Load(1, &x.kind) + m.Load(2, &x.major) + m.Load(3, &x.minor) +} + +func (x *directory) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.directory" +} + +func (x *directory) StateFields() []string { + return []string{ + "dentry", + "inode", + "childMap", + "numChildren", + "childList", + } +} + +func (x *directory) beforeSave() {} + +func (x *directory) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.dentry) + m.Save(1, &x.inode) + m.Save(2, &x.childMap) + m.Save(3, &x.numChildren) + m.Save(4, &x.childList) +} + +func (x *directory) afterLoad() {} + +func (x *directory) StateLoad(m state.Source) { + m.Load(0, &x.dentry) + m.Load(1, &x.inode) + m.Load(2, &x.childMap) + m.Load(3, &x.numChildren) + m.Load(4, &x.childList) +} + +func (x *directoryFD) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.directoryFD" +} + +func (x *directoryFD) StateFields() []string { + return []string{ + "fileDescription", + "DirectoryFileDescriptionDefaultImpl", + "iter", + "off", + } +} + +func (x *directoryFD) beforeSave() {} + +func (x *directoryFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Save(2, &x.iter) + m.Save(3, &x.off) +} + +func (x *directoryFD) afterLoad() {} + +func (x *directoryFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.DirectoryFileDescriptionDefaultImpl) + m.Load(2, &x.iter) + m.Load(3, &x.off) +} + func (x *inodeRefs) StateTypeName() string { return "pkg/sentry/fsimpl/tmpfs.inodeRefs" } @@ -81,8 +180,379 @@ func (x *inodeRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *namedPipe) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.namedPipe" +} + +func (x *namedPipe) StateFields() []string { + return []string{ + "inode", + "pipe", + } +} + +func (x *namedPipe) beforeSave() {} + +func (x *namedPipe) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inode) + m.Save(1, &x.pipe) +} + +func (x *namedPipe) afterLoad() {} + +func (x *namedPipe) StateLoad(m state.Source) { + m.Load(0, &x.inode) + m.Load(1, &x.pipe) +} + +func (x *regularFile) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.regularFile" +} + +func (x *regularFile) StateFields() []string { + return []string{ + "inode", + "memFile", + "memoryUsageKind", + "mappings", + "writableMappingPages", + "data", + "seals", + "size", + } +} + +func (x *regularFile) beforeSave() {} + +func (x *regularFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inode) + m.Save(1, &x.memFile) + m.Save(2, &x.memoryUsageKind) + m.Save(3, &x.mappings) + m.Save(4, &x.writableMappingPages) + m.Save(5, &x.data) + m.Save(6, &x.seals) + m.Save(7, &x.size) +} + +func (x *regularFile) afterLoad() {} + +func (x *regularFile) StateLoad(m state.Source) { + m.Load(0, &x.inode) + m.Load(1, &x.memFile) + m.Load(2, &x.memoryUsageKind) + m.Load(3, &x.mappings) + m.Load(4, &x.writableMappingPages) + m.Load(5, &x.data) + m.Load(6, &x.seals) + m.Load(7, &x.size) +} + +func (x *regularFileFD) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.regularFileFD" +} + +func (x *regularFileFD) StateFields() []string { + return []string{ + "fileDescription", + "off", + } +} + +func (x *regularFileFD) beforeSave() {} + +func (x *regularFileFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fileDescription) + m.Save(1, &x.off) +} + +func (x *regularFileFD) afterLoad() {} + +func (x *regularFileFD) StateLoad(m state.Source) { + m.Load(0, &x.fileDescription) + m.Load(1, &x.off) +} + +func (x *socketFile) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.socketFile" +} + +func (x *socketFile) StateFields() []string { + return []string{ + "inode", + "ep", + } +} + +func (x *socketFile) beforeSave() {} + +func (x *socketFile) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inode) + m.Save(1, &x.ep) +} + +func (x *socketFile) afterLoad() {} + +func (x *socketFile) StateLoad(m state.Source) { + m.Load(0, &x.inode) + m.Load(1, &x.ep) +} + +func (x *symlink) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.symlink" +} + +func (x *symlink) StateFields() []string { + return []string{ + "inode", + "target", + } +} + +func (x *symlink) beforeSave() {} + +func (x *symlink) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.inode) + m.Save(1, &x.target) +} + +func (x *symlink) afterLoad() {} + +func (x *symlink) StateLoad(m state.Source) { + m.Load(0, &x.inode) + m.Load(1, &x.target) +} + +func (x *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.FilesystemType" +} + +func (x *FilesystemType) StateFields() []string { + return []string{} +} + +func (x *FilesystemType) beforeSave() {} + +func (x *FilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FilesystemType) afterLoad() {} + +func (x *FilesystemType) StateLoad(m state.Source) { +} + +func (x *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.filesystem" +} + +func (x *filesystem) StateFields() []string { + return []string{ + "vfsfs", + "memFile", + "clock", + "devMinor", + "nextInoMinusOne", + } +} + +func (x *filesystem) beforeSave() {} + +func (x *filesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfs) + m.Save(1, &x.memFile) + m.Save(2, &x.clock) + m.Save(3, &x.devMinor) + m.Save(4, &x.nextInoMinusOne) +} + +func (x *filesystem) afterLoad() {} + +func (x *filesystem) StateLoad(m state.Source) { + m.Load(0, &x.vfsfs) + m.Load(1, &x.memFile) + m.Load(2, &x.clock) + m.Load(3, &x.devMinor) + m.Load(4, &x.nextInoMinusOne) +} + +func (x *FilesystemOpts) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.FilesystemOpts" +} + +func (x *FilesystemOpts) StateFields() []string { + return []string{ + "RootFileType", + "RootSymlinkTarget", + "FilesystemType", + } +} + +func (x *FilesystemOpts) beforeSave() {} + +func (x *FilesystemOpts) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.RootFileType) + m.Save(1, &x.RootSymlinkTarget) + m.Save(2, &x.FilesystemType) +} + +func (x *FilesystemOpts) afterLoad() {} + +func (x *FilesystemOpts) StateLoad(m state.Source) { + m.Load(0, &x.RootFileType) + m.Load(1, &x.RootSymlinkTarget) + m.Load(2, &x.FilesystemType) +} + +func (x *dentry) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.dentry" +} + +func (x *dentry) StateFields() []string { + return []string{ + "vfsd", + "parent", + "name", + "dentryEntry", + "inode", + } +} + +func (x *dentry) beforeSave() {} + +func (x *dentry) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsd) + m.Save(1, &x.parent) + m.Save(2, &x.name) + m.Save(3, &x.dentryEntry) + m.Save(4, &x.inode) +} + +func (x *dentry) afterLoad() {} + +func (x *dentry) StateLoad(m state.Source) { + m.Load(0, &x.vfsd) + m.Load(1, &x.parent) + m.Load(2, &x.name) + m.Load(3, &x.dentryEntry) + m.Load(4, &x.inode) +} + +func (x *inode) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.inode" +} + +func (x *inode) StateFields() []string { + return []string{ + "fs", + "refs", + "xattrs", + "mode", + "nlink", + "uid", + "gid", + "ino", + "atime", + "ctime", + "mtime", + "locks", + "watches", + "impl", + } +} + +func (x *inode) beforeSave() {} + +func (x *inode) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.fs) + m.Save(1, &x.refs) + m.Save(2, &x.xattrs) + m.Save(3, &x.mode) + m.Save(4, &x.nlink) + m.Save(5, &x.uid) + m.Save(6, &x.gid) + m.Save(7, &x.ino) + m.Save(8, &x.atime) + m.Save(9, &x.ctime) + m.Save(10, &x.mtime) + m.Save(11, &x.locks) + m.Save(12, &x.watches) + m.Save(13, &x.impl) +} + +func (x *inode) afterLoad() {} + +func (x *inode) StateLoad(m state.Source) { + m.Load(0, &x.fs) + m.Load(1, &x.refs) + m.Load(2, &x.xattrs) + m.Load(3, &x.mode) + m.Load(4, &x.nlink) + m.Load(5, &x.uid) + m.Load(6, &x.gid) + m.Load(7, &x.ino) + m.Load(8, &x.atime) + m.Load(9, &x.ctime) + m.Load(10, &x.mtime) + m.Load(11, &x.locks) + m.Load(12, &x.watches) + m.Load(13, &x.impl) +} + +func (x *fileDescription) StateTypeName() string { + return "pkg/sentry/fsimpl/tmpfs.fileDescription" +} + +func (x *fileDescription) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + } +} + +func (x *fileDescription) beforeSave() {} + +func (x *fileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.LockFD) +} + +func (x *fileDescription) afterLoad() {} + +func (x *fileDescription) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.LockFD) +} + func init() { state.Register((*dentryList)(nil)) state.Register((*dentryEntry)(nil)) + state.Register((*deviceFile)(nil)) + state.Register((*directory)(nil)) + state.Register((*directoryFD)(nil)) state.Register((*inodeRefs)(nil)) + state.Register((*namedPipe)(nil)) + state.Register((*regularFile)(nil)) + state.Register((*regularFileFD)(nil)) + state.Register((*socketFile)(nil)) + state.Register((*symlink)(nil)) + state.Register((*FilesystemType)(nil)) + state.Register((*filesystem)(nil)) + state.Register((*FilesystemOpts)(nil)) + state.Register((*dentry)(nil)) + state.Register((*inode)(nil)) + state.Register((*fileDescription)(nil)) } diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 22f9bb006..08bb5bd12 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -507,6 +507,10 @@ func (k *Kernel) SaveTo(w wire.Writer) error { // flushMountSourceRefs flushes the MountSources for all mounted filesystems // and open FDs. func (k *Kernel) flushMountSourceRefs(ctx context.Context) error { + if VFS2Enabled { + return nil // Not relevant. + } + // Flush all mount sources for currently mounted filesystems in each task. flushed := make(map[*fs.MountNamespace]struct{}) k.tasks.mu.RLock() @@ -533,11 +537,6 @@ func (k *Kernel) flushMountSourceRefs(ctx context.Context) error { // // Precondition: Must be called with the kernel paused. func (ts *TaskSet) forEachFDPaused(ctx context.Context, f func(*fs.File, *vfs.FileDescription) error) (err error) { - // TODO(gvisor.dev/issue/1663): Add save support for VFS2. - if VFS2Enabled { - return nil - } - ts.mu.RLock() defer ts.mu.RUnlock() for t := range ts.Root.tids { @@ -556,6 +555,10 @@ func (ts *TaskSet) forEachFDPaused(ctx context.Context, f func(*fs.File, *vfs.Fi func (ts *TaskSet) flushWritesToFiles(ctx context.Context) error { // TODO(gvisor.dev/issue/1663): Add save support for VFS2. + if VFS2Enabled { + return nil + } + return ts.forEachFDPaused(ctx, func(file *fs.File, _ *vfs.FileDescription) error { if flags := file.Flags(); !flags.Write { return nil diff --git a/pkg/sentry/socket/unix/unix_state_autogen.go b/pkg/sentry/socket/unix/unix_state_autogen.go index 6966529c6..89d78a9ad 100644 --- a/pkg/sentry/socket/unix/unix_state_autogen.go +++ b/pkg/sentry/socket/unix/unix_state_autogen.go @@ -90,8 +90,44 @@ func (x *socketOpsCommon) StateLoad(m state.Source) { m.Load(5, &x.abstractNamespace) } +func (x *SocketVFS2) StateTypeName() string { + return "pkg/sentry/socket/unix.SocketVFS2" +} + +func (x *SocketVFS2) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "LockFD", + "socketOpsCommon", + } +} + +func (x *SocketVFS2) beforeSave() {} + +func (x *SocketVFS2) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.LockFD) + m.Save(4, &x.socketOpsCommon) +} + +func (x *SocketVFS2) afterLoad() {} + +func (x *SocketVFS2) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.LockFD) + m.Load(4, &x.socketOpsCommon) +} + func init() { state.Register((*socketOpsCommonRefs)(nil)) state.Register((*SocketOperations)(nil)) state.Register((*socketOpsCommon)(nil)) + state.Register((*SocketVFS2)(nil)) } diff --git a/pkg/sentry/socket/unix/unix_vfs2.go b/pkg/sentry/socket/unix/unix_vfs2.go index 3688f22d2..b76c0e6fb 100644 --- a/pkg/sentry/socket/unix/unix_vfs2.go +++ b/pkg/sentry/socket/unix/unix_vfs2.go @@ -37,6 +37,8 @@ import ( // SocketVFS2 implements socket.SocketVFS2 (and by extension, // vfs.FileDescriptionImpl) for Unix sockets. +// +// +stateify savable type SocketVFS2 struct { vfsfd vfs.FileDescription vfs.FileDescriptionDefaultImpl diff --git a/pkg/sentry/state/state.go b/pkg/sentry/state/state.go index a06c9b8ab..245d2c5cf 100644 --- a/pkg/sentry/state/state.go +++ b/pkg/sentry/state/state.go @@ -61,8 +61,10 @@ func (opts SaveOpts) Save(k *kernel.Kernel, w *watchdog.Watchdog) error { log.Infof("Sandbox save started, pausing all tasks.") k.Pause() k.ReceiveTaskStates() - defer k.Unpause() - defer log.Infof("Tasks resumed after save.") + defer func() { + k.Unpause() + log.Infof("Tasks resumed after save.") + }() w.Stop() defer w.Start() diff --git a/pkg/sentry/vfs/anonfs.go b/pkg/sentry/vfs/anonfs.go index 9c4db3047..bdfd3ca8f 100644 --- a/pkg/sentry/vfs/anonfs.go +++ b/pkg/sentry/vfs/anonfs.go @@ -52,6 +52,8 @@ const ( ) // anonFilesystemType implements FilesystemType. +// +// +stateify savable type anonFilesystemType struct{} // GetFilesystem implements FilesystemType.GetFilesystem. @@ -69,12 +71,15 @@ func (anonFilesystemType) Name() string { // // Since all Dentries in anonFilesystem are non-directories, all FilesystemImpl // methods that would require an anonDentry to be a directory return ENOTDIR. +// +// +stateify savable type anonFilesystem struct { vfsfs Filesystem devMinor uint32 } +// +stateify savable type anonDentry struct { vfsd Dentry diff --git a/pkg/sentry/vfs/dentry.go b/pkg/sentry/vfs/dentry.go index a69a5b2f1..320ab7ce1 100644 --- a/pkg/sentry/vfs/dentry.go +++ b/pkg/sentry/vfs/dentry.go @@ -89,6 +89,8 @@ func (d *Dentry) Impl() DentryImpl { // DentryImpl contains implementation details for a Dentry. Implementations of // DentryImpl should contain their associated Dentry by value as their first // field. +// +// +stateify savable type DentryImpl interface { // IncRef increments the Dentry's reference count. A Dentry with a non-zero // reference count must remain coherent with the state of the filesystem. diff --git a/pkg/sentry/vfs/device.go b/pkg/sentry/vfs/device.go index 1e9dffc8f..dde2ad79b 100644 --- a/pkg/sentry/vfs/device.go +++ b/pkg/sentry/vfs/device.go @@ -22,6 +22,8 @@ import ( ) // DeviceKind indicates whether a device is a block or character device. +// +// +stateify savable type DeviceKind uint32 const ( @@ -44,6 +46,7 @@ func (kind DeviceKind) String() string { } } +// +stateify savable type devTuple struct { kind DeviceKind major uint32 diff --git a/pkg/sentry/vfs/epoll.go b/pkg/sentry/vfs/epoll.go index 754e76aec..8f36c3e3b 100644 --- a/pkg/sentry/vfs/epoll.go +++ b/pkg/sentry/vfs/epoll.go @@ -27,6 +27,8 @@ import ( var epollCycleMu sync.Mutex // EpollInstance represents an epoll instance, as described by epoll(7). +// +// +stateify savable type EpollInstance struct { vfsfd FileDescription FileDescriptionDefaultImpl @@ -38,11 +40,11 @@ type EpollInstance struct { // interest is the set of file descriptors that are registered with the // EpollInstance for monitoring. interest is protected by interestMu. - interestMu sync.Mutex + interestMu sync.Mutex `state:"nosave"` interest map[epollInterestKey]*epollInterest // mu protects fields in registered epollInterests. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // ready is the set of file descriptors that may be "ready" for I/O. Note // that this must be an ordered list, not a map: "If more than maxevents @@ -55,6 +57,7 @@ type EpollInstance struct { ready epollInterestList } +// +stateify savable type epollInterestKey struct { // file is the registered FileDescription. No reference is held on file; // instead, when the last reference is dropped, FileDescription.DecRef() @@ -67,6 +70,8 @@ type epollInterestKey struct { } // epollInterest represents an EpollInstance's interest in a file descriptor. +// +// +stateify savable type epollInterest struct { // epoll is the owning EpollInstance. epoll is immutable. epoll *EpollInstance diff --git a/pkg/sentry/vfs/file_description.go b/pkg/sentry/vfs/file_description.go index 73bb36d3e..1eba0270f 100644 --- a/pkg/sentry/vfs/file_description.go +++ b/pkg/sentry/vfs/file_description.go @@ -37,11 +37,13 @@ import ( // FileDescription methods require that a reference is held. // // FileDescription is analogous to Linux's struct file. +// +// +stateify savable type FileDescription struct { FileDescriptionRefs // flagsMu protects statusFlags and asyncHandler below. - flagsMu sync.Mutex + flagsMu sync.Mutex `state:"nosave"` // statusFlags contains status flags, "initialized by open(2) and possibly // modified by fcntl()" - fcntl(2). statusFlags can be read using atomic @@ -56,7 +58,7 @@ type FileDescription struct { // epolls is the set of epollInterests registered for this FileDescription. // epolls is protected by epollMu. - epollMu sync.Mutex + epollMu sync.Mutex `state:"nosave"` epolls map[*epollInterest]struct{} // vd is the filesystem location at which this FileDescription was opened. @@ -88,6 +90,8 @@ type FileDescription struct { } // FileDescriptionOptions contains options to FileDescription.Init(). +// +// +stateify savable type FileDescriptionOptions struct { // If AllowDirectIO is true, allow O_DIRECT to be set on the file. AllowDirectIO bool @@ -451,6 +455,8 @@ type FileDescriptionImpl interface { } // Dirent holds the information contained in struct linux_dirent64. +// +// +stateify savable type Dirent struct { // Name is the filename. Name string diff --git a/pkg/sentry/vfs/file_description_impl_util.go b/pkg/sentry/vfs/file_description_impl_util.go index 78da16bac..48ca9de44 100644 --- a/pkg/sentry/vfs/file_description_impl_util.go +++ b/pkg/sentry/vfs/file_description_impl_util.go @@ -42,6 +42,8 @@ import ( // FileDescriptionDefaultImpl may be embedded by implementations of // FileDescriptionImpl to obtain implementations of many FileDescriptionImpl // methods with default behavior analogous to Linux's. +// +// +stateify savable type FileDescriptionDefaultImpl struct{} // OnClose implements FileDescriptionImpl.OnClose analogously to @@ -166,6 +168,8 @@ func (FileDescriptionDefaultImpl) RemoveXattr(ctx context.Context, name string) // DirectoryFileDescriptionDefaultImpl may be embedded by implementations of // FileDescriptionImpl that always represent directories to obtain // implementations of non-directory I/O methods that return EISDIR. +// +// +stateify savable type DirectoryFileDescriptionDefaultImpl struct{} // Allocate implements DirectoryFileDescriptionDefaultImpl.Allocate. @@ -196,6 +200,8 @@ func (DirectoryFileDescriptionDefaultImpl) Write(ctx context.Context, src userme // DentryMetadataFileDescriptionImpl may be embedded by implementations of // FileDescriptionImpl for which FileDescriptionOptions.UseDentryMetadata is // true to obtain implementations of Stat and SetStat that panic. +// +// +stateify savable type DentryMetadataFileDescriptionImpl struct{} // Stat implements FileDescriptionImpl.Stat. @@ -210,12 +216,16 @@ func (DentryMetadataFileDescriptionImpl) SetStat(ctx context.Context, opts SetSt // DynamicBytesSource represents a data source for a // DynamicBytesFileDescriptionImpl. +// +// +stateify savable type DynamicBytesSource interface { // Generate writes the file's contents to buf. Generate(ctx context.Context, buf *bytes.Buffer) error } // StaticData implements DynamicBytesSource over a static string. +// +// +stateify savable type StaticData struct { Data string } @@ -242,14 +252,24 @@ type WritableDynamicBytesSource interface { // // DynamicBytesFileDescriptionImpl.SetDataSource() must be called before first // use. +// +// +stateify savable type DynamicBytesFileDescriptionImpl struct { data DynamicBytesSource // immutable - mu sync.Mutex // protects the following fields - buf bytes.Buffer + mu sync.Mutex `state:"nosave"` // protects the following fields + buf bytes.Buffer `state:".([]byte)"` off int64 lastRead int64 // offset at which the last Read, PRead, or Seek ended } +func (fd *DynamicBytesFileDescriptionImpl) saveBuf() []byte { + return fd.buf.Bytes() +} + +func (fd *DynamicBytesFileDescriptionImpl) loadBuf(p []byte) { + fd.buf.Write(p) +} + // SetDataSource must be called exactly once on fd before first use. func (fd *DynamicBytesFileDescriptionImpl) SetDataSource(data DynamicBytesSource) { fd.data = data @@ -382,6 +402,8 @@ func GenericConfigureMMap(fd *FileDescription, m memmap.Mappable, opts *memmap.M // LockFD may be used by most implementations of FileDescriptionImpl.Lock* // functions. Caller must call Init(). +// +// +stateify savable type LockFD struct { locks *FileLocks } @@ -409,6 +431,8 @@ func (fd *LockFD) UnlockBSD(ctx context.Context, uid fslock.UniqueID) error { // NoLockFD implements Lock*/Unlock* portion of FileDescriptionImpl interface // returning ENOLCK. +// +// +stateify savable type NoLockFD struct{} // LockBSD implements vfs.FileDescriptionImpl.LockBSD. diff --git a/pkg/sentry/vfs/filesystem.go b/pkg/sentry/vfs/filesystem.go index 7dae4e7e8..c93d94634 100644 --- a/pkg/sentry/vfs/filesystem.go +++ b/pkg/sentry/vfs/filesystem.go @@ -506,6 +506,8 @@ type FilesystemImpl interface { // PrependPathAtVFSRootError is returned by implementations of // FilesystemImpl.PrependPath() when they encounter the contextual VFS root. +// +// +stateify savable type PrependPathAtVFSRootError struct{} // Error implements error.Error. @@ -516,6 +518,8 @@ func (PrependPathAtVFSRootError) Error() string { // PrependPathAtNonMountRootError is returned by implementations of // FilesystemImpl.PrependPath() when they encounter an independent ancestor // Dentry that is not the Mount root. +// +// +stateify savable type PrependPathAtNonMountRootError struct{} // Error implements error.Error. @@ -526,6 +530,8 @@ func (PrependPathAtNonMountRootError) Error() string { // PrependPathSyntheticError is returned by implementations of // FilesystemImpl.PrependPath() for which prepended names do not represent real // paths. +// +// +stateify savable type PrependPathSyntheticError struct{} // Error implements error.Error. diff --git a/pkg/sentry/vfs/filesystem_type.go b/pkg/sentry/vfs/filesystem_type.go index 82ae35fdc..bc19db1d5 100644 --- a/pkg/sentry/vfs/filesystem_type.go +++ b/pkg/sentry/vfs/filesystem_type.go @@ -55,6 +55,8 @@ type registeredFilesystemType struct { // RegisterFilesystemTypeOptions contains options to // VirtualFilesystem.RegisterFilesystem(). +// +// +stateify savable type RegisterFilesystemTypeOptions struct { // AllowUserMount determines whether users are allowed to mount a file system // of this type, i.e. through mount(2). If AllowUserMount is true, allow calls diff --git a/pkg/sentry/vfs/inotify.go b/pkg/sentry/vfs/inotify.go index aff220a61..3f0b8f45b 100644 --- a/pkg/sentry/vfs/inotify.go +++ b/pkg/sentry/vfs/inotify.go @@ -37,6 +37,8 @@ const inotifyEventBaseSize = 16 // // The way events are labelled appears somewhat arbitrary, but they must match // Linux so that IN_EXCL_UNLINK behaves as it does in Linux. +// +// +stateify savable type EventType uint8 // PathEvent and InodeEvent correspond to FSNOTIFY_EVENT_PATH and diff --git a/pkg/sentry/vfs/lock.go b/pkg/sentry/vfs/lock.go index 42666eebf..55783d4eb 100644 --- a/pkg/sentry/vfs/lock.go +++ b/pkg/sentry/vfs/lock.go @@ -33,6 +33,8 @@ import ( // Note that in Linux these two types of locks are _not_ cooperative, because // race and deadlock conditions make merging them prohibitive. We do the same // and keep them oblivious to each other. +// +// +stateify savable type FileLocks struct { // bsd is a set of BSD-style advisory file wide locks, see flock(2). bsd fslock.Locks diff --git a/pkg/sentry/vfs/mount.go b/pkg/sentry/vfs/mount.go index 9da09d4c1..dfc3ae6c0 100644 --- a/pkg/sentry/vfs/mount.go +++ b/pkg/sentry/vfs/mount.go @@ -65,7 +65,7 @@ type Mount struct { // // Invariant: key.parent != nil iff key.point != nil. key.point belongs to // key.parent.fs. - key mountKey + key mountKey `state:".(VirtualDentry)"` // ns is the namespace in which this Mount was mounted. ns is protected by // VirtualFilesystem.mountMu. @@ -345,6 +345,7 @@ func (vfs *VirtualFilesystem) UmountAt(ctx context.Context, creds *auth.Credenti return nil } +// +stateify savable type umountRecursiveOptions struct { // If eager is true, ensure that future calls to Mount.tryIncMountedRef() // on umounted mounts fail. @@ -414,7 +415,7 @@ func (vfs *VirtualFilesystem) connectLocked(mnt *Mount, vd VirtualDentry, mntns } } mnt.IncRef() // dropped by callers of umountRecursiveLocked - mnt.storeKey(vd) + mnt.setKey(vd) if vd.mount.children == nil { vd.mount.children = make(map[*Mount]struct{}) } @@ -439,13 +440,13 @@ func (vfs *VirtualFilesystem) connectLocked(mnt *Mount, vd VirtualDentry, mntns // * vfs.mounts.seq must be in a writer critical section. // * mnt.parent() != nil. func (vfs *VirtualFilesystem) disconnectLocked(mnt *Mount) VirtualDentry { - vd := mnt.loadKey() + vd := mnt.getKey() if checkInvariants { if vd.mount != nil { panic("VFS.disconnectLocked called on disconnected mount") } } - mnt.storeKey(VirtualDentry{}) + mnt.loadKey(VirtualDentry{}) delete(vd.mount.children, mnt) atomic.AddUint32(&vd.dentry.mounts, math.MaxUint32) // -1 mnt.ns.mountpoints[vd.dentry]-- diff --git a/pkg/sentry/vfs/mount_unsafe.go b/pkg/sentry/vfs/mount_unsafe.go index da2a2e9c4..b7d122d22 100644 --- a/pkg/sentry/vfs/mount_unsafe.go +++ b/pkg/sentry/vfs/mount_unsafe.go @@ -34,6 +34,8 @@ import ( // structurally identical to VirtualDentry, but stores its fields as // unsafe.Pointer since mutators synchronize with VFS path traversal using // seqcounts. +// +// This is explicitly not savable. type mountKey struct { parent unsafe.Pointer // *Mount point unsafe.Pointer // *Dentry @@ -47,19 +49,23 @@ func (mnt *Mount) point() *Dentry { return (*Dentry)(atomic.LoadPointer(&mnt.key.point)) } -func (mnt *Mount) loadKey() VirtualDentry { +func (mnt *Mount) getKey() VirtualDentry { return VirtualDentry{ mount: mnt.parent(), dentry: mnt.point(), } } +func (mnt *Mount) saveKey() VirtualDentry { return mnt.getKey() } + // Invariant: mnt.key.parent == nil. vd.Ok(). -func (mnt *Mount) storeKey(vd VirtualDentry) { +func (mnt *Mount) setKey(vd VirtualDentry) { atomic.StorePointer(&mnt.key.parent, unsafe.Pointer(vd.mount)) atomic.StorePointer(&mnt.key.point, unsafe.Pointer(vd.dentry)) } +func (mnt *Mount) loadKey(vd VirtualDentry) { mnt.setKey(vd) } + // mountTable maps (mount parent, mount point) pairs to mounts. It supports // efficient concurrent lookup, even in the presence of concurrent mutators // (provided mutation is sufficiently uncommon). @@ -92,6 +98,7 @@ type mountTable struct { // length and cap in separate uint32s) for ~free. size uint64 + // FIXME(gvisor.dev/issue/1663): Slots need to be saved. slots unsafe.Pointer `state:"nosave"` // []mountSlot; never nil after Init } diff --git a/pkg/sentry/vfs/options.go b/pkg/sentry/vfs/options.go index 413cfb101..bc79e5ecc 100644 --- a/pkg/sentry/vfs/options.go +++ b/pkg/sentry/vfs/options.go @@ -21,6 +21,8 @@ import ( // GetDentryOptions contains options to VirtualFilesystem.GetDentryAt() and // FilesystemImpl.GetDentryAt(). +// +// +stateify savable type GetDentryOptions struct { // If CheckSearchable is true, FilesystemImpl.GetDentryAt() must check that // the returned Dentry is a directory for which creds has search @@ -30,6 +32,8 @@ type GetDentryOptions struct { // MkdirOptions contains options to VirtualFilesystem.MkdirAt() and // FilesystemImpl.MkdirAt(). +// +// +stateify savable type MkdirOptions struct { // Mode is the file mode bits for the created directory. Mode linux.FileMode @@ -56,6 +60,8 @@ type MkdirOptions struct { // MknodOptions contains options to VirtualFilesystem.MknodAt() and // FilesystemImpl.MknodAt(). +// +// +stateify savable type MknodOptions struct { // Mode is the file type and mode bits for the created file. Mode linux.FileMode @@ -72,6 +78,8 @@ type MknodOptions struct { // MountFlags contains flags as specified for mount(2), e.g. MS_NOEXEC. // MS_RDONLY is not part of MountFlags because it's tracked in Mount.writers. +// +// +stateify savable type MountFlags struct { // NoExec is equivalent to MS_NOEXEC. NoExec bool @@ -93,6 +101,8 @@ type MountFlags struct { } // MountOptions contains options to VirtualFilesystem.MountAt(). +// +// +stateify savable type MountOptions struct { // Flags contains flags as specified for mount(2), e.g. MS_NOEXEC. Flags MountFlags @@ -112,6 +122,8 @@ type MountOptions struct { // OpenOptions contains options to VirtualFilesystem.OpenAt() and // FilesystemImpl.OpenAt(). +// +// +stateify savable type OpenOptions struct { // Flags contains access mode and flags as specified for open(2). // @@ -137,6 +149,8 @@ type OpenOptions struct { // ReadOptions contains options to FileDescription.PRead(), // FileDescriptionImpl.PRead(), FileDescription.Read(), and // FileDescriptionImpl.Read(). +// +// +stateify savable type ReadOptions struct { // Flags contains flags as specified for preadv2(2). Flags uint32 @@ -144,6 +158,8 @@ type ReadOptions struct { // RenameOptions contains options to VirtualFilesystem.RenameAt() and // FilesystemImpl.RenameAt(). +// +// +stateify savable type RenameOptions struct { // Flags contains flags as specified for renameat2(2). Flags uint32 @@ -155,6 +171,8 @@ type RenameOptions struct { // SetStatOptions contains options to VirtualFilesystem.SetStatAt(), // FilesystemImpl.SetStatAt(), FileDescription.SetStat(), and // FileDescriptionImpl.SetStat(). +// +// +stateify savable type SetStatOptions struct { // Stat is the metadata that should be set. Only fields indicated by // Stat.Mask should be set. @@ -176,6 +194,8 @@ type SetStatOptions struct { // BoundEndpointOptions contains options to VirtualFilesystem.BoundEndpointAt() // and FilesystemImpl.BoundEndpointAt(). +// +// +stateify savable type BoundEndpointOptions struct { // Addr is the path of the file whose socket endpoint is being retrieved. // It is generally irrelevant: most endpoints are stored at a dentry that @@ -195,6 +215,8 @@ type BoundEndpointOptions struct { // GetXattrOptions contains options to VirtualFilesystem.GetXattrAt(), // FilesystemImpl.GetXattrAt(), FileDescription.GetXattr(), and // FileDescriptionImpl.GetXattr(). +// +// +stateify savable type GetXattrOptions struct { // Name is the name of the extended attribute to retrieve. Name string @@ -209,6 +231,8 @@ type GetXattrOptions struct { // SetXattrOptions contains options to VirtualFilesystem.SetXattrAt(), // FilesystemImpl.SetXattrAt(), FileDescription.SetXattr(), and // FileDescriptionImpl.SetXattr(). +// +// +stateify savable type SetXattrOptions struct { // Name is the name of the extended attribute being mutated. Name string @@ -223,6 +247,8 @@ type SetXattrOptions struct { // StatOptions contains options to VirtualFilesystem.StatAt(), // FilesystemImpl.StatAt(), FileDescription.Stat(), and // FileDescriptionImpl.Stat(). +// +// +stateify savable type StatOptions struct { // Mask is the set of fields in the returned Statx that the FilesystemImpl // or FileDescriptionImpl should provide. Bits are as in linux.Statx.Mask. @@ -240,6 +266,8 @@ type StatOptions struct { } // UmountOptions contains options to VirtualFilesystem.UmountAt(). +// +// +stateify savable type UmountOptions struct { // Flags contains flags as specified for umount2(2). Flags uint32 @@ -248,6 +276,8 @@ type UmountOptions struct { // WriteOptions contains options to FileDescription.PWrite(), // FileDescriptionImpl.PWrite(), FileDescription.Write(), and // FileDescriptionImpl.Write(). +// +// +stateify savable type WriteOptions struct { // Flags contains flags as specified for pwritev2(2). Flags uint32 diff --git a/pkg/sentry/vfs/permissions.go b/pkg/sentry/vfs/permissions.go index 00eeb8842..d48520d58 100644 --- a/pkg/sentry/vfs/permissions.go +++ b/pkg/sentry/vfs/permissions.go @@ -26,6 +26,8 @@ import ( ) // AccessTypes is a bitmask of Unix file permissions. +// +// +stateify savable type AccessTypes uint16 // Bits in AccessTypes. diff --git a/pkg/sentry/vfs/resolving_path.go b/pkg/sentry/vfs/resolving_path.go index 3304372d9..e4fd55012 100644 --- a/pkg/sentry/vfs/resolving_path.go +++ b/pkg/sentry/vfs/resolving_path.go @@ -35,6 +35,8 @@ import ( // FilesystemImpl methods. // // ResolvingPath is loosely analogous to Linux's struct nameidata. +// +// +stateify savable type ResolvingPath struct { vfs *VirtualFilesystem root VirtualDentry // refs borrowed from PathOperation @@ -88,6 +90,7 @@ func init() { // so error "constants" are really mutable vars, necessitating somewhat // expensive interface object comparisons. +// +stateify savable type resolveMountRootOrJumpError struct{} // Error implements error.Error. @@ -95,6 +98,7 @@ func (resolveMountRootOrJumpError) Error() string { return "resolving mount root or jump" } +// +stateify savable type resolveMountPointError struct{} // Error implements error.Error. @@ -102,6 +106,7 @@ func (resolveMountPointError) Error() string { return "resolving mount point" } +// +stateify savable type resolveAbsSymlinkError struct{} // Error implements error.Error. diff --git a/pkg/sentry/vfs/vfs.go b/pkg/sentry/vfs/vfs.go index 1ebf355ef..5bd756ea5 100644 --- a/pkg/sentry/vfs/vfs.go +++ b/pkg/sentry/vfs/vfs.go @@ -163,6 +163,8 @@ func (vfs *VirtualFilesystem) Init(ctx context.Context) error { // PathOperation is passed to VFS methods by pointer to reduce memory copying: // it's somewhat large and should never escape. (Options structs are passed by // pointer to VFS and FileDescription methods for the same reason.) +// +// +stateify savable type PathOperation struct { // Root is the VFS root. References on Root are borrowed from the provider // of the PathOperation. diff --git a/pkg/sentry/vfs/vfs_state_autogen.go b/pkg/sentry/vfs/vfs_state_autogen.go index be649f60a..3c35d1577 100644 --- a/pkg/sentry/vfs/vfs_state_autogen.go +++ b/pkg/sentry/vfs/vfs_state_autogen.go @@ -6,6 +6,77 @@ import ( "gvisor.dev/gvisor/pkg/state" ) +func (x *anonFilesystemType) StateTypeName() string { + return "pkg/sentry/vfs.anonFilesystemType" +} + +func (x *anonFilesystemType) StateFields() []string { + return []string{} +} + +func (x *anonFilesystemType) beforeSave() {} + +func (x *anonFilesystemType) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *anonFilesystemType) afterLoad() {} + +func (x *anonFilesystemType) StateLoad(m state.Source) { +} + +func (x *anonFilesystem) StateTypeName() string { + return "pkg/sentry/vfs.anonFilesystem" +} + +func (x *anonFilesystem) StateFields() []string { + return []string{ + "vfsfs", + "devMinor", + } +} + +func (x *anonFilesystem) beforeSave() {} + +func (x *anonFilesystem) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfs) + m.Save(1, &x.devMinor) +} + +func (x *anonFilesystem) afterLoad() {} + +func (x *anonFilesystem) StateLoad(m state.Source) { + m.Load(0, &x.vfsfs) + m.Load(1, &x.devMinor) +} + +func (x *anonDentry) StateTypeName() string { + return "pkg/sentry/vfs.anonDentry" +} + +func (x *anonDentry) StateFields() []string { + return []string{ + "vfsd", + "name", + } +} + +func (x *anonDentry) beforeSave() {} + +func (x *anonDentry) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsd) + m.Save(1, &x.name) +} + +func (x *anonDentry) afterLoad() {} + +func (x *anonDentry) StateLoad(m state.Source) { + m.Load(0, &x.vfsd) + m.Load(1, &x.name) +} + func (x *Dentry) StateTypeName() string { return "pkg/sentry/vfs.Dentry" } @@ -35,6 +106,43 @@ func (x *Dentry) StateLoad(m state.Source) { m.Load(2, &x.impl) } +func (x *DeviceKind) StateTypeName() string { + return "pkg/sentry/vfs.DeviceKind" +} + +func (x *DeviceKind) StateFields() []string { + return nil +} + +func (x *devTuple) StateTypeName() string { + return "pkg/sentry/vfs.devTuple" +} + +func (x *devTuple) StateFields() []string { + return []string{ + "kind", + "major", + "minor", + } +} + +func (x *devTuple) beforeSave() {} + +func (x *devTuple) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.kind) + m.Save(1, &x.major) + m.Save(2, &x.minor) +} + +func (x *devTuple) afterLoad() {} + +func (x *devTuple) StateLoad(m state.Source) { + m.Load(0, &x.kind) + m.Load(1, &x.major) + m.Load(2, &x.minor) +} + func (x *registeredDevice) StateTypeName() string { return "pkg/sentry/vfs.registeredDevice" } @@ -84,6 +192,114 @@ func (x *RegisterDeviceOptions) StateLoad(m state.Source) { m.Load(0, &x.GroupName) } +func (x *EpollInstance) StateTypeName() string { + return "pkg/sentry/vfs.EpollInstance" +} + +func (x *EpollInstance) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "DentryMetadataFileDescriptionImpl", + "NoLockFD", + "q", + "interest", + "ready", + } +} + +func (x *EpollInstance) beforeSave() {} + +func (x *EpollInstance) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfsfd) + m.Save(1, &x.FileDescriptionDefaultImpl) + m.Save(2, &x.DentryMetadataFileDescriptionImpl) + m.Save(3, &x.NoLockFD) + m.Save(4, &x.q) + m.Save(5, &x.interest) + m.Save(6, &x.ready) +} + +func (x *EpollInstance) afterLoad() {} + +func (x *EpollInstance) StateLoad(m state.Source) { + m.Load(0, &x.vfsfd) + m.Load(1, &x.FileDescriptionDefaultImpl) + m.Load(2, &x.DentryMetadataFileDescriptionImpl) + m.Load(3, &x.NoLockFD) + m.Load(4, &x.q) + m.Load(5, &x.interest) + m.Load(6, &x.ready) +} + +func (x *epollInterestKey) StateTypeName() string { + return "pkg/sentry/vfs.epollInterestKey" +} + +func (x *epollInterestKey) StateFields() []string { + return []string{ + "file", + "num", + } +} + +func (x *epollInterestKey) beforeSave() {} + +func (x *epollInterestKey) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.file) + m.Save(1, &x.num) +} + +func (x *epollInterestKey) afterLoad() {} + +func (x *epollInterestKey) StateLoad(m state.Source) { + m.Load(0, &x.file) + m.Load(1, &x.num) +} + +func (x *epollInterest) StateTypeName() string { + return "pkg/sentry/vfs.epollInterest" +} + +func (x *epollInterest) StateFields() []string { + return []string{ + "epoll", + "key", + "waiter", + "mask", + "ready", + "epollInterestEntry", + "userData", + } +} + +func (x *epollInterest) beforeSave() {} + +func (x *epollInterest) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.epoll) + m.Save(1, &x.key) + m.Save(2, &x.waiter) + m.Save(3, &x.mask) + m.Save(4, &x.ready) + m.Save(5, &x.epollInterestEntry) + m.Save(6, &x.userData) +} + +func (x *epollInterest) afterLoad() {} + +func (x *epollInterest) StateLoad(m state.Source) { + m.Load(0, &x.epoll) + m.Load(1, &x.key) + m.Load(2, &x.waiter) + m.Load(3, &x.mask) + m.Load(4, &x.ready) + m.Load(5, &x.epollInterestEntry) + m.Load(6, &x.userData) +} + func (x *epollInterestList) StateTypeName() string { return "pkg/sentry/vfs.epollInterestList" } @@ -188,6 +404,275 @@ func (x *eventEntry) StateLoad(m state.Source) { m.Load(1, &x.prev) } +func (x *FileDescription) StateTypeName() string { + return "pkg/sentry/vfs.FileDescription" +} + +func (x *FileDescription) StateFields() []string { + return []string{ + "FileDescriptionRefs", + "statusFlags", + "asyncHandler", + "epolls", + "vd", + "opts", + "readable", + "writable", + "usedLockBSD", + "impl", + } +} + +func (x *FileDescription) beforeSave() {} + +func (x *FileDescription) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.FileDescriptionRefs) + m.Save(1, &x.statusFlags) + m.Save(2, &x.asyncHandler) + m.Save(3, &x.epolls) + m.Save(4, &x.vd) + m.Save(5, &x.opts) + m.Save(6, &x.readable) + m.Save(7, &x.writable) + m.Save(8, &x.usedLockBSD) + m.Save(9, &x.impl) +} + +func (x *FileDescription) afterLoad() {} + +func (x *FileDescription) StateLoad(m state.Source) { + m.Load(0, &x.FileDescriptionRefs) + m.Load(1, &x.statusFlags) + m.Load(2, &x.asyncHandler) + m.Load(3, &x.epolls) + m.Load(4, &x.vd) + m.Load(5, &x.opts) + m.Load(6, &x.readable) + m.Load(7, &x.writable) + m.Load(8, &x.usedLockBSD) + m.Load(9, &x.impl) +} + +func (x *FileDescriptionOptions) StateTypeName() string { + return "pkg/sentry/vfs.FileDescriptionOptions" +} + +func (x *FileDescriptionOptions) StateFields() []string { + return []string{ + "AllowDirectIO", + "DenyPRead", + "DenyPWrite", + "UseDentryMetadata", + } +} + +func (x *FileDescriptionOptions) beforeSave() {} + +func (x *FileDescriptionOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.AllowDirectIO) + m.Save(1, &x.DenyPRead) + m.Save(2, &x.DenyPWrite) + m.Save(3, &x.UseDentryMetadata) +} + +func (x *FileDescriptionOptions) afterLoad() {} + +func (x *FileDescriptionOptions) StateLoad(m state.Source) { + m.Load(0, &x.AllowDirectIO) + m.Load(1, &x.DenyPRead) + m.Load(2, &x.DenyPWrite) + m.Load(3, &x.UseDentryMetadata) +} + +func (x *Dirent) StateTypeName() string { + return "pkg/sentry/vfs.Dirent" +} + +func (x *Dirent) StateFields() []string { + return []string{ + "Name", + "Type", + "Ino", + "NextOff", + } +} + +func (x *Dirent) beforeSave() {} + +func (x *Dirent) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Name) + m.Save(1, &x.Type) + m.Save(2, &x.Ino) + m.Save(3, &x.NextOff) +} + +func (x *Dirent) afterLoad() {} + +func (x *Dirent) StateLoad(m state.Source) { + m.Load(0, &x.Name) + m.Load(1, &x.Type) + m.Load(2, &x.Ino) + m.Load(3, &x.NextOff) +} + +func (x *FileDescriptionDefaultImpl) StateTypeName() string { + return "pkg/sentry/vfs.FileDescriptionDefaultImpl" +} + +func (x *FileDescriptionDefaultImpl) StateFields() []string { + return []string{} +} + +func (x *FileDescriptionDefaultImpl) beforeSave() {} + +func (x *FileDescriptionDefaultImpl) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *FileDescriptionDefaultImpl) afterLoad() {} + +func (x *FileDescriptionDefaultImpl) StateLoad(m state.Source) { +} + +func (x *DirectoryFileDescriptionDefaultImpl) StateTypeName() string { + return "pkg/sentry/vfs.DirectoryFileDescriptionDefaultImpl" +} + +func (x *DirectoryFileDescriptionDefaultImpl) StateFields() []string { + return []string{} +} + +func (x *DirectoryFileDescriptionDefaultImpl) beforeSave() {} + +func (x *DirectoryFileDescriptionDefaultImpl) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *DirectoryFileDescriptionDefaultImpl) afterLoad() {} + +func (x *DirectoryFileDescriptionDefaultImpl) StateLoad(m state.Source) { +} + +func (x *DentryMetadataFileDescriptionImpl) StateTypeName() string { + return "pkg/sentry/vfs.DentryMetadataFileDescriptionImpl" +} + +func (x *DentryMetadataFileDescriptionImpl) StateFields() []string { + return []string{} +} + +func (x *DentryMetadataFileDescriptionImpl) beforeSave() {} + +func (x *DentryMetadataFileDescriptionImpl) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *DentryMetadataFileDescriptionImpl) afterLoad() {} + +func (x *DentryMetadataFileDescriptionImpl) StateLoad(m state.Source) { +} + +func (x *StaticData) StateTypeName() string { + return "pkg/sentry/vfs.StaticData" +} + +func (x *StaticData) StateFields() []string { + return []string{ + "Data", + } +} + +func (x *StaticData) beforeSave() {} + +func (x *StaticData) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Data) +} + +func (x *StaticData) afterLoad() {} + +func (x *StaticData) StateLoad(m state.Source) { + m.Load(0, &x.Data) +} + +func (x *DynamicBytesFileDescriptionImpl) StateTypeName() string { + return "pkg/sentry/vfs.DynamicBytesFileDescriptionImpl" +} + +func (x *DynamicBytesFileDescriptionImpl) StateFields() []string { + return []string{ + "data", + "buf", + "off", + "lastRead", + } +} + +func (x *DynamicBytesFileDescriptionImpl) beforeSave() {} + +func (x *DynamicBytesFileDescriptionImpl) StateSave(m state.Sink) { + x.beforeSave() + var buf []byte = x.saveBuf() + m.SaveValue(1, buf) + m.Save(0, &x.data) + m.Save(2, &x.off) + m.Save(3, &x.lastRead) +} + +func (x *DynamicBytesFileDescriptionImpl) afterLoad() {} + +func (x *DynamicBytesFileDescriptionImpl) StateLoad(m state.Source) { + m.Load(0, &x.data) + m.Load(2, &x.off) + m.Load(3, &x.lastRead) + m.LoadValue(1, new([]byte), func(y interface{}) { x.loadBuf(y.([]byte)) }) +} + +func (x *LockFD) StateTypeName() string { + return "pkg/sentry/vfs.LockFD" +} + +func (x *LockFD) StateFields() []string { + return []string{ + "locks", + } +} + +func (x *LockFD) beforeSave() {} + +func (x *LockFD) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.locks) +} + +func (x *LockFD) afterLoad() {} + +func (x *LockFD) StateLoad(m state.Source) { + m.Load(0, &x.locks) +} + +func (x *NoLockFD) StateTypeName() string { + return "pkg/sentry/vfs.NoLockFD" +} + +func (x *NoLockFD) StateFields() []string { + return []string{} +} + +func (x *NoLockFD) beforeSave() {} + +func (x *NoLockFD) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *NoLockFD) afterLoad() {} + +func (x *NoLockFD) StateLoad(m state.Source) { +} + func (x *FileDescriptionRefs) StateTypeName() string { return "pkg/sentry/vfs.FileDescriptionRefs" } @@ -243,6 +728,63 @@ func (x *Filesystem) StateLoad(m state.Source) { m.Load(3, &x.impl) } +func (x *PrependPathAtVFSRootError) StateTypeName() string { + return "pkg/sentry/vfs.PrependPathAtVFSRootError" +} + +func (x *PrependPathAtVFSRootError) StateFields() []string { + return []string{} +} + +func (x *PrependPathAtVFSRootError) beforeSave() {} + +func (x *PrependPathAtVFSRootError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *PrependPathAtVFSRootError) afterLoad() {} + +func (x *PrependPathAtVFSRootError) StateLoad(m state.Source) { +} + +func (x *PrependPathAtNonMountRootError) StateTypeName() string { + return "pkg/sentry/vfs.PrependPathAtNonMountRootError" +} + +func (x *PrependPathAtNonMountRootError) StateFields() []string { + return []string{} +} + +func (x *PrependPathAtNonMountRootError) beforeSave() {} + +func (x *PrependPathAtNonMountRootError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *PrependPathAtNonMountRootError) afterLoad() {} + +func (x *PrependPathAtNonMountRootError) StateLoad(m state.Source) { +} + +func (x *PrependPathSyntheticError) StateTypeName() string { + return "pkg/sentry/vfs.PrependPathSyntheticError" +} + +func (x *PrependPathSyntheticError) StateFields() []string { + return []string{} +} + +func (x *PrependPathSyntheticError) beforeSave() {} + +func (x *PrependPathSyntheticError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *PrependPathSyntheticError) afterLoad() {} + +func (x *PrependPathSyntheticError) StateLoad(m state.Source) { +} + func (x *FilesystemRefs) StateTypeName() string { return "pkg/sentry/vfs.FilesystemRefs" } @@ -292,6 +834,43 @@ func (x *registeredFilesystemType) StateLoad(m state.Source) { m.Load(1, &x.opts) } +func (x *RegisterFilesystemTypeOptions) StateTypeName() string { + return "pkg/sentry/vfs.RegisterFilesystemTypeOptions" +} + +func (x *RegisterFilesystemTypeOptions) StateFields() []string { + return []string{ + "AllowUserMount", + "AllowUserList", + "RequiresDevice", + } +} + +func (x *RegisterFilesystemTypeOptions) beforeSave() {} + +func (x *RegisterFilesystemTypeOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.AllowUserMount) + m.Save(1, &x.AllowUserList) + m.Save(2, &x.RequiresDevice) +} + +func (x *RegisterFilesystemTypeOptions) afterLoad() {} + +func (x *RegisterFilesystemTypeOptions) StateLoad(m state.Source) { + m.Load(0, &x.AllowUserMount) + m.Load(1, &x.AllowUserList) + m.Load(2, &x.RequiresDevice) +} + +func (x *EventType) StateTypeName() string { + return "pkg/sentry/vfs.EventType" +} + +func (x *EventType) StateFields() []string { + return nil +} + func (x *Inotify) StateTypeName() string { return "pkg/sentry/vfs.Inotify" } @@ -435,6 +1014,32 @@ func (x *Event) StateLoad(m state.Source) { m.Load(5, &x.name) } +func (x *FileLocks) StateTypeName() string { + return "pkg/sentry/vfs.FileLocks" +} + +func (x *FileLocks) StateFields() []string { + return []string{ + "bsd", + "posix", + } +} + +func (x *FileLocks) beforeSave() {} + +func (x *FileLocks) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.bsd) + m.Save(1, &x.posix) +} + +func (x *FileLocks) afterLoad() {} + +func (x *FileLocks) StateLoad(m state.Source) { + m.Load(0, &x.bsd) + m.Load(1, &x.posix) +} + func (x *Mount) StateTypeName() string { return "pkg/sentry/vfs.Mount" } @@ -459,12 +1064,13 @@ func (x *Mount) beforeSave() {} func (x *Mount) StateSave(m state.Sink) { x.beforeSave() + var key VirtualDentry = x.saveKey() + m.SaveValue(5, key) m.Save(0, &x.vfs) m.Save(1, &x.fs) m.Save(2, &x.root) m.Save(3, &x.ID) m.Save(4, &x.Flags) - m.Save(5, &x.key) m.Save(6, &x.ns) m.Save(7, &x.refs) m.Save(8, &x.children) @@ -480,12 +1086,12 @@ func (x *Mount) StateLoad(m state.Source) { m.Load(2, &x.root) m.Load(3, &x.ID) m.Load(4, &x.Flags) - m.Load(5, &x.key) m.Load(6, &x.ns) m.Load(7, &x.refs) m.Load(8, &x.children) m.Load(9, &x.umounted) m.Load(10, &x.writers) + m.LoadValue(5, new(VirtualDentry), func(y interface{}) { x.loadKey(y.(VirtualDentry)) }) } func (x *MountNamespace) StateTypeName() string { @@ -520,6 +1126,32 @@ func (x *MountNamespace) StateLoad(m state.Source) { m.Load(3, &x.mountpoints) } +func (x *umountRecursiveOptions) StateTypeName() string { + return "pkg/sentry/vfs.umountRecursiveOptions" +} + +func (x *umountRecursiveOptions) StateFields() []string { + return []string{ + "eager", + "disconnectHierarchy", + } +} + +func (x *umountRecursiveOptions) beforeSave() {} + +func (x *umountRecursiveOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.eager) + m.Save(1, &x.disconnectHierarchy) +} + +func (x *umountRecursiveOptions) afterLoad() {} + +func (x *umountRecursiveOptions) StateLoad(m state.Source) { + m.Load(0, &x.eager) + m.Load(1, &x.disconnectHierarchy) +} + func (x *MountNamespaceRefs) StateTypeName() string { return "pkg/sentry/vfs.MountNamespaceRefs" } @@ -543,6 +1175,544 @@ func (x *MountNamespaceRefs) StateLoad(m state.Source) { m.Load(0, &x.refCount) } +func (x *GetDentryOptions) StateTypeName() string { + return "pkg/sentry/vfs.GetDentryOptions" +} + +func (x *GetDentryOptions) StateFields() []string { + return []string{ + "CheckSearchable", + } +} + +func (x *GetDentryOptions) beforeSave() {} + +func (x *GetDentryOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.CheckSearchable) +} + +func (x *GetDentryOptions) afterLoad() {} + +func (x *GetDentryOptions) StateLoad(m state.Source) { + m.Load(0, &x.CheckSearchable) +} + +func (x *MkdirOptions) StateTypeName() string { + return "pkg/sentry/vfs.MkdirOptions" +} + +func (x *MkdirOptions) StateFields() []string { + return []string{ + "Mode", + "ForSyntheticMountpoint", + } +} + +func (x *MkdirOptions) beforeSave() {} + +func (x *MkdirOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Mode) + m.Save(1, &x.ForSyntheticMountpoint) +} + +func (x *MkdirOptions) afterLoad() {} + +func (x *MkdirOptions) StateLoad(m state.Source) { + m.Load(0, &x.Mode) + m.Load(1, &x.ForSyntheticMountpoint) +} + +func (x *MknodOptions) StateTypeName() string { + return "pkg/sentry/vfs.MknodOptions" +} + +func (x *MknodOptions) StateFields() []string { + return []string{ + "Mode", + "DevMajor", + "DevMinor", + "Endpoint", + } +} + +func (x *MknodOptions) beforeSave() {} + +func (x *MknodOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Mode) + m.Save(1, &x.DevMajor) + m.Save(2, &x.DevMinor) + m.Save(3, &x.Endpoint) +} + +func (x *MknodOptions) afterLoad() {} + +func (x *MknodOptions) StateLoad(m state.Source) { + m.Load(0, &x.Mode) + m.Load(1, &x.DevMajor) + m.Load(2, &x.DevMinor) + m.Load(3, &x.Endpoint) +} + +func (x *MountFlags) StateTypeName() string { + return "pkg/sentry/vfs.MountFlags" +} + +func (x *MountFlags) StateFields() []string { + return []string{ + "NoExec", + "NoATime", + "NoDev", + "NoSUID", + } +} + +func (x *MountFlags) beforeSave() {} + +func (x *MountFlags) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.NoExec) + m.Save(1, &x.NoATime) + m.Save(2, &x.NoDev) + m.Save(3, &x.NoSUID) +} + +func (x *MountFlags) afterLoad() {} + +func (x *MountFlags) StateLoad(m state.Source) { + m.Load(0, &x.NoExec) + m.Load(1, &x.NoATime) + m.Load(2, &x.NoDev) + m.Load(3, &x.NoSUID) +} + +func (x *MountOptions) StateTypeName() string { + return "pkg/sentry/vfs.MountOptions" +} + +func (x *MountOptions) StateFields() []string { + return []string{ + "Flags", + "ReadOnly", + "GetFilesystemOptions", + "InternalMount", + } +} + +func (x *MountOptions) beforeSave() {} + +func (x *MountOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Flags) + m.Save(1, &x.ReadOnly) + m.Save(2, &x.GetFilesystemOptions) + m.Save(3, &x.InternalMount) +} + +func (x *MountOptions) afterLoad() {} + +func (x *MountOptions) StateLoad(m state.Source) { + m.Load(0, &x.Flags) + m.Load(1, &x.ReadOnly) + m.Load(2, &x.GetFilesystemOptions) + m.Load(3, &x.InternalMount) +} + +func (x *OpenOptions) StateTypeName() string { + return "pkg/sentry/vfs.OpenOptions" +} + +func (x *OpenOptions) StateFields() []string { + return []string{ + "Flags", + "Mode", + "FileExec", + } +} + +func (x *OpenOptions) beforeSave() {} + +func (x *OpenOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Flags) + m.Save(1, &x.Mode) + m.Save(2, &x.FileExec) +} + +func (x *OpenOptions) afterLoad() {} + +func (x *OpenOptions) StateLoad(m state.Source) { + m.Load(0, &x.Flags) + m.Load(1, &x.Mode) + m.Load(2, &x.FileExec) +} + +func (x *ReadOptions) StateTypeName() string { + return "pkg/sentry/vfs.ReadOptions" +} + +func (x *ReadOptions) StateFields() []string { + return []string{ + "Flags", + } +} + +func (x *ReadOptions) beforeSave() {} + +func (x *ReadOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Flags) +} + +func (x *ReadOptions) afterLoad() {} + +func (x *ReadOptions) StateLoad(m state.Source) { + m.Load(0, &x.Flags) +} + +func (x *RenameOptions) StateTypeName() string { + return "pkg/sentry/vfs.RenameOptions" +} + +func (x *RenameOptions) StateFields() []string { + return []string{ + "Flags", + "MustBeDir", + } +} + +func (x *RenameOptions) beforeSave() {} + +func (x *RenameOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Flags) + m.Save(1, &x.MustBeDir) +} + +func (x *RenameOptions) afterLoad() {} + +func (x *RenameOptions) StateLoad(m state.Source) { + m.Load(0, &x.Flags) + m.Load(1, &x.MustBeDir) +} + +func (x *SetStatOptions) StateTypeName() string { + return "pkg/sentry/vfs.SetStatOptions" +} + +func (x *SetStatOptions) StateFields() []string { + return []string{ + "Stat", + "NeedWritePerm", + } +} + +func (x *SetStatOptions) beforeSave() {} + +func (x *SetStatOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Stat) + m.Save(1, &x.NeedWritePerm) +} + +func (x *SetStatOptions) afterLoad() {} + +func (x *SetStatOptions) StateLoad(m state.Source) { + m.Load(0, &x.Stat) + m.Load(1, &x.NeedWritePerm) +} + +func (x *BoundEndpointOptions) StateTypeName() string { + return "pkg/sentry/vfs.BoundEndpointOptions" +} + +func (x *BoundEndpointOptions) StateFields() []string { + return []string{ + "Addr", + } +} + +func (x *BoundEndpointOptions) beforeSave() {} + +func (x *BoundEndpointOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Addr) +} + +func (x *BoundEndpointOptions) afterLoad() {} + +func (x *BoundEndpointOptions) StateLoad(m state.Source) { + m.Load(0, &x.Addr) +} + +func (x *GetXattrOptions) StateTypeName() string { + return "pkg/sentry/vfs.GetXattrOptions" +} + +func (x *GetXattrOptions) StateFields() []string { + return []string{ + "Name", + "Size", + } +} + +func (x *GetXattrOptions) beforeSave() {} + +func (x *GetXattrOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Name) + m.Save(1, &x.Size) +} + +func (x *GetXattrOptions) afterLoad() {} + +func (x *GetXattrOptions) StateLoad(m state.Source) { + m.Load(0, &x.Name) + m.Load(1, &x.Size) +} + +func (x *SetXattrOptions) StateTypeName() string { + return "pkg/sentry/vfs.SetXattrOptions" +} + +func (x *SetXattrOptions) StateFields() []string { + return []string{ + "Name", + "Value", + "Flags", + } +} + +func (x *SetXattrOptions) beforeSave() {} + +func (x *SetXattrOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Name) + m.Save(1, &x.Value) + m.Save(2, &x.Flags) +} + +func (x *SetXattrOptions) afterLoad() {} + +func (x *SetXattrOptions) StateLoad(m state.Source) { + m.Load(0, &x.Name) + m.Load(1, &x.Value) + m.Load(2, &x.Flags) +} + +func (x *StatOptions) StateTypeName() string { + return "pkg/sentry/vfs.StatOptions" +} + +func (x *StatOptions) StateFields() []string { + return []string{ + "Mask", + "Sync", + } +} + +func (x *StatOptions) beforeSave() {} + +func (x *StatOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Mask) + m.Save(1, &x.Sync) +} + +func (x *StatOptions) afterLoad() {} + +func (x *StatOptions) StateLoad(m state.Source) { + m.Load(0, &x.Mask) + m.Load(1, &x.Sync) +} + +func (x *UmountOptions) StateTypeName() string { + return "pkg/sentry/vfs.UmountOptions" +} + +func (x *UmountOptions) StateFields() []string { + return []string{ + "Flags", + } +} + +func (x *UmountOptions) beforeSave() {} + +func (x *UmountOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Flags) +} + +func (x *UmountOptions) afterLoad() {} + +func (x *UmountOptions) StateLoad(m state.Source) { + m.Load(0, &x.Flags) +} + +func (x *WriteOptions) StateTypeName() string { + return "pkg/sentry/vfs.WriteOptions" +} + +func (x *WriteOptions) StateFields() []string { + return []string{ + "Flags", + } +} + +func (x *WriteOptions) beforeSave() {} + +func (x *WriteOptions) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Flags) +} + +func (x *WriteOptions) afterLoad() {} + +func (x *WriteOptions) StateLoad(m state.Source) { + m.Load(0, &x.Flags) +} + +func (x *AccessTypes) StateTypeName() string { + return "pkg/sentry/vfs.AccessTypes" +} + +func (x *AccessTypes) StateFields() []string { + return nil +} + +func (x *ResolvingPath) StateTypeName() string { + return "pkg/sentry/vfs.ResolvingPath" +} + +func (x *ResolvingPath) StateFields() []string { + return []string{ + "vfs", + "root", + "mount", + "start", + "pit", + "flags", + "mustBeDir", + "mustBeDirOrig", + "symlinks", + "symlinksOrig", + "curPart", + "numOrigParts", + "creds", + "nextMount", + "nextStart", + "absSymlinkTarget", + "parts", + "origParts", + } +} + +func (x *ResolvingPath) beforeSave() {} + +func (x *ResolvingPath) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.vfs) + m.Save(1, &x.root) + m.Save(2, &x.mount) + m.Save(3, &x.start) + m.Save(4, &x.pit) + m.Save(5, &x.flags) + m.Save(6, &x.mustBeDir) + m.Save(7, &x.mustBeDirOrig) + m.Save(8, &x.symlinks) + m.Save(9, &x.symlinksOrig) + m.Save(10, &x.curPart) + m.Save(11, &x.numOrigParts) + m.Save(12, &x.creds) + m.Save(13, &x.nextMount) + m.Save(14, &x.nextStart) + m.Save(15, &x.absSymlinkTarget) + m.Save(16, &x.parts) + m.Save(17, &x.origParts) +} + +func (x *ResolvingPath) afterLoad() {} + +func (x *ResolvingPath) StateLoad(m state.Source) { + m.Load(0, &x.vfs) + m.Load(1, &x.root) + m.Load(2, &x.mount) + m.Load(3, &x.start) + m.Load(4, &x.pit) + m.Load(5, &x.flags) + m.Load(6, &x.mustBeDir) + m.Load(7, &x.mustBeDirOrig) + m.Load(8, &x.symlinks) + m.Load(9, &x.symlinksOrig) + m.Load(10, &x.curPart) + m.Load(11, &x.numOrigParts) + m.Load(12, &x.creds) + m.Load(13, &x.nextMount) + m.Load(14, &x.nextStart) + m.Load(15, &x.absSymlinkTarget) + m.Load(16, &x.parts) + m.Load(17, &x.origParts) +} + +func (x *resolveMountRootOrJumpError) StateTypeName() string { + return "pkg/sentry/vfs.resolveMountRootOrJumpError" +} + +func (x *resolveMountRootOrJumpError) StateFields() []string { + return []string{} +} + +func (x *resolveMountRootOrJumpError) beforeSave() {} + +func (x *resolveMountRootOrJumpError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *resolveMountRootOrJumpError) afterLoad() {} + +func (x *resolveMountRootOrJumpError) StateLoad(m state.Source) { +} + +func (x *resolveMountPointError) StateTypeName() string { + return "pkg/sentry/vfs.resolveMountPointError" +} + +func (x *resolveMountPointError) StateFields() []string { + return []string{} +} + +func (x *resolveMountPointError) beforeSave() {} + +func (x *resolveMountPointError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *resolveMountPointError) afterLoad() {} + +func (x *resolveMountPointError) StateLoad(m state.Source) { +} + +func (x *resolveAbsSymlinkError) StateTypeName() string { + return "pkg/sentry/vfs.resolveAbsSymlinkError" +} + +func (x *resolveAbsSymlinkError) StateFields() []string { + return []string{} +} + +func (x *resolveAbsSymlinkError) beforeSave() {} + +func (x *resolveAbsSymlinkError) StateSave(m state.Sink) { + x.beforeSave() +} + +func (x *resolveAbsSymlinkError) afterLoad() {} + +func (x *resolveAbsSymlinkError) StateLoad(m state.Source) { +} + func (x *VirtualFilesystem) StateTypeName() string { return "pkg/sentry/vfs.VirtualFilesystem" } @@ -590,6 +1760,38 @@ func (x *VirtualFilesystem) StateLoad(m state.Source) { m.Load(8, &x.filesystems) } +func (x *PathOperation) StateTypeName() string { + return "pkg/sentry/vfs.PathOperation" +} + +func (x *PathOperation) StateFields() []string { + return []string{ + "Root", + "Start", + "Path", + "FollowFinalSymlink", + } +} + +func (x *PathOperation) beforeSave() {} + +func (x *PathOperation) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Root) + m.Save(1, &x.Start) + m.Save(2, &x.Path) + m.Save(3, &x.FollowFinalSymlink) +} + +func (x *PathOperation) afterLoad() {} + +func (x *PathOperation) StateLoad(m state.Source) { + m.Load(0, &x.Root) + m.Load(1, &x.Start) + m.Load(2, &x.Path) + m.Load(3, &x.FollowFinalSymlink) +} + func (x *VirtualDentry) StateTypeName() string { return "pkg/sentry/vfs.VirtualDentry" } @@ -617,24 +1819,70 @@ func (x *VirtualDentry) StateLoad(m state.Source) { } func init() { + state.Register((*anonFilesystemType)(nil)) + state.Register((*anonFilesystem)(nil)) + state.Register((*anonDentry)(nil)) state.Register((*Dentry)(nil)) + state.Register((*DeviceKind)(nil)) + state.Register((*devTuple)(nil)) state.Register((*registeredDevice)(nil)) state.Register((*RegisterDeviceOptions)(nil)) + state.Register((*EpollInstance)(nil)) + state.Register((*epollInterestKey)(nil)) + state.Register((*epollInterest)(nil)) state.Register((*epollInterestList)(nil)) state.Register((*epollInterestEntry)(nil)) state.Register((*eventList)(nil)) state.Register((*eventEntry)(nil)) + state.Register((*FileDescription)(nil)) + state.Register((*FileDescriptionOptions)(nil)) + state.Register((*Dirent)(nil)) + state.Register((*FileDescriptionDefaultImpl)(nil)) + state.Register((*DirectoryFileDescriptionDefaultImpl)(nil)) + state.Register((*DentryMetadataFileDescriptionImpl)(nil)) + state.Register((*StaticData)(nil)) + state.Register((*DynamicBytesFileDescriptionImpl)(nil)) + state.Register((*LockFD)(nil)) + state.Register((*NoLockFD)(nil)) state.Register((*FileDescriptionRefs)(nil)) state.Register((*Filesystem)(nil)) + state.Register((*PrependPathAtVFSRootError)(nil)) + state.Register((*PrependPathAtNonMountRootError)(nil)) + state.Register((*PrependPathSyntheticError)(nil)) state.Register((*FilesystemRefs)(nil)) state.Register((*registeredFilesystemType)(nil)) + state.Register((*RegisterFilesystemTypeOptions)(nil)) + state.Register((*EventType)(nil)) state.Register((*Inotify)(nil)) state.Register((*Watches)(nil)) state.Register((*Watch)(nil)) state.Register((*Event)(nil)) + state.Register((*FileLocks)(nil)) state.Register((*Mount)(nil)) state.Register((*MountNamespace)(nil)) + state.Register((*umountRecursiveOptions)(nil)) state.Register((*MountNamespaceRefs)(nil)) + state.Register((*GetDentryOptions)(nil)) + state.Register((*MkdirOptions)(nil)) + state.Register((*MknodOptions)(nil)) + state.Register((*MountFlags)(nil)) + state.Register((*MountOptions)(nil)) + state.Register((*OpenOptions)(nil)) + state.Register((*ReadOptions)(nil)) + state.Register((*RenameOptions)(nil)) + state.Register((*SetStatOptions)(nil)) + state.Register((*BoundEndpointOptions)(nil)) + state.Register((*GetXattrOptions)(nil)) + state.Register((*SetXattrOptions)(nil)) + state.Register((*StatOptions)(nil)) + state.Register((*UmountOptions)(nil)) + state.Register((*WriteOptions)(nil)) + state.Register((*AccessTypes)(nil)) + state.Register((*ResolvingPath)(nil)) + state.Register((*resolveMountRootOrJumpError)(nil)) + state.Register((*resolveMountPointError)(nil)) + state.Register((*resolveAbsSymlinkError)(nil)) state.Register((*VirtualFilesystem)(nil)) + state.Register((*PathOperation)(nil)) state.Register((*VirtualDentry)(nil)) } diff --git a/pkg/state/types.go b/pkg/state/types.go index 215ef80f8..84aed8732 100644 --- a/pkg/state/types.go +++ b/pkg/state/types.go @@ -107,6 +107,14 @@ func lookupNameFields(typ reflect.Type) (string, []string, bool) { } return name, nil, true } + // Sanity check the type. + if raceEnabled { + if _, ok := reverseTypeDatabase[typ]; !ok { + // The type was not registered? Must be an embedded + // structure or something else. + return "", nil, false + } + } // Extract the name from the object. name := t.StateTypeName() fields := t.StateFields() @@ -313,6 +321,9 @@ var primitiveTypeDatabase = func() map[string]reflect.Type { // globalTypeDatabase is used for dispatching interfaces on decode. var globalTypeDatabase = map[string]reflect.Type{} +// reverseTypeDatabase is a reverse mapping. +var reverseTypeDatabase = map[reflect.Type]string{} + // Register registers a type. // // This must be called on init and only done once. @@ -358,4 +369,7 @@ func Register(t Type) { Failf("conflicting name for %T: matches interfaceType", t) } globalTypeDatabase[name] = typ + if raceEnabled { + reverseTypeDatabase[typ] = name + } } |