mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Create mq.Registry and mqfs.RegistryImpl.
Define a POSIX message queue Registry and RegistryImpl in mq package, implement RegistryImpl in mqfs, and add a Registry object to IPCNamespace initialized at filesystem creation. Updates #136
This commit is contained in:
@@ -20,6 +20,7 @@ go_library(
|
||||
"mqfs.go",
|
||||
"root.go",
|
||||
"queue.go",
|
||||
"registry.go",
|
||||
"root_inode_refs.go",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
@@ -32,6 +33,7 @@ go_library(
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/mq",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sync",
|
||||
"//pkg/usermem",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
fsName = "mqueue"
|
||||
Name = "mqueue"
|
||||
defaultMaxCachedDentries = uint64(1000)
|
||||
)
|
||||
|
||||
@@ -39,7 +39,7 @@ type FilesystemType struct{}
|
||||
|
||||
// Name implements vfs.FilesystemType.Name.
|
||||
func (FilesystemType) Name() string {
|
||||
return fsName
|
||||
return Name
|
||||
}
|
||||
|
||||
// Release implements vfs.FilesystemType.Release.
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mqfs
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/mq"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
)
|
||||
|
||||
// RegistryImpl implements mq.RegistryImpl. It implements the interface using
|
||||
// the message queue filesystem, and is provided to mq.Registry at
|
||||
// initialization.
|
||||
//
|
||||
// +stateify savable
|
||||
type RegistryImpl struct {
|
||||
// mu protects all fields below.
|
||||
mu sync.Mutex
|
||||
|
||||
// root is the root dentry of the mq filesystem. Its main usage is to
|
||||
// retreive the root inode, which we use to add, remove, and lookup message
|
||||
// queues.
|
||||
//
|
||||
// We hold a reference on root and release when the registry is destroyed.
|
||||
root *kernfs.Dentry
|
||||
|
||||
// fs is the filesystem backing this registry, used mainly to initialize
|
||||
// new inodes.
|
||||
fs *filesystem
|
||||
|
||||
// mount is the mount point used for this filesystem.
|
||||
mount *vfs.Mount
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup implements mq.RegistryImpl.Lookup.
|
||||
func (r *RegistryImpl) Lookup(ctx context.Context, name string) *mq.Queue {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
inode, err := r.lookup(ctx, name)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return inode.(*queueInode).queue
|
||||
}
|
||||
|
||||
// New implements mq.RegistryImpl.New.
|
||||
func (r *RegistryImpl) New(ctx context.Context, name string, q *mq.Queue, perm linux.FileMode) (*vfs.FileDescription, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
root := r.root.Inode().(*rootInode)
|
||||
qInode := r.fs.newQueueInode(ctx, auth.CredentialsFromContext(ctx), q, perm).(*queueInode)
|
||||
err := root.Insert(name, qInode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd := &queueFD{queue: q}
|
||||
err = fd.Init(r.mount, r.root, qInode.data, &qInode.locks, 0 /* flags */)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fd.VFSFileDescription(), nil
|
||||
}
|
||||
|
||||
// Unlink implements mq.RegistryImpl.Unlink.
|
||||
func (r *RegistryImpl) Unlink(ctx context.Context, name string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
root := r.root.Inode().(*rootInode)
|
||||
inode, err := r.lookup(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return root.Unlink(ctx, name, inode)
|
||||
}
|
||||
|
||||
// lookup retreives a kernfs.Inode using a name.
|
||||
//
|
||||
// Precondition: r.mu must be held.
|
||||
func (r *RegistryImpl) lookup(ctx context.Context, name string) (kernfs.Inode, error) {
|
||||
inode := r.root.Inode().(*rootInode)
|
||||
lookup, err := inode.Lookup(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lookup, nil
|
||||
}
|
||||
|
||||
// Destroy implements mq.RegistryImpl.Destroy.
|
||||
func (r *RegistryImpl) Destroy(ctx context.Context) {
|
||||
r.root.DecRef(ctx)
|
||||
}
|
||||
@@ -257,6 +257,7 @@ go_library(
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/epoll",
|
||||
"//pkg/sentry/kernel/futex",
|
||||
"//pkg/sentry/kernel/mq",
|
||||
"//pkg/sentry/kernel/msgqueue",
|
||||
"//pkg/sentry/kernel/sched",
|
||||
"//pkg/sentry/kernel/semaphore",
|
||||
|
||||
@@ -17,6 +17,7 @@ package kernel
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"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"
|
||||
@@ -31,9 +32,17 @@ type IPCNamespace struct {
|
||||
// User namespace which owns this IPC namespace. Immutable.
|
||||
userNS *auth.UserNamespace
|
||||
|
||||
// System V utilities.
|
||||
queues *msgqueue.Registry
|
||||
semaphores *semaphore.Registry
|
||||
shms *shm.Registry
|
||||
|
||||
// posixQueues is a POSIX message queue registry.
|
||||
//
|
||||
// posixQueues is somewhat equivelant to Linux's ipc_namespace.mq_mnt.
|
||||
// Unlike SysV utilities, mq.Registry is not map-based, but is backed by
|
||||
// a virtual filesystem.
|
||||
posixQueues *mq.Registry
|
||||
}
|
||||
|
||||
// NewIPCNamespace creates a new IPC namespace.
|
||||
@@ -63,10 +72,26 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
// PosixQueues returns the posix message queue registry for this namespace.
|
||||
func (i *IPCNamespace) PosixQueues() *mq.Registry {
|
||||
return i.posixQueues
|
||||
}
|
||||
|
||||
// DecRef implements refsvfs2.RefCounter.DecRef.
|
||||
func (i *IPCNamespace) DecRef(ctx context.Context) {
|
||||
i.IPCNamespaceRefs.DecRef(func() {
|
||||
i.shms.Release(ctx)
|
||||
if i.posixQueues != nil {
|
||||
i.posixQueues.Destroy(ctx)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ go_library(
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sync",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
@@ -30,6 +31,54 @@ const (
|
||||
maxPriority = linux.MQ_PRIO_MAX - 1 // Highest possible message priority.
|
||||
)
|
||||
|
||||
// Registry is a POSIX message queue registry.
|
||||
//
|
||||
// Unlike SysV utilities, Registry is not map-based. It uses a provided
|
||||
// RegistryImpl backed by a virtual filesystem to implement registry operations.
|
||||
//
|
||||
// +stateify savable
|
||||
type Registry struct {
|
||||
// impl is an implementation of several message queue utilities needed by
|
||||
// the registry. impl should be provided by mqfs.
|
||||
impl RegistryImpl
|
||||
}
|
||||
|
||||
// RegistryImpl defines utilities needed by a Registry to provide actual
|
||||
// registry implementation. It works mainly as an abstraction layer used by
|
||||
// Registry to avoid dealing directly with the filesystem. RegistryImpl should
|
||||
// be implemented by mqfs and provided to Registry at initialization.
|
||||
type RegistryImpl interface {
|
||||
// Lookup returns the queue with the given name, nil if non exists.
|
||||
Lookup(context.Context, string) *Queue
|
||||
|
||||
// New creates a new inode and file description using the given queue,
|
||||
// inserts the inode into the filesystem tree with the given name, and
|
||||
// returns the file description. An error is returned if creation fails, or
|
||||
// if the name already exists.
|
||||
New(context.Context, string, *Queue, linux.FileMode) (*vfs.FileDescription, error)
|
||||
|
||||
// Unlink removes the queue with given name from the registry, and returns
|
||||
// an error if the name doesn't exist.
|
||||
Unlink(context.Context, string) error
|
||||
|
||||
// Destroy destroys the registry.
|
||||
Destroy(context.Context)
|
||||
}
|
||||
|
||||
// NewRegistry returns a new, initialized message queue registry. NewRegistry
|
||||
// should be called when a new message queue filesystem is created, once per
|
||||
// IPCNamespace.
|
||||
func NewRegistry(impl RegistryImpl) *Registry {
|
||||
return &Registry{
|
||||
impl: impl,
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy destroys the registry and releases all held references.
|
||||
func (r *Registry) Destroy(ctx context.Context) {
|
||||
r.impl.Destroy(ctx)
|
||||
}
|
||||
|
||||
// Queue represents a POSIX message queue.
|
||||
//
|
||||
// +stateify savable
|
||||
@@ -103,7 +152,7 @@ type Subscriber struct {
|
||||
}
|
||||
|
||||
// Generate implements vfs.DynamicBytesSource.Generate. Queue is used as a
|
||||
// dynamic bytes source for mqfs's queueInode.
|
||||
// DynamicBytesSource for mqfs's queueInode.
|
||||
func (q *Queue) Generate(ctx context.Context, buf *bytes.Buffer) error {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user