mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add VFS2 support for /proc/filesystems.
Updates #1195 PiperOrigin-RevId: 287269106
This commit is contained in:
@@ -50,7 +50,9 @@ func setUp(b *testing.B, imagePath string) (context.Context, *vfs.VirtualFilesys
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("extfs", ext.FilesystemType{})
|
||||
vfsObj.MustRegisterFilesystemType("extfs", ext.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, imagePath, "extfs", &vfs.GetFilesystemOptions{InternalData: int(f.Fd())})
|
||||
if err != nil {
|
||||
f.Close()
|
||||
|
||||
@@ -66,7 +66,9 @@ func setUp(t *testing.T, imagePath string) (context.Context, *vfs.VirtualFilesys
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("extfs", FilesystemType{})
|
||||
vfsObj.MustRegisterFilesystemType("extfs", FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, localImagePath, "extfs", &vfs.GetFilesystemOptions{InternalData: int(f.Fd())})
|
||||
if err != nil {
|
||||
f.Close()
|
||||
|
||||
@@ -59,7 +59,9 @@ func newTestSystem(t *testing.T, rootFn RootDentryFn) *TestSystem {
|
||||
ctx := contexttest.Context(t)
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
v := vfs.New()
|
||||
v.MustRegisterFilesystemType("testfs", &fsType{rootFn: rootFn})
|
||||
v.MustRegisterFilesystemType("testfs", &fsType{rootFn: rootFn}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mns, err := v.NewMountNamespace(ctx, creds, "", "testfs", &vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create testfs root mount: %v", err)
|
||||
|
||||
@@ -176,7 +176,9 @@ func BenchmarkVFS2MemfsStat(b *testing.B) {
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("memfs", memfs.FilesystemType{})
|
||||
vfsObj.MustRegisterFilesystemType("memfs", memfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "memfs", &vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create tmpfs root mount: %v", err)
|
||||
@@ -365,7 +367,9 @@ func BenchmarkVFS2MemfsMountStat(b *testing.B) {
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("memfs", memfs.FilesystemType{})
|
||||
vfsObj.MustRegisterFilesystemType("memfs", memfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "memfs", &vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create tmpfs root mount: %v", err)
|
||||
|
||||
@@ -152,7 +152,9 @@ func setup(t *testing.T) (context.Context, *auth.Credentials, *vfs.VirtualFilesy
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("memfs", FilesystemType{})
|
||||
vfsObj.MustRegisterFilesystemType("memfs", FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "memfs", &vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tmpfs root mount: %v", err)
|
||||
|
||||
@@ -56,25 +56,25 @@ func checkDots(dirs []vfs.Dirent) ([]vfs.Dirent, error) {
|
||||
|
||||
func checkTasksStaticFiles(gots []vfs.Dirent) ([]vfs.Dirent, error) {
|
||||
wants := map[string]vfs.Dirent{
|
||||
"loadavg": vfs.Dirent{Type: linux.DT_REG},
|
||||
"meminfo": vfs.Dirent{Type: linux.DT_REG},
|
||||
"mounts": vfs.Dirent{Type: linux.DT_LNK},
|
||||
"self": vfs.Dirent{Type: linux.DT_LNK},
|
||||
"stat": vfs.Dirent{Type: linux.DT_REG},
|
||||
"thread-self": vfs.Dirent{Type: linux.DT_LNK},
|
||||
"version": vfs.Dirent{Type: linux.DT_REG},
|
||||
"loadavg": {Type: linux.DT_REG},
|
||||
"meminfo": {Type: linux.DT_REG},
|
||||
"mounts": {Type: linux.DT_LNK},
|
||||
"self": {Type: linux.DT_LNK},
|
||||
"stat": {Type: linux.DT_REG},
|
||||
"thread-self": {Type: linux.DT_LNK},
|
||||
"version": {Type: linux.DT_REG},
|
||||
}
|
||||
return checkFiles(gots, wants)
|
||||
}
|
||||
|
||||
func checkTaskStaticFiles(gots []vfs.Dirent) ([]vfs.Dirent, error) {
|
||||
wants := map[string]vfs.Dirent{
|
||||
"io": vfs.Dirent{Type: linux.DT_REG},
|
||||
"maps": vfs.Dirent{Type: linux.DT_REG},
|
||||
"smaps": vfs.Dirent{Type: linux.DT_REG},
|
||||
"stat": vfs.Dirent{Type: linux.DT_REG},
|
||||
"statm": vfs.Dirent{Type: linux.DT_REG},
|
||||
"status": vfs.Dirent{Type: linux.DT_REG},
|
||||
"io": {Type: linux.DT_REG},
|
||||
"maps": {Type: linux.DT_REG},
|
||||
"smaps": {Type: linux.DT_REG},
|
||||
"stat": {Type: linux.DT_REG},
|
||||
"statm": {Type: linux.DT_REG},
|
||||
"status": {Type: linux.DT_REG},
|
||||
}
|
||||
return checkFiles(gots, wants)
|
||||
}
|
||||
@@ -114,7 +114,9 @@ func setup() (context.Context, *vfs.VirtualFilesystem, vfs.VirtualDentry, error)
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("procfs", &procFSType{})
|
||||
vfsObj.MustRegisterFilesystemType("procfs", &procFSType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "procfs", &vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, vfs.VirtualDentry{}, fmt.Errorf("NewMountNamespace(): %v", err)
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestGenCountFD(t *testing.T) {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
vfsObj := New() // vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType("testfs", FDTestFilesystemType{})
|
||||
vfsObj.MustRegisterFilesystemType("testfs", FDTestFilesystemType{}, &RegisterFilesystemTypeOptions{})
|
||||
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "testfs", &GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create testfs root mount: %v", err)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package vfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
@@ -43,28 +44,70 @@ type GetFilesystemOptions struct {
|
||||
InternalData interface{}
|
||||
}
|
||||
|
||||
type registeredFilesystemType struct {
|
||||
fsType FilesystemType
|
||||
opts RegisterFilesystemTypeOptions
|
||||
}
|
||||
|
||||
// RegisterFilesystemTypeOptions contains options to
|
||||
// VirtualFilesystem.RegisterFilesystem().
|
||||
type RegisterFilesystemTypeOptions struct {
|
||||
// If AllowUserMount is true, allow calls to VirtualFilesystem.MountAt()
|
||||
// for which MountOptions.InternalMount == false to use this filesystem
|
||||
// type.
|
||||
AllowUserMount bool
|
||||
|
||||
// If AllowUserList is true, make this filesystem type visible in
|
||||
// /proc/filesystems.
|
||||
AllowUserList bool
|
||||
|
||||
// If RequiresDevice is true, indicate that mounting this filesystem
|
||||
// requires a block device as the mount source in /proc/filesystems.
|
||||
RequiresDevice bool
|
||||
}
|
||||
|
||||
// RegisterFilesystemType registers the given FilesystemType in vfs with the
|
||||
// given name.
|
||||
func (vfs *VirtualFilesystem) RegisterFilesystemType(name string, fsType FilesystemType) error {
|
||||
func (vfs *VirtualFilesystem) RegisterFilesystemType(name string, fsType FilesystemType, opts *RegisterFilesystemTypeOptions) error {
|
||||
vfs.fsTypesMu.Lock()
|
||||
defer vfs.fsTypesMu.Unlock()
|
||||
if existing, ok := vfs.fsTypes[name]; ok {
|
||||
return fmt.Errorf("name %q is already registered to filesystem type %T", name, existing)
|
||||
return fmt.Errorf("name %q is already registered to filesystem type %T", name, existing.fsType)
|
||||
}
|
||||
vfs.fsTypes[name] = ®isteredFilesystemType{
|
||||
fsType: fsType,
|
||||
opts: *opts,
|
||||
}
|
||||
vfs.fsTypes[name] = fsType
|
||||
return nil
|
||||
}
|
||||
|
||||
// MustRegisterFilesystemType is equivalent to RegisterFilesystemType but
|
||||
// panics on failure.
|
||||
func (vfs *VirtualFilesystem) MustRegisterFilesystemType(name string, fsType FilesystemType) {
|
||||
if err := vfs.RegisterFilesystemType(name, fsType); err != nil {
|
||||
func (vfs *VirtualFilesystem) MustRegisterFilesystemType(name string, fsType FilesystemType, opts *RegisterFilesystemTypeOptions) {
|
||||
if err := vfs.RegisterFilesystemType(name, fsType, opts); err != nil {
|
||||
panic(fmt.Sprintf("failed to register filesystem type %T: %v", fsType, err))
|
||||
}
|
||||
}
|
||||
|
||||
func (vfs *VirtualFilesystem) getFilesystemType(name string) FilesystemType {
|
||||
func (vfs *VirtualFilesystem) getFilesystemType(name string) *registeredFilesystemType {
|
||||
vfs.fsTypesMu.RLock()
|
||||
defer vfs.fsTypesMu.RUnlock()
|
||||
return vfs.fsTypes[name]
|
||||
}
|
||||
|
||||
// GenerateProcFilesystems emits the contents of /proc/filesystems for vfs to
|
||||
// buf.
|
||||
func (vfs *VirtualFilesystem) GenerateProcFilesystems(buf *bytes.Buffer) {
|
||||
vfs.fsTypesMu.RLock()
|
||||
defer vfs.fsTypesMu.RUnlock()
|
||||
for name, rft := range vfs.fsTypes {
|
||||
if !rft.opts.AllowUserList {
|
||||
continue
|
||||
}
|
||||
var nodev string
|
||||
if !rft.opts.RequiresDevice {
|
||||
nodev = "nodev"
|
||||
}
|
||||
fmt.Fprintf(buf, "%s\t%s\n", nodev, name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ type MountNamespace struct {
|
||||
// configured by the given arguments. A reference is taken on the returned
|
||||
// MountNamespace.
|
||||
func (vfs *VirtualFilesystem) NewMountNamespace(ctx context.Context, creds *auth.Credentials, source, fsTypeName string, opts *GetFilesystemOptions) (*MountNamespace, error) {
|
||||
fsType := vfs.getFilesystemType(fsTypeName)
|
||||
if fsType == nil {
|
||||
rft := vfs.getFilesystemType(fsTypeName)
|
||||
if rft == nil {
|
||||
return nil, syserror.ENODEV
|
||||
}
|
||||
fs, root, err := fsType.GetFilesystem(ctx, vfs, creds, source, *opts)
|
||||
fs, root, err := rft.fsType.GetFilesystem(ctx, vfs, creds, source, *opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -136,11 +136,14 @@ func (vfs *VirtualFilesystem) NewMountNamespace(ctx context.Context, creds *auth
|
||||
|
||||
// MountAt creates and mounts a Filesystem configured by the given arguments.
|
||||
func (vfs *VirtualFilesystem) MountAt(ctx context.Context, creds *auth.Credentials, source string, target *PathOperation, fsTypeName string, opts *MountOptions) error {
|
||||
fsType := vfs.getFilesystemType(fsTypeName)
|
||||
if fsType == nil {
|
||||
rft := vfs.getFilesystemType(fsTypeName)
|
||||
if rft == nil {
|
||||
return syserror.ENODEV
|
||||
}
|
||||
fs, root, err := fsType.GetFilesystem(ctx, vfs, creds, source, opts.GetFilesystemOptions)
|
||||
if !opts.InternalMount && !rft.opts.AllowUserMount {
|
||||
return syserror.ENODEV
|
||||
}
|
||||
fs, root, err := rft.fsType.GetFilesystem(ctx, vfs, creds, source, opts.GetFilesystemOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ type MknodOptions struct {
|
||||
type MountOptions struct {
|
||||
// GetFilesystemOptions contains options to FilesystemType.GetFilesystem().
|
||||
GetFilesystemOptions GetFilesystemOptions
|
||||
|
||||
// If InternalMount is true, allow the use of filesystem types for which
|
||||
// RegisterFilesystemTypeOptions.AllowUserMount == false.
|
||||
InternalMount bool
|
||||
}
|
||||
|
||||
// OpenOptions contains options to VirtualFilesystem.OpenAt() and
|
||||
|
||||
@@ -75,23 +75,23 @@ type VirtualFilesystem struct {
|
||||
// mountpoints is analogous to Linux's mountpoint_hashtable.
|
||||
mountpoints map[*Dentry]map[*Mount]struct{}
|
||||
|
||||
// fsTypes contains all registered FilesystemTypes. fsTypes is protected by
|
||||
// fsTypesMu.
|
||||
fsTypesMu sync.RWMutex
|
||||
fsTypes map[string]*registeredFilesystemType
|
||||
|
||||
// filesystems contains all Filesystems. filesystems is protected by
|
||||
// filesystemsMu.
|
||||
filesystemsMu sync.Mutex
|
||||
filesystems map[*Filesystem]struct{}
|
||||
|
||||
// fsTypes contains all FilesystemTypes that are usable in the
|
||||
// VirtualFilesystem. fsTypes is protected by fsTypesMu.
|
||||
fsTypesMu sync.RWMutex
|
||||
fsTypes map[string]FilesystemType
|
||||
}
|
||||
|
||||
// New returns a new VirtualFilesystem with no mounts or FilesystemTypes.
|
||||
func New() *VirtualFilesystem {
|
||||
vfs := &VirtualFilesystem{
|
||||
mountpoints: make(map[*Dentry]map[*Mount]struct{}),
|
||||
fsTypes: make(map[string]*registeredFilesystemType),
|
||||
filesystems: make(map[*Filesystem]struct{}),
|
||||
fsTypes: make(map[string]FilesystemType),
|
||||
}
|
||||
vfs.mounts.Init()
|
||||
return vfs
|
||||
|
||||
Reference in New Issue
Block a user