Move filesystem creation from GetFilesystem to RegistryImpl.

Move root dentry and filesystem creation from GetFilesystem to
NewRegistryImpl, create IPCNamespace.InitPosixQueues to create a new
mqueue filesystem for each ipc namespace, and update GetFilesystem to
retreive fs and root dentry from IPCNamespace and return them.

Updates #136
This commit is contained in:
Zyad A. Ali
2021-09-28 20:43:47 +02:00
parent bcef079ec2
commit 229c01552e
6 changed files with 96 additions and 27 deletions
+1
View File
@@ -31,6 +31,7 @@ go_library(
"//pkg/refsvfs2",
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/ipc",
"//pkg/sentry/kernel/mq",
"//pkg/sentry/vfs",
"//pkg/sync",
+46 -15
View File
@@ -24,6 +24,8 @@ import (
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/kernel/ipc"
"gvisor.dev/gvisor/pkg/sentry/kernel/mq"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
@@ -47,28 +49,32 @@ func (FilesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (ft 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()
if err != nil {
return nil, nil, err
// mqfs is initialized only once per ipc namespace. Each ipc namespace has
// a POSIX message registry with a root dentry, filesystem, and a
// disconnected mount. We want the fs to be consistent for all processes in
// the same ipc namespace, so instead of creating a new fs and root dentry,
// we retreive them using IPCNamespace.PosixQueues and use them.
i := ipcNamespaceFromContext(ctx)
if i == nil {
return nil, nil, fmt.Errorf("mqfs.FilesystemType.GetFilesystem: ipc namespace doesn't exist")
}
defer i.DecRef(ctx)
registry := i.PosixQueues()
if registry == nil {
return nil, nil, fmt.Errorf("mqfs.FilesystemType.GetFilesystem: ipc namespace doesn't have a POSIX registry")
}
impl := registry.Impl().(*RegistryImpl)
maxCachedDentries, err := maxCachedDentries(ctx, vfs.GenericParseMountOptions(opts.Data))
if err != nil {
return nil, nil, err
}
impl.fs.MaxCachedDentries = maxCachedDentries
fs := &filesystem{
devMinor: devMinor,
Filesystem: kernfs.Filesystem{
MaxCachedDentries: maxCachedDentries,
},
}
fs.VFSFilesystem().Init(vfsObj, &ft, fs)
var dentry kernfs.Dentry
dentry.InitRoot(&fs.Filesystem, fs.newRootInode(ctx, creds))
return fs.VFSFilesystem(), dentry.VFSDentry(), nil
impl.root.IncRef()
return impl.fs.VFSFilesystem(), impl.root.VFSDentry(), nil
}
// maxCachedDentries checks mopts for dentry_cache_limit. If a value is
@@ -93,15 +99,40 @@ func maxCachedDentries(ctx context.Context, mopts map[string]string) (_ uint64,
type filesystem struct {
kernfs.Filesystem
devMinor uint32
// root is the filesystem's root dentry. Since we take a reference on it in
// GetFilesystem, we should release it when the fs is released.
root *kernfs.Dentry
}
// Release implements vfs.FilesystemImpl.Release.
func (fs *filesystem) Release(ctx context.Context) {
fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor)
fs.Filesystem.Release(ctx)
fs.root.DecRef(ctx)
}
// MountOptions implements vfs.FilesystemImpl.MountOptions.
func (fs *filesystem) MountOptions() string {
return fmt.Sprintf("dentry_cache_limit=%d", fs.MaxCachedDentries)
}
// ipcNamespace defines functions we need from kernel.IPCNamespace. We redefine
// ipcNamespace along with ipcNamespaceFromContext to avoid circular dependency
// with package sentry/kernel.
type ipcNamespace interface {
// PosixQueues returns a POSIX message queue registry.
PosixQueues() *mq.Registry
// DecRef decrements ipcNamespace's number of references.
DecRef(ctx context.Context)
}
// ipcNamespaceFromContext returns the IPC namespace in which ctx is executing.
// Copied from package sentry/kernel.
func ipcNamespaceFromContext(ctx context.Context) ipcNamespace {
if v := ctx.Value(ipc.CtxIPCNamespace); v != nil {
return v.(ipcNamespace)
}
return nil
}
+27 -7
View File
@@ -50,12 +50,32 @@ type RegistryImpl struct {
// NewRegistryImpl returns a new, initialized RegistryImpl, and takes a
// reference on root.
func NewRegistryImpl(root *kernfs.Dentry, fs *filesystem) *RegistryImpl {
root.IncRef()
return &RegistryImpl{
root: root,
fs: fs,
func NewRegistryImpl(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) (*RegistryImpl, error) {
devMinor, err := vfsObj.GetAnonBlockDevMinor()
if err != nil {
return nil, err
}
var dentry kernfs.Dentry
fs := &filesystem{
devMinor: devMinor,
root: &dentry,
}
fs.VFSFilesystem().Init(vfsObj, &FilesystemType{}, fs)
dentry.InitRoot(&fs.Filesystem, fs.newRootInode(ctx, creds))
dentry.IncRef()
mount, err := vfsObj.NewDisconnectedMount(fs.VFSFilesystem(), dentry.VFSDentry(), &vfs.MountOptions{})
if err != nil {
return nil, err
}
return &RegistryImpl{
root: &dentry,
fs: fs,
mount: mount,
}, nil
}
// Lookup implements mq.RegistryImpl.Lookup.
@@ -83,11 +103,11 @@ func (r *RegistryImpl) New(ctx context.Context, name string, q *mq.Queue, perm l
}
fd := &queueFD{queue: q}
err = fd.Init(r.mount, r.root, qInode.data, &qInode.locks, 0 /* flags */)
err = fd.Init(r.mount, r.root, q, qInode.Locks(), 0 /* flags */)
if err != nil {
return nil, err
}
return fd.VFSFileDescription(), nil
return &fd.vfsfd, nil
}
// Unlink implements mq.RegistryImpl.Unlink.
+1
View File
@@ -249,6 +249,7 @@ go_library(
"//pkg/sentry/fs/timerfd",
"//pkg/sentry/fsbridge",
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/fsimpl/mqfs",
"//pkg/sentry/fsimpl/pipefs",
"//pkg/sentry/fsimpl/sockfs",
"//pkg/sentry/fsimpl/timerfd",
+16 -5
View File
@@ -15,12 +15,16 @@
package kernel
import (
"fmt"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/mqfs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/kernel/mq"
"gvisor.dev/gvisor/pkg/sentry/kernel/msgqueue"
"gvisor.dev/gvisor/pkg/sentry/kernel/semaphore"
"gvisor.dev/gvisor/pkg/sentry/kernel/shm"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
// IPCNamespace represents an IPC namespace.
@@ -72,12 +76,19 @@ func (i *IPCNamespace) ShmRegistry() *shm.Registry {
return i.shms
}
// SetPosixQueues sets value of posixQueues if the value is currently nil,
// otherwise returns without doing anything.
func (i *IPCNamespace) SetPosixQueues(r *mq.Registry) {
if i.posixQueues == nil {
i.posixQueues = r
// InitPosixQueues creates a new POSIX queue registry, and returns an error if
// the registry was previously initialized.
func (i *IPCNamespace) InitPosixQueues(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) error {
if i.posixQueues != nil {
return fmt.Errorf("IPCNamespace.InitPosixQueues: already initialized")
}
impl, err := mqfs.NewRegistryImpl(ctx, vfsObj, creds)
if err != nil {
return err
}
i.posixQueues = mq.NewRegistry(impl)
return nil
}
// PosixQueues returns the posix message queue registry for this namespace.
+5
View File
@@ -79,6 +79,11 @@ func (r *Registry) Destroy(ctx context.Context) {
r.impl.Destroy(ctx)
}
// Impl returns RegistryImpl inside r.
func (r *Registry) Impl() RegistryImpl {
return r.impl
}
// Queue represents a POSIX message queue.
//
// +stateify savable