summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/proc
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fsimpl/proc')
-rw-r--r--pkg/sentry/fsimpl/proc/BUILD133
-rw-r--r--pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go140
-rw-r--r--pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go140
-rw-r--r--pkg/sentry/fsimpl/proc/proc_state_autogen.go2348
-rw-r--r--pkg/sentry/fsimpl/proc/subtasks_inode_refs.go140
-rw-r--r--pkg/sentry/fsimpl/proc/task_inode_refs.go140
-rw-r--r--pkg/sentry/fsimpl/proc/tasks_inode_refs.go140
-rw-r--r--pkg/sentry/fsimpl/proc/tasks_sys_test.go149
-rw-r--r--pkg/sentry/fsimpl/proc/tasks_test.go511
9 files changed, 3048 insertions, 793 deletions
diff --git a/pkg/sentry/fsimpl/proc/BUILD b/pkg/sentry/fsimpl/proc/BUILD
deleted file mode 100644
index 2b628bd55..000000000
--- a/pkg/sentry/fsimpl/proc/BUILD
+++ /dev/null
@@ -1,133 +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/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/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/syserror",
- "//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..bda0589f8
--- /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.RefCounter.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..f000064ef
--- /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.RefCounter.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..ebcb21edb
--- /dev/null
+++ b/pkg/sentry/fsimpl/proc/proc_state_autogen.go
@@ -0,0 +1,2348 @@
+// 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",
+ "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.task)
+ stateSinkObject.Save(5, &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.task)
+ stateSourceObject.Load(5, &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",
+ "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.task)
+ stateSinkObject.Save(2, &d.fd)
+}
+
+func (d *fdInfoData) afterLoad() {}
+
+// +checklocksignore
+func (d *fdInfoData) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &d.DynamicBytesFile)
+ stateSourceObject.Load(1, &d.task)
+ stateSourceObject.Load(2, &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 *statusData) StateTypeName() string {
+ return "pkg/sentry/fsimpl/proc.statusData"
+}
+
+func (s *statusData) StateFields() []string {
+ return []string{
+ "DynamicBytesFile",
+ "task",
+ "pidns",
+ }
+}
+
+func (s *statusData) beforeSave() {}
+
+// +checklocksignore
+func (s *statusData) StateSave(stateSinkObject state.Sink) {
+ s.beforeSave()
+ stateSinkObject.Save(0, &s.DynamicBytesFile)
+ stateSinkObject.Save(1, &s.task)
+ stateSinkObject.Save(2, &s.pidns)
+}
+
+func (s *statusData) afterLoad() {}
+
+// +checklocksignore
+func (s *statusData) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &s.DynamicBytesFile)
+ stateSourceObject.Load(1, &s.task)
+ stateSourceObject.Load(2, &s.pidns)
+}
+
+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",
+ "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.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.task)
+}
+
+func (s *cwdSymlink) StateTypeName() string {
+ return "pkg/sentry/fsimpl/proc.cwdSymlink"
+}
+
+func (s *cwdSymlink) StateFields() []string {
+ return []string{
+ "implStatFS",
+ "InodeAttrs",
+ "InodeNoopRefCount",
+ "InodeSymlink",
+ "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.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.task)
+}
+
+func (i *mountInfoData) StateTypeName() string {
+ return "pkg/sentry/fsimpl/proc.mountInfoData"
+}
+
+func (i *mountInfoData) StateFields() []string {
+ return []string{
+ "DynamicBytesFile",
+ "task",
+ }
+}
+
+func (i *mountInfoData) beforeSave() {}
+
+// +checklocksignore
+func (i *mountInfoData) StateSave(stateSinkObject state.Sink) {
+ i.beforeSave()
+ stateSinkObject.Save(0, &i.DynamicBytesFile)
+ stateSinkObject.Save(1, &i.task)
+}
+
+func (i *mountInfoData) afterLoad() {}
+
+// +checklocksignore
+func (i *mountInfoData) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &i.DynamicBytesFile)
+ stateSourceObject.Load(1, &i.task)
+}
+
+func (i *mountsData) StateTypeName() string {
+ return "pkg/sentry/fsimpl/proc.mountsData"
+}
+
+func (i *mountsData) StateFields() []string {
+ return []string{
+ "DynamicBytesFile",
+ "task",
+ }
+}
+
+func (i *mountsData) beforeSave() {}
+
+// +checklocksignore
+func (i *mountsData) StateSave(stateSinkObject state.Sink) {
+ i.beforeSave()
+ stateSinkObject.Save(0, &i.DynamicBytesFile)
+ stateSinkObject.Save(1, &i.task)
+}
+
+func (i *mountsData) afterLoad() {}
+
+// +checklocksignore
+func (i *mountsData) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &i.DynamicBytesFile)
+ stateSourceObject.Load(1, &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((*statusData)(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..fb3517437
--- /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.RefCounter.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..5d08a2992
--- /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.RefCounter.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..2bfadc272
--- /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.RefCounter.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 e534fbca8..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/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/syserror"
- "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{}); err != syserror.EISDIR {
- t.Errorf("wrong error reading directory: %v", err)
- }
- }
-
- if _, err := s.VFS.OpenAt(
- s.Ctx,
- s.Creds,
- s.PathOpAtRoot("/proc/9999"),
- &vfs.OpenOptions{},
- ); err != syserror.ENOENT {
- 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)
-}