diff options
Diffstat (limited to 'pkg/sentry/fsimpl/proc')
-rw-r--r-- | pkg/sentry/fsimpl/proc/BUILD | 134 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go | 140 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go | 140 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/proc_state_autogen.go | 2454 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/subtasks_inode_refs.go | 140 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/task_inode_refs.go | 140 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/tasks_inode_refs.go | 140 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/tasks_sys_test.go | 149 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/tasks_test.go | 511 |
9 files changed, 3154 insertions, 794 deletions
diff --git a/pkg/sentry/fsimpl/proc/BUILD b/pkg/sentry/fsimpl/proc/BUILD deleted file mode 100644 index 1d3d2d95f..000000000 --- a/pkg/sentry/fsimpl/proc/BUILD +++ /dev/null @@ -1,134 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") -load("//tools/go_generics:defs.bzl", "go_template_instance") - -licenses(["notice"]) - -go_template_instance( - name = "fd_dir_inode_refs", - out = "fd_dir_inode_refs.go", - package = "proc", - prefix = "fdDirInode", - template = "//pkg/refsvfs2:refs_template", - types = { - "T": "fdDirInode", - }, -) - -go_template_instance( - name = "fd_info_dir_inode_refs", - out = "fd_info_dir_inode_refs.go", - package = "proc", - prefix = "fdInfoDirInode", - template = "//pkg/refsvfs2:refs_template", - types = { - "T": "fdInfoDirInode", - }, -) - -go_template_instance( - name = "subtasks_inode_refs", - out = "subtasks_inode_refs.go", - package = "proc", - prefix = "subtasksInode", - template = "//pkg/refsvfs2:refs_template", - types = { - "T": "subtasksInode", - }, -) - -go_template_instance( - name = "task_inode_refs", - out = "task_inode_refs.go", - package = "proc", - prefix = "taskInode", - template = "//pkg/refsvfs2:refs_template", - types = { - "T": "taskInode", - }, -) - -go_template_instance( - name = "tasks_inode_refs", - out = "tasks_inode_refs.go", - package = "proc", - prefix = "tasksInode", - template = "//pkg/refsvfs2:refs_template", - types = { - "T": "tasksInode", - }, -) - -go_library( - name = "proc", - srcs = [ - "fd_dir_inode_refs.go", - "fd_info_dir_inode_refs.go", - "filesystem.go", - "subtasks.go", - "subtasks_inode_refs.go", - "task.go", - "task_fds.go", - "task_files.go", - "task_inode_refs.go", - "task_net.go", - "tasks.go", - "tasks_files.go", - "tasks_inode_refs.go", - "tasks_sys.go", - "yama.go", - ], - visibility = ["//pkg/sentry:internal"], - deps = [ - "//pkg/abi/linux", - "//pkg/context", - "//pkg/errors/linuxerr", - "//pkg/hostarch", - "//pkg/log", - "//pkg/refs", - "//pkg/refsvfs2", - "//pkg/safemem", - "//pkg/sentry/fs/lock", - "//pkg/sentry/fsbridge", - "//pkg/sentry/fsimpl/kernfs", - "//pkg/sentry/inet", - "//pkg/sentry/kernel", - "//pkg/sentry/kernel/auth", - "//pkg/sentry/kernel/time", - "//pkg/sentry/limits", - "//pkg/sentry/mm", - "//pkg/sentry/socket", - "//pkg/sentry/socket/unix", - "//pkg/sentry/socket/unix/transport", - "//pkg/sentry/usage", - "//pkg/sentry/vfs", - "//pkg/sync", - "//pkg/syserror", - "//pkg/tcpip/header", - "//pkg/tcpip/network/ipv4", - "//pkg/usermem", - ], -) - -go_test( - name = "proc_test", - size = "small", - srcs = [ - "tasks_sys_test.go", - "tasks_test.go", - ], - library = ":proc", - deps = [ - "//pkg/abi/linux", - "//pkg/context", - "//pkg/errors/linuxerr", - "//pkg/fspath", - "//pkg/sentry/contexttest", - "//pkg/sentry/fsimpl/testutil", - "//pkg/sentry/fsimpl/tmpfs", - "//pkg/sentry/inet", - "//pkg/sentry/kernel", - "//pkg/sentry/kernel/auth", - "//pkg/sentry/vfs", - "//pkg/usermem", - ], -) diff --git a/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go b/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go new file mode 100644 index 000000000..61138f055 --- /dev/null +++ b/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go @@ -0,0 +1,140 @@ +package proc + +import ( + "fmt" + "sync/atomic" + + "gvisor.dev/gvisor/pkg/refsvfs2" +) + +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const fdDirInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var fdDirInodeobj *fdDirInode + +// Refs implements refs.RefCounter. It keeps a reference count using atomic +// operations and calls the destructor when the count reaches zero. +// +// NOTE: Do not introduce additional fields to the Refs struct. It is used by +// many filesystem objects, and we want to keep it as small as possible (i.e., +// the same size as using an int64 directly) to avoid taking up extra cache +// space. In general, this template should not be extended at the cost of +// performance. If it does not offer enough flexibility for a particular object +// (example: b/187877947), we should implement the RefCounter/CheckedObject +// interfaces manually. +// +// +stateify savable +type fdDirInodeRefs struct { + // refCount is composed of two fields: + // + // [32-bit speculative references]:[32-bit real references] + // + // Speculative references are used for TryIncRef, to avoid a CompareAndSwap + // loop. See IncRef, DecRef and TryIncRef for details of how these fields are + // used. + refCount int64 +} + +// InitRefs initializes r with one reference and, if enabled, activates leak +// checking. +func (r *fdDirInodeRefs) InitRefs() { + atomic.StoreInt64(&r.refCount, 1) + refsvfs2.Register(r) +} + +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *fdDirInodeRefs) RefType() string { + return fmt.Sprintf("%T", fdDirInodeobj)[1:] +} + +// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +func (r *fdDirInodeRefs) LeakMessage() string { + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *fdDirInodeRefs) LogRefs() bool { + return fdDirInodeenableLogging +} + +// ReadRefs returns the current number of references. The returned count is +// inherently racy and is unsafe to use without external synchronization. +func (r *fdDirInodeRefs) ReadRefs() int64 { + return atomic.LoadInt64(&r.refCount) +} + +// IncRef implements refs.RefCounter.IncRef. +// +//go:nosplit +func (r *fdDirInodeRefs) IncRef() { + v := atomic.AddInt64(&r.refCount, 1) + if fdDirInodeenableLogging { + refsvfs2.LogIncRef(r, v) + } + if v <= 1 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) + } +} + +// TryIncRef implements refs.TryRefCounter.TryIncRef. +// +// To do this safely without a loop, a speculative reference is first acquired +// on the object. This allows multiple concurrent TryIncRef calls to distinguish +// other TryIncRef calls from genuine references held. +// +//go:nosplit +func (r *fdDirInodeRefs) TryIncRef() bool { + const speculativeRef = 1 << 32 + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) == 0 { + + atomic.AddInt64(&r.refCount, -speculativeRef) + return false + } + + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + if fdDirInodeenableLogging { + refsvfs2.LogTryIncRef(r, v) + } + return true +} + +// DecRef implements refs.RefCounter.DecRef. +// +// Note that speculative references are counted here. Since they were added +// prior to real references reaching zero, they will successfully convert to +// real references. In other words, we see speculative references only in the +// following case: +// +// A: TryIncRef [speculative increase => sees non-negative references] +// B: DecRef [real decrease] +// A: TryIncRef [transform speculative to real] +// +//go:nosplit +func (r *fdDirInodeRefs) DecRef(destroy func()) { + v := atomic.AddInt64(&r.refCount, -1) + if fdDirInodeenableLogging { + refsvfs2.LogDecRef(r, v) + } + switch { + case v < 0: + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) + + case v == 0: + refsvfs2.Unregister(r) + + if destroy != nil { + destroy() + } + } +} + +func (r *fdDirInodeRefs) afterLoad() { + if r.ReadRefs() > 0 { + refsvfs2.Register(r) + } +} diff --git a/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go b/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go new file mode 100644 index 000000000..53fb0910a --- /dev/null +++ b/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go @@ -0,0 +1,140 @@ +package proc + +import ( + "fmt" + "sync/atomic" + + "gvisor.dev/gvisor/pkg/refsvfs2" +) + +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const fdInfoDirInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var fdInfoDirInodeobj *fdInfoDirInode + +// Refs implements refs.RefCounter. It keeps a reference count using atomic +// operations and calls the destructor when the count reaches zero. +// +// NOTE: Do not introduce additional fields to the Refs struct. It is used by +// many filesystem objects, and we want to keep it as small as possible (i.e., +// the same size as using an int64 directly) to avoid taking up extra cache +// space. In general, this template should not be extended at the cost of +// performance. If it does not offer enough flexibility for a particular object +// (example: b/187877947), we should implement the RefCounter/CheckedObject +// interfaces manually. +// +// +stateify savable +type fdInfoDirInodeRefs struct { + // refCount is composed of two fields: + // + // [32-bit speculative references]:[32-bit real references] + // + // Speculative references are used for TryIncRef, to avoid a CompareAndSwap + // loop. See IncRef, DecRef and TryIncRef for details of how these fields are + // used. + refCount int64 +} + +// InitRefs initializes r with one reference and, if enabled, activates leak +// checking. +func (r *fdInfoDirInodeRefs) InitRefs() { + atomic.StoreInt64(&r.refCount, 1) + refsvfs2.Register(r) +} + +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *fdInfoDirInodeRefs) RefType() string { + return fmt.Sprintf("%T", fdInfoDirInodeobj)[1:] +} + +// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +func (r *fdInfoDirInodeRefs) LeakMessage() string { + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *fdInfoDirInodeRefs) LogRefs() bool { + return fdInfoDirInodeenableLogging +} + +// ReadRefs returns the current number of references. The returned count is +// inherently racy and is unsafe to use without external synchronization. +func (r *fdInfoDirInodeRefs) ReadRefs() int64 { + return atomic.LoadInt64(&r.refCount) +} + +// IncRef implements refs.RefCounter.IncRef. +// +//go:nosplit +func (r *fdInfoDirInodeRefs) IncRef() { + v := atomic.AddInt64(&r.refCount, 1) + if fdInfoDirInodeenableLogging { + refsvfs2.LogIncRef(r, v) + } + if v <= 1 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) + } +} + +// TryIncRef implements refs.TryRefCounter.TryIncRef. +// +// To do this safely without a loop, a speculative reference is first acquired +// on the object. This allows multiple concurrent TryIncRef calls to distinguish +// other TryIncRef calls from genuine references held. +// +//go:nosplit +func (r *fdInfoDirInodeRefs) TryIncRef() bool { + const speculativeRef = 1 << 32 + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) == 0 { + + atomic.AddInt64(&r.refCount, -speculativeRef) + return false + } + + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + if fdInfoDirInodeenableLogging { + refsvfs2.LogTryIncRef(r, v) + } + return true +} + +// DecRef implements refs.RefCounter.DecRef. +// +// Note that speculative references are counted here. Since they were added +// prior to real references reaching zero, they will successfully convert to +// real references. In other words, we see speculative references only in the +// following case: +// +// A: TryIncRef [speculative increase => sees non-negative references] +// B: DecRef [real decrease] +// A: TryIncRef [transform speculative to real] +// +//go:nosplit +func (r *fdInfoDirInodeRefs) DecRef(destroy func()) { + v := atomic.AddInt64(&r.refCount, -1) + if fdInfoDirInodeenableLogging { + refsvfs2.LogDecRef(r, v) + } + switch { + case v < 0: + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) + + case v == 0: + refsvfs2.Unregister(r) + + if destroy != nil { + destroy() + } + } +} + +func (r *fdInfoDirInodeRefs) afterLoad() { + if r.ReadRefs() > 0 { + refsvfs2.Register(r) + } +} diff --git a/pkg/sentry/fsimpl/proc/proc_state_autogen.go b/pkg/sentry/fsimpl/proc/proc_state_autogen.go new file mode 100644 index 000000000..e32e7671c --- /dev/null +++ b/pkg/sentry/fsimpl/proc/proc_state_autogen.go @@ -0,0 +1,2454 @@ +// automatically generated by stateify. + +package proc + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (r *fdDirInodeRefs) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdDirInodeRefs" +} + +func (r *fdDirInodeRefs) StateFields() []string { + return []string{ + "refCount", + } +} + +func (r *fdDirInodeRefs) beforeSave() {} + +// +checklocksignore +func (r *fdDirInodeRefs) StateSave(stateSinkObject state.Sink) { + r.beforeSave() + stateSinkObject.Save(0, &r.refCount) +} + +// +checklocksignore +func (r *fdDirInodeRefs) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &r.refCount) + stateSourceObject.AfterLoad(r.afterLoad) +} + +func (r *fdInfoDirInodeRefs) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdInfoDirInodeRefs" +} + +func (r *fdInfoDirInodeRefs) StateFields() []string { + return []string{ + "refCount", + } +} + +func (r *fdInfoDirInodeRefs) beforeSave() {} + +// +checklocksignore +func (r *fdInfoDirInodeRefs) StateSave(stateSinkObject state.Sink) { + r.beforeSave() + stateSinkObject.Save(0, &r.refCount) +} + +// +checklocksignore +func (r *fdInfoDirInodeRefs) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &r.refCount) + stateSourceObject.AfterLoad(r.afterLoad) +} + +func (ft *FilesystemType) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.FilesystemType" +} + +func (ft *FilesystemType) StateFields() []string { + return []string{} +} + +func (ft *FilesystemType) beforeSave() {} + +// +checklocksignore +func (ft *FilesystemType) StateSave(stateSinkObject state.Sink) { + ft.beforeSave() +} + +func (ft *FilesystemType) afterLoad() {} + +// +checklocksignore +func (ft *FilesystemType) StateLoad(stateSourceObject state.Source) { +} + +func (fs *filesystem) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.filesystem" +} + +func (fs *filesystem) StateFields() []string { + return []string{ + "Filesystem", + "devMinor", + } +} + +func (fs *filesystem) beforeSave() {} + +// +checklocksignore +func (fs *filesystem) StateSave(stateSinkObject state.Sink) { + fs.beforeSave() + stateSinkObject.Save(0, &fs.Filesystem) + stateSinkObject.Save(1, &fs.devMinor) +} + +func (fs *filesystem) afterLoad() {} + +// +checklocksignore +func (fs *filesystem) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &fs.Filesystem) + stateSourceObject.Load(1, &fs.devMinor) +} + +func (s *staticFile) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.staticFile" +} + +func (s *staticFile) StateFields() []string { + return []string{ + "DynamicBytesFile", + "StaticData", + } +} + +func (s *staticFile) beforeSave() {} + +// +checklocksignore +func (s *staticFile) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.DynamicBytesFile) + stateSinkObject.Save(1, &s.StaticData) +} + +func (s *staticFile) afterLoad() {} + +// +checklocksignore +func (s *staticFile) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.DynamicBytesFile) + stateSourceObject.Load(1, &s.StaticData) +} + +func (i *InternalData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.InternalData" +} + +func (i *InternalData) StateFields() []string { + return []string{ + "Cgroups", + } +} + +func (i *InternalData) beforeSave() {} + +// +checklocksignore +func (i *InternalData) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.Cgroups) +} + +func (i *InternalData) afterLoad() {} + +// +checklocksignore +func (i *InternalData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.Cgroups) +} + +func (i *implStatFS) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.implStatFS" +} + +func (i *implStatFS) StateFields() []string { + return []string{} +} + +func (i *implStatFS) beforeSave() {} + +// +checklocksignore +func (i *implStatFS) StateSave(stateSinkObject state.Sink) { + i.beforeSave() +} + +func (i *implStatFS) afterLoad() {} + +// +checklocksignore +func (i *implStatFS) StateLoad(stateSourceObject state.Source) { +} + +func (i *subtasksInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.subtasksInode" +} + +func (i *subtasksInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAlwaysValid", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNotSymlink", + "InodeTemporary", + "OrderedChildren", + "subtasksInodeRefs", + "locks", + "fs", + "task", + "pidns", + "cgroupControllers", + } +} + +func (i *subtasksInode) beforeSave() {} + +// +checklocksignore +func (i *subtasksInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.implStatFS) + stateSinkObject.Save(1, &i.InodeAlwaysValid) + stateSinkObject.Save(2, &i.InodeAttrs) + stateSinkObject.Save(3, &i.InodeDirectoryNoNewChildren) + stateSinkObject.Save(4, &i.InodeNotSymlink) + stateSinkObject.Save(5, &i.InodeTemporary) + stateSinkObject.Save(6, &i.OrderedChildren) + stateSinkObject.Save(7, &i.subtasksInodeRefs) + stateSinkObject.Save(8, &i.locks) + stateSinkObject.Save(9, &i.fs) + stateSinkObject.Save(10, &i.task) + stateSinkObject.Save(11, &i.pidns) + stateSinkObject.Save(12, &i.cgroupControllers) +} + +func (i *subtasksInode) afterLoad() {} + +// +checklocksignore +func (i *subtasksInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.implStatFS) + stateSourceObject.Load(1, &i.InodeAlwaysValid) + stateSourceObject.Load(2, &i.InodeAttrs) + stateSourceObject.Load(3, &i.InodeDirectoryNoNewChildren) + stateSourceObject.Load(4, &i.InodeNotSymlink) + stateSourceObject.Load(5, &i.InodeTemporary) + stateSourceObject.Load(6, &i.OrderedChildren) + stateSourceObject.Load(7, &i.subtasksInodeRefs) + stateSourceObject.Load(8, &i.locks) + stateSourceObject.Load(9, &i.fs) + stateSourceObject.Load(10, &i.task) + stateSourceObject.Load(11, &i.pidns) + stateSourceObject.Load(12, &i.cgroupControllers) +} + +func (fd *subtasksFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.subtasksFD" +} + +func (fd *subtasksFD) StateFields() []string { + return []string{ + "GenericDirectoryFD", + "task", + } +} + +func (fd *subtasksFD) beforeSave() {} + +// +checklocksignore +func (fd *subtasksFD) StateSave(stateSinkObject state.Sink) { + fd.beforeSave() + stateSinkObject.Save(0, &fd.GenericDirectoryFD) + stateSinkObject.Save(1, &fd.task) +} + +func (fd *subtasksFD) afterLoad() {} + +// +checklocksignore +func (fd *subtasksFD) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &fd.GenericDirectoryFD) + stateSourceObject.Load(1, &fd.task) +} + +func (r *subtasksInodeRefs) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.subtasksInodeRefs" +} + +func (r *subtasksInodeRefs) StateFields() []string { + return []string{ + "refCount", + } +} + +func (r *subtasksInodeRefs) beforeSave() {} + +// +checklocksignore +func (r *subtasksInodeRefs) StateSave(stateSinkObject state.Sink) { + r.beforeSave() + stateSinkObject.Save(0, &r.refCount) +} + +// +checklocksignore +func (r *subtasksInodeRefs) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &r.refCount) + stateSourceObject.AfterLoad(r.afterLoad) +} + +func (i *taskInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.taskInode" +} + +func (i *taskInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNotSymlink", + "InodeTemporary", + "OrderedChildren", + "taskInodeRefs", + "locks", + "task", + } +} + +func (i *taskInode) beforeSave() {} + +// +checklocksignore +func (i *taskInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.implStatFS) + stateSinkObject.Save(1, &i.InodeAttrs) + stateSinkObject.Save(2, &i.InodeDirectoryNoNewChildren) + stateSinkObject.Save(3, &i.InodeNotSymlink) + stateSinkObject.Save(4, &i.InodeTemporary) + stateSinkObject.Save(5, &i.OrderedChildren) + stateSinkObject.Save(6, &i.taskInodeRefs) + stateSinkObject.Save(7, &i.locks) + stateSinkObject.Save(8, &i.task) +} + +func (i *taskInode) afterLoad() {} + +// +checklocksignore +func (i *taskInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.implStatFS) + stateSourceObject.Load(1, &i.InodeAttrs) + stateSourceObject.Load(2, &i.InodeDirectoryNoNewChildren) + stateSourceObject.Load(3, &i.InodeNotSymlink) + stateSourceObject.Load(4, &i.InodeTemporary) + stateSourceObject.Load(5, &i.OrderedChildren) + stateSourceObject.Load(6, &i.taskInodeRefs) + stateSourceObject.Load(7, &i.locks) + stateSourceObject.Load(8, &i.task) +} + +func (i *taskOwnedInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.taskOwnedInode" +} + +func (i *taskOwnedInode) StateFields() []string { + return []string{ + "Inode", + "owner", + } +} + +func (i *taskOwnedInode) beforeSave() {} + +// +checklocksignore +func (i *taskOwnedInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.Inode) + stateSinkObject.Save(1, &i.owner) +} + +func (i *taskOwnedInode) afterLoad() {} + +// +checklocksignore +func (i *taskOwnedInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.Inode) + stateSourceObject.Load(1, &i.owner) +} + +func (i *fdDir) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdDir" +} + +func (i *fdDir) StateFields() []string { + return []string{ + "locks", + "fs", + "task", + "produceSymlink", + } +} + +func (i *fdDir) beforeSave() {} + +// +checklocksignore +func (i *fdDir) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.locks) + stateSinkObject.Save(1, &i.fs) + stateSinkObject.Save(2, &i.task) + stateSinkObject.Save(3, &i.produceSymlink) +} + +func (i *fdDir) afterLoad() {} + +// +checklocksignore +func (i *fdDir) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.locks) + stateSourceObject.Load(1, &i.fs) + stateSourceObject.Load(2, &i.task) + stateSourceObject.Load(3, &i.produceSymlink) +} + +func (i *fdDirInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdDirInode" +} + +func (i *fdDirInode) StateFields() []string { + return []string{ + "fdDir", + "fdDirInodeRefs", + "implStatFS", + "InodeAlwaysValid", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNotSymlink", + "InodeTemporary", + "OrderedChildren", + } +} + +func (i *fdDirInode) beforeSave() {} + +// +checklocksignore +func (i *fdDirInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.fdDir) + stateSinkObject.Save(1, &i.fdDirInodeRefs) + stateSinkObject.Save(2, &i.implStatFS) + stateSinkObject.Save(3, &i.InodeAlwaysValid) + stateSinkObject.Save(4, &i.InodeAttrs) + stateSinkObject.Save(5, &i.InodeDirectoryNoNewChildren) + stateSinkObject.Save(6, &i.InodeNotSymlink) + stateSinkObject.Save(7, &i.InodeTemporary) + stateSinkObject.Save(8, &i.OrderedChildren) +} + +func (i *fdDirInode) afterLoad() {} + +// +checklocksignore +func (i *fdDirInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.fdDir) + stateSourceObject.Load(1, &i.fdDirInodeRefs) + stateSourceObject.Load(2, &i.implStatFS) + stateSourceObject.Load(3, &i.InodeAlwaysValid) + stateSourceObject.Load(4, &i.InodeAttrs) + stateSourceObject.Load(5, &i.InodeDirectoryNoNewChildren) + stateSourceObject.Load(6, &i.InodeNotSymlink) + stateSourceObject.Load(7, &i.InodeTemporary) + stateSourceObject.Load(8, &i.OrderedChildren) +} + +func (s *fdSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdSymlink" +} + +func (s *fdSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "fs", + "task", + "fd", + } +} + +func (s *fdSymlink) beforeSave() {} + +// +checklocksignore +func (s *fdSymlink) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.implStatFS) + stateSinkObject.Save(1, &s.InodeAttrs) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeSymlink) + stateSinkObject.Save(4, &s.fs) + stateSinkObject.Save(5, &s.task) + stateSinkObject.Save(6, &s.fd) +} + +func (s *fdSymlink) afterLoad() {} + +// +checklocksignore +func (s *fdSymlink) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.implStatFS) + stateSourceObject.Load(1, &s.InodeAttrs) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeSymlink) + stateSourceObject.Load(4, &s.fs) + stateSourceObject.Load(5, &s.task) + stateSourceObject.Load(6, &s.fd) +} + +func (i *fdInfoDirInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdInfoDirInode" +} + +func (i *fdInfoDirInode) StateFields() []string { + return []string{ + "fdDir", + "fdInfoDirInodeRefs", + "implStatFS", + "InodeAlwaysValid", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNotSymlink", + "InodeTemporary", + "OrderedChildren", + } +} + +func (i *fdInfoDirInode) beforeSave() {} + +// +checklocksignore +func (i *fdInfoDirInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.fdDir) + stateSinkObject.Save(1, &i.fdInfoDirInodeRefs) + stateSinkObject.Save(2, &i.implStatFS) + stateSinkObject.Save(3, &i.InodeAlwaysValid) + stateSinkObject.Save(4, &i.InodeAttrs) + stateSinkObject.Save(5, &i.InodeDirectoryNoNewChildren) + stateSinkObject.Save(6, &i.InodeNotSymlink) + stateSinkObject.Save(7, &i.InodeTemporary) + stateSinkObject.Save(8, &i.OrderedChildren) +} + +func (i *fdInfoDirInode) afterLoad() {} + +// +checklocksignore +func (i *fdInfoDirInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.fdDir) + stateSourceObject.Load(1, &i.fdInfoDirInodeRefs) + stateSourceObject.Load(2, &i.implStatFS) + stateSourceObject.Load(3, &i.InodeAlwaysValid) + stateSourceObject.Load(4, &i.InodeAttrs) + stateSourceObject.Load(5, &i.InodeDirectoryNoNewChildren) + stateSourceObject.Load(6, &i.InodeNotSymlink) + stateSourceObject.Load(7, &i.InodeTemporary) + stateSourceObject.Load(8, &i.OrderedChildren) +} + +func (d *fdInfoData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.fdInfoData" +} + +func (d *fdInfoData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "fs", + "task", + "fd", + } +} + +func (d *fdInfoData) beforeSave() {} + +// +checklocksignore +func (d *fdInfoData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.fs) + stateSinkObject.Save(2, &d.task) + stateSinkObject.Save(3, &d.fd) +} + +func (d *fdInfoData) afterLoad() {} + +// +checklocksignore +func (d *fdInfoData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.fs) + stateSourceObject.Load(2, &d.task) + stateSourceObject.Load(3, &d.fd) +} + +func (d *auxvData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.auxvData" +} + +func (d *auxvData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (d *auxvData) beforeSave() {} + +// +checklocksignore +func (d *auxvData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.task) +} + +func (d *auxvData) afterLoad() {} + +// +checklocksignore +func (d *auxvData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.task) +} + +func (d *cmdlineData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.cmdlineData" +} + +func (d *cmdlineData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + "arg", + } +} + +func (d *cmdlineData) beforeSave() {} + +// +checklocksignore +func (d *cmdlineData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.task) + stateSinkObject.Save(2, &d.arg) +} + +func (d *cmdlineData) afterLoad() {} + +// +checklocksignore +func (d *cmdlineData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.task) + stateSourceObject.Load(2, &d.arg) +} + +func (i *commInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.commInode" +} + +func (i *commInode) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (i *commInode) beforeSave() {} + +// +checklocksignore +func (i *commInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.DynamicBytesFile) + stateSinkObject.Save(1, &i.task) +} + +func (i *commInode) afterLoad() {} + +// +checklocksignore +func (i *commInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.DynamicBytesFile) + stateSourceObject.Load(1, &i.task) +} + +func (d *commData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.commData" +} + +func (d *commData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (d *commData) beforeSave() {} + +// +checklocksignore +func (d *commData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.task) +} + +func (d *commData) afterLoad() {} + +// +checklocksignore +func (d *commData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.task) +} + +func (d *idMapData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.idMapData" +} + +func (d *idMapData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + "gids", + } +} + +func (d *idMapData) beforeSave() {} + +// +checklocksignore +func (d *idMapData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.task) + stateSinkObject.Save(2, &d.gids) +} + +func (d *idMapData) afterLoad() {} + +// +checklocksignore +func (d *idMapData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.task) + stateSourceObject.Load(2, &d.gids) +} + +func (f *memInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.memInode" +} + +func (f *memInode) StateFields() []string { + return []string{ + "InodeAttrs", + "InodeNoStatFS", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "task", + "locks", + } +} + +func (f *memInode) beforeSave() {} + +// +checklocksignore +func (f *memInode) StateSave(stateSinkObject state.Sink) { + f.beforeSave() + stateSinkObject.Save(0, &f.InodeAttrs) + stateSinkObject.Save(1, &f.InodeNoStatFS) + stateSinkObject.Save(2, &f.InodeNoopRefCount) + stateSinkObject.Save(3, &f.InodeNotDirectory) + stateSinkObject.Save(4, &f.InodeNotSymlink) + stateSinkObject.Save(5, &f.task) + stateSinkObject.Save(6, &f.locks) +} + +func (f *memInode) afterLoad() {} + +// +checklocksignore +func (f *memInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &f.InodeAttrs) + stateSourceObject.Load(1, &f.InodeNoStatFS) + stateSourceObject.Load(2, &f.InodeNoopRefCount) + stateSourceObject.Load(3, &f.InodeNotDirectory) + stateSourceObject.Load(4, &f.InodeNotSymlink) + stateSourceObject.Load(5, &f.task) + stateSourceObject.Load(6, &f.locks) +} + +func (fd *memFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.memFD" +} + +func (fd *memFD) StateFields() []string { + return []string{ + "vfsfd", + "FileDescriptionDefaultImpl", + "LockFD", + "inode", + "offset", + } +} + +func (fd *memFD) beforeSave() {} + +// +checklocksignore +func (fd *memFD) StateSave(stateSinkObject state.Sink) { + fd.beforeSave() + stateSinkObject.Save(0, &fd.vfsfd) + stateSinkObject.Save(1, &fd.FileDescriptionDefaultImpl) + stateSinkObject.Save(2, &fd.LockFD) + stateSinkObject.Save(3, &fd.inode) + stateSinkObject.Save(4, &fd.offset) +} + +func (fd *memFD) afterLoad() {} + +// +checklocksignore +func (fd *memFD) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &fd.vfsfd) + stateSourceObject.Load(1, &fd.FileDescriptionDefaultImpl) + stateSourceObject.Load(2, &fd.LockFD) + stateSourceObject.Load(3, &fd.inode) + stateSourceObject.Load(4, &fd.offset) +} + +func (d *mapsData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.mapsData" +} + +func (d *mapsData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (d *mapsData) beforeSave() {} + +// +checklocksignore +func (d *mapsData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.task) +} + +func (d *mapsData) afterLoad() {} + +// +checklocksignore +func (d *mapsData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.task) +} + +func (d *smapsData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.smapsData" +} + +func (d *smapsData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (d *smapsData) beforeSave() {} + +// +checklocksignore +func (d *smapsData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.task) +} + +func (d *smapsData) afterLoad() {} + +// +checklocksignore +func (d *smapsData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.task) +} + +func (s *taskStatData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.taskStatData" +} + +func (s *taskStatData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + "tgstats", + "pidns", + } +} + +func (s *taskStatData) beforeSave() {} + +// +checklocksignore +func (s *taskStatData) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.DynamicBytesFile) + stateSinkObject.Save(1, &s.task) + stateSinkObject.Save(2, &s.tgstats) + stateSinkObject.Save(3, &s.pidns) +} + +func (s *taskStatData) afterLoad() {} + +// +checklocksignore +func (s *taskStatData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.DynamicBytesFile) + stateSourceObject.Load(1, &s.task) + stateSourceObject.Load(2, &s.tgstats) + stateSourceObject.Load(3, &s.pidns) +} + +func (s *statmData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statmData" +} + +func (s *statmData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (s *statmData) beforeSave() {} + +// +checklocksignore +func (s *statmData) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.DynamicBytesFile) + stateSinkObject.Save(1, &s.task) +} + +func (s *statmData) afterLoad() {} + +// +checklocksignore +func (s *statmData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.DynamicBytesFile) + stateSourceObject.Load(1, &s.task) +} + +func (s *statusInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statusInode" +} + +func (s *statusInode) StateFields() []string { + return []string{ + "InodeAttrs", + "InodeNoStatFS", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "task", + "pidns", + "locks", + } +} + +func (s *statusInode) beforeSave() {} + +// +checklocksignore +func (s *statusInode) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.InodeAttrs) + stateSinkObject.Save(1, &s.InodeNoStatFS) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeNotDirectory) + stateSinkObject.Save(4, &s.InodeNotSymlink) + stateSinkObject.Save(5, &s.task) + stateSinkObject.Save(6, &s.pidns) + stateSinkObject.Save(7, &s.locks) +} + +func (s *statusInode) afterLoad() {} + +// +checklocksignore +func (s *statusInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.InodeAttrs) + stateSourceObject.Load(1, &s.InodeNoStatFS) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeNotDirectory) + stateSourceObject.Load(4, &s.InodeNotSymlink) + stateSourceObject.Load(5, &s.task) + stateSourceObject.Load(6, &s.pidns) + stateSourceObject.Load(7, &s.locks) +} + +func (s *statusFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statusFD" +} + +func (s *statusFD) StateFields() []string { + return []string{ + "statusFDLowerBase", + "DynamicBytesFileDescriptionImpl", + "LockFD", + "vfsfd", + "inode", + "task", + "pidns", + "userns", + } +} + +func (s *statusFD) beforeSave() {} + +// +checklocksignore +func (s *statusFD) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.statusFDLowerBase) + stateSinkObject.Save(1, &s.DynamicBytesFileDescriptionImpl) + stateSinkObject.Save(2, &s.LockFD) + stateSinkObject.Save(3, &s.vfsfd) + stateSinkObject.Save(4, &s.inode) + stateSinkObject.Save(5, &s.task) + stateSinkObject.Save(6, &s.pidns) + stateSinkObject.Save(7, &s.userns) +} + +func (s *statusFD) afterLoad() {} + +// +checklocksignore +func (s *statusFD) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.statusFDLowerBase) + stateSourceObject.Load(1, &s.DynamicBytesFileDescriptionImpl) + stateSourceObject.Load(2, &s.LockFD) + stateSourceObject.Load(3, &s.vfsfd) + stateSourceObject.Load(4, &s.inode) + stateSourceObject.Load(5, &s.task) + stateSourceObject.Load(6, &s.pidns) + stateSourceObject.Load(7, &s.userns) +} + +func (s *statusFDLowerBase) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statusFDLowerBase" +} + +func (s *statusFDLowerBase) StateFields() []string { + return []string{ + "FileDescriptionDefaultImpl", + } +} + +func (s *statusFDLowerBase) beforeSave() {} + +// +checklocksignore +func (s *statusFDLowerBase) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.FileDescriptionDefaultImpl) +} + +func (s *statusFDLowerBase) afterLoad() {} + +// +checklocksignore +func (s *statusFDLowerBase) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.FileDescriptionDefaultImpl) +} + +func (i *ioData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.ioData" +} + +func (i *ioData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "ioUsage", + } +} + +func (i *ioData) beforeSave() {} + +// +checklocksignore +func (i *ioData) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.DynamicBytesFile) + stateSinkObject.Save(1, &i.ioUsage) +} + +func (i *ioData) afterLoad() {} + +// +checklocksignore +func (i *ioData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.DynamicBytesFile) + stateSourceObject.Load(1, &i.ioUsage) +} + +func (o *oomScoreAdj) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.oomScoreAdj" +} + +func (o *oomScoreAdj) StateFields() []string { + return []string{ + "DynamicBytesFile", + "task", + } +} + +func (o *oomScoreAdj) beforeSave() {} + +// +checklocksignore +func (o *oomScoreAdj) StateSave(stateSinkObject state.Sink) { + o.beforeSave() + stateSinkObject.Save(0, &o.DynamicBytesFile) + stateSinkObject.Save(1, &o.task) +} + +func (o *oomScoreAdj) afterLoad() {} + +// +checklocksignore +func (o *oomScoreAdj) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &o.DynamicBytesFile) + stateSourceObject.Load(1, &o.task) +} + +func (s *exeSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.exeSymlink" +} + +func (s *exeSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "fs", + "task", + } +} + +func (s *exeSymlink) beforeSave() {} + +// +checklocksignore +func (s *exeSymlink) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.implStatFS) + stateSinkObject.Save(1, &s.InodeAttrs) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeSymlink) + stateSinkObject.Save(4, &s.fs) + stateSinkObject.Save(5, &s.task) +} + +func (s *exeSymlink) afterLoad() {} + +// +checklocksignore +func (s *exeSymlink) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.implStatFS) + stateSourceObject.Load(1, &s.InodeAttrs) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeSymlink) + stateSourceObject.Load(4, &s.fs) + stateSourceObject.Load(5, &s.task) +} + +func (s *cwdSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.cwdSymlink" +} + +func (s *cwdSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "fs", + "task", + } +} + +func (s *cwdSymlink) beforeSave() {} + +// +checklocksignore +func (s *cwdSymlink) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.implStatFS) + stateSinkObject.Save(1, &s.InodeAttrs) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeSymlink) + stateSinkObject.Save(4, &s.fs) + stateSinkObject.Save(5, &s.task) +} + +func (s *cwdSymlink) afterLoad() {} + +// +checklocksignore +func (s *cwdSymlink) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.implStatFS) + stateSourceObject.Load(1, &s.InodeAttrs) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeSymlink) + stateSourceObject.Load(4, &s.fs) + stateSourceObject.Load(5, &s.task) +} + +func (i *mountInfoData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.mountInfoData" +} + +func (i *mountInfoData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "fs", + "task", + } +} + +func (i *mountInfoData) beforeSave() {} + +// +checklocksignore +func (i *mountInfoData) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.DynamicBytesFile) + stateSinkObject.Save(1, &i.fs) + stateSinkObject.Save(2, &i.task) +} + +func (i *mountInfoData) afterLoad() {} + +// +checklocksignore +func (i *mountInfoData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.DynamicBytesFile) + stateSourceObject.Load(1, &i.fs) + stateSourceObject.Load(2, &i.task) +} + +func (i *mountsData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.mountsData" +} + +func (i *mountsData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "fs", + "task", + } +} + +func (i *mountsData) beforeSave() {} + +// +checklocksignore +func (i *mountsData) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.DynamicBytesFile) + stateSinkObject.Save(1, &i.fs) + stateSinkObject.Save(2, &i.task) +} + +func (i *mountsData) afterLoad() {} + +// +checklocksignore +func (i *mountsData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.DynamicBytesFile) + stateSourceObject.Load(1, &i.fs) + stateSourceObject.Load(2, &i.task) +} + +func (s *namespaceSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.namespaceSymlink" +} + +func (s *namespaceSymlink) StateFields() []string { + return []string{ + "StaticSymlink", + "task", + } +} + +func (s *namespaceSymlink) beforeSave() {} + +// +checklocksignore +func (s *namespaceSymlink) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.StaticSymlink) + stateSinkObject.Save(1, &s.task) +} + +func (s *namespaceSymlink) afterLoad() {} + +// +checklocksignore +func (s *namespaceSymlink) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.StaticSymlink) + stateSourceObject.Load(1, &s.task) +} + +func (i *namespaceInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.namespaceInode" +} + +func (i *namespaceInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", + "locks", + } +} + +func (i *namespaceInode) beforeSave() {} + +// +checklocksignore +func (i *namespaceInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.implStatFS) + stateSinkObject.Save(1, &i.InodeAttrs) + stateSinkObject.Save(2, &i.InodeNoopRefCount) + stateSinkObject.Save(3, &i.InodeNotDirectory) + stateSinkObject.Save(4, &i.InodeNotSymlink) + stateSinkObject.Save(5, &i.locks) +} + +func (i *namespaceInode) afterLoad() {} + +// +checklocksignore +func (i *namespaceInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.implStatFS) + stateSourceObject.Load(1, &i.InodeAttrs) + stateSourceObject.Load(2, &i.InodeNoopRefCount) + stateSourceObject.Load(3, &i.InodeNotDirectory) + stateSourceObject.Load(4, &i.InodeNotSymlink) + stateSourceObject.Load(5, &i.locks) +} + +func (fd *namespaceFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.namespaceFD" +} + +func (fd *namespaceFD) StateFields() []string { + return []string{ + "FileDescriptionDefaultImpl", + "LockFD", + "vfsfd", + "inode", + } +} + +func (fd *namespaceFD) beforeSave() {} + +// +checklocksignore +func (fd *namespaceFD) StateSave(stateSinkObject state.Sink) { + fd.beforeSave() + stateSinkObject.Save(0, &fd.FileDescriptionDefaultImpl) + stateSinkObject.Save(1, &fd.LockFD) + stateSinkObject.Save(2, &fd.vfsfd) + stateSinkObject.Save(3, &fd.inode) +} + +func (fd *namespaceFD) afterLoad() {} + +// +checklocksignore +func (fd *namespaceFD) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &fd.FileDescriptionDefaultImpl) + stateSourceObject.Load(1, &fd.LockFD) + stateSourceObject.Load(2, &fd.vfsfd) + stateSourceObject.Load(3, &fd.inode) +} + +func (d *taskCgroupData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.taskCgroupData" +} + +func (d *taskCgroupData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + "task", + } +} + +func (d *taskCgroupData) beforeSave() {} + +// +checklocksignore +func (d *taskCgroupData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.dynamicBytesFileSetAttr) + stateSinkObject.Save(1, &d.task) +} + +func (d *taskCgroupData) afterLoad() {} + +// +checklocksignore +func (d *taskCgroupData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.dynamicBytesFileSetAttr) + stateSourceObject.Load(1, &d.task) +} + +func (r *taskInodeRefs) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.taskInodeRefs" +} + +func (r *taskInodeRefs) StateFields() []string { + return []string{ + "refCount", + } +} + +func (r *taskInodeRefs) beforeSave() {} + +// +checklocksignore +func (r *taskInodeRefs) StateSave(stateSinkObject state.Sink) { + r.beforeSave() + stateSinkObject.Save(0, &r.refCount) +} + +// +checklocksignore +func (r *taskInodeRefs) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &r.refCount) + stateSourceObject.AfterLoad(r.afterLoad) +} + +func (n *ifinet6) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.ifinet6" +} + +func (n *ifinet6) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + } +} + +func (n *ifinet6) beforeSave() {} + +// +checklocksignore +func (n *ifinet6) StateSave(stateSinkObject state.Sink) { + n.beforeSave() + stateSinkObject.Save(0, &n.DynamicBytesFile) + stateSinkObject.Save(1, &n.stack) +} + +func (n *ifinet6) afterLoad() {} + +// +checklocksignore +func (n *ifinet6) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &n.DynamicBytesFile) + stateSourceObject.Load(1, &n.stack) +} + +func (n *netDevData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netDevData" +} + +func (n *netDevData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + } +} + +func (n *netDevData) beforeSave() {} + +// +checklocksignore +func (n *netDevData) StateSave(stateSinkObject state.Sink) { + n.beforeSave() + stateSinkObject.Save(0, &n.DynamicBytesFile) + stateSinkObject.Save(1, &n.stack) +} + +func (n *netDevData) afterLoad() {} + +// +checklocksignore +func (n *netDevData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &n.DynamicBytesFile) + stateSourceObject.Load(1, &n.stack) +} + +func (n *netUnixData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netUnixData" +} + +func (n *netUnixData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "kernel", + } +} + +func (n *netUnixData) beforeSave() {} + +// +checklocksignore +func (n *netUnixData) StateSave(stateSinkObject state.Sink) { + n.beforeSave() + stateSinkObject.Save(0, &n.DynamicBytesFile) + stateSinkObject.Save(1, &n.kernel) +} + +func (n *netUnixData) afterLoad() {} + +// +checklocksignore +func (n *netUnixData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &n.DynamicBytesFile) + stateSourceObject.Load(1, &n.kernel) +} + +func (d *netTCPData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netTCPData" +} + +func (d *netTCPData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "kernel", + } +} + +func (d *netTCPData) beforeSave() {} + +// +checklocksignore +func (d *netTCPData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.kernel) +} + +func (d *netTCPData) afterLoad() {} + +// +checklocksignore +func (d *netTCPData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.kernel) +} + +func (d *netTCP6Data) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netTCP6Data" +} + +func (d *netTCP6Data) StateFields() []string { + return []string{ + "DynamicBytesFile", + "kernel", + } +} + +func (d *netTCP6Data) beforeSave() {} + +// +checklocksignore +func (d *netTCP6Data) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.kernel) +} + +func (d *netTCP6Data) afterLoad() {} + +// +checklocksignore +func (d *netTCP6Data) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.kernel) +} + +func (d *netUDPData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netUDPData" +} + +func (d *netUDPData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "kernel", + } +} + +func (d *netUDPData) beforeSave() {} + +// +checklocksignore +func (d *netUDPData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.kernel) +} + +func (d *netUDPData) afterLoad() {} + +// +checklocksignore +func (d *netUDPData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.kernel) +} + +func (d *netSnmpData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netSnmpData" +} + +func (d *netSnmpData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + } +} + +func (d *netSnmpData) beforeSave() {} + +// +checklocksignore +func (d *netSnmpData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.stack) +} + +func (d *netSnmpData) afterLoad() {} + +// +checklocksignore +func (d *netSnmpData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.stack) +} + +func (s *snmpLine) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.snmpLine" +} + +func (s *snmpLine) StateFields() []string { + return []string{ + "prefix", + "header", + } +} + +func (s *snmpLine) beforeSave() {} + +// +checklocksignore +func (s *snmpLine) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.prefix) + stateSinkObject.Save(1, &s.header) +} + +func (s *snmpLine) afterLoad() {} + +// +checklocksignore +func (s *snmpLine) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.prefix) + stateSourceObject.Load(1, &s.header) +} + +func (d *netRouteData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netRouteData" +} + +func (d *netRouteData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + } +} + +func (d *netRouteData) beforeSave() {} + +// +checklocksignore +func (d *netRouteData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.stack) +} + +func (d *netRouteData) afterLoad() {} + +// +checklocksignore +func (d *netRouteData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.stack) +} + +func (d *netStatData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.netStatData" +} + +func (d *netStatData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + } +} + +func (d *netStatData) beforeSave() {} + +// +checklocksignore +func (d *netStatData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.stack) +} + +func (d *netStatData) afterLoad() {} + +// +checklocksignore +func (d *netStatData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.stack) +} + +func (i *tasksInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tasksInode" +} + +func (i *tasksInode) StateFields() []string { + return []string{ + "implStatFS", + "InodeAlwaysValid", + "InodeAttrs", + "InodeDirectoryNoNewChildren", + "InodeNotSymlink", + "InodeTemporary", + "OrderedChildren", + "tasksInodeRefs", + "locks", + "fs", + "pidns", + "fakeCgroupControllers", + } +} + +func (i *tasksInode) beforeSave() {} + +// +checklocksignore +func (i *tasksInode) StateSave(stateSinkObject state.Sink) { + i.beforeSave() + stateSinkObject.Save(0, &i.implStatFS) + stateSinkObject.Save(1, &i.InodeAlwaysValid) + stateSinkObject.Save(2, &i.InodeAttrs) + stateSinkObject.Save(3, &i.InodeDirectoryNoNewChildren) + stateSinkObject.Save(4, &i.InodeNotSymlink) + stateSinkObject.Save(5, &i.InodeTemporary) + stateSinkObject.Save(6, &i.OrderedChildren) + stateSinkObject.Save(7, &i.tasksInodeRefs) + stateSinkObject.Save(8, &i.locks) + stateSinkObject.Save(9, &i.fs) + stateSinkObject.Save(10, &i.pidns) + stateSinkObject.Save(11, &i.fakeCgroupControllers) +} + +func (i *tasksInode) afterLoad() {} + +// +checklocksignore +func (i *tasksInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &i.implStatFS) + stateSourceObject.Load(1, &i.InodeAlwaysValid) + stateSourceObject.Load(2, &i.InodeAttrs) + stateSourceObject.Load(3, &i.InodeDirectoryNoNewChildren) + stateSourceObject.Load(4, &i.InodeNotSymlink) + stateSourceObject.Load(5, &i.InodeTemporary) + stateSourceObject.Load(6, &i.OrderedChildren) + stateSourceObject.Load(7, &i.tasksInodeRefs) + stateSourceObject.Load(8, &i.locks) + stateSourceObject.Load(9, &i.fs) + stateSourceObject.Load(10, &i.pidns) + stateSourceObject.Load(11, &i.fakeCgroupControllers) +} + +func (s *staticFileSetStat) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.staticFileSetStat" +} + +func (s *staticFileSetStat) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + "StaticData", + } +} + +func (s *staticFileSetStat) beforeSave() {} + +// +checklocksignore +func (s *staticFileSetStat) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.dynamicBytesFileSetAttr) + stateSinkObject.Save(1, &s.StaticData) +} + +func (s *staticFileSetStat) afterLoad() {} + +// +checklocksignore +func (s *staticFileSetStat) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.dynamicBytesFileSetAttr) + stateSourceObject.Load(1, &s.StaticData) +} + +func (s *selfSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.selfSymlink" +} + +func (s *selfSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "pidns", + } +} + +func (s *selfSymlink) beforeSave() {} + +// +checklocksignore +func (s *selfSymlink) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.implStatFS) + stateSinkObject.Save(1, &s.InodeAttrs) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeSymlink) + stateSinkObject.Save(4, &s.pidns) +} + +func (s *selfSymlink) afterLoad() {} + +// +checklocksignore +func (s *selfSymlink) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.implStatFS) + stateSourceObject.Load(1, &s.InodeAttrs) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeSymlink) + stateSourceObject.Load(4, &s.pidns) +} + +func (s *threadSelfSymlink) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.threadSelfSymlink" +} + +func (s *threadSelfSymlink) StateFields() []string { + return []string{ + "implStatFS", + "InodeAttrs", + "InodeNoopRefCount", + "InodeSymlink", + "pidns", + } +} + +func (s *threadSelfSymlink) beforeSave() {} + +// +checklocksignore +func (s *threadSelfSymlink) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.implStatFS) + stateSinkObject.Save(1, &s.InodeAttrs) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeSymlink) + stateSinkObject.Save(4, &s.pidns) +} + +func (s *threadSelfSymlink) afterLoad() {} + +// +checklocksignore +func (s *threadSelfSymlink) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.implStatFS) + stateSourceObject.Load(1, &s.InodeAttrs) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeSymlink) + stateSourceObject.Load(4, &s.pidns) +} + +func (d *dynamicBytesFileSetAttr) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.dynamicBytesFileSetAttr" +} + +func (d *dynamicBytesFileSetAttr) StateFields() []string { + return []string{ + "DynamicBytesFile", + } +} + +func (d *dynamicBytesFileSetAttr) beforeSave() {} + +// +checklocksignore +func (d *dynamicBytesFileSetAttr) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) +} + +func (d *dynamicBytesFileSetAttr) afterLoad() {} + +// +checklocksignore +func (d *dynamicBytesFileSetAttr) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) +} + +func (c *cpuStats) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.cpuStats" +} + +func (c *cpuStats) StateFields() []string { + return []string{ + "user", + "nice", + "system", + "idle", + "ioWait", + "irq", + "softirq", + "steal", + "guest", + "guestNice", + } +} + +func (c *cpuStats) beforeSave() {} + +// +checklocksignore +func (c *cpuStats) StateSave(stateSinkObject state.Sink) { + c.beforeSave() + stateSinkObject.Save(0, &c.user) + stateSinkObject.Save(1, &c.nice) + stateSinkObject.Save(2, &c.system) + stateSinkObject.Save(3, &c.idle) + stateSinkObject.Save(4, &c.ioWait) + stateSinkObject.Save(5, &c.irq) + stateSinkObject.Save(6, &c.softirq) + stateSinkObject.Save(7, &c.steal) + stateSinkObject.Save(8, &c.guest) + stateSinkObject.Save(9, &c.guestNice) +} + +func (c *cpuStats) afterLoad() {} + +// +checklocksignore +func (c *cpuStats) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &c.user) + stateSourceObject.Load(1, &c.nice) + stateSourceObject.Load(2, &c.system) + stateSourceObject.Load(3, &c.idle) + stateSourceObject.Load(4, &c.ioWait) + stateSourceObject.Load(5, &c.irq) + stateSourceObject.Load(6, &c.softirq) + stateSourceObject.Load(7, &c.steal) + stateSourceObject.Load(8, &c.guest) + stateSourceObject.Load(9, &c.guestNice) +} + +func (s *statData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statData" +} + +func (s *statData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (s *statData) beforeSave() {} + +// +checklocksignore +func (s *statData) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.dynamicBytesFileSetAttr) +} + +func (s *statData) afterLoad() {} + +// +checklocksignore +func (s *statData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.dynamicBytesFileSetAttr) +} + +func (l *loadavgData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.loadavgData" +} + +func (l *loadavgData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (l *loadavgData) beforeSave() {} + +// +checklocksignore +func (l *loadavgData) StateSave(stateSinkObject state.Sink) { + l.beforeSave() + stateSinkObject.Save(0, &l.dynamicBytesFileSetAttr) +} + +func (l *loadavgData) afterLoad() {} + +// +checklocksignore +func (l *loadavgData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &l.dynamicBytesFileSetAttr) +} + +func (m *meminfoData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.meminfoData" +} + +func (m *meminfoData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (m *meminfoData) beforeSave() {} + +// +checklocksignore +func (m *meminfoData) StateSave(stateSinkObject state.Sink) { + m.beforeSave() + stateSinkObject.Save(0, &m.dynamicBytesFileSetAttr) +} + +func (m *meminfoData) afterLoad() {} + +// +checklocksignore +func (m *meminfoData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &m.dynamicBytesFileSetAttr) +} + +func (u *uptimeData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.uptimeData" +} + +func (u *uptimeData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (u *uptimeData) beforeSave() {} + +// +checklocksignore +func (u *uptimeData) StateSave(stateSinkObject state.Sink) { + u.beforeSave() + stateSinkObject.Save(0, &u.dynamicBytesFileSetAttr) +} + +func (u *uptimeData) afterLoad() {} + +// +checklocksignore +func (u *uptimeData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &u.dynamicBytesFileSetAttr) +} + +func (v *versionData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.versionData" +} + +func (v *versionData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (v *versionData) beforeSave() {} + +// +checklocksignore +func (v *versionData) StateSave(stateSinkObject state.Sink) { + v.beforeSave() + stateSinkObject.Save(0, &v.dynamicBytesFileSetAttr) +} + +func (v *versionData) afterLoad() {} + +// +checklocksignore +func (v *versionData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &v.dynamicBytesFileSetAttr) +} + +func (d *filesystemsData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.filesystemsData" +} + +func (d *filesystemsData) StateFields() []string { + return []string{ + "DynamicBytesFile", + } +} + +func (d *filesystemsData) beforeSave() {} + +// +checklocksignore +func (d *filesystemsData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) +} + +func (d *filesystemsData) afterLoad() {} + +// +checklocksignore +func (d *filesystemsData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) +} + +func (c *cgroupsData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.cgroupsData" +} + +func (c *cgroupsData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (c *cgroupsData) beforeSave() {} + +// +checklocksignore +func (c *cgroupsData) StateSave(stateSinkObject state.Sink) { + c.beforeSave() + stateSinkObject.Save(0, &c.dynamicBytesFileSetAttr) +} + +func (c *cgroupsData) afterLoad() {} + +// +checklocksignore +func (c *cgroupsData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &c.dynamicBytesFileSetAttr) +} + +func (c *cmdLineData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.cmdLineData" +} + +func (c *cmdLineData) StateFields() []string { + return []string{ + "dynamicBytesFileSetAttr", + } +} + +func (c *cmdLineData) beforeSave() {} + +// +checklocksignore +func (c *cmdLineData) StateSave(stateSinkObject state.Sink) { + c.beforeSave() + stateSinkObject.Save(0, &c.dynamicBytesFileSetAttr) +} + +func (c *cmdLineData) afterLoad() {} + +// +checklocksignore +func (c *cmdLineData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &c.dynamicBytesFileSetAttr) +} + +func (r *tasksInodeRefs) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tasksInodeRefs" +} + +func (r *tasksInodeRefs) StateFields() []string { + return []string{ + "refCount", + } +} + +func (r *tasksInodeRefs) beforeSave() {} + +// +checklocksignore +func (r *tasksInodeRefs) StateSave(stateSinkObject state.Sink) { + r.beforeSave() + stateSinkObject.Save(0, &r.refCount) +} + +// +checklocksignore +func (r *tasksInodeRefs) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &r.refCount) + stateSourceObject.AfterLoad(r.afterLoad) +} + +func (t *tcpMemDir) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tcpMemDir" +} + +func (t *tcpMemDir) StateFields() []string { + return nil +} + +func (d *mmapMinAddrData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.mmapMinAddrData" +} + +func (d *mmapMinAddrData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "k", + } +} + +func (d *mmapMinAddrData) beforeSave() {} + +// +checklocksignore +func (d *mmapMinAddrData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.k) +} + +func (d *mmapMinAddrData) afterLoad() {} + +// +checklocksignore +func (d *mmapMinAddrData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.k) +} + +func (h *hostnameData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.hostnameData" +} + +func (h *hostnameData) StateFields() []string { + return []string{ + "DynamicBytesFile", + } +} + +func (h *hostnameData) beforeSave() {} + +// +checklocksignore +func (h *hostnameData) StateSave(stateSinkObject state.Sink) { + h.beforeSave() + stateSinkObject.Save(0, &h.DynamicBytesFile) +} + +func (h *hostnameData) afterLoad() {} + +// +checklocksignore +func (h *hostnameData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &h.DynamicBytesFile) +} + +func (d *tcpSackData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tcpSackData" +} + +func (d *tcpSackData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + "enabled", + } +} + +func (d *tcpSackData) beforeSave() {} + +// +checklocksignore +func (d *tcpSackData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.stack) + stateSinkObject.Save(2, &d.enabled) +} + +func (d *tcpSackData) afterLoad() {} + +// +checklocksignore +func (d *tcpSackData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.LoadWait(1, &d.stack) + stateSourceObject.Load(2, &d.enabled) +} + +func (d *tcpRecoveryData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tcpRecoveryData" +} + +func (d *tcpRecoveryData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + } +} + +func (d *tcpRecoveryData) beforeSave() {} + +// +checklocksignore +func (d *tcpRecoveryData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.stack) +} + +func (d *tcpRecoveryData) afterLoad() {} + +// +checklocksignore +func (d *tcpRecoveryData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.LoadWait(1, &d.stack) +} + +func (d *tcpMemData) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.tcpMemData" +} + +func (d *tcpMemData) StateFields() []string { + return []string{ + "DynamicBytesFile", + "dir", + "stack", + } +} + +func (d *tcpMemData) beforeSave() {} + +// +checklocksignore +func (d *tcpMemData) StateSave(stateSinkObject state.Sink) { + d.beforeSave() + stateSinkObject.Save(0, &d.DynamicBytesFile) + stateSinkObject.Save(1, &d.dir) + stateSinkObject.Save(2, &d.stack) +} + +func (d *tcpMemData) afterLoad() {} + +// +checklocksignore +func (d *tcpMemData) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &d.DynamicBytesFile) + stateSourceObject.Load(1, &d.dir) + stateSourceObject.LoadWait(2, &d.stack) +} + +func (ipf *ipForwarding) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.ipForwarding" +} + +func (ipf *ipForwarding) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + "enabled", + } +} + +func (ipf *ipForwarding) beforeSave() {} + +// +checklocksignore +func (ipf *ipForwarding) StateSave(stateSinkObject state.Sink) { + ipf.beforeSave() + stateSinkObject.Save(0, &ipf.DynamicBytesFile) + stateSinkObject.Save(1, &ipf.stack) + stateSinkObject.Save(2, &ipf.enabled) +} + +func (ipf *ipForwarding) afterLoad() {} + +// +checklocksignore +func (ipf *ipForwarding) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &ipf.DynamicBytesFile) + stateSourceObject.LoadWait(1, &ipf.stack) + stateSourceObject.Load(2, &ipf.enabled) +} + +func (pr *portRange) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.portRange" +} + +func (pr *portRange) StateFields() []string { + return []string{ + "DynamicBytesFile", + "stack", + "start", + "end", + } +} + +func (pr *portRange) beforeSave() {} + +// +checklocksignore +func (pr *portRange) StateSave(stateSinkObject state.Sink) { + pr.beforeSave() + stateSinkObject.Save(0, &pr.DynamicBytesFile) + stateSinkObject.Save(1, &pr.stack) + stateSinkObject.Save(2, &pr.start) + stateSinkObject.Save(3, &pr.end) +} + +func (pr *portRange) afterLoad() {} + +// +checklocksignore +func (pr *portRange) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &pr.DynamicBytesFile) + stateSourceObject.LoadWait(1, &pr.stack) + stateSourceObject.Load(2, &pr.start) + stateSourceObject.Load(3, &pr.end) +} + +func (s *yamaPtraceScope) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.yamaPtraceScope" +} + +func (s *yamaPtraceScope) StateFields() []string { + return []string{ + "DynamicBytesFile", + "level", + } +} + +func (s *yamaPtraceScope) beforeSave() {} + +// +checklocksignore +func (s *yamaPtraceScope) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.DynamicBytesFile) + stateSinkObject.Save(1, &s.level) +} + +func (s *yamaPtraceScope) afterLoad() {} + +// +checklocksignore +func (s *yamaPtraceScope) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.DynamicBytesFile) + stateSourceObject.Load(1, &s.level) +} + +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)) + state.Register((*fdInfoData)(nil)) + state.Register((*auxvData)(nil)) + state.Register((*cmdlineData)(nil)) + state.Register((*commInode)(nil)) + state.Register((*commData)(nil)) + state.Register((*idMapData)(nil)) + state.Register((*memInode)(nil)) + state.Register((*memFD)(nil)) + state.Register((*mapsData)(nil)) + state.Register((*smapsData)(nil)) + state.Register((*taskStatData)(nil)) + state.Register((*statmData)(nil)) + state.Register((*statusInode)(nil)) + state.Register((*statusFD)(nil)) + state.Register((*statusFDLowerBase)(nil)) + state.Register((*ioData)(nil)) + state.Register((*oomScoreAdj)(nil)) + state.Register((*exeSymlink)(nil)) + state.Register((*cwdSymlink)(nil)) + state.Register((*mountInfoData)(nil)) + state.Register((*mountsData)(nil)) + state.Register((*namespaceSymlink)(nil)) + state.Register((*namespaceInode)(nil)) + state.Register((*namespaceFD)(nil)) + state.Register((*taskCgroupData)(nil)) + state.Register((*taskInodeRefs)(nil)) + state.Register((*ifinet6)(nil)) + state.Register((*netDevData)(nil)) + state.Register((*netUnixData)(nil)) + state.Register((*netTCPData)(nil)) + 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)) + state.Register((*uptimeData)(nil)) + state.Register((*versionData)(nil)) + state.Register((*filesystemsData)(nil)) + state.Register((*cgroupsData)(nil)) + state.Register((*cmdLineData)(nil)) + state.Register((*tasksInodeRefs)(nil)) + state.Register((*tcpMemDir)(nil)) + state.Register((*mmapMinAddrData)(nil)) + state.Register((*hostnameData)(nil)) + state.Register((*tcpSackData)(nil)) + state.Register((*tcpRecoveryData)(nil)) + state.Register((*tcpMemData)(nil)) + state.Register((*ipForwarding)(nil)) + state.Register((*portRange)(nil)) + state.Register((*yamaPtraceScope)(nil)) +} diff --git a/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go b/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go new file mode 100644 index 000000000..bd4998cbc --- /dev/null +++ b/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go @@ -0,0 +1,140 @@ +package proc + +import ( + "fmt" + "sync/atomic" + + "gvisor.dev/gvisor/pkg/refsvfs2" +) + +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const subtasksInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var subtasksInodeobj *subtasksInode + +// Refs implements refs.RefCounter. It keeps a reference count using atomic +// operations and calls the destructor when the count reaches zero. +// +// NOTE: Do not introduce additional fields to the Refs struct. It is used by +// many filesystem objects, and we want to keep it as small as possible (i.e., +// the same size as using an int64 directly) to avoid taking up extra cache +// space. In general, this template should not be extended at the cost of +// performance. If it does not offer enough flexibility for a particular object +// (example: b/187877947), we should implement the RefCounter/CheckedObject +// interfaces manually. +// +// +stateify savable +type subtasksInodeRefs struct { + // refCount is composed of two fields: + // + // [32-bit speculative references]:[32-bit real references] + // + // Speculative references are used for TryIncRef, to avoid a CompareAndSwap + // loop. See IncRef, DecRef and TryIncRef for details of how these fields are + // used. + refCount int64 +} + +// InitRefs initializes r with one reference and, if enabled, activates leak +// checking. +func (r *subtasksInodeRefs) InitRefs() { + atomic.StoreInt64(&r.refCount, 1) + refsvfs2.Register(r) +} + +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *subtasksInodeRefs) RefType() string { + return fmt.Sprintf("%T", subtasksInodeobj)[1:] +} + +// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +func (r *subtasksInodeRefs) LeakMessage() string { + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *subtasksInodeRefs) LogRefs() bool { + return subtasksInodeenableLogging +} + +// ReadRefs returns the current number of references. The returned count is +// inherently racy and is unsafe to use without external synchronization. +func (r *subtasksInodeRefs) ReadRefs() int64 { + return atomic.LoadInt64(&r.refCount) +} + +// IncRef implements refs.RefCounter.IncRef. +// +//go:nosplit +func (r *subtasksInodeRefs) IncRef() { + v := atomic.AddInt64(&r.refCount, 1) + if subtasksInodeenableLogging { + refsvfs2.LogIncRef(r, v) + } + if v <= 1 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) + } +} + +// TryIncRef implements refs.TryRefCounter.TryIncRef. +// +// To do this safely without a loop, a speculative reference is first acquired +// on the object. This allows multiple concurrent TryIncRef calls to distinguish +// other TryIncRef calls from genuine references held. +// +//go:nosplit +func (r *subtasksInodeRefs) TryIncRef() bool { + const speculativeRef = 1 << 32 + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) == 0 { + + atomic.AddInt64(&r.refCount, -speculativeRef) + return false + } + + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + if subtasksInodeenableLogging { + refsvfs2.LogTryIncRef(r, v) + } + return true +} + +// DecRef implements refs.RefCounter.DecRef. +// +// Note that speculative references are counted here. Since they were added +// prior to real references reaching zero, they will successfully convert to +// real references. In other words, we see speculative references only in the +// following case: +// +// A: TryIncRef [speculative increase => sees non-negative references] +// B: DecRef [real decrease] +// A: TryIncRef [transform speculative to real] +// +//go:nosplit +func (r *subtasksInodeRefs) DecRef(destroy func()) { + v := atomic.AddInt64(&r.refCount, -1) + if subtasksInodeenableLogging { + refsvfs2.LogDecRef(r, v) + } + switch { + case v < 0: + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) + + case v == 0: + refsvfs2.Unregister(r) + + if destroy != nil { + destroy() + } + } +} + +func (r *subtasksInodeRefs) afterLoad() { + if r.ReadRefs() > 0 { + refsvfs2.Register(r) + } +} diff --git a/pkg/sentry/fsimpl/proc/task_inode_refs.go b/pkg/sentry/fsimpl/proc/task_inode_refs.go new file mode 100644 index 000000000..82c63213a --- /dev/null +++ b/pkg/sentry/fsimpl/proc/task_inode_refs.go @@ -0,0 +1,140 @@ +package proc + +import ( + "fmt" + "sync/atomic" + + "gvisor.dev/gvisor/pkg/refsvfs2" +) + +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const taskInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var taskInodeobj *taskInode + +// Refs implements refs.RefCounter. It keeps a reference count using atomic +// operations and calls the destructor when the count reaches zero. +// +// NOTE: Do not introduce additional fields to the Refs struct. It is used by +// many filesystem objects, and we want to keep it as small as possible (i.e., +// the same size as using an int64 directly) to avoid taking up extra cache +// space. In general, this template should not be extended at the cost of +// performance. If it does not offer enough flexibility for a particular object +// (example: b/187877947), we should implement the RefCounter/CheckedObject +// interfaces manually. +// +// +stateify savable +type taskInodeRefs struct { + // refCount is composed of two fields: + // + // [32-bit speculative references]:[32-bit real references] + // + // Speculative references are used for TryIncRef, to avoid a CompareAndSwap + // loop. See IncRef, DecRef and TryIncRef for details of how these fields are + // used. + refCount int64 +} + +// InitRefs initializes r with one reference and, if enabled, activates leak +// checking. +func (r *taskInodeRefs) InitRefs() { + atomic.StoreInt64(&r.refCount, 1) + refsvfs2.Register(r) +} + +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *taskInodeRefs) RefType() string { + return fmt.Sprintf("%T", taskInodeobj)[1:] +} + +// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +func (r *taskInodeRefs) LeakMessage() string { + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *taskInodeRefs) LogRefs() bool { + return taskInodeenableLogging +} + +// ReadRefs returns the current number of references. The returned count is +// inherently racy and is unsafe to use without external synchronization. +func (r *taskInodeRefs) ReadRefs() int64 { + return atomic.LoadInt64(&r.refCount) +} + +// IncRef implements refs.RefCounter.IncRef. +// +//go:nosplit +func (r *taskInodeRefs) IncRef() { + v := atomic.AddInt64(&r.refCount, 1) + if taskInodeenableLogging { + refsvfs2.LogIncRef(r, v) + } + if v <= 1 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) + } +} + +// TryIncRef implements refs.TryRefCounter.TryIncRef. +// +// To do this safely without a loop, a speculative reference is first acquired +// on the object. This allows multiple concurrent TryIncRef calls to distinguish +// other TryIncRef calls from genuine references held. +// +//go:nosplit +func (r *taskInodeRefs) TryIncRef() bool { + const speculativeRef = 1 << 32 + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) == 0 { + + atomic.AddInt64(&r.refCount, -speculativeRef) + return false + } + + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + if taskInodeenableLogging { + refsvfs2.LogTryIncRef(r, v) + } + return true +} + +// DecRef implements refs.RefCounter.DecRef. +// +// Note that speculative references are counted here. Since they were added +// prior to real references reaching zero, they will successfully convert to +// real references. In other words, we see speculative references only in the +// following case: +// +// A: TryIncRef [speculative increase => sees non-negative references] +// B: DecRef [real decrease] +// A: TryIncRef [transform speculative to real] +// +//go:nosplit +func (r *taskInodeRefs) DecRef(destroy func()) { + v := atomic.AddInt64(&r.refCount, -1) + if taskInodeenableLogging { + refsvfs2.LogDecRef(r, v) + } + switch { + case v < 0: + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) + + case v == 0: + refsvfs2.Unregister(r) + + if destroy != nil { + destroy() + } + } +} + +func (r *taskInodeRefs) afterLoad() { + if r.ReadRefs() > 0 { + refsvfs2.Register(r) + } +} diff --git a/pkg/sentry/fsimpl/proc/tasks_inode_refs.go b/pkg/sentry/fsimpl/proc/tasks_inode_refs.go new file mode 100644 index 000000000..73adc5278 --- /dev/null +++ b/pkg/sentry/fsimpl/proc/tasks_inode_refs.go @@ -0,0 +1,140 @@ +package proc + +import ( + "fmt" + "sync/atomic" + + "gvisor.dev/gvisor/pkg/refsvfs2" +) + +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const tasksInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var tasksInodeobj *tasksInode + +// Refs implements refs.RefCounter. It keeps a reference count using atomic +// operations and calls the destructor when the count reaches zero. +// +// NOTE: Do not introduce additional fields to the Refs struct. It is used by +// many filesystem objects, and we want to keep it as small as possible (i.e., +// the same size as using an int64 directly) to avoid taking up extra cache +// space. In general, this template should not be extended at the cost of +// performance. If it does not offer enough flexibility for a particular object +// (example: b/187877947), we should implement the RefCounter/CheckedObject +// interfaces manually. +// +// +stateify savable +type tasksInodeRefs struct { + // refCount is composed of two fields: + // + // [32-bit speculative references]:[32-bit real references] + // + // Speculative references are used for TryIncRef, to avoid a CompareAndSwap + // loop. See IncRef, DecRef and TryIncRef for details of how these fields are + // used. + refCount int64 +} + +// InitRefs initializes r with one reference and, if enabled, activates leak +// checking. +func (r *tasksInodeRefs) InitRefs() { + atomic.StoreInt64(&r.refCount, 1) + refsvfs2.Register(r) +} + +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *tasksInodeRefs) RefType() string { + return fmt.Sprintf("%T", tasksInodeobj)[1:] +} + +// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +func (r *tasksInodeRefs) LeakMessage() string { + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *tasksInodeRefs) LogRefs() bool { + return tasksInodeenableLogging +} + +// ReadRefs returns the current number of references. The returned count is +// inherently racy and is unsafe to use without external synchronization. +func (r *tasksInodeRefs) ReadRefs() int64 { + return atomic.LoadInt64(&r.refCount) +} + +// IncRef implements refs.RefCounter.IncRef. +// +//go:nosplit +func (r *tasksInodeRefs) IncRef() { + v := atomic.AddInt64(&r.refCount, 1) + if tasksInodeenableLogging { + refsvfs2.LogIncRef(r, v) + } + if v <= 1 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) + } +} + +// TryIncRef implements refs.TryRefCounter.TryIncRef. +// +// To do this safely without a loop, a speculative reference is first acquired +// on the object. This allows multiple concurrent TryIncRef calls to distinguish +// other TryIncRef calls from genuine references held. +// +//go:nosplit +func (r *tasksInodeRefs) TryIncRef() bool { + const speculativeRef = 1 << 32 + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) == 0 { + + atomic.AddInt64(&r.refCount, -speculativeRef) + return false + } + + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + if tasksInodeenableLogging { + refsvfs2.LogTryIncRef(r, v) + } + return true +} + +// DecRef implements refs.RefCounter.DecRef. +// +// Note that speculative references are counted here. Since they were added +// prior to real references reaching zero, they will successfully convert to +// real references. In other words, we see speculative references only in the +// following case: +// +// A: TryIncRef [speculative increase => sees non-negative references] +// B: DecRef [real decrease] +// A: TryIncRef [transform speculative to real] +// +//go:nosplit +func (r *tasksInodeRefs) DecRef(destroy func()) { + v := atomic.AddInt64(&r.refCount, -1) + if tasksInodeenableLogging { + refsvfs2.LogDecRef(r, v) + } + switch { + case v < 0: + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) + + case v == 0: + refsvfs2.Unregister(r) + + if destroy != nil { + destroy() + } + } +} + +func (r *tasksInodeRefs) afterLoad() { + if r.ReadRefs() > 0 { + refsvfs2.Register(r) + } +} diff --git a/pkg/sentry/fsimpl/proc/tasks_sys_test.go b/pkg/sentry/fsimpl/proc/tasks_sys_test.go deleted file mode 100644 index 19b012f7d..000000000 --- a/pkg/sentry/fsimpl/proc/tasks_sys_test.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package proc - -import ( - "bytes" - "reflect" - "testing" - - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/context" - "gvisor.dev/gvisor/pkg/sentry/contexttest" - "gvisor.dev/gvisor/pkg/sentry/inet" - "gvisor.dev/gvisor/pkg/usermem" -) - -func newIPv6TestStack() *inet.TestStack { - s := inet.NewTestStack() - s.SupportsIPv6Flag = true - return s -} - -func TestIfinet6NoAddresses(t *testing.T) { - n := &ifinet6{stack: newIPv6TestStack()} - var buf bytes.Buffer - n.Generate(contexttest.Context(t), &buf) - if buf.Len() > 0 { - t.Errorf("n.Generate() generated = %v, want = %v", buf.Bytes(), []byte{}) - } -} - -func TestIfinet6(t *testing.T) { - s := newIPv6TestStack() - s.InterfacesMap[1] = inet.Interface{Name: "eth0"} - s.InterfaceAddrsMap[1] = []inet.InterfaceAddr{ - { - Family: linux.AF_INET6, - PrefixLen: 128, - Addr: []byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"), - }, - } - s.InterfacesMap[2] = inet.Interface{Name: "eth1"} - s.InterfaceAddrsMap[2] = []inet.InterfaceAddr{ - { - Family: linux.AF_INET6, - PrefixLen: 128, - Addr: []byte("\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"), - }, - } - want := map[string]struct{}{ - "000102030405060708090a0b0c0d0e0f 01 80 00 00 eth0\n": {}, - "101112131415161718191a1b1c1d1e1f 02 80 00 00 eth1\n": {}, - } - - n := &ifinet6{stack: s} - contents := n.contents() - if len(contents) != len(want) { - t.Errorf("Got len(n.contents()) = %d, want = %d", len(contents), len(want)) - } - got := map[string]struct{}{} - for _, l := range contents { - got[l] = struct{}{} - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Got n.contents() = %v, want = %v", got, want) - } -} - -// TestIPForwarding tests the implementation of -// /proc/sys/net/ipv4/ip_forwarding -func TestConfigureIPForwarding(t *testing.T) { - ctx := context.Background() - s := inet.NewTestStack() - - var cases = []struct { - comment string - initial bool - str string - final bool - }{ - { - comment: `Forwarding is disabled; write 1 and enable forwarding`, - initial: false, - str: "1", - final: true, - }, - { - comment: `Forwarding is disabled; write 0 and disable forwarding`, - initial: false, - str: "0", - final: false, - }, - { - comment: `Forwarding is enabled; write 1 and enable forwarding`, - initial: true, - str: "1", - final: true, - }, - { - comment: `Forwarding is enabled; write 0 and disable forwarding`, - initial: true, - str: "0", - final: false, - }, - { - comment: `Forwarding is disabled; write 2404 and enable forwarding`, - initial: false, - str: "2404", - final: true, - }, - { - comment: `Forwarding is enabled; write 2404 and enable forwarding`, - initial: true, - str: "2404", - final: true, - }, - } - for _, c := range cases { - t.Run(c.comment, func(t *testing.T) { - s.IPForwarding = c.initial - - file := &ipForwarding{stack: s, enabled: c.initial} - - // Write the values. - src := usermem.BytesIOSequence([]byte(c.str)) - if n, err := file.Write(ctx, src, 0); n != int64(len(c.str)) || err != nil { - t.Errorf("file.Write(ctx, nil, %q, 0) = (%d, %v); want (%d, nil)", c.str, n, err, len(c.str)) - } - - // Read the values from the stack and check them. - if got, want := s.IPForwarding, c.final; got != want { - t.Errorf("s.IPForwarding incorrect; got: %v, want: %v", got, want) - } - }) - } -} diff --git a/pkg/sentry/fsimpl/proc/tasks_test.go b/pkg/sentry/fsimpl/proc/tasks_test.go deleted file mode 100644 index 14f806c3c..000000000 --- a/pkg/sentry/fsimpl/proc/tasks_test.go +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package proc - -import ( - "fmt" - "math" - "path" - "strconv" - "testing" - - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/context" - "gvisor.dev/gvisor/pkg/errors/linuxerr" - "gvisor.dev/gvisor/pkg/fspath" - "gvisor.dev/gvisor/pkg/sentry/fsimpl/testutil" - "gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs" - "gvisor.dev/gvisor/pkg/sentry/kernel" - "gvisor.dev/gvisor/pkg/sentry/kernel/auth" - "gvisor.dev/gvisor/pkg/sentry/vfs" - "gvisor.dev/gvisor/pkg/usermem" -) - -var ( - // Next offset 256 by convention. Adds 1 for the next offset. - selfLink = vfs.Dirent{Type: linux.DT_LNK, NextOff: 256 + 0 + 1} - threadSelfLink = vfs.Dirent{Type: linux.DT_LNK, NextOff: 256 + 1 + 1} - - // /proc/[pid] next offset starts at 256+2 (files above), then adds the - // PID, and adds 1 for the next offset. - proc1 = vfs.Dirent{Type: linux.DT_DIR, NextOff: 258 + 1 + 1} - proc2 = vfs.Dirent{Type: linux.DT_DIR, NextOff: 258 + 2 + 1} - proc3 = vfs.Dirent{Type: linux.DT_DIR, NextOff: 258 + 3 + 1} -) - -var ( - tasksStaticFiles = map[string]testutil.DirentType{ - "cmdline": linux.DT_REG, - "cpuinfo": linux.DT_REG, - "filesystems": linux.DT_REG, - "loadavg": linux.DT_REG, - "meminfo": linux.DT_REG, - "mounts": linux.DT_LNK, - "net": linux.DT_LNK, - "self": linux.DT_LNK, - "stat": linux.DT_REG, - "sys": linux.DT_DIR, - "thread-self": linux.DT_LNK, - "uptime": linux.DT_REG, - "version": linux.DT_REG, - } - tasksStaticFilesNextOffs = map[string]int64{ - "self": selfLink.NextOff, - "thread-self": threadSelfLink.NextOff, - } - taskStaticFiles = map[string]testutil.DirentType{ - "auxv": linux.DT_REG, - "cgroup": linux.DT_REG, - "cwd": linux.DT_LNK, - "cmdline": linux.DT_REG, - "comm": linux.DT_REG, - "environ": linux.DT_REG, - "exe": linux.DT_LNK, - "fd": linux.DT_DIR, - "fdinfo": linux.DT_DIR, - "gid_map": linux.DT_REG, - "io": linux.DT_REG, - "maps": linux.DT_REG, - "mem": linux.DT_REG, - "mountinfo": linux.DT_REG, - "mounts": linux.DT_REG, - "net": linux.DT_DIR, - "ns": linux.DT_DIR, - "oom_score": linux.DT_REG, - "oom_score_adj": linux.DT_REG, - "smaps": linux.DT_REG, - "stat": linux.DT_REG, - "statm": linux.DT_REG, - "status": linux.DT_REG, - "task": linux.DT_DIR, - "uid_map": linux.DT_REG, - } -) - -func setup(t *testing.T) *testutil.System { - k, err := testutil.Boot() - if err != nil { - t.Fatalf("Error creating kernel: %v", err) - } - - ctx := k.SupervisorContext() - creds := auth.CredentialsFromContext(ctx) - - k.VFS().MustRegisterFilesystemType(Name, &FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ - AllowUserMount: true, - }) - - mntns, err := k.VFS().NewMountNamespace(ctx, creds, "", tmpfs.Name, &vfs.MountOptions{}) - if err != nil { - t.Fatalf("NewMountNamespace(): %v", err) - } - root := mntns.Root() - root.IncRef() - defer root.DecRef(ctx) - pop := &vfs.PathOperation{ - Root: root, - Start: root, - Path: fspath.Parse("/proc"), - } - if err := k.VFS().MkdirAt(ctx, creds, pop, &vfs.MkdirOptions{Mode: 0777}); err != nil { - t.Fatalf("MkDir(/proc): %v", err) - } - - pop = &vfs.PathOperation{ - Root: root, - Start: root, - Path: fspath.Parse("/proc"), - } - mntOpts := &vfs.MountOptions{ - GetFilesystemOptions: vfs.GetFilesystemOptions{ - InternalData: &InternalData{ - Cgroups: map[string]string{ - "cpuset": "/foo/cpuset", - "memory": "/foo/memory", - }, - }, - }, - } - if _, err := k.VFS().MountAt(ctx, creds, "", pop, Name, mntOpts); err != nil { - t.Fatalf("MountAt(/proc): %v", err) - } - return testutil.NewSystem(ctx, t, k.VFS(), mntns) -} - -func TestTasksEmpty(t *testing.T) { - s := setup(t) - defer s.Destroy() - - collector := s.ListDirents(s.PathOpAtRoot("/proc")) - s.AssertAllDirentTypes(collector, tasksStaticFiles) - s.AssertDirentOffsets(collector, tasksStaticFilesNextOffs) -} - -func TestTasks(t *testing.T) { - s := setup(t) - defer s.Destroy() - - expectedDirents := make(map[string]testutil.DirentType) - for n, d := range tasksStaticFiles { - expectedDirents[n] = d - } - - k := kernel.KernelFromContext(s.Ctx) - var tasks []*kernel.Task - for i := 0; i < 5; i++ { - tc := k.NewThreadGroup(nil, k.RootPIDNamespace(), kernel.NewSignalHandlers(), linux.SIGCHLD, k.GlobalInit().Limits()) - task, err := testutil.CreateTask(s.Ctx, fmt.Sprintf("name-%d", i), tc, s.MntNs, s.Root, s.Root) - if err != nil { - t.Fatalf("CreateTask(): %v", err) - } - tasks = append(tasks, task) - expectedDirents[fmt.Sprintf("%d", i+1)] = linux.DT_DIR - } - - collector := s.ListDirents(s.PathOpAtRoot("/proc")) - s.AssertAllDirentTypes(collector, expectedDirents) - s.AssertDirentOffsets(collector, tasksStaticFilesNextOffs) - - lastPid := 0 - dirents := collector.OrderedDirents() - doneSkippingNonTaskDirs := false - for _, d := range dirents { - pid, err := strconv.Atoi(d.Name) - if err != nil { - if !doneSkippingNonTaskDirs { - // We haven't gotten to the task dirs yet. - continue - } - t.Fatalf("Invalid process directory %q", d.Name) - } - doneSkippingNonTaskDirs = true - if lastPid > pid { - t.Errorf("pids not in order: %v", dirents) - } - found := false - for _, t := range tasks { - if k.TaskSet().Root.IDOfTask(t) == kernel.ThreadID(pid) { - found = true - } - } - if !found { - t.Errorf("Additional task ID %d listed: %v", pid, tasks) - } - // Next offset starts at 256+2 ('self' and 'thread-self'), then adds the - // PID, and adds 1 for the next offset. - if want := int64(256 + 2 + pid + 1); d.NextOff != want { - t.Errorf("Wrong dirent offset want: %d got: %d: %+v", want, d.NextOff, d) - } - } - if !doneSkippingNonTaskDirs { - t.Fatalf("Never found any process directories.") - } - - // Test lookup. - for _, path := range []string{"/proc/1", "/proc/2"} { - fd, err := s.VFS.OpenAt( - s.Ctx, - s.Creds, - s.PathOpAtRoot(path), - &vfs.OpenOptions{}, - ) - if err != nil { - t.Fatalf("vfsfs.OpenAt(%q) failed: %v", path, err) - } - defer fd.DecRef(s.Ctx) - buf := make([]byte, 1) - bufIOSeq := usermem.BytesIOSequence(buf) - if _, err := fd.Read(s.Ctx, bufIOSeq, vfs.ReadOptions{}); !linuxerr.Equals(linuxerr.EISDIR, err) { - t.Errorf("wrong error reading directory: %v", err) - } - } - - if _, err := s.VFS.OpenAt( - s.Ctx, - s.Creds, - s.PathOpAtRoot("/proc/9999"), - &vfs.OpenOptions{}, - ); !linuxerr.Equals(linuxerr.ENOENT, err) { - t.Fatalf("wrong error from vfsfs.OpenAt(/proc/9999): %v", err) - } -} - -func TestTasksOffset(t *testing.T) { - s := setup(t) - defer s.Destroy() - - k := kernel.KernelFromContext(s.Ctx) - for i := 0; i < 3; i++ { - tc := k.NewThreadGroup(nil, k.RootPIDNamespace(), kernel.NewSignalHandlers(), linux.SIGCHLD, k.GlobalInit().Limits()) - if _, err := testutil.CreateTask(s.Ctx, fmt.Sprintf("name-%d", i), tc, s.MntNs, s.Root, s.Root); err != nil { - t.Fatalf("CreateTask(): %v", err) - } - } - - for _, tc := range []struct { - name string - offset int64 - wants map[string]vfs.Dirent - }{ - { - name: "small offset", - offset: 100, - wants: map[string]vfs.Dirent{ - "self": selfLink, - "thread-self": threadSelfLink, - "1": proc1, - "2": proc2, - "3": proc3, - }, - }, - { - name: "offset at start", - offset: 256, - wants: map[string]vfs.Dirent{ - "self": selfLink, - "thread-self": threadSelfLink, - "1": proc1, - "2": proc2, - "3": proc3, - }, - }, - { - name: "skip /proc/self", - offset: 257, - wants: map[string]vfs.Dirent{ - "thread-self": threadSelfLink, - "1": proc1, - "2": proc2, - "3": proc3, - }, - }, - { - name: "skip symlinks", - offset: 258, - wants: map[string]vfs.Dirent{ - "1": proc1, - "2": proc2, - "3": proc3, - }, - }, - { - name: "skip first process", - offset: 260, - wants: map[string]vfs.Dirent{ - "2": proc2, - "3": proc3, - }, - }, - { - name: "last process", - offset: 261, - wants: map[string]vfs.Dirent{ - "3": proc3, - }, - }, - { - name: "after last", - offset: 262, - wants: nil, - }, - { - name: "TaskLimit+1", - offset: kernel.TasksLimit + 1, - wants: nil, - }, - { - name: "max", - offset: math.MaxInt64, - wants: nil, - }, - } { - t.Run(tc.name, func(t *testing.T) { - s := s.WithSubtest(t) - fd, err := s.VFS.OpenAt( - s.Ctx, - s.Creds, - s.PathOpAtRoot("/proc"), - &vfs.OpenOptions{}, - ) - if err != nil { - t.Fatalf("vfsfs.OpenAt(/) failed: %v", err) - } - defer fd.DecRef(s.Ctx) - if _, err := fd.Seek(s.Ctx, tc.offset, linux.SEEK_SET); err != nil { - t.Fatalf("Seek(%d, SEEK_SET): %v", tc.offset, err) - } - - var collector testutil.DirentCollector - if err := fd.IterDirents(s.Ctx, &collector); err != nil { - t.Fatalf("IterDirent(): %v", err) - } - - expectedTypes := make(map[string]testutil.DirentType) - expectedOffsets := make(map[string]int64) - for name, want := range tc.wants { - expectedTypes[name] = want.Type - if want.NextOff != 0 { - expectedOffsets[name] = want.NextOff - } - } - - collector.SkipDotsChecks(true) // We seek()ed past the dots. - s.AssertAllDirentTypes(&collector, expectedTypes) - s.AssertDirentOffsets(&collector, expectedOffsets) - }) - } -} - -func TestTask(t *testing.T) { - s := setup(t) - defer s.Destroy() - - k := kernel.KernelFromContext(s.Ctx) - tc := k.NewThreadGroup(nil, k.RootPIDNamespace(), kernel.NewSignalHandlers(), linux.SIGCHLD, k.GlobalInit().Limits()) - _, err := testutil.CreateTask(s.Ctx, "name", tc, s.MntNs, s.Root, s.Root) - if err != nil { - t.Fatalf("CreateTask(): %v", err) - } - - collector := s.ListDirents(s.PathOpAtRoot("/proc/1")) - s.AssertAllDirentTypes(collector, taskStaticFiles) -} - -func TestProcSelf(t *testing.T) { - s := setup(t) - defer s.Destroy() - - k := kernel.KernelFromContext(s.Ctx) - tc := k.NewThreadGroup(nil, k.RootPIDNamespace(), kernel.NewSignalHandlers(), linux.SIGCHLD, k.GlobalInit().Limits()) - task, err := testutil.CreateTask(s.Ctx, "name", tc, s.MntNs, s.Root, s.Root) - if err != nil { - t.Fatalf("CreateTask(): %v", err) - } - - collector := s.WithTemporaryContext(task.AsyncContext()).ListDirents(&vfs.PathOperation{ - Root: s.Root, - Start: s.Root, - Path: fspath.Parse("/proc/self/"), - FollowFinalSymlink: true, - }) - s.AssertAllDirentTypes(collector, taskStaticFiles) -} - -func iterateDir(ctx context.Context, t *testing.T, s *testutil.System, fd *vfs.FileDescription) { - t.Logf("Iterating: %s", fd.MappedName(ctx)) - - var collector testutil.DirentCollector - if err := fd.IterDirents(ctx, &collector); err != nil { - t.Fatalf("IterDirents(): %v", err) - } - if err := collector.Contains(".", linux.DT_DIR); err != nil { - t.Error(err.Error()) - } - if err := collector.Contains("..", linux.DT_DIR); err != nil { - t.Error(err.Error()) - } - - for _, d := range collector.Dirents() { - if d.Name == "." || d.Name == ".." { - continue - } - absPath := path.Join(fd.MappedName(ctx), d.Name) - if d.Type == linux.DT_LNK { - link, err := s.VFS.ReadlinkAt( - ctx, - auth.CredentialsFromContext(ctx), - &vfs.PathOperation{Root: s.Root, Start: s.Root, Path: fspath.Parse(absPath)}, - ) - if err != nil { - t.Errorf("vfsfs.ReadlinkAt(%v) failed: %v", absPath, err) - } else { - t.Logf("Skipping symlink: %s => %s", absPath, link) - } - continue - } - - t.Logf("Opening: %s", absPath) - child, err := s.VFS.OpenAt( - ctx, - auth.CredentialsFromContext(ctx), - &vfs.PathOperation{Root: s.Root, Start: s.Root, Path: fspath.Parse(absPath)}, - &vfs.OpenOptions{}, - ) - if err != nil { - t.Errorf("vfsfs.OpenAt(%v) failed: %v", absPath, err) - continue - } - defer child.DecRef(ctx) - stat, err := child.Stat(ctx, vfs.StatOptions{}) - if err != nil { - t.Errorf("Stat(%v) failed: %v", absPath, err) - } - if got := linux.FileMode(stat.Mode).DirentType(); got != d.Type { - t.Errorf("wrong file mode, stat: %v, dirent: %v", got, d.Type) - } - if d.Type == linux.DT_DIR { - // Found another dir, let's do it again! - iterateDir(ctx, t, s, child) - } - } -} - -// TestTree iterates all directories and stats every file. -func TestTree(t *testing.T) { - s := setup(t) - defer s.Destroy() - - k := kernel.KernelFromContext(s.Ctx) - - pop := &vfs.PathOperation{ - Root: s.Root, - Start: s.Root, - Path: fspath.Parse("test-file"), - } - opts := &vfs.OpenOptions{ - Flags: linux.O_RDONLY | linux.O_CREAT, - Mode: 0777, - } - file, err := s.VFS.OpenAt(s.Ctx, s.Creds, pop, opts) - if err != nil { - t.Fatalf("failed to create test file: %v", err) - } - defer file.DecRef(s.Ctx) - - var tasks []*kernel.Task - for i := 0; i < 5; i++ { - tc := k.NewThreadGroup(nil, k.RootPIDNamespace(), kernel.NewSignalHandlers(), linux.SIGCHLD, k.GlobalInit().Limits()) - task, err := testutil.CreateTask(s.Ctx, fmt.Sprintf("name-%d", i), tc, s.MntNs, s.Root, s.Root) - if err != nil { - t.Fatalf("CreateTask(): %v", err) - } - // Add file to populate /proc/[pid]/fd and fdinfo directories. - task.FDTable().NewFDVFS2(task.AsyncContext(), 0, file, kernel.FDFlags{}) - tasks = append(tasks, task) - } - - ctx := tasks[0].AsyncContext() - fd, err := s.VFS.OpenAt( - ctx, - auth.CredentialsFromContext(s.Ctx), - &vfs.PathOperation{Root: s.Root, Start: s.Root, Path: fspath.Parse("/proc")}, - &vfs.OpenOptions{}, - ) - if err != nil { - t.Fatalf("vfsfs.OpenAt(/proc) failed: %v", err) - } - iterateDir(ctx, t, s, fd) - fd.DecRef(ctx) -} |