Add support for sentry internal pipe for gofer mounts

Internal pipes are supported similarly to how internal UDS is done.
It is also controlled by the same flag.

Fixes #1102

PiperOrigin-RevId: 293150045
This commit is contained in:
Fabricio Voznika
2020-02-04 08:20:52 -08:00
committed by gVisor bot
parent f37e913a35
commit d7cd484091
9 changed files with 298 additions and 146 deletions
+2
View File
@@ -9,6 +9,7 @@ go_library(
"cache_policy.go",
"context_file.go",
"device.go",
"fifo.go",
"file.go",
"file_state.go",
"fs.go",
@@ -38,6 +39,7 @@ go_library(
"//pkg/sentry/fs/fsutil",
"//pkg/sentry/fs/host",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/pipe",
"//pkg/sentry/kernel/time",
"//pkg/sentry/memmap",
"//pkg/sentry/socket/unix/transport",
+3
View File
@@ -127,6 +127,9 @@ func (cp cachePolicy) revalidate(ctx context.Context, name string, parent, child
childIops, ok := child.InodeOperations.(*inodeOperations)
if !ok {
if _, ok := child.InodeOperations.(*fifo); ok {
return false
}
panic(fmt.Sprintf("revalidating inode operations of unknown type %T", child.InodeOperations))
}
parentIops, ok := parent.InodeOperations.(*inodeOperations)
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2020 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 gofer
import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sentry/fs"
)
// +stateify savable
type fifo struct {
fs.InodeOperations
fileIops *inodeOperations
}
var _ fs.InodeOperations = (*fifo)(nil)
// Rename implements fs.InodeOperations. It forwards the call to the underlying
// file inode to handle the file rename. Note that file key remains the same
// after the rename to keep the endpoint mapping.
func (i *fifo) Rename(ctx context.Context, inode *fs.Inode, oldParent *fs.Inode, oldName string, newParent *fs.Inode, newName string, replacement bool) error {
return i.fileIops.Rename(ctx, inode, oldParent, oldName, newParent, newName, replacement)
}
// StatFS implements fs.InodeOperations.
func (i *fifo) StatFS(ctx context.Context) (fs.Info, error) {
return i.fileIops.StatFS(ctx)
}
+1 -1
View File
@@ -61,7 +61,7 @@ func rootTest(t *testing.T, name string, cp cachePolicy, fn func(context.Context
ctx := contexttest.Context(t)
sattr, rootInodeOperations := newInodeOperations(ctx, s, contextFile{
file: rootFile,
}, root.QID, p9.AttrMaskAll(), root.Attr, false /* socket */)
}, root.QID, p9.AttrMaskAll(), root.Attr)
m := fs.NewMountSource(ctx, s, &filesystem{}, fs.MountSourceFlags{})
rootInode := fs.NewInode(ctx, rootInodeOperations, m, sattr)
+124 -61
View File
@@ -23,14 +23,24 @@ import (
"gvisor.dev/gvisor/pkg/p9"
"gvisor.dev/gvisor/pkg/sentry/device"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel/pipe"
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
"gvisor.dev/gvisor/pkg/syserror"
"gvisor.dev/gvisor/pkg/usermem"
)
// maxFilenameLen is the maximum length of a filename. This is dictated by 9P's
// encoding of strings, which uses 2 bytes for the length prefix.
const maxFilenameLen = (1 << 16) - 1
func changeType(mode p9.FileMode, newType p9.FileMode) p9.FileMode {
if newType&^p9.FileModeMask != 0 {
panic(fmt.Sprintf("newType contained more bits than just file mode: %x", newType))
}
clear := mode &^ p9.FileModeMask
return clear | newType
}
// Lookup loads an Inode at name into a Dirent based on the session's cache
// policy.
func (i *inodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name string) (*fs.Dirent, error) {
@@ -69,8 +79,25 @@ func (i *inodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name string
return nil, err
}
if i.session().overrides != nil {
// Check if file belongs to a internal named pipe. Note that it doesn't need
// to check for sockets because it's done in newInodeOperations below.
deviceKey := device.MultiDeviceKey{
Device: p9attr.RDev,
SecondaryDevice: i.session().connID,
Inode: qids[0].Path,
}
unlock := i.session().overrides.lock()
if pipeInode := i.session().overrides.getPipe(deviceKey); pipeInode != nil {
unlock()
pipeInode.IncRef()
return fs.NewDirent(ctx, pipeInode, name), nil
}
unlock()
}
// Construct the Inode operations.
sattr, node := newInodeOperations(ctx, i.fileState.s, newFile, qids[0], mask, p9attr, false)
sattr, node := newInodeOperations(ctx, i.fileState.s, newFile, qids[0], mask, p9attr)
// Construct a positive Dirent.
return fs.NewDirent(ctx, fs.NewInode(ctx, node, dir.MountSource, sattr), name), nil
@@ -138,7 +165,7 @@ func (i *inodeOperations) Create(ctx context.Context, dir *fs.Inode, name string
qid := qids[0]
// Construct the InodeOperations.
sattr, iops := newInodeOperations(ctx, i.fileState.s, unopened, qid, mask, p9attr, false)
sattr, iops := newInodeOperations(ctx, i.fileState.s, unopened, qid, mask, p9attr)
// Construct the positive Dirent.
d := fs.NewDirent(ctx, fs.NewInode(ctx, iops, dir.MountSource, sattr), name)
@@ -223,63 +250,22 @@ func (i *inodeOperations) Bind(ctx context.Context, dir *fs.Inode, name string,
return nil, syserror.ENAMETOOLONG
}
if i.session().endpoints == nil {
if i.session().overrides == nil {
return nil, syscall.EOPNOTSUPP
}
// Create replaces the directory fid with the newly created/opened
// file, so clone this directory so it doesn't change out from under
// this node.
_, newFile, err := i.fileState.file.walk(ctx, nil)
if err != nil {
return nil, err
}
// We're not going to use newFile after return.
defer newFile.close(ctx)
// Stabilize the endpoint map while creation is in progress.
unlock := i.session().endpoints.lock()
// Stabilize the override map while creation is in progress.
unlock := i.session().overrides.lock()
defer unlock()
// Create a regular file in the gofer and then mark it as a socket by
// adding this inode key in the 'endpoints' map.
owner := fs.FileOwnerFromContext(ctx)
hostFile, err := newFile.create(ctx, name, p9.ReadWrite, p9.FileMode(perm.LinuxMode()), p9.UID(owner.UID), p9.GID(owner.GID))
sattr, iops, err := i.createEndpointFile(ctx, dir, name, perm, p9.ModeSocket)
if err != nil {
return nil, err
}
// We're not going to use this file.
hostFile.Close()
i.touchModificationAndStatusChangeTime(ctx, dir)
// Get the attributes of the file to create inode key.
qid, mask, attr, err := getattr(ctx, newFile)
if err != nil {
return nil, err
}
key := device.MultiDeviceKey{
Device: attr.RDev,
SecondaryDevice: i.session().connID,
Inode: qid.Path,
}
// Create child dirent.
// Get an unopened p9.File for the file we created so that it can be
// cloned and re-opened multiple times after creation.
_, unopened, err := i.fileState.file.walk(ctx, []string{name})
if err != nil {
return nil, err
}
// Construct the InodeOperations.
sattr, iops := newInodeOperations(ctx, i.fileState.s, unopened, qid, mask, attr, true)
// Construct the positive Dirent.
childDir := fs.NewDirent(ctx, fs.NewInode(ctx, iops, dir.MountSource, sattr), name)
i.session().endpoints.add(key, childDir, ep)
i.session().overrides.addBoundEndpoint(iops.fileState.key, childDir, ep)
return childDir, nil
}
@@ -294,33 +280,110 @@ func (i *inodeOperations) CreateFifo(ctx context.Context, dir *fs.Inode, name st
// N.B. FIFOs use major/minor numbers 0.
if _, err := i.fileState.file.mknod(ctx, name, mode, 0, 0, p9.UID(owner.UID), p9.GID(owner.GID)); err != nil {
return err
if i.session().overrides == nil || err != syscall.EPERM {
return err
}
// If gofer doesn't support mknod, check if we can create an internal fifo.
return i.createInternalFifo(ctx, dir, name, owner, perm)
}
i.touchModificationAndStatusChangeTime(ctx, dir)
return nil
}
func (i *inodeOperations) createInternalFifo(ctx context.Context, dir *fs.Inode, name string, owner fs.FileOwner, perm fs.FilePermissions) error {
if i.session().overrides == nil {
return syserror.EPERM
}
// Stabilize the override map while creation is in progress.
unlock := i.session().overrides.lock()
defer unlock()
sattr, fileOps, err := i.createEndpointFile(ctx, dir, name, perm, p9.ModeNamedPipe)
if err != nil {
return err
}
// First create a pipe.
p := pipe.NewPipe(true /* isNamed */, pipe.DefaultPipeSize, usermem.PageSize)
// Wrap the fileOps with our Fifo.
iops := &fifo{
InodeOperations: pipe.NewInodeOperations(ctx, perm, p),
fileIops: fileOps,
}
inode := fs.NewInode(ctx, iops, dir.MountSource, sattr)
// Construct the positive Dirent.
childDir := fs.NewDirent(ctx, fs.NewInode(ctx, iops, dir.MountSource, sattr), name)
i.session().overrides.addPipe(fileOps.fileState.key, childDir, inode)
return nil
}
// Caller must hold Session.endpoint lock.
func (i *inodeOperations) createEndpointFile(ctx context.Context, dir *fs.Inode, name string, perm fs.FilePermissions, fileType p9.FileMode) (fs.StableAttr, *inodeOperations, error) {
_, dirClone, err := i.fileState.file.walk(ctx, nil)
if err != nil {
return fs.StableAttr{}, nil, err
}
// We're not going to use dirClone after return.
defer dirClone.close(ctx)
// Create a regular file in the gofer and then mark it as a socket by
// adding this inode key in the 'overrides' map.
owner := fs.FileOwnerFromContext(ctx)
hostFile, err := dirClone.create(ctx, name, p9.ReadWrite, p9.FileMode(perm.LinuxMode()), p9.UID(owner.UID), p9.GID(owner.GID))
if err != nil {
return fs.StableAttr{}, nil, err
}
// We're not going to use this file.
hostFile.Close()
i.touchModificationAndStatusChangeTime(ctx, dir)
// Get the attributes of the file to create inode key.
qid, mask, attr, err := getattr(ctx, dirClone)
if err != nil {
return fs.StableAttr{}, nil, err
}
// Get an unopened p9.File for the file we created so that it can be
// cloned and re-opened multiple times after creation.
_, unopened, err := i.fileState.file.walk(ctx, []string{name})
if err != nil {
return fs.StableAttr{}, nil, err
}
// Construct new inode with file type overridden.
attr.Mode = changeType(attr.Mode, fileType)
sattr, iops := newInodeOperations(ctx, i.fileState.s, unopened, qid, mask, attr)
return sattr, iops, nil
}
// Remove implements InodeOperations.Remove.
func (i *inodeOperations) Remove(ctx context.Context, dir *fs.Inode, name string) error {
if len(name) > maxFilenameLen {
return syserror.ENAMETOOLONG
}
var key device.MultiDeviceKey
removeSocket := false
if i.session().endpoints != nil {
// Find out if file being deleted is a socket that needs to be
var key *device.MultiDeviceKey
if i.session().overrides != nil {
// Find out if file being deleted is a socket or pipe that needs to be
// removed from endpoint map.
if d, err := i.Lookup(ctx, dir, name); err == nil {
defer d.DecRef()
if fs.IsSocket(d.Inode.StableAttr) {
child := d.Inode.InodeOperations.(*inodeOperations)
key = child.fileState.key
removeSocket = true
// Stabilize the endpoint map while deletion is in progress.
unlock := i.session().endpoints.lock()
if fs.IsSocket(d.Inode.StableAttr) || fs.IsPipe(d.Inode.StableAttr) {
switch iops := d.Inode.InodeOperations.(type) {
case *inodeOperations:
key = &iops.fileState.key
case *fifo:
key = &iops.fileIops.fileState.key
}
// Stabilize the override map while deletion is in progress.
unlock := i.session().overrides.lock()
defer unlock()
}
}
@@ -329,8 +392,8 @@ func (i *inodeOperations) Remove(ctx context.Context, dir *fs.Inode, name string
if err := i.fileState.file.unlinkAt(ctx, name, 0); err != nil {
return err
}
if removeSocket {
i.session().endpoints.remove(key)
if key != nil {
i.session().overrides.remove(*key)
}
i.touchModificationAndStatusChangeTime(ctx, dir)
+118 -73
View File
@@ -33,60 +33,107 @@ import (
var DefaultDirentCacheSize uint64 = fs.DefaultDirentCacheSize
// +stateify savable
type endpointMaps struct {
// mu protexts the direntMap, the keyMap, and the pathMap below.
mu sync.RWMutex `state:"nosave"`
type overrideInfo struct {
dirent *fs.Dirent
// direntMap links sockets to their dirents.
// It is filled concurrently with the keyMap and is stored upon save.
// Before saving, this map is used to populate the pathMap.
direntMap map[transport.BoundEndpoint]*fs.Dirent
// endpoint is set when dirent points to a socket. inode must not be set.
endpoint transport.BoundEndpoint
// keyMap links MultiDeviceKeys (containing inode IDs) to their sockets.
// It is not stored during save because the inode ID may change upon restore.
keyMap map[device.MultiDeviceKey]transport.BoundEndpoint `state:"nosave"`
// pathMap links the sockets to their paths.
// It is filled before saving from the direntMap and is stored upon save.
// Upon restore, this map is used to re-populate the keyMap.
pathMap map[transport.BoundEndpoint]string
// inode is set when dirent points to a pipe. endpoint must not be set.
inode *fs.Inode
}
// add adds the endpoint to the maps.
func (l *overrideInfo) inodeType() fs.InodeType {
switch {
case l.endpoint != nil:
return fs.Socket
case l.inode != nil:
return fs.Pipe
}
panic("endpoint or node must be set")
}
// +stateify savable
type overrideMaps struct {
// mu protexts the keyMap, and the pathMap below.
mu sync.RWMutex `state:"nosave"`
// keyMap links MultiDeviceKeys (containing inode IDs) to their sockets/pipes.
// It is not stored during save because the inode ID may change upon restore.
keyMap map[device.MultiDeviceKey]*overrideInfo `state:"nosave"`
// pathMap links the sockets/pipes to their paths.
// It is filled before saving from the direntMap and is stored upon save.
// Upon restore, this map is used to re-populate the keyMap.
pathMap map[*overrideInfo]string
}
// addBoundEndpoint adds the bound endpoint to the map.
// A reference is taken on the dirent argument.
//
// Precondition: maps must have been locked with 'lock'.
func (e *endpointMaps) add(key device.MultiDeviceKey, d *fs.Dirent, ep transport.BoundEndpoint) {
e.keyMap[key] = ep
func (e *overrideMaps) addBoundEndpoint(key device.MultiDeviceKey, d *fs.Dirent, ep transport.BoundEndpoint) {
d.IncRef()
e.direntMap[ep] = d
e.keyMap[key] = &overrideInfo{dirent: d, endpoint: ep}
}
// addPipe adds the pipe inode to the map.
// A reference is taken on the dirent argument.
//
// Precondition: maps must have been locked with 'lock'.
func (e *overrideMaps) addPipe(key device.MultiDeviceKey, d *fs.Dirent, inode *fs.Inode) {
d.IncRef()
e.keyMap[key] = &overrideInfo{dirent: d, inode: inode}
}
// remove deletes the key from the maps.
//
// Precondition: maps must have been locked with 'lock'.
func (e *endpointMaps) remove(key device.MultiDeviceKey) {
endpoint := e.get(key)
func (e *overrideMaps) remove(key device.MultiDeviceKey) {
endpoint := e.keyMap[key]
delete(e.keyMap, key)
d := e.direntMap[endpoint]
d.DecRef()
delete(e.direntMap, endpoint)
endpoint.dirent.DecRef()
}
// lock blocks other addition and removal operations from happening while
// the backing file is being created or deleted. Returns a function that unlocks
// the endpoint map.
func (e *endpointMaps) lock() func() {
func (e *overrideMaps) lock() func() {
e.mu.Lock()
return func() { e.mu.Unlock() }
}
// get returns the endpoint mapped to the given key.
// getBoundEndpoint returns the bound endpoint mapped to the given key.
//
// Precondition: maps must have been locked for reading.
func (e *endpointMaps) get(key device.MultiDeviceKey) transport.BoundEndpoint {
return e.keyMap[key]
// Precondition: maps must have been locked.
func (e *overrideMaps) getBoundEndpoint(key device.MultiDeviceKey) transport.BoundEndpoint {
if v := e.keyMap[key]; v != nil {
return v.endpoint
}
return nil
}
// getPipe returns the pipe inode mapped to the given key.
//
// Precondition: maps must have been locked.
func (e *overrideMaps) getPipe(key device.MultiDeviceKey) *fs.Inode {
if v := e.keyMap[key]; v != nil {
return v.inode
}
return nil
}
// getType returns the inode type if there is a corresponding endpoint for the
// given key. Returns false otherwise.
func (e *overrideMaps) getType(key device.MultiDeviceKey) (fs.InodeType, bool) {
e.mu.Lock()
v := e.keyMap[key]
e.mu.Unlock()
if v != nil {
return v.inodeType(), true
}
return 0, false
}
// session holds state for each 9p session established during sys_mount.
@@ -137,16 +184,16 @@ type session struct {
// mounter is the EUID/EGID that mounted this file system.
mounter fs.FileOwner `state:"wait"`
// endpoints is used to map inodes that represent socket files to their
// corresponding endpoint. Socket files are created as regular files in the
// gofer and their presence in this map indicate that they should indeed be
// socket files. This allows unix domain sockets to be used with paths that
// belong to a gofer.
// overrides is used to map inodes that represent socket/pipes files to their
// corresponding endpoint/iops. These files are created as regular files in
// the gofer and their presence in this map indicate that they should indeed
// be socket/pipe files. This allows unix domain sockets and named pipes to
// be used with paths that belong to a gofer.
//
// TODO(gvisor.dev/issue/1200): there are few possible races with someone
// stat'ing the file and another deleting it concurrently, where the file
// will not be reported as socket file.
endpoints *endpointMaps `state:"wait"`
overrides *overrideMaps `state:"wait"`
}
// Destroy tears down the session.
@@ -179,15 +226,21 @@ func (s *session) SaveInodeMapping(inode *fs.Inode, path string) {
// This is very unintuitive. We *CANNOT* trust the inode's StableAttrs,
// because overlay copyUp may have changed them out from under us.
// So much for "immutable".
sattr := inode.InodeOperations.(*inodeOperations).fileState.sattr
s.inodeMappings[sattr.InodeID] = path
switch iops := inode.InodeOperations.(type) {
case *inodeOperations:
s.inodeMappings[iops.fileState.sattr.InodeID] = path
case *fifo:
s.inodeMappings[iops.fileIops.fileState.sattr.InodeID] = path
default:
panic(fmt.Sprintf("Invalid type: %T", iops))
}
}
// newInodeOperations creates a new 9p fs.InodeOperations backed by a p9.File and attributes
// (p9.QID, p9.AttrMask, p9.Attr).
// newInodeOperations creates a new 9p fs.InodeOperations backed by a p9.File
// and attributes (p9.QID, p9.AttrMask, p9.Attr).
//
// Endpoints lock must not be held if socket == false.
func newInodeOperations(ctx context.Context, s *session, file contextFile, qid p9.QID, valid p9.AttrMask, attr p9.Attr, socket bool) (fs.StableAttr, *inodeOperations) {
func newInodeOperations(ctx context.Context, s *session, file contextFile, qid p9.QID, valid p9.AttrMask, attr p9.Attr) (fs.StableAttr, *inodeOperations) {
deviceKey := device.MultiDeviceKey{
Device: attr.RDev,
SecondaryDevice: s.connID,
@@ -201,17 +254,11 @@ func newInodeOperations(ctx context.Context, s *session, file contextFile, qid p
BlockSize: bsize(attr),
}
if s.endpoints != nil {
if socket {
sattr.Type = fs.Socket
} else {
// If unix sockets are allowed on this filesystem, check if this file is
// supposed to be a socket file.
unlock := s.endpoints.lock()
if s.endpoints.get(deviceKey) != nil {
sattr.Type = fs.Socket
}
unlock()
if s.overrides != nil && sattr.Type == fs.RegularFile {
// If overrides are allowed on this filesystem, check if this file is
// supposed to be of a different type, e.g. socket.
if t, ok := s.overrides.getType(deviceKey); ok {
sattr.Type = t
}
}
@@ -267,7 +314,7 @@ func Root(ctx context.Context, dev string, filesystem fs.Filesystem, superBlockF
s.EnableLeakCheck("gofer.session")
if o.privateunixsocket {
s.endpoints = newEndpointMaps()
s.overrides = newOverrideMaps()
}
// Construct the MountSource with the session and superBlockFlags.
@@ -305,26 +352,24 @@ func Root(ctx context.Context, dev string, filesystem fs.Filesystem, superBlockF
return nil, err
}
sattr, iops := newInodeOperations(ctx, &s, s.attach, qid, valid, attr, false)
sattr, iops := newInodeOperations(ctx, &s, s.attach, qid, valid, attr)
return fs.NewInode(ctx, iops, m, sattr), nil
}
// newEndpointMaps creates a new endpointMaps.
func newEndpointMaps() *endpointMaps {
return &endpointMaps{
direntMap: make(map[transport.BoundEndpoint]*fs.Dirent),
keyMap: make(map[device.MultiDeviceKey]transport.BoundEndpoint),
pathMap: make(map[transport.BoundEndpoint]string),
// newOverrideMaps creates a new overrideMaps.
func newOverrideMaps() *overrideMaps {
return &overrideMaps{
keyMap: make(map[device.MultiDeviceKey]*overrideInfo),
pathMap: make(map[*overrideInfo]string),
}
}
// fillKeyMap populates key and dirent maps upon restore from saved
// pathmap.
// fillKeyMap populates key and dirent maps upon restore from saved pathmap.
func (s *session) fillKeyMap(ctx context.Context) error {
unlock := s.endpoints.lock()
unlock := s.overrides.lock()
defer unlock()
for ep, dirPath := range s.endpoints.pathMap {
for ep, dirPath := range s.overrides.pathMap {
_, file, err := s.attach.walk(ctx, splitAbsolutePath(dirPath))
if err != nil {
return fmt.Errorf("error filling endpointmaps, failed to walk to %q: %v", dirPath, err)
@@ -341,25 +386,25 @@ func (s *session) fillKeyMap(ctx context.Context) error {
Inode: qid.Path,
}
s.endpoints.keyMap[key] = ep
s.overrides.keyMap[key] = ep
}
return nil
}
// fillPathMap populates paths for endpoints from dirents in direntMap
// fillPathMap populates paths for overrides from dirents in direntMap
// before save.
func (s *session) fillPathMap() error {
unlock := s.endpoints.lock()
unlock := s.overrides.lock()
defer unlock()
for ep, dir := range s.endpoints.direntMap {
mountRoot := dir.MountRoot()
for _, endpoint := range s.overrides.keyMap {
mountRoot := endpoint.dirent.MountRoot()
defer mountRoot.DecRef()
dirPath, _ := dir.FullName(mountRoot)
dirPath, _ := endpoint.dirent.FullName(mountRoot)
if dirPath == "" {
return fmt.Errorf("error getting path from dirent")
}
s.endpoints.pathMap[ep] = dirPath
s.overrides.pathMap[endpoint] = dirPath
}
return nil
}
@@ -368,7 +413,7 @@ func (s *session) fillPathMap() error {
func (s *session) restoreEndpointMaps(ctx context.Context) error {
// When restoring, only need to create the keyMap because the dirent and path
// maps got stored through the save.
s.endpoints.keyMap = make(map[device.MultiDeviceKey]transport.BoundEndpoint)
s.overrides.keyMap = make(map[device.MultiDeviceKey]*overrideInfo)
if err := s.fillKeyMap(ctx); err != nil {
return fmt.Errorf("failed to insert sockets into endpoint map: %v", err)
}
@@ -376,6 +421,6 @@ func (s *session) restoreEndpointMaps(ctx context.Context) error {
// Re-create pathMap because it can no longer be trusted as socket paths can
// change while process continues to run. Empty pathMap will be re-filled upon
// next save.
s.endpoints.pathMap = make(map[transport.BoundEndpoint]string)
s.overrides.pathMap = make(map[*overrideInfo]string)
return nil
}
+6 -6
View File
@@ -25,9 +25,9 @@ import (
// beforeSave is invoked by stateify.
func (s *session) beforeSave() {
if s.endpoints != nil {
if s.overrides != nil {
if err := s.fillPathMap(); err != nil {
panic("failed to save paths to endpoint map before saving" + err.Error())
panic("failed to save paths to override map before saving" + err.Error())
}
}
}
@@ -74,10 +74,10 @@ func (s *session) afterLoad() {
panic(fmt.Sprintf("new attach name %v, want %v", opts.aname, s.aname))
}
// Check if endpointMaps exist when uds sockets are enabled
// (only pathmap will actualy have been saved).
if opts.privateunixsocket != (s.endpoints != nil) {
panic(fmt.Sprintf("new privateunixsocket option %v, want %v", opts.privateunixsocket, s.endpoints != nil))
// Check if overrideMaps exist when uds sockets are enabled (only pathmaps
// will actually have been saved).
if opts.privateunixsocket != (s.overrides != nil) {
panic(fmt.Sprintf("new privateunixsocket option %v, want %v", opts.privateunixsocket, s.overrides != nil))
}
if args.Flags != s.superBlockFlags {
panic(fmt.Sprintf("new mount flags %v, want %v", args.Flags, s.superBlockFlags))
+4 -4
View File
@@ -32,15 +32,15 @@ func (i *inodeOperations) BoundEndpoint(inode *fs.Inode, path string) transport.
return nil
}
if i.session().endpoints != nil {
unlock := i.session().endpoints.lock()
if i.session().overrides != nil {
unlock := i.session().overrides.lock()
defer unlock()
ep := i.session().endpoints.get(i.fileState.key)
ep := i.session().overrides.getBoundEndpoint(i.fileState.key)
if ep != nil {
return ep
}
// Not found in endpoints map, it may be a gofer backed unix socket...
// Not found in overrides map, it may be a gofer backed unix socket...
}
inode.IncRef()
-1
View File
@@ -225,7 +225,6 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:mknod_test",
use_tmpfs = True, # mknod is not supported over gofer.
)
syscall_test(