diff options
Diffstat (limited to 'pkg/sentry/fsimpl/mqfs/mqfs.go')
-rw-r--r-- | pkg/sentry/fsimpl/mqfs/mqfs.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/pkg/sentry/fsimpl/mqfs/mqfs.go b/pkg/sentry/fsimpl/mqfs/mqfs.go new file mode 100644 index 000000000..c2b53c9d0 --- /dev/null +++ b/pkg/sentry/fsimpl/mqfs/mqfs.go @@ -0,0 +1,138 @@ +// 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 provides a filesystem implementation to back POSIX message +// queues. +package mqfs + +import ( + "fmt" + "strconv" + + "gvisor.dev/gvisor/pkg/context" + "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" +) + +const ( + // Name is the user-visible filesystem name. + Name = "mqueue" + defaultMaxCachedDentries = uint64(1000) +) + +// FilesystemType implements vfs.FilesystemType. +// +// +stateify savable +type FilesystemType struct{} + +// Name implements vfs.FilesystemType.Name. +func (FilesystemType) Name() string { + return Name +} + +// Release implements vfs.FilesystemType.Release. +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) { + // 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 + + impl.fs.VFSFilesystem().IncRef() + return impl.fs.VFSFilesystem(), impl.root.VFSDentry(), nil +} + +// maxCachedDentries checks mopts for dentry_cache_limit. If a value is +// specified, parse it into uint64 and return it. Otherwise, return the default +// value. An error is returned if a value is found but can't be parsed. +func maxCachedDentries(ctx context.Context, mopts map[string]string) (_ uint64, err error) { + max := defaultMaxCachedDentries + if str, ok := mopts["dentry_cache_limit"]; ok { + delete(mopts, "dentry_cache_limit") + max, err = strconv.ParseUint(str, 10, 64) + if err != nil { + ctx.Warningf("mqfs.FilesystemType.GetFilesystem: invalid dentry cache limit: dentry_cache_limit=%s", str) + return 0, linuxerr.EINVAL + } + } + return max, nil +} + +// filesystem implements kernfs.Filesystem. +// +// +stateify savable +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) +} + +// 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 +} |