Inline vfs.VirtualFilesystem in Kernel struct
This saves one pointer dereference per VFS access. Updates #1623 PiperOrigin-RevId: 295216176
This commit is contained in:
parent
50c493193b
commit
e4c7f3e6f6
|
@ -199,7 +199,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
|
|||
}
|
||||
|
||||
paths := fs.GetPath(initArgs.Envv)
|
||||
vfsObj := proc.Kernel.VFS
|
||||
vfsObj := proc.Kernel.VFS()
|
||||
file, err := ResolveExecutablePath(ctx, vfsObj, initArgs.WorkingDirectory, initArgs.Argv[0], paths)
|
||||
if err != nil {
|
||||
return nil, 0, nil, fmt.Errorf("error finding executable %q in PATH %v: %v", initArgs.Argv[0], paths, err)
|
||||
|
|
|
@ -29,7 +29,10 @@ func TestDevtmpfs(t *testing.T) {
|
|||
ctx := contexttest.Context(t)
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := &vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
t.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
// Register tmpfs just so that we can have a root filesystem that isn't
|
||||
// devtmpfs.
|
||||
vfsObj.MustRegisterFilesystemType("tmpfs", tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
|
|
|
@ -52,7 +52,10 @@ func setUp(b *testing.B, imagePath string) (context.Context, *vfs.VirtualFilesys
|
|||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := &vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
vfsObj.MustRegisterFilesystemType("extfs", ext.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
|
|
@ -65,7 +65,10 @@ func setUp(t *testing.T, imagePath string) (context.Context, *vfs.VirtualFilesys
|
|||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := &vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
t.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
vfsObj.MustRegisterFilesystemType("extfs", FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
|
|
@ -45,7 +45,10 @@ type RootDentryFn func(*auth.Credentials, *filesystem) *kernfs.Dentry
|
|||
func newTestSystem(t *testing.T, rootFn RootDentryFn) *testutil.System {
|
||||
ctx := contexttest.Context(t)
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
v := vfs.New()
|
||||
v := &vfs.VirtualFilesystem{}
|
||||
if err := v.Init(); err != nil {
|
||||
t.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
v.MustRegisterFilesystemType("testfs", &fsType{rootFn: rootFn}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
|
|
@ -90,7 +90,7 @@ func setup(t *testing.T) *testutil.System {
|
|||
ctx := k.SupervisorContext()
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
k.VFS.MustRegisterFilesystemType(Name, &FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
k.VFS().MustRegisterFilesystemType(Name, &FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
fsOpts := vfs.GetFilesystemOptions{
|
||||
|
@ -101,11 +101,11 @@ func setup(t *testing.T) *testutil.System {
|
|||
},
|
||||
},
|
||||
}
|
||||
mntns, err := k.VFS.NewMountNamespace(ctx, creds, "", Name, &fsOpts)
|
||||
mntns, err := k.VFS().NewMountNamespace(ctx, creds, "", Name, &fsOpts)
|
||||
if err != nil {
|
||||
t.Fatalf("NewMountNamespace(): %v", err)
|
||||
}
|
||||
return testutil.NewSystem(ctx, t, k.VFS, mntns)
|
||||
return testutil.NewSystem(ctx, t, k.VFS(), mntns)
|
||||
}
|
||||
|
||||
func TestTasksEmpty(t *testing.T) {
|
||||
|
|
|
@ -34,15 +34,15 @@ func newTestSystem(t *testing.T) *testutil.System {
|
|||
}
|
||||
ctx := k.SupervisorContext()
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
k.VFS.MustRegisterFilesystemType(sys.Name, sys.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
k.VFS().MustRegisterFilesystemType(sys.Name, sys.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
||||
mns, err := k.VFS.NewMountNamespace(ctx, creds, "", sys.Name, &vfs.GetFilesystemOptions{})
|
||||
mns, err := k.VFS().NewMountNamespace(ctx, creds, "", sys.Name, &vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new mount namespace: %v", err)
|
||||
}
|
||||
return testutil.NewSystem(ctx, t, k.VFS, mns)
|
||||
return testutil.NewSystem(ctx, t, k.VFS(), mns)
|
||||
}
|
||||
|
||||
func TestReadCPUFile(t *testing.T) {
|
||||
|
|
|
@ -102,12 +102,13 @@ func Boot() (*kernel.Kernel, error) {
|
|||
|
||||
kernel.VFS2Enabled = true
|
||||
|
||||
vfsObj := vfs.New()
|
||||
vfsObj.MustRegisterFilesystemType(tmpfs.Name, &tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
if err := k.VFS().Init(); err != nil {
|
||||
return nil, fmt.Errorf("VFS init: %v", err)
|
||||
}
|
||||
k.VFS().MustRegisterFilesystemType(tmpfs.Name, &tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
AllowUserList: true,
|
||||
})
|
||||
k.VFS = vfsObj
|
||||
|
||||
ls, err := limits.NewLinuxLimitSet()
|
||||
if err != nil {
|
||||
|
|
|
@ -175,7 +175,10 @@ func BenchmarkVFS2MemfsStat(b *testing.B) {
|
|||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
b.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
vfsObj.MustRegisterFilesystemType("tmpfs", tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
@ -366,7 +369,10 @@ func BenchmarkVFS2MemfsMountStat(b *testing.B) {
|
|||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
b.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
vfsObj.MustRegisterFilesystemType("tmpfs", tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
|
|
@ -151,7 +151,10 @@ func setup(t *testing.T) (context.Context, *auth.Credentials, *vfs.VirtualFilesy
|
|||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
// Create VFS.
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := &vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
t.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
vfsObj.MustRegisterFilesystemType("tmpfs", FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
|
|
@ -40,7 +40,11 @@ var nextFileID int64
|
|||
func newTmpfsRoot(ctx context.Context) (*vfs.VirtualFilesystem, vfs.VirtualDentry, func(), error) {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
|
||||
vfsObj := vfs.New()
|
||||
vfsObj := &vfs.VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
return nil, vfs.VirtualDentry{}, nil, fmt.Errorf("VFS init: %v", err)
|
||||
}
|
||||
|
||||
vfsObj.MustRegisterFilesystemType("tmpfs", FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
|
||||
AllowUserMount: true,
|
||||
})
|
||||
|
|
|
@ -246,7 +246,7 @@ type Kernel struct {
|
|||
SpecialOpts
|
||||
|
||||
// VFS keeps the filesystem state used across the kernel.
|
||||
VFS *vfs.VirtualFilesystem
|
||||
vfs vfs.VirtualFilesystem
|
||||
}
|
||||
|
||||
// InitKernelArgs holds arguments to Init.
|
||||
|
@ -815,7 +815,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
|||
FollowFinalSymlink: true,
|
||||
}
|
||||
var err error
|
||||
wd, err = k.VFS.GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{
|
||||
wd, err = k.VFS().GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{
|
||||
CheckSearchable: true,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -1506,3 +1506,8 @@ func (k *Kernel) EmitUnimplementedEvent(ctx context.Context) {
|
|||
Registers: t.Arch().StateData().Proto(),
|
||||
})
|
||||
}
|
||||
|
||||
// VFS returns the virtual filesystem for the kernel.
|
||||
func (k *Kernel) VFS() *vfs.VirtualFilesystem {
|
||||
return &k.vfs
|
||||
}
|
||||
|
|
|
@ -71,6 +71,8 @@ import (
|
|||
// lifetime. Dentry reference counts only indicate the extent to which VFS
|
||||
// requires Dentries to exist; Filesystems may elect to cache or discard
|
||||
// Dentries with zero references.
|
||||
//
|
||||
// +stateify savable
|
||||
type Dentry struct {
|
||||
// parent is this Dentry's parent in this Filesystem. If this Dentry is
|
||||
// independent, parent is nil.
|
||||
|
@ -89,7 +91,7 @@ type Dentry struct {
|
|||
children map[string]*Dentry
|
||||
|
||||
// mu synchronizes disowning and mounting over this Dentry.
|
||||
mu sync.Mutex
|
||||
mu sync.Mutex `state:"nosave"`
|
||||
|
||||
// impl is the DentryImpl associated with this Dentry. impl is immutable.
|
||||
// This should be the last field in Dentry.
|
||||
|
|
|
@ -56,6 +56,7 @@ type Device interface {
|
|||
Open(ctx context.Context, mnt *Mount, d *Dentry, opts OpenOptions) (*FileDescription, error)
|
||||
}
|
||||
|
||||
// +stateify savable
|
||||
type registeredDevice struct {
|
||||
dev Device
|
||||
opts RegisterDeviceOptions
|
||||
|
@ -63,6 +64,8 @@ type registeredDevice struct {
|
|||
|
||||
// RegisterDeviceOptions contains options to
|
||||
// VirtualFilesystem.RegisterDevice().
|
||||
//
|
||||
// +stateify savable
|
||||
type RegisterDeviceOptions struct {
|
||||
// GroupName is the name shown for this device registration in
|
||||
// /proc/devices. If GroupName is empty, this registration will not be
|
||||
|
|
|
@ -107,7 +107,10 @@ func (fd *testFD) SetStat(ctx context.Context, opts SetStatOptions) error {
|
|||
func TestGenCountFD(t *testing.T) {
|
||||
ctx := contexttest.Context(t)
|
||||
|
||||
vfsObj := New() // vfs.New()
|
||||
vfsObj := &VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
t.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
fd := newTestFD(vfsObj, linux.O_RDWR, &genCount{})
|
||||
defer fd.DecRef()
|
||||
|
||||
|
@ -162,7 +165,10 @@ func TestGenCountFD(t *testing.T) {
|
|||
func TestWritable(t *testing.T) {
|
||||
ctx := contexttest.Context(t)
|
||||
|
||||
vfsObj := New() // vfs.New()
|
||||
vfsObj := &VirtualFilesystem{}
|
||||
if err := vfsObj.Init(); err != nil {
|
||||
t.Fatalf("VFS init: %v", err)
|
||||
}
|
||||
fd := newTestFD(vfsObj, linux.O_RDWR, &storeData{data: "init"})
|
||||
defer fd.DecRef()
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ import (
|
|||
// Filesystem methods require that a reference is held.
|
||||
//
|
||||
// Filesystem is analogous to Linux's struct super_block.
|
||||
//
|
||||
// +stateify savable
|
||||
type Filesystem struct {
|
||||
// refs is the reference count. refs is accessed using atomic memory
|
||||
// operations.
|
||||
|
|
|
@ -44,6 +44,7 @@ type GetFilesystemOptions struct {
|
|||
InternalData interface{}
|
||||
}
|
||||
|
||||
// +stateify savable
|
||||
type registeredFilesystemType struct {
|
||||
fsType FilesystemType
|
||||
opts RegisterFilesystemTypeOptions
|
||||
|
|
|
@ -38,6 +38,8 @@ import (
|
|||
//
|
||||
// Mount is analogous to Linux's struct mount. (gVisor does not distinguish
|
||||
// between struct mount and struct vfsmount.)
|
||||
//
|
||||
// +stateify savable
|
||||
type Mount struct {
|
||||
// vfs, fs, and root are immutable. References are held on fs and root.
|
||||
//
|
||||
|
@ -85,6 +87,8 @@ type Mount struct {
|
|||
// MountNamespace methods require that a reference is held.
|
||||
//
|
||||
// MountNamespace is analogous to Linux's struct mnt_namespace.
|
||||
//
|
||||
// +stateify savable
|
||||
type MountNamespace struct {
|
||||
// root is the MountNamespace's root mount. root is immutable.
|
||||
root *Mount
|
||||
|
|
|
@ -64,6 +64,8 @@ func (mnt *Mount) storeKey(vd VirtualDentry) {
|
|||
// (provided mutation is sufficiently uncommon).
|
||||
//
|
||||
// mountTable.Init() must be called on new mountTables before use.
|
||||
//
|
||||
// +stateify savable
|
||||
type mountTable struct {
|
||||
// mountTable is implemented as a seqcount-protected hash table that
|
||||
// resolves collisions with linear probing, featuring Robin Hood insertion
|
||||
|
@ -75,8 +77,8 @@ type mountTable struct {
|
|||
// intrinsics and inline assembly, limiting the performance of this
|
||||
// approach.)
|
||||
|
||||
seq sync.SeqCount
|
||||
seed uint32 // for hashing keys
|
||||
seq sync.SeqCount `state:"nosave"`
|
||||
seed uint32 // for hashing keys
|
||||
|
||||
// size holds both length (number of elements) and capacity (number of
|
||||
// slots): capacity is stored as its base-2 log (referred to as order) in
|
||||
|
@ -89,7 +91,7 @@ type mountTable struct {
|
|||
// length and cap in separate uint32s) for ~free.
|
||||
size uint64
|
||||
|
||||
slots unsafe.Pointer // []mountSlot; never nil after Init
|
||||
slots unsafe.Pointer `state:"nosave"` // []mountSlot; never nil after Init
|
||||
}
|
||||
|
||||
type mountSlot struct {
|
||||
|
|
|
@ -46,11 +46,13 @@ import (
|
|||
//
|
||||
// There is no analogue to the VirtualFilesystem type in Linux, as the
|
||||
// equivalent state in Linux is global.
|
||||
//
|
||||
// +stateify savable
|
||||
type VirtualFilesystem struct {
|
||||
// mountMu serializes mount mutations.
|
||||
//
|
||||
// mountMu is analogous to Linux's namespace_sem.
|
||||
mountMu sync.Mutex
|
||||
mountMu sync.Mutex `state:"nosave"`
|
||||
|
||||
// mounts maps (mount parent, mount point) pairs to mounts. (Since mounts
|
||||
// are uniquely namespaced, including mount parent in the key correctly
|
||||
|
@ -89,44 +91,42 @@ type VirtualFilesystem struct {
|
|||
|
||||
// devices contains all registered Devices. devices is protected by
|
||||
// devicesMu.
|
||||
devicesMu sync.RWMutex
|
||||
devicesMu sync.RWMutex `state:"nosave"`
|
||||
devices map[devTuple]*registeredDevice
|
||||
|
||||
// anonBlockDevMinor contains all allocated anonymous block device minor
|
||||
// numbers. anonBlockDevMinorNext is a lower bound for the smallest
|
||||
// unallocated anonymous block device number. anonBlockDevMinorNext and
|
||||
// anonBlockDevMinor are protected by anonBlockDevMinorMu.
|
||||
anonBlockDevMinorMu sync.Mutex
|
||||
anonBlockDevMinorMu sync.Mutex `state:"nosave"`
|
||||
anonBlockDevMinorNext uint32
|
||||
anonBlockDevMinor map[uint32]struct{}
|
||||
|
||||
// fsTypes contains all registered FilesystemTypes. fsTypes is protected by
|
||||
// fsTypesMu.
|
||||
fsTypesMu sync.RWMutex
|
||||
fsTypesMu sync.RWMutex `state:"nosave"`
|
||||
fsTypes map[string]*registeredFilesystemType
|
||||
|
||||
// filesystems contains all Filesystems. filesystems is protected by
|
||||
// filesystemsMu.
|
||||
filesystemsMu sync.Mutex
|
||||
filesystemsMu sync.Mutex `state:"nosave"`
|
||||
filesystems map[*Filesystem]struct{}
|
||||
}
|
||||
|
||||
// New returns a new VirtualFilesystem with no mounts or FilesystemTypes.
|
||||
func New() *VirtualFilesystem {
|
||||
vfs := &VirtualFilesystem{
|
||||
mountpoints: make(map[*Dentry]map[*Mount]struct{}),
|
||||
devices: make(map[devTuple]*registeredDevice),
|
||||
anonBlockDevMinorNext: 1,
|
||||
anonBlockDevMinor: make(map[uint32]struct{}),
|
||||
fsTypes: make(map[string]*registeredFilesystemType),
|
||||
filesystems: make(map[*Filesystem]struct{}),
|
||||
}
|
||||
// Init initializes a new VirtualFilesystem with no mounts or FilesystemTypes.
|
||||
func (vfs *VirtualFilesystem) Init() error {
|
||||
vfs.mountpoints = make(map[*Dentry]map[*Mount]struct{})
|
||||
vfs.devices = make(map[devTuple]*registeredDevice)
|
||||
vfs.anonBlockDevMinorNext = 1
|
||||
vfs.anonBlockDevMinor = make(map[uint32]struct{})
|
||||
vfs.fsTypes = make(map[string]*registeredFilesystemType)
|
||||
vfs.filesystems = make(map[*Filesystem]struct{})
|
||||
vfs.mounts.Init()
|
||||
|
||||
// Construct vfs.anonMount.
|
||||
anonfsDevMinor, err := vfs.GetAnonBlockDevMinor()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("VirtualFilesystem.GetAnonBlockDevMinor() failed during VirtualFilesystem construction: %v", err))
|
||||
return err
|
||||
}
|
||||
anonfs := anonFilesystem{
|
||||
devMinor: anonfsDevMinor,
|
||||
|
@ -137,8 +137,7 @@ func New() *VirtualFilesystem {
|
|||
fs: &anonfs.vfsfs,
|
||||
refs: 1,
|
||||
}
|
||||
|
||||
return vfs
|
||||
return nil
|
||||
}
|
||||
|
||||
// PathOperation specifies the path operated on by a VFS method.
|
||||
|
|
Loading…
Reference in New Issue