mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
[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:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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().
|
||||
//
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user