mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Use new reference count utility throughout gvisor.
This uses the refs_vfs2 template in vfs2 as well as objects common to vfs1 and vfs2. Note that vfs1-only refcounts are not replaced, since vfs1 will be deleted soon anyway. The following structs now use the new tool, with leak check enabled: devpts:rootInode fuse:inode kernfs:Dentry kernfs:dir kernfs:readonlyDir kernfs:StaticDirectory proc:fdDirInode proc:fdInfoDirInode proc:subtasksInode proc:taskInode proc:tasksInode vfs:FileDescription vfs:MountNamespace vfs:Filesystem sys:dir kernel:FSContext kernel:ProcessGroup kernel:Session shm:Shm mm:aioMappable mm:SpecialMappable transport:queue And the following use the template, but because they currently are not leak checked, a TODO is left instead of enabling leak check in this patch: kernel:FDTable tun:tunEndpoint Updates #1486. PiperOrigin-RevId: 328460377
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ go_template(
|
||||
types = [
|
||||
"T",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
"//pkg/log",
|
||||
"//pkg/refs",
|
||||
|
||||
@@ -12,11 +12,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package refs_template defines a template that can be used by reference counted
|
||||
// objects.
|
||||
// Package refs_template defines a template that can be used by reference
|
||||
// counted objects. The "owner" template parameter is used in log messages to
|
||||
// indicate the type of reference-counted object that exhibited a reference
|
||||
// leak. As a result, structs that are embedded in other structs should not use
|
||||
// this template, since it will make tracking down leaks more difficult.
|
||||
package refs_template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
|
||||
@@ -38,6 +42,11 @@ var ownerType *T
|
||||
// Note that the number of references is actually refCount + 1 so that a default
|
||||
// zero-value Refs object contains one reference.
|
||||
//
|
||||
// TODO(gvisor.dev/issue/1486): Store stack traces when leak check is enabled in
|
||||
// a map with 16-bit hashes, and store the hash in the top 16 bits of refCount.
|
||||
// This will allow us to add stack trace information to the leak messages
|
||||
// without growing the size of Refs.
|
||||
//
|
||||
// +stateify savable
|
||||
type Refs struct {
|
||||
// refCount is composed of two fields:
|
||||
@@ -82,7 +91,7 @@ func (r *Refs) ReadRefs() int64 {
|
||||
//go:nosplit
|
||||
func (r *Refs) IncRef() {
|
||||
if v := atomic.AddInt64(&r.refCount, 1); v <= 0 {
|
||||
panic("Incrementing non-positive ref count")
|
||||
panic(fmt.Sprintf("Incrementing non-positive ref count %p owned by %T", r, ownerType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +131,7 @@ func (r *Refs) TryIncRef() bool {
|
||||
func (r *Refs) DecRef(destroy func()) {
|
||||
switch v := atomic.AddInt64(&r.refCount, -1); {
|
||||
case v < -1:
|
||||
panic("Decrementing non-positive ref count")
|
||||
panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %T", r, ownerType))
|
||||
|
||||
case v == -1:
|
||||
// Call the destructor.
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
load("//tools/go_generics:defs.bzl", "go_template_instance")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
go_template_instance(
|
||||
name = "root_inode_refs",
|
||||
out = "root_inode_refs.go",
|
||||
package = "devpts",
|
||||
prefix = "rootInode",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "rootInode",
|
||||
},
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "devpts",
|
||||
srcs = [
|
||||
@@ -9,6 +21,7 @@ go_library(
|
||||
"line_discipline.go",
|
||||
"master.go",
|
||||
"queue.go",
|
||||
"root_inode_refs.go",
|
||||
"slave.go",
|
||||
"terminal.go",
|
||||
],
|
||||
@@ -16,6 +29,8 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/log",
|
||||
"//pkg/refs",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fs/lock",
|
||||
|
||||
@@ -83,6 +83,7 @@ func (fstype FilesystemType) newFilesystem(vfsObj *vfs.VirtualFilesystem, creds
|
||||
}
|
||||
root.InodeAttrs.Init(creds, linux.UNNAMED_MAJOR, devMinor, 1, linux.ModeDirectory|0555)
|
||||
root.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
root.EnableLeakCheck()
|
||||
root.dentry.Init(root)
|
||||
|
||||
// Construct the pts master inode and dentry. Linux always uses inode
|
||||
@@ -110,6 +111,7 @@ func (fs *filesystem) Release(ctx context.Context) {
|
||||
|
||||
// rootInode is the root directory inode for the devpts mounts.
|
||||
type rootInode struct {
|
||||
rootInodeRefs
|
||||
kernfs.AlwaysValid
|
||||
kernfs.InodeAttrs
|
||||
kernfs.InodeDirectoryNoNewChildren
|
||||
@@ -233,3 +235,8 @@ func (i *rootInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback,
|
||||
}
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *rootInode) DecRef(context.Context) {
|
||||
i.rootInodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,17 @@ go_template_instance(
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "inode_refs",
|
||||
out = "inode_refs.go",
|
||||
package = "fuse",
|
||||
prefix = "inode",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "inode",
|
||||
},
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "fuse",
|
||||
srcs = [
|
||||
@@ -22,6 +33,7 @@ go_library(
|
||||
"dev.go",
|
||||
"fusefs.go",
|
||||
"init.go",
|
||||
"inode_refs.go",
|
||||
"register.go",
|
||||
"request_list.go",
|
||||
],
|
||||
@@ -30,6 +42,7 @@ go_library(
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/log",
|
||||
"//pkg/refs",
|
||||
"//pkg/sentry/fsimpl/devtmpfs",
|
||||
"//pkg/sentry/fsimpl/kernfs",
|
||||
"//pkg/sentry/kernel",
|
||||
|
||||
@@ -198,6 +198,7 @@ func (fs *filesystem) Release(ctx context.Context) {
|
||||
|
||||
// inode implements kernfs.Inode.
|
||||
type inode struct {
|
||||
inodeRefs
|
||||
kernfs.InodeAttrs
|
||||
kernfs.InodeNoDynamicLookup
|
||||
kernfs.InodeNotSymlink
|
||||
@@ -213,6 +214,7 @@ func (fs *filesystem) newInode(creds *auth.Credentials, mode linux.FileMode) *ke
|
||||
i := &inode{}
|
||||
i.InodeAttrs.Init(creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0755)
|
||||
i.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
i.EnableLeakCheck()
|
||||
i.dentry.Init(i)
|
||||
|
||||
return &i.dentry
|
||||
@@ -324,3 +326,8 @@ func (i *inode) Stat(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOptio
|
||||
|
||||
return statFromFUSEAttr(out.Attr, opts.Mask, fusefs.devMinor), nil
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *inode) DecRef(context.Context) {
|
||||
i.inodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
@@ -26,9 +26,54 @@ go_template_instance(
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "dentry_refs",
|
||||
out = "dentry_refs.go",
|
||||
package = "kernfs",
|
||||
prefix = "Dentry",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "Dentry",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "static_directory_refs",
|
||||
out = "static_directory_refs.go",
|
||||
package = "kernfs",
|
||||
prefix = "StaticDirectory",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "StaticDirectory",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "dir_refs",
|
||||
out = "dir_refs.go",
|
||||
package = "kernfs_test",
|
||||
prefix = "dir",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "dir",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "readonly_dir_refs",
|
||||
out = "readonly_dir_refs.go",
|
||||
package = "kernfs_test",
|
||||
prefix = "readonlyDir",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "readonlyDir",
|
||||
},
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "kernfs",
|
||||
srcs = [
|
||||
"dentry_refs.go",
|
||||
"dynamic_bytes_file.go",
|
||||
"fd_impl_util.go",
|
||||
"filesystem.go",
|
||||
@@ -36,6 +81,7 @@ go_library(
|
||||
"inode_impl_util.go",
|
||||
"kernfs.go",
|
||||
"slot_list.go",
|
||||
"static_directory_refs.go",
|
||||
"symlink.go",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
@@ -59,11 +105,17 @@ go_library(
|
||||
go_test(
|
||||
name = "kernfs_test",
|
||||
size = "small",
|
||||
srcs = ["kernfs_test.go"],
|
||||
srcs = [
|
||||
"dir_refs.go",
|
||||
"kernfs_test.go",
|
||||
"readonly_dir_refs.go",
|
||||
],
|
||||
deps = [
|
||||
":kernfs",
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/log",
|
||||
"//pkg/refs",
|
||||
"//pkg/sentry/contexttest",
|
||||
"//pkg/sentry/fsimpl/testutil",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
@@ -344,8 +343,6 @@ type OrderedChildrenOptions struct {
|
||||
//
|
||||
// Must be initialize with Init before first use.
|
||||
type OrderedChildren struct {
|
||||
refs.AtomicRefCount
|
||||
|
||||
// Can children be modified by user syscalls? It set to false, interface
|
||||
// methods that would modify the children return EPERM. Immutable.
|
||||
writable bool
|
||||
@@ -361,14 +358,14 @@ func (o *OrderedChildren) Init(opts OrderedChildrenOptions) {
|
||||
o.set = make(map[string]*slot)
|
||||
}
|
||||
|
||||
// DecRef implements Inode.DecRef.
|
||||
func (o *OrderedChildren) DecRef(ctx context.Context) {
|
||||
o.AtomicRefCount.DecRefWithDestructor(ctx, func(context.Context) {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
o.order.Reset()
|
||||
o.set = nil
|
||||
})
|
||||
// Destroy clears the children stored in o. It should be called by structs
|
||||
// embedding OrderedChildren upon destruction, i.e. when their reference count
|
||||
// reaches zero.
|
||||
func (o *OrderedChildren) Destroy() {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
o.order.Reset()
|
||||
o.set = nil
|
||||
}
|
||||
|
||||
// Populate inserts children into this OrderedChildren, and d's dentry
|
||||
@@ -549,6 +546,7 @@ func (InodeSymlink) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.D
|
||||
//
|
||||
// +stateify savable
|
||||
type StaticDirectory struct {
|
||||
StaticDirectoryRefs
|
||||
InodeNotSymlink
|
||||
InodeDirectoryNoNewChildren
|
||||
InodeAttrs
|
||||
@@ -594,11 +592,16 @@ func (s *StaticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd
|
||||
return fd.VFSFileDescription(), nil
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
// SetStat implements kernfs.Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*StaticDirectory) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (s *StaticDirectory) DecRef(context.Context) {
|
||||
s.StaticDirectoryRefs.DecRef(s.Destroy)
|
||||
}
|
||||
|
||||
// AlwaysValid partially implements kernfs.inodeDynamicLookup.
|
||||
type AlwaysValid struct{}
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
@@ -161,9 +160,9 @@ const (
|
||||
//
|
||||
// Must be initialized by Init prior to first use.
|
||||
type Dentry struct {
|
||||
vfsd vfs.Dentry
|
||||
DentryRefs
|
||||
|
||||
refs.AtomicRefCount
|
||||
vfsd vfs.Dentry
|
||||
|
||||
// flags caches useful information about the dentry from the inode. See the
|
||||
// dflags* consts above. Must be accessed by atomic ops.
|
||||
@@ -194,6 +193,7 @@ func (d *Dentry) Init(inode Inode) {
|
||||
if ftype == linux.ModeSymlink {
|
||||
d.flags |= dflagsIsSymlink
|
||||
}
|
||||
d.EnableLeakCheck()
|
||||
}
|
||||
|
||||
// VFSDentry returns the generic vfs dentry for this kernfs dentry.
|
||||
@@ -213,16 +213,14 @@ func (d *Dentry) isSymlink() bool {
|
||||
|
||||
// DecRef implements vfs.DentryImpl.DecRef.
|
||||
func (d *Dentry) DecRef(ctx context.Context) {
|
||||
d.AtomicRefCount.DecRefWithDestructor(ctx, d.destroy)
|
||||
}
|
||||
|
||||
// Precondition: Dentry must be removed from VFS' dentry cache.
|
||||
func (d *Dentry) destroy(ctx context.Context) {
|
||||
d.inode.DecRef(ctx) // IncRef from Init.
|
||||
d.inode = nil
|
||||
if d.parent != nil {
|
||||
d.parent.DecRef(ctx) // IncRef from Dentry.InsertChild.
|
||||
}
|
||||
// Before the destructor is called, Dentry must be removed from VFS' dentry cache.
|
||||
d.DentryRefs.DecRef(func() {
|
||||
d.inode.DecRef(ctx) // IncRef from Init.
|
||||
d.inode = nil
|
||||
if d.parent != nil {
|
||||
d.parent.DecRef(ctx) // IncRef from Dentry.InsertChild.
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// InotifyWithParent implements vfs.DentryImpl.InotifyWithParent.
|
||||
|
||||
@@ -96,6 +96,7 @@ func (*attrs) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.S
|
||||
}
|
||||
|
||||
type readonlyDir struct {
|
||||
readonlyDirRefs
|
||||
attrs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeNoDynamicLookup
|
||||
@@ -111,6 +112,7 @@ func (fs *filesystem) newReadonlyDir(creds *auth.Credentials, mode linux.FileMod
|
||||
dir := &readonlyDir{}
|
||||
dir.attrs.Init(creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), linux.ModeDirectory|mode)
|
||||
dir.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
dir.EnableLeakCheck()
|
||||
dir.dentry.Init(dir)
|
||||
|
||||
dir.IncLinks(dir.OrderedChildren.Populate(&dir.dentry, contents))
|
||||
@@ -128,7 +130,12 @@ func (d *readonlyDir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs
|
||||
return fd.VFSFileDescription(), nil
|
||||
}
|
||||
|
||||
func (d *readonlyDir) DecRef(context.Context) {
|
||||
d.readonlyDirRefs.DecRef(d.Destroy)
|
||||
}
|
||||
|
||||
type dir struct {
|
||||
dirRefs
|
||||
attrs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeNoDynamicLookup
|
||||
@@ -145,6 +152,7 @@ func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, conte
|
||||
dir.fs = fs
|
||||
dir.attrs.Init(creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), linux.ModeDirectory|mode)
|
||||
dir.OrderedChildren.Init(kernfs.OrderedChildrenOptions{Writable: true})
|
||||
dir.EnableLeakCheck()
|
||||
dir.dentry.Init(dir)
|
||||
|
||||
dir.IncLinks(dir.OrderedChildren.Populate(&dir.dentry, contents))
|
||||
@@ -162,6 +170,10 @@ func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry,
|
||||
return fd.VFSFileDescription(), nil
|
||||
}
|
||||
|
||||
func (d *dir) DecRef(context.Context) {
|
||||
d.dirRefs.DecRef(d.Destroy)
|
||||
}
|
||||
|
||||
func (d *dir) NewDir(ctx context.Context, name string, opts vfs.MkdirOptions) (*vfs.Dentry, error) {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
dir := d.fs.newDir(creds, opts.Mode, nil)
|
||||
|
||||
@@ -1,18 +1,79 @@
|
||||
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/refs_vfs2: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/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "fdInfoDirInode",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "subtasks_inode_refs",
|
||||
out = "subtasks_inode_refs.go",
|
||||
package = "proc",
|
||||
prefix = "subtasksInode",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "subtasksInode",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "task_inode_refs",
|
||||
out = "task_inode_refs.go",
|
||||
package = "proc",
|
||||
prefix = "taskInode",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "taskInode",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "tasks_inode_refs",
|
||||
out = "tasks_inode_refs.go",
|
||||
package = "proc",
|
||||
prefix = "tasksInode",
|
||||
template = "//pkg/refs_vfs2: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",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
//
|
||||
// +stateify savable
|
||||
type subtasksInode struct {
|
||||
subtasksInodeRefs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeDirectoryNoNewChildren
|
||||
kernfs.InodeAttrs
|
||||
@@ -57,6 +58,7 @@ func (fs *filesystem) newSubtasks(task *kernel.Task, pidns *kernel.PIDNamespace,
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
subInode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
subInode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
subInode.EnableLeakCheck()
|
||||
|
||||
inode := &taskOwnedInode{Inode: subInode, owner: task}
|
||||
dentry := &kernfs.Dentry{}
|
||||
@@ -182,3 +184,8 @@ func (i *subtasksInode) Stat(ctx context.Context, vsfs *vfs.Filesystem, opts vfs
|
||||
func (*subtasksInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *subtasksInode) DecRef(context.Context) {
|
||||
i.subtasksInodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
//
|
||||
// +stateify savable
|
||||
type taskInode struct {
|
||||
taskInodeRefs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeDirectoryNoNewChildren
|
||||
kernfs.InodeNoDynamicLookup
|
||||
@@ -84,6 +85,7 @@ func (fs *filesystem) newTaskInode(task *kernel.Task, pidns *kernel.PIDNamespace
|
||||
taskInode := &taskInode{task: task}
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
taskInode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
taskInode.EnableLeakCheck()
|
||||
|
||||
inode := &taskOwnedInode{Inode: taskInode, owner: task}
|
||||
dentry := &kernfs.Dentry{}
|
||||
@@ -119,6 +121,11 @@ func (*taskInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, v
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *taskInode) DecRef(context.Context) {
|
||||
i.taskInodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
// taskOwnedInode implements kernfs.Inode and overrides inode owner with task
|
||||
// effective user and group.
|
||||
type taskOwnedInode struct {
|
||||
@@ -147,6 +154,7 @@ func (fs *filesystem) newTaskOwnedDir(task *kernel.Task, ino uint64, perm linux.
|
||||
dir.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, perm, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
dir.EnableLeakCheck()
|
||||
|
||||
inode := &taskOwnedInode{Inode: dir, owner: task}
|
||||
d := &kernfs.Dentry{}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
@@ -101,6 +100,7 @@ func (i *fdDir) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, off
|
||||
//
|
||||
// +stateify savable
|
||||
type fdDirInode struct {
|
||||
fdDirInodeRefs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeDirectoryNoNewChildren
|
||||
kernfs.InodeAttrs
|
||||
@@ -120,6 +120,7 @@ func (fs *filesystem) newFDDirInode(task *kernel.Task) *kernfs.Dentry {
|
||||
},
|
||||
}
|
||||
inode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.EnableLeakCheck()
|
||||
|
||||
dentry := &kernfs.Dentry{}
|
||||
dentry.Init(inode)
|
||||
@@ -175,6 +176,11 @@ func (i *fdDirInode) CheckPermissions(ctx context.Context, creds *auth.Credentia
|
||||
return err
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *fdDirInode) DecRef(context.Context) {
|
||||
i.fdDirInodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
// fdSymlink is an symlink for the /proc/[pid]/fd/[fd] file.
|
||||
//
|
||||
// +stateify savable
|
||||
@@ -227,6 +233,7 @@ func (s *fdSymlink) Getlink(ctx context.Context, mnt *vfs.Mount) (vfs.VirtualDen
|
||||
//
|
||||
// +stateify savable
|
||||
type fdInfoDirInode struct {
|
||||
fdInfoDirInodeRefs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeDirectoryNoNewChildren
|
||||
kernfs.InodeAttrs
|
||||
@@ -245,6 +252,7 @@ func (fs *filesystem) newFDInfoDirInode(task *kernel.Task) *kernfs.Dentry {
|
||||
},
|
||||
}
|
||||
inode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.EnableLeakCheck()
|
||||
|
||||
dentry := &kernfs.Dentry{}
|
||||
dentry.Init(inode)
|
||||
@@ -282,12 +290,16 @@ func (i *fdInfoDirInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *
|
||||
return fd.VFSFileDescription(), nil
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *fdInfoDirInode) DecRef(context.Context) {
|
||||
i.fdInfoDirInodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
// fdInfoData implements vfs.DynamicBytesSource for /proc/[pid]/fdinfo/[fd].
|
||||
//
|
||||
// +stateify savable
|
||||
type fdInfoData struct {
|
||||
kernfs.DynamicBytesFile
|
||||
refs.AtomicRefCount
|
||||
|
||||
task *kernel.Task
|
||||
fd int32
|
||||
|
||||
@@ -262,7 +262,7 @@ func (n *netUnixData) Generate(ctx context.Context, buf *bytes.Buffer) error {
|
||||
// For now, we always redact this pointer.
|
||||
fmt.Fprintf(buf, "%#016p: %08X %08X %08X %04X %02X %8d",
|
||||
(*unix.SocketOperations)(nil), // Num, pointer to kernel socket struct.
|
||||
s.Refs()-1, // RefCount, don't count our own ref.
|
||||
s.ReadRefs()-1, // RefCount, don't count our own ref.
|
||||
0, // Protocol, always 0 for UDS.
|
||||
sockFlags, // Flags.
|
||||
sops.Endpoint().Type(), // Type.
|
||||
@@ -430,7 +430,7 @@ func commonGenerateTCP(ctx context.Context, buf *bytes.Buffer, k *kernel.Kernel,
|
||||
|
||||
// Field: refcount. Don't count the ref we obtain while deferencing
|
||||
// the weakref to this socket.
|
||||
fmt.Fprintf(buf, "%d ", s.Refs()-1)
|
||||
fmt.Fprintf(buf, "%d ", s.ReadRefs()-1)
|
||||
|
||||
// Field: Socket struct address. Redacted due to the same reason as
|
||||
// the 'Num' field in /proc/net/unix, see netUnix.ReadSeqFileData.
|
||||
@@ -589,7 +589,7 @@ func (d *netUDPData) Generate(ctx context.Context, buf *bytes.Buffer) error {
|
||||
|
||||
// Field: ref; reference count on the socket inode. Don't count the ref
|
||||
// we obtain while deferencing the weakref to this socket.
|
||||
fmt.Fprintf(buf, "%d ", s.Refs()-1)
|
||||
fmt.Fprintf(buf, "%d ", s.ReadRefs()-1)
|
||||
|
||||
// Field: Socket struct address. Redacted due to the same reason as
|
||||
// the 'Num' field in /proc/net/unix, see netUnix.ReadSeqFileData.
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
//
|
||||
// +stateify savable
|
||||
type tasksInode struct {
|
||||
tasksInodeRefs
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeDirectoryNoNewChildren
|
||||
kernfs.InodeAttrs
|
||||
@@ -84,6 +85,7 @@ func (fs *filesystem) newTasksInode(k *kernel.Kernel, pidns *kernel.PIDNamespace
|
||||
cgroupControllers: cgroupControllers,
|
||||
}
|
||||
inode.InodeAttrs.Init(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.EnableLeakCheck()
|
||||
|
||||
dentry := &kernfs.Dentry{}
|
||||
dentry.Init(inode)
|
||||
@@ -226,6 +228,11 @@ func (i *tasksInode) Stat(ctx context.Context, vsfs *vfs.Filesystem, opts vfs.St
|
||||
return stat, nil
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.
|
||||
func (i *tasksInode) DecRef(context.Context) {
|
||||
i.tasksInodeRefs.DecRef(i.Destroy)
|
||||
}
|
||||
|
||||
// staticFileSetStat implements a special static file that allows inode
|
||||
// attributes to be set. This is to support /proc files that are readonly, but
|
||||
// allow attributes to be set.
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
load("//tools/go_generics:defs.bzl", "go_template_instance")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
go_template_instance(
|
||||
name = "dir_refs",
|
||||
out = "dir_refs.go",
|
||||
package = "sys",
|
||||
prefix = "dir",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "dir",
|
||||
},
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "sys",
|
||||
srcs = [
|
||||
"dir_refs.go",
|
||||
"kcov.go",
|
||||
"sys.go",
|
||||
],
|
||||
@@ -13,6 +26,8 @@ go_library(
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/coverage",
|
||||
"//pkg/log",
|
||||
"//pkg/refs",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fsimpl/kernfs",
|
||||
"//pkg/sentry/kernel",
|
||||
|
||||
@@ -118,6 +118,7 @@ func (fs *filesystem) Release(ctx context.Context) {
|
||||
|
||||
// dir implements kernfs.Inode.
|
||||
type dir struct {
|
||||
dirRefs
|
||||
kernfs.InodeAttrs
|
||||
kernfs.InodeNoDynamicLookup
|
||||
kernfs.InodeNotSymlink
|
||||
@@ -133,6 +134,7 @@ func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, conte
|
||||
d := &dir{}
|
||||
d.InodeAttrs.Init(creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0755)
|
||||
d.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
d.EnableLeakCheck()
|
||||
d.dentry.Init(d)
|
||||
|
||||
d.IncLinks(d.OrderedChildren.Populate(&d.dentry, contents))
|
||||
@@ -140,7 +142,7 @@ func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, conte
|
||||
return &d.dentry
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
|
||||
// SetStat implements kernfs.Inode.SetStat not allowing inode attributes to be changed.
|
||||
func (*dir) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
@@ -156,6 +158,11 @@ func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry,
|
||||
return fd.VFSFileDescription(), nil
|
||||
}
|
||||
|
||||
// DecRef implements kernfs.Inode.DecRef.
|
||||
func (d *dir) DecRef(context.Context) {
|
||||
d.dirRefs.DecRef(d.Destroy)
|
||||
}
|
||||
|
||||
// cpuFile implements kernfs.Inode.
|
||||
type cpuFile struct {
|
||||
kernfs.DynamicBytesFile
|
||||
|
||||
@@ -74,6 +74,50 @@ go_template_instance(
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "fd_table_refs",
|
||||
out = "fd_table_refs.go",
|
||||
package = "kernel",
|
||||
prefix = "FDTable",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "FDTable",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "fs_context_refs",
|
||||
out = "fs_context_refs.go",
|
||||
package = "kernel",
|
||||
prefix = "FSContext",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "FSContext",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "process_group_refs",
|
||||
out = "process_group_refs.go",
|
||||
package = "kernel",
|
||||
prefix = "ProcessGroup",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "ProcessGroup",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "session_refs",
|
||||
out = "session_refs.go",
|
||||
package = "kernel",
|
||||
prefix = "Session",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "Session",
|
||||
},
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "uncaught_signal",
|
||||
srcs = ["uncaught_signal.proto"],
|
||||
@@ -88,8 +132,10 @@ go_library(
|
||||
"aio.go",
|
||||
"context.go",
|
||||
"fd_table.go",
|
||||
"fd_table_refs.go",
|
||||
"fd_table_unsafe.go",
|
||||
"fs_context.go",
|
||||
"fs_context_refs.go",
|
||||
"ipc_namespace.go",
|
||||
"kcov.go",
|
||||
"kcov_unsafe.go",
|
||||
@@ -101,6 +147,7 @@ go_library(
|
||||
"pending_signals_state.go",
|
||||
"posixtimer.go",
|
||||
"process_group_list.go",
|
||||
"process_group_refs.go",
|
||||
"ptrace.go",
|
||||
"ptrace_amd64.go",
|
||||
"ptrace_arm64.go",
|
||||
@@ -108,6 +155,7 @@ go_library(
|
||||
"seccomp.go",
|
||||
"seqatomic_taskgoroutineschedinfo_unsafe.go",
|
||||
"session_list.go",
|
||||
"session_refs.go",
|
||||
"sessions.go",
|
||||
"signal.go",
|
||||
"signal_handlers.go",
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/lock"
|
||||
"gvisor.dev/gvisor/pkg/sentry/limits"
|
||||
@@ -78,7 +77,8 @@ type descriptor struct {
|
||||
//
|
||||
// +stateify savable
|
||||
type FDTable struct {
|
||||
refs.AtomicRefCount
|
||||
FDTableRefs
|
||||
|
||||
k *Kernel
|
||||
|
||||
// mu protects below.
|
||||
@@ -176,16 +176,15 @@ func (k *Kernel) NewFDTable() *FDTable {
|
||||
return f
|
||||
}
|
||||
|
||||
// destroy removes all of the file descriptors from the map.
|
||||
func (f *FDTable) destroy(ctx context.Context) {
|
||||
f.RemoveIf(ctx, func(*fs.File, *vfs.FileDescription, FDFlags) bool {
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// DecRef implements RefCounter.DecRef with destructor f.destroy.
|
||||
// DecRef implements RefCounter.DecRef.
|
||||
//
|
||||
// If f reaches zero references, all of its file descriptors are removed.
|
||||
func (f *FDTable) DecRef(ctx context.Context) {
|
||||
f.DecRefWithDestructor(ctx, f.destroy)
|
||||
f.FDTableRefs.DecRef(func() {
|
||||
f.RemoveIf(ctx, func(*fs.File, *vfs.FileDescription, FDFlags) bool {
|
||||
return true
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Size returns the number of file descriptor slots currently allocated.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user