[vfs2] Add FilesystemType.Release to avoid reference leaks.

Singleton filesystem like devpts and devtmpfs have a single filesystem shared
among all mounts, so they acquire a "self-reference" when initialized that
must be released when the entire virtual filesystem is released at sandbox
exit.

PiperOrigin-RevId: 336828852
This commit is contained in:
Dean Deng
2020-10-13 01:13:22 -07:00
committed by gVisor bot
parent fc7df53222
commit 577c82f22c
18 changed files with 96 additions and 23 deletions
+1
View File
@@ -35,6 +35,7 @@ go_library(
"//pkg/refs",
"//pkg/safemem",
"//pkg/sentry/arch",
"//pkg/sentry/fs",
"//pkg/sentry/fs/lock",
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/kernel",
+34 -10
View File
@@ -37,27 +37,51 @@ const Name = "devpts"
// FilesystemType implements vfs.FilesystemType.
//
// +stateify savable
type FilesystemType struct{}
type FilesystemType struct {
initOnce sync.Once `state:"nosave"` // FIXME(gvisor.dev/issue/1663): not yet supported.
initErr error
// fs backs all mounts of this FilesystemType. root is fs' root. fs and root
// are immutable.
fs *vfs.Filesystem
root *vfs.Dentry
}
// Name implements vfs.FilesystemType.Name.
func (FilesystemType) Name() string {
func (*FilesystemType) Name() string {
return Name
}
var _ vfs.FilesystemType = (*FilesystemType)(nil)
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
func (fstype *FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
// No data allowed.
if opts.Data != "" {
return nil, nil, syserror.EINVAL
}
fs, root, err := fstype.newFilesystem(vfsObj, creds)
if err != nil {
return nil, nil, err
fstype.initOnce.Do(func() {
fs, root, err := fstype.newFilesystem(vfsObj, creds)
if err != nil {
fstype.initErr = err
return
}
fstype.fs = fs.VFSFilesystem()
fstype.root = root.VFSDentry()
})
if fstype.initErr != nil {
return nil, nil, fstype.initErr
}
fstype.fs.IncRef()
fstype.root.IncRef()
return fstype.fs, fstype.root, nil
}
// Release implements vfs.FilesystemType.Release.
func (fstype *FilesystemType) Release(ctx context.Context) {
if fstype.fs != nil {
fstype.root.DecRef(ctx)
fstype.fs.DecRef(ctx)
}
return fs.Filesystem.VFSFilesystem(), root.VFSDentry(), nil
}
// +stateify savable
@@ -69,7 +93,7 @@ type filesystem struct {
// newFilesystem creates a new devpts filesystem with root directory and ptmx
// master inode. It returns the filesystem and root Dentry.
func (fstype FilesystemType) newFilesystem(vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) (*filesystem, *kernfs.Dentry, error) {
func (fstype *FilesystemType) newFilesystem(vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) (*filesystem, *kernfs.Dentry, error) {
devMinor, err := vfsObj.GetAnonBlockDevMinor()
if err != nil {
return nil, nil, err
+9
View File
@@ -71,6 +71,15 @@ func (fst *FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virtua
return fst.fs, fst.root, nil
}
// Release implements vfs.FilesystemType.Release.
func (fst *FilesystemType) Release(ctx context.Context) {
if fst.fs != nil {
// Release the original reference obtained when creating the filesystem.
fst.root.DecRef(ctx)
fst.fs.DecRef(ctx)
}
}
// Accessor allows devices to create device special files in devtmpfs.
type Accessor struct {
vfsObj *vfs.VirtualFilesystem
+3 -3
View File
@@ -38,9 +38,6 @@ const Name = "ext"
// +stateify savable
type FilesystemType struct{}
// Compiles only if FilesystemType implements vfs.FilesystemType.
var _ vfs.FilesystemType = (*FilesystemType)(nil)
// getDeviceFd returns an io.ReaderAt to the underlying device.
// Currently there are two ways of mounting an ext(2/3/4) fs:
// 1. Specify a mount with our internal special MountType in the OCI spec.
@@ -101,6 +98,9 @@ func (FilesystemType) Name() string {
return Name
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
// TODO(b/134676337): Ensure that the user is mounting readonly. If not,
+3
View File
@@ -98,6 +98,9 @@ func (FilesystemType) Name() string {
return Name
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
devMinor, err := vfsObj.GetAnonBlockDevMinor()
+3
View File
@@ -272,6 +272,9 @@ func (FilesystemType) Name() string {
return Name
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
mfp := pgalloc.MemoryFileProviderFromContext(ctx)
+3
View File
@@ -151,6 +151,9 @@ func (filesystemType) Name() string {
return "none"
}
// Release implements vfs.FilesystemType.Release.
func (filesystemType) Release(ctx context.Context) {}
// NewFilesystem sets up and returns a new hostfs filesystem.
//
// Note that there should only ever be one instance of host.filesystem,
+2
View File
@@ -204,6 +204,8 @@ func (fsType) Name() string {
return "kernfs"
}
func (fsType) Release(ctx context.Context) {}
func (fst fsType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opt vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
fs := &filesystem{}
fs.VFSFilesystem().Init(vfsObj, &fst, fs)
+3
View File
@@ -60,6 +60,9 @@ func (FilesystemType) Name() string {
return Name
}
// Release implements FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// FilesystemOptions may be passed as vfs.GetFilesystemOptions.InternalData to
// FilesystemType.GetFilesystem.
//
+3
View File
@@ -39,6 +39,9 @@ func (filesystemType) Name() string {
return "pipefs"
}
// Release implements vfs.FilesystemType.Release.
func (filesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (filesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
panic("pipefs.filesystemType.GetFilesystem should never be called")
+3 -2
View File
@@ -34,13 +34,14 @@ const Name = "proc"
// +stateify savable
type FilesystemType struct{}
var _ vfs.FilesystemType = (*FilesystemType)(nil)
// Name implements vfs.FilesystemType.Name.
func (FilesystemType) Name() string {
return Name
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// +stateify savable
type filesystem struct {
kernfs.Filesystem
+3
View File
@@ -46,6 +46,9 @@ func (filesystemType) Name() string {
return "sockfs"
}
// Release implements vfs.FilesystemType.Release.
func (filesystemType) Release(ctx context.Context) {}
// +stateify savable
type filesystem struct {
kernfs.Filesystem
+3
View File
@@ -52,6 +52,9 @@ func (FilesystemType) Name() string {
return Name
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
devMinor, err := vfsObj.GetAnonBlockDevMinor()
+3
View File
@@ -81,6 +81,9 @@ func (FilesystemType) Name() string {
return Name
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// FilesystemOpts is used to pass configuration data to tmpfs.
//
// +stateify savable
+3
View File
@@ -156,6 +156,9 @@ func isEnabled(d *dentry) bool {
return !d.fs.allowRuntimeEnable || len(d.hash) != 0
}
// Release implements vfs.FilesystemType.Release.
func (FilesystemType) Release(ctx context.Context) {}
// alertIntegrityViolation alerts a violation of integrity, which usually means
// unexpected modification to the file system is detected. In
// noCrashOnVerificationFailure mode, it returns an error, otherwise it panic.
+4 -1
View File
@@ -61,11 +61,14 @@ func (anonFilesystemType) GetFilesystem(context.Context, *VirtualFilesystem, *au
panic("cannot instaniate an anon filesystem")
}
// Name implemenents FilesystemType.Name.
// Name implements FilesystemType.Name.
func (anonFilesystemType) Name() string {
return "none"
}
// Release implemenents FilesystemType.Release.
func (anonFilesystemType) Release(ctx context.Context) {}
// anonFilesystem is the implementation of FilesystemImpl that backs
// VirtualDentries returned by VirtualFilesystem.NewAnonVirtualDentry().
//
+3
View File
@@ -33,6 +33,9 @@ type FilesystemType interface {
// Name returns the name of this FilesystemType.
Name() string
// Release releases all resources held by this FilesystemType.
Release(ctx context.Context)
}
// GetFilesystemOptions contains options to FilesystemType.GetFilesystem.
+10 -7
View File
@@ -122,13 +122,6 @@ type VirtualFilesystem struct {
filesystems map[*Filesystem]struct{}
}
// Release drops references on filesystem objects held by vfs.
//
// Precondition: This must be called after VFS.Init() has succeeded.
func (vfs *VirtualFilesystem) Release(ctx context.Context) {
vfs.anonMount.DecRef(ctx)
}
// Init initializes a new VirtualFilesystem with no mounts or FilesystemTypes.
func (vfs *VirtualFilesystem) Init(ctx context.Context) error {
if vfs.mountpoints != nil {
@@ -165,6 +158,16 @@ func (vfs *VirtualFilesystem) Init(ctx context.Context) error {
return nil
}
// Release drops references on filesystem objects held by vfs.
//
// Precondition: This must be called after VFS.Init() has succeeded.
func (vfs *VirtualFilesystem) Release(ctx context.Context) {
vfs.anonMount.DecRef(ctx)
for _, fst := range vfs.fsTypes {
fst.fsType.Release(ctx)
}
}
// PathOperation specifies the path operated on by a VFS method.
//
// PathOperation is passed to VFS methods by pointer to reduce memory copying: